blob: 747d8c63b0c49a1fb390dacfd5cdd96d58e35a95 [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
63 pci_mmcfg_config_num = 1;
64 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
65 if (!pci_mmcfg_config)
66 return NULL;
67 pci_mmcfg_config[0].address = (win & 0xf000) << 16;
68 pci_mmcfg_config[0].pci_segment = 0;
69 pci_mmcfg_config[0].start_bus_number = 0;
70 pci_mmcfg_config[0].end_bus_number = 255;
71
72 return "Intel Corporation E7520 Memory Controller Hub";
73}
74
OGAWA Hirofumi429d5122007-02-13 13:26:20 +010075static const char __init *pci_mmcfg_intel_945(void)
Olivier Galibert9358c692007-02-13 13:26:20 +010076{
77 u32 pciexbar, mask = 0, len = 0;
78
79 pci_mmcfg_config_num = 1;
80
81 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
82
83 /* Enable bit */
84 if (!(pciexbar & 1))
85 pci_mmcfg_config_num = 0;
86
87 /* Size bits */
88 switch ((pciexbar >> 1) & 3) {
89 case 0:
90 mask = 0xf0000000U;
91 len = 0x10000000U;
92 break;
93 case 1:
94 mask = 0xf8000000U;
95 len = 0x08000000U;
96 break;
97 case 2:
98 mask = 0xfc000000U;
99 len = 0x04000000U;
100 break;
101 default:
102 pci_mmcfg_config_num = 0;
103 }
104
105 /* Errata #2, things break when not aligned on a 256Mb boundary */
106 /* Can only happen in 64M/128M mode */
107
108 if ((pciexbar & mask) & 0x0fffffffU)
109 pci_mmcfg_config_num = 0;
110
111 if (pci_mmcfg_config_num) {
112 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
113 if (!pci_mmcfg_config)
114 return NULL;
115 pci_mmcfg_config[0].address = pciexbar & mask;
116 pci_mmcfg_config[0].pci_segment = 0;
117 pci_mmcfg_config[0].start_bus_number = 0;
118 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
119 }
120
121 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
122}
123
124struct pci_mmcfg_hostbridge_probe {
125 u32 vendor;
126 u32 device;
127 const char *(*probe)(void);
128};
129
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100130static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
Olivier Galibert9358c692007-02-13 13:26:20 +0100131 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
132 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
133};
134
135static int __init pci_mmcfg_check_hostbridge(void)
136{
137 u32 l;
138 u16 vendor, device;
139 int i;
140 const char *name;
141
142 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
143 vendor = l & 0xffff;
144 device = (l >> 16) & 0xffff;
145
146 pci_mmcfg_config_num = 0;
147 pci_mmcfg_config = NULL;
148 name = NULL;
149
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100150 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
151 if (pci_mmcfg_probes[i].vendor == vendor &&
152 pci_mmcfg_probes[i].device == device)
Olivier Galibert9358c692007-02-13 13:26:20 +0100153 name = pci_mmcfg_probes[i].probe();
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100154 }
Olivier Galibert9358c692007-02-13 13:26:20 +0100155
156 if (name) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100157 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
158 name, pci_mmcfg_config_num ? "with" : "without");
Olivier Galibert9358c692007-02-13 13:26:20 +0100159 }
160
161 return name != NULL;
162}
163
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100164static void __init pci_mmcfg_insert_resources(void)
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100165{
166#define PCI_MMCFG_RESOURCE_NAME_LEN 19
167 int i;
168 struct resource *res;
169 char *names;
170 unsigned num_buses;
171
172 res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
173 pci_mmcfg_config_num, GFP_KERNEL);
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100174 if (!res) {
175 printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
176 return;
177 }
178
179 names = (void *)&res[pci_mmcfg_config_num];
180 for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100181 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
182 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100183 res->name = names;
184 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
OGAWA Hirofumi429d5122007-02-13 13:26:20 +0100185 cfg->pci_segment);
186 res->start = cfg->address;
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100187 res->end = res->start + (num_buses << 20) - 1;
188 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
189 insert_resource(&iomem_resource, res);
190 names += PCI_MMCFG_RESOURCE_NAME_LEN;
191 }
192}
193
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100194static void __init pci_mmcfg_reject_broken(int type)
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100195{
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100196 typeof(pci_mmcfg_config[0]) *cfg;
197
198 if ((pci_mmcfg_config_num == 0) ||
199 (pci_mmcfg_config == NULL) ||
200 (pci_mmcfg_config[0].address == 0))
201 return;
202
203 cfg = &pci_mmcfg_config[0];
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100204
205 /*
206 * Handle more broken MCFG tables on Asus etc.
207 * They only contain a single entry for bus 0-0.
208 */
209 if (pci_mmcfg_config_num == 1 &&
210 cfg->pci_segment == 0 &&
211 (cfg->start_bus_number | cfg->end_bus_number) == 0) {
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100212 printk(KERN_ERR "PCI: start and end of bus number is 0. "
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100213 "Rejected as broken MCFG.\n");
214 goto reject;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100215 }
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100216
217 /*
218 * Only do this check when type 1 works. If it doesn't work
219 * assume we run on a Mac and always use MCFG
220 */
221 if (type == 1 && !e820_all_mapped(cfg->address,
222 cfg->address + MMCONFIG_APER_MIN,
223 E820_RESERVED)) {
224 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
225 " E820-reserved\n", cfg->address);
226 goto reject;
227 }
228 return;
229
230reject:
231 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
232 kfree(pci_mmcfg_config);
233 pci_mmcfg_config = NULL;
234 pci_mmcfg_config_num = 0;
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100235}
236
Olivier Galibertb7867392007-02-13 13:26:20 +0100237void __init pci_mmcfg_init(int type)
238{
Olivier Galibert9358c692007-02-13 13:26:20 +0100239 int known_bridge = 0;
240
Olivier Galibertb7867392007-02-13 13:26:20 +0100241 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
242 return;
243
Olivier Galibert9358c692007-02-13 13:26:20 +0100244 if (type == 1 && pci_mmcfg_check_hostbridge())
245 known_bridge = 1;
246
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100247 if (!known_bridge) {
Olivier Galibert9358c692007-02-13 13:26:20 +0100248 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
OGAWA Hirofumi26054ed2007-02-13 13:26:20 +0100249 pci_mmcfg_reject_broken(type);
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100250 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100251
252 if ((pci_mmcfg_config_num == 0) ||
253 (pci_mmcfg_config == NULL) ||
254 (pci_mmcfg_config[0].address == 0))
255 return;
256
Olivier Galibertb7867392007-02-13 13:26:20 +0100257 if (pci_mmcfg_arch_init()) {
Olivier Galibert5f027382007-02-13 13:26:20 +0100258 if (type == 1)
259 unreachable_devices();
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100260 if (known_bridge)
261 pci_mmcfg_insert_resources();
Olivier Galibertb7867392007-02-13 13:26:20 +0100262 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
263 }
264}