---------- Forwarded message ---------- Date: Mon, 26 Aug 2002 21:49:37 +0200 (CEST) From: Vivien Chappelier <glaurung@melkor.maisel.enst-bretagne.fr> To: Ralf Baechle <ralf@oss.sgi.com> Cc: Brian Murphy <brm@murphy.dk>, linux-mips@oss.sgi.com Subject: [PATCH 2.5] R5000 secondary cache support Hi, I've tested and updated Brian Murphy's R5K SC patch to the 2.5 kernel. I've also changed a few comments, changed Page_Invalidate operation to R5K_Page_Invalidate_S to be consistent with the naming of R4K cache ops, and simplified the r5k_dma_cache_inv_sc routine (no need for two 'while'). And I've also removed the extra crap for in config-shared.in in Brian's latest diff (removing spaces/formating) :) I've also tested this patch at runtime, it runs fine (as far as a 2.5.8 can run fine :)). This patch is for both 2.5.8/mips64 and 2.5.8/mips. Please comment and/or apply, Vivien. diff -Naur linux/arch/mips/config-shared.in linux.patch/arch/mips/config-shared.in --- linux/arch/mips/config-shared.in 2002-08-24 14:58:40.000000000 +0200 +++ linux.patch/arch/mips/config-shared.in 2002-08-24 16:44:34.000000000 +0200 @@ -388,6 +388,14 @@ RM7000 CONFIG_CPU_RM7000 \ SB1 CONFIG_CPU_SB1" R4x00 +if [ "$CONFIG_CPU_R5000" = "y" ]; then + define_bool CONFIG_BOARD_SCACHE y +fi + +if [ "$CONFIG_CPU_NEVADA" = "y" ]; then + define_bool CONFIG_BOARD_SCACHE y +fi + if [ "$CONFIG_CPU_MIPS32" = "y" ]; then define_bool CONFIG_CPU_HAS_PREFETCH y bool ' Support for Virtual Tagged I-cache' CONFIG_VTAG_ICACHE diff -Naur linux/arch/mips/mm/c-r4k.c linux.patch/arch/mips/mm/c-r4k.c --- linux/arch/mips/mm/c-r4k.c 2002-08-09 08:04:58.000000000 +0200 +++ linux.patch/arch/mips/mm/c-r4k.c 2002-08-24 16:44:34.000000000 +0200 @@ -1436,7 +1436,9 @@ _dma_cache_inv = r4k_dma_cache_inv_sc; } + typedef int (*probe_func_t)(unsigned long); +extern void r5k_sc_init(void); static inline void __init setup_scache(unsigned int config) { @@ -1447,12 +1449,24 @@ probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); sc_present = probe_scache_kseg1(config); - if (sc_present) { - setup_scache_funcs(); + if (!sc_present) { + setup_noscache_funcs(); return; } - setup_noscache_funcs(); + switch(mips_cpu.cputype) { + case CPU_R5000: + case CPU_NEVADA: + setup_noscache_funcs(); +#if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) + r5k_sc_init(); +#endif + break; + default: + setup_scache_funcs(); + } + + } void __init ld_mmu_r4xx0(void) diff -Naur linux/arch/mips/mm/Makefile linux.patch/arch/mips/mm/Makefile --- linux/arch/mips/mm/Makefile 2002-06-25 18:11:44.000000000 +0200 +++ linux.patch/arch/mips/mm/Makefile 2002-08-24 16:44:34.000000000 +0200 @@ -20,8 +20,10 @@ obj-$(CONFIG_CPU_R4300) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o obj-$(CONFIG_CPU_R4X00) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o obj-$(CONFIG_CPU_VR41XX) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o -obj-$(CONFIG_CPU_R5000) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o -obj-$(CONFIG_CPU_NEVADA) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o +obj-$(CONFIG_CPU_R5000) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o \ + r5k-sc.o +obj-$(CONFIG_CPU_NEVADA) += pg-r4k.o c-r4k.o tlb-r4k.o tlbex-r4k.o \ + r5k-sc.o obj-$(CONFIG_CPU_R5432) += pg-r5432.o c-r5432.o tlb-r4k.o tlbex-r4k.o obj-$(CONFIG_CPU_RM7000) += pg-rm7k.o c-rm7k.o tlb-r4k.o tlbex-r4k.o obj-$(CONFIG_CPU_R10000) += pg-andes.o c-andes.o tlb-r4k.o tlbex-r4k.o diff -Naur linux/arch/mips/mm/r5k-sc.c linux.patch/arch/mips/mm/r5k-sc.c --- linux/arch/mips/mm/r5k-sc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.patch/arch/mips/mm/r5k-sc.c 2002-08-24 17:06:25.000000000 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org), + * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/mipsregs.h> +#include <asm/bcache.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/mmu_context.h> +#include <asm/cacheops.h> + +/* Secondary cache size in bytes, if present. */ +static unsigned long scache_size; + +#define SC_LINE 32 +#define SC_PAGE (128*SC_LINE) + +#define cache_op(base,op) \ +__asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, (%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +static inline void blast_r5000_scache(void) +{ + unsigned long start = KSEG0; + unsigned long end = KSEG0 + scache_size; + + while(start < end) { + cache_op(start, R5K_Page_Invalidate_S); + start += SC_PAGE; + } +} + +static void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + blast_r5000_scache(); + return; + } + + /* On the R5000 secondary cache we cannot + * invalidate less than a page at a time. + * The secondary cache is physically indexed, write-through. + */ + a = addr & ~(SC_PAGE - 1); + end = (addr + size - 1) & ~(SC_PAGE - 1); + while (a <= end) { + cache_op(a, R5K_Page_Invalidate_S); + a += SC_PAGE; + } +} + +static void r5k_sc_enable(void) +{ + unsigned long flags; + + __save_and_cli(flags); + change_cp0_config(CONF_SE, CONF_SE); + blast_r5000_scache(); + __restore_flags(flags); +} + +static void r5k_sc_disable(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_r5000_scache(); + change_cp0_config(CONF_SE, 0); + __restore_flags(flags); +} + +static inline int __init r5k_sc_probe(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + if(config & CONF_SC) + return(0); + + scache_size = (512*1024) << ((config >> 20)&3); + + printk("R5000 SCACHE size %ldK, linesize 32 bytes.\n", + scache_size >> 10); + + return 1; +} + +struct bcache_ops r5k_sc_ops = { + r5k_sc_enable, + r5k_sc_disable, + r5k_dma_cache_inv_sc, + r5k_dma_cache_inv_sc +}; + +void __init r5k_sc_init(void) +{ + if (r5k_sc_probe()) { + r5k_sc_enable(); + bcops = &r5k_sc_ops; + } +} diff -Naur linux/arch/mips64/mm/Makefile linux.patch/arch/mips64/mm/Makefile --- linux/arch/mips64/mm/Makefile 2002-07-24 18:12:02.000000000 +0200 +++ linux.patch/arch/mips64/mm/Makefile 2002-08-24 16:46:55.000000000 +0200 @@ -11,8 +11,10 @@ obj-$(CONFIG_CPU_R4300) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o obj-$(CONFIG_CPU_R4X00) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o -obj-$(CONFIG_CPU_R5000) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o -obj-$(CONFIG_CPU_NEVADA) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o \ + r5k-sc.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o tlbex-r4k.o tlb-glue-r4k.o \ + r5k-sc.o obj-$(CONFIG_CPU_R10000) += andes.o tlbex-r4k.o tlb-glue-r4k.o obj-$(CONFIG_CPU_SB1) += pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o \ tlb-glue-r4k.o diff -Naur linux/arch/mips64/mm/r4xx0.c linux.patch/arch/mips64/mm/r4xx0.c --- linux/arch/mips64/mm/r4xx0.c 2002-08-20 01:23:54.000000000 +0200 +++ linux.patch/arch/mips64/mm/r4xx0.c 2002-08-24 16:51:47.000000000 +0200 @@ -2274,6 +2274,7 @@ } typedef int (*probe_func_t)(unsigned long); +extern int r5k_sc_init(void); static inline void __init setup_scache(unsigned int config) { @@ -2284,12 +2285,23 @@ probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); sc_present = probe_scache_kseg1(config); - if (sc_present) { - setup_scache_funcs(); + if (!sc_present) { + setup_noscache_funcs(); return; } - setup_noscache_funcs(); + switch(mips_cpu.cputype) { + case CPU_R5000: + case CPU_NEVADA: + setup_noscache_funcs(); +#if defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) + r5k_sc_init(); +#endif + break; + default: + setup_scache_funcs(); + } + } void __init ld_mmu_r4xx0(void) diff -Naur linux/arch/mips64/mm/r5k-sc.c linux.patch/arch/mips64/mm/r5k-sc.c --- linux/arch/mips64/mm/r5k-sc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.patch/arch/mips64/mm/r5k-sc.c 2002-08-24 17:12:50.000000000 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org), + * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/mipsregs.h> +#include <asm/bcache.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/mmu_context.h> +#include <asm/r4kcacheops.h> + +/* Secondary cache size in bytes, if present. */ +static unsigned long scache_size; + +#define SC_LINE 32 +#define SC_PAGE (128*SC_LINE) + +#define cache_op(base,op) \ +__asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, (%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +static inline void blast_r5000_scache(void) +{ + unsigned long start = KSEG0; + unsigned long end = KSEG0 + scache_size; + + while(start < end) { + cache_op(start, R5K_Page_Invalidate_S); + start += SC_PAGE; + } +} + +static void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + blast_r5000_scache(); + return; + } + + /* On the R5000 secondary cache we cannot + * invalidate less than a page at a time. + * The secondary cache is physically indexed, write-through. + */ + a = addr & ~(SC_PAGE - 1); + end = (addr + size - 1) & ~(SC_PAGE - 1); + while (a <= end) { + cache_op(a, R5K_Page_Invalidate_S); + a += SC_PAGE; + } +} + +static void r5k_sc_enable(void) +{ + unsigned long flags; + + __save_and_cli(flags); + change_cp0_config(CONF_SE, CONF_SE); + blast_r5000_scache(); + __restore_flags(flags); +} + +static void r5k_sc_disable(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_r5000_scache(); + change_cp0_config(CONF_SE, 0); + __restore_flags(flags); +} + +static inline int __init r5k_sc_probe(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + if(config & CONF_SC) + return(0); + + scache_size = (512*1024) << ((config >> 20)&3); + + printk("R5000 SCACHE size %ldK, linesize 32 bytes.\n", + scache_size >> 10); + + return 1; +} + +struct bcache_ops r5k_sc_ops = { + r5k_sc_enable, + r5k_sc_disable, + r5k_dma_cache_inv_sc, + r5k_dma_cache_inv_sc +}; + +void __init r5k_sc_init(void) +{ + if (r5k_sc_probe()) { + r5k_sc_enable(); + bcops = &r5k_sc_ops; + } +} diff -Naur linux/include/asm-mips/cacheops.h linux.patch/include/asm-mips/cacheops.h --- linux/include/asm-mips/cacheops.h 1997-06-01 05:17:12.000000000 +0200 +++ linux.patch/include/asm-mips/cacheops.h 2002-08-24 16:50:51.000000000 +0200 @@ -35,6 +35,7 @@ #define Hit_Writeback_Inv_D 0x15 /* 0x16 is unused */ #define Hit_Writeback_Inv_SD 0x17 +#define R5K_Page_Invalidate_S 0x17 #define Hit_Writeback_I 0x18 #define Hit_Writeback_D 0x19 /* 0x1a is unused */ diff -Naur linux/include/asm-mips/mipsregs.h linux.patch/include/asm-mips/mipsregs.h --- linux/include/asm-mips/mipsregs.h 2002-08-06 02:08:58.000000000 +0200 +++ linux.patch/include/asm-mips/mipsregs.h 2002-08-24 16:44:34.000000000 +0200 @@ -377,6 +377,7 @@ #define CONF_CU (1 << 3) #define CONF_DB (1 << 4) #define CONF_IB (1 << 5) +#define CONF_SE (1 << 12) #define CONF_SC (1 << 17) #define CONF_AC (1 << 23) #define CONF_HALT (1 << 25) diff -Naur linux/include/asm-mips64/mipsregs.h linux.patch/include/asm-mips64/mipsregs.h --- linux/include/asm-mips64/mipsregs.h 2002-08-06 02:09:00.000000000 +0200 +++ linux.patch/include/asm-mips64/mipsregs.h 2002-08-24 16:51:35.000000000 +0200 @@ -377,6 +377,7 @@ #define CONF_CU (1 << 3) #define CONF_DB (1 << 4) #define CONF_IB (1 << 5) +#define CONF_SE (1 << 12) #define CONF_SC (1 << 17) #define CONF_AC (1 << 23) #define CONF_HALT (1 << 25) diff -Naur linux/include/asm-mips64/r4kcacheops.h linux.patch/include/asm-mips64/r4kcacheops.h --- linux/include/asm-mips64/r4kcacheops.h 2001-07-09 02:25:38.000000000 +0200 +++ linux.patch/include/asm-mips64/r4kcacheops.h 2002-08-24 16:50:27.000000000 +0200 @@ -35,6 +35,7 @@ #define Hit_Writeback_Inv_D 0x15 /* 0x16 is unused */ #define Hit_Writeback_Inv_SD 0x17 +#define R5K_Page_Invalidate_S 0x17 #define Hit_Writeback_I 0x18 #define Hit_Writeback_D 0x19 /* 0x1a is unused */