Subject: [PATCH] [PPC 44x] L2-cache synchronization for ppc44x

From: Yuri Tikhonov <[email-masked]>
Date: Thu, 8 Nov 2007 02:12:52 +0300

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 <[email-masked]>
Signed-off-by: Pavel Kolesnikov <[email-masked]>

--
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"
 	 */