|
|
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.