/*ARGSUSED*/ static void px_fdvma_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, ddi_dma_cookie_t *cp) { ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; fdvma_t *fdvma_p = (fdvma_t *)mp->dmai_fdvma; px_t *px_p = (px_t *)fdvma_p->softsp; px_mmu_t *mmu_p = px_p->px_mmu_p; dev_info_t *dip = px_p->px_dip; px_dvma_addr_t dvma_addr, dvma_pg; uint32_t offset; size_t npages, pg_index; io_attributes_t attr; offset = (uint32_t)(uintptr_t)a & MMU_PAGE_OFFSET; npages = MMU_BTOPR(len + offset); if (!npages) return; /* make sure we don't exceed reserved boundary */ DBG(DBG_FAST_DVMA, dip, "load index=%x: %p+%x ", index, a, len); if (index + npages > mp->dmai_ndvmapages) { cmn_err(px_panic_on_fatal_errors ? CE_PANIC : CE_WARN, "%s%d: kaddr_load index(%x)+pgs(%lx) exceeds limit\n", ddi_driver_name(dip), ddi_get_instance(dip), index, npages); return; } fdvma_p->pagecnt[index] = npages; dvma_addr = mp->dmai_mapping + MMU_PTOB(index); dvma_pg = MMU_BTOP(dvma_addr); pg_index = dvma_pg - mmu_p->dvma_base_pg; /* construct the dma cookie to be returned */ MAKE_DMA_COOKIE(cp, dvma_addr | offset, len); DBG(DBG_FAST_DVMA | DBG_CONT, dip, "cookie: %x+%x\n", cp->dmac_address, cp->dmac_size); attr = PX_GET_TTE_ATTR(mp->dmai_rflags, mp->dmai_attr.dma_attr_flags); if (px_lib_iommu_map(dip, PCI_TSBID(0, pg_index), npages, PX_ADD_ATTR_EXTNS(attr, mp->dmai_bdf), (void *)a, 0, MMU_MAP_BUF) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: kaddr_load can't get " "page frame for vaddr %lx", ddi_driver_name(dip), ddi_get_instance(dip), (uintptr_t)a); } }
/* * bus dma bind handle entry point: */ int px_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, ddi_dma_cookie_t *cookiep, uint_t *ccountp) { px_t *px_p = DIP_TO_STATE(dip); px_mmu_t *mmu_p = px_p->px_mmu_p; ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; int ret; DBG(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq); if (mp->dmai_flags & PX_DMAI_FLAGS_INUSE) return (DDI_DMA_INUSE); ASSERT((mp->dmai_flags & ~PX_DMAI_FLAGS_PRESERVE) == 0); mp->dmai_flags |= PX_DMAI_FLAGS_INUSE; if (ret = px_dma_type(px_p, dmareq, mp)) goto err; if (ret = px_dma_pfn(px_p, dmareq, mp)) goto err; switch (PX_DMA_TYPE(mp)) { case PX_DMAI_FLAGS_DVMA: if (ret = px_dvma_win(px_p, dmareq, mp)) goto map_err; if (!PX_DMA_CANCACHE(mp)) { /* try fast track */ if (PX_DMA_CANFAST(mp)) { if (!px_dvma_map_fast(mmu_p, mp)) goto mapped; /*LINTED E_NOP_ELSE_STMT*/ } else { PX_DVMA_FASTTRAK_PROF(mp); } } if (ret = px_dvma_map(mp, dmareq, mmu_p)) goto map_err; mapped: *ccountp = 1; MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size); break; case PX_DMAI_FLAGS_BYPASS: case PX_DMAI_FLAGS_PTP: if (ret = px_dma_physwin(px_p, dmareq, mp)) goto map_err; *ccountp = PX_WINLST(mp)->win_ncookies; *cookiep = *(ddi_dma_cookie_t *)(PX_WINLST(mp) + 1); /* wholeobj */ break; default: cmn_err(CE_PANIC, "%s%d: px_dma_bindhdl(%p): bad dma type", ddi_driver_name(rdip), ddi_get_instance(rdip), mp); /*NOTREACHED*/ } DBG(DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x\n", cookiep->dmac_address, cookiep->dmac_size); px_dump_dma_handle(DBG_DMA_MAP, dip, mp); /* insert dma handle into FMA cache */ if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) mp->dmai_error.err_cf = px_err_dma_hdl_check; return (mp->dmai_nwin == 1 ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP); map_err: px_dma_freepfn(mp); err: mp->dmai_flags &= PX_DMAI_FLAGS_PRESERVE; return (ret); }
/* * bus dma win entry point: */ int px_dma_win(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) { ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; int ret; DBG(DBG_DMA_WIN, dip, "rdip=%s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); px_dump_dma_handle(DBG_DMA_WIN, dip, mp); if (win >= mp->dmai_nwin) { DBG(DBG_DMA_WIN, dip, "%x out of range\n", win); return (DDI_FAILURE); } switch (PX_DMA_TYPE(mp)) { case PX_DMAI_FLAGS_DVMA: if (win != PX_DMA_CURWIN(mp)) { px_t *px_p = DIP_TO_STATE(dip); px_mmu_t *mmu_p = px_p->px_mmu_p; px_mmu_unmap_window(mmu_p, mp); /* map_window sets dmai_mapping/size/offset */ px_mmu_map_window(mmu_p, mp, win); if ((ret = px_mmu_map_window(mmu_p, mp, win)) != DDI_SUCCESS) return (ret); } if (cookiep) MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size); if (ccountp) *ccountp = 1; break; case PX_DMAI_FLAGS_PTP: case PX_DMAI_FLAGS_BYPASS: { int i; ddi_dma_cookie_t *ck_p; px_dma_win_t *win_p = mp->dmai_winlst; for (i = 0; i < win; win_p = win_p->win_next, i++) {}; ck_p = (ddi_dma_cookie_t *)(win_p + 1); *cookiep = *ck_p; mp->dmai_offset = win_p->win_offset; mp->dmai_size = win_p->win_size; mp->dmai_mapping = ck_p->dmac_laddress; mp->dmai_cookie = ck_p + 1; win_p->win_curseg = 0; if (ccountp) *ccountp = win_p->win_ncookies; } break; default: cmn_err(CE_WARN, "%s%d: px_dma_win:bad dma type 0x%x", ddi_driver_name(rdip), ddi_get_instance(rdip), PX_DMA_TYPE(mp)); return (DDI_FAILURE); } if (cookiep) DBG(DBG_DMA_WIN, dip, "cookie - dmac_address=%x dmac_size=%x\n", cookiep->dmac_address, cookiep->dmac_size); if (offp) *offp = (off_t)mp->dmai_offset; if (lenp) *lenp = mp->dmai_size; return (DDI_SUCCESS); }