1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249#include <linux/types.h>
250#include <linux/errno.h>
251#include <linux/sched.h>
252#include <linux/tty.h>
253#include <linux/timer.h>
254#include <linux/config.h>
255#include <linux/kernel.h>
256#include <linux/wait.h>
257#include <linux/string.h>
258#include <linux/slab.h>
259#include <linux/ioport.h>
260#include <linux/delay.h>
261#include <linux/fs.h>
262#include <linux/ctype.h>
263#include <linux/proc_fs.h>
264#include <linux/devfs_fs_kernel.h>
265#include <linux/mm.h>
266#include <linux/module.h>
267#include <linux/pci.h>
268#define MTRR_NEED_STRINGS
269#include <asm/mtrr.h>
270#include <linux/init.h>
271#include <linux/smp.h>
272#include <linux/smp_lock.h>
273
274#include <asm/uaccess.h>
275#include <asm/io.h>
276#include <asm/processor.h>
277#include <asm/system.h>
278#include <asm/pgtable.h>
279#include <asm/segment.h>
280#include <asm/bitops.h>
281#include <asm/atomic.h>
282#include <asm/msr.h>
283
284#include <asm/hardirq.h>
285#include <linux/irq.h>
286
287#define MTRR_VERSION "1.40 (20010327)"
288
289#define TRUE 1
290#define FALSE 0
291
292
293
294
295
296
297enum mtrr_if_type {
298 MTRR_IF_NONE,
299 MTRR_IF_INTEL,
300 MTRR_IF_AMD_K6,
301 MTRR_IF_CYRIX_ARR,
302 MTRR_IF_CENTAUR_MCR,
303} mtrr_if = MTRR_IF_NONE;
304
305static __initdata char *mtrr_if_name[] = {
306 "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
307};
308
309#define MTRRcap_MSR 0x0fe
310#define MTRRdefType_MSR 0x2ff
311
312#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
313#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
314
315#define NUM_FIXED_RANGES 88
316#define MTRRfix64K_00000_MSR 0x250
317#define MTRRfix16K_80000_MSR 0x258
318#define MTRRfix16K_A0000_MSR 0x259
319#define MTRRfix4K_C0000_MSR 0x268
320#define MTRRfix4K_C8000_MSR 0x269
321#define MTRRfix4K_D0000_MSR 0x26a
322#define MTRRfix4K_D8000_MSR 0x26b
323#define MTRRfix4K_E0000_MSR 0x26c
324#define MTRRfix4K_E8000_MSR 0x26d
325#define MTRRfix4K_F0000_MSR 0x26e
326#define MTRRfix4K_F8000_MSR 0x26f
327
328#ifdef CONFIG_SMP
329# define MTRR_CHANGE_MASK_FIXED 0x01
330# define MTRR_CHANGE_MASK_VARIABLE 0x02
331# define MTRR_CHANGE_MASK_DEFTYPE 0x04
332#endif
333
334
335
336typedef u8 mtrr_type;
337
338#define LINE_SIZE 80
339#define JIFFIE_TIMEOUT 100
340
341#ifdef CONFIG_SMP
342# define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
343#else
344# define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
345 TRUE)
346#endif
347
348#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)
349# define USERSPACE_INTERFACE
350#endif
351
352#ifndef USERSPACE_INTERFACE
353# define compute_ascii() while (0)
354#endif
355
356#ifdef USERSPACE_INTERFACE
357static char *ascii_buffer;
358static unsigned int ascii_buf_bytes;
359#endif
360static unsigned int *usage_table;
361static DECLARE_MUTEX(main_lock);
362
363
364#ifdef USERSPACE_INTERFACE
365static void compute_ascii (void);
366#endif
367
368
369struct set_mtrr_context
370{
371 unsigned long flags;
372 unsigned long deftype_lo;
373 unsigned long deftype_hi;
374 unsigned long cr4val;
375 unsigned long ccr3;
376};
377
378static int arr3_protected;
379
380
381static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt)
382{
383
384 __save_flags (ctxt->flags); __cli ();
385
386 if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
387 return;
388
389
390 if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) {
391 ctxt->cr4val = read_cr4();
392 write_cr4(ctxt->cr4val & (unsigned char) ~(1<<7));
393 }
394
395
396
397 {
398 unsigned int cr0 = read_cr0() | 0x40000000;
399 wbinvd();
400 write_cr0( cr0 );
401 wbinvd();
402 }
403
404 if ( mtrr_if == MTRR_IF_INTEL ) {
405
406 rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
407 } else {
408
409 ctxt->ccr3 = getCx86 (CX86_CCR3);
410 }
411}
412
413static void set_mtrr_disable (struct set_mtrr_context *ctxt)
414{
415 if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
416 return;
417
418 if ( mtrr_if == MTRR_IF_INTEL ) {
419
420 wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
421 } else {
422
423 setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
424 }
425}
426
427
428static void set_mtrr_done (struct set_mtrr_context *ctxt)
429{
430 if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) {
431 __restore_flags (ctxt->flags);
432 return;
433 }
434
435
436 wbinvd();
437
438
439 if ( mtrr_if == MTRR_IF_INTEL ) {
440
441 wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
442 } else {
443
444 setCx86 (CX86_CCR3, ctxt->ccr3);
445 }
446
447
448 write_cr0( read_cr0() & 0xbfffffff );
449
450
451 if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
452 write_cr4(ctxt->cr4val);
453
454
455 __restore_flags (ctxt->flags);
456}
457
458
459static unsigned int get_num_var_ranges (void)
460{
461 unsigned long config, dummy;
462
463 switch ( mtrr_if )
464 {
465 case MTRR_IF_INTEL:
466 rdmsr (MTRRcap_MSR, config, dummy);
467 return (config & 0xff);
468 case MTRR_IF_AMD_K6:
469 return 2;
470 case MTRR_IF_CYRIX_ARR:
471 return 8;
472 case MTRR_IF_CENTAUR_MCR:
473 return 8;
474 default:
475 return 0;
476 }
477}
478
479
480static int have_wrcomb (void)
481{
482 unsigned long config, dummy;
483 struct pci_dev *dev = NULL;
484
485
486
487
488 if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
489 if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
490 (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) {
491 printk (KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n");
492 return 0;
493 }
494 }
495
496
497 dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, NULL);
498 if(dev)
499 {
500 printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
501 return 0;
502 }
503
504 switch ( mtrr_if )
505 {
506 case MTRR_IF_INTEL:
507 rdmsr (MTRRcap_MSR, config, dummy);
508 return (config & (1<<10));
509 return 1;
510 case MTRR_IF_AMD_K6:
511 case MTRR_IF_CENTAUR_MCR:
512 case MTRR_IF_CYRIX_ARR:
513 return 1;
514 default:
515 return 0;
516 }
517}
518
519static u32 size_or_mask, size_and_mask;
520
521static void intel_get_mtrr (unsigned int reg, unsigned long *base,
522 unsigned long *size, mtrr_type *type)
523{
524 unsigned long mask_lo, mask_hi, base_lo, base_hi;
525
526 rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);
527 if ( (mask_lo & 0x800) == 0 )
528 {
529
530 *base = 0;
531 *size = 0;
532 *type = 0;
533 return;
534 }
535
536 rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
537
538
539 mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
540 | mask_lo >> PAGE_SHIFT;
541
542
543
544 *size = -mask_lo;
545 *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
546 *type = base_lo & 0xff;
547}
548
549static void cyrix_get_arr (unsigned int reg, unsigned long *base,
550 unsigned long *size, mtrr_type *type)
551{
552 unsigned long flags;
553 unsigned char arr, ccr3, rcr, shift;
554
555 arr = CX86_ARR_BASE + (reg << 1) + reg;
556
557
558 __save_flags (flags); __cli ();
559
560 ccr3 = getCx86 (CX86_CCR3);
561 setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);
562 ((unsigned char *) base)[3] = getCx86 (arr);
563 ((unsigned char *) base)[2] = getCx86 (arr+1);
564 ((unsigned char *) base)[1] = getCx86 (arr+2);
565 rcr = getCx86(CX86_RCR_BASE + reg);
566 setCx86 (CX86_CCR3, ccr3);
567
568
569 __restore_flags (flags);
570 shift = ((unsigned char *) base)[1] & 0x0f;
571 *base >>= PAGE_SHIFT;
572
573
574
575
576 if (shift)
577 *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
578 else
579 *size = 0;
580
581
582 if (reg < 7)
583 {
584 switch (rcr)
585 {
586 case 1: *type = MTRR_TYPE_UNCACHABLE; break;
587 case 8: *type = MTRR_TYPE_WRBACK; break;
588 case 9: *type = MTRR_TYPE_WRCOMB; break;
589 case 24:
590 default: *type = MTRR_TYPE_WRTHROUGH; break;
591 }
592 } else
593 {
594 switch (rcr)
595 {
596 case 0: *type = MTRR_TYPE_UNCACHABLE; break;
597 case 8: *type = MTRR_TYPE_WRCOMB; break;
598 case 9: *type = MTRR_TYPE_WRBACK; break;
599 case 25:
600 default: *type = MTRR_TYPE_WRTHROUGH; break;
601 }
602 }
603}
604
605static void amd_get_mtrr (unsigned int reg, unsigned long *base,
606 unsigned long *size, mtrr_type *type)
607{
608 unsigned long low, high;
609
610 rdmsr (MSR_K6_UWCCR, low, high);
611
612 if (reg == 1) low = high;
613
614 *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
615 *type = 0;
616 if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
617 if (low & 2) *type = MTRR_TYPE_WRCOMB;
618 if ( !(low & 3) )
619 {
620 *size = 0;
621 return;
622 }
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638 low = (~low) & 0x1FFFC;
639 *size = (low + 4) << (15 - PAGE_SHIFT);
640 return;
641}
642
643static struct
644{
645 unsigned long high;
646 unsigned long low;
647} centaur_mcr[8];
648
649static u8 centaur_mcr_reserved;
650static u8 centaur_mcr_type;
651
652
653
654
655
656void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
657{
658 centaur_mcr[mcr].low = lo;
659 centaur_mcr[mcr].high = hi;
660}
661
662static void centaur_get_mcr (unsigned int reg, unsigned long *base,
663 unsigned long *size, mtrr_type *type)
664{
665 *base = centaur_mcr[reg].high >> PAGE_SHIFT;
666 *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
667 *type = MTRR_TYPE_WRCOMB;
668 if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2))
669 *type = MTRR_TYPE_UNCACHABLE;
670 if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25)
671 *type = MTRR_TYPE_WRBACK;
672 if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31)
673 *type = MTRR_TYPE_WRBACK;
674
675}
676
677static void (*get_mtrr) (unsigned int reg, unsigned long *base,
678 unsigned long *size, mtrr_type *type);
679
680static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
681 unsigned long size, mtrr_type type, int do_safe)
682
683
684
685
686
687
688
689
690
691{
692 struct set_mtrr_context ctxt;
693
694 if (do_safe) {
695 set_mtrr_prepare_save (&ctxt);
696 set_mtrr_disable (&ctxt);
697 }
698 if (size == 0)
699 {
700
701
702 wrmsr (MTRRphysMask_MSR (reg), 0, 0);
703 }
704 else
705 {
706 wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,
707 (base & size_and_mask) >> (32 - PAGE_SHIFT));
708 wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,
709 (-size & size_and_mask) >> (32 - PAGE_SHIFT));
710 }
711 if (do_safe) set_mtrr_done (&ctxt);
712}
713
714static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
715 unsigned long size, mtrr_type type, int do_safe)
716{
717 struct set_mtrr_context ctxt;
718 unsigned char arr, arr_type, arr_size;
719
720 arr = CX86_ARR_BASE + (reg << 1) + reg;
721
722
723 if (reg >= 7)
724 size >>= 6;
725
726 size &= 0x7fff;
727 for(arr_size = 0; size; arr_size++, size >>= 1);
728
729 if (reg<7)
730 {
731 switch (type) {
732 case MTRR_TYPE_UNCACHABLE: arr_type = 1; break;
733 case MTRR_TYPE_WRCOMB: arr_type = 9; break;
734 case MTRR_TYPE_WRTHROUGH: arr_type = 24; break;
735 default: arr_type = 8; break;
736 }
737 }
738 else
739 {
740 switch (type)
741 {
742 case MTRR_TYPE_UNCACHABLE: arr_type = 0; break;
743 case MTRR_TYPE_WRCOMB: arr_type = 8; break;
744 case MTRR_TYPE_WRTHROUGH: arr_type = 25; break;
745 default: arr_type = 9; break;
746 }
747 }
748
749 if (do_safe) {
750 set_mtrr_prepare_save (&ctxt);
751 set_mtrr_disable (&ctxt);
752 }
753 base <<= PAGE_SHIFT;
754 setCx86(arr, ((unsigned char *) &base)[3]);
755 setCx86(arr+1, ((unsigned char *) &base)[2]);
756 setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
757 setCx86(CX86_RCR_BASE + reg, arr_type);
758 if (do_safe) set_mtrr_done (&ctxt);
759}
760
761static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
762 unsigned long size, mtrr_type type, int do_safe)
763
764
765
766
767
768
769
770
771
772{
773 u32 regs[2];
774 struct set_mtrr_context ctxt;
775
776 if (do_safe) {
777 set_mtrr_prepare_save (&ctxt);
778 set_mtrr_disable (&ctxt);
779 }
780
781
782
783 rdmsr (MSR_K6_UWCCR, regs[0], regs[1]);
784
785
786
787 if (size == 0)
788 regs[reg] = 0;
789 else
790
791
792
793
794
795
796
797 regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)
798 | (base<<PAGE_SHIFT) | (type+1);
799
800
801
802
803
804 wbinvd();
805 wrmsr (MSR_K6_UWCCR, regs[0], regs[1]);
806 if (do_safe) set_mtrr_done (&ctxt);
807}
808
809
810static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
811 unsigned long size, mtrr_type type,
812 int do_safe)
813{
814 struct set_mtrr_context ctxt;
815 unsigned long low, high;
816
817 if (do_safe) {
818 set_mtrr_prepare_save (&ctxt);
819 set_mtrr_disable (&ctxt);
820 }
821 if (size == 0)
822 {
823
824 high = low = 0;
825 }
826 else
827 {
828 high = base << PAGE_SHIFT;
829 if(centaur_mcr_type == 0)
830 low = -size << PAGE_SHIFT | 0x1f;
831 else
832 {
833 if(type == MTRR_TYPE_UNCACHABLE)
834 low = -size << PAGE_SHIFT | 0x02;
835 else
836 low = -size << PAGE_SHIFT | 0x09;
837 }
838 }
839 centaur_mcr[reg].high = high;
840 centaur_mcr[reg].low = low;
841 wrmsr (MSR_IDT_MCR0 + reg, low, high);
842 if (do_safe) set_mtrr_done( &ctxt );
843}
844
845static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
846 unsigned long size, mtrr_type type,
847 int do_safe);
848
849#ifdef CONFIG_SMP
850
851struct mtrr_var_range
852{
853 unsigned long base_lo;
854 unsigned long base_hi;
855 unsigned long mask_lo;
856 unsigned long mask_hi;
857};
858
859
860
861static void __init get_mtrr_var_range (unsigned int index,
862 struct mtrr_var_range *vr)
863{
864 rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi);
865 rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi);
866}
867
868
869
870
871static int __init set_mtrr_var_range_testing (unsigned int index,
872 struct mtrr_var_range *vr)
873{
874 unsigned int lo, hi;
875 int changed = FALSE;
876
877 rdmsr(MTRRphysBase_MSR(index), lo, hi);
878 if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
879 || (vr->base_hi & 0xfUL) != (hi & 0xfUL) )
880 {
881 wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
882 changed = TRUE;
883 }
884
885 rdmsr (MTRRphysMask_MSR(index), lo, hi);
886
887 if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
888 || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) )
889 {
890 wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
891 changed = TRUE;
892 }
893 return changed;
894}
895
896static void __init get_fixed_ranges(mtrr_type *frs)
897{
898 unsigned long *p = (unsigned long *)frs;
899 int i;
900
901 rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
902
903 for (i = 0; i < 2; i++)
904 rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
905 for (i = 0; i < 8; i++)
906 rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
907}
908
909static int __init set_fixed_ranges_testing(mtrr_type *frs)
910{
911 unsigned long *p = (unsigned long *)frs;
912 int changed = FALSE;
913 int i;
914 unsigned long lo, hi;
915
916 rdmsr(MTRRfix64K_00000_MSR, lo, hi);
917 if (p[0] != lo || p[1] != hi)
918 {
919 wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]);
920 changed = TRUE;
921 }
922
923 for (i = 0; i < 2; i++)
924 {
925 rdmsr (MTRRfix16K_80000_MSR + i, lo, hi);
926 if (p[2 + i*2] != lo || p[3 + i*2] != hi)
927 {
928 wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
929 changed = TRUE;
930 }
931 }
932
933 for (i = 0; i < 8; i++)
934 {
935 rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi);
936 if (p[6 + i*2] != lo || p[7 + i*2] != hi)
937 {
938 wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
939 changed = TRUE;
940 }
941 }
942 return changed;
943}
944
945struct mtrr_state
946{
947 unsigned int num_var_ranges;
948 struct mtrr_var_range *var_ranges;
949 mtrr_type fixed_ranges[NUM_FIXED_RANGES];
950 unsigned char enabled;
951 mtrr_type def_type;
952};
953
954
955
956static void __init get_mtrr_state(struct mtrr_state *state)
957{
958 unsigned int nvrs, i;
959 struct mtrr_var_range *vrs;
960 unsigned long lo, dummy;
961
962 nvrs = state->num_var_ranges = get_num_var_ranges();
963 vrs = state->var_ranges
964 = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
965 if (vrs == NULL)
966 nvrs = state->num_var_ranges = 0;
967
968 for (i = 0; i < nvrs; i++)
969 get_mtrr_var_range (i, &vrs[i]);
970 get_fixed_ranges (state->fixed_ranges);
971
972 rdmsr (MTRRdefType_MSR, lo, dummy);
973 state->def_type = (lo & 0xff);
974 state->enabled = (lo & 0xc00) >> 10;
975}
976
977
978
979static void __init finalize_mtrr_state(struct mtrr_state *state)
980{
981 if (state->var_ranges) kfree (state->var_ranges);
982}
983
984
985static unsigned long __init set_mtrr_state (struct mtrr_state *state,
986 struct set_mtrr_context *ctxt)
987
988
989
990
991
992
993{
994 unsigned int i;
995 unsigned long change_mask = 0;
996
997 for (i = 0; i < state->num_var_ranges; i++)
998 if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
999 change_mask |= MTRR_CHANGE_MASK_VARIABLE;
1000
1001 if ( set_fixed_ranges_testing(state->fixed_ranges) )
1002 change_mask |= MTRR_CHANGE_MASK_FIXED;
1003
1004
1005 if ( (ctxt->deftype_lo & 0xff) != state->def_type
1006 || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled)
1007 {
1008 ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
1009 change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
1010 }
1011
1012 return change_mask;
1013}
1014
1015
1016static atomic_t undone_count;
1017static volatile int wait_barrier_mtrr_disable = FALSE;
1018static volatile int wait_barrier_execute = FALSE;
1019static volatile int wait_barrier_cache_enable = FALSE;
1020
1021struct set_mtrr_data
1022{
1023 unsigned long smp_base;
1024 unsigned long smp_size;
1025 unsigned int smp_reg;
1026 mtrr_type smp_type;
1027};
1028
1029static void ipi_handler (void *info)
1030
1031
1032
1033{
1034 struct set_mtrr_data *data = info;
1035 struct set_mtrr_context ctxt;
1036 set_mtrr_prepare_save (&ctxt);
1037
1038 atomic_dec (&undone_count);
1039 while (wait_barrier_mtrr_disable) { rep_nop(); barrier(); }
1040 set_mtrr_disable (&ctxt);
1041
1042 atomic_dec (&undone_count);
1043 while (wait_barrier_execute) { rep_nop(); barrier(); }
1044
1045 (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
1046 data->smp_type, FALSE);
1047
1048 atomic_dec (&undone_count);
1049
1050 while (wait_barrier_cache_enable) { rep_nop(); barrier(); }
1051 set_mtrr_done (&ctxt);
1052}
1053
1054static void set_mtrr_smp (unsigned int reg, unsigned long base,
1055 unsigned long size, mtrr_type type)
1056{
1057 struct set_mtrr_data data;
1058 struct set_mtrr_context ctxt;
1059
1060 data.smp_reg = reg;
1061 data.smp_base = base;
1062 data.smp_size = size;
1063 data.smp_type = type;
1064 wait_barrier_mtrr_disable = TRUE;
1065 wait_barrier_execute = TRUE;
1066 wait_barrier_cache_enable = TRUE;
1067 atomic_set (&undone_count, smp_num_cpus - 1);
1068
1069 if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
1070 panic ("mtrr: timed out waiting for other CPUs\n");
1071
1072 set_mtrr_prepare_save (&ctxt);
1073
1074 while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
1075
1076 atomic_set (&undone_count, smp_num_cpus - 1);
1077 wait_barrier_mtrr_disable = FALSE;
1078 set_mtrr_disable (&ctxt);
1079
1080
1081 while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
1082
1083 atomic_set (&undone_count, smp_num_cpus - 1);
1084 wait_barrier_execute = FALSE;
1085 (*set_mtrr_up) (reg, base, size, type, FALSE);
1086
1087 while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
1088
1089
1090
1091 wait_barrier_cache_enable = FALSE;
1092 set_mtrr_done (&ctxt);
1093}
1094
1095
1096
1097static void __init mtrr_state_warn(unsigned long mask)
1098{
1099 if (!mask) return;
1100 if (mask & MTRR_CHANGE_MASK_FIXED)
1101 printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
1102 if (mask & MTRR_CHANGE_MASK_VARIABLE)
1103 printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
1104 if (mask & MTRR_CHANGE_MASK_DEFTYPE)
1105 printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
1106 printk ("mtrr: probably your BIOS does not setup all CPUs\n");
1107}
1108
1109#endif
1110
1111static char *attrib_to_str (int x)
1112{
1113 return (x <= 6) ? mtrr_strings[x] : "?";
1114}
1115
1116static void init_table (void)
1117{
1118 int i, max;
1119
1120 max = get_num_var_ranges ();
1121 if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) )
1122 == NULL )
1123 {
1124 printk ("mtrr: could not allocate\n");
1125 return;
1126 }
1127 for (i = 0; i < max; i++) usage_table[i] = 1;
1128#ifdef USERSPACE_INTERFACE
1129 if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL )
1130 {
1131 printk ("mtrr: could not allocate\n");
1132 return;
1133 }
1134 ascii_buf_bytes = 0;
1135 compute_ascii ();
1136#endif
1137}
1138
1139static int generic_get_free_region (unsigned long base, unsigned long size)
1140
1141
1142
1143
1144
1145{
1146 int i, max;
1147 mtrr_type ltype;
1148 unsigned long lbase, lsize;
1149
1150 max = get_num_var_ranges ();
1151 for (i = 0; i < max; ++i)
1152 {
1153 (*get_mtrr) (i, &lbase, &lsize, <ype);
1154 if (lsize == 0) return i;
1155 }
1156 return -ENOSPC;
1157}
1158
1159static int centaur_get_free_region (unsigned long base, unsigned long size)
1160
1161
1162
1163
1164
1165{
1166 int i, max;
1167 mtrr_type ltype;
1168 unsigned long lbase, lsize;
1169
1170 max = get_num_var_ranges ();
1171 for (i = 0; i < max; ++i)
1172 {
1173 if(centaur_mcr_reserved & (1<<i))
1174 continue;
1175 (*get_mtrr) (i, &lbase, &lsize, <ype);
1176 if (lsize == 0) return i;
1177 }
1178 return -ENOSPC;
1179}
1180
1181static int cyrix_get_free_region (unsigned long base, unsigned long size)
1182
1183
1184
1185
1186
1187{
1188 int i;
1189 mtrr_type ltype;
1190 unsigned long lbase, lsize;
1191
1192
1193 if (size > 0x2000)
1194 {
1195 cyrix_get_arr (7, &lbase, &lsize, <ype);
1196 if (lsize == 0) return 7;
1197
1198 }
1199 else
1200 {
1201 for (i = 0; i < 7; i++)
1202 {
1203 cyrix_get_arr (i, &lbase, &lsize, <ype);
1204 if ((i == 3) && arr3_protected) continue;
1205 if (lsize == 0) return i;
1206 }
1207
1208 cyrix_get_arr (i, &lbase, &lsize, <ype);
1209 if ((lsize == 0) && (size >= 0x40)) return i;
1210 }
1211 return -ENOSPC;
1212}
1213
1214static int (*get_free_region) (unsigned long base,
1215 unsigned long size) = generic_get_free_region;
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment)
1254{
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265 int i, max;
1266 mtrr_type ltype;
1267 unsigned long lbase, lsize, last;
1268
1269 switch ( mtrr_if )
1270 {
1271 case MTRR_IF_NONE:
1272 return -ENXIO;
1273
1274 case MTRR_IF_AMD_K6:
1275
1276
1277
1278
1279
1280
1281
1282 if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) ||
1283 (size & ~(size-1))-size || ( base & (size-1) ) )
1284 return -EINVAL;
1285 break;
1286
1287 case MTRR_IF_INTEL:
1288
1289
1290 if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
1291 boot_cpu_data.x86 == 6 &&
1292 boot_cpu_data.x86_model == 1 &&
1293 boot_cpu_data.x86_mask <= 7 )
1294 {
1295 if ( base & ((1 << (22-PAGE_SHIFT))-1) )
1296 {
1297 printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
1298 return -EINVAL;
1299 }
1300 if (!(base + size < 0x70000000 || base > 0x7003FFFF) &&
1301 (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK))
1302 {
1303 printk (KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
1304 return -EINVAL;
1305 }
1306 }
1307
1308
1309 case MTRR_IF_CYRIX_ARR:
1310 case MTRR_IF_CENTAUR_MCR:
1311 if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
1312 {
1313
1314
1315
1316 if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE))
1317 {
1318 printk (KERN_WARNING "mtrr: only write-combining%s supported\n",
1319 centaur_mcr_type?" and uncacheable are":" is");
1320 return -EINVAL;
1321 }
1322 }
1323 else if (base + size < 0x100)
1324 {
1325 printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
1326 base, size);
1327 return -EINVAL;
1328 }
1329
1330
1331 last = base + size - 1;
1332 for (lbase = base; !(lbase & 1) && (last & 1);
1333 lbase = lbase >> 1, last = last >> 1);
1334 if (lbase != last)
1335 {
1336 printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
1337 base, size);
1338 return -EINVAL;
1339 }
1340 break;
1341
1342 default:
1343 return -EINVAL;
1344 }
1345
1346 if (type >= MTRR_NUM_TYPES)
1347 {
1348 printk ("mtrr: type: %u illegal\n", type);
1349 return -EINVAL;
1350 }
1351
1352
1353 if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
1354 {
1355 printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n");
1356 return -ENOSYS;
1357 }
1358
1359 if ( base & size_or_mask || size & size_or_mask )
1360 {
1361 printk ("mtrr: base or size exceeds the MTRR width\n");
1362 return -EINVAL;
1363 }
1364
1365 increment = increment ? 1 : 0;
1366 max = get_num_var_ranges ();
1367
1368 down(&main_lock);
1369 for (i = 0; i < max; ++i)
1370 {
1371 (*get_mtrr) (i, &lbase, &lsize, <ype);
1372 if (base >= lbase + lsize) continue;
1373 if ( (base < lbase) && (base + size <= lbase) ) continue;
1374
1375 if ( (base < lbase) || (base + size > lbase + lsize) )
1376 {
1377 up(&main_lock);
1378 printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing"
1379 " 0x%lx000,0x%lx000\n",
1380 base, size, lbase, lsize);
1381 return -EINVAL;
1382 }
1383
1384 if (ltype != type)
1385 {
1386 if (type == MTRR_TYPE_UNCACHABLE) continue;
1387 up(&main_lock);
1388 printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
1389 base, size, attrib_to_str (ltype), attrib_to_str (type) );
1390 return -EINVAL;
1391 }
1392 if (increment) ++usage_table[i];
1393 compute_ascii ();
1394 up(&main_lock);
1395 return i;
1396 }
1397
1398 i = (*get_free_region) (base, size);
1399 if (i < 0)
1400 {
1401 up(&main_lock);
1402 printk ("mtrr: no more MTRRs available\n");
1403 return i;
1404 }
1405 set_mtrr (i, base, size, type);
1406 usage_table[i] = 1;
1407 compute_ascii ();
1408 up(&main_lock);
1409 return i;
1410}
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment)
1449{
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460 if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
1461 {
1462 printk ("mtrr: size and base must be multiples of 4 kiB\n");
1463 printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
1464 return -EINVAL;
1465 }
1466 return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);
1467}
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484int mtrr_del_page (int reg, unsigned long base, unsigned long size)
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494{
1495 int i, max;
1496 mtrr_type ltype;
1497 unsigned long lbase, lsize;
1498
1499 if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO;
1500
1501 max = get_num_var_ranges ();
1502 down (&main_lock);
1503 if (reg < 0)
1504 {
1505
1506 for (i = 0; i < max; ++i)
1507 {
1508 (*get_mtrr) (i, &lbase, &lsize, <ype);
1509 if (lbase == base && lsize == size)
1510 {
1511 reg = i;
1512 break;
1513 }
1514 }
1515 if (reg < 0)
1516 {
1517 up(&main_lock);
1518 printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);
1519 return -EINVAL;
1520 }
1521 }
1522 if (reg >= max)
1523 {
1524 up (&main_lock);
1525 printk ("mtrr: register: %d too big\n", reg);
1526 return -EINVAL;
1527 }
1528 if ( mtrr_if == MTRR_IF_CYRIX_ARR )
1529 {
1530 if ( (reg == 3) && arr3_protected )
1531 {
1532 up (&main_lock);
1533 printk ("mtrr: ARR3 cannot be changed\n");
1534 return -EINVAL;
1535 }
1536 }
1537 (*get_mtrr) (reg, &lbase, &lsize, <ype);
1538 if (lsize < 1)
1539 {
1540 up (&main_lock);
1541 printk ("mtrr: MTRR %d not used\n", reg);
1542 return -EINVAL;
1543 }
1544 if (usage_table[reg] < 1)
1545 {
1546 up (&main_lock);
1547 printk ("mtrr: reg: %d has count=0\n", reg);
1548 return -EINVAL;
1549 }
1550 if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
1551 compute_ascii ();
1552 up (&main_lock);
1553 return reg;
1554}
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571int mtrr_del (int reg, unsigned long base, unsigned long size)
1572
1573
1574
1575
1576
1577
1578
1579
1580{
1581 if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
1582 {
1583 printk ("mtrr: size and base must be multiples of 4 kiB\n");
1584 printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
1585 return -EINVAL;
1586 }
1587 return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
1588}
1589
1590#ifdef USERSPACE_INTERFACE
1591
1592static int mtrr_file_add (unsigned long base, unsigned long size,
1593 unsigned int type, char increment, struct file *file, int page)
1594{
1595 int reg, max;
1596 unsigned int *fcount = file->private_data;
1597
1598 max = get_num_var_ranges ();
1599 if (fcount == NULL)
1600 {
1601 if ( ( fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL) ) == NULL )
1602 {
1603 printk ("mtrr: could not allocate\n");
1604 return -ENOMEM;
1605 }
1606 memset (fcount, 0, max * sizeof *fcount);
1607 file->private_data = fcount;
1608 }
1609 if (!page) {
1610 if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
1611 {
1612 printk ("mtrr: size and base must be multiples of 4 kiB\n");
1613 printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
1614 return -EINVAL;
1615 }
1616 base >>= PAGE_SHIFT;
1617 size >>= PAGE_SHIFT;
1618 }
1619 reg = mtrr_add_page (base, size, type, 1);
1620 if (reg >= 0) ++fcount[reg];
1621 return reg;
1622}
1623
1624static int mtrr_file_del (unsigned long base, unsigned long size,
1625 struct file *file, int page)
1626{
1627 int reg;
1628 unsigned int *fcount = file->private_data;
1629
1630 if (!page) {
1631 if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
1632 {
1633 printk ("mtrr: size and base must be multiples of 4 kiB\n");
1634 printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
1635 return -EINVAL;
1636 }
1637 base >>= PAGE_SHIFT;
1638 size >>= PAGE_SHIFT;
1639 }
1640 reg = mtrr_del_page (-1, base, size);
1641 if (reg < 0) return reg;
1642 if (fcount == NULL) return reg;
1643 if (fcount[reg] < 1) return -EINVAL;
1644 --fcount[reg];
1645 return reg;
1646}
1647
1648static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
1649 loff_t *ppos)
1650{
1651 if (*ppos >= ascii_buf_bytes) return 0;
1652 if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos;
1653 if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT;
1654 *ppos += len;
1655 return len;
1656}
1657
1658static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
1659 loff_t *ppos)
1660
1661
1662
1663
1664{
1665 int i, err;
1666 unsigned long reg;
1667 unsigned long long base, size;
1668 char *ptr;
1669 char line[LINE_SIZE];
1670
1671 if ( !suser () ) return -EPERM;
1672
1673 if (ppos != &file->f_pos) return -ESPIPE;
1674 memset (line, 0, LINE_SIZE);
1675 if (len > LINE_SIZE) len = LINE_SIZE;
1676 if ( copy_from_user (line, buf, len - 1) ) return -EFAULT;
1677 ptr = line + strlen (line) - 1;
1678 if (*ptr == '\n') *ptr = '\0';
1679 if ( !strncmp (line, "disable=", 8) )
1680 {
1681 reg = simple_strtoul (line + 8, &ptr, 0);
1682 err = mtrr_del_page (reg, 0, 0);
1683 if (err < 0) return err;
1684 return len;
1685 }
1686 if ( strncmp (line, "base=", 5) )
1687 {
1688 printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
1689 return -EINVAL;
1690 }
1691 base = simple_strtoull (line + 5, &ptr, 0);
1692 for (; isspace (*ptr); ++ptr);
1693 if ( strncmp (ptr, "size=", 5) )
1694 {
1695 printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);
1696 return -EINVAL;
1697 }
1698 size = simple_strtoull (ptr + 5, &ptr, 0);
1699 if ( (base & 0xfff) || (size & 0xfff) )
1700 {
1701 printk ("mtrr: size and base must be multiples of 4 kiB\n");
1702 printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base);
1703 return -EINVAL;
1704 }
1705 for (; isspace (*ptr); ++ptr);
1706 if ( strncmp (ptr, "type=", 5) )
1707 {
1708 printk ("mtrr: no \"type=\" in line: \"%s\"\n", line);
1709 return -EINVAL;
1710 }
1711 ptr += 5;
1712 for (; isspace (*ptr); ++ptr);
1713 for (i = 0; i < MTRR_NUM_TYPES; ++i)
1714 {
1715 if ( strcmp (ptr, mtrr_strings[i]) ) continue;
1716 base >>= PAGE_SHIFT;
1717 size >>= PAGE_SHIFT;
1718 err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1);
1719 if (err < 0) return err;
1720 return len;
1721 }
1722 printk ("mtrr: illegal type: \"%s\"\n", ptr);
1723 return -EINVAL;
1724}
1725
1726static int mtrr_ioctl (struct inode *inode, struct file *file,
1727 unsigned int cmd, unsigned long arg)
1728{
1729 int err;
1730 mtrr_type type;
1731 struct mtrr_sentry sentry;
1732 struct mtrr_gentry gentry;
1733
1734 switch (cmd)
1735 {
1736 default:
1737 return -ENOIOCTLCMD;
1738 case MTRRIOC_ADD_ENTRY:
1739 if ( !suser () ) return -EPERM;
1740 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1741 return -EFAULT;
1742 err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0);
1743 if (err < 0) return err;
1744 break;
1745 case MTRRIOC_SET_ENTRY:
1746 if ( !suser () ) return -EPERM;
1747 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1748 return -EFAULT;
1749 err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
1750 if (err < 0) return err;
1751 break;
1752 case MTRRIOC_DEL_ENTRY:
1753 if ( !suser () ) return -EPERM;
1754 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1755 return -EFAULT;
1756 err = mtrr_file_del (sentry.base, sentry.size, file, 0);
1757 if (err < 0) return err;
1758 break;
1759 case MTRRIOC_KILL_ENTRY:
1760 if ( !suser () ) return -EPERM;
1761 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1762 return -EFAULT;
1763 err = mtrr_del (-1, sentry.base, sentry.size);
1764 if (err < 0) return err;
1765 break;
1766 case MTRRIOC_GET_ENTRY:
1767 if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
1768 return -EFAULT;
1769 if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
1770 (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
1771
1772
1773 if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000)
1774 gentry.base = gentry.size = gentry.type = 0;
1775 else {
1776 gentry.base <<= PAGE_SHIFT;
1777 gentry.size <<= PAGE_SHIFT;
1778 gentry.type = type;
1779 }
1780
1781 if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
1782 return -EFAULT;
1783 break;
1784 case MTRRIOC_ADD_PAGE_ENTRY:
1785 if ( !suser () ) return -EPERM;
1786 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1787 return -EFAULT;
1788 err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1);
1789 if (err < 0) return err;
1790 break;
1791 case MTRRIOC_SET_PAGE_ENTRY:
1792 if ( !suser () ) return -EPERM;
1793 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1794 return -EFAULT;
1795 err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
1796 if (err < 0) return err;
1797 break;
1798 case MTRRIOC_DEL_PAGE_ENTRY:
1799 if ( !suser () ) return -EPERM;
1800 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1801 return -EFAULT;
1802 err = mtrr_file_del (sentry.base, sentry.size, file, 1);
1803 if (err < 0) return err;
1804 break;
1805 case MTRRIOC_KILL_PAGE_ENTRY:
1806 if ( !suser () ) return -EPERM;
1807 if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
1808 return -EFAULT;
1809 err = mtrr_del_page (-1, sentry.base, sentry.size);
1810 if (err < 0) return err;
1811 break;
1812 case MTRRIOC_GET_PAGE_ENTRY:
1813 if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
1814 return -EFAULT;
1815 if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
1816 (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
1817 gentry.type = type;
1818
1819 if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
1820 return -EFAULT;
1821 break;
1822 }
1823 return 0;
1824}
1825
1826static int mtrr_close (struct inode *ino, struct file *file)
1827{
1828 int i, max;
1829 unsigned int *fcount = file->private_data;
1830
1831 if (fcount == NULL) return 0;
1832 lock_kernel();
1833 max = get_num_var_ranges ();
1834 for (i = 0; i < max; ++i)
1835 {
1836 while (fcount[i] > 0)
1837 {
1838 if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i);
1839 --fcount[i];
1840 }
1841 }
1842 unlock_kernel();
1843 kfree (fcount);
1844 file->private_data = NULL;
1845 return 0;
1846}
1847
1848static struct file_operations mtrr_fops =
1849{
1850 owner: THIS_MODULE,
1851 read: mtrr_read,
1852 write: mtrr_write,
1853 ioctl: mtrr_ioctl,
1854 release: mtrr_close,
1855};
1856
1857# ifdef CONFIG_PROC_FS
1858
1859static struct proc_dir_entry *proc_root_mtrr;
1860
1861# endif
1862
1863static devfs_handle_t devfs_handle;
1864
1865static void compute_ascii (void)
1866{
1867 char factor;
1868 int i, max;
1869 mtrr_type type;
1870 unsigned long base, size;
1871
1872 ascii_buf_bytes = 0;
1873 max = get_num_var_ranges ();
1874 for (i = 0; i < max; i++)
1875 {
1876 (*get_mtrr) (i, &base, &size, &type);
1877 if (size == 0) usage_table[i] = 0;
1878 else
1879 {
1880 if (size < (0x100000 >> PAGE_SHIFT))
1881 {
1882
1883 factor = 'K';
1884 size <<= PAGE_SHIFT - 10;
1885 }
1886 else
1887 {
1888 factor = 'M';
1889 size >>= 20 - PAGE_SHIFT;
1890 }
1891 sprintf
1892 (ascii_buffer + ascii_buf_bytes,
1893 "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
1894 i, base, base >> (20 - PAGE_SHIFT), size, factor,
1895 attrib_to_str (type), usage_table[i]);
1896 ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
1897 }
1898 }
1899 devfs_set_file_size (devfs_handle, ascii_buf_bytes);
1900# ifdef CONFIG_PROC_FS
1901 if (proc_root_mtrr)
1902 proc_root_mtrr->size = ascii_buf_bytes;
1903# endif
1904}
1905
1906#endif
1907
1908EXPORT_SYMBOL(mtrr_add);
1909EXPORT_SYMBOL(mtrr_del);
1910
1911#ifdef CONFIG_SMP
1912
1913typedef struct
1914{
1915 unsigned long base;
1916 unsigned long size;
1917 mtrr_type type;
1918} arr_state_t;
1919
1920arr_state_t arr_state[8] __initdata =
1921{
1922 {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
1923 {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
1924};
1925
1926unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
1927
1928static void __init cyrix_arr_init_secondary(void)
1929{
1930 struct set_mtrr_context ctxt;
1931 int i;
1932
1933
1934 set_mtrr_prepare_save (&ctxt);
1935 set_mtrr_disable (&ctxt);
1936
1937
1938 for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
1939 for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
1940 for(i=0; i<8; i++)
1941 cyrix_set_arr_up(i,
1942 arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
1943
1944 set_mtrr_done (&ctxt);
1945}
1946
1947#endif
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963static void __init cyrix_arr_init(void)
1964{
1965 struct set_mtrr_context ctxt;
1966 unsigned char ccr[7];
1967 int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
1968#ifdef CONFIG_SMP
1969 int i;
1970#endif
1971
1972
1973 set_mtrr_prepare_save (&ctxt);
1974 set_mtrr_disable (&ctxt);
1975
1976
1977 ccr[0] = getCx86 (CX86_CCR0);
1978 ccr[1] = getCx86 (CX86_CCR1);
1979 ccr[2] = getCx86 (CX86_CCR2);
1980 ccr[3] = ctxt.ccr3;
1981 ccr[4] = getCx86 (CX86_CCR4);
1982 ccr[5] = getCx86 (CX86_CCR5);
1983 ccr[6] = getCx86 (CX86_CCR6);
1984
1985 if (ccr[3] & 1)
1986 {
1987 ccrc[3] = 1;
1988 arr3_protected = 1;
1989 }
1990 else
1991 {
1992
1993
1994
1995 if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
1996 if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
1997 if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
1998 arr3_protected = 0;
1999 if (ccr[6] & 0x02) {
2000 ccr[6] &= 0xfd; ccrc[6] = 1;
2001 setCx86 (CX86_CCR6, ccr[6]);
2002 }
2003
2004
2005 }
2006
2007 if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
2008
2009
2010 if (!(ccr[5] & 0x20))
2011 {
2012 ccr[5] |= 0x20; ccrc[5] = 1;
2013 setCx86 (CX86_CCR5, ccr[5]);
2014 }
2015
2016#ifdef CONFIG_SMP
2017 for(i=0; i<7; i++) ccr_state[i] = ccr[i];
2018 for(i=0; i<8; i++)
2019 cyrix_get_arr(i,
2020 &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
2021#endif
2022
2023 set_mtrr_done (&ctxt);
2024
2025 if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
2026 if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
2027
2028
2029
2030
2031
2032 if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
2033}
2034
2035
2036
2037
2038
2039
2040
2041static void __init centaur_mcr1_init(void)
2042{
2043 unsigned i;
2044 u32 lo, hi;
2045
2046
2047
2048
2049
2050 rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
2051 if(((lo>>17)&7)==1)
2052 {
2053 lo&= ~0x1C0;
2054 lo|= 0x040;
2055 wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
2056 }
2057
2058 centaur_mcr_type = 1;
2059
2060
2061
2062
2063
2064 for (i = 0; i < 8; ++i)
2065 {
2066 if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0)
2067 {
2068 if(!(lo & (1<<(9+i))))
2069 wrmsr (MSR_IDT_MCR0 + i , 0, 0);
2070 else
2071
2072
2073
2074
2075 centaur_mcr_reserved |= (1<<i);
2076 }
2077 }
2078
2079
2080
2081
2082
2083
2084 lo |= 15;
2085 wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
2086}
2087
2088
2089
2090
2091
2092
2093static void __init centaur_mcr0_init(void)
2094{
2095 unsigned i;
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106 for (i = 0; i < 8; ++i)
2107 {
2108 if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0)
2109 wrmsr (MSR_IDT_MCR0 + i , 0, 0);
2110 }
2111
2112 wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
2113}
2114
2115
2116
2117
2118
2119static void __init centaur_mcr_init(void)
2120{
2121 struct set_mtrr_context ctxt;
2122
2123 set_mtrr_prepare_save (&ctxt);
2124 set_mtrr_disable (&ctxt);
2125
2126 if(boot_cpu_data.x86_model==4)
2127 centaur_mcr0_init();
2128 else if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9)
2129 centaur_mcr1_init();
2130
2131 set_mtrr_done (&ctxt);
2132}
2133
2134static int __init mtrr_setup(void)
2135{
2136 if ( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ) {
2137
2138 mtrr_if = MTRR_IF_INTEL;
2139 get_mtrr = intel_get_mtrr;
2140 set_mtrr_up = intel_set_mtrr_up;
2141 switch (boot_cpu_data.x86_vendor) {
2142
2143 case X86_VENDOR_AMD:
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154 if (boot_cpu_data.x86 == 15 && (cpuid_eax(0x80000000) >= 0x80000008)) {
2155 u32 phys_addr;
2156 phys_addr = cpuid_eax(0x80000008) & 0xff ;
2157 size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
2158 size_and_mask = ~size_or_mask & 0xfff00000;
2159 break;
2160 }
2161 size_or_mask = 0xff000000;
2162 size_and_mask = 0x00f00000;
2163 break;
2164
2165 case X86_VENDOR_CENTAUR:
2166
2167 if (boot_cpu_data.x86 == 6) {
2168 size_or_mask = 0xfff00000;
2169 size_and_mask = 0;
2170 }
2171 break;
2172
2173 default:
2174
2175 size_or_mask = 0xff000000;
2176 size_and_mask = 0x00f00000;
2177 break;
2178 }
2179
2180 } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
2181
2182 mtrr_if = MTRR_IF_AMD_K6;
2183 get_mtrr = amd_get_mtrr;
2184 set_mtrr_up = amd_set_mtrr_up;
2185 size_or_mask = 0xfff00000;
2186 size_and_mask = 0;
2187 } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
2188
2189 mtrr_if = MTRR_IF_CYRIX_ARR;
2190 get_mtrr = cyrix_get_arr;
2191 set_mtrr_up = cyrix_set_arr_up;
2192 get_free_region = cyrix_get_free_region;
2193 cyrix_arr_init();
2194 size_or_mask = 0xfff00000;
2195 size_and_mask = 0;
2196 } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
2197
2198 mtrr_if = MTRR_IF_CENTAUR_MCR;
2199 get_mtrr = centaur_get_mcr;
2200 set_mtrr_up = centaur_set_mcr_up;
2201 get_free_region = centaur_get_free_region;
2202 centaur_mcr_init();
2203 size_or_mask = 0xfff00000;
2204 size_and_mask = 0;
2205 } else {
2206
2207 mtrr_if = MTRR_IF_NONE;
2208 }
2209
2210 printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
2211 "mtrr: detected mtrr type: %s\n",
2212 MTRR_VERSION, mtrr_if_name[mtrr_if]);
2213
2214 return (mtrr_if != MTRR_IF_NONE);
2215}
2216
2217#ifdef CONFIG_SMP
2218
2219static volatile unsigned long smp_changes_mask __initdata = 0;
2220static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
2221
2222void __init mtrr_init_boot_cpu(void)
2223{
2224 if ( !mtrr_setup () )
2225 return;
2226
2227 if ( mtrr_if == MTRR_IF_INTEL ) {
2228
2229 get_mtrr_state (&smp_mtrr_state);
2230 }
2231}
2232
2233static void __init intel_mtrr_init_secondary_cpu(void)
2234{
2235 unsigned long mask, count;
2236 struct set_mtrr_context ctxt;
2237
2238
2239
2240
2241 set_mtrr_prepare_save (&ctxt);
2242 set_mtrr_disable (&ctxt);
2243 mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
2244 set_mtrr_done (&ctxt);
2245
2246 for (count = 0; count < sizeof mask * 8; ++count)
2247 {
2248 if (mask & 0x01) set_bit (count, &smp_changes_mask);
2249 mask >>= 1;
2250 }
2251}
2252
2253void __init mtrr_init_secondary_cpu(void)
2254{
2255 switch ( mtrr_if ) {
2256 case MTRR_IF_INTEL:
2257
2258 intel_mtrr_init_secondary_cpu();
2259 break;
2260 case MTRR_IF_CYRIX_ARR:
2261
2262
2263
2264
2265
2266
2267 cyrix_arr_init_secondary ();
2268 break;
2269 case MTRR_IF_NONE:
2270 break;
2271 default:
2272
2273 printk ("mtrr: SMP support incomplete for this vendor\n");
2274 }
2275}
2276#endif
2277
2278int __init mtrr_init(void)
2279{
2280#ifdef CONFIG_SMP
2281
2282
2283 if ( mtrr_if == MTRR_IF_INTEL ) {
2284 finalize_mtrr_state (&smp_mtrr_state);
2285 mtrr_state_warn (smp_changes_mask);
2286 }
2287#else
2288 if ( !mtrr_setup() )
2289 return 0;
2290#endif
2291
2292#ifdef CONFIG_PROC_FS
2293 proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
2294 if (proc_root_mtrr) {
2295 proc_root_mtrr->owner = THIS_MODULE;
2296 proc_root_mtrr->proc_fops = &mtrr_fops;
2297 }
2298#endif
2299#ifdef USERSPACE_INTERFACE
2300 devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
2301 S_IFREG | S_IRUGO | S_IWUSR,
2302 &mtrr_fops, NULL);
2303#endif
2304 init_table ();
2305 return 0;
2306}
2307
2308
2309
2310
2311
2312
2313
2314
2315