 031bd879f7
			
		
	
	
	031bd879f7
	
	
	
		
			
			ARM v7 architecture introduced the concept of cache levels and related control registers. New processors like A7 and A15 embed an L2 unified cache controller that becomes part of the cache level hierarchy. Some operations in the kernel like cpu_suspend and __cpu_disable do not require a flush of the entire cache hierarchy to DRAM but just the cache levels belonging to the Level of Unification Inner Shareable (LoUIS), which in most of ARM v7 systems correspond to L1. The current cache flushing API used in cpu_suspend and __cpu_disable, flush_cache_all(), ends up flushing the whole cache hierarchy since for v7 it cleans and invalidates all cache levels up to Level of Coherency (LoC) which cripples system performance when used in hot paths like hotplug and cpuidle. Therefore a new kernel cache maintenance API must be added to cope with latest ARM system requirements. This patch adds flush_cache_louis() to the ARM kernel cache maintenance API. This function cleans and invalidates all data cache levels up to the Level of Unification Inner Shareable (LoUIS) and invalidates the instruction cache for processors that support it (> v7). This patch also creates an alias of the cache LoUIS function to flush_kern_all for all processor versions prior to v7, so that the current cache flushing behaviour is unchanged for those processors. v7 cache maintenance code implements a cache LoUIS function that cleans and invalidates the D-cache up to LoUIS and invalidates the I-cache, according to the new API. Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Reviewed-by: Nicolas Pitre <nico@linaro.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Tested-by: Shawn Guo <shawn.guo@linaro.org>
		
			
				
	
	
		
			205 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  *  linux/arch/arm/mm/cache-v4wt.S
 | |
|  *
 | |
|  *  Copyright (C) 1997-2002 Russell king
 | |
|  *
 | |
|  * 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.
 | |
|  *
 | |
|  *  ARMv4 write through cache operations support.
 | |
|  *
 | |
|  *  We assume that the write buffer is not enabled.
 | |
|  */
 | |
| #include <linux/linkage.h>
 | |
| #include <linux/init.h>
 | |
| #include <asm/page.h>
 | |
| #include "proc-macros.S"
 | |
| 
 | |
| /*
 | |
|  * The size of one data cache line.
 | |
|  */
 | |
| #define CACHE_DLINESIZE	32
 | |
| 
 | |
| /*
 | |
|  * The number of data cache segments.
 | |
|  */
 | |
| #define CACHE_DSEGMENTS	8
 | |
| 
 | |
| /*
 | |
|  * The number of lines in a cache segment.
 | |
|  */
 | |
| #define CACHE_DENTRIES	64
 | |
| 
 | |
| /*
 | |
|  * This is the size at which it becomes more efficient to
 | |
|  * clean the whole cache, rather than using the individual
 | |
|  * cache line maintenance instructions.
 | |
|  *
 | |
|  * *** This needs benchmarking
 | |
|  */
 | |
| #define CACHE_DLIMIT	16384
 | |
| 
 | |
| /*
 | |
|  *	flush_icache_all()
 | |
|  *
 | |
|  *	Unconditionally clean and invalidate the entire icache.
 | |
|  */
 | |
| ENTRY(v4wt_flush_icache_all)
 | |
| 	mov	r0, #0
 | |
| 	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
 | |
| 	mov	pc, lr
 | |
| ENDPROC(v4wt_flush_icache_all)
 | |
| 
 | |
| /*
 | |
|  *	flush_user_cache_all()
 | |
|  *
 | |
|  *	Invalidate all cache entries in a particular address
 | |
|  *	space.
 | |
|  */
 | |
| ENTRY(v4wt_flush_user_cache_all)
 | |
| 	/* FALLTHROUGH */
 | |
| /*
 | |
|  *	flush_kern_cache_all()
 | |
|  *
 | |
|  *	Clean and invalidate the entire cache.
 | |
|  */
 | |
| ENTRY(v4wt_flush_kern_cache_all)
 | |
| 	mov	r2, #VM_EXEC
 | |
| 	mov	ip, #0
 | |
| __flush_whole_cache:
 | |
| 	tst	r2, #VM_EXEC
 | |
| 	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
 | |
| 	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
 | |
| 	mov	pc, lr
 | |
| 
 | |
| /*
 | |
|  *	flush_user_cache_range(start, end, flags)
 | |
|  *
 | |
|  *	Clean and invalidate a range of cache entries in the specified
 | |
|  *	address space.
 | |
|  *
 | |
|  *	- start - start address (inclusive, page aligned)
 | |
|  *	- end	- end address (exclusive, page aligned)
 | |
|  *	- flags	- vma_area_struct flags describing address space
 | |
|  */
 | |
| ENTRY(v4wt_flush_user_cache_range)
 | |
| 	sub	r3, r1, r0			@ calculate total size
 | |
| 	cmp	r3, #CACHE_DLIMIT
 | |
| 	bhs	__flush_whole_cache
 | |
