All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Baatz <gmbnomis@gmail.com>
To: Catalin Marinas <catalin.marinas@arm.com>
Cc: linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>
Subject: Re: [PATCH v3 09/31] arm64: Cache maintenance routines
Date: Fri, 7 Sep 2012 21:35:42 +0200	[thread overview]
Message-ID: <20120907193542.GA22806@schnuecks.de> (raw)
In-Reply-To: <1347035226-18649-10-git-send-email-catalin.marinas@arm.com>

Hi Catalin,

On Fri, Sep 07, 2012 at 05:26:44PM +0100, Catalin Marinas wrote:
> The patch adds functionality required for cache maintenance. The AArch64
> architecture mandates non-aliasing VIPT or PIPT D-cache and VIPT (may
> have aliases) or ASID-tagged VIVT I-cache. Cache maintenance operations
> are automatically broadcast in hardware between CPUs.
> 
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Acked-by: Tony Lindgren <tony@atomide.com>
> ---
>  arch/arm64/include/asm/cache.h      |   32 +++++
>  arch/arm64/include/asm/cacheflush.h |  168 +++++++++++++++++++++++
>  arch/arm64/include/asm/cachetype.h  |   48 +++++++
>  arch/arm64/mm/cache.S               |  251 +++++++++++++++++++++++++++++++++++
>  arch/arm64/mm/flush.c               |  138 +++++++++++++++++++
>  5 files changed, 637 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm64/include/asm/cache.h
>  create mode 100644 arch/arm64/include/asm/cacheflush.h
>  create mode 100644 arch/arm64/include/asm/cachetype.h
>  create mode 100644 arch/arm64/mm/cache.S
>  create mode 100644 arch/arm64/mm/flush.c
> 
> diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> new file mode 100644
> index 0000000..390308a
> --- /dev/null
> +++ b/arch/arm64/include/asm/cache.h
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHE_H
> +#define __ASM_CACHE_H
> +
> +#define L1_CACHE_SHIFT		6
> +#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
> +
> +/*
> + * Memory returned by kmalloc() may be used for DMA, so we must make
> + * sure that all such allocations are cache aligned. Otherwise,
> + * unrelated code may cause parts of the buffer to be read into the
> + * cache before the transfer is done, causing old data to be seen by
> + * the CPU.
> + */
> +#define ARCH_DMA_MINALIGN	L1_CACHE_BYTES
> +#define ARCH_SLAB_MINALIGN	8
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
> new file mode 100644
> index 0000000..0bb9853
> --- /dev/null
> +++ b/arch/arm64/include/asm/cacheflush.h
> @@ -0,0 +1,168 @@
> +/*
> + * Based on arch/arm/include/asm/cacheflush.h
> + *
> + * Copyright (C) 1999-2002 Russell King.
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHEFLUSH_H
> +#define __ASM_CACHEFLUSH_H
> +
> +#include <linux/mm.h>
> +
> +/*
> + * This flag is used to indicate that the page pointed to by a pte is clean
> + * and does not require cleaning before returning it to the user.
> + */
> +#define PG_dcache_clean PG_arch_1
> +
> +/*
> + *	MM Cache Management
> + *	===================
> + *
> + *	The arch/arm64/mm/cache.S implements these methods.
> + *
> + *	Start addresses are inclusive and end addresses are exclusive; start
> + *	addresses should be rounded down, end addresses up.
> + *
> + *	See Documentation/cachetlb.txt for more information. Please note that
> + *	the implementation assumes non-aliasing VIPT D-cache and (aliasing)
> + *	VIPT or ASID-tagged VIVT I-cache.
> + *
> + *	flush_cache_all()
> + *
> + *		Unconditionally clean and invalidate the entire cache.
> + *
> + *	flush_cache_mm(mm)
> + *
> + *		Clean and invalidate all user space cache entries
> + *		before a change of page tables.
> + *
> + *	flush_icache_range(start, end)
> + *
> + *		Ensure coherency between the I-cache and the D-cache in the
> + *		region described by start, end.
> + *		- start  - virtual start address
> + *		- end    - virtual end address
> + *
> + *	__flush_cache_user_range(start, end)
> + *
> + *		Ensure coherency between the I-cache and the D-cache in the
> + *		region described by start, end.
> + *		- start  - virtual start address
> + *		- end    - virtual end address
> + *
> + *	__flush_dcache_area(kaddr, size)
> + *
> + *		Ensure that the data held in page is written back.
> + *		- kaddr  - page address
> + *		- size   - region size
> + */
> +extern void flush_cache_all(void);
> +extern void flush_cache_mm(struct mm_struct *mm);
> +extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
> +extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
> +extern void flush_icache_range(unsigned long start, unsigned long end);
> +extern void __flush_dcache_area(void *addr, size_t len);
> +extern void __flush_cache_user_range(unsigned long start, unsigned long end);
> +
> +/*
> + * These are private to the dma-mapping API.  Do not use directly.
> + * Their sole purpose is to ensure that data held in the cache
> + * is visible to DMA, or data written by DMA to system memory is
> + * visible to the CPU.
> + */
> +extern void dmac_map_area(const void *, size_t, int);
> +extern void dmac_unmap_area(const void *, size_t, int);
> +extern void dmac_flush_range(const void *, const void *);
> +
> +/*
> + * Copy user data from/to a page which is mapped into a different
> + * processes address space.  Really, we want to allow our "user
> + * space" model to handle this.
> + */
> +extern void copy_to_user_page(struct vm_area_struct *, struct page *,
> +	unsigned long, void *, const void *, unsigned long);
> +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
> +	do {							\
> +		memcpy(dst, src, len);				\
> +	} while (0)
> +
> +#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
> +
> +/*
> + * flush_dcache_page is used when the kernel has written to the page
> + * cache page at virtual address page->virtual.
> + *
> + * If this page isn't mapped (ie, page_mapping == NULL), or it might
> + * have userspace mappings, then we _must_ always clean + invalidate
> + * the dcache entries associated with the kernel mapping.
> + *
> + * Otherwise we can defer the operation, and clean the cache when we are
> + * about to change to user space.  This is the same method as used on SPARC64.
> + * See update_mmu_cache for the user space part.
> + */
> +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
> +extern void flush_dcache_page(struct page *);
> +
> +static inline void __flush_icache_all(void)
> +{
> +	asm("ic	ialluis");
> +}
> +
> +#define ARCH_HAS_FLUSH_ANON_PAGE
> +static inline void flush_anon_page(struct vm_area_struct *vma,
> +			 struct page *page, unsigned long vmaddr)
> +{
> +	extern void __flush_anon_page(struct vm_area_struct *vma,
> +				struct page *, unsigned long);
> +	if (PageAnon(page))
> +		__flush_anon_page(vma, page, vmaddr);


__flush_anon_page() does nothing. Shouldn't this be removed as well?

> +}
> +
> +#define flush_dcache_mmap_lock(mapping) \
> +	spin_lock_irq(&(mapping)->tree_lock)
> +#define flush_dcache_mmap_unlock(mapping) \
> +	spin_unlock_irq(&(mapping)->tree_lock)
> +
> +#define flush_icache_user_range(vma,page,addr,len) \
> +	flush_dcache_page(page)
> +
> +/*
> + * We don't appear to need to do anything here.  In fact, if we did, we'd
> + * duplicate cache flushing elsewhere performed by flush_dcache_page().
> + */
> +#define flush_icache_page(vma,page)	do { } while (0)
> +
> +/*
> + * flush_cache_vmap() is used when creating mappings (eg, via vmap,
> + * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
> + * caches, since the direct-mappings of these pages may contain cached
> + * data, we need to do a full cache flush to ensure that writebacks
> + * don't corrupt data placed into these pages via the new mappings.
> + */
> +static inline void flush_cache_vmap(unsigned long start, unsigned long end)
> +{
> +	/*
> +	 * set_pte_at() called from vmap_pte_range() does not
> +	 * have a DSB after cleaning the cache line.
> +	 */
> +	dsb();
> +}
> +
> +static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
> +{
> +}
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h
> new file mode 100644
> index 0000000..85f5f51
> --- /dev/null
> +++ b/arch/arm64/include/asm/cachetype.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHETYPE_H
> +#define __ASM_CACHETYPE_H
> +
> +#include <asm/cputype.h>
> +
> +#define CTR_L1IP_SHIFT		14
> +#define CTR_L1IP_MASK		3
> +
> +#define ICACHE_POLICY_RESERVED	0
> +#define ICACHE_POLICY_AIVIVT	1
> +#define ICACHE_POLICY_VIPT	2
> +#define ICACHE_POLICY_PIPT	3
> +
> +static inline u32 icache_policy(void)
> +{
> +	return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK;
> +}
> +
> +/*
> + * Whilst the D-side always behaves as PIPT on AArch64, aliasing is
> + * permitted in the I-cache.
> + */
> +static inline int icache_is_aliasing(void)
> +{
> +	return icache_policy() != ICACHE_POLICY_PIPT;
> +}
> +
> +static inline int icache_is_aivivt(void)
> +{
> +	return icache_policy() == ICACHE_POLICY_AIVIVT;
> +}
> +
> +#endif	/* __ASM_CACHETYPE_H */
> diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
> new file mode 100644
> index 0000000..3df0aa7
> --- /dev/null
> +++ b/arch/arm64/mm/cache.S
> @@ -0,0 +1,251 @@
> +/*
> + * Cache maintenance
> + *
> + * Copyright (C) 2001 Deep Blue Solutions Ltd.
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +#include <asm/assembler.h>
> +
> +#include "proc-macros.S"
> +
> +/*
> + *	__flush_dcache_all()
> + *
> + *	Flush the whole D-cache.
> + *
> + *	Corrupted registers: x0-x7, x9-x11
> + */
> +ENTRY(__flush_dcache_all)
> +	dsb	sy				// ensure ordering with previous memory accesses
> +	mrs	x0, clidr_el1			// read clidr
> +	and	x3, x0, #0x7000000		// extract loc from clidr
> +	lsr	x3, x3, #23			// left align loc bit field
> +	cbz	x3, finished			// if loc is 0, then no need to clean
> +	mov	x10, #0				// start clean at cache level 0
> +loop1:
> +	add	x2, x10, x10, lsr #1		// work out 3x current cache level
> +	lsr	x1, x0, x2			// extract cache type bits from clidr
> +	and	x1, x1, #7			// mask of the bits for current cache only
> +	cmp	x1, #2				// see what cache we have at this level
> +	b.lt	skip				// skip if no cache, or just i-cache
> +	save_and_disable_irqs x9		// make CSSELR and CCSIDR access atomic
> +	msr	csselr_el1, x10			// select current cache level in csselr
> +	isb					// isb to sych the new cssr&csidr
> +	mrs	x1, ccsidr_el1			// read the new ccsidr
> +	restore_irqs x9
> +	and	x2, x1, #7			// extract the length of the cache lines
> +	add	x2, x2, #4			// add 4 (line length offset)
> +	mov	x4, #0x3ff
> +	and	x4, x4, x1, lsr #3		// find maximum number on the way size
> +	clz	x5, x4				// find bit position of way size increment
> +	mov	x7, #0x7fff
> +	and	x7, x7, x1, lsr #13		// extract max number of the index size
> +loop2:
> +	mov	x9, x4				// create working copy of max way size
> +loop3:
> +	lsl	x6, x9, x5
> +	orr	x11, x10, x6			// factor way and cache number into x11
> +	lsl	x6, x7, x2
> +	orr	x11, x11, x6			// factor index number into x11
> +	dc	cisw, x11			// clean & invalidate by set/way
> +	subs	x9, x9, #1			// decrement the way
> +	b.ge	loop3
> +	subs	x7, x7, #1			// decrement the index
> +	b.ge	loop2
> +skip:
> +	add	x10, x10, #2			// increment cache number
> +	cmp	x3, x10
> +	b.gt	loop1
> +finished:
> +	mov	x10, #0				// swith back to cache level 0
> +	msr	csselr_el1, x10			// select current cache level in csselr
> +	dsb	sy
> +	isb
> +	ret
> +ENDPROC(__flush_dcache_all)
> +
> +/*
> + *	flush_cache_all()
> + *
> + *	Flush the entire cache system.  The data cache flush is now achieved
> + *	using atomic clean / invalidates working outwards from L1 cache. This
> + *	is done using Set/Way based cache maintainance instructions.  The
> + *	instruction cache can still be invalidated back to the point of
> + *	unification in a single instruction.
> + */
> +ENTRY(flush_cache_all)
> +	mov	x12, lr
> +	bl	__flush_dcache_all
> +	mov	x0, #0
> +	ic	ialluis				// I+BTB cache invalidate
> +	ret	x12
> +ENDPROC(flush_cache_all)
> +
> +/*
> + *	flush_icache_range(start,end)
> + *
> + *	Ensure that the I and D caches are coherent within specified region.
> + *	This is typically used when code has been written to a memory region,
> + *	and will be executed.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(flush_icache_range)
> +	/* FALLTHROUGH */
> +
> +/*
> + *	__flush_cache_user_range(start,end)
> + *
> + *	Ensure that the I and D caches are coherent within specified region.
> + *	This is typically used when code has been written to a memory region,
> + *	and will be executed.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(__flush_cache_user_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x4, x0, x3
> +1:
> +USER(9f, dc	cvau, x4	)		// clean D line to PoU
> +	add	x4, x4, x2
> +	cmp	x4, x1
> +	b.lo	1b
> +	dsb	sy
> +
> +	icache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x4, x0, x3
> +1:
> +USER(9f, ic	ivau, x4	)		// invalidate I line PoU
> +	add	x4, x4, x2
> +	cmp	x4, x1
> +	b.lo	1b
> +9:						// ignore any faulting cache operation
> +	dsb	sy
> +	isb
> +	ret
> +ENDPROC(flush_icache_range)
> +ENDPROC(__flush_cache_user_range)
> +
> +/*
> + *	__flush_kern_dcache_page(kaddr)


Should be:  __flush_dcache_area(kaddr,size)

> + *
> + *	Ensure that the data held in the page kaddr is written back to the
> + *	page in question.

s/page/area

> + *
> + *	- kaddr   - kernel address
> + *	- size    - size in question
> + */
> +ENTRY(__flush_dcache_area)
> +	dcache_line_size x2, x3
> +	add	x1, x0, x1
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	civac, x0			// clean & invalidate D line / unified line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(__flush_dcache_area)
> +
> +/*
> + *	dmac_inv_range(start,end)
> + *
> + *	Invalidate the data cache within the specified region; we will be
> + *	performing a DMA operation in this region and we want to purge old
> + *	data in the cache.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_inv_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +	bic	x1, x1, x3
> +1:	dc	ivac, x0			// invalidate D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_inv_range)
> +
> +/*
> + *	dmac_clean_range(start,end)
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_clean_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	cvac, x0			// clean D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_clean_range)
> +
> +/*
> + *	dmac_flush_range(start,end)
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_flush_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	civac, x0			// clean & invalidate D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_flush_range)
> +
> +/*
> + *	dmac_map_area(start, size, dir)
> + *	- start	- kernel virtual start address
> + *	- size	- size of region
> + *	- dir	- DMA direction
> + */
> +ENTRY(dmac_map_area)
> +	add	x1, x1, x0
> +	cmp	x2, #DMA_FROM_DEVICE
> +	b.eq	dmac_inv_range
> +	b	dmac_clean_range
> +ENDPROC(dmac_map_area)
> +
> +/*
> + *	dmac_unmap_area(start, size, dir)
> + *	- start	- kernel virtual start address
> + *	- size	- size of region
> + *	- dir	- DMA direction
> + */
> +ENTRY(dmac_unmap_area)
> +	add	x1, x1, x0
> +	cmp	x2, #DMA_TO_DEVICE
> +	b.ne	dmac_inv_range
> +	ret
> +ENDPROC(dmac_unmap_area)
> diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
> new file mode 100644
> index 0000000..6138d86
> --- /dev/null
> +++ b/arch/arm64/mm/flush.c
> @@ -0,0 +1,138 @@
> +/*
> + * Based on arch/arm/mm/flush.c
> + *
> + * Copyright (C) 1995-2002 Russell King
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/export.h>
> +#include <linux/mm.h>
> +#include <linux/pagemap.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/cachetype.h>
> +#include <asm/tlbflush.h>
> +
> +#include "mm.h"
> +
> +void flush_cache_mm(struct mm_struct *mm)
> +{
> +}
> +
> +void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
> +		       unsigned long end)
> +{
> +	if (vma->vm_flags & VM_EXEC)
> +		__flush_icache_all();
> +}
> +
> +void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr,
> +		      unsigned long pfn)
> +{
> +}
> +
> +static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
> +				unsigned long uaddr, void *kaddr,
> +				unsigned long len)
> +{
> +	if (vma->vm_flags & VM_EXEC) {
> +		unsigned long addr = (unsigned long)kaddr;
> +		if (icache_is_aliasing()) {
> +			__flush_dcache_area(kaddr, len);
> +			__flush_icache_all();
> +		} else {
> +			flush_icache_range(addr, addr + len);
> +		}
> +	}
> +}
> +
> +/*
> + * Copy user data from/to a page which is mapped into a different processes
> + * address space.  Really, we want to allow our "user space" model to handle
> + * this.
> + *
> + * Note that this code needs to run on the current CPU.
> + */
> +void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
> +		       unsigned long uaddr, void *dst, const void *src,
> +		       unsigned long len)
> +{
> +#ifdef CONFIG_SMP
> +	preempt_disable();
> +#endif
> +	memcpy(dst, src, len);
> +	flush_ptrace_access(vma, page, uaddr, dst, len);
> +#ifdef CONFIG_SMP
> +	preempt_enable();
> +#endif
> +}
> +
> +void __flush_dcache_page(struct address_space *mapping, struct page *page)
> +{
> +	__flush_dcache_area(page_address(page), PAGE_SIZE);
> +}
> +
> +void __sync_icache_dcache(pte_t pte)
> +{
> +	unsigned long pfn;
> +	struct page *page;
> +
> +	pfn = pte_pfn(pte);
> +	if (!pfn_valid(pfn))
> +		return;
> +
> +	page = pfn_to_page(pfn);
> +	if (!test_and_set_bit(PG_dcache_clean, &page->flags))
> +		__flush_dcache_page(NULL, page);
> +	__flush_icache_all();
> +}
> +
> +/*
> + * Ensure cache coherency between kernel mapping and userspace mapping of this
> + * page.
> + */
> +void flush_dcache_page(struct page *page)
> +{
> +	struct address_space *mapping;
> +
> +	/*
> +	 * The zero page is never written to, so never has any dirty cache
> +	 * lines, and therefore never needs to be flushed.
> +	 */
> +	if (page == ZERO_PAGE(0))
> +		return;
> +
> +	mapping = page_mapping(page);
> +
> +	if (mapping && !mapping_mapped(mapping))
> +		clear_bit(PG_dcache_clean, &page->flags);
> +	else {
> +		__flush_dcache_page(mapping, page);
> +		if (mapping)
> +			__flush_icache_all();


Is this necessary to ensure I/D coherency? Then, I would have
expected

		if (mapping) {
			__flush_dcache_page(mapping, page);
			__flush_icache_all();
		}

similar to __sync_icache_dcache() above.

What is the reason why the D-cache flush is done in different
cases than the following I-cache flush?

> +		set_bit(PG_dcache_clean, &page->flags);
> +	}
> +}
> +EXPORT_SYMBOL(flush_dcache_page);
> +
> +void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
> +{
> +}

