On Tue, 16 Apr 2002, Louis Hamilton wrote: > What happens is the kernel comes up to the point in init where /sbin/init is > execve'd and hangs (or waits) forever. Since our QED RM7000 module > (which we also ported) is able to bootup all the way we don't suspect > file system problems. You may want to try disabling support for WAIT, if the errata fix is not properly engaging for some reason you might hang in init. > At the load_mmu stage of bring-up I noticed I cannot call the > "clear_enable_caches" routine without suffering an exeception. This is in > arch/mips/mm/c-sr71000.c, routine > ld_mmu_sr71000 where the call is made to clear_enable_caches as a KSEG1 > address. That's a bit odd, Linux type exceptions are generally not active when cache init is done - so the exception must come from pmon? My stuff was tested without a monitor program like pmon, Linux is the first thing the processor executed when it came out of reset. The only init done (in prom_init) is to set the tcache size and enable the tcache bits. > I noticed the config register K0 is already set (before load_mmu) to 0x3 > (Cached, Write-back) > and that L2, L3 are enabled, no doubt due to some init done by the PMON > monitor. You definately do not want to try to cache init if the caches are turned on, it will blow away any pending writebacks. This is true on the RM7K code too, so I'm not sure what the proper solution should be. This may be why you see it crash when it runs, the stack/etc could be trashed if kseg0 caching is enabled when cec is called. Presumably your pmon has been hacked to support SR71K - if it it touching the caches it is really not safe to use stuff made for RM7K on the SR71K. I have tested this on the SR71010A-600 chips, with and without tcache. > Is this the latest SR71K support patch? (I can't get access in my > browser to > http://oss.sgi.com/mips/archive to see prior postings on this...) It is the latest I have posted, internally I have a version that is against a newer 2.4 kernel, has a bug fix for the cec routine and has the right name for the chip (woops). I don't have time to make a proper diff right now, but I have attached the mm/c-sr71000.c file (note the name change) I don't think the rest of the patch has really been changed. Jason
/* Jason Gunthorpe <jgg@yottayotta.com> Copyright (C) 2002 YottaYotta. Inc. Based on c-mips32: Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. This file is subject to the terms and conditions of the GNU General Public License. See the file "COPYING" in the main directory of this archive for more details. Sandcraft SR71000 cache routines. The SR71000 is a MIPS64 compatible CPU with 4 caches: * 4 way 32K primary ICache - virtually indexed/physically tagged * 4 way 32K primary DCache - virtually indexed/physically tagged * 8 way 512K secondary cache - physically indexed/taged * 8 way up to 16M tertiary cache - physically indexed/taged (and off chip) ICache and DCache do not have any sort of snooping. Unlike the RM7k, the virtual index is 13 bits, and we use a 4k page size. This means you can have cache aliasing effects, so they have to be treated as virtually tagged. (unless that can be solved elsewhere, should investigate) Note that on this chip all the _SD type cache ops (ie Hit_Writeback_Inv_SD) are really just _S. This is in line with what the MIPS64 spec permits. Also, the line size of the tertiary cache is really the block size. The line size is always 32 bytes. The chip can tag partial blocks and the cache op instructions work on those partial blocks too. See ./Documentation/cachetlb.txt */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> #include <asm/bootinfo.h> #include <asm/cpu.h> #include <asm/bcache.h> #include <asm/io.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/mmu_context.h> // Should move to mipsregs.h #define read_32bit_cp0_registerx(source,sel) \ ({ int __res; \ __asm__ __volatile__( \ ".set\tpush\n\t" \ ".set\treorder\n\t" \ ".set\tmips64\n\t" \ "mfc0\t%0,"STR(source)","STR(sel)"\n\t" \ ".set\tmips0\n\t" \ ".set\tpop" \ : "=r" (__res)); \ __res;}) #define write_32bit_cp0_registerx(register,sel,value) \ __asm__ __volatile__( \ ".set\tmips64\n\t" \ "mtc0\t%0,"STR(register)","STR(sel)"\n\t" \ ".set\tmips0\n\t" \ "nop" \ : : "r" (value)); #undef DEBUG_CACHE /* Primary cache parameters. */ int icache_size, dcache_size; /* Size in bytes */ int ic_lsize, dc_lsize; /* LineSize in bytes */ /* Secondary cache parameters. */ unsigned int scache_size, sc_lsize; /* Again, in bytes */ /* tertiary cache (if present) parameters. */ unsigned int tcache_size, tc_lsize; /* Again, in bytes */ #include <asm/cacheops.h> #include <asm/mips32_cache.h> // Unique the SR71000 #define Index_Invalidate_T 0x2 #define Hit_Invalidate_T 0x16 static inline void blast_tcache(void) { unsigned long start = KSEG0; unsigned long end = KSEG0 + tcache_size; // Could use flash invalidate perhaps.. while(start < end) { cache_unroll(start,Index_Invalidate_T); start += tc_lsize; } } static inline void flush_tcache_line(unsigned long addr) { __asm__ __volatile__ ( ".set noreorder\n\t" ".set mips3\n\t" "cache %1, (%0)\n\t" ".set mips0\n\t" ".set reorder" : : "r" (addr), "i" (Hit_Invalidate_T)); } /* * Dummy cache handling routines for machines without boardcaches */ static void no_sc_noop(void) {} static struct bcache_ops no_sc_ops = { (void *)no_sc_noop, (void *)no_sc_noop, (void *)no_sc_noop, (void *)no_sc_noop }; struct bcache_ops *bcops = &no_sc_ops; // Clean all virtually indexed caches static inline void sr71000_flush_cache_all_pc(void) { unsigned long flags; __save_and_cli(flags); blast_dcache(); blast_icache(); __restore_flags(flags); } // This clears all caches. It is only used from a syscall.. static inline void sr71000_nuke_caches(void) { unsigned long flags; __save_and_cli(flags); blast_dcache(); blast_icache(); blast_scache(); if (tcache_size != 0) blast_tcache(); __restore_flags(flags); } /* This is called to clean out a virtual mapping. We only need to flush the I and D caches since the other two are physically tagged */ static void sr71000_flush_cache_range_pc(struct mm_struct *mm, unsigned long start, unsigned long end) { if(mm->context != 0) { unsigned long flags; #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif __save_and_cli(flags); blast_dcache(); blast_icache(); __restore_flags(flags); } } /* * On architectures like the Sparc, we could get rid of lines in * the cache created only by a certain context, but on the MIPS * (and actually certain Sparc's) we cannot. * Again, only clean the virtually tagged cache. */ static void sr71000_flush_cache_mm_pc(struct mm_struct *mm) { if(mm->context != 0) { #ifdef DEBUG_CACHE printk("cmm[%d]", (int)mm->context); #endif sr71000_flush_cache_all_pc(); } } static void sr71000_flush_cache_page_pc(struct vm_area_struct *vma, unsigned long page) { struct mm_struct *mm = vma->vm_mm; unsigned long flags; pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; /* * If ownes no valid ASID yet, cannot possibly have gotten * this page into the cache. */ if (mm->context == 0) return; #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); ptep = pte_offset(pmdp, page); /* * If the page isn't marked valid, the page cannot possibly be * in the cache. */ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; /* * Doing flushes for another ASID than the current one is * too difficult since Mips32 caches do a TLB translation * for every cache flush operation. So we do indexed flushes * in that case, which doesn't overly flush the cache too much. */ if (mm == current->active_mm) { blast_dcache_page(page); } else { /* Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. */ page = (KSEG0 + (page & (dcache_size - 1))); blast_dcache_page_indexed(page); } out: __restore_flags(flags); } /* If the addresses passed to these routines are valid, they are * either: * * 1) In KSEG0, so we can do a direct flush of the page. * 2) In KSEG2, and since every process can translate those * addresses all the time in kernel mode we can do a direct * flush. * 3) In KSEG1, no flush necessary. */ static void sr71000_flush_page_to_ram_pc(struct page *page) { blast_dcache_page((unsigned long)page_address(page)); } /* I-Cache and D-Cache are seperate and virtually tagged, these need to flush them */ static void sr71000_flush_icache_range(unsigned long start, unsigned long end) { flush_cache_all(); // only does i and d, probably excessive } static void sr71000_flush_icache_page(struct vm_area_struct *vma, struct page *page) { int address; if (!(vma->vm_flags & VM_EXEC)) return; address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & (dcache_size - 1)); blast_icache_page_indexed(address); } /* Writeback and invalidate the primary cache dcache before DMA. See asm-mips/io.h */ static void sr71000_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) { unsigned long end, a; if (size >= scache_size) { sr71000_nuke_caches(); return; } a = addr & ~(sc_lsize - 1); end = (addr + size) & ~(sc_lsize - 1); while (1) { flush_dcache_line(a); flush_scache_line(a); // Hit_Writeback_Inv_SD if (a == end) break; a += sc_lsize; } } static void sr71000_dma_cache_wback_inv_tc(unsigned long addr, unsigned long size) { unsigned long end, a; a = addr & ~(sc_lsize - 1); end = (addr + size) & ~(sc_lsize - 1); while (1) { flush_dcache_line(a); flush_scache_line(a); // Hit_Writeback_Inv_SD flush_tcache_line(a); // Hit_Invalidate_T if (a == end) break; a += sc_lsize; } } /* It is kind of silly to writeback for the inv case.. Oh well */ static void sr71000_dma_cache_inv_sc(unsigned long addr, unsigned long size) { unsigned long end, a; if (size >= scache_size) { sr71000_nuke_caches(); return; } a = addr & ~(sc_lsize - 1); end = (addr + size) & ~(sc_lsize - 1); while (1) { flush_dcache_line(a); flush_scache_line(a); // Hit_Writeback_Inv_SD if (a == end) break; a += sc_lsize; } } static void sr71000_dma_cache_inv_tc(unsigned long addr, unsigned long size) { unsigned long end, a; a = addr & ~(sc_lsize - 1); end = (addr + size) & ~(sc_lsize - 1); while (1) { flush_dcache_line(a); flush_scache_line(a); // Hit_Writeback_Inv_SD flush_tcache_line(a); // Hit_Invalidate_T if (a == end) break; a += sc_lsize; } } static void sr71000_dma_cache_wback(unsigned long addr, unsigned long size) { panic("sr71000_dma_cache_wback called - should not happen."); } /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation * fault will dump the process later on anyway ... */ static void sr71000_flush_cache_sigtramp(unsigned long addr) { protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); protected_flush_icache_line(addr & ~(ic_lsize - 1)); } /* Detect and size the various caches. */ static void __init probe_icache(unsigned long config,unsigned long config1) { unsigned int lsize; config1 = read_mips32_cp0_config1(); if ((lsize = ((config1 >> 19) & 7))) mips_cpu.icache.linesz = 2 << lsize; else mips_cpu.icache.linesz = lsize; mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7); mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7); ic_lsize = mips_cpu.icache.linesz; icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * ic_lsize; printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n", icache_size >> 10, ic_lsize, mips_cpu.icache.ways); } static void __init probe_dcache(unsigned long config,unsigned long config1) { unsigned int lsize; if ((lsize = ((config1 >> 10) & 7))) mips_cpu.dcache.linesz = 2 << lsize; else mips_cpu.dcache.linesz = lsize; mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7); mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7); dc_lsize = mips_cpu.dcache.linesz; dcache_size = mips_cpu.dcache.sets * mips_cpu.dcache.ways * dc_lsize; printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n", dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways); } static void __init probe_scache(unsigned long config,unsigned long config2) { unsigned int lsize; if ((lsize = ((config2 >> 4) & 7))) mips_cpu.scache.linesz = 2 << lsize; else mips_cpu.scache.linesz = lsize; mips_cpu.scache.sets = 64 << ((config2 >> 8) & 7); mips_cpu.scache.ways = 1 + ((config2 >> 0) & 7); sc_lsize = mips_cpu.scache.linesz; scache_size = mips_cpu.scache.sets * mips_cpu.scache.ways * sc_lsize; printk("Secondary cache %dK, linesize %d bytes (%d ways)\n", scache_size >> 10, sc_lsize, mips_cpu.scache.ways); } static void __init probe_tcache(unsigned long config,unsigned long config2) { unsigned int lsize; /* Firmware or prom_init is required to configure the size of the tertiary cache in config2 and set the TE bit in config2 to signal the external SRAM chips are present. */ if ((config2 & (1<<28)) == 0) return; if ((lsize = ((config2 >> 20) & 7))) mips_cpu.tcache.linesz = 2 << lsize; else mips_cpu.tcache.linesz = lsize; mips_cpu.tcache.sets = 64 << ((config2 >> 24) & 7); mips_cpu.tcache.ways = 1 + ((config2 >> 16) & 7); tc_lsize = mips_cpu.tcache.linesz; tcache_size = mips_cpu.tcache.sets * mips_cpu.tcache.ways * tc_lsize; printk("Tertiary cache %dK, linesize %d bytes, blocksize %d " "bytes (%d ways)\n", tcache_size >> 10, sc_lsize, tc_lsize, mips_cpu.tcache.ways); } static void __init setup_scache_funcs(void) { _flush_cache_all = sr71000_flush_cache_all_pc; ___flush_cache_all = sr71000_nuke_caches; _flush_cache_mm = sr71000_flush_cache_mm_pc; _flush_cache_range = sr71000_flush_cache_range_pc; _flush_cache_page = sr71000_flush_cache_page_pc; _flush_page_to_ram = sr71000_flush_page_to_ram_pc; // These can only be done on the primary cache. _clear_page = (void *)mips32_clear_page_dc; _copy_page = (void *)mips32_copy_page_dc; _flush_icache_page = sr71000_flush_icache_page; if (tcache_size == 0) { _dma_cache_wback_inv = sr71000_dma_cache_wback_inv_sc; _dma_cache_inv = sr71000_dma_cache_inv_sc; } else { _dma_cache_wback_inv = sr71000_dma_cache_wback_inv_tc; _dma_cache_inv = sr71000_dma_cache_inv_tc; } _dma_cache_wback = sr71000_dma_cache_wback; } /* This implements the cache intialization stuff from the SR71000 guide. After this all the caches will be empty and ready to run. It must be run from uncached space. */ static void __init clear_enable_caches(unsigned long config) { config = (config & (~CONF_CM_CMASK)) | CONF_CM_CACHABLE_NONCOHERENT; /* Primary cache init (7.1.1) SR71000 Primary Cache initialization of 4-way, 32 Kbyte line I/D caches. */ __asm__ __volatile__ ( ".set push\n" ".set noreorder\n" ".set noat\n" ".set mips64\n" // Enable KSEG0 caching " mtc0 %0, $16\n" /* It is recommended that parity be disabled during cache initialization. */ " mfc0 $1, $12\n" // Read CP0 Status Register. " li $2, 0x00010000\n" // DE Bit. " or $2, $1, $2\n" " mtc0 $2, $12\n" // Disable Parity. " ori $3, %1, 0x1FE0\n" // 256 sets. " mtc0 $0, $28\n" // Set CP0 Tag_Lo Register "1:\n" " cache 8, 0x0000($3)\n" // Index_Store_Tag_I " cache 8, 0x2000($3)\n" // Index_Store_Tag_I " cache 8, 0x4000($3)\n" // Index_Store_Tag_I " cache 8, 0x6000($3)\n" // Index_Store_Tag_I " cache 9, 0x0000($3)\n" // Index_Store_Tag_D " cache 9, 0x2000($3)\n" // Index_Store_Tag_D " cache 9, 0x4000($3)\n" // Index_Store_Tag_D " cache 9, 0x6000($3)\n" // Index_Store_Tag_D " bne $3, %1, 1b\n" " addiu $3, $3, -0x0020\n" // 32 byte cache line " mtc0 $1, $12\n" // Put original back in Status Register. ".set pop\n" : : "r"(config), "r"(KSEG0 | 0x9FD0) // arbitary address : "$1","$2","$3"); /* Secondary and tertiary flash invalidate (7.5.18) This code fragment, invalidates (also disables), and restores (re-enables) the secondary and tertiary caches. Ensure system is operating in uncached space. */ __asm__ __volatile__ ( ".set push\n" ".set noreorder\n" ".set noat\n" ".set mips64\n" " sync\n" // flush core pipeline " lw $2, 0(%0)\n" // flush pending accesses " bne $2, $2, 1f\n" // prevent I-fetches " nop\n" "1: mfc0 $1, $16, 2\n" // save current Config2 " li $2, 0x20002000\n" // set flash invalidation bits " or $2, $1, $2\n" " mtc0 $2, $16, 2\n" // invalidate & disable caches " mtc0 $1, $16, 2\n" // restore Config2 ".set pop\n" : : "r"(KSEG1) : "$1","$2"); } void __init ld_mmu_sr71000(void) { unsigned long config = read_32bit_cp0_registerx(CP0_CONFIG,0); unsigned long config1 = read_32bit_cp0_registerx(CP0_CONFIG,1); unsigned long config2 = read_32bit_cp0_registerx(CP0_CONFIG,2); void (*kseg1_cec)(unsigned long config) = (void *)KSEG1ADDR(&clear_enable_caches); // Should never happen if (!(config & (1 << 31)) || !(config1 & (1 << 31))) panic("sr71000 does not have necessary config registers"); probe_icache(config,config1); probe_dcache(config,config1); probe_scache(config,config2); probe_tcache(config,config2); setup_scache_funcs(); // Make sure the the secondary cache is turned on (always present) write_32bit_cp0_registerx(CP0_CONFIG,2,config2 | (1<<12)); #ifndef CONFIG_MIPS_UNCACHED if ((config & CONF_CM_CMASK) != CONF_CM_UNCACHED) printk("Caches already enabled, leaving alone..\n"); else kseg1_cec(config); #endif _flush_cache_sigtramp = sr71000_flush_cache_sigtramp; _flush_icache_range = sr71000_flush_icache_range; }