Messages in this thread Patch in this message | | | From | Becky Bruce <> | Subject | Re: [PATCH V2 2/3] powerpc: Add support for swiotlb on 32-bit | Date | Wed, 27 May 2009 14:05:08 -0500 |
| |
On May 22, 2009, at 6:11 AM, Ian Campbell wrote: > > > BTW do you need swiotlb_bus_to_virt to be __weak or is the fact that > it > is implemented in terms of swiotlb_bus_to_phys sufficient?
The default one in swiotlb calls phys_to_virt on the result of swiotlb_bus_to_phys, which only works on lowmem.
> > > I have an appointment all afternoon and it's a bank holiday on Monday > but here is my WIP patch as an example of what I'm thinking. Obviously > some cleanups are still very much required: > * The Xen specific stuff in arch/x86/include/asm/dma-mapping.h > clearly needs to be properly abstracted away (I just stuck it > there for testing). > * swiotlb_phys_to_bus and swiotlb_bus_to_phys need to move to > arch/*/include/asm/dma-mapping.h instead of being __weak > * Maybe swiotlb_bus_to_virt can become static again. > * Need to finish auditing the handful of non-swiotlb users of > is_buffer_dma_capable. > * It might be possible to implement swiolb_dma_mapping_error > and/or swiotlb_dma_supported in terms of dma_map_range. > * Minor detail: it doesn't actually work at the moment ;-)
Minor detail :)
I'm in the same boat- been offline most of the week and will continue to be offline (I'm sneaking in an hour here to read emails!!!!) until sometime next week. I'm in the middle of a big lab construction and move project. I'll take a look as soon as I can - thanks!
-Becky
> > > Ian. > > diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/ > asm/dma-mapping.h > index 36c0009..026667f 100644 > --- a/arch/ia64/include/asm/dma-mapping.h > +++ b/arch/ia64/include/asm/dma-mapping.h > @@ -174,4 +174,12 @@ dma_cache_sync (struct device *dev, void > *vaddr, size_t size, > > #define dma_is_consistent(d, h) (1) /* all we do is coherent > memory... */ > > +static inline dma_addr_t dma_map_range(struct device *dev, u64 mask, > + phys_addr_t addr, size_t size) > +{ > + if (addr + size <= mask) > + return addr; > + return 0; > +} > + > #endif /* _ASM_IA64_DMA_MAPPING_H */ > diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/ > asm/dma-mapping.h > index 916cbb6..b2813ab 100644 > --- a/arch/x86/include/asm/dma-mapping.h > +++ b/arch/x86/include/asm/dma-mapping.h > @@ -309,4 +309,20 @@ static inline void dma_free_coherent(struct > device *dev, size_t size, > ops->free_coherent(dev, size, vaddr, bus); > } > > +static inline dma_addr_t dma_map_range(struct device *dev, u64 mask, > + phys_addr_t addr, size_t size) > +{ > + dma_addr_t dma_addr; > +#ifdef CONFIG_XEN > + extern int xen_range_needs_mapping(phys_addr_t paddr, size_t size); > + if (xen_pv_domain() && xen_range_needs_mapping(addr, size)) > + return 0; > +#endif > + > + dma_addr = swiotlb_phys_to_bus(dev, addr); > + if (dma_addr + size <= mask) > + return 0; > + return dma_addr; > +} > + > #endif > diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c > index 2fffc22..c2b4196 100644 > --- a/arch/x86/kernel/pci-dma.c > +++ b/arch/x86/kernel/pci-dma.c > @@ -145,8 +145,8 @@ again: > if (!page) > return NULL; > > - addr = page_to_phys(page); > - if (!is_buffer_dma_capable(dma_mask, addr, size)) { > + addr = dma_map_range(dev, dma_mask, page_to_phys(page), size); > + if (!(addr == 0)) { > __free_pages(page, get_order(size)); > > if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) { > diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci- > gart_64.c > index 1e8920d..6a55770 100644 > --- a/arch/x86/kernel/pci-gart_64.c > +++ b/arch/x86/kernel/pci-gart_64.c > @@ -191,13 +191,13 @@ static inline int > need_iommu(struct device *dev, unsigned long addr, size_t size) > { > return force_iommu || > - !is_buffer_dma_capable(*dev->dma_mask, addr, size); > + dma_map_range(dev, *dev->dma_mask, addr, size) == 0; > } > > static inline int > nonforced_iommu(struct device *dev, unsigned long addr, size_t size) > { > - return !is_buffer_dma_capable(*dev->dma_mask, addr, size); > + return dma_map_range(dev, *dev->dma_mask, addr, size) == 0; > } > > /* Map a single continuous physical area into the IOMMU. > diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c > index 71d412a..712ce59 100644 > --- a/arch/x86/kernel/pci-nommu.c > +++ b/arch/x86/kernel/pci-nommu.c > @@ -12,13 +12,13 @@ > #include <asm/dma.h> > > static int > -check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t > size) > +check_addr(char *name, struct device *hwdev, phys_addr_t phys, > size_t size) > { > - if (hwdev && !is_buffer_dma_capable(*hwdev->dma_mask, bus, size)) { > + if (hwdev && dma_map_range(hwdev, *hwdev->dma_mask, phys, size) == > 0) { > if (*hwdev->dma_mask >= DMA_BIT_MASK(32)) > printk(KERN_ERR > "nommu_%s: overflow %Lx+%zu of device mask %Lx\n", > - name, (long long)bus, size, > + name, (long long)phys, size, > (long long)*hwdev->dma_mask); > return 0; > } > @@ -30,12 +30,12 @@ static dma_addr_t nommu_map_page(struct device > *dev, struct page *page, > enum dma_data_direction dir, > struct dma_attrs *attrs) > { > - dma_addr_t bus = page_to_phys(page) + offset; > + phys_addr_t phys = page_to_phys(page) + offset; > WARN_ON(size == 0); > - if (!check_addr("map_single", dev, bus, size)) > + if (!check_addr("map_single", dev, phys, size)) > return bad_dma_address; > flush_write_buffers(); > - return bus; > + return phys; > } > > /* Map a set of buffers described by scatterlist in streaming > diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h > index 8083b6a..85dafa1 100644 > --- a/include/linux/dma-mapping.h > +++ b/include/linux/dma-mapping.h > @@ -96,11 +96,6 @@ static inline int is_device_dma_capable(struct > device *dev) > return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE; > } > > -static inline int is_buffer_dma_capable(u64 mask, dma_addr_t addr, > size_t size) > -{ > - return addr + size <= mask; > -} > - > #ifdef CONFIG_HAS_DMA > #include <asm/dma-mapping.h> > #else > diff --git a/lib/swiotlb.c b/lib/swiotlb.c > index cec5f62..4fd5185 100644 > --- a/lib/swiotlb.c > +++ b/lib/swiotlb.c > @@ -147,17 +147,6 @@ void * __weak swiotlb_bus_to_virt(struct device > *hwdev, dma_addr_t address) > return phys_to_virt(swiotlb_bus_to_phys(hwdev, address)); > } > > -int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev, > - dma_addr_t addr, size_t size) > -{ > - return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); > -} > - > -int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, > size_t size) > -{ > - return 0; > -} > - > static void swiotlb_print_info(unsigned long bytes) > { > phys_addr_t pstart, pend; > @@ -318,17 +307,6 @@ cleanup1: > return -ENOMEM; > } > > -static inline int > -address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t > size) > -{ > - return swiotlb_arch_address_needs_mapping(hwdev, addr, size); > -} > - > -static inline int range_needs_mapping(phys_addr_t paddr, size_t size) > -{ > - return swiotlb_force || swiotlb_arch_range_needs_mapping(paddr, > size); > -} > - > static int is_swiotlb_buffer(char *addr) > { > return addr >= io_tlb_start && addr < io_tlb_end; > @@ -555,18 +533,17 @@ void * > swiotlb_alloc_coherent(struct device *hwdev, size_t size, > dma_addr_t *dma_handle, gfp_t flags) > { > - dma_addr_t dev_addr; > + phys_addr_t phys; > void *ret; > int order = get_order(size); > u64 dma_mask = DMA_BIT_MASK(32); > + dma_addr_t dma_addr; > > if (hwdev && hwdev->coherent_dma_mask) > dma_mask = hwdev->coherent_dma_mask; > > ret = (void *)__get_free_pages(flags, order); > - if (ret && > - !is_buffer_dma_capable(dma_mask, swiotlb_virt_to_bus(hwdev, > ret), > - size)) { > + if (ret && dma_map_range(hwdev, dma_mask, virt_to_phys(ret), size) > == 0) { > /* > * The allocated memory isn't reachable by the device. > */ > @@ -585,19 +562,20 @@ swiotlb_alloc_coherent(struct device *hwdev, > size_t size, > } > > memset(ret, 0, size); > - dev_addr = swiotlb_virt_to_bus(hwdev, ret); > + phys = virt_to_phys(ret); > > /* Confirm address can be DMA'd by device */ > - if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) { > - printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", > + dma_addr = dma_map_range(hwdev, dma_mask, phys, size); > + if (dma_addr == 0) { > + printk("hwdev DMA mask = 0x%016Lx, physical addr = 0x%016Lx\n", > (unsigned long long)dma_mask, > - (unsigned long long)dev_addr); > + (unsigned long long)phys); > > /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ > do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE); > return NULL; > } > - *dma_handle = dev_addr; > + *dma_handle = dma_addr; > return ret; > } > EXPORT_SYMBOL(swiotlb_alloc_coherent); > @@ -649,7 +627,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, > struct page *page, > struct dma_attrs *attrs) > { > phys_addr_t phys = page_to_phys(page) + offset; > - dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys); > + dma_addr_t dma_addr; > void *map; > > BUG_ON(dir == DMA_NONE); > @@ -658,9 +636,9 @@ dma_addr_t swiotlb_map_page(struct device *dev, > struct page *page, > * we can safely return the device addr and not worry about bounce > * buffering it. > */ > - if (!address_needs_mapping(dev, dev_addr, size) && > - !range_needs_mapping(phys, size)) > - return dev_addr; > + dma_addr = dma_map_range(dev, dma_get_mask(dev), phys, size); > + if (dma_addr && !swiotlb_force) > + return dma_addr; > > /* > * Oh well, have to allocate and map a bounce buffer. > @@ -671,15 +649,14 @@ dma_addr_t swiotlb_map_page(struct device > *dev, struct page *page, > map = io_tlb_overflow_buffer; > } > > - dev_addr = swiotlb_virt_to_bus(dev, map); > - > /* > * Ensure that the address returned is DMA'ble > */ > - if (address_needs_mapping(dev, dev_addr, size)) > + dma_addr = dma_map_range(dev, dma_get_mask(dev), > virt_to_phys(map), size); > + if (dma_addr == 0) > panic("map_single: bounce buffer is not DMA'ble"); > > - return dev_addr; > + return dma_addr; > } > EXPORT_SYMBOL_GPL(swiotlb_map_page); > > @@ -820,10 +797,8 @@ swiotlb_map_sg_attrs(struct device *hwdev, > struct scatterlist *sgl, int nelems, > > for_each_sg(sgl, sg, nelems, i) { > phys_addr_t paddr = sg_phys(sg); > - dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr); > - > - if (range_needs_mapping(paddr, sg->length) || > - address_needs_mapping(hwdev, dev_addr, sg->length)) { > + dma_addr_t dma_addr = dma_map_range(hwdev, dma_get_mask(hwdev), > paddr, sg->length); > + if (dma_addr == 0 || swiotlb_force) { > void *map = map_single(hwdev, sg_phys(sg), > sg->length, dir); > if (!map) { > @@ -835,9 +810,9 @@ swiotlb_map_sg_attrs(struct device *hwdev, > struct scatterlist *sgl, int nelems, > sgl[0].dma_length = 0; > return 0; > } > - sg->dma_address = swiotlb_virt_to_bus(hwdev, map); > - } else > - sg->dma_address = dev_addr; > + dma_addr = dma_map_range(hwdev, dma_get_mask(hwdev), > virt_to_phys(map), sg->length); > + } > + sg->dma_address = dma_addr; > sg->dma_length = sg->length; > } > return nelems; >
| |