Note that the __flush_dcache_page(mapping, page) in
flush_dcache_page() above is called when page is an anonymous page
(since mapping == NULL in this case).  If the call to
__flush_dcache_page() is right above, it should be needed
here as well?

> +
> +/*
> + * Additional functions defined in assembly.
> + */
> +EXPORT_SYMBOL(flush_cache_all);
> +EXPORT_SYMBOL(flush_icache_range);
> 
> 


- Simon

WARNING: multiple messages have this Message-ID (diff)
From: gmbnomis@gmail.com (Simon Baatz)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 09/31] arm64: Cache maintenance routines
Date: Fri, 7 Sep 2012 21:35:42 +0200	[thread overview]
Message-ID: <20120907193542.GA22806@schnuecks.de> (raw)
In-Reply-To: <1347035226-18649-10-git-send-email-catalin.marinas@arm.com>

Hi Catalin,

On Fri, Sep 07, 2012 at 05:26:44PM +0100, Catalin Marinas wrote:
> The patch adds functionality required for cache maintenance. The AArch64
> architecture mandates non-aliasing VIPT or PIPT D-cache and VIPT (may
> have aliases) or ASID-tagged VIVT I-cache. Cache maintenance operations
> are automatically broadcast in hardware between CPUs.
> 
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Acked-by: Tony Lindgren <tony@atomide.com>
> ---
>  arch/arm64/include/asm/cache.h      |   32 +++++
>  arch/arm64/include/asm/cacheflush.h |  168 +++++++++++++++++++++++
>  arch/arm64/include/asm/cachetype.h  |   48 +++++++
>  arch/arm64/mm/cache.S               |  251 +++++++++++++++++++++++++++++++++++
>  arch/arm64/mm/flush.c               |  138 +++++++++++++++++++
>  5 files changed, 637 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm64/include/asm/cache.h
>  create mode 100644 arch/arm64/include/asm/cacheflush.h
>  create mode 100644 arch/arm64/include/asm/cachetype.h
>  create mode 100644 arch/arm64/mm/cache.S
>  create mode 100644 arch/arm64/mm/flush.c
> 
> diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> new file mode 100644
> index 0000000..390308a
> --- /dev/null
> +++ b/arch/arm64/include/asm/cache.h
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHE_H
> +#define __ASM_CACHE_H
> +
> +#define L1_CACHE_SHIFT		6
> +#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
> +
> +/*
> + * Memory returned by kmalloc() may be used for DMA, so we must make
> + * sure that all such allocations are cache aligned. Otherwise,
> + * unrelated code may cause parts of the buffer to be read into the
> + * cache before the transfer is done, causing old data to be seen by
> + * the CPU.
> + */
> +#define ARCH_DMA_MINALIGN	L1_CACHE_BYTES
> +#define ARCH_SLAB_MINALIGN	8
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
> new file mode 100644
> index 0000000..0bb9853
> --- /dev/null
> +++ b/arch/arm64/include/asm/cacheflush.h
> @@ -0,0 +1,168 @@
> +/*
> + * Based on arch/arm/include/asm/cacheflush.h
> + *
> + * Copyright (C) 1999-2002 Russell King.
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHEFLUSH_H
> +#define __ASM_CACHEFLUSH_H
> +
> +#include <linux/mm.h>
> +
> +/*
> + * This flag is used to indicate that the page pointed to by a pte is clean
> + * and does not require cleaning before returning it to the user.
> + */
> +#define PG_dcache_clean PG_arch_1
> +
> +/*
> + *	MM Cache Management
> + *	===================
> + *
> + *	The arch/arm64/mm/cache.S implements these methods.
> + *
> + *	Start addresses are inclusive and end addresses are exclusive; start
> + *	addresses should be rounded down, end addresses up.
> + *
> + *	See Documentation/cachetlb.txt for more information. Please note that
> + *	the implementation assumes non-aliasing VIPT D-cache and (aliasing)
> + *	VIPT or ASID-tagged VIVT I-cache.
> + *
> + *	flush_cache_all()
> + *
> + *		Unconditionally clean and invalidate the entire cache.
> + *
> + *	flush_cache_mm(mm)
> + *
> + *		Clean and invalidate all user space cache entries
> + *		before a change of page tables.
> + *
> + *	flush_icache_range(start, end)
> + *
> + *		Ensure coherency between the I-cache and the D-cache in the
> + *		region described by start, end.
> + *		- start  - virtual start address
> + *		- end    - virtual end address
> + *
> + *	__flush_cache_user_range(start, end)
> + *
> + *		Ensure coherency between the I-cache and the D-cache in the
> + *		region described by start, end.
> + *		- start  - virtual start address
> + *		- end    - virtual end address
> + *
> + *	__flush_dcache_area(kaddr, size)
> + *
> + *		Ensure that the data held in page is written back.
> + *		- kaddr  - page address
> + *		- size   - region size
> + */
> +extern void flush_cache_all(void);
> +extern void flush_cache_mm(struct mm_struct *mm);
> +extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
> +extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
> +extern void flush_icache_range(unsigned long start, unsigned long end);
> +extern void __flush_dcache_area(void *addr, size_t len);
> +extern void __flush_cache_user_range(unsigned long start, unsigned long end);
> +
> +/*
> + * These are private to the dma-mapping API.  Do not use directly.
> + * Their sole purpose is to ensure that data held in the cache
> + * is visible to DMA, or data written by DMA to system memory is
> + * visible to the CPU.
> + */
> +extern void dmac_map_area(const void *, size_t, int);
> +extern void dmac_unmap_area(const void *, size_t, int);
> +extern void dmac_flush_range(const void *, const void *);
> +
> +/*
> + * Copy user data from/to a page which is mapped into a different
> + * processes address space.  Really, we want to allow our "user
> + * space" model to handle this.
> + */
> +extern void copy_to_user_page(struct vm_area_struct *, struct page *,
> +	unsigned long, void *, const void *, unsigned long);
> +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
> +	do {							\
> +		memcpy(dst, src, len);				\
> +	} while (0)
> +
> +#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
> +
> +/*
> + * flush_dcache_page is used when the kernel has written to the page
> + * cache page at virtual address page->virtual.
> + *
> + * If this page isn't mapped (ie, page_mapping == NULL), or it might
> + * have userspace mappings, then we _must_ always clean + invalidate
> + * the dcache entries associated with the kernel mapping.
> + *
> + * Otherwise we can defer the operation, and clean the cache when we are
> + * about to change to user space.  This is the same method as used on SPARC64.
> + * See update_mmu_cache for the user space part.
> + */
> +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
> +extern void flush_dcache_page(struct page *);
> +
> +static inline void __flush_icache_all(void)
> +{
> +	asm("ic	ialluis");
> +}
> +
> +#define ARCH_HAS_FLUSH_ANON_PAGE
> +static inline void flush_anon_page(struct vm_area_struct *vma,
> +			 struct page *page, unsigned long vmaddr)
> +{
> +	extern void __flush_anon_page(struct vm_area_struct *vma,
> +				struct page *, unsigned long);
> +	if (PageAnon(page))
> +		__flush_anon_page(vma, page, vmaddr);


__flush_anon_page() does nothing. Shouldn't this be removed as well?

> +}
> +
> +#define flush_dcache_mmap_lock(mapping) \
> +	spin_lock_irq(&(mapping)->tree_lock)
> +#define flush_dcache_mmap_unlock(mapping) \
> +	spin_unlock_irq(&(mapping)->tree_lock)
> +
> +#define flush_icache_user_range(vma,page,addr,len) \
> +	flush_dcache_page(page)
> +
> +/*
> + * We don't appear to need to do anything here.  In fact, if we did, we'd
> + * duplicate cache flushing elsewhere performed by flush_dcache_page().
> + */
> +#define flush_icache_page(vma,page)	do { } while (0)
> +
> +/*
> + * flush_cache_vmap() is used when creating mappings (eg, via vmap,
> + * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
> + * caches, since the direct-mappings of these pages may contain cached
> + * data, we need to do a full cache flush to ensure that writebacks
> + * don't corrupt data placed into these pages via the new mappings.
> + */
> +static inline void flush_cache_vmap(unsigned long start, unsigned long end)
> +{
> +	/*
> +	 * set_pte_at() called from vmap_pte_range() does not
> +	 * have a DSB after cleaning the cache line.
> +	 */
> +	dsb();
> +}
> +
> +static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
> +{
> +}
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h
> new file mode 100644
> index 0000000..85f5f51
> --- /dev/null
> +++ b/arch/arm64/include/asm/cachetype.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_CACHETYPE_H
> +#define __ASM_CACHETYPE_H
> +
> +#include <asm/cputype.h>
> +
> +#define CTR_L1IP_SHIFT		14
> +#define CTR_L1IP_MASK		3
> +
> +#define ICACHE_POLICY_RESERVED	0
> +#define ICACHE_POLICY_AIVIVT	1
> +#define ICACHE_POLICY_VIPT	2
> +#define ICACHE_POLICY_PIPT	3
> +
> +static inline u32 icache_policy(void)
> +{
> +	return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK;
> +}
> +
> +/*
> + * Whilst the D-side always behaves as PIPT on AArch64, aliasing is
> + * permitted in the I-cache.
> + */
> +static inline int icache_is_aliasing(void)
> +{
> +	return icache_policy() != ICACHE_POLICY_PIPT;
> +}
> +
> +static inline int icache_is_aivivt(void)
> +{
> +	return icache_policy() == ICACHE_POLICY_AIVIVT;
> +}
> +
> +#endif	/* __ASM_CACHETYPE_H */
> diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
> new file mode 100644
> index 0000000..3df0aa7
> --- /dev/null
> +++ b/arch/arm64/mm/cache.S
> @@ -0,0 +1,251 @@
> +/*
> + * Cache maintenance
> + *
> + * Copyright (C) 2001 Deep Blue Solutions Ltd.
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +#include <asm/assembler.h>
> +
> +#include "proc-macros.S"
> +
> +/*
> + *	__flush_dcache_all()
> + *
> + *	Flush the whole D-cache.
> + *
> + *	Corrupted registers: x0-x7, x9-x11
> + */
> +ENTRY(__flush_dcache_all)
> +	dsb	sy				// ensure ordering with previous memory accesses
> +	mrs	x0, clidr_el1			// read clidr
> +	and	x3, x0, #0x7000000		// extract loc from clidr
> +	lsr	x3, x3, #23			// left align loc bit field
> +	cbz	x3, finished			// if loc is 0, then no need to clean
> +	mov	x10, #0				// start clean at cache level 0
> +loop1:
> +	add	x2, x10, x10, lsr #1		// work out 3x current cache level
> +	lsr	x1, x0, x2			// extract cache type bits from clidr
> +	and	x1, x1, #7			// mask of the bits for current cache only
> +	cmp	x1, #2				// see what cache we have at this level
> +	b.lt	skip				// skip if no cache, or just i-cache
> +	save_and_disable_irqs x9		// make CSSELR and CCSIDR access atomic
> +	msr	csselr_el1, x10			// select current cache level in csselr
> +	isb					// isb to sych the new cssr&csidr
> +	mrs	x1, ccsidr_el1			// read the new ccsidr
> +	restore_irqs x9
> +	and	x2, x1, #7			// extract the length of the cache lines
> +	add	x2, x2, #4			// add 4 (line length offset)
> +	mov	x4, #0x3ff
> +	and	x4, x4, x1, lsr #3		// find maximum number on the way size
> +	clz	x5, x4				// find bit position of way size increment
> +	mov	x7, #0x7fff
> +	and	x7, x7, x1, lsr #13		// extract max number of the index size
> +loop2:
> +	mov	x9, x4				// create working copy of max way size
> +loop3:
> +	lsl	x6, x9, x5
> +	orr	x11, x10, x6			// factor way and cache number into x11
> +	lsl	x6, x7, x2
> +	orr	x11, x11, x6			// factor index number into x11
> +	dc	cisw, x11			// clean & invalidate by set/way
> +	subs	x9, x9, #1			// decrement the way
> +	b.ge	loop3
> +	subs	x7, x7, #1			// decrement the index
> +	b.ge	loop2
> +skip:
> +	add	x10, x10, #2			// increment cache number
> +	cmp	x3, x10
> +	b.gt	loop1
> +finished:
> +	mov	x10, #0				// swith back to cache level 0
> +	msr	csselr_el1, x10			// select current cache level in csselr
> +	dsb	sy
> +	isb
> +	ret
> +ENDPROC(__flush_dcache_all)
> +
> +/*
> + *	flush_cache_all()
> + *
> + *	Flush the entire cache system.  The data cache flush is now achieved
> + *	using atomic clean / invalidates working outwards from L1 cache. This
> + *	is done using Set/Way based cache maintainance instructions.  The
> + *	instruction cache can still be invalidated back to the point of
> + *	unification in a single instruction.
> + */
> +ENTRY(flush_cache_all)
> +	mov	x12, lr
> +	bl	__flush_dcache_all
> +	mov	x0, #0
> +	ic	ialluis				// I+BTB cache invalidate
> +	ret	x12
> +ENDPROC(flush_cache_all)
> +
> +/*
> + *	flush_icache_range(start,end)
> + *
> + *	Ensure that the I and D caches are coherent within specified region.
> + *	This is typically used when code has been written to a memory region,
> + *	and will be executed.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(flush_icache_range)
> +	/* FALLTHROUGH */
> +
> +/*
> + *	__flush_cache_user_range(start,end)
> + *
> + *	Ensure that the I and D caches are coherent within specified region.
> + *	This is typically used when code has been written to a memory region,
> + *	and will be executed.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(__flush_cache_user_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x4, x0, x3
> +1:
> +USER(9f, dc	cvau, x4	)		// clean D line to PoU
> +	add	x4, x4, x2
> +	cmp	x4, x1
> +	b.lo	1b
> +	dsb	sy
> +
> +	icache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x4, x0, x3
> +1:
> +USER(9f, ic	ivau, x4	)		// invalidate I line PoU
> +	add	x4, x4, x2
> +	cmp	x4, x1
> +	b.lo	1b
> +9:						// ignore any faulting cache operation
> +	dsb	sy
> +	isb
> +	ret
> +ENDPROC(flush_icache_range)
> +ENDPROC(__flush_cache_user_range)
> +
> +/*
> + *	__flush_kern_dcache_page(kaddr)


Should be:  __flush_dcache_area(kaddr,size)

> + *
> + *	Ensure that the data held in the page kaddr is written back to the
> + *	page in question.

s/page/area

> + *
> + *	- kaddr   - kernel address
> + *	- size    - size in question
> + */
> +ENTRY(__flush_dcache_area)
> +	dcache_line_size x2, x3
> +	add	x1, x0, x1
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	civac, x0			// clean & invalidate D line / unified line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(__flush_dcache_area)
> +
> +/*
> + *	dmac_inv_range(start,end)
> + *
> + *	Invalidate the data cache within the specified region; we will be
> + *	performing a DMA operation in this region and we want to purge old
> + *	data in the cache.
> + *
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_inv_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +	bic	x1, x1, x3
> +1:	dc	ivac, x0			// invalidate D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_inv_range)
> +
> +/*
> + *	dmac_clean_range(start,end)
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_clean_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	cvac, x0			// clean D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_clean_range)
> +
> +/*
> + *	dmac_flush_range(start,end)
> + *	- start   - virtual start address of region
> + *	- end     - virtual end address of region
> + */
> +ENTRY(dmac_flush_range)
> +	dcache_line_size x2, x3
> +	sub	x3, x2, #1
> +	bic	x0, x0, x3
> +1:	dc	civac, x0			// clean & invalidate D / U line
> +	add	x0, x0, x2
> +	cmp	x0, x1
> +	b.lo	1b
> +	dsb	sy
> +	ret
> +ENDPROC(dmac_flush_range)
> +
> +/*
> + *	dmac_map_area(start, size, dir)
> + *	- start	- kernel virtual start address
> + *	- size	- size of region
> + *	- dir	- DMA direction
> + */
> +ENTRY(dmac_map_area)
> +	add	x1, x1, x0
> +	cmp	x2, #DMA_FROM_DEVICE
> +	b.eq	dmac_inv_range
> +	b	dmac_clean_range
> +ENDPROC(dmac_map_area)
> +
> +/*
> + *	dmac_unmap_area(start, size, dir)
> + *	- start	- kernel virtual start address
> + *	- size	- size of region
> + *	- dir	- DMA direction
> + */
> +ENTRY(dmac_unmap_area)
> +	add	x1, x1, x0
> +	cmp	x2, #DMA_TO_DEVICE
> +	b.ne	dmac_inv_range
> +	ret
> +ENDPROC(dmac_unmap_area)
> diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
> new file mode 100644
> index 0000000..6138d86
> --- /dev/null
> +++ b/arch/arm64/mm/flush.c
> @@ -0,0 +1,138 @@
> +/*
> + * Based on arch/arm/mm/flush.c
> + *
> + * Copyright (C) 1995-2002 Russell King
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/export.h>
> +#include <linux/mm.h>
> +#include <linux/pagemap.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/cachetype.h>
> +#include <asm/tlbflush.h>
> +
> +#include "mm.h"
> +
> +void flush_cache_mm(struct mm_struct *mm)
> +{
> +}
> +
> +void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
> +		       unsigned long end)
> +{
> +	if (vma->vm_flags & VM_EXEC)
> +		__flush_icache_all();
> +}
> +
> +void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr,
> +		      unsigned long pfn)
> +{
> +}
> +
> +static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
> +				unsigned long uaddr, void *kaddr,
> +				unsigned long len)
> +{
> +	if (vma->vm_flags & VM_EXEC) {
> +		unsigned long addr = (unsigned long)kaddr;
> +		if (icache_is_aliasing()) {
> +			__flush_dcache_area(kaddr, len);
> +			__flush_icache_all();
> +		} else {
> +			flush_icache_range(addr, addr + len);
> +		}
> +	}
> +}
> +
> +/*
> + * Copy user data from/to a page which is mapped into a different processes
> + * address space.  Really, we want to allow our "user space" model to handle
> + * this.
> + *
> + * Note that this code needs to run on the current CPU.
> + */
> +void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
> +		       unsigned long uaddr, void *dst, const void *src,
> +		       unsigned long len)
> +{
> +#ifdef CONFIG_SMP
> +	preempt_disable();
> +#endif
> +	memcpy(dst, src, len);
> +	flush_ptrace_access(vma, page, uaddr, dst, len);
> +#ifdef CONFIG_SMP
> +	preempt_enable();
> +#endif
> +}
> +
> +void __flush_dcache_page(struct address_space *mapping, struct page *page)
> +{
> +	__flush_dcache_area(page_address(page), PAGE_SIZE);
> +}
> +
> +void __sync_icache_dcache(pte_t pte)
> +{
> +	unsigned long pfn;
> +	struct page *page;
> +
> +	pfn = pte_pfn(pte);
> +	if (!pfn_valid(pfn))
> +		return;
> +
> +	page = pfn_to_page(pfn);
> +	if (!test_and_set_bit(PG_dcache_clean, &page->flags))
> +		__flush_dcache_page(NULL, page);
> +	__flush_icache_all();
> +}
> +
> +/*
> + * Ensure cache coherency between kernel mapping and userspace mapping of this
> + * page.
> + */
> +void flush_dcache_page(struct page *page)
> +{
> +	struct address_space *mapping;
> +
> +	/*
> +	 * The zero page is never written to, so never has any dirty cache
> +	 * lines, and therefore never needs to be flushed.
> +	 */
> +	if (page == ZERO_PAGE(0))
> +		return;
> +
> +	mapping = page_mapping(page);
> +
> +	if (mapping && !mapping_mapped(mapping))
> +		clear_bit(PG_dcache_clean, &page->flags);
> +	else {
> +		__flush_dcache_page(mapping, page);
> +		if (mapping)
> +			__flush_icache_all();


Is this necessary to ensure I/D coherency? Then, I would have
expected

		if (mapping) {
			__flush_dcache_page(mapping, page);
			__flush_icache_all();
		}

similar to __sync_icache_dcache() above.

What is the reason why the D-cache flush is done in different
cases than the following I-cache flush?

> +		set_bit(PG_dcache_clean, &page->flags);
> +	}
> +}
> +EXPORT_SYMBOL(flush_dcache_page);
> +
> +void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
> +{
> +}

