aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorYinghai Lu <Yinghai.Lu@Sun.COM>2008-02-19 06:13:43 -0500
committerIngo Molnar <mingo@elte.hu>2008-04-26 17:41:04 -0400
commiteee206c3bfd0888f22ae9da3172487c61d72187d (patch)
tree0ef518f8ac5fcde5a1aed6cffe4ab7ddecec7273 /arch/x86/kernel
parent57741a779070e0b141b6148136b420c8d35ccbce (diff)
x86_64: check and enable MMCONFIG for AMD Family 10h
So we can use MMCONF when MMCONF is not set by BIOS using TOP_MEM2 msr to get memory top, and try to scan fam10h mmio routing to make sure the range is not conflicted with some prefetch MMIO that is above 4G. (current only LinuxBIOS assign 64 bit mmio above 4G for some co-processor) Signed-off-by: Yinghai Lu <yinghai.lu@sun.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/setup_64.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 60e64c8eee92..185d3cc9129b 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -29,6 +29,7 @@
29#include <linux/crash_dump.h> 29#include <linux/crash_dump.h>
30#include <linux/root_dev.h> 30#include <linux/root_dev.h>
31#include <linux/pci.h> 31#include <linux/pci.h>
32#include <asm/pci-direct.h>
32#include <linux/efi.h> 33#include <linux/efi.h>
33#include <linux/acpi.h> 34#include <linux/acpi.h>
34#include <linux/kallsyms.h> 35#include <linux/kallsyms.h>
@@ -40,6 +41,7 @@
40#include <linux/dmi.h> 41#include <linux/dmi.h>
41#include <linux/dma-mapping.h> 42#include <linux/dma-mapping.h>
42#include <linux/ctype.h> 43#include <linux/ctype.h>
44#include <linux/sort.h>
43#include <linux/uaccess.h> 45#include <linux/uaccess.h>
44#include <linux/init_ohci1394_dma.h> 46#include <linux/init_ohci1394_dma.h>
45 47
@@ -577,6 +579,205 @@ static int __cpuinit nearby_node(int apicid)
577} 579}
578#endif 580#endif
579 581
582#ifdef CONFIG_PCI_MMCONFIG
583struct pci_hostbridge_probe {
584 u32 bus;
585 u32 slot;
586 u32 vendor;
587 u32 device;
588};
589
590static u64 __cpuinitdata fam10h_pci_mmconf_base;
591static int __cpuinitdata fam10h_pci_mmconf_base_status;
592
593static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = {
594 { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
595 { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
596};
597
598struct range {
599 u64 start;
600 u64 end;
601};
602
603static int __cpuinit cmp_range(const void *x1, const void *x2)
604{
605 const struct range *r1 = x1;
606 const struct range *r2 = x2;
607 int start1, start2;
608
609 start1 = r1->start >> 32;
610 start2 = r2->start >> 32;
611
612 return start1 - start2;
613}
614
615/*[47:0] */
616/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
617#define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
618#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
619static void __cpuinit get_fam10h_pci_mmconf_base(void)
620{
621 int i;
622 unsigned bus;
623 unsigned slot;
624 int found;
625
626 u64 val;
627 u32 address;
628 u64 tom2;
629 u64 base = FAM10H_PCI_MMCONF_BASE;
630
631 int hi_mmio_num;
632 struct range range[8];
633
634 /* only try to get setting from BSP */
635 /* -1 or 1 */
636 if (fam10h_pci_mmconf_base_status)
637 return;
638
639 if (!early_pci_allowed())
640 goto fail;
641
642 found = 0;
643 for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
644 u32 id;
645 u16 device;
646 u16 vendor;
647
648 bus = pci_probes[i].bus;
649 slot = pci_probes[i].slot;
650 id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
651
652 vendor = id & 0xffff;
653 device = (id>>16) & 0xffff;
654 if (pci_probes[i].vendor == vendor &&
655 pci_probes[i].device == device) {
656 found = 1;
657 break;
658 }
659 }
660
661 if (!found)
662 goto fail;
663
664 /* SYS_CFG */
665 address = MSR_K8_SYSCFG;
666 rdmsrl(address, val);
667
668 /* TOP_MEM2 is not enabled? */
669 if (!(val & (1<<21))) {
670 tom2 = 0;
671 } else {
672 /* TOP_MEM2 */
673 address = MSR_K8_TOP_MEM2;
674 rdmsrl(address, val);
675 tom2 = val & (0xffffULL<<32);
676 }
677
678 if (base <= tom2)
679 base = tom2 + (1ULL<<32);
680
681 /*
682 * need to check if the range is in the high mmio range that is
683 * above 4G
684 */
685 hi_mmio_num = 0;
686 for (i = 0; i < 8; i++) {
687 u32 reg;
688 u64 start;
689 u64 end;
690 reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
691 if (!(reg & 3))
692 continue;
693
694 start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
695 reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
696 end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
697
698 if (!end)
699 continue;
700
701 range[hi_mmio_num].start = start;
702 range[hi_mmio_num].end = end;
703 hi_mmio_num++;
704 }
705
706 if (!hi_mmio_num)
707 goto out;
708
709 /* sort the range */
710 sort(range, hi_mmio_num, sizeof(struct range), cmp_range, NULL);
711
712 if (range[hi_mmio_num - 1].end < base)
713 goto out;
714 if (range[0].start > base)
715 goto out;
716
717 /* need to find one window */
718 base = range[0].start - (1ULL << 32);
719 if ((base > tom2) && BASE_VALID(base))
720 goto out;
721 base = range[hi_mmio_num - 1].end + (1ULL << 32);
722 if ((base > tom2) && BASE_VALID(base))
723 goto out;
724 /* need to find window between ranges */
725 if (hi_mmio_num > 1)
726 for (i = 0; i < hi_mmio_num - 1; i++) {
727 if (range[i + 1].start > (range[i].end + (1ULL << 32))) {
728 base = range[i].end + (1ULL << 32);
729 if ((base > tom2) && BASE_VALID(base))
730 goto out;
731 }
732 }
733
734fail:
735 fam10h_pci_mmconf_base_status = -1;
736 return;
737out:
738 fam10h_pci_mmconf_base = base;
739 fam10h_pci_mmconf_base_status = 1;
740}
741#endif
742
743static void __cpuinit fam10h_check_enable_mmcfg(struct cpuinfo_x86 *c)
744{
745#ifdef CONFIG_PCI_MMCONFIG
746 u64 val;
747 u32 address;
748
749 address = MSR_FAM10H_MMIO_CONF_BASE;
750 rdmsrl(address, val);
751
752 /* try to make sure that AP's setting is identical to BSP setting */
753 if (val & FAM10H_MMIO_CONF_ENABLE) {
754 u64 base;
755 base = val & (0xffffULL << 32);
756 if (fam10h_pci_mmconf_base_status <= 0) {
757 fam10h_pci_mmconf_base = base;
758 fam10h_pci_mmconf_base_status = 1;
759 return;
760 } else if (fam10h_pci_mmconf_base == base)
761 return;
762 }
763
764 /*
765 * if it is not enabled, try to enable it and assume only one segment
766 * with 256 buses
767 */
768 get_fam10h_pci_mmconf_base();
769 if (fam10h_pci_mmconf_base_status <= 0)
770 return;
771
772 printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
773 val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
774 (FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT));
775 val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
776 FAM10H_MMIO_CONF_ENABLE;
777 wrmsrl(address, val);
778#endif
779}
780
580/* 781/*
581 * On a AMD dual core setup the lower bits of the APIC id distingush the cores. 782 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
582 * Assumes number of cores is a power of two. 783 * Assumes number of cores is a power of two.
@@ -760,6 +961,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
760 /* MFENCE stops RDTSC speculation */ 961 /* MFENCE stops RDTSC speculation */
761 set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); 962 set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
762 963
964 if (c->x86 == 0x10)
965 fam10h_check_enable_mmcfg(c);
966
763 if (amd_apic_timer_broken()) 967 if (amd_apic_timer_broken())
764 disable_apic_timer = 1; 968 disable_apic_timer = 1;
765 969