Subject: [PATCH] R3912 mm stuff from linux-vr tree

From: Florian Lohoff <[email-masked]>
Date: Sat, 3 Feb 2001 16:27:58 +0100

Hi,
here is a patch against the OSS tree to basically add R3912
support - It has mainly be done by Harald Koerfgen - I did basically
change the stuff to get it into the oss tree. 

The CPU Probing with the PRID is definitly not right but probably
someone else can come up with solutions. I havent got any R4650 
hardwate so i cant try.

I only booted on an R3912 Board and it seemed to work at least for
Cache detection - Could someone verify if this doesnt break R3k
Decstations e.g ?

Index: include/asm-mips/bootinfo.h
===================================================================
RCS file: /cvs/linux/include/asm-mips/bootinfo.h,v
retrieving revision 1.22
diff -u -r1.22 bootinfo.h
--- include/asm-mips/bootinfo.h	2000/12/13 19:43:03	1.22
+++ include/asm-mips/bootinfo.h	2001/02/03 15:25:58
@@ -176,14 +185,15 @@
 #define CPU_4KC                 30
 #define CPU_5KC                 31
 #define CPU_R4310               32
-#define CPU_LAST		32
+#define CPU_R3912		33
+#define CPU_LAST		33
 
 #define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \
         "R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC",         \
         "R4200", "R4400PC", "R4400SC", "R4400MC", "R4600", "R6000",          \
         "R6000A", "R8000", "R10000", "R4300", "R4650", "R4700", "R5000",     \
         "R5000A", "R4640", "Nevada", "RM7000", "R5432", "MIPS 4Kc",          \
-        "MIPS 5Kc", "R4310" }
+        "MIPS 5Kc", "R4310", "R3912" }
 
 #define COMMAND_LINE_SIZE	256
 
Index: include/asm-mips/cpu.h
===================================================================
RCS file: /cvs/linux/include/asm-mips/cpu.h,v
retrieving revision 1.3
diff -u -r1.3 cpu.h
--- include/asm-mips/cpu.h	2000/11/25 04:49:47	1.3
+++ include/asm-mips/cpu.h	2001/02/03 15:25:58
@@ -26,6 +26,8 @@
 #define PRID_IMP_R4700		0x2100
 #define PRID_IMP_R4640		0x2200
 #define PRID_IMP_R4650		0x2200		/* Same as R4640 */
+#define PRID_IMP_R3912		0x2210
+#define PRID_IMP_R3922		0x2230
 #define PRID_IMP_R5000		0x2300
 #define PRID_IMP_R5432		0x5400
 #define PRID_IMP_SONIC		0x2400
Index: arch/mips/mm/r2300.c
===================================================================
RCS file: /cvs/linux/arch/mips/mm/r2300.c,v
retrieving revision 1.27
diff -u -r1.27 r2300.c
--- arch/mips/mm/r2300.c	2000/12/13 20:34:08	1.27
+++ arch/mips/mm/r2300.c	2001/02/03 15:25:59
@@ -4,9 +4,11 @@
  * Copyright (C) 1996 David S. Miller ([email-masked])
  *
  * with a lot of changes to make this thing work for R3000s
- * Copyright (C) 1998, 2000 Harald Koerfgen
+ * Tx39XX R4k style caches added. HK
+ * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  */
+#include <asm/bootinfo.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -19,16 +21,26 @@
 #include <asm/isadep.h>
 #include <asm/io.h>
 #include <asm/wbflush.h>
+#include <asm/cpu.h>
 
-/* Primary cache parameters. */
-static unsigned long icache_size, dcache_size; /* Size in bytes */
-/* the linesizes are usually fixed on R3000s */
+/*
+ * According to the paper written by D. Miller about Linux cache & TLB
+ * flush implementation, DMA/Driver coherence should be done at the 
+ * driver layer.  Thus, normally, we don't need flush dcache for R3000.
+ * Define this if driver does not handle cache consistency during DMA ops.
+ */
+
+/* For R3000 cores with R4000 style caches */
+static unsigned long icache_size, icache_lsize;
+static unsigned long dcache_size, dcache_lsize;
+static unsigned int scache_size = 0;
+
+#include <asm/cacheops.h>
+#include <asm/r4kcache.h>
 
 #undef DEBUG_TLB
 #undef DEBUG_CACHE
 
