|
|
1.1 root 1: /*
2: * bios32.c - BIOS32, PCI BIOS functions.
3: *
4: * Sponsored by
5: * iX Multiuser Multitasking Magazine
6: * Hannover, Germany
7: * [email protected]
8: *
9: * Copyright 1993, 1994 Drew Eckhardt
10: * Visionary Computing
11: * (Unix and Linux consulting and custom programming)
12: * [email protected]
13: * +1 (303) 786-7975
14: *
15: * For more information, please consult
16: *
17: * PCI BIOS Specification Revision
18: * PCI Local Bus Specification
19: * PCI System Design Guide
20: *
21: * PCI Special Interest Group
22: * M/S HF3-15A
23: * 5200 N.E. Elam Young Parkway
24: * Hillsboro, Oregon 97124-6497
25: * +1 (503) 696-2000
26: * +1 (800) 433-5177
27: *
28: * Manuals are $25 each or $50 for all three, plus $7 shipping
29: * within the United States, $35 abroad.
30: *
31: *
32: * CHANGELOG :
33: * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
34: * Revision 2.0 present on <[email protected]>'s ASUS mainboard.
35: *
36: * Jan 5, 1995 : Modified to probe PCI hardware at boot time by Frederic
37: * Potter, [email protected]
38: *
39: * Jan 10, 1995 : Modified to store the information about configured pci
40: * devices into a list, which can be accessed via /proc/pci by
41: * Curtis Varner, [email protected]
42: *
43: * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
44: * Alpha version. Intel & UMC chipset support only.
45: *
46: * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
47: * moved to drivers/pci/pci.c.
48: *
49: *
50: */
51:
52: #include <linux/config.h>
53: #include <linux/types.h>
54: #include <linux/kernel.h>
55: #include <linux/bios32.h>
56: #include <linux/pci.h>
57:
58: #include <asm/segment.h>
59:
60: #define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
61: #define PCIBIOS_PCI_BIOS_PRESENT 0xb101
62: #define PCIBIOS_FIND_PCI_DEVICE 0xb102
63: #define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
64: #define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
65: #define PCIBIOS_READ_CONFIG_BYTE 0xb108
66: #define PCIBIOS_READ_CONFIG_WORD 0xb109
67: #define PCIBIOS_READ_CONFIG_DWORD 0xb10a
68: #define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
69: #define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
70: #define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
71:
72:
73: /* BIOS32 signature: "_32_" */
74: #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
75:
76: /* PCI signature: "PCI " */
77: #define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
78:
79: /* PCI service signature: "$PCI" */
80: #define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
81:
82: /*
83: * This is the standard structure used to identify the entry point
84: * to the BIOS32 Service Directory, as documented in
85: * Standard BIOS 32-bit Service Directory Proposal
86: * Revision 0.4 May 24, 1993
87: * Phoenix Technologies Ltd.
88: * Norwood, MA
89: * and the PCI BIOS specification.
90: */
91:
92: union bios32 {
93: struct {
94: unsigned long signature; /* _32_ */
95: unsigned long entry; /* 32 bit physical address */
96: unsigned char revision; /* Revision level, 0 */
97: unsigned char length; /* Length in paragraphs should be 01 */
98: unsigned char checksum; /* All bytes must add up to zero */
99: unsigned char reserved[5]; /* Must be zero */
100: } fields;
101: char chars[16];
102: };
103:
104: /*
105: * Physical address of the service directory. I don't know if we're
106: * allowed to have more than one of these or not, so just in case
107: * we'll make pcibios_present() take a memory start parameter and store
108: * the array there.
109: */
110:
111: static unsigned long bios32_entry = 0;
112: static struct {
113: unsigned long address;
114: unsigned short segment;
115: } bios32_indirect = { 0, KERNEL_CS };
116:
117: #ifdef CONFIG_PCI
118: /*
119: * Returns the entry point for the given service, NULL on error
120: */
121:
122: static unsigned long bios32_service(unsigned long service)
123: {
124: unsigned char return_code; /* %al */
125: unsigned long address; /* %ebx */
126: unsigned long length; /* %ecx */
127: unsigned long entry; /* %edx */
128:
129: __asm__("lcall (%%edi)"
130: : "=a" (return_code),
131: "=b" (address),
132: "=c" (length),
133: "=d" (entry)
134: : "0" (service),
135: "1" (0),
136: "D" (&bios32_indirect));
137:
138: switch (return_code) {
139: case 0:
140: return address + entry;
141: case 0x80: /* Not present */
142: printk("bios32_service(%ld) : not present\n", service);
143: return 0;
144: default: /* Shouldn't happen */
145: printk("bios32_service(%ld) : returned 0x%x, mail [email protected]\n",
146: service, return_code);
147: return 0;
148: }
149: }
150:
151: static long pcibios_entry = 0;
152: static struct {
153: unsigned long address;
154: unsigned short segment;
155: } pci_indirect = { 0, KERNEL_CS };
156:
157:
158: extern unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end)
159: {
160: unsigned long signature;
161: unsigned char present_status;
162: unsigned char major_revision;
163: unsigned char minor_revision;
164: int pack;
165:
166: if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
167: pci_indirect.address = pcibios_entry;
168:
169: __asm__("lcall (%%edi)\n\t"
170: "jc 1f\n\t"
171: "xor %%ah, %%ah\n"
172: "1:\tshl $8, %%eax\n\t"
173: "movw %%bx, %%ax"
174: : "=d" (signature),
175: "=a" (pack)
176: : "1" (PCIBIOS_PCI_BIOS_PRESENT),
177: "D" (&pci_indirect)
178: : "bx", "cx");
179:
180: present_status = (pack >> 16) & 0xff;
181: major_revision = (pack >> 8) & 0xff;
182: minor_revision = pack & 0xff;
183: if (present_status || (signature != PCI_SIGNATURE)) {
184: printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
185: " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
186: " and signature of 0x%08lx (%c%c%c%c). mail [email protected]\n",
187: (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
188: present_status, signature,
189: (char) (signature >> 0), (char) (signature >> 8),
190: (char) (signature >> 16), (char) (signature >> 24));
191:
192: if (signature != PCI_SIGNATURE)
193: pcibios_entry = 0;
194: }
195: #if 0
196: if (pcibios_entry) {
197: printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
198: major_revision, minor_revision, pcibios_entry);
199: }
200: #endif
201: }
202: return memory_start;
203: }
204:
205: int pcibios_present(void)
206: {
207: return pcibios_entry ? 1 : 0;
208: }
209:
210: int pcibios_find_class (unsigned int class_code, unsigned short index,
211: unsigned char *bus, unsigned char *device_fn)
212: {
213: unsigned long bx;
214: unsigned long ret;
215:
216: __asm__ ("lcall (%%edi)\n\t"
217: "jc 1f\n\t"
218: "xor %%ah, %%ah\n"
219: "1:"
220: : "=b" (bx),
221: "=a" (ret)
222: : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
223: "c" (class_code),
224: "S" ((int) index),
225: "D" (&pci_indirect));
226: *bus = (bx >> 8) & 0xff;
227: *device_fn = bx & 0xff;
228: return (int) (ret & 0xff00) >> 8;
229: }
230:
231:
232: int pcibios_find_device (unsigned short vendor, unsigned short device_id,
233: unsigned short index, unsigned char *bus, unsigned char *device_fn)
234: {
235: unsigned short bx;
236: unsigned short ret;
237:
238: __asm__("lcall (%%edi)\n\t"
239: "jc 1f\n\t"
240: "xor %%ah, %%ah\n"
241: "1:"
242: : "=b" (bx),
243: "=a" (ret)
244: : "1" (PCIBIOS_FIND_PCI_DEVICE),
245: "c" (device_id),
246: "d" (vendor),
247: "S" ((int) index),
248: "D" (&pci_indirect));
249: *bus = (bx >> 8) & 0xff;
250: *device_fn = bx & 0xff;
251: return (int) (ret & 0xff00) >> 8;
252: }
253:
254: int pcibios_read_config_byte(unsigned char bus,
255: unsigned char device_fn, unsigned char where, unsigned char *value)
256: {
257: unsigned long ret;
258: unsigned long bx = (bus << 8) | device_fn;
259:
260: __asm__("lcall (%%esi)\n\t"
261: "jc 1f\n\t"
262: "xor %%ah, %%ah\n"
263: "1:"
264: : "=c" (*value),
265: "=a" (ret)
266: : "1" (PCIBIOS_READ_CONFIG_BYTE),
267: "b" (bx),
268: "D" ((long) where),
269: "S" (&pci_indirect));
270: return (int) (ret & 0xff00) >> 8;
271: }
272:
273: int pcibios_read_config_word (unsigned char bus,
274: unsigned char device_fn, unsigned char where, unsigned short *value)
275: {
276: unsigned long ret;
277: unsigned long bx = (bus << 8) | device_fn;
278:
279: __asm__("lcall (%%esi)\n\t"
280: "jc 1f\n\t"
281: "xor %%ah, %%ah\n"
282: "1:"
283: : "=c" (*value),
284: "=a" (ret)
285: : "1" (PCIBIOS_READ_CONFIG_WORD),
286: "b" (bx),
287: "D" ((long) where),
288: "S" (&pci_indirect));
289: return (int) (ret & 0xff00) >> 8;
290: }
291:
292: int pcibios_read_config_dword (unsigned char bus,
293: unsigned char device_fn, unsigned char where, unsigned int *value)
294: {
295: unsigned long ret;
296: unsigned long bx = (bus << 8) | device_fn;
297:
298: __asm__("lcall (%%esi)\n\t"
299: "jc 1f\n\t"
300: "xor %%ah, %%ah\n"
301: "1:"
302: : "=c" (*value),
303: "=a" (ret)
304: : "1" (PCIBIOS_READ_CONFIG_DWORD),
305: "b" (bx),
306: "D" ((long) where),
307: "S" (&pci_indirect));
308: return (int) (ret & 0xff00) >> 8;
309: }
310:
311: int pcibios_write_config_byte (unsigned char bus,
312: unsigned char device_fn, unsigned char where, unsigned char value)
313: {
314: unsigned long ret;
315: unsigned long bx = (bus << 8) | device_fn;
316:
317: __asm__("lcall (%%esi)\n\t"
318: "jc 1f\n\t"
319: "xor %%ah, %%ah\n"
320: "1:"
321: : "=a" (ret)
322: : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
323: "c" (value),
324: "b" (bx),
325: "D" ((long) where),
326: "S" (&pci_indirect));
327: return (int) (ret & 0xff00) >> 8;
328: }
329:
330: int pcibios_write_config_word (unsigned char bus,
331: unsigned char device_fn, unsigned char where, unsigned short value)
332: {
333: unsigned long ret;
334: unsigned long bx = (bus << 8) | device_fn;
335:
336: __asm__("lcall (%%esi)\n\t"
337: "jc 1f\n\t"
338: "xor %%ah, %%ah\n"
339: "1:"
340: : "=a" (ret)
341: : "0" (PCIBIOS_WRITE_CONFIG_WORD),
342: "c" (value),
343: "b" (bx),
344: "D" ((long) where),
345: "S" (&pci_indirect));
346: return (int) (ret & 0xff00) >> 8;
347: }
348:
349: int pcibios_write_config_dword (unsigned char bus,
350: unsigned char device_fn, unsigned char where, unsigned int value)
351: {
352: unsigned long ret;
353: unsigned long bx = (bus << 8) | device_fn;
354:
355: __asm__("lcall (%%esi)\n\t"
356: "jc 1f\n\t"
357: "xor %%ah, %%ah\n"
358: "1:"
359: : "=a" (ret)
360: : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
361: "c" (value),
362: "b" (bx),
363: "D" ((long) where),
364: "S" (&pci_indirect));
365: return (int) (ret & 0xff00) >> 8;
366: }
367:
368: const char *pcibios_strerror (int error)
369: {
370: static char buf[80];
371:
372: switch (error) {
373: case PCIBIOS_SUCCESSFUL:
374: return "SUCCESSFUL";
375:
376: case PCIBIOS_FUNC_NOT_SUPPORTED:
377: return "FUNC_NOT_SUPPORTED";
378:
379: case PCIBIOS_BAD_VENDOR_ID:
380: return "SUCCESSFUL";
381:
382: case PCIBIOS_DEVICE_NOT_FOUND:
383: return "DEVICE_NOT_FOUND";
384:
385: case PCIBIOS_BAD_REGISTER_NUMBER:
386: return "BAD_REGISTER_NUMBER";
387:
388: case PCIBIOS_SET_FAILED:
389: return "SET_FAILED";
390:
391: case PCIBIOS_BUFFER_TOO_SMALL:
392: return "BUFFER_TOO_SMALL";
393:
394: default:
395: sprintf (buf, "UNKNOWN RETURN 0x%x", error);
396: return buf;
397: }
398: }
399:
400:
401: unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
402: {
403: return mem_start;
404: }
405:
406:
407: #endif
408:
409: unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
410: {
411: union bios32 *check;
412: unsigned char sum;
413: int i, length;
414:
415: /*
416: * Follow the standard procedure for locating the BIOS32 Service
417: * directory by scanning the permissible address range from
418: * 0xe0000 through 0xfffff for a valid BIOS32 structure.
419: *
420: */
421:
422: for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
423: if (check->fields.signature != BIOS32_SIGNATURE)
424: continue;
425: length = check->fields.length * 16;
426: if (!length)
427: continue;
428: sum = 0;
429: for (i = 0; i < length ; ++i)
430: sum += check->chars[i];
431: if (sum != 0)
432: continue;
433: if (check->fields.revision != 0) {
434: printk("pcibios_init : unsupported revision %d at 0x%p, mail [email protected]\n",
435: check->fields.revision, check);
436: continue;
437: }
438: #if 0
439: printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
440: #endif
441: if (!bios32_entry) {
442: if (check->fields.entry >= 0x100000) {
443: printk("pcibios_init: entry in high memory, unable to access\n");
444: } else {
445: bios32_indirect.address = bios32_entry = check->fields.entry;
446: #if 0
447: printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
448: #endif
449: }
450: } else {
451: printk ("pcibios_init : multiple entries, mail [email protected]\n");
452: /*
453: * Jeremy Fitzhardinge reports at least one PCI BIOS
454: * with two different service directories, and as both
455: * worked for him, we'll just mention the fact, and
456: * not actually disallow it..
457: */
458: }
459: }
460: #ifdef CONFIG_PCI
461: if (bios32_entry) {
462: memory_start = check_pcibios (memory_start, memory_end);
463: }
464: #endif
465: return memory_start;
466: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.