# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1181205552 -32400 # Node ID ce1c94602516444bcadd38f9678d8abd0f3147c6 # Parent ca58c12a9dff5732c5a164f48b9abf1724539b84 ia64 dma tracking support PATCHNAME: ia64_dma_tracking_support Signed-off-by: Isaku Yamahata diff -r ca58c12a9dff -r ce1c94602516 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 Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/hp/common/sba_iommu.c Thu Jun 07 17:39:12 2007 +0900 @@ -42,6 +42,10 @@ #include /* wmb() */ #include +#ifdef CONFIG_XEN +#include +#include +#endif #define PFX "IOC: " @@ -901,7 +905,19 @@ sba_map_single(struct device *dev, void unsigned long flags; #endif #ifdef ALLOW_IOV_BYPASS +#ifdef CONFIG_XEN + unsigned long pci_addr; + void* tmp_addr = addr - PAGE_SIZE; + size_t tmp_size = size + PAGE_SIZE; + do { + tmp_addr += PAGE_SIZE; + tmp_size -= PAGE_SIZE; + gnttab_dma_use_page(virt_to_page(addr)); + } while (tmp_size > PAGE_SIZE); + pci_addr = virt_to_bus(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_use_sg(struct scatterlist *sglist, int nents) +{ + int i; + + if (!is_running_on_xen()) + return; + + for (i = 0; i < nents; i++) + gnttab_dma_use_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. @@ -1003,7 +1061,11 @@ sba_mark_clean(struct ioc *ioc, dma_addr * * See Documentation/DMA-mapping.txt */ +#ifdef CONFIG_XEN +static void __sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir, int gnttab_unmap) +#else void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) +#endif { struct ioc *ioc; #if DELAYED_RESOURCE_CNT > 0 @@ -1016,7 +1078,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 +1090,17 @@ void sba_unmap_single(struct device *dev mark_clean(bus_to_virt(iova), size); } #endif +#ifdef CONFIG_XEN + if (gnttab_unmap) { + for (;;) { + gnttab_dma_unmap_page(iova); + if (size <= PAGE_SIZE) + break; + iova += PAGE_SIZE; + size -= PAGE_SIZE; + } + } +#endif return; } #endif @@ -1043,7 +1117,11 @@ void sba_unmap_single(struct device *dev if (dir == DMA_FROM_DEVICE) sba_mark_clean(ioc, iova, size); #endif - +#ifdef CONFIG_XEN + if (gnttab_unmap) + 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]); @@ -1071,6 +1149,14 @@ void sba_unmap_single(struct device *dev #endif /* DELAYED_RESOURCE_CNT == 0 */ } +#ifdef CONFIG_XEN +void +sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) +{ + __sba_unmap_single(dev, iova, size, dir, 1); +} +#endif + /** * sba_alloc_coherent - allocate/map shared mem for DMA @@ -1427,7 +1513,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->page) + sg->offset; +#else sg->dma_address = virt_to_bus(sba_sg_address(sg)); +#endif } return filled; } @@ -1450,6 +1540,10 @@ int sba_map_sg(struct device *dev, struc #endif prefetch(ioc->res_hint); + +#ifdef CONFIG_XEN + sba_gnttab_dma_use_sg(sglist, nents); +#endif /* ** First coalesce the chunks and allocate I/O pdir space @@ -1517,8 +1611,12 @@ void sba_unmap_sg (struct device *dev, s #endif while (nents && sglist->dma_length) { - +#ifdef CONFIG_XEN + __sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir, 0); + __gnttab_dma_unmap_page(sglist->page); +#else sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir); +#endif sglist++; nents--; } diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/arch/ia64/xen/swiotlb.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/swiotlb.c Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/swiotlb.c Thu Jun 07 17:39:12 2007 +0900 @@ -33,6 +33,8 @@ #include #ifdef CONFIG_XEN +#include +#include /* * What DMA mask should Xen use to remap the bounce buffer pool? Most * reports seem to indicate 30 bits is sufficient, except maybe for old @@ -597,7 +599,7 @@ dma_addr_t dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) { - unsigned long dev_addr = virt_to_bus(ptr); + unsigned long dev_addr = gnttab_dma_map_virt(ptr); void *map; BUG_ON(dir == DMA_NONE); @@ -610,6 +612,7 @@ swiotlb_map_single(struct device *hwdev, !address_needs_mapping(hwdev, dev_addr) && !swiotlb_force) return dev_addr; + __gnttab_dma_unmap_page(virt_to_page(ptr)); /* * Oh well, have to allocate and map a bounce buffer. */ @@ -672,8 +675,11 @@ swiotlb_unmap_single(struct device *hwde BUG_ON(dir == DMA_NONE); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) unmap_single(hwdev, dma_addr, size, dir); - else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + else { + gnttab_dma_unmap_page(dev_addr); + if (dir == DMA_FROM_DEVICE) + mark_clean(dma_addr, size); + } } /* @@ -774,9 +780,11 @@ swiotlb_map_sg(struct device *hwdev, str for (i = 0; i < nelems; i++, sg++) { addr = SG_ENT_VIRT_ADDRESS(sg); - dev_addr = virt_to_bus(addr); + dev_addr = gnttab_dma_map_virt(addr); if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { - void *map = map_single(hwdev, addr, sg->length, dir); + void *map; + gnttab_dma_unmap_page(dev_addr); + map = map_single(hwdev, addr, sg->length, dir); sg->dma_address = virt_to_bus(map); if (!map) { /* Don't panic here, we expect map_sg users @@ -808,8 +816,12 @@ swiotlb_unmap_sg(struct device *hwdev, s for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) unmap_single(hwdev, (void *) bus_to_virt(sg->dma_address), sg->dma_length, dir); - else if (dir == DMA_FROM_DEVICE) - mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); + else { + gnttab_dma_unmap_page(sg->dma_address); + if (dir == DMA_FROM_DEVICE) + mark_clean(SG_ENT_VIRT_ADDRESS(sg), + sg->dma_length); + } } /* diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c Thu Jun 07 17:39:12 2007 +0900 @@ -105,6 +105,7 @@ xencommize_grant_table_op(unsigned int c switch (cmd) { case GNTTABOP_map_grant_ref: case GNTTABOP_unmap_grant_ref: + case GNTTABOP_unmap_and_replace: break; case GNTTABOP_setup_table: { diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c Thu Jun 07 17:39:12 2007 +0900 @@ -70,6 +70,9 @@ xencommize_mini_grant_table_op(struct xe case GNTTABOP_unmap_grant_ref: argsize = sizeof(struct gnttab_unmap_grant_ref); break; + case GNTTABOP_unmap_and_replace: + argsize = sizeof(struct gnttab_unmap_and_replace); + break; case GNTTABOP_setup_table: { struct gnttab_setup_table *setup = op; diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/arch/ia64/xen/xen_dma.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/xen_dma.c Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xen_dma.c Thu Jun 07 17:39:12 2007 +0900 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define IOMMU_BUG_ON(test) \ do { \ @@ -57,7 +59,7 @@ xen_map_sg(struct device *hwdev, struct int i; for (i = 0 ; i < nents ; i++) { - sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset; + sg[i].dma_address = gnttab_dma_map_page(sg[i].page) + sg[i].offset; sg[i].dma_length = sg[i].length; IOMMU_BUG_ON(address_needs_mapping(hwdev, sg[i].dma_address)); @@ -71,6 +73,9 @@ xen_unmap_sg(struct device *hwdev, struc xen_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, int direction) { + int i; + for (i = 0; i < nents; i++) + __gnttab_dma_unmap_page(sg[i].page); } EXPORT_SYMBOL(xen_unmap_sg); @@ -128,7 +133,7 @@ xen_map_single(struct device *dev, void xen_map_single(struct device *dev, void *ptr, size_t size, int direction) { - dma_addr_t dma_addr = virt_to_bus(ptr); + dma_addr_t dma_addr = gnttab_dma_map_virt(ptr); IOMMU_BUG_ON(range_straddles_page_boundary(ptr, size)); IOMMU_BUG_ON(address_needs_mapping(dev, dma_addr)); @@ -141,5 +146,6 @@ xen_unmap_single(struct device *dev, dma xen_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, int direction) { + gnttab_dma_unmap_page(dma_addr); } EXPORT_SYMBOL(xen_unmap_single); diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/include/asm-ia64/gnttab_dma.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/include/asm-ia64/gnttab_dma.h Thu Jun 07 17:39:12 2007 +0900 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007 Herbert Xu + * Copyright (c) 2007 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_IA64_GNTTAB_DMA_H +#define _ASM_IA64_GNTTAB_DMA_H + +/* caller must get dma address after calling this function */ +static inline void gnttab_dma_use_page(struct page *page) +{ + __gnttab_dma_map_page(page, NULL); +} + +static inline dma_addr_t gnttab_dma_map_page(struct page *page) +{ + gnttab_dma_use_page(page); + return page_to_bus(page); +} + +static inline dma_addr_t gnttab_dma_map_virt(void *ptr) +{ + return gnttab_dma_map_page(virt_to_page(ptr)) + offset_in_page(ptr); +} + +static inline void gnttab_dma_unmap_page(dma_addr_t dma_address) +{ + __gnttab_dma_unmap_page(virt_to_page(bus_to_virt(dma_address))); +} + +#endif /* _ASM_IA64_GNTTAB_DMA_H */ diff -r ca58c12a9dff -r ce1c94602516 linux-2.6-xen-sparse/include/asm-ia64/hypercall.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Thu Jun 07 17:22:17 2007 +0900 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Thu Jun 07 17:39:12 2007 +0900 @@ -422,4 +422,7 @@ xencomm_arch_hypercall_fpswa_revision(st #define HYPERVISOR_suspend xencomm_hypercall_suspend #define HYPERVISOR_vcpu_op xencomm_hypercall_vcpu_op +/* to compile gnttab_copy_grant_page() in drivers/xen/core/gnttab.c */ +#define HYPERVISOR_mmu_update(req, count, success_count, domid) ({BUG();0;}) + #endif /* __HYPERCALL_H__ */