blob: c7cabeed4d7b589cc9637ab326d71ae68efba1da [file] [log] [blame]
Olivier Galibertb7867392007-02-13 13:26:20 +01001/*
2 * mmconfig-shared.c - Low-level direct PCI config space access via
3 * MMCONFIG - common code between i386 and x86-64.
4 *
5 * This code does:
Olivier Galibert9358c692007-02-13 13:26:20 +01006 * - known chipset handling
Olivier Galibertb7867392007-02-13 13:26:20 +01007 * - ACPI decoding and validation
8 *
9 * Per-architecture code takes care of the mappings and accesses
10 * themselves.
11 */
12
13#include <linux/pci.h>
14#include <linux/init.h>
15#include <linux/acpi.h>
16#include <linux/bitmap.h>
17#include <asm/e820.h>
18
19#include "pci.h"
20
21/* aperture is up to 256MB but BIOS may reserve less */
22#define MMCONFIG_APER_MIN (2 * 1024*1024)
23#define MMCONFIG_APER_MAX (256 * 1024*1024)
24
Olivier Galibertb7867392007-02-13 13:26:20 +010025DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
26
27/* K8 systems have some devices (typically in the builtin northbridge)
28 that are only accessible using type1
29 Normally this can be expressed in the MCFG by not listing them
30 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
31 Instead try to discover all devices on bus 0 that are unreachable using MM
32 and fallback for them. */
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010033static void __init unreachable_devices(void)
Olivier Galibertb7867392007-02-13 13:26:20 +010034{
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010035 int i, bus;
Olivier Galibertb7867392007-02-13 13:26:20 +010036 /* Use the max bus number from ACPI here? */
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010037 for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
Olivier Galibertb7867392007-02-13 13:26:20 +010038 for (i = 0; i < 32; i++) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010039 unsigned int devfn = PCI_DEVFN(i, 0);
Olivier Galibertb7867392007-02-13 13:26:20 +010040 u32 val1, val2;
41
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010042 pci_conf1_read(0, bus, devfn, 0, 4, &val1);
Olivier Galibertb7867392007-02-13 13:26:20 +010043 if (val1 == 0xffffffff)
44 continue;
45
OGAWA Hirofumi56829d12007-02-13 13:26:20 +010046 if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
47 raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
48 if (val1 == val2)
49 continue;
Olivier Galibertb7867392007-02-13 13:26:20 +010050 }
OGAWA Hirofumi56829d12007-02-13 13:26:20 +010051 set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
52 printk(KERN_NOTICE "PCI: No mmconfig possible on device"
53 " %02x:%02x\n", bus, i);
Olivier Galibertb7867392007-02-13 13:26:20 +010054 }
55 }
56}
57
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010058static const char __init *pci_mmcfg_e7520(void)
Olivier Galibert9358c692007-02-13 13:26:20 +010059{
60 u32 win;
61 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
62
Olivier Galibertb5229db2007-05-02 19:27:22 +020063 win = win & 0xf000;
64 if(win == 0x0000 || win == 0xf000)
65 pci_mmcfg_config_num = 0;
66 else {
67 pci_mmcfg_config_num = 1;
68 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
69 if (!pci_mmcfg_config)
70 return NULL;
71 pci_mmcfg_config[0].address = win << 16;
72 pci_mmcfg_config[0].pci_segment = 0;
73 pci_mmcfg_config[0].start_bus_number = 0;
74 pci_mmcfg_config[0].end_bus_number = 255;
75 }
Olivier Galibert9358c692007-02-13 13:26:20 +010076
77 return "Intel Corporation E7520 Memory Controller Hub";
78}
79
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010080static const char __init *pci_mmcfg_intel_945(void)
Olivier Galibert9358c692007-02-13 13:26:20 +010081{
82 u32 pciexbar, mask = 0, len = 0;
83
84 pci_mmcfg_config_num = 1;
85
86 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
87
88 /* Enable bit */
89 if (!(pciexbar & 1))
90 pci_mmcfg_config_num = 0;
91
92 /* Size bits */
93 switch ((pciexbar >> 1) & 3) {
94 case 0:
95 mask = 0xf0000000U;
96 len = 0x10000000U;
97 break;
98 case 1:
99 mask = 0xf8000000U;
100 len = 0x08000000U;
101 break;
102 case 2:
103 mask = 0xfc000000U;
104 len = 0x04000000U;
105 break;
106 default:
107 pci_mmcfg_config_num = 0;
108 }
109
110 /* Errata #2, things break when not aligned on a 256Mb boundary */
111 /* Can only happen in 64M/128M mode */
112
113 if ((pciexbar & mask) & 0x0fffffffU)
114 pci_mmcfg_config_num = 0;
115
Olivier Galibertb5229db2007-05-02 19:27:22 +0200116 /* Don't hit the APIC registers and their friends */
117 if ((pciexbar & mask) >= 0xf0000000U)
118 pci_mmcfg_config_num = 0;
119
Olivier Galibert9358c692007-02-13 13:26:20 +0100120 if (pci_mmcfg_config_num) {
121 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
122 if (!pci_mmcfg_config)
123 return NULL;
124 pci_mmcfg_config[0].address = pciexbar & mask;
125 pci_mmcfg_config[0].pci_segment = 0;
126 pci_mmcfg_config[0].start_bus_number = 0;
127 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
128 }
129
130 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
131}
132
133struct pci_mmcfg_hostbridge_probe {
134 u32 vendor;
135 u32 device;
136 const char *(*probe)(void);
137};
138
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100139static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
Olivier Galibert9358c692007-02-13 13:26:20 +0100140 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
141 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
142};
143
144static int __init pci_mmcfg_check_hostbridge(void)
145{
146 u32 l;
147 u16 vendor, device;
148 int i;
149 const char *name;
150
151 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
152 vendor = l & 0xffff;
153 device = (l >> 16) & 0xffff;
154
155 pci_mmcfg_config_num = 0;
156 pci_mmcfg_config = NULL;
157 name = NULL;
158
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100159 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
160 if (pci_mmcfg_probes[i].vendor == vendor &&
161 pci_mmcfg_probes[i].device == device)
Olivier Galibert9358c692007-02-13 13:26:20 +0100162 name = pci_mmcfg_probes[i].probe();
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100163 }
Olivier Galibert9358c692007-02-13 13:26:20 +0100164
165 if (name) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100166 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
167 name, pci_mmcfg_config_num ? "with" : "without");
Olivier Galibert9358c692007-02-13 13:26:20 +0100168 }
169
170 return name != NULL;
171}
172
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100173static void __init pci_mmcfg_insert_resources(void)
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100174{
175#define PCI_MMCFG_RESOURCE_NAME_LEN 19
176 int i;
177 struct resource *res;
178 char *names;
179 unsigned num_buses;
180
181 res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
182 pci_mmcfg_config_num, GFP_KERNEL);
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100183 if (!res) {
184 printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
185 return;
186 }
187
188 names = (void *)&res[pci_mmcfg_config_num];
189 for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100190 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
191 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100192 res->name = names;
193 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100194 cfg->pci_segment);
195 res->start = cfg->address;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100196 res->end = res->start + (num_buses << 20) - 1;
197 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
198 insert_resource(&iomem_resource, res);
199 names += PCI_MMCFG_RESOURCE_NAME_LEN;
200 }
201}
202
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100203static void __init pci_mmcfg_reject_broken(int type)
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100204{
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100205 typeof(pci_mmcfg_config[0]) *cfg;
206
207 if ((pci_mmcfg_config_num == 0) ||
208 (pci_mmcfg_config == NULL) ||
209 (pci_mmcfg_config[0].address == 0))
210 return;
211
212 cfg = &pci_mmcfg_config[0];
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100213
214 /*
215 * Handle more broken MCFG tables on Asus etc.
216 * They only contain a single entry for bus 0-0.
217 */
218 if (pci_mmcfg_config_num == 1 &&
219 cfg->pci_segment == 0 &&
220 (cfg->start_bus_number | cfg->end_bus_number) == 0) {
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100221 printk(KERN_ERR "PCI: start and end of bus number is 0. "
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100222 "Rejected as broken MCFG.\n");
223 goto reject;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100224 }
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100225
226 /*
227 * Only do this check when type 1 works. If it doesn't work
228 * assume we run on a Mac and always use MCFG
229 */
230 if (type == 1 && !e820_all_mapped(cfg->address,
231 cfg->address + MMCONFIG_APER_MIN,
232 E820_RESERVED)) {
233 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
234 " E820-reserved\n", cfg->address);
235 goto reject;
236 }
237 return;
238
239reject:
240 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
241 kfree(pci_mmcfg_config);
242 pci_mmcfg_config = NULL;
243 pci_mmcfg_config_num = 0;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100244}
245
Olivier Galibertb7867392007-02-13 13:26:20 +0100246void __init pci_mmcfg_init(int type)
247{
Olivier Galibert9358c692007-02-13 13:26:20 +0100248 int known_bridge = 0;
249
Olivier Galibertb7867392007-02-13 13:26:20 +0100250 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
251 return;
252
Olivier Galibert9358c692007-02-13 13:26:20 +0100253 if (type == 1 && pci_mmcfg_check_hostbridge())
254 known_bridge = 1;
255
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100256 if (!known_bridge) {
Olivier Galibert9358c692007-02-13 13:26:20 +0100257 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100258 pci_mmcfg_reject_broken(type);
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100259 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100260
261 if ((pci_mmcfg_config_num == 0) ||
262 (pci_mmcfg_config == NULL) ||
263 (pci_mmcfg_config[0].address == 0))
264 return;
265
Olivier Galibertb7867392007-02-13 13:26:20 +0100266 if (pci_mmcfg_arch_init()) {
Olivier Galibert5f027382007-02-13 13:26:20 +0100267 if (type == 1)
268 unreachable_devices();
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100269 if (known_bridge)
270 pci_mmcfg_insert_resources();
Olivier Galibertb7867392007-02-13 13:26:20 +0100271 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
272 }
273}