From mboxrd@z Thu Jan 1 00:00:00 1970 From: Greg Ungerer Subject: Re: [PATCH 3/4 V2] Add for MCF54xx a virtual non cached zone usable for data exchange with DMA Date: Tue, 16 Oct 2012 15:15:58 +1000 Message-ID: <507CED8E.1000004@snapgear.com> References: <1350305680-5441-3-git-send-email-stany.marcel@novasys-ingenierie.com> <1350307324-7396-1-git-send-email-stany.marcel@novasys-ingenierie.com> Mime-Version: 1.0 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit Return-path: Received: from dalsmrelay2.nai.com ([205.227.136.216]:39121 "EHLO dalsmrelay2.nai.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752100Ab2JPFT2 (ORCPT ); Tue, 16 Oct 2012 01:19:28 -0400 In-Reply-To: <1350307324-7396-1-git-send-email-stany.marcel@novasys-ingenierie.com> Sender: linux-m68k-owner@vger.kernel.org List-Id: linux-m68k@vger.kernel.org To: Stany MARCEL Cc: linux-m68k@vger.kernel.org, gerg@uclinux.org Hi Stany, On 15/10/12 23:22, Stany MARCEL wrote: > This permit to share data with DMA without caching issues. M54xx DMA bypass > cache so exchanged data must be flushed before DMA operation. But M54xx cache > opperation does not permit to easily flush concerned data. So this patch permit > to have a non cached zone used for GFP_DMA allocated data. Interesting, but I think this is the wrong approach. We don't want to bypass the cache. Admittedly the current cache support code we have for ColdFire is not great, it could be improved a lot. So lets do that, not work around it. Regards Greg > Signed-off-by: Stany MARCEL > --- > > Changes: > V2: This patch does not touch ACR anymore, ACR cache mode is only > modified by following patch that is now independant. > > arch/m68k/Kconfig.machine | 32 +++++++++++++++++ > arch/m68k/include/asm/dma.h | 8 +++++ > arch/m68k/include/asm/mcf_pgalloc.h | 6 ++-- > arch/m68k/include/asm/page_mm.h | 68 ++++++++++++++++++++++++++++++++++- > arch/m68k/kernel/dma.c | 14 ++++++++ > arch/m68k/mm/mcfmmu.c | 38 ++++++++++++++++++++ > arch/m68k/platform/coldfire/head.S | 31 ++++++++++++++++ > arch/m68k/platform/coldfire/m54xx.c | 21 +++++++++++ > 8 files changed, 214 insertions(+), 4 deletions(-) > > diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine > index 7cdf6b0..f9a4d9d 100644 > --- a/arch/m68k/Kconfig.machine > +++ b/arch/m68k/Kconfig.machine > @@ -512,6 +512,38 @@ config KERNELBASE > a system with the RAM based at address 0, and leaving enough room > for the theoretical maximum number of 256 vectors. > > +config M54xx_DMA_ZONE > + bool "M54xx non cached virtual zone for DMA" > + depends on MMU > + depends on M54xx > + select SINGLE_MEMORY_CHUNK > + help > + Activate a virtual zone with tlb data entries initialized, in non > + cached precise mode. This permit to share data with DMA without caching > + issues. M54xx DMA bypass cache so exchanged data must be flushed > + before DMA operation. But M54xx cache opperation does not permit to > + easily flush concerned data. So this patch permit to have a non cached > + zone used for GFP_DMA allocated data. > + > +config M54xx_DMA_ZONE_BASE > + hex "Address of the base of a vitual non cached zone usable for DMA" > + depends on M54xx_DMA_ZONE > + default 0xC0000000 > + help > + Define the address of a virtual zone, with tlb data entries > + initialized, in non cached precise mode. > + Addresse must be 1MB aligned, not already mapped and different than > + KMAP and VM memory map > + > +config M54xx_DMA_ZONE_SIZE > + hex "Size of the vitual non cached zone usable for DMA" > + depends on M54xx_DMA_ZONE > + default 0x800000 > + help > + Define the size of a virtual zone, with tlb data entries > + initialized, in non cached precise mode. > + Size must be 1MB divisable. > + > comment "ROM configuration" > > config ROM > diff --git a/arch/m68k/include/asm/dma.h b/arch/m68k/include/asm/dma.h > index 0ff3fc6..04e5d2c 100644 > --- a/arch/m68k/include/asm/dma.h > +++ b/arch/m68k/include/asm/dma.h > @@ -479,10 +479,18 @@ static __inline__ int get_dma_residue(unsigned int dmanr) > #endif /* !defined(CONFIG_M5272) */ > #endif /* CONFIG_COLDFIRE */ > > +#if defined(CONFIG_M54xx_DMA_ZONE) > + > +#define MAX_DMA_ADDRESS (CONFIG_M54xx_DMA_ZONE_BASE + \ > + CONFIG_M54xx_DMA_ZONE_SIZE - 1) > + > +#else > /* it's useless on the m68k, but unfortunately needed by the new > bootmem allocator (but this should do it for this) */ > #define MAX_DMA_ADDRESS PAGE_OFFSET > > +#endif > + > #define MAX_DMA_CHANNELS 8 > > extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ > diff --git a/arch/m68k/include/asm/mcf_pgalloc.h b/arch/m68k/include/asm/mcf_pgalloc.h > index 313f3dd..7fbb5ce 100644 > --- a/arch/m68k/include/asm/mcf_pgalloc.h > +++ b/arch/m68k/include/asm/mcf_pgalloc.h > @@ -14,7 +14,7 @@ extern const char bad_pmd_string[]; > extern inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, > unsigned long address) > { > - unsigned long page = __get_free_page(GFP_DMA|__GFP_REPEAT); > + unsigned long page = __get_free_page(GFP_KERNEL|__GFP_REPEAT); > > if (!page) > return NULL; > @@ -51,7 +51,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page, > static inline struct page *pte_alloc_one(struct mm_struct *mm, > unsigned long address) > { > - struct page *page = alloc_pages(GFP_DMA|__GFP_REPEAT, 0); > + struct page *page = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); > pte_t *pte; > > if (!page) > @@ -89,7 +89,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) > { > pgd_t *new_pgd; > > - new_pgd = (pgd_t *)__get_free_page(GFP_DMA | __GFP_NOWARN); > + new_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_NOWARN); > if (!new_pgd) > return NULL; > memcpy(new_pgd, swapper_pg_dir, PAGE_SIZE); > diff --git a/arch/m68k/include/asm/page_mm.h b/arch/m68k/include/asm/page_mm.h > index 89f2014..7985ffd 100644 > --- a/arch/m68k/include/asm/page_mm.h > +++ b/arch/m68k/include/asm/page_mm.h > @@ -70,6 +70,8 @@ extern unsigned long m68k_memoffset; > > #define WANT_PAGE_VIRTUAL > > +#ifndef CONFIG_M54xx_DMA_ZONE > + > static inline unsigned long ___pa(void *vaddr) > { > unsigned long paddr; > @@ -91,6 +93,58 @@ static inline void *__va(unsigned long paddr) > : "0" (paddr), "i" (m68k_fixup_memoffset)); > return vaddr; > } > +#else /* !CONFIG_M54xx_DMA_ZONE */ > + > +extern unsigned long m54xx_dma_base; > +extern unsigned long m54xx_dma_end; > + > +/* > + * Convert a virt to a phys > + */ > +static inline unsigned long ___pa(void *vaddr) > +{ > +#if CONFIG_RAMBASE != PAGE_OFFSET > + return ((unsigned long)vaddr & 0x0fffffff) + CONFIG_RAMBASE; > +#else > + if ((unsigned long)vaddr >= CONFIG_M54xx_DMA_ZONE_BASE && > + (unsigned long)vaddr < (CONFIG_M54xx_DMA_ZONE_BASE + > + CONFIG_M54xx_DMA_ZONE_SIZE)) { > + /* address is in carved out DMA range */ > + return ((unsigned long)vaddr - CONFIG_M54xx_DMA_ZONE_BASE) > + + CONFIG_RAMBASE; > + } else if ((unsigned long)vaddr >= PAGE_OFFSET && > + (unsigned long)vaddr < (PAGE_OFFSET + CONFIG_RAMSIZE)) { > + /* normal mapping */ > + return ((unsigned long)vaddr - PAGE_OFFSET) + CONFIG_RAMBASE; > + } > + > + return (unsigned long)vaddr; > +#endif > +} > +#define __pa(vaddr) ___pa((void *)(vaddr)) > + > +/* > + * Convert a phys to a virt > + */ > +static inline void *__va(unsigned long paddr) > +{ > +#if CONFIG_RAMBASE != PAGE_OFFSET > + return (void *)((paddr & 0x0fffffff) + PAGE_OFFSET); > +#else > + if (paddr >= m54xx_dma_base && paddr <= m54xx_dma_end) { > + /* mapped address for DMA */ > + return (void *)((paddr - CONFIG_RAMBASE) > + + CONFIG_M54xx_DMA_ZONE_BASE); > + } else if (paddr >= m54xx_dma_end && > + paddr < (CONFIG_RAMBASE + CONFIG_RAMSIZE)) { > + /* normal mapping */ > + return (void *)((paddr - CONFIG_RAMBASE) + PAGE_OFFSET); > + } > + return (void *)paddr; > +#endif > +} > + > +#endif > > #else /* !CONFIG_SUN3 */ > /* This #define is a horrible hack to suppress lots of warnings. --m */ > @@ -168,7 +222,19 @@ static inline __attribute_const__ int __virt_to_node_shift(void) > ((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \ > }) > > -#define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory) > +#ifndef CONFIG_M54xx_DMA_ZONE > +#define virt_addr_valid(kaddr) \ > + ((void *)(kaddr) >= (void *)PAGE_OFFSET && \ > + (void *)(kaddr) < high_memory) > +#else > +#define virt_addr_valid(kaddr) \ > + (((void *)(kaddr) >= (void *)PAGE_OFFSET && \ > + (void *)(kaddr) < high_memory) || \ > + ((void *)(kaddr) >= (void *)CONFIG_M54xx_DMA_ZONE_BASE && \ > + (void *)(kaddr) < (void *)(CONFIG_M54xx_DMA_ZONE_BASE \ > + + CONFIG_M54xx_DMA_ZONE_SIZE))) > +#endif > + > #define pfn_valid(pfn) virt_addr_valid(pfn_to_virt(pfn)) > > #endif /* __ASSEMBLY__ */ > diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c > index e546a55..57873d1 100644 > --- a/arch/m68k/kernel/dma.c > +++ b/arch/m68k/kernel/dma.c > @@ -76,6 +76,15 @@ void *dma_alloc_coherent(struct device *dev, size_t size, > dma_addr_t *dma_handle, gfp_t gfp) > { > void *ret; > +#ifdef CONFIG_M54xx_DMA_ZONE > + /* > + * On the M54xx platform with CONFIG_M54xx_DMA_ZONE the memory allocated > + * with GFP_DMA is guaranteed to be DMA'able, and cache coherent. > + */ > + size = PAGE_ALIGN(size); > + ret = kmalloc(size, GFP_DMA); > + *dma_handle = virt_to_phys(ret); > +#else > /* ignore region specifiers */ > gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); > > @@ -87,13 +96,18 @@ void *dma_alloc_coherent(struct device *dev, size_t size, > memset(ret, 0, size); > *dma_handle = virt_to_phys(ret); > } > +#endif > return ret; > } > > void dma_free_coherent(struct device *dev, size_t size, > void *vaddr, dma_addr_t dma_handle) > { > +#ifdef CONFIG_M54xx_DMA_ZONE > + kfree((void *)dma_handle); > +#else > free_pages((unsigned long)vaddr, get_order(size)); > +#endif > } > > #endif /* CONFIG_MMU && !CONFIG_COLDFIRE */ > diff --git a/arch/m68k/mm/mcfmmu.c b/arch/m68k/mm/mcfmmu.c > index 875b800..932415b 100644 > --- a/arch/m68k/mm/mcfmmu.c > +++ b/arch/m68k/mm/mcfmmu.c > @@ -77,11 +77,49 @@ void __init paging_init(void) > } > } > > +#ifdef CONFIG_M54xx_DMA_ZONE > + /* setup page tables for DMA area */ > + /* starting loc in page directory */ > + pg_dir = swapper_pg_dir + (CONFIG_M54xx_DMA_ZONE_BASE >> PGDIR_SHIFT); > + > + size = (CONFIG_M54xx_DMA_ZONE_SIZE >> PAGE_SHIFT) * sizeof(pte_t); > + size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); > + > + next_pgtable = (unsigned long)alloc_bootmem_pages(size); > + > + address = CONFIG_M54xx_DMA_ZONE_BASE; > + while (address < (CONFIG_M54xx_DMA_ZONE_BASE + > + CONFIG_M54xx_DMA_ZONE_SIZE)) { > + pg_table = (pte_t *)next_pgtable; > + next_pgtable += PTRS_PER_PTE * sizeof(pte_t); > + pgd_val(*pg_dir) = (unsigned long)pg_table; > + pg_dir++; > + > + for (i = 0; i < PTRS_PER_PTE; ++i, ++pg_table) { > + pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT); > + if (address >= (CONFIG_M54xx_DMA_ZONE_BASE > + + CONFIG_M54xx_DMA_ZONE_SIZE)) > + pte_val(pte) = 0; > + > + set_pte(pg_table, pte); > + address += PAGE_SIZE; > + } > + } > +#endif > current->mm = NULL; > > for (zone = 0; zone < MAX_NR_ZONES; zone++) > zones_size[zone] = 0x0; > + > +#ifdef CONFIG_M54xx_DMA_ZONE > + zones_size[ZONE_DMA] = CONFIG_M54xx_DMA_ZONE_SIZE >> PAGE_SHIFT; > + zones_size[ZONE_NORMAL] = > + (((unsigned long)high_memory > + - PAGE_OFFSET) >> PAGE_SHIFT) > + - zones_size[ZONE_DMA]; > +#else > zones_size[ZONE_DMA] = num_pages; > +#endif > free_area_init(zones_size); > } > > diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S > index fa31be2..62b4f17 100644 > --- a/arch/m68k/platform/coldfire/head.S > +++ b/arch/m68k/platform/coldfire/head.S > @@ -265,6 +265,37 @@ _clear_bss: > cmpl %a0,%a1 /* check if at end */ > bne _clear_bss > > + > +#ifdef CONFIG_M54xx_DMA_ZONE > + clrl %d0 > +__mmu_dma_map: > + /* Set up search of TLB */ > + movel #CONFIG_M54xx_DMA_ZONE_BASE, %d1 > + addl %d0,%d1 > + addil #1,%d1 > + movel %d1, MMUAR > + /* Search */ > + movel #(MMUOR_STLB+MMUOR_ADR), %d1 > + movel %d1, MMUOR > + /* Set up tag value */ > + movel #CONFIG_M54xx_DMA_ZONE_BASE,%d1 > + addl %d0,%d1 > + addil #(MMUTR_SG+MMUTR_V),%d1 > + movel %d1, MMUTR > + /* Set up data value */ > + movel #CONFIG_RAMBASE,%d1 > + addl %d0,%d1 > + addil #(MMUDR_SZ_1MB+MMUDR_CM_NCP+MMUDR_SP+MMUDR_R+MMUDR_W+MMUDR_LK),%d1 > + movel %d1, MMUDR > + /* Save */ > + movel #(MMUOR_ACC+MMUOR_UAA), %d1 > + movel %d1, MMUOR > + > + addil #0x100000,%d0 > + cmpil #CONFIG_M54xx_DMA_ZONE_SIZE,%d0 > + bnes __mmu_dma_map > +#endif > + > /* > * Load the current task pointer and stack. > */ > diff --git a/arch/m68k/platform/coldfire/m54xx.c b/arch/m68k/platform/coldfire/m54xx.c > index b587bf3..c207822 100644 > --- a/arch/m68k/platform/coldfire/m54xx.c > +++ b/arch/m68k/platform/coldfire/m54xx.c > @@ -23,6 +23,9 @@ > #include > #ifdef CONFIG_MMU > #include > +#ifdef CONFIG_M54xx_DMA_ZONE > +#include > +#endif > #endif > > /***************************************************************************/ > @@ -56,6 +59,17 @@ static void mcf54xx_reset(void) > > unsigned long num_pages; > > +#ifdef CONFIG_M54xx_DMA_ZONE > +/* cf dma physical addresses */ > +unsigned long m54xx_dma_base; > +EXPORT_SYMBOL(m54xx_dma_base); > +unsigned long m54xx_dma_end; > +EXPORT_SYMBOL(m54xx_dma_end); > +unsigned long m54xx_dma_size; > +EXPORT_SYMBOL(m54xx_dma_size); > +#endif > + > + > static void __init mcf54xx_bootmem_alloc(void) > { > unsigned long start_pfn; > @@ -83,6 +97,13 @@ static void __init mcf54xx_bootmem_alloc(void) > memstart += init_bootmem_node(NODE_DATA(0), start_pfn, > min_low_pfn, max_low_pfn); > free_bootmem_node(NODE_DATA(0), memstart, _ramend - memstart); > + > +#ifdef CONFIG_M54xx_DMA_ZONE > + /* configure physical dma area */ > + m54xx_dma_base = __pa(PAGE_ALIGN(_ramstart)); > + m54xx_dma_size = CONFIG_M54xx_DMA_ZONE_SIZE; > + m54xx_dma_end = CONFIG_RAMBASE + m54xx_dma_size - 1; > +#endif /* CONFIG_M54xx_DMA_ZONE */ > } > > #endif /* CONFIG_MMU */ > -- > 1.7.9.5 > > > > -- ------------------------------------------------------------------------ Greg Ungerer -- Principal Engineer EMAIL: gerg@snapgear.com SnapGear Group, McAfee PHONE: +61 7 3435 2888 8 Gardner Close FAX: +61 7 3217 5323 Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com