From mboxrd@z Thu Jan 1 00:00:00 1970 From: Helge Deller Date: Sat, 21 Apr 2018 17:43:46 +0000 Subject: Re: [PATCH 22/22] parisc: use generic dma_noncoherent_ops Message-Id: List-Id: References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> In-Reply-To: <20180420080313.18796-23-hch@lst.de> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: Christoph Hellwig Cc: linux-arch@vger.kernel.org, Michal Simek , Vincent Chen , linux-c6x-dev@linux-c6x.org, linux-parisc@vger.kernel.org, linux-sh@vger.kernel.org, linux-hexagon@vger.kernel.org, linux-kernel@vger.kernel.org, linux-m68k@lists.linux-m68k.org, openrisc@lists.librecores.org, Greentime Hu , linux-alpha@vger.kernel.org, sparclinux@vger.kernel.org, nios2-dev@lists.rocketboards.org, linux-snps-arc@lists.infradead.org, linux-arm-kernel@lists.infradead.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction = DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction = DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction = DMA_TO_DEVICE) > + if (dir = DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction = DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction = DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction = DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction = DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction = DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) = 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type = pcxl2 || boot_cpu_data.cpu_type = pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type = pcxl2 || boot_cpu_data.cpu_type = pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops = &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type = pcxl2 || boot_cpu_data.cpu_type = pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Helge Deller Subject: Re: [PATCH 22/22] parisc: use generic dma_noncoherent_ops Date: Sat, 21 Apr 2018 19:43:46 +0200 Message-ID: References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Cc: linux-arch@vger.kernel.org, Michal Simek , Vincent Chen , linux-c6x-dev@linux-c6x.org, linux-parisc@vger.kernel.org, linux-sh@vger.kernel.org, linux-hexagon@vger.kernel.org, linux-kernel@vger.kernel.org, linux-m68k@lists.linux-m68k.org, openrisc@lists.librecores.org, Greentime Hu , linux-alpha@vger.kernel.org, sparclinux@vger.kernel.org, nios2-dev@lists.rocketboards.org, linux-snps-arc@lists.infradead.org, linux-arm-kernel@lists.infradead.org To: Christoph Hellwig Return-path: In-Reply-To: <20180420080313.18796-23-hch@lst.de> List-Id: Linux on Synopsys ARC Processors List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linux-snps-arc-bounces+gla-linux-snps-arc=m.gmane.org@lists.infradead.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753241AbeDURoS (ORCPT ); Sat, 21 Apr 2018 13:44:18 -0400 Received: from mout.gmx.net ([212.227.17.21]:45271 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752911AbeDURoN (ORCPT ); Sat, 21 Apr 2018 13:44:13 -0400 Subject: Re: [PATCH 22/22] parisc: use generic dma_noncoherent_ops To: Christoph Hellwig Cc: linux-arch@vger.kernel.org, Michal Simek , Greentime Hu , Vincent Chen , linux-alpha@vger.kernel.org, linux-snps-arc@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-c6x-dev@linux-c6x.org, linux-hexagon@vger.kernel.org, linux-m68k@vger.kernel.org, nios2-dev@lists.rocketboards.org, openrisc@lists.librecores.org, linux-parisc@vger.kernel.org, linux-sh@vger.kernel.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> From: Helge Deller Message-ID: Date: Sat, 21 Apr 2018 19:43:46 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2 MIME-Version: 1.0 In-Reply-To: <20180420080313.18796-23-hch@lst.de> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Provags-ID: V03:K1:ru/tGzmF2CfbTAiAG4zvEGzI7ebdGuQP/m/ZEQ9asHx+hC/VmSx jdDChQB+7NoeSyYmYdccvLcyNEtVKZ7mDFvwW/tk34KlN5SDnUde1K5eSWaTrafW7WYz6Uk VT6vFieNoYRMFdJtejkI5Z2Ukij8QdhtZHSpxMPlHhpTDnwoGi1E17pct317Rc7hsqGvjAA aGiF4eVQowPugMPW8+w7w== X-UI-Out-Filterresults: notjunk:1;V01:K0:aom1hrK4FWQ=:DM9tLV23QMjAGWncynBhqF oMRYxEwQA4ZlE7fzqtyWgw9W9s2ywcR7X7E4FCHNVXJGA8AFQjbZDZB7DHN2x1KZid5QNOxKV 1yvjsXIVapigYTle/YAwfetLnZrnGXIlr8k8HtgwAZfkV2zc8Z7bZwFbTUwKAv3G4oFmX82DQ 3onz+H2/Y6H0tSDf5ptbTUxxdnwbgPBveKwj0O+ovqgfnhkmzSu5dEBdeK3ZaiA6HLktJgg1U ++gjkktmrTIdr27YcdxjVPv1rtusCPwnwL6L5o+C84EfiGk+61mt0pkImeiDOjTzppeIB8wym PF/AAmBiYAZAMNdaKk7v58M5iR4TecCtWkUZaGVv6J1azxv58/iVCllGuxm4AEKp5JSo8pat+ PdixteQFXFJIuaUKLYG89e5QQTfd4YyseXlLrDVUxkY8lIJwlebj0Vy7jIN+6Xq8+DxFG5jqK YYiTN1TNSb9OquLljaTz9GdHf3oepMUYt5yULtwNbioxGIkdwMVm5dRzcrFw762TNdtbzisCV PPxpWdB3YR2oe6HVARbzZ535W+tQ/AV4WtIlR+gsBXeRKBjuXdJdeH7uO1OY8cgc/z+mBbQ4V viA+IknP5niyYjUTX2abh+eSRLKnX+hq4sIqyULZB99cMBcaiNEIpVRtf0Osg/3vDp9pWFpTj 3utMgk8CkryClTldWEJMB2tYKV+wK86Tb7o5ws6KMZK2mMQLuZJ8yf4XWdvNHcQzHHTgbaLZK 7NZkazugsvzIdXm9h7NABK2fJcG4ExyP3lkURhD4PEG8np+dhZ1q6oxeekKyU3UYQxsjzMuJ9 Zuk6RQHmqo6nPItoTPTqsConzscWyWaTbyGVlafXm66pjDUJ34= Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mout.gmx.net ([212.227.17.21]:45271 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752911AbeDURoN (ORCPT ); Sat, 21 Apr 2018 13:44:13 -0400 Subject: Re: [PATCH 22/22] parisc: use generic dma_noncoherent_ops References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> From: Helge Deller Message-ID: Date: Sat, 21 Apr 2018 19:43:46 +0200 MIME-Version: 1.0 In-Reply-To: <20180420080313.18796-23-hch@lst.de> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-arch-owner@vger.kernel.org List-ID: To: Christoph Hellwig Cc: linux-arch@vger.kernel.org, Michal Simek , Greentime Hu , Vincent Chen , linux-alpha@vger.kernel.org, linux-snps-arc@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-c6x-dev@linux-c6x.org, linux-hexagon@vger.kernel.org, linux-m68k@lists.linux-m68k.org, nios2-dev@lists.rocketboards.org, openrisc@lists.librecores.org, linux-parisc@vger.kernel.org, linux-sh@vger.kernel.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org Message-ID: <20180421174346.51CIWRdpY08d-DdjZT-NOp9nAwUefBmzbRbTQOWSQng@z> On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: deller@gmx.de (Helge Deller) Date: Sat, 21 Apr 2018 19:43:46 +0200 Subject: [PATCH 22/22] parisc: use generic dma_noncoherent_ops In-Reply-To: <20180420080313.18796-23-hch@lst.de> References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> List-ID: Message-ID: To: linux-snps-arc@lists.infradead.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: deller@gmx.de (Helge Deller) Date: Sat, 21 Apr 2018 19:43:46 +0200 Subject: [PATCH 22/22] parisc: use generic dma_noncoherent_ops In-Reply-To: <20180420080313.18796-23-hch@lst.de> References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Helge Deller Date: Sat, 21 Apr 2018 19:43:46 +0200 Subject: [OpenRISC] [PATCH 22/22] parisc: use generic dma_noncoherent_ops In-Reply-To: <20180420080313.18796-23-hch@lst.de> References: <20180420080313.18796-1-hch@lst.de> <20180420080313.18796-23-hch@lst.de> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: openrisc@lists.librecores.org On 20.04.2018 10:03, Christoph Hellwig wrote: > Switch to the generic noncoherent direct mapping implementation. > > Parisc previously had two different non-coherent dma ops implementation > that just different in the way coherent allocations were handled or not > handled. The different behavior is not selected at runtime in the > arch_dma_alloc and arch_dma_free routines. The non-coherent allocation > in the pcx cases now uses the dma_direct helpers that are a little more > sophisticated and used by a lot of other architectures. > > Fix sync_single_for_cpu to do skip the cache flush unless the transfer > is to the device to match the more tested unmap_single path which should > have the same cache coherency implications. > > This also now consistenly uses flush_kernel_dcache_range for cache > flushing while previously some of the SG based operations used > flush_kernel_vmap_range instead. This patch breaks a 32bit kernel on a B160L machine (PA7300LC CPU, "pcxl2"). After applying this patch series the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work. See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions. Helge > Signed-off-by: Christoph Hellwig > --- > arch/parisc/Kconfig | 4 + > arch/parisc/include/asm/dma-mapping.h | 5 - > arch/parisc/kernel/pci-dma.c | 181 ++++---------------------- > arch/parisc/kernel/setup.c | 8 +- > arch/parisc/mm/init.c | 11 +- > 5 files changed, 35 insertions(+), 174 deletions(-) > > diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig > index 47047f0cbe35..80166a1cbcb7 100644 > --- a/arch/parisc/Kconfig > +++ b/arch/parisc/Kconfig > @@ -188,6 +188,10 @@ config PA20 > config PA11 > def_bool y > depends on PA7000 || PA7100LC || PA7200 || PA7300LC > + select ARCH_HAS_SYNC_DMA_FOR_CPU > + select ARCH_HAS_SYNC_DMA_FOR_DEVICE > + select DMA_NONCOHERENT_OPS > + select DMA_NONCOHERENT_CACHE_SYNC > > config PREFETCH > def_bool y > diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h > index 01e1fc057c83..44a9f97194aa 100644 > --- a/arch/parisc/include/asm/dma-mapping.h > +++ b/arch/parisc/include/asm/dma-mapping.h > @@ -21,11 +21,6 @@ > ** flush/purge and allocate "regular" cacheable pages for everything. > */ > > -#ifdef CONFIG_PA11 > -extern const struct dma_map_ops pcxl_dma_ops; > -extern const struct dma_map_ops pcx_dma_ops; > -#endif > - > extern const struct dma_map_ops *hppa_dma_ops; > > static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) > diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c > index 91bc0cac03a1..235e2e53959e 100644 > --- a/arch/parisc/kernel/pci-dma.c > +++ b/arch/parisc/kernel/pci-dma.c > @@ -21,13 +21,12 @@ > #include > #include > #include > -#include > #include > #include > #include > #include > -#include > -#include > +#include > +#include > > #include > #include /* for DMA_CHUNK_SIZE */ > @@ -447,178 +446,48 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, > free_pages((unsigned long)__va(dma_handle), order); > } > > -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, > - unsigned long offset, size_t size, > - enum dma_data_direction direction, unsigned long attrs) > +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - void *addr = page_address(page) + offset; > - BUG_ON(direction == DMA_NONE); > - > - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) > - flush_kernel_dcache_range((unsigned long) addr, size); > - > - return virt_to_phys(addr); > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, > - size_t size, enum dma_data_direction direction, > - unsigned long attrs) > +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, > + size_t size, enum dma_data_direction dir) > { > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > + if (dir == DMA_TO_DEVICE) > return; > > /* > - * For PCI_DMA_FROMDEVICE this flush is not necessary for the > + * For DMA_FROM_DEVICE this flush is not necessary for the > * simple map/unmap case. However, it IS necessary if if > - * pci_dma_sync_single_* has been called and the buffer reused. > + * dma_sync_single_* has been called and the buffer reused. > */ > > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); > -} > - > -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - for_each_sg(sglist, sg, nents, i) { > - unsigned long vaddr = (unsigned long)sg_virt(sg); > - > - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); > - sg_dma_len(sg) = sg->length; > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - continue; > - > - flush_kernel_dcache_range(vaddr, sg->length); > - } > - return nents; > + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); > } > > -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, > - int nents, enum dma_data_direction direction, > - unsigned long attrs) > -{ > - int i; > - struct scatterlist *sg; > - > - BUG_ON(direction == DMA_NONE); > - > - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) > - return; > - > - if (direction == DMA_TO_DEVICE) > - return; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_single_for_cpu(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_single_for_device(struct device *dev, > - dma_addr_t dma_handle, size_t size, > - enum dma_data_direction direction) > -{ > - BUG_ON(direction == DMA_NONE); > - > - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), > - size); > -} > - > -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) > -{ > - int i; > - struct scatterlist *sg; > - > - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ > - > - for_each_sg(sglist, sg, nents, i) > - flush_kernel_vmap_range(sg_virt(sg), sg->length); > -} > - > -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, > enum dma_data_direction direction) > { > flush_kernel_dcache_range((unsigned long)vaddr, size); > } > > -const struct dma_map_ops pcxl_dma_ops = { > - .alloc = pa11_dma_alloc, > - .free = pa11_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > - > -static void *pcx_dma_alloc(struct device *dev, size_t size, > - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) > +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, > + gfp_t gfp, unsigned long attrs) > { > - void *addr; > - > - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) > - return NULL; > - > - addr = (void *)__get_free_pages(flag, get_order(size)); > - if (addr) > - *dma_handle = (dma_addr_t)virt_to_phys(addr); > - > - return addr; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + return pa11_dma_alloc(dev, size, dma_handle, gfp, attrs); > + if (attrs & DMA_ATTR_NON_CONSISTENT) > + return dma_direct_alloc(dev, size, dma_handle, gfp, attrs); > + return NULL; > } > > -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, > - dma_addr_t iova, unsigned long attrs) > +void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, > + dma_addr_t dma_addr, unsigned long attrs) > { > - free_pages((unsigned long)vaddr, get_order(size)); > - return; > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) > + pa11_dma_free(dev, size, cpu_addr, dma_addr, attrs); > + else > + dma_direct_free(dev, size, cpu_addr, dma_addr, attrs); > } > - > -const struct dma_map_ops pcx_dma_ops = { > - .alloc = pcx_dma_alloc, > - .free = pcx_dma_free, > - .map_page = pa11_dma_map_page, > - .unmap_page = pa11_dma_unmap_page, > - .map_sg = pa11_dma_map_sg, > - .unmap_sg = pa11_dma_unmap_sg, > - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, > - .sync_single_for_device = pa11_dma_sync_single_for_device, > - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, > - .sync_sg_for_device = pa11_dma_sync_sg_for_device, > - .cache_sync = pa11_dma_cache_sync, > -}; > diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c > index 8d3a7b80ac42..4e87c35c22b7 100644 > --- a/arch/parisc/kernel/setup.c > +++ b/arch/parisc/kernel/setup.c > @@ -97,14 +97,12 @@ void __init dma_ops_init(void) > panic( "PA-RISC Linux currently only supports machines that conform to\n" > "the PA-RISC 1.1 or 2.0 architecture specification.\n"); > > - case pcxs: > - case pcxt: > - hppa_dma_ops = &pcx_dma_ops; > - break; > case pcxl2: > pa7300lc_init(); > case pcxl: /* falls through */ > - hppa_dma_ops = &pcxl_dma_ops; > + case pcxs: > + case pcxt: > + hppa_dma_ops = &dma_noncoherent_ops; > break; > default: > break; > diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c > index cab32ee824d2..4ad91c28ecbe 100644 > --- a/arch/parisc/mm/init.c > +++ b/arch/parisc/mm/init.c > @@ -19,7 +19,6 @@ > #include > #include > #include > -#include /* for hppa_dma_ops and pcxl_dma_ops */ > #include > #include > #include > @@ -616,17 +615,13 @@ void __init mem_init(void) > free_all_bootmem(); > > #ifdef CONFIG_PA11 > - if (hppa_dma_ops == &pcxl_dma_ops) { > + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { > pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); > parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start > + PCXL_DMA_MAP_SIZE); > - } else { > - pcxl_dma_start = 0; > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > - } > -#else > - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > + } else > #endif > + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); > > mem_init_print_info(NULL); > >