blob: 77de6de94f1f729465f20c5006d3c2cd82d2cfe1 [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
25/* Verify the first 16 busses. We assume that systems with more busses
26 get MCFG right. */
27#define PCI_MMCFG_MAX_CHECK_BUS 16
28
29DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
30
31/* K8 systems have some devices (typically in the builtin northbridge)
32 that are only accessible using type1
33 Normally this can be expressed in the MCFG by not listing them
34 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
35 Instead try to discover all devices on bus 0 that are unreachable using MM
36 and fallback for them. */
37static __init void unreachable_devices(void)
38{
39 int i, k;
40 /* Use the max bus number from ACPI here? */
41 for (k = 0; k < PCI_MMCFG_MAX_CHECK_BUS; k++) {
42 for (i = 0; i < 32; i++) {
43 u32 val1, val2;
44
45 pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1);
46 if (val1 == 0xffffffff)
47 continue;
48
49 raw_pci_ops->read(0, k, PCI_DEVFN(i, 0), 0, 4, &val2);
50 if (val1 != val2) {
51 set_bit(i + 32*k, pci_mmcfg_fallback_slots);
52 printk(KERN_NOTICE "PCI: No mmconfig possible"
53 " on device %02x:%02x\n", k, i);
54 }
55 }
56 }
57}
58
Olivier Galibert9358c692007-02-13 13:26:20 +010059static __init const char *pci_mmcfg_e7520(void)
60{
61 u32 win;
62 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
63
64 pci_mmcfg_config_num = 1;
65 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
66 if (!pci_mmcfg_config)
67 return NULL;
68 pci_mmcfg_config[0].address = (win & 0xf000) << 16;
69 pci_mmcfg_config[0].pci_segment = 0;
70 pci_mmcfg_config[0].start_bus_number = 0;
71 pci_mmcfg_config[0].end_bus_number = 255;
72
73 return "Intel Corporation E7520 Memory Controller Hub";
74}
75
76static __init const char *pci_mmcfg_intel_945(void)
77{
78 u32 pciexbar, mask = 0, len = 0;
79
80 pci_mmcfg_config_num = 1;
81
82 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
83
84 /* Enable bit */
85 if (!(pciexbar & 1))
86 pci_mmcfg_config_num = 0;
87
88 /* Size bits */
89 switch ((pciexbar >> 1) & 3) {
90 case 0:
91 mask = 0xf0000000U;
92 len = 0x10000000U;
93 break;
94 case 1:
95 mask = 0xf8000000U;
96 len = 0x08000000U;
97 break;
98 case 2:
99 mask = 0xfc000000U;
100 len = 0x04000000U;
101 break;
102 default:
103 pci_mmcfg_config_num = 0;
104 }
105
106 /* Errata #2, things break when not aligned on a 256Mb boundary */
107 /* Can only happen in 64M/128M mode */
108
109 if ((pciexbar & mask) & 0x0fffffffU)
110 pci_mmcfg_config_num = 0;
111
112 if (pci_mmcfg_config_num) {
113 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
114 if (!pci_mmcfg_config)
115 return NULL;
116 pci_mmcfg_config[0].address = pciexbar & mask;
117 pci_mmcfg_config[0].pci_segment = 0;
118 pci_mmcfg_config[0].start_bus_number = 0;
119 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
120 }
121
122 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
123}
124
125struct pci_mmcfg_hostbridge_probe {
126 u32 vendor;
127 u32 device;
128 const char *(*probe)(void);
129};
130
131static __initdata struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] = {
132 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
133 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
134};
135
136static int __init pci_mmcfg_check_hostbridge(void)
137{
138 u32 l;
139 u16 vendor, device;
140 int i;
141 const char *name;
142
143 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
144 vendor = l & 0xffff;
145 device = (l >> 16) & 0xffff;
146
147 pci_mmcfg_config_num = 0;
148 pci_mmcfg_config = NULL;
149 name = NULL;
150
151 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++)
152 if ((pci_mmcfg_probes[i].vendor == PCI_ANY_ID ||
153 pci_mmcfg_probes[i].vendor == vendor) &&
154 (pci_mmcfg_probes[i].device == PCI_ANY_ID ||
155 pci_mmcfg_probes[i].device == device))
156 name = pci_mmcfg_probes[i].probe();
157
158 if (name) {
159 if (pci_mmcfg_config_num)
160 printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", name);
161 else
162 printk(KERN_INFO "PCI: Found %s without MMCONFIG support.\n",
163 name);
164 }
165
166 return name != NULL;
167}
168
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100169static __init void pci_mmcfg_insert_resources(void)
170{
171#define PCI_MMCFG_RESOURCE_NAME_LEN 19
172 int i;
173 struct resource *res;
174 char *names;
175 unsigned num_buses;
176
177 res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
178 pci_mmcfg_config_num, GFP_KERNEL);
179
180 if (!res) {
181 printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
182 return;
183 }
184
185 names = (void *)&res[pci_mmcfg_config_num];
186 for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
187 num_buses = pci_mmcfg_config[i].end_bus_number -
188 pci_mmcfg_config[i].start_bus_number + 1;
189 res->name = names;
190 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
191 pci_mmcfg_config[i].pci_segment);
192 res->start = pci_mmcfg_config[i].address;
193 res->end = res->start + (num_buses << 20) - 1;
194 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
195 insert_resource(&iomem_resource, res);
196 names += PCI_MMCFG_RESOURCE_NAME_LEN;
197 }
198}
199
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100200static void __init pci_mmcfg_reject_broken(void)
201{
202 typeof(pci_mmcfg_config[0]) *cfg = &pci_mmcfg_config[0];
203
204 /*
205 * Handle more broken MCFG tables on Asus etc.
206 * They only contain a single entry for bus 0-0.
207 */
208 if (pci_mmcfg_config_num == 1 &&
209 cfg->pci_segment == 0 &&
210 (cfg->start_bus_number | cfg->end_bus_number) == 0) {
211 kfree(pci_mmcfg_config);
212 pci_mmcfg_config = NULL;
213 pci_mmcfg_config_num = 0;
214
215 printk(KERN_ERR "PCI: start and end of bus number is 0. "
216 "Rejected as broken MCFG.");
217 }
218}
219
Olivier Galibertb7867392007-02-13 13:26:20 +0100220void __init pci_mmcfg_init(int type)
221{
Olivier Galibert9358c692007-02-13 13:26:20 +0100222 int known_bridge = 0;
223
Olivier Galibertb7867392007-02-13 13:26:20 +0100224 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
225 return;
226
Olivier Galibert9358c692007-02-13 13:26:20 +0100227 if (type == 1 && pci_mmcfg_check_hostbridge())
228 known_bridge = 1;
229
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100230 if (!known_bridge) {
Olivier Galibert9358c692007-02-13 13:26:20 +0100231 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
OGAWA Hirofumi44de0202007-02-13 13:26:20 +0100232 pci_mmcfg_reject_broken();
233 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100234
235 if ((pci_mmcfg_config_num == 0) ||
236 (pci_mmcfg_config == NULL) ||
237 (pci_mmcfg_config[0].address == 0))
238 return;
239
240 /* Only do this check when type 1 works. If it doesn't work
241 assume we run on a Mac and always use MCFG */
Olivier Galibert9358c692007-02-13 13:26:20 +0100242 if (type == 1 && !known_bridge &&
Olivier Galibertb7867392007-02-13 13:26:20 +0100243 !e820_all_mapped(pci_mmcfg_config[0].address,
244 pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
245 E820_RESERVED)) {
246 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not E820-reserved\n",
247 pci_mmcfg_config[0].address);
248 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
249 return;
250 }
251
252 if (pci_mmcfg_arch_init()) {
Olivier Galibert5f027382007-02-13 13:26:20 +0100253 if (type == 1)
254 unreachable_devices();
Olivier Galibert6a0668f2007-02-13 13:26:20 +0100255 if (known_bridge)
256 pci_mmcfg_insert_resources();
Olivier Galibertb7867392007-02-13 13:26:20 +0100257 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
258 }
259}