Note that the __flush_dcache_page(mapping, page) in
flush_dcache_page() above is called when page is an anonymous page
(since mapping == NULL in this case).  If the call to
__flush_dcache_page() is right above, it should be needed
here as well?

> +
> +/*
> + * Additional functions defined in assembly.
> + */
> +EXPORT_SYMBOL(flush_cache_all);
> +EXPORT_SYMBOL(flush_icache_range);
> 
> 


- Simon

  parent reply	other threads:[~2012-09-07 19:35 UTC|newest]

Thread overview: 263+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-07 16:26 [PATCH v3 00/31] AArch64 Linux kernel port Catalin Marinas
2012-09-07 16:26 ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 01/31] arm64: Assembly macros and definitions Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 02/31] arm64: Kernel booting and initialisation Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:07   ` Arnd Bergmann
2012-09-07 19:07     ` Arnd Bergmann
2012-09-09 17:20   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-09 17:20     ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-09 23:29     ` Nicolas Pitre
2012-09-09 23:29       ` Nicolas Pitre
2012-09-10  5:53       ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10  5:53         ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 12:51         ` Catalin Marinas
2012-09-10 12:51           ` Catalin Marinas
2012-09-10 12:51           ` Catalin Marinas
2012-09-10 13:53           ` Arnd Bergmann
2012-09-10 13:53             ` Arnd Bergmann
2012-09-10 13:53             ` Arnd Bergmann
2012-09-10 14:12             ` Nicolas Pitre
2012-09-10 14:12               ` Nicolas Pitre
2012-09-10 14:12               ` Nicolas Pitre
2012-09-10 14:48               ` Arnd Bergmann
2012-09-10 14:48                 ` Arnd Bergmann
2012-09-10 14:48                 ` Arnd Bergmann
2012-09-10 14:48                 ` Arnd Bergmann
2012-09-10 14:53                 ` Catalin Marinas
2012-09-10 14:53                   ` Catalin Marinas
2012-09-10 14:53                   ` Catalin Marinas
2012-09-10 15:00                 ` Nicolas Pitre
2012-09-10 15:00                   ` Nicolas Pitre
2012-09-10 15:00                   ` Nicolas Pitre
2012-09-10 15:21           ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 15:21             ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 15:21             ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 15:21             ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 16:08             ` Catalin Marinas
2012-09-10 16:08               ` Catalin Marinas
2012-09-10 16:08               ` Catalin Marinas
2012-09-10 16:29             ` Nicolas Pitre
2012-09-10 16:29               ` Nicolas Pitre
2012-09-10 16:29               ` Nicolas Pitre
2012-09-10 20:28         ` Jon Masters
2012-09-10 20:28           ` Jon Masters
2012-09-10 16:11     ` Catalin Marinas
2012-09-10 16:11       ` Catalin Marinas
2012-09-10 16:11       ` Catalin Marinas
2012-09-12 12:08       ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-12 12:08         ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-12 12:08         ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-12 13:49         ` Catalin Marinas
2012-09-12 13:49           ` Catalin Marinas
2012-09-12 13:49           ` Catalin Marinas
2012-09-13 15:56           ` Christopher Covington
2012-09-13 15:56             ` Christopher Covington
2012-09-13 15:56             ` Christopher Covington
2012-09-13 17:11             ` Catalin Marinas
2012-09-13 17:11               ` Catalin Marinas
2012-09-13 17:11               ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 03/31] arm64: Exception handling Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:09   ` Arnd Bergmann
2012-09-07 19:09     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 04/31] arm64: MMU definitions Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:10   ` Arnd Bergmann
2012-09-07 19:10     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 05/31] arm64: MMU initialisation Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:10   ` Arnd Bergmann
2012-09-07 19:10     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 06/31] arm64: MMU fault handling and page table management Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:11   ` Arnd Bergmann
2012-09-07 19:11     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 07/31] arm64: Process management Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:20   ` Arnd Bergmann
2012-09-07 19:20     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 08/31] arm64: CPU support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:24   ` Arnd Bergmann
2012-09-07 19:24     ` Arnd Bergmann
2012-09-10 16:43     ` Catalin Marinas
2012-09-10 16:43       ` Catalin Marinas
2012-09-10 16:43       ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 09/31] arm64: Cache maintenance routines Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:28   ` Arnd Bergmann
2012-09-07 19:28     ` Arnd Bergmann
2012-09-10 16:48     ` Catalin Marinas
2012-09-10 16:48       ` Catalin Marinas
2012-09-10 16:48       ` Catalin Marinas
2012-09-10 17:29       ` Nicolas Pitre
2012-09-10 17:29         ` Nicolas Pitre
2012-09-10 17:29         ` Nicolas Pitre
2012-09-14 16:53         ` Catalin Marinas
2012-09-14 16:53           ` Catalin Marinas
2012-09-14 16:53           ` Catalin Marinas
2012-09-07 19:35   ` Simon Baatz [this message]
2012-09-07 19:35     ` Simon Baatz
2012-09-12  9:29     ` Catalin Marinas
2012-09-12  9:29       ` Catalin Marinas
2012-09-12  9:29       ` Catalin Marinas
2012-09-12 21:55       ` Simon Baatz
2012-09-12 21:55         ` Simon Baatz
2012-09-12 21:55         ` Simon Baatz
2012-09-13 12:38         ` Catalin Marinas
2012-09-13 12:38           ` Catalin Marinas
2012-09-13 12:38           ` Catalin Marinas
2012-09-13 20:14           ` Simon Baatz
2012-09-13 20:14             ` Simon Baatz
2012-09-13 20:14             ` Simon Baatz
2012-09-07 16:26 ` [PATCH v3 10/31] arm64: TLB maintenance functionality Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:28   ` Arnd Bergmann
2012-09-07 19:28     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 11/31] arm64: IRQ handling Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:37   ` Arnd Bergmann
2012-09-07 19:37     ` Arnd Bergmann
2012-09-12 10:24     ` Catalin Marinas
2012-09-12 10:24       ` Catalin Marinas
2012-09-12 10:24       ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 12/31] arm64: Atomic operations Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:37   ` Arnd Bergmann
2012-09-07 19:37     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 13/31] arm64: Device specific operations Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 14/31] arm64: DMA mapping API Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:38   ` Arnd Bergmann
2012-09-07 19:38     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 15/31] arm64: SMP support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:39   ` Arnd Bergmann
2012-09-07 19:39     ` Arnd Bergmann
2015-08-06  0:46   ` Timur Tabi
2015-08-06  9:56     ` Catalin Marinas
2015-08-10 11:00       ` Hanjun Guo
2015-08-10 17:05         ` Timur Tabi
2015-08-21 16:45           ` Timur Tabi
2015-08-24 12:14             ` Hanjun Guo
2015-08-27 22:15               ` Timur Tabi
2012-09-07 16:26 ` [PATCH v3 16/31] arm64: ELF definitions Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:40   ` Arnd Bergmann
2012-09-07 19:40     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 17/31] arm64: System calls handling Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:43   ` Arnd Bergmann
2012-09-07 19:43     ` Arnd Bergmann
2012-09-07 19:54     ` Al Viro
2012-09-07 19:54       ` Al Viro
2012-09-10  9:56     ` Catalin Marinas
2012-09-10  9:56       ` Catalin Marinas
2012-09-10  9:56       ` Catalin Marinas
2012-09-10 13:51       ` Arnd Bergmann
2012-09-10 13:51         ` Arnd Bergmann
2012-09-10 13:51         ` Arnd Bergmann
2012-09-10 14:01         ` Catalin Marinas
2012-09-10 14:01           ` Catalin Marinas
2012-09-10 14:01           ` Catalin Marinas
2012-09-10 14:24           ` Arnd Bergmann
2012-09-10 14:24             ` Arnd Bergmann
2012-09-10 14:24             ` Arnd Bergmann
2012-09-10 15:50             ` Catalin Marinas
2012-09-10 15:50               ` Catalin Marinas
2012-09-10 15:50               ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 18/31] arm64: VDSO support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:44   ` Arnd Bergmann
2012-09-07 19:44     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 19/31] arm64: Signal handling support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 20/31] arm64: User access library functions Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:46   ` Arnd Bergmann
2012-09-07 19:46     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 21/31] arm64: 32-bit (compat) applications support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:47   ` Arnd Bergmann
2012-09-07 19:47     ` Arnd Bergmann
2012-09-13  9:07     ` Catalin Marinas
2012-09-13  9:07       ` Catalin Marinas
2012-09-13  9:07       ` Catalin Marinas
2012-09-13 11:03       ` Arnd Bergmann
2012-09-13 11:03         ` Arnd Bergmann
2012-09-13 11:03         ` Arnd Bergmann
2012-09-13 15:50         ` Catalin Marinas
2012-09-13 15:50           ` Catalin Marinas
2012-09-13 15:50           ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 22/31] arm64: Floating point and SIMD Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 16:26 ` [PATCH v3 23/31] arm64: Debugging support Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 19:49   ` Arnd Bergmann
2012-09-07 19:49     ` Arnd Bergmann
2012-09-07 16:26 ` [PATCH v3 24/31] arm64: Add support for /proc/sys/debug/exception-trace Catalin Marinas
2012-09-07 16:26   ` Catalin Marinas
2012-09-07 16:27 ` [PATCH v3 25/31] arm64: Performance counters support Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 16:27 ` [PATCH v3 26/31] arm64: Miscellaneous library functions Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 19:52   ` Arnd Bergmann
2012-09-07 19:52     ` Arnd Bergmann
2012-09-12 21:12     ` Catalin Marinas
2012-09-12 21:12       ` Catalin Marinas
2012-09-12 21:12       ` Catalin Marinas
2012-09-13 10:48       ` Arnd Bergmann
2012-09-13 10:48         ` Arnd Bergmann
2012-09-13 10:48         ` Arnd Bergmann
2012-09-07 16:27 ` [PATCH v3 27/31] arm64: Loadable modules Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 19:52   ` Arnd Bergmann
2012-09-07 19:52     ` Arnd Bergmann
2012-09-07 16:27 ` [PATCH v3 28/31] arm64: Generic timers support Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 19:53   ` Arnd Bergmann
2012-09-07 19:53     ` Arnd Bergmann
2012-09-08  8:28   ` Shilimkar, Santosh
2012-09-08  8:28     ` Shilimkar, Santosh
2012-09-08  8:28     ` Shilimkar, Santosh
2012-09-07 16:27 ` [PATCH v3 29/31] arm64: Miscellaneous header files Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 19:54   ` Arnd Bergmann
2012-09-07 19:54     ` Arnd Bergmann
2012-09-07 16:27 ` [PATCH v3 30/31] arm64: Build infrastructure Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-07 19:55   ` Arnd Bergmann
2012-09-07 19:55     ` Arnd Bergmann
2012-09-07 16:27 ` [PATCH v3 31/31] arm64: MAINTAINERS update Catalin Marinas
2012-09-07 16:27   ` Catalin Marinas
2012-09-09 16:31   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-09 16:31     ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-09 16:31     ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-10 17:57     ` Nicolas Pitre
2012-09-10 17:57       ` Nicolas Pitre
2012-09-10 21:17       ` Russell King - ARM Linux
2012-09-10 21:17         ` Russell King - ARM Linux
2012-09-10 23:31         ` Nicolas Pitre
2012-09-10 23:31           ` Nicolas Pitre
2012-09-10 23:31           ` Nicolas Pitre
2012-09-07 23:25 ` [PATCH v3 00/31] AArch64 Linux kernel port Olof Johansson
2012-09-07 23:25   ` Olof Johansson
2012-09-12 14:54   ` Catalin Marinas
2012-09-12 14:54     ` Catalin Marinas
2012-09-12 14:54     ` Catalin Marinas
2012-09-08  9:18 ` Santosh Shilimkar
2012-09-08  9:18   ` Santosh Shilimkar
2012-09-08 13:59   ` Nicolas Pitre
2012-09-08 13:59     ` Nicolas Pitre
2012-09-08 14:42     ` Shilimkar, Santosh
2012-09-08 14:42       ` Shilimkar, Santosh
2012-09-10 17:53 ` Nicolas Pitre
2012-09-10 17:53   ` Nicolas Pitre
2012-09-10 20:22 ` Jon Masters
2012-09-10 20:22   ` Jon Masters
2012-09-12 11:54   ` Arnd Bergmann
2012-09-12 11:54     ` Arnd Bergmann
2012-09-12 11:54     ` Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120907193542.GA22806@schnuecks.de \
    --to=gmbnomis@gmail.com \
    --cc=arnd@arndb.de \
    --cc=catalin.marinas@arm.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.