linux-bk/arch/mips/mm/sc-rm7k.c
<<
>>
Prefs
   1/*
   2 * sc-rm7k.c: RM7000 cache management functions.
   3 *
   4 * Copyright (C) 1997, 2001, 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
   5 */
   6
   7#undef DEBUG
   8
   9#include <linux/init.h>
  10#include <linux/kernel.h>
  11#include <linux/mm.h>
  12
  13#include <asm/addrspace.h>
  14#include <asm/bcache.h>
  15#include <asm/cacheops.h>
  16#include <asm/mipsregs.h>
  17#include <asm/processor.h>
  18
  19/* Primary cache parameters. */
  20#define sc_lsize        32
  21#define tc_pagesize     (32*128)
  22
  23/* Secondary cache parameters. */
  24#define scache_size     (256*1024)      /* Fixed to 256KiB on RM7000 */
  25
  26extern unsigned long icache_way_size, dcache_way_size;
  27
  28#include <asm/r4kcache.h>
  29
  30int rm7k_tcache_enabled;
  31
  32/*
  33 * Writeback and invalidate the primary cache dcache before DMA.
  34 * (XXX These need to be fixed ...)
  35 */
  36static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size)
  37{
  38        unsigned long end, a;
  39
  40        pr_debug("rm7k_sc_wback_inv[%08lx,%08lx]", addr, size);
  41
  42        /* Catch bad driver code */
  43        BUG_ON(size == 0);
  44
  45        a = addr & ~(sc_lsize - 1);
  46        end = (addr + size - 1) & ~(sc_lsize - 1);
  47        while (1) {
  48                flush_scache_line(a);   /* Hit_Writeback_Inv_SD */
  49                if (a == end)
  50                        break;
  51                a += sc_lsize;
  52        }
  53
  54        if (!rm7k_tcache_enabled)
  55                return;
  56
  57        a = addr & ~(tc_pagesize - 1);
  58        end = (addr + size - 1) & ~(tc_pagesize - 1);
  59        while(1) {
  60                invalidate_tcache_page(a);      /* Page_Invalidate_T */
  61                if (a == end)
  62                        break;
  63                a += tc_pagesize;
  64        }
  65}
  66
  67static void rm7k_sc_inv(unsigned long addr, unsigned long size)
  68{
  69        unsigned long end, a;
  70
  71        pr_debug("rm7k_sc_inv[%08lx,%08lx]", addr, size);
  72
  73        /* Catch bad driver code */
  74        BUG_ON(size == 0);
  75
  76        a = addr & ~(sc_lsize - 1);
  77        end = (addr + size - 1) & ~(sc_lsize - 1);
  78        while (1) {
  79                invalidate_scache_line(a);      /* Hit_Invalidate_SD */
  80                if (a == end)
  81                        break;
  82                a += sc_lsize;
  83        }
  84
  85        if (!rm7k_tcache_enabled)
  86                return;
  87
  88        a = addr & ~(tc_pagesize - 1);
  89        end = (addr + size - 1) & ~(tc_pagesize - 1);
  90        while(1) {
  91                invalidate_tcache_page(a);      /* Page_Invalidate_T */
  92                if (a == end)
  93                        break;
  94                a += tc_pagesize;
  95        }
  96}
  97
  98/*
  99 * This function is executed in the uncached segment KSEG1.
 100 * It must not touch the stack, because the stack pointer still points
 101 * into KSEG0.
 102 *
 103 * Three options:
 104 *      - Write it in assembly and guarantee that we don't use the stack.
 105 *      - Disable caching for KSEG0 before calling it.
 106 *      - Pray that GCC doesn't randomly start using the stack.
 107 *
 108 * This being Linux, we obviously take the least sane of those options -
 109 * following DaveM's lead in c-r4k.c
 110 *
 111 * It seems we get our kicks from relying on unguaranteed behaviour in GCC
 112 */
 113static __init void __rm7k_sc_enable(void)
 114{
 115        int i;
 116
 117        set_c0_config(1 << 3);                          /* CONF_SE */
 118
 119        write_c0_taglo(0);
 120        write_c0_taghi(0);
 121
 122        for (i = 0; i < scache_size; i += sc_lsize) {
 123                __asm__ __volatile__ (
 124                      ".set noreorder\n\t"
 125                      ".set mips3\n\t"
 126                      "cache %1, (%0)\n\t"
 127                      ".set mips0\n\t"
 128                      ".set reorder"
 129                      :
 130                      : "r" (KSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
 131        }
 132}
 133
 134static __init void rm7k_sc_enable(void)
 135{
 136        void (*func)(void) = (void *) KSEG1ADDR(&__rm7k_sc_enable);
 137
 138        if (read_c0_config() & 0x08)                    /* CONF_SE */
 139                return;
 140
 141        printk(KERN_INFO "Enabling secondary cache...");
 142        func();
 143}
 144
 145static void rm7k_sc_disable(void)
 146{
 147        clear_c0_config(1<<3);                          /* CONF_SE */
 148}
 149
 150struct bcache_ops rm7k_sc_ops = {
 151        .bc_enable = rm7k_sc_enable,
 152        .bc_disable = rm7k_sc_disable,
 153        .bc_wback_inv = rm7k_sc_wback_inv,
 154        .bc_inv = rm7k_sc_inv
 155};
 156
 157void __init rm7k_sc_init(void)
 158{
 159        unsigned int config = read_c0_config();
 160
 161        if ((config >> 31) & 1)         /* Bit 31 set -> no S-Cache */
 162                return;
 163
 164        printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
 165               (scache_size >> 10), sc_lsize);
 166
 167        if (!((config >> 3) & 1))       /* CONF_SE */
 168                rm7k_sc_enable();
 169
 170        /*
 171         * While we're at it let's deal with the tertiary cache.
 172         */
 173        if (!((config >> 17) & 1)) {
 174
 175                /*
 176                 * We can't enable the L3 cache yet. There may be board-specific
 177                 * magic necessary to turn it on, and blindly asking the CPU to
 178                 * start using it would may give cache errors.
 179                 *
 180                 * Also, board-specific knowledge may allow us to use the
 181                 * CACHE Flash_Invalidate_T instruction if the tag RAM supports
 182                 * it, and may specify the size of the L3 cache so we don't have
 183                 * to probe it.
 184                 */
 185                printk(KERN_INFO "Tertiary cache present, %s enabled\n",
 186                       config&(1<<12) ? "already" : "not (yet)");
 187
 188                if ((config >> 12) & 1)
 189                        rm7k_tcache_enabled = 1;
 190        }
 191
 192        bcops = &rm7k_sc_ops;
 193}
 194
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.