-#define NTLB_ENTRIES       64  /* Fixed on all R23000 variants... */
-
 /* page functions */
 void r3k_clear_page(void * page)
 {
@@ -113,7 +125,7 @@
 
 	p = (volatile unsigned long *) KSEG0;
 
-	flags = read_32bit_cp0_register(CP0_STATUS);
+	save_and_cli(flags);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC);
@@ -135,8 +147,7 @@
 		if (size > 0x40000)
 			size = 0;
 	}
-
-	write_32bit_cp0_register(CP0_STATUS, flags);
+	restore_flags(flags);
 
 	return size * sizeof(*p);
 }
@@ -144,27 +155,26 @@
 static void __init probe_dcache(void)
 {
 	dcache_size = r3k_cache_size(ST0_ISC);
-	printk("Primary data cache %lukb, linesize 4 bytes\n",
+	printk("Primary data cache %dkb, linesize 4 bytes\n",
 		dcache_size >> 10);
 }
 
 static void __init probe_icache(void)
 {
 	icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
-	printk("Primary instruction cache %lukb, linesize 4 bytes\n",
+	printk("Primary instruction cache %dkb, linesize 4 bytes\n",
 		icache_size >> 10);
 }
 
-static void r3k_flush_icache_range(unsigned long start, unsigned long end)
+static void r3k_flush_icache_range(unsigned long start, unsigned long size)
 {
-	unsigned long size, i, flags;
+	unsigned long i, flags;
 	volatile unsigned char *p = (char *)start;
 
-	size = end - start;
 	if (size > icache_size)
 		size = icache_size;
 
-	flags = read_32bit_cp0_register(CP0_STATUS);
+	save_and_cli(flags);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
@@ -206,19 +216,18 @@
 		p += 0x080;
 	}
 
-	write_32bit_cp0_register(CP0_STATUS, flags);
+	restore_flags(flags);
 }
 
-static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
+static void r3k_flush_dcache_range(unsigned long start, unsigned long size)
 {
-	unsigned long size, i, flags;
+	unsigned long i, flags;
 	volatile unsigned char *p = (char *)start;
 
-	size = end - start;
 	if (size > dcache_size)
 		size = dcache_size;
 
-	flags = read_32bit_cp0_register(CP0_STATUS);
+	save_and_cli(flags);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC);
@@ -260,7 +269,7 @@
 		p += 0x080;
 	}
 
-	write_32bit_cp0_register(CP0_STATUS, flags);
+	restore_flags(flags);
 }
 
 static inline unsigned long get_phys_page (unsigned long addr,
@@ -357,7 +366,7 @@
 }
 
 static void r3k_flush_icache_page(struct vm_area_struct *vma,
-				  struct page *page)
+				  struct page *page, unsigned long address)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long physpage;
@@ -385,7 +394,7 @@
 	printk("csigtramp[%08lx]", addr);
 #endif
 
-	flags = read_32bit_cp0_register(CP0_STATUS);
+	save_and_cli(flags);
 
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
 
@@ -394,15 +403,66 @@
 		"sb\t$0,0x008(%0)\n\t"
 		: : "r" (addr) );
 
-	write_32bit_cp0_register(CP0_STATUS, flags);
+	restore_flags(flags);
 }
 
 static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
 {
 	wbflush();
-	r3k_flush_dcache_range(start, start + size);
+	r3k_flush_dcache_range(start, size);
 }
 
