Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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