# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1181100682 -32400 # Node ID 2d56bb613bedb3638ff52a4a9f6566c0552d696b # Parent cb024947fa0186c5e08a71ecd4c0550967c5509a support dma tracking for sba_iommu.c PATCHNAME: dma_tracking_sba_iommu_c Signed-off-by: Isaku Yamahata diff -r cb024947fa01 -r 2d56bb613bed linux-2.6-xen-sparse/arch/ia64/hp/common/sba_iommu.c --- a/linux-2.6-xen-sparse/arch/ia64/hp/common/sba_iommu.c Tue Jun 05 18:24:11 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/hp/common/sba_iommu.c Wed Jun 06 12:31:22 2007 +0900 @@ -42,6 +42,9 @@ #include /* wmb() */ #include +#ifdef CONFIG_XEN +#include +#endif #define PFX "IOC: " @@ -901,7 +904,20 @@ sba_map_single(struct device *dev, void unsigned long flags; #endif #ifdef ALLOW_IOV_BYPASS +#ifdef CONFIG_XEN + unsigned long pci_addr = gnttab_dma_map_page(addr) + + offset_in_page(addr); + void* tmp_addr = addr; + size_t tmp_size = size; + while (tmp_size > PAGE_SIZE) { + tmp_addr += PAGE_SIZE; + tmp_size -= PAGE_SIZE; + + gnttab_dma_map_page(tmp_addr); + } +#else unsigned long pci_addr = virt_to_bus(addr); +#endif ASSERT(to_pci_dev(dev)->dma_mask); /* @@ -994,6 +1010,48 @@ sba_mark_clean(struct ioc *ioc, dma_addr } #endif +#ifdef CONFIG_XEN +static void +sba_gnttab_dma_unmap_page(struct ioc *ioc, dma_addr_t iova, size_t size) +{ + u32 iovp = (u32) SBA_IOVP(ioc,iova); + int off = PDIR_INDEX(iovp); + int i; + size_t step_size = max(PAGE_SIZE, iovp_size); + + if (!is_running_on_xen()) + return; + + for (;;) { + size_t unmap_pages = + (min(step_size, size) + PAGE_SIZE - 1) / PAGE_SIZE; + dma_addr_t dma_address = ioc->pdir_base[off] & + ~0xE000000000000FFFULL; + for (i = 0; i < unmap_pages; i++) { + gnttab_dma_unmap_page(dma_address); + dma_address += PAGE_SIZE; + } + + if (size <= step_size) + break; + off += step_size / iovp_size; + size -= step_size; + } +} + +static void +sba_gnttab_dma_map_sg(struct scatterlist *sglist, int nents) +{ + int i; + + if (!is_running_on_xen()) + return; + + for (i = 0; i < nents; i++) + gnttab_dma_map_page(sglist[i].page); +} +#endif + /** * sba_unmap_single - unmap one IOVA and free resources * @dev: instance of PCI owned by the driver that's asking. @@ -1016,7 +1074,8 @@ void sba_unmap_single(struct device *dev ASSERT(ioc); #ifdef ALLOW_IOV_BYPASS - if (likely((iova & ioc->imask) != ioc->ibase)) { + if (likely((iova & ioc->imask) != ioc->ibase) && + !range_straddles_page_boundary(bus_to_virt(iova), size)) { /* ** Address does not fall w/in IOVA, must be bypassing */ @@ -1027,6 +1086,15 @@ void sba_unmap_single(struct device *dev mark_clean(bus_to_virt(iova), size); } #endif +#ifdef CONFIG_XEN + for (;;) { + gnttab_dma_unmap_page(iova); + if (size <= PAGE_SIZE) + break; + iova += PAGE_SIZE; + size -= PAGE_SIZE; + } +#endif return; } #endif @@ -1043,7 +1111,10 @@ void sba_unmap_single(struct device *dev if (dir == DMA_FROM_DEVICE) sba_mark_clean(ioc, iova, size); #endif - +#ifdef CONFIG_XEN + sba_gnttab_dma_unmap_page(ioc, iova, size); +#endif + #if DELAYED_RESOURCE_CNT > 0 spin_lock_irqsave(&ioc->saved_lock, flags); d = &(ioc->saved[ioc->saved_cnt]); @@ -1427,7 +1498,11 @@ int sba_map_sg(struct device *dev, struc if (likely((ioc->dma_mask & ~to_pci_dev(dev)->dma_mask) == 0)) { for (sg = sglist ; filled < nents ; filled++, sg++){ sg->dma_length = sg->length; +#ifdef CONFIG_XEN + sg->dma_address = gnttab_dma_map_page(sg->address) + sg->offset; +#else sg->dma_address = virt_to_bus(sba_sg_address(sg)); +#endif } return filled; } @@ -1450,6 +1525,10 @@ int sba_map_sg(struct device *dev, struc #endif prefetch(ioc->res_hint); + +#ifdef CONFIG_XEN + sba_gnttab_dma_map_sg(sglist, nents); +#endif /* ** First coalesce the chunks and allocate I/O pdir space