+static __init void r3912_size_caches(void)
+  {
+	unsigned long config;
+
+	config = read_32bit_cp0_register(CP0_ENTRYLO1);
+
+	icache_size = 1 << (10 + ((config >> 19) & 7));
+	icache_lsize = 16;
+
+	dcache_size = 1 << (10 + ((config >> 16) & 7));
+	dcache_lsize = 4;
+
+	printk("Primary instruction cache %dkb, linesize %d bytes\n",
+	       icache_size >> 10, icache_lsize);
+	printk("Primary data cache %dkb, linesize %d bytes\n",
+	       dcache_size >> 10, dcache_lsize);	
+}
+
+static void r3912_flush_icache_all(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + icache_size);
+	unsigned long dummy = 0;
+
+	/* disable icache and stop streaming */
+	__asm__ __volatile__("
+	.set	noreorder
+	mfc0	%0, $3
+	xori	%0, 32		/* toggle ICE bit */
+	mtc0	%0, $3
+	j	1f		/* stop streaming */
+	nop
+	1:	.set	reorder"
+	: : "r"(dummy));
+
+	/* invalidate icache */
+	while(start < end) {
+		cache16_unroll32(start,Index_Invalidate_I);
+		start += 0x200;
+	}
+
+	/* enable icache */
+	__asm__ __volatile__("
+	.set	noreorder
+	mfc0	%0, $3
+	xori	%0, 32		/* toggle ICE bit */
+	mtc0	%0, $3
+	.set	reorder"
+	: : "r"(dummy));
+}
+
 /* TLB operations. */
 void flush_tlb_all(void)
 {
@@ -417,7 +477,7 @@
 	save_and_cli(flags);
 	old_ctx = (get_entryhi() & 0xfc0);
 	write_32bit_cp0_register(CP0_ENTRYLO0, 0);
-	for(entry = 0; entry < NTLB_ENTRIES; entry++) {
+	for(entry = 8; entry < mips_cpu.tlbsize; entry++) {
 		write_32bit_cp0_register(CP0_INDEX, entry << 8);
 		write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12));
 		__asm__ __volatile__("tlbwi");
@@ -455,7 +515,7 @@
 #endif
 		save_and_cli(flags);
 		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-		if(size <= NTLB_ENTRIES) {
+		if(size <= mips_cpu.tlbsize) {
 			int oldpid = (get_entryhi() & 0xfc0);
 			int newpid = (mm->context & 0xfc0);
 
@@ -590,19 +650,6 @@
 		printk("[HIT]");
 #endif
 	}
-#if 0
-	if(!strcmp(current->comm, "args")) {
-		printk("<");
-		for(idx = 0; idx < NTLB_ENTRIES; idx++) {
-			set_index(idx);
-			tlb_read();
-			address = get_entryhi();
-			if((address & 0xfc0) != 0)
-				printk("[%08lx]", address);
-		}
-		printk(">\n");
-	}
-#endif
 	set_entryhi(pid);
 	restore_flags(flags);
 }
@@ -643,10 +690,22 @@
 void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
 				  unsigned long entryhi, unsigned long pagemask)
 {
-printk("r3k_add_wired_entry");
-        /*
-	 * FIXME, to be done
-	 */
+	unsigned long flags;
+	unsigned long old_ctx;
+	static unsigned long wired = 0;
+	
+	if (wired < 8) {
+		save_and_cli(flags);
+		old_ctx = get_entryhi() & 0xfc0;
+		set_entrylo0(entrylo0);
+		set_entryhi(entryhi);
+		set_index(wired);
+		wired++;
+		tlb_write_indexed();
+		set_entryhi(old_ctx);
+	        flush_tlb_all();    
+		restore_flags(flags);
+	}
 }
 
 void __init ld_mmu_r2300(void)
@@ -656,19 +715,49 @@
 	_clear_page = r3k_clear_page;
 	_copy_page = r3k_copy_page;
 
