linux-mips
[Top] [All Lists]

[PATCH] R3912 mm stuff from linux-vr tree

To: linux-mips@oss.sgi.com
Subject: [PATCH] R3912 mm stuff from linux-vr tree
From: Florian Lohoff <flo@rfc822.org>
Date: Sat, 3 Feb 2001 16:27:58 +0100
Organization: rfc822 - pure communication
Sender: owner-linux-mips@oss.sgi.com
User-agent: Mutt/1.2.5i
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 (dm@engr.sgi.com)
  *
  * 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                  flo@rfc822.org             +49-5201-669912
     Why is it called "common sense" when nobody seems to have any?


<Prev in Thread] Current Thread [Next in Thread>