root/kernel/bios32.c

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

DEFINITIONS

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

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

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