diff options
author | Yinghai Lu <Yinghai.Lu@Sun.COM> | 2008-02-19 06:13:02 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-26 17:41:04 -0400 |
commit | 7fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4 (patch) | |
tree | 766efc8ae28bcc4a04903b99dbd79c1515979d81 /arch/x86 | |
parent | eee206c3bfd0888f22ae9da3172487c61d72187d (diff) |
x86_64: check MSR to get MMCONFIG for AMD Family 10h
so even booting kernel with acpi=off or even MCFG is not there, we still can
use MMCONFIG.
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Greg KH <greg@kroah.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 36a4a7514b05..8707e24e625e 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -100,33 +100,96 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | 100 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; |
101 | } | 101 | } |
102 | 102 | ||
103 | static const char __init *pci_mmcfg_amd_fam10h(void) | ||
104 | { | ||
105 | u32 low, high, address; | ||
106 | u64 base, msr; | ||
107 | int i; | ||
108 | unsigned segnbits = 0, busnbits; | ||
109 | |||
110 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
111 | if (rdmsr_safe(address, &low, &high)) | ||
112 | return NULL; | ||
113 | |||
114 | msr = high; | ||
115 | msr <<= 32; | ||
116 | msr |= low; | ||
117 | |||
118 | /* mmconfig is not enable */ | ||
119 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) | ||
120 | return NULL; | ||
121 | |||
122 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); | ||
123 | |||
124 | busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
125 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
126 | |||
127 | /* | ||
128 | * only handle bus 0 ? | ||
129 | * need to skip it | ||
130 | */ | ||
131 | if (!busnbits) | ||
132 | return NULL; | ||
133 | |||
134 | if (busnbits > 8) { | ||
135 | segnbits = busnbits - 8; | ||
136 | busnbits = 8; | ||
137 | } | ||
138 | |||
139 | pci_mmcfg_config_num = (1 << segnbits); | ||
140 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) * | ||
141 | pci_mmcfg_config_num, GFP_KERNEL); | ||
142 | if (!pci_mmcfg_config) | ||
143 | return NULL; | ||
144 | |||
145 | for (i = 0; i < (1 << segnbits); i++) { | ||
146 | pci_mmcfg_config[i].address = base + (1<<28) * i; | ||
147 | pci_mmcfg_config[i].pci_segment = i; | ||
148 | pci_mmcfg_config[i].start_bus_number = 0; | ||
149 | pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1; | ||
150 | } | ||
151 | |||
152 | return "AMD Family 10h NB"; | ||
153 | } | ||
154 | |||
103 | struct pci_mmcfg_hostbridge_probe { | 155 | struct pci_mmcfg_hostbridge_probe { |
156 | u32 bus; | ||
157 | u32 devfn; | ||
104 | u32 vendor; | 158 | u32 vendor; |
105 | u32 device; | 159 | u32 device; |
106 | const char *(*probe)(void); | 160 | const char *(*probe)(void); |
107 | }; | 161 | }; |
108 | 162 | ||
109 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | 163 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { |
110 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, | 164 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, |
111 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | 165 | PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
166 | { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, | ||
167 | PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | ||
168 | { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD, | ||
169 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
170 | { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, | ||
171 | 0x1200, pci_mmcfg_amd_fam10h }, | ||
112 | }; | 172 | }; |
113 | 173 | ||
114 | static int __init pci_mmcfg_check_hostbridge(void) | 174 | static int __init pci_mmcfg_check_hostbridge(void) |
115 | { | 175 | { |
116 | u32 l; | 176 | u32 l; |
177 | u32 bus, devfn; | ||
117 | u16 vendor, device; | 178 | u16 vendor, device; |
118 | int i; | 179 | int i; |
119 | const char *name; | 180 | const char *name; |
120 | 181 | ||
121 | pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); | ||
122 | vendor = l & 0xffff; | ||
123 | device = (l >> 16) & 0xffff; | ||
124 | |||
125 | pci_mmcfg_config_num = 0; | 182 | pci_mmcfg_config_num = 0; |
126 | pci_mmcfg_config = NULL; | 183 | pci_mmcfg_config = NULL; |
127 | name = NULL; | 184 | name = NULL; |
128 | 185 | ||
129 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { | 186 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
187 | bus = pci_mmcfg_probes[i].bus; | ||
188 | devfn = pci_mmcfg_probes[i].devfn; | ||
189 | pci_direct_conf1.read(0, bus, devfn, 0, 4, &l); | ||
190 | vendor = l & 0xffff; | ||
191 | device = (l >> 16) & 0xffff; | ||
192 | |||
130 | if (pci_mmcfg_probes[i].vendor == vendor && | 193 | if (pci_mmcfg_probes[i].vendor == vendor && |
131 | pci_mmcfg_probes[i].device == device) | 194 | pci_mmcfg_probes[i].device == device) |
132 | name = pci_mmcfg_probes[i].probe(); | 195 | name = pci_mmcfg_probes[i].probe(); |