[PATCH] [PPC 44x] L2-cache synchronization for ppc44x
Yuri Tikhonov
yur at emcraft.com
Thu Nov 8 10:12:52 EST 2007
This is the updated patch for support synchronization of L2-Cache with the external memory on the ppc44x-based platforms.
Differencies against the previous patch-set:
- remove L2_CACHE config option;
- introduce the ppc machdep to invalidate L2 cache lines;
- some code clean-up.
Signed-off-by: Yuri Tikhonov <yur at emcraft.com>
Signed-off-by: Pavel Kolesnikov <concord at emcraft.com>
--
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 1947380..b06f05c 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <asm/tlbflush.h>
+#include <asm/machdep.h>
/*
* This address range defaults to a value that is safe for all
@@ -186,6 +187,8 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
unsigned long kaddr = (unsigned long)page_address(page);
memset(page_address(page), 0, size);
flush_dcache_range(kaddr, kaddr + size);
+ if (ppc_md.l2cache_inv_range)
+ ppc_md.l2cache_inv_range(__pa(kaddr), __pa(kaddr + size));
}
/*
@@ -351,12 +354,16 @@ void __dma_sync(void *vaddr, size_t size, int direction)
BUG();
case DMA_FROM_DEVICE: /* invalidate only */
invalidate_dcache_range(start, end);
+ if (ppc_md.l2cache_inv_range)
+ ppc_md.l2cache_inv_range(__pa(start), __pa(end));
break;
case DMA_TO_DEVICE: /* writeback only */
clean_dcache_range(start, end);
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
flush_dcache_range(start, end);
+ if (ppc_md.l2cache_inv_range)
+ ppc_md.l2cache_inv_range(__pa(start), __pa(end));
break;
}
}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 46cf8fa..31c9149 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -25,6 +25,10 @@
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
+#ifdef CONFIG_44x
+#include <asm/ibm44x.h>
+#endif
+
#ifdef CONFIG_8xx
#define ISYNC_8xx isync
#else
@@ -386,6 +390,35 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
sync /* additional sync needed on g4 */
isync
blr
+
+#if defined(CONFIG_44x)
+/*
+ * Invalidate the Level-2 cache lines corresponded to the address
+ * range.
+ *
+ * invalidate_l2cache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_l2cache_range)
+ li r5,PPC44X_L2_CACHE_BYTES-1 /* align on L2-cache line */
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,PPC44X_L2_CACHE_SHIFT
+ mtctr r4
+
+ lis r4, L2C_CMD_INV>>16
+1: mtdcr DCRN_L2C0_ADDR,r3 /* write address to invalidate */
+ mtdcr DCRN_L2C0_CMD,r4 /* issue the Invalidate cmd */
+
+2: mfdcr r5,DCRN_L2C0_SR /* wait for complete */
+ andis. r5,r5,L2C_CMD_CLR>>16
+ beq 2b
+
+ addi r3,r3,PPC44X_L2_CACHE_BYTES /* next address to invalidate */
+ bdnz 1b
+ blr
+#endif
+
/*
* Write any modified data cache blocks out to memory.
* Does not invalidate the corresponding cache lines (especially for
diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c
index 6b1a801..64c663f 100644
--- a/arch/ppc/syslib/ibm440gx_common.c
+++ b/arch/ppc/syslib/ibm440gx_common.c
@@ -12,6 +12,8 @@
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/cacheflush.h>
#include <asm/ibm44x.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -201,6 +203,7 @@ void __init ibm440gx_l2c_enable(void){
asm volatile ("sync; isync" ::: "memory");
local_irq_restore(flags);
+ ppc_md.l2cache_inv_range = invalidate_l2cache_range;
}
/* Disable L2 cache */
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
index ba667a3..bdebfaa 100644
--- a/include/asm-powerpc/cacheflush.h
+++ b/include/asm-powerpc/cacheflush.h
@@ -49,6 +49,7 @@ extern void flush_dcache_range(unsigned long start, unsigned long stop);
#ifdef CONFIG_PPC32
extern void clean_dcache_range(unsigned long start, unsigned long stop);
extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
+extern void invalidate_l2cache_range(unsigned long start, unsigned long stop);
#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 71c6e7e..754f416 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -201,6 +201,8 @@ struct machdep_calls {
void (*early_serial_map)(void);
void (*kgdb_map_scc)(void);
+ void (*l2cache_inv_range)(unsigned long s, unsigned long e);
+
/*
* optional PCI "hooks"
*/
diff --git a/include/asm-ppc/ibm44x.h b/include/asm-ppc/ibm44x.h
index 8078a58..8ac0a13 100644
--- a/include/asm-ppc/ibm44x.h
+++ b/include/asm-ppc/ibm44x.h
@@ -138,7 +138,6 @@
* The "residual" board information structure the boot loader passes
* into the kernel.
*/
-#ifndef __ASSEMBLY__
/*
* DCRN definitions
@@ -596,6 +595,9 @@
#define SRAM_DPC_ENABLE 0x80000000
/* L2 Cache Controller 440GX/440SP/440SPe */
+#define PPC44X_L2_CACHE_SHIFT 5
+#define PPC44X_L2_CACHE_BYTES (1 << PPC44X_L2_CACHE_SHIFT)
+
#define DCRN_L2C0_CFG 0x030
#define L2C_CFG_L2M 0x80000000
#define L2C_CFG_ICU 0x40000000
@@ -814,6 +816,5 @@
#include <asm/ibm4xx.h>
-#endif /* __ASSEMBLY__ */
#endif /* __ASM_IBM44x_H__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index 293a444..4e7a270 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -80,6 +80,8 @@ struct machdep_calls {
void (*nvram_write_val)(int addr, unsigned char val);
void (*nvram_sync)(void);
+ void (*l2cache_inv_range)(unsigned long s, unsigned long e);
+
/*
* optional PCI "hooks"
*/
More information about the Linuxppc-dev
mailing list