0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <linux/types.h> /* FIXME: kvm_para.h needs this */
0035
0036 #include <linux/stop_machine.h>
0037 #include <linux/kvm_para.h>
0038 #include <linux/uaccess.h>
0039 #include <linux/export.h>
0040 #include <linux/mutex.h>
0041 #include <linux/init.h>
0042 #include <linux/sort.h>
0043 #include <linux/cpu.h>
0044 #include <linux/pci.h>
0045 #include <linux/smp.h>
0046 #include <linux/syscore_ops.h>
0047 #include <linux/rcupdate.h>
0048
0049 #include <asm/cpufeature.h>
0050 #include <asm/e820/api.h>
0051 #include <asm/mtrr.h>
0052 #include <asm/msr.h>
0053 #include <asm/memtype.h>
0054
0055 #include "mtrr.h"
0056
0057
0058 #define MTRR_TO_PHYS_WC_OFFSET 1000
0059
0060 u32 num_var_ranges;
0061 static bool __mtrr_enabled;
0062
0063 static bool mtrr_enabled(void)
0064 {
0065 return __mtrr_enabled;
0066 }
0067
0068 unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
0069 static DEFINE_MUTEX(mtrr_mutex);
0070
0071 u64 size_or_mask, size_and_mask;
0072 static bool mtrr_aps_delayed_init;
0073
0074 static const struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM] __ro_after_init;
0075
0076 const struct mtrr_ops *mtrr_if;
0077
0078 static void set_mtrr(unsigned int reg, unsigned long base,
0079 unsigned long size, mtrr_type type);
0080
0081 void __init set_mtrr_ops(const struct mtrr_ops *ops)
0082 {
0083 if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
0084 mtrr_ops[ops->vendor] = ops;
0085 }
0086
0087
0088 static int have_wrcomb(void)
0089 {
0090 struct pci_dev *dev;
0091
0092 dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL);
0093 if (dev != NULL) {
0094
0095
0096
0097
0098
0099 if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
0100 dev->device == PCI_DEVICE_ID_SERVERWORKS_LE &&
0101 dev->revision <= 5) {
0102 pr_info("Serverworks LE rev < 6 detected. Write-combining disabled.\n");
0103 pci_dev_put(dev);
0104 return 0;
0105 }
0106
0107
0108
0109
0110 if (dev->vendor == PCI_VENDOR_ID_INTEL &&
0111 dev->device == PCI_DEVICE_ID_INTEL_82451NX) {
0112 pr_info("Intel 450NX MMC detected. Write-combining disabled.\n");
0113 pci_dev_put(dev);
0114 return 0;
0115 }
0116 pci_dev_put(dev);
0117 }
0118 return mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0;
0119 }
0120
0121
0122 static void __init set_num_var_ranges(void)
0123 {
0124 unsigned long config = 0, dummy;
0125
0126 if (use_intel())
0127 rdmsr(MSR_MTRRcap, config, dummy);
0128 else if (is_cpu(AMD) || is_cpu(HYGON))
0129 config = 2;
0130 else if (is_cpu(CYRIX) || is_cpu(CENTAUR))
0131 config = 8;
0132
0133 num_var_ranges = config & 0xff;
0134 }
0135
0136 static void __init init_table(void)
0137 {
0138 int i, max;
0139
0140 max = num_var_ranges;
0141 for (i = 0; i < max; i++)
0142 mtrr_usage_table[i] = 1;
0143 }
0144
0145 struct set_mtrr_data {
0146 unsigned long smp_base;
0147 unsigned long smp_size;
0148 unsigned int smp_reg;
0149 mtrr_type smp_type;
0150 };
0151
0152
0153
0154
0155
0156
0157
0158
0159 static int mtrr_rendezvous_handler(void *info)
0160 {
0161 struct set_mtrr_data *data = info;
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 if (data->smp_reg != ~0U) {
0177 mtrr_if->set(data->smp_reg, data->smp_base,
0178 data->smp_size, data->smp_type);
0179 } else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
0180 mtrr_if->set_all();
0181 }
0182 return 0;
0183 }
0184
0185 static inline int types_compatible(mtrr_type type1, mtrr_type type2)
0186 {
0187 return type1 == MTRR_TYPE_UNCACHABLE ||
0188 type2 == MTRR_TYPE_UNCACHABLE ||
0189 (type1 == MTRR_TYPE_WRTHROUGH && type2 == MTRR_TYPE_WRBACK) ||
0190 (type1 == MTRR_TYPE_WRBACK && type2 == MTRR_TYPE_WRTHROUGH);
0191 }
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227 static void
0228 set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
0229 {
0230 struct set_mtrr_data data = { .smp_reg = reg,
0231 .smp_base = base,
0232 .smp_size = size,
0233 .smp_type = type
0234 };
0235
0236 stop_machine(mtrr_rendezvous_handler, &data, cpu_online_mask);
0237 }
0238
0239 static void set_mtrr_cpuslocked(unsigned int reg, unsigned long base,
0240 unsigned long size, mtrr_type type)
0241 {
0242 struct set_mtrr_data data = { .smp_reg = reg,
0243 .smp_base = base,
0244 .smp_size = size,
0245 .smp_type = type
0246 };
0247
0248 stop_machine_cpuslocked(mtrr_rendezvous_handler, &data, cpu_online_mask);
0249 }
0250
0251 static void set_mtrr_from_inactive_cpu(unsigned int reg, unsigned long base,
0252 unsigned long size, mtrr_type type)
0253 {
0254 struct set_mtrr_data data = { .smp_reg = reg,
0255 .smp_base = base,
0256 .smp_size = size,
0257 .smp_type = type
0258 };
0259
0260 stop_machine_from_inactive_cpu(mtrr_rendezvous_handler, &data,
0261 cpu_callout_mask);
0262 }
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299 int mtrr_add_page(unsigned long base, unsigned long size,
0300 unsigned int type, bool increment)
0301 {
0302 unsigned long lbase, lsize;
0303 int i, replace, error;
0304 mtrr_type ltype;
0305
0306 if (!mtrr_enabled())
0307 return -ENXIO;
0308
0309 error = mtrr_if->validate_add_page(base, size, type);
0310 if (error)
0311 return error;
0312
0313 if (type >= MTRR_NUM_TYPES) {
0314 pr_warn("type: %u invalid\n", type);
0315 return -EINVAL;
0316 }
0317
0318
0319 if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {
0320 pr_warn("your processor doesn't support write-combining\n");
0321 return -ENOSYS;
0322 }
0323
0324 if (!size) {
0325 pr_warn("zero sized request\n");
0326 return -EINVAL;
0327 }
0328
0329 if ((base | (base + size - 1)) >>
0330 (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) {
0331 pr_warn("base or size exceeds the MTRR width\n");
0332 return -EINVAL;
0333 }
0334
0335 error = -EINVAL;
0336 replace = -1;
0337
0338
0339 cpus_read_lock();
0340
0341
0342 mutex_lock(&mtrr_mutex);
0343 for (i = 0; i < num_var_ranges; ++i) {
0344 mtrr_if->get(i, &lbase, &lsize, <ype);
0345 if (!lsize || base > lbase + lsize - 1 ||
0346 base + size - 1 < lbase)
0347 continue;
0348
0349
0350
0351
0352 if (base < lbase || base + size - 1 > lbase + lsize - 1) {
0353 if (base <= lbase &&
0354 base + size - 1 >= lbase + lsize - 1) {
0355
0356 if (type == ltype) {
0357 replace = replace == -1 ? i : -2;
0358 continue;
0359 } else if (types_compatible(type, ltype))
0360 continue;
0361 }
0362 pr_warn("0x%lx000,0x%lx000 overlaps existing 0x%lx000,0x%lx000\n", base, size, lbase,
0363 lsize);
0364 goto out;
0365 }
0366
0367 if (ltype != type) {
0368 if (types_compatible(type, ltype))
0369 continue;
0370 pr_warn("type mismatch for %lx000,%lx000 old: %s new: %s\n",
0371 base, size, mtrr_attrib_to_str(ltype),
0372 mtrr_attrib_to_str(type));
0373 goto out;
0374 }
0375 if (increment)
0376 ++mtrr_usage_table[i];
0377 error = i;
0378 goto out;
0379 }
0380
0381 i = mtrr_if->get_free_region(base, size, replace);
0382 if (i >= 0) {
0383 set_mtrr_cpuslocked(i, base, size, type);
0384 if (likely(replace < 0)) {
0385 mtrr_usage_table[i] = 1;
0386 } else {
0387 mtrr_usage_table[i] = mtrr_usage_table[replace];
0388 if (increment)
0389 mtrr_usage_table[i]++;
0390 if (unlikely(replace != i)) {
0391 set_mtrr_cpuslocked(replace, 0, 0, 0);
0392 mtrr_usage_table[replace] = 0;
0393 }
0394 }
0395 } else {
0396 pr_info("no more MTRRs available\n");
0397 }
0398 error = i;
0399 out:
0400 mutex_unlock(&mtrr_mutex);
0401 cpus_read_unlock();
0402 return error;
0403 }
0404
0405 static int mtrr_check(unsigned long base, unsigned long size)
0406 {
0407 if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
0408 pr_warn("size and base must be multiples of 4 kiB\n");
0409 pr_debug("size: 0x%lx base: 0x%lx\n", size, base);
0410 dump_stack();
0411 return -1;
0412 }
0413 return 0;
0414 }
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451 int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
0452 bool increment)
0453 {
0454 if (!mtrr_enabled())
0455 return -ENODEV;
0456 if (mtrr_check(base, size))
0457 return -EINVAL;
0458 return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
0459 increment);
0460 }
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476 int mtrr_del_page(int reg, unsigned long base, unsigned long size)
0477 {
0478 int i, max;
0479 mtrr_type ltype;
0480 unsigned long lbase, lsize;
0481 int error = -EINVAL;
0482
0483 if (!mtrr_enabled())
0484 return -ENODEV;
0485
0486 max = num_var_ranges;
0487
0488 cpus_read_lock();
0489 mutex_lock(&mtrr_mutex);
0490 if (reg < 0) {
0491
0492 for (i = 0; i < max; ++i) {
0493 mtrr_if->get(i, &lbase, &lsize, <ype);
0494 if (lbase == base && lsize == size) {
0495 reg = i;
0496 break;
0497 }
0498 }
0499 if (reg < 0) {
0500 pr_debug("no MTRR for %lx000,%lx000 found\n",
0501 base, size);
0502 goto out;
0503 }
0504 }
0505 if (reg >= max) {
0506 pr_warn("register: %d too big\n", reg);
0507 goto out;
0508 }
0509 mtrr_if->get(reg, &lbase, &lsize, <ype);
0510 if (lsize < 1) {
0511 pr_warn("MTRR %d not used\n", reg);
0512 goto out;
0513 }
0514 if (mtrr_usage_table[reg] < 1) {
0515 pr_warn("reg: %d has count=0\n", reg);
0516 goto out;
0517 }
0518 if (--mtrr_usage_table[reg] < 1)
0519 set_mtrr_cpuslocked(reg, 0, 0, 0);
0520 error = reg;
0521 out:
0522 mutex_unlock(&mtrr_mutex);
0523 cpus_read_unlock();
0524 return error;
0525 }
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541 int mtrr_del(int reg, unsigned long base, unsigned long size)
0542 {
0543 if (!mtrr_enabled())
0544 return -ENODEV;
0545 if (mtrr_check(base, size))
0546 return -EINVAL;
0547 return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
0548 }
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565 int arch_phys_wc_add(unsigned long base, unsigned long size)
0566 {
0567 int ret;
0568
0569 if (pat_enabled() || !mtrr_enabled())
0570 return 0;
0571
0572 ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
0573 if (ret < 0) {
0574 pr_warn("Failed to add WC MTRR for [%p-%p]; performance may suffer.",
0575 (void *)base, (void *)(base + size - 1));
0576 return ret;
0577 }
0578 return ret + MTRR_TO_PHYS_WC_OFFSET;
0579 }
0580 EXPORT_SYMBOL(arch_phys_wc_add);
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 void arch_phys_wc_del(int handle)
0592 {
0593 if (handle >= 1) {
0594 WARN_ON(handle < MTRR_TO_PHYS_WC_OFFSET);
0595 mtrr_del(handle - MTRR_TO_PHYS_WC_OFFSET, 0, 0);
0596 }
0597 }
0598 EXPORT_SYMBOL(arch_phys_wc_del);
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611 int arch_phys_wc_index(int handle)
0612 {
0613 if (handle < MTRR_TO_PHYS_WC_OFFSET)
0614 return -1;
0615 else
0616 return handle - MTRR_TO_PHYS_WC_OFFSET;
0617 }
0618 EXPORT_SYMBOL_GPL(arch_phys_wc_index);
0619
0620
0621
0622
0623
0624
0625 static void __init init_ifs(void)
0626 {
0627 #ifndef CONFIG_X86_64
0628 amd_init_mtrr();
0629 cyrix_init_mtrr();
0630 centaur_init_mtrr();
0631 #endif
0632 }
0633
0634
0635
0636
0637 struct mtrr_value {
0638 mtrr_type ltype;
0639 unsigned long lbase;
0640 unsigned long lsize;
0641 };
0642
0643 static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];
0644
0645 static int mtrr_save(void)
0646 {
0647 int i;
0648
0649 for (i = 0; i < num_var_ranges; i++) {
0650 mtrr_if->get(i, &mtrr_value[i].lbase,
0651 &mtrr_value[i].lsize,
0652 &mtrr_value[i].ltype);
0653 }
0654 return 0;
0655 }
0656
0657 static void mtrr_restore(void)
0658 {
0659 int i;
0660
0661 for (i = 0; i < num_var_ranges; i++) {
0662 if (mtrr_value[i].lsize) {
0663 set_mtrr(i, mtrr_value[i].lbase,
0664 mtrr_value[i].lsize,
0665 mtrr_value[i].ltype);
0666 }
0667 }
0668 }
0669
0670
0671
0672 static struct syscore_ops mtrr_syscore_ops = {
0673 .suspend = mtrr_save,
0674 .resume = mtrr_restore,
0675 };
0676
0677 int __initdata changed_by_mtrr_cleanup;
0678
0679 #define SIZE_OR_MASK_BITS(n) (~((1ULL << ((n) - PAGE_SHIFT)) - 1))
0680
0681
0682
0683
0684
0685
0686
0687 void __init mtrr_bp_init(void)
0688 {
0689 u32 phys_addr;
0690
0691 init_ifs();
0692
0693 phys_addr = 32;
0694
0695 if (boot_cpu_has(X86_FEATURE_MTRR)) {
0696 mtrr_if = &generic_mtrr_ops;
0697 size_or_mask = SIZE_OR_MASK_BITS(36);
0698 size_and_mask = 0x00f00000;
0699 phys_addr = 36;
0700
0701
0702
0703
0704
0705
0706 if (cpuid_eax(0x80000000) >= 0x80000008) {
0707 phys_addr = cpuid_eax(0x80000008) & 0xff;
0708
0709 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
0710 boot_cpu_data.x86 == 0xF &&
0711 boot_cpu_data.x86_model == 0x3 &&
0712 (boot_cpu_data.x86_stepping == 0x3 ||
0713 boot_cpu_data.x86_stepping == 0x4))
0714 phys_addr = 36;
0715
0716 size_or_mask = SIZE_OR_MASK_BITS(phys_addr);
0717 size_and_mask = ~size_or_mask & 0xfffff00000ULL;
0718 } else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
0719 boot_cpu_data.x86 == 6) {
0720
0721
0722
0723
0724 size_or_mask = SIZE_OR_MASK_BITS(32);
0725 size_and_mask = 0;
0726 phys_addr = 32;
0727 }
0728 } else {
0729 switch (boot_cpu_data.x86_vendor) {
0730 case X86_VENDOR_AMD:
0731 if (cpu_feature_enabled(X86_FEATURE_K6_MTRR)) {
0732
0733 mtrr_if = mtrr_ops[X86_VENDOR_AMD];
0734 size_or_mask = SIZE_OR_MASK_BITS(32);
0735 size_and_mask = 0;
0736 }
0737 break;
0738 case X86_VENDOR_CENTAUR:
0739 if (cpu_feature_enabled(X86_FEATURE_CENTAUR_MCR)) {
0740 mtrr_if = mtrr_ops[X86_VENDOR_CENTAUR];
0741 size_or_mask = SIZE_OR_MASK_BITS(32);
0742 size_and_mask = 0;
0743 }
0744 break;
0745 case X86_VENDOR_CYRIX:
0746 if (cpu_feature_enabled(X86_FEATURE_CYRIX_ARR)) {
0747 mtrr_if = mtrr_ops[X86_VENDOR_CYRIX];
0748 size_or_mask = SIZE_OR_MASK_BITS(32);
0749 size_and_mask = 0;
0750 }
0751 break;
0752 default:
0753 break;
0754 }
0755 }
0756
0757 if (mtrr_if) {
0758 __mtrr_enabled = true;
0759 set_num_var_ranges();
0760 init_table();
0761 if (use_intel()) {
0762
0763 __mtrr_enabled = get_mtrr_state();
0764
0765 if (mtrr_enabled())
0766 mtrr_bp_pat_init();
0767
0768 if (mtrr_cleanup(phys_addr)) {
0769 changed_by_mtrr_cleanup = 1;
0770 mtrr_if->set_all();
0771 }
0772 }
0773 }
0774
0775 if (!mtrr_enabled()) {
0776 pr_info("Disabled\n");
0777
0778
0779
0780
0781
0782
0783 pat_disable("MTRRs disabled, skipping PAT initialization too.");
0784 }
0785 }
0786
0787 void mtrr_ap_init(void)
0788 {
0789 if (!mtrr_enabled())
0790 return;
0791
0792 if (!use_intel() || mtrr_aps_delayed_init)
0793 return;
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808 set_mtrr_from_inactive_cpu(~0U, 0, 0, 0);
0809 }
0810
0811
0812
0813
0814
0815 void mtrr_save_state(void)
0816 {
0817 int first_cpu;
0818
0819 if (!mtrr_enabled())
0820 return;
0821
0822 first_cpu = cpumask_first(cpu_online_mask);
0823 smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
0824 }
0825
0826 void set_mtrr_aps_delayed_init(void)
0827 {
0828 if (!mtrr_enabled())
0829 return;
0830 if (!use_intel())
0831 return;
0832
0833 mtrr_aps_delayed_init = true;
0834 }
0835
0836
0837
0838
0839 void mtrr_aps_init(void)
0840 {
0841 if (!use_intel() || !mtrr_enabled())
0842 return;
0843
0844
0845
0846
0847
0848
0849 if (!mtrr_aps_delayed_init)
0850 return;
0851
0852 set_mtrr(~0U, 0, 0, 0);
0853 mtrr_aps_delayed_init = false;
0854 }
0855
0856 void mtrr_bp_restore(void)
0857 {
0858 if (!use_intel() || !mtrr_enabled())
0859 return;
0860
0861 mtrr_if->set_all();
0862 }
0863
0864 static int __init mtrr_init_finialize(void)
0865 {
0866 if (!mtrr_enabled())
0867 return 0;
0868
0869 if (use_intel()) {
0870 if (!changed_by_mtrr_cleanup)
0871 mtrr_state_warn();
0872 return 0;
0873 }
0874
0875
0876
0877
0878
0879
0880
0881
0882
0883 register_syscore_ops(&mtrr_syscore_ops);
0884
0885 return 0;
0886 }
0887 subsys_initcall(mtrr_init_finialize);