static void sba_unmap_page()

in hp/common/sba_iommu.c [1032:1099]


static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
			   enum dma_data_direction dir, unsigned long attrs)
{
	struct ioc *ioc;
#if DELAYED_RESOURCE_CNT > 0
	struct sba_dma_pair *d;
#endif
	unsigned long flags;
	dma_addr_t offset;

	ioc = GET_IOC(dev);
	ASSERT(ioc);

#ifdef ALLOW_IOV_BYPASS
	if (likely((iova & ioc->imask) != ioc->ibase)) {
		/*
		** Address does not fall w/in IOVA, must be bypassing
		*/
		DBG_BYPASS("sba_unmap_page() bypass addr: 0x%lx\n",
			   iova);

#ifdef ENABLE_MARK_CLEAN
		if (dir == DMA_FROM_DEVICE) {
			mark_clean(phys_to_virt(iova), size);
		}
#endif
		return;
	}
#endif
	offset = iova & ~iovp_mask;

	DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);

	iova ^= offset;        /* clear offset bits */
	size += offset;
	size = ROUNDUP(size, iovp_size);

#ifdef ENABLE_MARK_CLEAN
	if (dir == DMA_FROM_DEVICE)
		sba_mark_clean(ioc, iova, size);
#endif

#if DELAYED_RESOURCE_CNT > 0
	spin_lock_irqsave(&ioc->saved_lock, flags);
	d = &(ioc->saved[ioc->saved_cnt]);
	d->iova = iova;
	d->size = size;
	if (unlikely(++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT)) {
		int cnt = ioc->saved_cnt;
		spin_lock(&ioc->res_lock);
		while (cnt--) {
			sba_mark_invalid(ioc, d->iova, d->size);
			sba_free_range(ioc, d->iova, d->size);
			d--;
		}
		ioc->saved_cnt = 0;
		READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
		spin_unlock(&ioc->res_lock);
	}
	spin_unlock_irqrestore(&ioc->saved_lock, flags);
#else /* DELAYED_RESOURCE_CNT == 0 */
	spin_lock_irqsave(&ioc->res_lock, flags);
	sba_mark_invalid(ioc, iova, size);
	sba_free_range(ioc, iova, size);
	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
	spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif /* DELAYED_RESOURCE_CNT == 0 */
}