linux/arch/mips/mm/sc-mips.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006 Chris Dearman (chris@mips.com),
   3 */
   4#include <linux/init.h>
   5#include <linux/kernel.h>
   6#include <linux/sched.h>
   7#include <linux/mm.h>
   8
   9#include <asm/cpu-type.h>
  10#include <asm/mipsregs.h>
  11#include <asm/bcache.h>
  12#include <asm/cacheops.h>
  13#include <asm/page.h>
  14#include <asm/pgtable.h>
  15#include <asm/mmu_context.h>
  16#include <asm/r4kcache.h>
  17
  18/*
  19 * MIPS32/MIPS64 L2 cache handling
  20 */
  21
  22/*
  23 * Writeback and invalidate the secondary cache before DMA.
  24 */
  25static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
  26{
  27        blast_scache_range(addr, addr + size);
  28}
  29
  30/*
  31 * Invalidate the secondary cache before DMA.
  32 */
  33static void mips_sc_inv(unsigned long addr, unsigned long size)
  34{
  35        unsigned long lsize = cpu_scache_line_size();
  36        unsigned long almask = ~(lsize - 1);
  37
  38        cache_op(Hit_Writeback_Inv_SD, addr & almask);
  39        cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask);
  40        blast_inv_scache_range(addr, addr + size);
  41}
  42
  43static void mips_sc_enable(void)
  44{
  45        /* L2 cache is permanently enabled */
  46}
  47
  48static void mips_sc_disable(void)
  49{
  50        /* L2 cache is permanently enabled */
  51}
  52
  53static struct bcache_ops mips_sc_ops = {
  54        .bc_enable = mips_sc_enable,
  55        .bc_disable = mips_sc_disable,
  56        .bc_wback_inv = mips_sc_wback_inv,
  57        .bc_inv = mips_sc_inv
  58};
  59
  60/*
  61 * Check if the L2 cache controller is activated on a particular platform.
  62 * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS
  63 * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the
  64 * cache being disabled.  However there is no guarantee for this to be
  65 * true on all platforms.  In an act of stupidity the spec defined bits
  66 * 12..15 as implementation defined so below function will eventually have
  67 * to be replaced by a platform specific probe.
  68 */
  69static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
  70{
  71        unsigned int config2 = read_c0_config2();
  72        unsigned int tmp;
  73
  74        /* Check the bypass bit (L2B) */
  75        switch (current_cpu_type()) {
  76        case CPU_34K:
  77        case CPU_74K:
  78        case CPU_1004K:
  79        case CPU_BMIPS5000:
  80                if (config2 & (1 << 12))
  81                        return 0;
  82        }
  83
  84        tmp = (config2 >> 4) & 0x0f;
  85        if (0 < tmp && tmp <= 7)
  86                c->scache.linesz = 2 << tmp;
  87        else
  88                return 0;
  89        return 1;
  90}
  91
  92static inline int __init mips_sc_probe(void)
  93{
  94        struct cpuinfo_mips *c = &current_cpu_data;
  95        unsigned int config1, config2;
  96        unsigned int tmp;
  97
  98        /* Mark as not present until probe completed */
  99        c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
 100
 101        /* Ignore anything but MIPSxx processors */
 102        if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
 103                              MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)))
 104                return 0;
 105
 106        /* Does this MIPS32/MIPS64 CPU have a config2 register? */
 107        config1 = read_c0_config1();
 108        if (!(config1 & MIPS_CONF_M))
 109                return 0;
 110
 111        config2 = read_c0_config2();
 112
 113        if (!mips_sc_is_activated(c))
 114                return 0;
 115
 116        tmp = (config2 >> 8) & 0x0f;
 117        if (0 <= tmp && tmp <= 7)
 118                c->scache.sets = 64 << tmp;
 119        else
 120                return 0;
 121
 122        tmp = (config2 >> 0) & 0x0f;
 123        if (0 <= tmp && tmp <= 7)
 124                c->scache.ways = tmp + 1;
 125        else
 126                return 0;
 127
 128        c->scache.waysize = c->scache.sets * c->scache.linesz;
 129        c->scache.waybit = __ffs(c->scache.waysize);
 130
 131        c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
 132
 133        return 1;
 134}
 135
 136int mips_sc_init(void)
 137{
 138        int found = mips_sc_probe();
 139        if (found) {
 140                mips_sc_enable();
 141                bcops = &mips_sc_ops;
 142        }
 143        return found;
 144}
 145