* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/war.h>
#include <asm/cacheflush.h> /* for run_uncached() */
-
-/*
- * Special Variant of smp_call_function for use by cache functions:
- *
- * o No return value
- * o collapses to normal function call on UP kernels
- * o collapses to normal function call on systems with a single shared
- * primary cache.
- */
-static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
- int retry, int wait)
-{
- preempt_disable();
-
-#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
- smp_call_function(func, info, retry, wait);
-#endif
- func(info);
- preempt_enable();
-}
-
/*
* Must die.
*/
/*
* Dummy cache handling routines for machines without boardcaches
*/
-static void cache_noop(void) {}
+static void no_sc_noop(void) {}
static struct bcache_ops no_sc_ops = {
- .bc_enable = (void *)cache_noop,
- .bc_disable = (void *)cache_noop,
- .bc_wback_inv = (void *)cache_noop,
- .bc_inv = (void *)cache_noop
+ .bc_enable = (void *)no_sc_noop,
+ .bc_disable = (void *)no_sc_noop,
+ .bc_wback_inv = (void *)no_sc_noop,
+ .bc_inv = (void *)no_sc_noop
};
struct bcache_ops *bcops = &no_sc_ops;
{
unsigned long dc_lsize = cpu_dcache_line_size();
- if (dc_lsize == 0)
- r4k_blast_dcache_page = (void *)cache_noop;
- else if (dc_lsize == 16)
+ if (dc_lsize == 16)
r4k_blast_dcache_page = blast_dcache16_page;
else if (dc_lsize == 32)
r4k_blast_dcache_page = r4k_blast_dcache_page_dc32;
{
unsigned long dc_lsize = cpu_dcache_line_size();
- if (dc_lsize == 0)
- r4k_blast_dcache_page_indexed = (void *)cache_noop;
- else if (dc_lsize == 16)
+ if (dc_lsize == 16)
r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed;
else if (dc_lsize == 32)
r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed;
{
unsigned long dc_lsize = cpu_dcache_line_size();
- if (dc_lsize == 0)
- r4k_blast_dcache = (void *)cache_noop;
- else if (dc_lsize == 16)
+ if (dc_lsize == 16)
r4k_blast_dcache = blast_dcache16;
else if (dc_lsize == 32)
r4k_blast_dcache = blast_dcache32;
{
unsigned long ic_lsize = cpu_icache_line_size();
- if (ic_lsize == 0)
- r4k_blast_icache_page = (void *)cache_noop;
- else if (ic_lsize == 16)
+ if (ic_lsize == 16)
r4k_blast_icache_page = blast_icache16_page;
else if (ic_lsize == 32)
r4k_blast_icache_page = blast_icache32_page;
{
unsigned long ic_lsize = cpu_icache_line_size();
- if (ic_lsize == 0)
- r4k_blast_icache_page_indexed = (void *)cache_noop;
- else if (ic_lsize == 16)
+ if (ic_lsize == 16)
r4k_blast_icache_page_indexed = blast_icache16_page_indexed;
else if (ic_lsize == 32) {
if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x())
{
unsigned long ic_lsize = cpu_icache_line_size();
- if (ic_lsize == 0)
- r4k_blast_icache = (void *)cache_noop;
- else if (ic_lsize == 16)
+ if (ic_lsize == 16)
r4k_blast_icache = blast_icache16;
else if (ic_lsize == 32) {
if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x())
unsigned long sc_lsize = cpu_scache_line_size();
if (scache_size == 0)
- r4k_blast_scache_page = (void *)cache_noop;
+ r4k_blast_scache_page = (void *)no_sc_noop;
else if (sc_lsize == 16)
r4k_blast_scache_page = blast_scache16_page;
else if (sc_lsize == 32)
unsigned long sc_lsize = cpu_scache_line_size();
if (scache_size == 0)
- r4k_blast_scache_page_indexed = (void *)cache_noop;
+ r4k_blast_scache_page_indexed = (void *)no_sc_noop;
else if (sc_lsize == 16)
r4k_blast_scache_page_indexed = blast_scache16_page_indexed;
else if (sc_lsize == 32)
unsigned long sc_lsize = cpu_scache_line_size();
if (scache_size == 0)
- r4k_blast_scache = (void *)cache_noop;
+ r4k_blast_scache = (void *)no_sc_noop;
else if (sc_lsize == 16)
r4k_blast_scache = blast_scache16;
else if (sc_lsize == 32)
if (!cpu_has_dc_aliases)
return;
- r4k_on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1);
+ on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1);
}
static inline void local_r4k___flush_cache_all(void * args)
case CPU_R4400MC:
case CPU_R10000:
case CPU_R12000:
- case CPU_R14000:
r4k_blast_scache();
}
}
static void r4k___flush_cache_all(void)
{
- r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 1);
+ on_each_cpu(local_r4k___flush_cache_all, NULL, 1, 1);
}
static inline void local_r4k_flush_cache_range(void * args)
static void r4k_flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1);
+ on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1);
}
static inline void local_r4k_flush_cache_mm(void * args)
if (!cpu_has_dc_aliases)
return;
- r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
+ on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1);
}
struct flush_cache_page_args {
args.addr = addr;
args.pfn = pfn;
- r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1, 1);
+ on_each_cpu(local_r4k_flush_cache_page, &args, 1, 1);
}
static inline void local_r4k_flush_data_cache_page(void * addr)
static void r4k_flush_data_cache_page(unsigned long addr)
{
- r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr, 1, 1);
+ on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr, 1, 1);
}
struct flush_icache_range_args {
unsigned long end = fir_args->end;
if (!cpu_has_ic_fills_f_dc) {
- if (end - start >= dcache_size) {
+ if (end - start > dcache_size) {
r4k_blast_dcache();
} else {
R4600_HIT_CACHEOP_WAR_IMPL;
args.start = start;
args.end = end;
- r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
+ on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
instruction_hazard();
}
* secondary cache will result in any entries in the primary caches
* also getting invalidated which hopefully is a bit more economical.
*/
- if (cpu_has_inclusive_pcaches) {
+ if (cpu_has_subset_pcaches) {
unsigned long addr = (unsigned long) page_address(page);
r4k_blast_scache_page(addr);
args.vma = vma;
args.page = page;
- r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
+ on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
}
/* Catch bad driver code */
BUG_ON(size == 0);
- if (cpu_has_inclusive_pcaches) {
+ if (cpu_has_subset_pcaches) {
if (size >= scache_size)
r4k_blast_scache();
else
/* Catch bad driver code */
BUG_ON(size == 0);
- if (cpu_has_inclusive_pcaches) {
+ if (cpu_has_subset_pcaches) {
if (size >= scache_size)
r4k_blast_scache();
else
unsigned long addr = (unsigned long) arg;
R4600_HIT_CACHEOP_WAR_IMPL;
- if (dc_lsize)
- protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+ protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
if (!cpu_icache_snoops_remote_store && scache_size)
protected_writeback_scache_line(addr & ~(sc_lsize - 1));
- if (ic_lsize)
- protected_flush_icache_line(addr & ~(ic_lsize - 1));
+ protected_flush_icache_line(addr & ~(ic_lsize - 1));
if (MIPS4K_ICACHE_REFILL_WAR) {
__asm__ __volatile__ (
".set push\n\t"
static void r4k_flush_cache_sigtramp(unsigned long addr)
{
- r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1, 1);
+ on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1, 1);
}
static void r4k_flush_icache_all(void)
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 2;
- c->icache.waybit = __ffs(icache_size/2);
+ c->icache.waybit = ffs(icache_size/2) - 1;
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 2;
- c->dcache.waybit= __ffs(dcache_size/2);
+ c->dcache.waybit= ffs(dcache_size/2) - 1;
c->options |= MIPS_CPU_CACHE_CDEX_P;
break;
c->dcache.waybit = 0;
c->options |= MIPS_CPU_CACHE_CDEX_P;
- c->options |= MIPS_CPU_PREFETCH;
break;
case CPU_R4000PC:
case CPU_R10000:
case CPU_R12000:
- case CPU_R14000:
icache_size = 1 << (12 + ((config & R10K_CONF_IC) >> 29));
c->icache.linesz = 64;
c->icache.ways = 2;
break;
case CPU_VR4133:
- write_c0_config(config & ~VR41_CONF_P4K);
+ write_c0_config(config & ~CONF_EB);
case CPU_VR4131:
/* Workaround for cache instruction bug of VR4131 */
if (c->processor_id == 0x0c80U || c->processor_id == 0x0c81U ||
c->processor_id == 0x0c82U) {
- config |= 0x00400000U;
- if (c->processor_id == 0x0c80U)
- config |= VR41_CONF_BP;
+ config &= ~0x00000030U;
+ config |= 0x00410000U;
write_c0_config(config);
- } else
- c->options |= MIPS_CPU_CACHE_CDEX_P;
-
+ }
icache_size = 1 << (10 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 2;
- c->icache.waybit = __ffs(icache_size/2);
+ c->icache.waybit = ffs(icache_size/2) - 1;
dcache_size = 1 << (10 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 2;
- c->dcache.waybit = __ffs(dcache_size/2);
+ c->dcache.waybit = ffs(dcache_size/2) - 1;
+
+ c->options |= MIPS_CPU_CACHE_CDEX_P;
break;
case CPU_VR41XX:
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 4;
- c->icache.waybit = __ffs(icache_size / c->icache.ways);
+ c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 4;
- c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
+ c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1;
#if !defined(CONFIG_SMP) || !defined(RM9000_CDEX_SMP_WAR)
c->options |= MIPS_CPU_CACHE_CDEX_P;
icache_size = c->icache.sets *
c->icache.ways *
c->icache.linesz;
- c->icache.waybit = __ffs(icache_size/c->icache.ways);
+ c->icache.waybit = ffs(icache_size/c->icache.ways) - 1;
if (config & 0x8) /* VI bit */
c->icache.flags |= MIPS_CACHE_VTAG;
dcache_size = c->dcache.sets *
c->dcache.ways *
c->dcache.linesz;
- c->dcache.waybit = __ffs(dcache_size/c->dcache.ways);
+ c->dcache.waybit = ffs(dcache_size/c->dcache.ways) - 1;
c->options |= MIPS_CPU_PREFETCH;
break;
c->icache.waysize = icache_size / c->icache.ways;
c->dcache.waysize = dcache_size / c->dcache.ways;
- c->icache.sets = c->icache.linesz ?
- icache_size / (c->icache.linesz * c->icache.ways) : 0;
- c->dcache.sets = c->dcache.linesz ?
- dcache_size / (c->dcache.linesz * c->dcache.ways) : 0;
+ c->icache.sets = icache_size / (c->icache.linesz * c->icache.ways);
+ c->dcache.sets = dcache_size / (c->dcache.linesz * c->dcache.ways);
/*
* R10000 and R12000 P-caches are odd in a positive way. They're 32kB
c->dcache.flags |= MIPS_CACHE_PINDEX;
case CPU_R10000:
case CPU_R12000:
- case CPU_R14000:
case CPU_SB1:
break;
case CPU_24K:
- case CPU_34K:
- case CPU_74K:
- if ((read_c0_config7() & (1 << 16))) {
- /* effectively physically indexed dcache,
- thus no virtual aliases. */
- c->dcache.flags |= MIPS_CACHE_PINDEX;
- break;
- }
+ if (!(read_c0_config7() & (1 << 16)))
default:
- if (c->dcache.waysize > PAGE_SIZE)
- c->dcache.flags |= MIPS_CACHE_ALIASES;
+ if (c->dcache.waysize > PAGE_SIZE)
+ c->dcache.flags |= MIPS_CACHE_ALIASES;
}
switch (c->cputype) {
extern int r5k_sc_init(void);
extern int rm7k_sc_init(void);
-extern int mips_sc_init(void);
static void __init setup_scache(void)
{
case CPU_R10000:
case CPU_R12000:
- case CPU_R14000:
scache_size = 0x80000 << ((config & R10K_CONF_SS) >> 16);
c->scache.linesz = 64 << ((config >> 13) & 1);
c->scache.ways = 2;
return;
default:
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
-#ifdef CONFIG_MIPS_CPU_SCACHE
- if (mips_sc_init ()) {
- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
- scache_size >> 10,
- way_string[c->scache.ways], c->scache.linesz);
- }
-#else
- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
- panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
-#endif
- return;
- }
sc_present = 0;
}
if (!sc_present)
return;
+ if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
+ c->isa_level == MIPS_CPU_ISA_M64R1) &&
+ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
+ panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
+
/* compute a couple of other cache variables */
c->scache.waysize = scache_size / c->scache.ways;
printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n",
scache_size >> 10, way_string[c->scache.ways], c->scache.linesz);
- c->options |= MIPS_CPU_INCLUSIVE_CACHES;
-}
-
-void au1x00_fixup_config_od(void)
-{
- /*
- * c0_config.od (bit 19) was write only (and read as 0)
- * on the early revisions of Alchemy SOCs. It disables the bus
- * transaction overlapping and needs to be set to fix various errata.
- */
- switch (read_c0_prid()) {
- case 0x00030100: /* Au1000 DA */
- case 0x00030201: /* Au1000 HA */
- case 0x00030202: /* Au1000 HB */
- case 0x01030200: /* Au1500 AB */
- /*
- * Au1100 errata actually keeps silence about this bit, so we set it
- * just in case for those revisions that require it to be set according
- * to arch/mips/au1000/common/cputable.c
- */
- case 0x02030200: /* Au1100 AB */
- case 0x02030201: /* Au1100 BA */
- case 0x02030202: /* Au1100 BC */
- set_c0_config(1 << 19);
- break;
- }
+ c->options |= MIPS_CPU_SUBSET_CACHES;
}
static inline void coherency_setup(void)
case CPU_R4400MC:
clear_c0_config(CONF_CU);
break;
- /*
- * We need to catch the ealry Alchemy SOCs with
- * the write-only co_config.od bit and set it back to one...
- */
- case CPU_AU1000: /* rev. DA, HA, HB */
- case CPU_AU1100: /* rev. AB, BA, BC ?? */
- case CPU_AU1500: /* rev. AB */
- au1x00_fixup_config_od();
- break;
}
}
* This code supports virtually indexed processors and will be
* unnecessarily inefficient on physically indexed processors.
*/
- if (c->dcache.linesz)
- shm_align_mask = max_t( unsigned long,
- c->dcache.sets * c->dcache.linesz - 1,
- PAGE_SIZE - 1);
- else
- shm_align_mask = PAGE_SIZE-1;
+ shm_align_mask = max_t( unsigned long,
+ c->dcache.sets * c->dcache.linesz - 1,
+ PAGE_SIZE - 1);
+
flush_cache_all = r4k_flush_cache_all;
__flush_cache_all = r4k___flush_cache_all;
flush_cache_mm = r4k_flush_cache_mm;
flush_cache_sigtramp = r4k_flush_cache_sigtramp;
flush_icache_all = r4k_flush_icache_all;
- local_flush_data_cache_page = local_r4k_flush_data_cache_page;
flush_data_cache_page = r4k_flush_data_cache_page;
flush_icache_range = r4k_flush_icache_range;