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

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