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

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