| 
 | |
| 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
 | |
| 	tst	r2, #VM_EXEC
 | |
| 	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
 | |
| 	add	r0, r0, #CACHE_DLINESIZE
 | |
| 	cmp	r0, r1
 | |
| 	blo	1b
 | |
| 	mov	pc, lr
 | |
| 
 | |
| /*
 | |
|  *	coherent_kern_range(start, end)
 | |
|  *
 | |
|  *	Ensure coherency between the Icache and the Dcache in the
 | |
|  *	region described by start.  If you have non-snooping
 | |
|  *	Harvard caches, you need to implement this function.
 | |
|  *
 | |
|  *	- start  - virtual start address
 | |
|  *	- end	 - virtual end address
 | |
|  */
 | |
| ENTRY(v4wt_coherent_kern_range)
 | |
| 	/* FALLTRHOUGH */
 | |
| 
 | |
| /*
 | |
|  *	coherent_user_range(start, end)
 | |
|  *
 | |
|  *	Ensure coherency between the Icache and the Dcache in the
 | |
|  *	region described by start.  If you have non-snooping
 | |
|  *	Harvard caches, you need to implement this function.
 | |
|  *
 | |
|  *	- start  - virtual start address
 | |
|  *	- end	 - virtual end address
 | |
|  */
 | |
| ENTRY(v4wt_coherent_user_range)
 | |
| 	bic	r0, r0, #CACHE_DLINESIZE - 1
 | |
| 1:	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
 | |
| 	add	r0, r0, #CACHE_DLINESIZE
 | |
| 	cmp	r0, r1
 | |
| 	blo	1b
 | |
| 	mov	r0, #0
 | |
| 	mov	pc, lr
 | |
| 
 | |
| /*
 | |
|  *	flush_kern_dcache_area(void *addr, size_t size)
 | |
|  *
 | |
|  *	Ensure no D cache aliasing occurs, either with itself or
 | |
|  *	the I cache
 | |
|  *
 | |
|  *	- addr	- kernel address
 | |
|  *	- size	- region size
 | |
|  */
 | |
| ENTRY(v4wt_flush_kern_dcache_area)
 | |
| 	mov	r2, #0
 | |
| 	mcr	p15, 0, r2, c7, c5, 0		@ invalidate I cache
 | |
| 	add	r1, r0, r1
 | |
| 	/* fallthrough */
 | |
| 
 | |
| /*
 | |
|  *	dma_inv_range(start, end)
 | |
|  *
 | |
|  *	Invalidate (discard) the specified virtual address range.
 | |
|  *	May not write back any entries.  If 'start' or 'end'
 | |
|  *	are not cache line aligned, those lines must be written
 | |
|  *	back.
 | |
|  *
 | |
|  *	- start  - virtual start address
 | |
|  *	- end	 - virtual end address
 | |
|  */
 | |
| v4wt_dma_inv_range:
 | |
| 	bic	r0, r0, #CACHE_DLINESIZE - 1
 | |
| 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
 | |
| 	add	r0, r0, #CACHE_DLINESIZE
 | |
| 	cmp	r0, r1
 | |
| 	blo	1b
 | |
| 	mov	pc, lr
 | |
| 
 | |
| /*
 | |
|  *	dma_flush_range(start, end)
 | |
|  *
 | |
|  *	Clean and invalidate the specified virtual address range.
 | |
|  *
 | |
|  *	- start  - virtual start address
 | |
|  *	- end	 - virtual end address
 | |
|  */
 | |
| 	.globl	v4wt_dma_flush_range
 | |
| 	.equ	v4wt_dma_flush_range, v4wt_dma_inv_range
 | |
| 
 | |
| /*
 | |
|  *	dma_unmap_area(start, size, dir)
 | |
|  *	- start	- kernel virtual start address
 | |
|  *	- size	- size of region
 | |
|  *	- dir	- DMA direction
 | |
|  */
 | |
| ENTRY(v4wt_dma_unmap_area)
 | |
| 	add	r1, r1, r0
 | |
| 	teq	r2, #DMA_TO_DEVICE
 | |
| 	bne	v4wt_dma_inv_range
 | |
| 	/* FALLTHROUGH */
 | |
| 
 | |
| /*
 | |
|  *	dma_map_area(start, size, dir)
 | |
|  *	- start	- kernel virtual start address
 | |
|  *	- size	- size of region
 | |
|  *	- dir	- DMA direction
 | |
|  */
 | |
| ENTRY(v4wt_dma_map_area)
 | |
| 	mov	pc, lr
 | |
| ENDPROC(v4wt_dma_unmap_area)
 | |
| ENDPROC(v4wt_dma_map_area)
 | |
| 
 | |
| 	.globl	v4wt_flush_kern_cache_louis
 | |
| 	.equ	v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all
 | |
| 
 | |
| 	__INITDATA
 | |
| 
 | |
| 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 | |
| 	define_cache_functions v4wt
 |