]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - arch/x86/pci/common.c
Merge commit 'origin/HEAD' into test-merge
[mirror_ubuntu-artful-kernel.git] / arch / x86 / pci / common.c
CommitLineData
1da177e4
LT
1/*
2 * Low-Level PCI Support for PC
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 */
6
7#include <linux/sched.h>
8#include <linux/pci.h>
9#include <linux/ioport.h>
10#include <linux/init.h>
8c4b2cf9 11#include <linux/dmi.h>
1da177e4
LT
12
13#include <asm/acpi.h>
14#include <asm/segment.h>
15#include <asm/io.h>
16#include <asm/smp.h>
17
18#include "pci.h"
19
1da177e4
LT
20unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
21 PCI_PROBE_MMCONF;
22
2b290da0 23static int pci_bf_sort;
1da177e4
LT
24int pci_routeirq;
25int pcibios_last_bus = -1;
120bb424 26unsigned long pirq_table_addr;
27struct pci_bus *pci_root_bus;
1da177e4 28struct pci_raw_ops *raw_pci_ops;
b6ce068a
MW
29struct pci_raw_ops *raw_pci_ext_ops;
30
31int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
32 int reg, int len, u32 *val)
33{
34 if (reg < 256 && raw_pci_ops)
35 return raw_pci_ops->read(domain, bus, devfn, reg, len, val);
36 if (raw_pci_ext_ops)
37 return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val);
38 return -EINVAL;
39}
40
41int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
42 int reg, int len, u32 val)
43{
44 if (reg < 256 && raw_pci_ops)
45 return raw_pci_ops->write(domain, bus, devfn, reg, len, val);
46 if (raw_pci_ext_ops)
47 return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val);
48 return -EINVAL;
49}
1da177e4
LT
50
51static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
52{
b6ce068a 53 return raw_pci_read(pci_domain_nr(bus), bus->number,
a79e4198 54 devfn, where, size, value);
1da177e4
LT
55}
56
57static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
58{
b6ce068a 59 return raw_pci_write(pci_domain_nr(bus), bus->number,
a79e4198 60 devfn, where, size, value);
1da177e4
LT
61}
62
63struct pci_ops pci_root_ops = {
64 .read = pci_read,
65 .write = pci_write,
66};
67
68/*
69 * legacy, numa, and acpi all want to call pcibios_scan_root
70 * from their initcalls. This flag prevents that.
71 */
72int pcibios_scanned;
73
74/*
75 * This interrupt-safe spinlock protects all accesses to PCI
76 * configuration space.
77 */
78DEFINE_SPINLOCK(pci_config_lock);
79
13a6ddb0
YL
80static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
81{
82 pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
83 printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
84 return 0;
85}
86
87static struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitdata = {
88/*
89 * Systems where PCI IO resource ISA alignment can be skipped
90 * when the ISA enable bit in the bridge control is not set
91 */
92 {
93 .callback = can_skip_ioresource_align,
94 .ident = "IBM System x3800",
95 .matches = {
96 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
97 DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
98 },
99 },
100 {
101 .callback = can_skip_ioresource_align,
102 .ident = "IBM System x3850",
103 .matches = {
104 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "x3850"),
106 },
107 },
108 {
109 .callback = can_skip_ioresource_align,
110 .ident = "IBM System x3950",
111 .matches = {
112 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
113 DMI_MATCH(DMI_PRODUCT_NAME, "x3950"),
114 },
115 },
116 {}
117};
118
119void __init dmi_check_skip_isa_align(void)
120{
121 dmi_check_system(can_skip_pciprobe_dmi_table);
122}
123
1da177e4
LT
124/*
125 * Called after each bus is probed, but before its children
126 * are examined.
127 */
128
129void __devinit pcibios_fixup_bus(struct pci_bus *b)
130{
1da177e4
LT
131 pci_read_bridge_bases(b);
132}
133
6b4b78fe
MD
134/*
135 * Only use DMI information to set this if nothing was passed
136 * on the kernel command line (which was parsed earlier).
137 */
138
1855256c 139static int __devinit set_bf_sort(const struct dmi_system_id *d)
6b4b78fe
MD
140{
141 if (pci_bf_sort == pci_bf_sort_default) {
142 pci_bf_sort = pci_dmi_bf;
143 printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
144 }
145 return 0;
146}
147
8c4b2cf9
BK
148/*
149 * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
150 */
151#ifdef __i386__
1855256c 152static int __devinit assign_all_busses(const struct dmi_system_id *d)
8c4b2cf9
BK
153{
154 pci_probe |= PCI_ASSIGN_ALL_BUSSES;
155 printk(KERN_INFO "%s detected: enabling PCI bus# renumbering"
156 " (pci=assign-busses)\n", d->ident);
157 return 0;
158}
159#endif
160
6b4b78fe
MD
161static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
162#ifdef __i386__
8c4b2cf9
BK
163/*
164 * Laptops which need pci=assign-busses to see Cardbus cards
165 */
8c4b2cf9
BK
166 {
167 .callback = assign_all_busses,
168 .ident = "Samsung X20 Laptop",
169 .matches = {
170 DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"),
171 DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"),
172 },
173 },
174#endif /* __i386__ */
6b4b78fe
MD
175 {
176 .callback = set_bf_sort,
177 .ident = "Dell PowerEdge 1950",
178 .matches = {
179 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
180 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
181 },
182 },
183 {
184 .callback = set_bf_sort,
185 .ident = "Dell PowerEdge 1955",
186 .matches = {
187 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
188 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
189 },
190 },
191 {
192 .callback = set_bf_sort,
193 .ident = "Dell PowerEdge 2900",
194 .matches = {
195 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
196 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
197 },
198 },
199 {
200 .callback = set_bf_sort,
201 .ident = "Dell PowerEdge 2950",
202 .matches = {
203 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
204 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
205 },
206 },
f7a9dae7
MD
207 {
208 .callback = set_bf_sort,
209 .ident = "Dell PowerEdge R900",
210 .matches = {
211 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
212 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"),
213 },
214 },
f52383d3
AG
215 {
216 .callback = set_bf_sort,
217 .ident = "HP ProLiant BL20p G3",
218 .matches = {
219 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
220 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"),
221 },
222 },
223 {
224 .callback = set_bf_sort,
225 .ident = "HP ProLiant BL20p G4",
226 .matches = {
227 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
228 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"),
229 },
230 },
231 {
232 .callback = set_bf_sort,
233 .ident = "HP ProLiant BL30p G1",
234 .matches = {
235 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
236 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"),
237 },
238 },
239 {
240 .callback = set_bf_sort,
241 .ident = "HP ProLiant BL25p G1",
242 .matches = {
243 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
244 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"),
245 },
246 },
247 {
248 .callback = set_bf_sort,
249 .ident = "HP ProLiant BL35p G1",
250 .matches = {
251 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
252 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"),
253 },
254 },
255 {
256 .callback = set_bf_sort,
257 .ident = "HP ProLiant BL45p G1",
258 .matches = {
259 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
260 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"),
261 },
262 },
263 {
264 .callback = set_bf_sort,
265 .ident = "HP ProLiant BL45p G2",
266 .matches = {
267 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
268 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"),
269 },
270 },
271 {
272 .callback = set_bf_sort,
273 .ident = "HP ProLiant BL460c G1",
274 .matches = {
275 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
276 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"),
277 },
278 },
279 {
280 .callback = set_bf_sort,
281 .ident = "HP ProLiant BL465c G1",
282 .matches = {
283 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
284 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"),
285 },
286 },
287 {
288 .callback = set_bf_sort,
289 .ident = "HP ProLiant BL480c G1",
290 .matches = {
291 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
292 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"),
293 },
294 },
295 {
296 .callback = set_bf_sort,
297 .ident = "HP ProLiant BL685c G1",
298 .matches = {
299 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
300 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"),
301 },
302 },
8f8ae1a7
MS
303 {
304 .callback = set_bf_sort,
8d64c781 305 .ident = "HP ProLiant DL360",
8f8ae1a7
MS
306 .matches = {
307 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
8d64c781 308 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"),
8f8ae1a7
MS
309 },
310 },
311 {
312 .callback = set_bf_sort,
8d64c781 313 .ident = "HP ProLiant DL380",
8f8ae1a7
MS
314 .matches = {
315 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
8d64c781 316 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"),
8f8ae1a7
MS
317 },
318 },
5b1ea82f
JL
319#ifdef __i386__
320 {
321 .callback = assign_all_busses,
322 .ident = "Compaq EVO N800c",
323 .matches = {
324 DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
325 DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"),
326 },
327 },
328#endif
c82bc5ad
MS
329 {
330 .callback = set_bf_sort,
739db07f 331 .ident = "HP ProLiant DL385 G2",
c82bc5ad
MS
332 .matches = {
333 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
739db07f 334 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"),
c82bc5ad
MS
335 },
336 },
337 {
338 .callback = set_bf_sort,
739db07f 339 .ident = "HP ProLiant DL585 G2",
c82bc5ad
MS
340 .matches = {
341 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
739db07f 342 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"),
c82bc5ad
MS
343 },
344 },
8c4b2cf9
BK
345 {}
346};
1da177e4 347
0df18ff3
YL
348void __init dmi_check_pciprobe(void)
349{
350 dmi_check_system(pciprobe_dmi_table);
351}
352
1da177e4
LT
353struct pci_bus * __devinit pcibios_scan_root(int busnum)
354{
355 struct pci_bus *bus = NULL;
08f1c192 356 struct pci_sysdata *sd;
1da177e4
LT
357
358 while ((bus = pci_find_next_bus(bus)) != NULL) {
359 if (bus->number == busnum) {
360 /* Already scanned */
361 return bus;
362 }
363 }
364
08f1c192
MBY
365 /* Allocate per-root-bus (not per bus) arch-specific data.
366 * TODO: leak; this memory is never freed.
367 * It's arguable whether it's worth the trouble to care.
368 */
369 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
370 if (!sd) {
371 printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
372 return NULL;
373 }
374
871d5f8d
YL
375 sd->node = get_mp_bus_to_node(busnum);
376