root/arch/i386/kernel/bios32.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bios32_service
  2. check_pcibios
  3. pcibios_present
  4. pcibios_find_class
  5. pcibios_find_device
  6. pcibios_read_config_byte
  7. pcibios_read_config_word
  8. pcibios_read_config_dword
  9. pcibios_write_config_byte
  10. pcibios_write_config_word
  11. pcibios_write_config_dword
  12. pcibios_strerror
  13. pcibios_fixup
  14. pcibios_init

   1 /*
   2  * bios32.c - BIOS32, PCI BIOS functions.
   3  *
   4  * Sponsored by
   5  *      iX Multiuser Multitasking Magazine
   6  *      Hannover, Germany
   7  *      hm@ix.de
   8  *
   9  * Copyright 1993, 1994 Drew Eckhardt
  10  *      Visionary Computing
  11  *      (Unix and Linux consulting and custom programming)
  12  *      Drew@Colorado.EDU
  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 <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
  35  *
  36  * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
  37  *     Potter, potter@cao-vlsi.ibp.fr
  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, cvarner@cs.ucr.edu
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 drew@colorado.edu\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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 drew@Colorado.EDU\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 (pcibios_entry) {
 196                         printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
 197                                 major_revision, minor_revision, pcibios_entry);
 198                 }
 199         }
 200         return memory_start;
 201 }
 202 
 203 int pcibios_present(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 204 {
 205         return pcibios_entry ? 1 : 0;
 206 }
 207 
 208 int pcibios_find_class (unsigned int class_code, unsigned short index,
     /* [previous][next][first][last][top][bottom][index][help] */
 209         unsigned char *bus, unsigned char *device_fn)
 210 {
 211         unsigned long bx;
 212         unsigned long ret;
 213 
 214         __asm__ ("lcall (%%edi)\n\t"
 215                 "jc 1f\n\t"
 216                 "xor %%ah, %%ah\n"
 217                 "1:"
 218                 : "=b" (bx),
 219                   "=a" (ret)
 220                 : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
 221                   "c" (class_code),
 222                   "S" ((int) index),
 223                   "D" (&pci_indirect));
 224         *bus = (bx >> 8) & 0xff;
 225         *device_fn = bx & 0xff;
 226         return (int) (ret & 0xff00) >> 8;
 227 }
 228 
 229 
 230 int pcibios_find_device (unsigned short vendor, unsigned short device_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 231         unsigned short index, unsigned char *bus, unsigned char *device_fn)
 232 {
 233         unsigned short bx;
 234         unsigned short ret;
 235 
 236         __asm__("lcall (%%edi)\n\t"
 237                 "jc 1f\n\t"
 238                 "xor %%ah, %%ah\n"
 239                 "1:"
 240                 : "=b" (bx),
 241                   "=a" (ret)
 242                 : "1" (PCIBIOS_FIND_PCI_DEVICE),
 243                   "c" (device_id),
 244                   "d" (vendor),
 245                   "S" ((int) index),
 246                   "D" (&pci_indirect));
 247         *bus = (bx >> 8) & 0xff;
 248         *device_fn = bx & 0xff;
 249         return (int) (ret & 0xff00) >> 8;
 250 }
 251 
 252 int pcibios_read_config_byte(unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 253         unsigned char device_fn, unsigned char where, unsigned char *value)
 254 {
 255         unsigned long ret;
 256         unsigned long bx = (bus << 8) | device_fn;
 257 
 258         __asm__("lcall (%%esi)\n\t"
 259                 "jc 1f\n\t"
 260                 "xor %%ah, %%ah\n"
 261                 "1:"
 262                 : "=c" (*value),
 263                   "=a" (ret)
 264                 : "1" (PCIBIOS_READ_CONFIG_BYTE),
 265                   "b" (bx),
 266                   "D" ((long) where),
 267                   "S" (&pci_indirect));
 268         return (int) (ret & 0xff00) >> 8;
 269 }
 270 
 271 int pcibios_read_config_word (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 272         unsigned char device_fn, unsigned char where, unsigned short *value)
 273 {
 274         unsigned long ret;
 275         unsigned long bx = (bus << 8) | device_fn;
 276 
 277         __asm__("lcall (%%esi)\n\t"
 278                 "jc 1f\n\t"
 279                 "xor %%ah, %%ah\n"
 280                 "1:"
 281                 : "=c" (*value),
 282                   "=a" (ret)
 283                 : "1" (PCIBIOS_READ_CONFIG_WORD),
 284                   "b" (bx),
 285                   "D" ((long) where),
 286                   "S" (&pci_indirect));
 287         return (int) (ret & 0xff00) >> 8;
 288 }
 289 
 290 int pcibios_read_config_dword (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 291         unsigned char device_fn, unsigned char where, unsigned int *value)
 292 {
 293         unsigned long ret;
 294         unsigned long bx = (bus << 8) | device_fn;
 295 
 296         __asm__("lcall (%%esi)\n\t"
 297                 "jc 1f\n\t"
 298                 "xor %%ah, %%ah\n"
 299                 "1:"
 300                 : "=c" (*value),
 301                   "=a" (ret)
 302                 : "1" (PCIBIOS_READ_CONFIG_DWORD),
 303                   "b" (bx),
 304                   "D" ((long) where),
 305                   "S" (&pci_indirect));
 306         return (int) (ret & 0xff00) >> 8;
 307 }
 308 
 309 int pcibios_write_config_byte (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 310         unsigned char device_fn, unsigned char where, unsigned char value)
 311 {
 312         unsigned long ret;
 313         unsigned long bx = (bus << 8) | device_fn;
 314 
 315         __asm__("lcall (%%esi)\n\t"
 316                 "jc 1f\n\t"
 317                 "xor %%ah, %%ah\n"
 318                 "1:"
 319                 : "=a" (ret)
 320                 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
 321                   "c" (value),
 322                   "b" (bx),
 323                   "D" ((long) where),
 324                   "S" (&pci_indirect));
 325         return (int) (ret & 0xff00) >> 8;
 326 }
 327 
 328 int pcibios_write_config_word (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 329         unsigned char device_fn, unsigned char where, unsigned short value)
 330 {
 331         unsigned long ret;
 332         unsigned long bx = (bus << 8) | device_fn;
 333 
 334         __asm__("lcall (%%esi)\n\t"
 335                 "jc 1f\n\t"
 336                 "xor %%ah, %%ah\n"
 337                 "1:"
 338                 : "=a" (ret)
 339                 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
 340                   "c" (value),
 341                   "b" (bx),
 342                   "D" ((long) where),
 343                   "S" (&pci_indirect));
 344         return (int) (ret & 0xff00) >> 8;
 345 }
 346 
 347 int pcibios_write_config_dword (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 348         unsigned char device_fn, unsigned char where, unsigned int value)
 349 {
 350         unsigned long ret;
 351         unsigned long bx = (bus << 8) | device_fn;
 352 
 353         __asm__("lcall (%%esi)\n\t"
 354                 "jc 1f\n\t"
 355                 "xor %%ah, %%ah\n"
 356                 "1:"
 357                 : "=a" (ret)
 358                 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
 359                   "c" (value),
 360                   "b" (bx),
 361                   "D" ((long) where),
 362                   "S" (&pci_indirect));
 363         return (int) (ret & 0xff00) >> 8;
 364 }
 365 
 366 const char *pcibios_strerror (int error)
     /* [previous][next][first][last][top][bottom][index][help] */
 367 {
 368         static char buf[80];
 369 
 370         switch (error) {
 371                 case PCIBIOS_SUCCESSFUL:
 372                         return "SUCCESSFUL";
 373 
 374                 case PCIBIOS_FUNC_NOT_SUPPORTED:
 375                         return "FUNC_NOT_SUPPORTED";
 376 
 377                 case PCIBIOS_BAD_VENDOR_ID:
 378                         return "SUCCESSFUL";
 379 
 380                 case PCIBIOS_DEVICE_NOT_FOUND:
 381                         return "DEVICE_NOT_FOUND";
 382 
 383                 case PCIBIOS_BAD_REGISTER_NUMBER:
 384                         return "BAD_REGISTER_NUMBER";
 385 
 386                 case PCIBIOS_SET_FAILED:          
 387                         return "SET_FAILED";
 388 
 389                 case PCIBIOS_BUFFER_TOO_SMALL:    
 390                         return "BUFFER_TOO_SMALL";
 391 
 392                 default:
 393                         sprintf (buf, "UNKNOWN RETURN 0x%x", error);
 394                         return buf;
 395         }
 396 }
 397 
 398 
 399 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401 return mem_start;
 402 }
 403 
 404 
 405 #endif
 406 
 407 unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409         union bios32 *check;
 410         unsigned char sum;
 411         int i, length;
 412 
 413         /*
 414          * Follow the standard procedure for locating the BIOS32 Service
 415          * directory by scanning the permissible address range from
 416          * 0xe0000 through 0xfffff for a valid BIOS32 structure.
 417          *
 418          */
 419 
 420         for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
 421                 if (check->fields.signature != BIOS32_SIGNATURE)
 422                         continue;
 423                 length = check->fields.length * 16;
 424                 if (!length)
 425                         continue;
 426                 sum = 0;
 427                 for (i = 0; i < length ; ++i)
 428                         sum += check->chars[i];
 429                 if (sum != 0)
 430                         continue;
 431                 if (check->fields.revision != 0) {
 432                         printk("pcibios_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
 433                                 check->fields.revision, check);
 434                         continue;
 435                 }
 436                 printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
 437                 if (!bios32_entry) {
 438                         if (check->fields.entry >= 0x100000) {
 439                                 printk("pcibios_init: entry in high memory, unable to access\n");
 440                         } else {
 441                                 bios32_indirect.address = bios32_entry = check->fields.entry;
 442                                 printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
 443                         }
 444                 } else {
 445                         printk ("pcibios_init : multiple entries, mail drew@colorado.edu\n");
 446                         /*
 447                          * Jeremy Fitzhardinge reports at least one PCI BIOS
 448                          * with two different service directories, and as both
 449                          * worked for him, we'll just mention the fact, and
 450                          * not actually disallow it..
 451                          */
 452                 }
 453         }
 454 #ifdef CONFIG_PCI
 455         if (bios32_entry) {
 456                 memory_start = check_pcibios (memory_start, memory_end);
 457         }
 458 #endif
 459         return memory_start;
 460 }

/* [previous][next][first][last][top][bottom][index][help] */