linux/arch/i386/kernel/cpu/mtrr/centaur.c
<<
>>
Prefs
   1#include <linux/init.h>
   2#include <linux/mm.h>
   3#include <asm/mtrr.h>
   4#include <asm/msr.h>
   5#include "mtrr.h"
   6
   7static struct {
   8        unsigned long high;
   9        unsigned long low;
  10} centaur_mcr[8];
  11
  12static u8 centaur_mcr_reserved;
  13static u8 centaur_mcr_type;     /* 0 for winchip, 1 for winchip2 */
  14
  15/*
  16 *      Report boot time MCR setups 
  17 */
  18
  19static int
  20centaur_get_free_region(unsigned long base, unsigned long size)
  21/*  [SUMMARY] Get a free MTRR.
  22    <base> The starting (base) address of the region.
  23    <size> The size (in bytes) of the region.
  24    [RETURNS] The index of the region on success, else -1 on error.
  25*/
  26{
  27        int i, max;
  28        mtrr_type ltype;
  29        unsigned long lbase;
  30        unsigned int lsize;
  31
  32        max = num_var_ranges;
  33        for (i = 0; i < max; ++i) {
  34                if (centaur_mcr_reserved & (1 << i))
  35                        continue;
  36                mtrr_if->get(i, &lbase, &lsize, &ltype);
  37                if (lsize == 0)
  38                        return i;
  39        }
  40        return -ENOSPC;
  41}
  42
  43void
  44mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
  45{
  46        centaur_mcr[mcr].low = lo;
  47        centaur_mcr[mcr].high = hi;
  48}
  49
  50static void
  51centaur_get_mcr(unsigned int reg, unsigned long *base,
  52                unsigned int *size, mtrr_type * type)
  53{
  54        *base = centaur_mcr[reg].high >> PAGE_SHIFT;
  55        *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
  56        *type = MTRR_TYPE_WRCOMB;       /*  If it is there, it is write-combining  */
  57        if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))
  58                *type = MTRR_TYPE_UNCACHABLE;
  59        if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)
  60                *type = MTRR_TYPE_WRBACK;
  61        if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)
  62                *type = MTRR_TYPE_WRBACK;
  63
  64}
  65
  66static void centaur_set_mcr(unsigned int reg, unsigned long base,
  67                            unsigned long size, mtrr_type type)
  68{
  69        unsigned long low, high;
  70
  71        if (size == 0) {
  72                /*  Disable  */
  73                high = low = 0;
  74        } else {
  75                high = base << PAGE_SHIFT;
  76                if (centaur_mcr_type == 0)
  77                        low = -size << PAGE_SHIFT | 0x1f;       /* only support write-combining... */
  78                else {
  79                        if (type == MTRR_TYPE_UNCACHABLE)
  80                                low = -size << PAGE_SHIFT | 0x02;       /* NC */
  81                        else
  82                                low = -size << PAGE_SHIFT | 0x09;       /* WWO,WC */
  83                }
  84        }
  85        centaur_mcr[reg].high = high;
  86        centaur_mcr[reg].low = low;
  87        wrmsr(MSR_IDT_MCR0 + reg, low, high);
  88}
  89/*
  90 *      Initialise the later (saner) Winchip MCR variant. In this version
  91 *      the BIOS can pass us the registers it has used (but not their values)
  92 *      and the control register is read/write
  93 */
  94
  95static void __init
  96centaur_mcr1_init(void)
  97{
  98        unsigned i;
  99        u32 lo, hi;
 100
 101        /* Unfortunately, MCR's are read-only, so there is no way to
 102         * find out what the bios might have done.
 103         */
 104
 105        rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
 106        if (((lo >> 17) & 7) == 1) {    /* Type 1 Winchip2 MCR */
 107                lo &= ~0x1C0;   /* clear key */
 108                lo |= 0x040;    /* set key to 1 */
 109                wrmsr(MSR_IDT_MCR_CTRL, lo, hi);        /* unlock MCR */
 110        }
 111
 112        centaur_mcr_type = 1;
 113
 114        /*
 115         *  Clear any unconfigured MCR's.
 116         */
 117
 118        for (i = 0; i < 8; ++i) {
 119                if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) {
 120                        if (!(lo & (1 << (9 + i))))
 121                                wrmsr(MSR_IDT_MCR0 + i, 0, 0);
 122                        else
 123                                /*
 124                                 *      If the BIOS set up an MCR we cannot see it
 125                                 *      but we don't wish to obliterate it
 126                                 */
 127                                centaur_mcr_reserved |= (1 << i);
 128                }
 129        }
 130        /*  
 131         *  Throw the main write-combining switch... 
 132         *  However if OOSTORE is enabled then people have already done far
 133         *  cleverer things and we should behave. 
 134         */
 135
 136        lo |= 15;               /* Write combine enables */
 137        wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
 138}
 139
 140/*
 141 *      Initialise the original winchip with read only MCR registers
 142 *      no used bitmask for the BIOS to pass on and write only control
 143 */
 144
 145static void __init
 146centaur_mcr0_init(void)
 147{
 148        unsigned i;
 149
 150        /* Unfortunately, MCR's are read-only, so there is no way to
 151         * find out what the bios might have done.
 152         */
 153
 154        /* Clear any unconfigured MCR's.
 155         * This way we are sure that the centaur_mcr array contains the actual
 156         * values. The disadvantage is that any BIOS tweaks are thus undone.
 157         *
 158         */
 159        for (i = 0; i < 8; ++i) {
 160                if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0)
 161                        wrmsr(MSR_IDT_MCR0 + i, 0, 0);
 162        }
 163
 164        wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */
 165}
 166
 167/*
 168 *      Initialise Winchip series MCR registers
 169 */
 170
 171static void __init
 172centaur_mcr_init(void)
 173{
 174        struct set_mtrr_context ctxt;
 175
 176        set_mtrr_prepare_save(&ctxt);
 177        set_mtrr_cache_disable(&ctxt);
 178
 179        if (boot_cpu_data.x86_model == 4)
 180                centaur_mcr0_init();
 181        else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9)
 182                centaur_mcr1_init();
 183
 184        set_mtrr_done(&ctxt);
 185}
 186
 187static int centaur_validate_add_page(unsigned long base, 
 188                                     unsigned long size, unsigned int type)
 189{
 190        /*
 191         *  FIXME: Winchip2 supports uncached
 192         */
 193        if (type != MTRR_TYPE_WRCOMB && 
 194            (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {
 195                printk(KERN_WARNING
 196                       "mtrr: only write-combining%s supported\n",
 197                       centaur_mcr_type ? " and uncacheable are"
 198                       : " is");
 199                return -EINVAL;
 200        }
 201        return 0;
 202}
 203
 204static struct mtrr_ops centaur_mtrr_ops = {
 205        .vendor            = X86_VENDOR_CENTAUR,
 206        .init              = centaur_mcr_init,
 207        .set               = centaur_set_mcr,
 208        .get               = centaur_get_mcr,
 209        .get_free_region   = centaur_get_free_region,
 210        .validate_add_page = centaur_validate_add_page,
 211        .have_wrcomb       = positive_have_wrcomb,
 212};
 213
 214int __init centaur_init_mtrr(void)
 215{
 216        set_mtrr_ops(&centaur_mtrr_ops);
 217        return 0;
 218}
 219
 220//arch_initcall(centaur_init_mtrr);
 221
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.