root/kernel/bios32.c

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

DEFINITIONS

This source file includes following definitions.
  1. bios32_service
  2. pcibios_init
  3. pcibios_present
  4. pcibios_find_class_code
  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. NCR53c810_test
  13. pcibios_strerror
  14. bios32_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 
  37 #include <linux/config.h>
  38 #include <linux/kernel.h>
  39 #include <linux/bios32.h>
  40 #include <linux/pci.h>
  41 
  42 #include <asm/segment.h>
  43 
  44 #define PCIBIOS_PCI_FUNCTION_ID         0xb1XX
  45 #define PCIBIOS_PCI_BIOS_PRESENT        0xb101
  46 #define PCIBIOS_FIND_PCI_DEVICE         0xb102
  47 #define PCIBIOS_FIND_PCI_CLASS_CODE     0xb103
  48 #define PCIBIOS_GENERATE_SPECIAL_CYCLE  0xb106
  49 #define PCIBIOS_READ_CONFIG_BYTE        0xb108
  50 #define PCIBIOS_READ_CONFIG_WORD        0xb109
  51 #define PCIBIOS_READ_CONFIG_DWORD       0xb10a
  52 #define PCIBIOS_WRITE_CONFIG_BYTE       0xb10b
  53 #define PCIBIOS_WRITE_CONFIG_WORD       0xb10c
  54 #define PCIBIOS_WRITE_CONFIG_DWORD      0xb10d
  55 
  56 /* BIOS32 signature: "_32_" */
  57 #define BIOS32_SIGNATURE        (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
  58 
  59 /* PCI signature: "PCI " */
  60 #define PCI_SIGNATURE           (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
  61 
  62 /* PCI service signature: "$PCI" */
  63 #define PCI_SERVICE             (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
  64 
  65 /*
  66  * This is the standard structure used to identify the entry point
  67  * to the BIOS32 Service Directory, as documented in
  68  *      Standard BIOS 32-bit Service Directory Proposal
  69  *      Revision 0.4 May 24, 1993
  70  *      Phoenix Technologies Ltd.
  71  *      Norwood, MA
  72  * and the PCI BIOS specification.
  73  */
  74 
  75 union bios32 {
  76         struct {
  77                 unsigned long signature;        /* _32_ */
  78                 unsigned long entry;            /* 32 bit physical address */
  79                 unsigned char revision;         /* Revision level, 0 */
  80                 unsigned char length;           /* Length in paragraphs should be 01 */
  81                 unsigned char checksum;         /* All bytes must add up to zero */
  82                 unsigned char reserved[5];      /* Must be zero */
  83         } fields;
  84         char chars[16];
  85 };
  86 
  87 /*
  88  * Physical address of the service directory.  I don't know if we're
  89  * allowed to have more than one of these or not, so just in case
  90  * we'll make bios32_init() take a memory start parameter and store
  91  * the array there.
  92  */
  93 
  94 static unsigned long bios32_entry = 0;
  95 static struct {
  96         unsigned long address;
  97         unsigned short segment;
  98 } bios32_indirect = { 0, KERNEL_CS };
  99 
 100 #ifdef CONFIG_PCI
 101 /*
 102  * Returns the entry point for the given service, NULL on error
 103  */
 104 
 105 static unsigned long bios32_service(unsigned long service)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107         unsigned char return_code;      /* %al */
 108         unsigned long address;          /* %ebx */
 109         unsigned long length;           /* %ecx */
 110         unsigned long entry;            /* %edx */
 111 
 112         __asm__("lcall (%%edi)"
 113                 : "=a" (return_code),
 114                   "=b" (address),
 115                   "=c" (length),
 116                   "=d" (entry)
 117                 : "0" (service),
 118                   "1" (0),
 119                   "D" (&bios32_indirect));
 120 
 121         switch (return_code) {
 122                 case 0:
 123                         return address + entry;
 124                 case 0x80:      /* Not present */
 125                         printk("bios32_service(%ld) : not present\n", service);
 126                         return 0;
 127                 default: /* Shouldn't happen */
 128                         printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n",
 129                                 service, return_code);
 130                         return 0;
 131         }
 132 }
 133 
 134 static long pcibios_entry = 0;
 135 static struct {
 136         unsigned long address;
 137         unsigned short segment;
 138 } pci_indirect = { 0, KERNEL_CS };
 139 
 140 void NCR53c810_test(void);
 141 
 142 static unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         unsigned long signature;
 145         unsigned char present_status;
 146         unsigned char major_revision;
 147         unsigned char minor_revision;
 148         int pack;
 149 
 150         if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
 151                 pci_indirect.address = pcibios_entry;
 152 
 153                 __asm__("lcall (%%edi)\n\t"
 154                         "jc 1f\n\t"
 155                         "xor %%ah, %%ah\n"
 156                         "1:\tshl $8, %%eax\n\t"
 157                         "movw %%bx, %%ax"
 158                         : "=d" (signature),
 159                           "=a" (pack)
 160                         : "1" (PCIBIOS_PCI_BIOS_PRESENT),
 161                           "D" (&pci_indirect)
 162                         : "bx", "cx");
 163 
 164                 present_status = (pack >> 16) & 0xff;
 165                 major_revision = (pack >> 8) & 0xff;
 166                 minor_revision = pack & 0xff;
 167                 if (present_status || (signature != PCI_SIGNATURE)) {
 168                         printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
 169                                 "       but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
 170                                 "       and signature of 0x%08lx (%c%c%c%c).  mail drew@Colorado.EDU\n",
 171                                 (signature == PCI_SIGNATURE) ?  "WARNING" : "ERROR",
 172                                 present_status, signature,
 173                                 (char) (signature >>  0), (char) (signature >>  8),
 174                                 (char) (signature >> 16), (char) (signature >> 24));
 175 
 176                         if (signature != PCI_SIGNATURE)
 177                                 pcibios_entry = 0;
 178                 }
 179                 if (pcibios_entry) {
 180                         printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
 181                                 major_revision, minor_revision, pcibios_entry);
 182                 }
 183         }
 184 
 185 #if 0
 186         NCR53c810_test();
 187 #endif
 188         return memory_start;
 189 }
 190 
 191 int pcibios_present(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193         return pcibios_entry ? 1 : 0;
 194 }
 195 
 196 int pcibios_find_class_code (unsigned long class_code, unsigned short index,
     /* [previous][next][first][last][top][bottom][index][help] */
 197         unsigned char *bus, unsigned char *device_fn)
 198 {
 199         unsigned long bx;
 200         unsigned long ret;
 201 
 202         __asm__ ("lcall (%%edi)\n\t"
 203                 "jc 1f\n\t"
 204                 "xor %%ah, %%ah\n"
 205                 "1:"
 206                 : "=b" (bx),
 207                   "=a" (ret)
 208                 : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
 209                   "c" (class_code),
 210                   "S" ((int) index),
 211                   "D" (&pci_indirect));
 212         *bus = (bx >> 8) & 0xff;
 213         *device_fn = bx & 0xff;
 214         return (int) (ret & 0xff00) >> 8;
 215 }
 216 
 217 
 218 int pcibios_find_device (unsigned short vendor, unsigned short device_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 219         unsigned short index, unsigned char *bus, unsigned char *device_fn)
 220 {
 221         unsigned short bx;
 222         unsigned short ret;
 223 
 224         __asm__("lcall (%%edi)\n\t"
 225                 "jc 1f\n\t"
 226                 "xor %%ah, %%ah\n"
 227                 "1:"
 228                 : "=b" (bx),
 229                   "=a" (ret)
 230                 : "1" (PCIBIOS_FIND_PCI_DEVICE),
 231                   "c" (device_id),
 232                   "d" (vendor),
 233                   "S" ((int) index),
 234                   "D" (&pci_indirect));
 235         *bus = (bx >> 8) & 0xff;
 236         *device_fn = bx & 0xff;
 237         return (int) (ret & 0xff00) >> 8;
 238 }
 239 
 240 int pcibios_read_config_byte(unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 241         unsigned char device_fn, unsigned char where, unsigned char *value)
 242 {
 243         unsigned long ret;
 244         unsigned long bx = (bus << 8) | device_fn;
 245 
 246         __asm__("lcall (%%esi)\n\t"
 247                 "jc 1f\n\t"
 248                 "xor %%ah, %%ah\n"
 249                 "1:"
 250                 : "=c" (*value),
 251                   "=a" (ret)
 252                 : "1" (PCIBIOS_READ_CONFIG_BYTE),
 253                   "b" (bx),
 254                   "D" ((long) where),
 255                   "S" (&pci_indirect));
 256         return (int) (ret & 0xff00) >> 8;
 257 }
 258 
 259 int pcibios_read_config_word (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 260         unsigned char device_fn, unsigned char where, unsigned short *value)
 261 {
 262         unsigned long ret;
 263         unsigned long bx = (bus << 8) | device_fn;
 264 
 265         __asm__("lcall (%%esi)\n\t"
 266                 "jc 1f\n\t"
 267                 "xor %%ah, %%ah\n"
 268                 "1:"
 269                 : "=c" (*value),
 270                   "=a" (ret)
 271                 : "1" (PCIBIOS_READ_CONFIG_WORD),
 272                   "b" (bx),
 273                   "D" ((long) where),
 274                   "S" (&pci_indirect));
 275         return (int) (ret & 0xff00) >> 8;
 276 }
 277 
 278 int pcibios_read_config_dword (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 279         unsigned char device_fn, unsigned char where, unsigned long *value)
 280 {
 281         unsigned long ret;
 282         unsigned long bx = (bus << 8) | device_fn;
 283 
 284         __asm__("lcall (%%esi)\n\t"
 285                 "jc 1f\n\t"
 286                 "xor %%ah, %%ah\n"
 287                 "1:"
 288                 : "=c" (*value),
 289                   "=a" (ret)
 290                 : "1" (PCIBIOS_READ_CONFIG_DWORD),
 291                   "b" (bx),
 292                   "D" ((long) where),
 293                   "S" (&pci_indirect));
 294         return (int) (ret & 0xff00) >> 8;
 295 }
 296 
 297 int pcibios_write_config_byte (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 298         unsigned char device_fn, unsigned char where, unsigned char value)
 299 {
 300         unsigned long ret;
 301         unsigned long bx = (bus << 8) | device_fn;
 302 
 303         __asm__("lcall (%%esi)\n\t"
 304                 "jc 1f\n\t"
 305                 "xor %%ah, %%ah\n"
 306                 "1:"
 307                 : "=a" (ret)
 308                 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
 309                   "c" (value),
 310                   "b" (bx),
 311                   "D" ((long) where),
 312                   "S" (&pci_indirect));
 313         return (int) (ret & 0xff00) >> 8;
 314 }
 315 
 316 int pcibios_write_config_word (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 317         unsigned char device_fn, unsigned char where, unsigned short value)
 318 {
 319         unsigned long ret;
 320         unsigned long bx = (bus << 8) | device_fn;
 321 
 322         __asm__("lcall (%%esi)\n\t"
 323                 "jc 1f\n\t"
 324                 "xor %%ah, %%ah\n"
 325                 "1:"
 326                 : "=a" (ret)
 327                 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
 328                   "c" (value),
 329                   "b" (bx),
 330                   "D" ((long) where),
 331                   "S" (&pci_indirect));
 332         return (int) (ret & 0xff00) >> 8;
 333 }
 334 
 335 int pcibios_write_config_dword (unsigned char bus,
     /* [previous][next][first][last][top][bottom][index][help] */
 336         unsigned char device_fn, unsigned char where, unsigned long value)
 337 {
 338         unsigned long ret;
 339         unsigned long bx = (bus << 8) | device_fn;
 340 
 341         __asm__("lcall (%%esi)\n\t"
 342                 "jc 1f\n\t"
 343                 "xor %%ah, %%ah\n"
 344                 "1:"
 345                 : "=a" (ret)
 346                 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
 347                   "c" (value),
 348                   "b" (bx),
 349                   "D" ((long) where),
 350                   "S" (&pci_indirect));
 351         return (int) (ret & 0xff00) >> 8;
 352 }
 353 
 354 void NCR53c810_test(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356         unsigned char bus, device_fn;
 357         unsigned short index;
 358         int ret;
 359         unsigned char row, col;
 360         unsigned long val;
 361 
 362         for (index = 0; index < 4; ++index) {
 363                 ret = pcibios_find_device (
 364                         (unsigned short) PCI_VENDOR_ID_NCR,
 365                         (unsigned short) PCI_DEVICE_ID_NCR_53C810,
 366                         index, &bus, &device_fn);
 367                 if (ret)
 368                         break;
 369                 printk ("ncr53c810 : at PCI bus %d, device %d, function %d.",
 370                         bus, ((device_fn & 0xf8) >> 3), (device_fn & 7));
 371                 for (row = 0; row < 0x3c; row += 0x10) {
 372                         printk ("\n     reg 0x%02x      ", row);
 373                         for (col = 0; col < 0x10; col += 4) {
 374                         if (!(ret = pcibios_read_config_dword (bus, device_fn, row+col, &val)))
 375                                 printk ("0x%08lx          ", val);
 376                         else
 377                                 printk ("error 0x%02x ", ret);
 378                         }
 379                 }
 380                 printk ("\n");
 381         }
 382 }
 383 
 384 char *pcibios_strerror (int error)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386         static char buf[80];
 387 
 388         switch (error) {
 389                 case PCIBIOS_SUCCESSFUL:
 390                         return "SUCCESSFUL";
 391 
 392                 case PCIBIOS_FUNC_NOT_SUPPORTED:
 393                         return "FUNC_NOT_SUPPORTED";
 394 
 395                 case PCIBIOS_BAD_VENDOR_ID:
 396                         return "SUCCESSFUL";
 397 
 398                 case PCIBIOS_DEVICE_NOT_FOUND:
 399                         return "DEVICE_NOT_FOUND";
 400 
 401                 case PCIBIOS_BAD_REGISTER_NUMBER:
 402                         return "BAD_REGISTER_NUMBER";
 403 
 404                 default:
 405                         sprintf (buf, "UNKNOWN RETURN 0x%x", error);
 406                         return buf;
 407         }
 408 }
 409 
 410 #endif
 411 
 412 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 413 {
 414         union bios32 *check;
 415         unsigned char sum;
 416         int i, length;
 417 
 418         /*
 419          * Follow the standard procedure for locating the BIOS32 Service
 420          * directory by scanning the permissible address range from
 421          * 0xe0000 through 0xfffff for a valid BIOS32 structure.
 422          *
 423          * The PCI BIOS doesn't seem to work too well on many machines,
 424          * so we disable this unless it's really needed (NCR SCSI driver)
 425          */
 426 
 427         for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
 428                 if (check->fields.signature != BIOS32_SIGNATURE)
 429                         continue;
 430                 length = check->fields.length * 16;
 431                 if (!length)
 432                         continue;
 433                 sum = 0;
 434                 for (i = 0; i < length ; ++i)
 435                         sum += check->chars[i];
 436                 if (sum != 0)
 437                         continue;
 438                 if (check->fields.revision != 0) {
 439                         printk("bios32_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
 440                                 check->fields.revision, check);
 441                         continue;
 442                 }
 443                 printk ("bios32_init : BIOS32 Service Directory structure at 0x%p\n", check);
 444                 if (!bios32_entry) {
 445                         bios32_indirect.address = bios32_entry = check->fields.entry;
 446                         printk ("bios32_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
 447                 } else {
 448                         printk ("bios32_init : multiple entries, mail drew@colorado.edu\n");
 449                         /*
 450                          * Jeremy Fitzhardinge reports at least one PCI BIOS
 451                          * with two different service directories, and as both
 452                          * worked for him, we'll just mention the fact, and
 453                          * not actually disallow it..
 454                          */
 455 #if 0
 456                         return memory_start;
 457 #endif
 458                 }
 459         }
 460 #ifdef CONFIG_PCI
 461         if (bios32_entry) {
 462                 memory_start = pcibios_init (memory_start, memory_end);
 463         }
 464 #endif
 465         return memory_start;
 466 }

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