aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/pci/pcbios.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/pci/pcbios.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/i386/pci/pcbios.c')
-rw-r--r--arch/i386/pci/pcbios.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
new file mode 100644
index 000000000000..141421b673b0
--- /dev/null
+++ b/arch/i386/pci/pcbios.c
@@ -0,0 +1,487 @@
1/*
2 * BIOS32 and PCI BIOS handling.
3 */
4
5#include <linux/pci.h>
6#include <linux/init.h>
7#include "pci.h"
8#include "pci-functions.h"
9
10
11/* BIOS32 signature: "_32_" */
12#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
13
14/* PCI signature: "PCI " */
15#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
16
17/* PCI service signature: "$PCI" */
18#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
19
20/* PCI BIOS hardware mechanism flags */
21#define PCIBIOS_HW_TYPE1 0x01
22#define PCIBIOS_HW_TYPE2 0x02
23#define PCIBIOS_HW_TYPE1_SPEC 0x10
24#define PCIBIOS_HW_TYPE2_SPEC 0x20
25
26/*
27 * This is the standard structure used to identify the entry point
28 * to the BIOS32 Service Directory, as documented in
29 * Standard BIOS 32-bit Service Directory Proposal
30 * Revision 0.4 May 24, 1993
31 * Phoenix Technologies Ltd.
32 * Norwood, MA
33 * and the PCI BIOS specification.
34 */
35
36union bios32 {
37 struct {
38 unsigned long signature; /* _32_ */
39 unsigned long entry; /* 32 bit physical address */
40 unsigned char revision; /* Revision level, 0 */
41 unsigned char length; /* Length in paragraphs should be 01 */
42 unsigned char checksum; /* All bytes must add up to zero */
43 unsigned char reserved[5]; /* Must be zero */
44 } fields;
45 char chars[16];
46};
47
48/*
49 * Physical address of the service directory. I don't know if we're
50 * allowed to have more than one of these or not, so just in case
51 * we'll make pcibios_present() take a memory start parameter and store
52 * the array there.
53 */
54
55static struct {
56 unsigned long address;
57 unsigned short segment;
58} bios32_indirect = { 0, __KERNEL_CS };
59
60/*
61 * Returns the entry point for the given service, NULL on error
62 */
63
64static unsigned long bios32_service(unsigned long service)
65{
66 unsigned char return_code; /* %al */
67 unsigned long address; /* %ebx */
68 unsigned long length; /* %ecx */
69 unsigned long entry; /* %edx */
70 unsigned long flags;
71
72 local_irq_save(flags);
73 __asm__("lcall *(%%edi); cld"
74 : "=a" (return_code),
75 "=b" (address),
76 "=c" (length),
77 "=d" (entry)
78 : "0" (service),
79 "1" (0),
80 "D" (&bios32_indirect));
81 local_irq_restore(flags);
82
83 switch (return_code) {
84 case 0:
85 return address + entry;
86 case 0x80: /* Not present */
87 printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
88 return 0;
89 default: /* Shouldn't happen */
90 printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
91 service, return_code);
92 return 0;
93 }
94}
95
96static struct {
97 unsigned long address;
98 unsigned short segment;
99} pci_indirect = { 0, __KERNEL_CS };
100
101static int pci_bios_present;
102
103static int __devinit check_pcibios(void)
104{
105 u32 signature, eax, ebx, ecx;
106 u8 status, major_ver, minor_ver, hw_mech;
107 unsigned long flags, pcibios_entry;
108
109 if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
110 pci_indirect.address = pcibios_entry + PAGE_OFFSET;
111
112 local_irq_save(flags);
113 __asm__(
114 "lcall *(%%edi); cld\n\t"
115 "jc 1f\n\t"
116 "xor %%ah, %%ah\n"
117 "1:"
118 : "=d" (signature),
119 "=a" (eax),
120 "=b" (ebx),
121 "=c" (ecx)
122 : "1" (PCIBIOS_PCI_BIOS_PRESENT),
123 "D" (&pci_indirect)
124 : "memory");
125 local_irq_restore(flags);
126
127 status = (eax >> 8) & 0xff;
128 hw_mech = eax & 0xff;
129 major_ver = (ebx >> 8) & 0xff;
130 minor_ver = ebx & 0xff;
131 if (pcibios_last_bus < 0)
132 pcibios_last_bus = ecx & 0xff;
133 DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
134 status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
135 if (status || signature != PCI_SIGNATURE) {
136 printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
137 status, signature);
138 return 0;
139 }
140 printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
141 major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
142#ifdef CONFIG_PCI_DIRECT
143 if (!(hw_mech & PCIBIOS_HW_TYPE1))
144 pci_probe &= ~PCI_PROBE_CONF1;
145 if (!(hw_mech & PCIBIOS_HW_TYPE2))
146 pci_probe &= ~PCI_PROBE_CONF2;
147#endif
148 return 1;
149 }
150 return 0;
151}
152
153static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
154 unsigned short index, unsigned char *bus, unsigned char *device_fn)
155{
156 unsigned short bx;
157 unsigned short ret;
158
159 __asm__("lcall *(%%edi); cld\n\t"
160 "jc 1f\n\t"
161 "xor %%ah, %%ah\n"
162 "1:"
163 : "=b" (bx),
164 "=a" (ret)
165 : "1" (PCIBIOS_FIND_PCI_DEVICE),
166 "c" (device_id),
167 "d" (vendor),
168 "S" ((int) index),
169 "D" (&pci_indirect));
170 *bus = (bx >> 8) & 0xff;
171 *device_fn = bx & 0xff;
172 return (int) (ret & 0xff00) >> 8;
173}
174
175static int pci_bios_read(unsigned int seg, unsigned int bus,
176 unsigned int devfn, int reg, int len, u32 *value)
177{
178 unsigned long result = 0;
179 unsigned long flags;
180 unsigned long bx = (bus << 8) | devfn;
181
182 if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
183 return -EINVAL;
184
185 spin_lock_irqsave(&pci_config_lock, flags);
186
187 switch (len) {
188 case 1:
189 __asm__("lcall *(%%esi); cld\n\t"
190 "jc 1f\n\t"
191 "xor %%ah, %%ah\n"
192 "1:"
193 : "=c" (*value),
194 "=a" (result)
195 : "1" (PCIBIOS_READ_CONFIG_BYTE),
196 "b" (bx),
197 "D" ((long)reg),
198 "S" (&pci_indirect));
199 break;
200 case 2:
201 __asm__("lcall *(%%esi); cld\n\t"
202 "jc 1f\n\t"
203 "xor %%ah, %%ah\n"
204 "1:"
205 : "=c" (*value),
206 "=a" (result)
207 : "1" (PCIBIOS_READ_CONFIG_WORD),
208 "b" (bx),
209 "D" ((long)reg),
210 "S" (&pci_indirect));
211 break;
212 case 4:
213 __asm__("lcall *(%%esi); cld\n\t"
214 "jc 1f\n\t"
215 "xor %%ah, %%ah\n"
216 "1:"
217 : "=c" (*value),
218 "=a" (result)
219 : "1" (PCIBIOS_READ_CONFIG_DWORD),
220 "b" (bx),
221 "D" ((long)reg),
222 "S" (&pci_indirect));
223 break;
224 }
225
226 spin_unlock_irqrestore(&pci_config_lock, flags);
227
228 return (int)((result & 0xff00) >> 8);
229}
230
231static int pci_bios_write(unsigned int seg, unsigned int bus,
232 unsigned int devfn, int reg, int len, u32 value)
233{
234 unsigned long result = 0;
235 unsigned long flags;
236 unsigned long bx = (bus << 8) | devfn;
237
238 if ((bus > 255) || (devfn > 255) || (reg > 255))
239 return -EINVAL;
240
241 spin_lock_irqsave(&pci_config_lock, flags);
242
243 switch (len) {
244 case 1:
245 __asm__("lcall *(%%esi); cld\n\t"
246 "jc 1f\n\t"
247 "xor %%ah, %%ah\n"
248 "1:"
249 : "=a" (result)
250 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
251 "c" (value),
252 "b" (bx),
253 "D" ((long)reg),
254 "S" (&pci_indirect));
255 break;
256 case 2:
257 __asm__("lcall *(%%esi); cld\n\t"
258 "jc 1f\n\t"
259 "xor %%ah, %%ah\n"
260 "1:"
261 : "=a" (result)
262 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
263 "c" (value),
264 "b" (bx),
265 "D" ((long)reg),
266 "S" (&pci_indirect));
267 break;
268 case 4:
269 __asm__("lcall *(%%esi); cld\n\t"
270 "jc 1f\n\t"
271 "xor %%ah, %%ah\n"
272 "1:"
273 : "=a" (result)
274 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
275 "c" (value),
276 "b" (bx),
277 "D" ((long)reg),
278 "S" (&pci_indirect));
279 break;
280 }
281
282 spin_unlock_irqrestore(&pci_config_lock, flags);
283
284 return (int)((result & 0xff00) >> 8);
285}
286
287
288/*
289 * Function table for BIOS32 access
290 */
291
292static struct pci_raw_ops pci_bios_access = {
293 .read = pci_bios_read,
294 .write = pci_bios_write
295};
296
297/*
298 * Try to find PCI BIOS.
299 */
300
301static struct pci_raw_ops * __devinit pci_find_bios(void)
302{
303 union bios32 *check;
304 unsigned char sum;
305 int i, length;
306
307 /*
308 * Follow the standard procedure for locating the BIOS32 Service
309 * directory by scanning the permissible address range from
310 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
311 */
312
313 for (check = (union bios32 *) __va(0xe0000);
314 check <= (union bios32 *) __va(0xffff0);
315 ++check) {
316 if (check->fields.signature != BIOS32_SIGNATURE)
317 continue;
318 length = check->fields.length * 16;
319 if (!length)
320 continue;
321 sum = 0;
322 for (i = 0; i < length ; ++i)
323 sum += check->chars[i];
324 if (sum != 0)
325 continue;
326 if (check->fields.revision != 0) {
327 printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
328 check->fields.revision, check);
329 continue;
330 }
331 DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
332 if (check->fields.entry >= 0x100000) {
333 printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
334 return NULL;
335 } else {
336 unsigned long bios32_entry = check->fields.entry;
337 DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
338 bios32_indirect.address = bios32_entry + PAGE_OFFSET;
339 if (check_pcibios())
340 return &pci_bios_access;
341 }
342 break; /* Hopefully more than one BIOS32 cannot happen... */
343 }
344
345 return NULL;
346}
347
348/*
349 * Sort the device list according to PCI BIOS. Nasty hack, but since some
350 * fool forgot to define the `correct' device order in the PCI BIOS specs
351 * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
352 * which used BIOS ordering, we are bound to do this...
353 */
354
355void __devinit pcibios_sort(void)
356{
357 LIST_HEAD(sorted_devices);
358 struct list_head *ln;
359 struct pci_dev *dev, *d;
360 int idx, found;
361 unsigned char bus, devfn;
362
363 DBG("PCI: Sorting device list...\n");
364 while (!list_empty(&pci_devices)) {
365 ln = pci_devices.next;
366 dev = pci_dev_g(ln);
367 idx = found = 0;
368 while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
369 idx++;
370 list_for_each(ln, &pci_devices) {
371 d = pci_dev_g(ln);
372 if (d->bus->number == bus && d->devfn == devfn) {
373 list_del(&d->global_list);
374 list_add_tail(&d->global_list, &sorted_devices);
375 if (d == dev)
376 found = 1;
377 break;
378 }
379 }
380 if (ln == &pci_devices) {
381 printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
382 /*
383 * We must not continue scanning as several buggy BIOSes
384 * return garbage after the last device. Grr.
385 */
386 break;
387 }
388 }
389 if (!found) {
390 printk(KERN_WARNING "PCI: Device %s not found by BIOS\n",
391 pci_name(dev));
392 list_del(&dev->global_list);
393 list_add_tail(&dev->global_list, &sorted_devices);
394 }
395 }
396 list_splice(&sorted_devices, &pci_devices);
397}
398
399/*
400 * BIOS Functions for IRQ Routing
401 */
402
403struct irq_routing_options {
404 u16 size;
405 struct irq_info *table;
406 u16 segment;
407} __attribute__((packed));
408
409struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
410{
411 struct irq_routing_options opt;
412 struct irq_routing_table *rt = NULL;
413 int ret, map;
414 unsigned long page;
415
416 if (!pci_bios_present)
417 return NULL;
418 page = __get_free_page(GFP_KERNEL);
419 if (!page)
420 return NULL;
421 opt.table = (struct irq_info *) page;
422 opt.size = PAGE_SIZE;
423 opt.segment = __KERNEL_DS;
424
425 DBG("PCI: Fetching IRQ routing table... ");
426 __asm__("push %%es\n\t"
427 "push %%ds\n\t"
428 "pop %%es\n\t"
429 "lcall *(%%esi); cld\n\t"
430 "pop %%es\n\t"
431 "jc 1f\n\t"
432 "xor %%ah, %%ah\n"
433 "1:"
434 : "=a" (ret),
435 "=b" (map),
436 "=m" (opt)
437 : "0" (PCIBIOS_GET_ROUTING_OPTIONS),
438 "1" (0),
439 "D" ((long) &opt),
440 "S" (&pci_indirect),
441 "m" (opt)
442 : "memory");
443 DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map);
444 if (ret & 0xff00)
445 printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
446 else if (opt.size) {
447 rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
448 if (rt) {
449 memset(rt, 0, sizeof(struct irq_routing_table));
450 rt->size = opt.size + sizeof(struct irq_routing_table);
451 rt->exclusive_irqs = map;
452 memcpy(rt->slots, (void *) page, opt.size);
453 printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
454 }
455 }
456 free_page(page);
457 return rt;
458}
459
460
461int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
462{
463 int ret;
464
465 __asm__("lcall *(%%esi); cld\n\t"
466 "jc 1f\n\t"
467 "xor %%ah, %%ah\n"
468 "1:"
469 : "=a" (ret)
470 : "0" (PCIBIOS_SET_PCI_HW_INT),
471 "b" ((dev->bus->number << 8) | dev->devfn),
472 "c" ((irq << 8) | (pin + 10)),
473 "S" (&pci_indirect));
474 return !(ret & 0xff00);
475}
476
477static int __init pci_pcbios_init(void)
478{
479 if ((pci_probe & PCI_PROBE_BIOS)
480 && ((raw_pci_ops = pci_find_bios()))) {
481 pci_probe |= PCI_BIOS_SORT;
482 pci_bios_present = 1;
483 }
484 return 0;
485}
486
487arch_initcall(pci_pcbios_init);