/*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);
	}
}
Exemple #2
0
/*
 * 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);
}
Exemple #3
0
/*
 * 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);
}