-	probe_icache();
-	probe_dcache();
+	switch (mips_cpu.cputype) {
+	case CPU_R2000:
+	case CPU_R3000:
+	case CPU_R3000A:
+		probe_icache();
+		probe_dcache();
+
+		_flush_cache_all = r3k_flush_cache_all;
+		_flush_cache_mm = r3k_flush_cache_mm;
+		_flush_cache_range = r3k_flush_cache_range;
+		_flush_cache_page = r3k_flush_cache_page;
+		_flush_cache_sigtramp = r3k_flush_cache_sigtramp;
+		_flush_page_to_ram = r3k_flush_page_to_ram;
+		_flush_icache_page = r3k_flush_icache_page;
+		_flush_icache_range = r3k_flush_icache_range;
+
+		_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+
+		break;
+	case CPU_R3912:
+		r3912_size_caches();
+
+		_flush_cache_all = r3912_flush_icache_all;
+		_flush_cache_mm = (void (*)(struct mm_struct *))r3912_flush_icache_all;
+		_flush_cache_range = (void (*)(struct mm_struct *, unsigned long, unsigned long))r3912_flush_icache_all;
+		_flush_cache_page = (void (*)(struct vm_area_struct *, unsigned long))r3912_flush_icache_all;
+		_flush_cache_sigtramp = (void (*)(unsigned long))r3912_flush_icache_all;
+		_flush_page_to_ram = r3k_flush_page_to_ram;
+
+#warning "This is extremely ineffective: I'm flushing all caches on r3912 when I should flush just one page"
+#warning "r3912_flush_icache_page needs to be written for r3912:"
+// MFK: I'm very confused here.  The above asignments for _flush_cache_{range,page} seem to
+//      only flush the icache, and apparently do the entire cache (not too unreasonable, given
+//      the size of the cache.  So this is probably a reasonable solution for
+//      _flush_icache_{page,range} below, but what about the dcache above???  Am I misisng
+//      something?  Can someone review and remove this comment (and above #warning lines)?
+		_flush_icache_page = r3912_flush_icache_all;
+		_flush_icache_range = r3912_flush_icache_all;
 
-	_flush_cache_all = r3k_flush_cache_all;
-	_flush_cache_mm = r3k_flush_cache_mm;
-	_flush_cache_range = r3k_flush_cache_range;
-	_flush_cache_page = r3k_flush_cache_page;
-	_flush_cache_sigtramp = r3k_flush_cache_sigtramp;
-	_flush_page_to_ram = r3k_flush_page_to_ram;
-	_flush_icache_page = r3k_flush_icache_page;
-	_flush_icache_range = r3k_flush_icache_range;
+	        _dma_cache_wback_inv = (void (*)(unsigned long, unsigned long))r3k_flush_page_to_ram;
 
-        _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+		break;
+	}
 
 	flush_tlb_all();
 }
Index: arch/mips/kernel/setup.c
===================================================================
RCS file: /cvs/linux/arch/mips/kernel/setup.c,v
retrieving revision 1.48
diff -u -r1.48 setup.c
--- arch/mips/kernel/setup.c	2001/01/10 17:17:55	1.48
+++ arch/mips/kernel/setup.c	2001/02/03 15:25:59
@@ -210,10 +210,18 @@
 		mips_cpu.tlbsize = 48;
 		break;
 	case PRID_IMP_R4650:
-		mips_cpu.cputype = CPU_R4650;
-		mips_cpu.isa_level = MIPS_CPU_ISA_III;
-		mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-		mips_cpu.tlbsize = 48;
+		/* This might also be R3912 & R3922 */
+		if (mips_cpu.processor_id == PRID_IMP_R3912) {
+			mips_cpu.isa_level = MIPS_CPU_ISA_I;
+			mips_cpu.options = MIPS_CPU_TLB;
+			mips_cpu.tlbsize = 32;
+			mips_cpu.cputype = CPU_R3912;
+		} else {
+			mips_cpu.cputype = CPU_R4650;
+			mips_cpu.isa_level = MIPS_CPU_ISA_III;
+			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+			mips_cpu.tlbsize = 48;
+		}
 		break;
 	case PRID_IMP_R4700:
 		mips_cpu.cputype = CPU_R4700;

Flo
-- 
Florian Lohoff                  [email-masked]             +49-5201-669912
     Why is it called "common sense" when nobody seems to have any?

---

From: Karsten Merker <[email-masked]>
Date: Sat, 3 Feb 2001 18:05:32 +0100

On Sat, Feb 03, 2001 at 04:27:58PM +0100, Florian Lohoff wrote:

[PATCH]
> Cache detection - Could someone verify if this doesnt break R3k

It looks like the DECstation support is already broken again :-(. I have
just tried to test the current CVS on a 5000/150 - the kernel crashes just
after mounting the rootfs. Anybody with similar experience?

Greetings,
Karsten
-- 
#include <standard_disclaimer>
Nach Paragraph 28 Abs. 3 Bundesdatenschutzgesetz widerspreche ich der
Nutzung oder Uebermittlung meiner Daten fuer Werbezwecke oder fuer die
Markt- oder Meinungsforschung.

---

From: Florian Lohoff <[email-masked]>
Date: Sat, 3 Feb 2001 19:24:53 +0100

> after mounting the rootfs. Anybody with similar experience?

This is R4k and yes i have seen that too - But i cant find why but i didnt
have the time to search much.

Flo

---

From: Harald Koerfgen <[email-masked]>
Date: Mon, 05 Feb 2001 20:03:12 +0100 (CET)

> change the stuff to get it into the oss tree. 

Now that I am seeing the stuff again I would say that it's in badly need of
some polishing here and there :)

-- 
Regards,
Harald