1 /* 2 ** Support for NE2000 PCI clones added David Monro June 1997 3 ** Generalised to other NICs by Ken Yap July 1997 4 ** 5 ** Most of this is taken from: 6 ** 7 ** /usr/src/linux/drivers/pci/pci.c 8 ** /usr/src/linux/include/linux/pci.h 9 ** /usr/src/linux/arch/i386/bios32.c 10 ** /usr/src/linux/include/linux/bios32.h 11 ** /usr/src/linux/drivers/net/ne.c 12 */ 13 #define PCBIOS 14 #include "grub.h" 15 #include "pci.h" 16 17 #ifdef CONFIG_PCI_DIRECT 18 #define PCIBIOS_SUCCESSFUL 0x00 19 20 #define DEBUG 0 21 22 /* 23 * Functions for accessing PCI configuration space with type 1 accesses 24 */ 25 26 #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) 27 28 int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, 29 unsigned int where, uint8_t *value) 30 { 31 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 32 *value = inb(0xCFC + (where&3)); 33 return PCIBIOS_SUCCESSFUL; 34 } 35 36 int pcibios_read_config_word (unsigned int bus, 37 unsigned int device_fn, unsigned int where, uint16_t *value) 38 { 39 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 40 *value = inw(0xCFC + (where&2)); 41 return PCIBIOS_SUCCESSFUL; 42 } 43 44 int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn, 45 unsigned int where, uint32_t *value) 46 { 47 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 48 *value = inl(0xCFC); 49 return PCIBIOS_SUCCESSFUL; 50 } 51 52 int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, 53 unsigned int where, uint8_t value) 54 { 55 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 56 outb(value, 0xCFC + (where&3)); 57 return PCIBIOS_SUCCESSFUL; 58 } 59 60 int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, 61 unsigned int where, uint16_t value) 62 { 63 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 64 outw(value, 0xCFC + (where&2)); 65 return PCIBIOS_SUCCESSFUL; 66 } 67 68 int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, uint32_t value) 69 { 70 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); 71 outl(value, 0xCFC); 72 return PCIBIOS_SUCCESSFUL; 73 } 74 75 #undef CONFIG_CMD 76 77 #else /* CONFIG_PCI_DIRECT not defined */ 78 79 #if !defined(PCBIOS) 80 #error "The pcibios can only be used when the PCBIOS support is compiled in" 81 #endif 82 83 84 #define KERN_CODE_SEG 0X8 85 /* Stuff for asm */ 86 #define save_flags(x) \ 87 __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") 88 89 #define cli() __asm__ __volatile__ ("cli": : :"memory") 90 91 #define restore_flags(x) \ 92 __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") 93 94 95 96 static struct { 97 unsigned long address; 98 unsigned short segment; 99 } bios32_indirect = { 0, KERN_CODE_SEG }; 100 101 static long pcibios_entry = 0; 102 static struct { 103 unsigned long address; 104 unsigned short segment; 105 } pci_indirect = { 0, KERN_CODE_SEG }; 106 107 static unsigned long bios32_service(unsigned long service) 108 { 109 unsigned char return_code; /* %al */ 110 unsigned long address; /* %ebx */ 111 unsigned long length; /* %ecx */ 112 unsigned long entry; /* %edx */ 113 unsigned long flags; 114 115 save_flags(flags); 116 __asm__( 117 #ifdef ABSOLUTE_WITHOUT_ASTERISK 118 "lcall (%%edi)" 119 #else 120 "lcall *(%%edi)" 121 #endif 122 : "=a" (return_code), 123 "=b" (address), 124 "=c" (length), 125 "=d" (entry) 126 : "0" (service), 127 "1" (0), 128 "D" (&bios32_indirect)); 129 restore_flags(flags); 130 131 switch (return_code) { 132 case 0: 133 return address + entry; 134 case 0x80: /* Not present */ 135 printf("bios32_service(%d) : not present\n", service); 136 return 0; 137 default: /* Shouldn't happen */ 138 printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n", 139 service, return_code); 140 return 0; 141 } 142 } 143 144 int pcibios_read_config_byte(unsigned int bus, 145 unsigned int device_fn, unsigned int where, uint8_t *value) 146 { 147 unsigned long ret; 148 unsigned long bx = (bus << 8) | device_fn; 149 unsigned long flags; 150 151 save_flags(flags); 152 __asm__( 153 #ifdef ABSOLUTE_WITHOUT_ASTERISK 154 "lcall (%%esi)\n\t" 155 #else 156 "lcall *(%%esi)\n\t" 157 #endif 158 "jc 1f\n\t" 159 "xor %%ah, %%ah\n" 160 "1:" 161 : "=c" (*value), 162 "=a" (ret) 163 : "1" (PCIBIOS_READ_CONFIG_BYTE), 164 "b" (bx), 165 "D" ((long) where), 166 "S" (&pci_indirect)); 167 restore_flags(flags); 168 return (int) (ret & 0xff00) >> 8; 169 } 170 171 int pcibios_read_config_word(unsigned int bus, 172 unsigned int device_fn, unsigned int where, uint16_t *value) 173 { 174 unsigned long ret; 175 unsigned long bx = (bus << 8) | device_fn; 176 unsigned long flags; 177 178 save_flags(flags); 179 __asm__( 180 #ifdef ABSOLUTE_WITHOUT_ASTERISK 181 "lcall (%%esi)\n\t" 182 #else 183 "lcall *(%%esi)\n\t" 184 #endif 185 "jc 1f\n\t" 186 "xor %%ah, %%ah\n" 187 "1:" 188 : "=c" (*value), 189 "=a" (ret) 190 : "1" (PCIBIOS_READ_CONFIG_WORD), 191 "b" (bx), 192 "D" ((long) where), 193 "S" (&pci_indirect)); 194 restore_flags(flags); 195 return (int) (ret & 0xff00) >> 8; 196 } 197 198 int pcibios_read_config_dword(unsigned int bus, 199 unsigned int device_fn, unsigned int where, uint32_t *value) 200 { 201 unsigned long ret; 202 unsigned long bx = (bus << 8) | device_fn; 203 unsigned long flags; 204 205 save_flags(flags); 206 __asm__( 207 #ifdef ABSOLUTE_WITHOUT_ASTERISK 208 "lcall (%%esi)\n\t" 209 #else 210 "lcall *(%%esi)\n\t" 211 #endif 212 "jc 1f\n\t" 213 "xor %%ah, %%ah\n" 214 "1:" 215 : "=c" (*value), 216 "=a" (ret) 217 : "1" (PCIBIOS_READ_CONFIG_DWORD), 218 "b" (bx), 219 "D" ((long) where), 220 "S" (&pci_indirect)); 221 restore_flags(flags); 222 return (int) (ret & 0xff00) >> 8; 223 } 224 225 int pcibios_write_config_byte (unsigned int bus, 226 unsigned int device_fn, unsigned int where, uint8_t value) 227 { 228 unsigned long ret; 229 unsigned long bx = (bus << 8) | device_fn; 230 unsigned long flags; 231 232 save_flags(flags); cli(); 233 __asm__( 234 #ifdef ABSOLUTE_WITHOUT_ASTERISK 235 "lcall (%%esi)\n\t" 236 #else 237 "lcall *(%%esi)\n\t" 238 #endif 239 "jc 1f\n\t" 240 "xor %%ah, %%ah\n" 241 "1:" 242 : "=a" (ret) 243 : "0" (PCIBIOS_WRITE_CONFIG_BYTE), 244 "c" (value), 245 "b" (bx), 246 "D" ((long) where), 247 "S" (&pci_indirect)); 248 restore_flags(flags); 249 return (int) (ret & 0xff00) >> 8; 250 } 251 252 int pcibios_write_config_word (unsigned int bus, 253 unsigned int device_fn, unsigned int where, uint16_t value) 254 { 255 unsigned long ret; 256 unsigned long bx = (bus << 8) | device_fn; 257 unsigned long flags; 258 259 save_flags(flags); cli(); 260 __asm__( 261 #ifdef ABSOLUTE_WITHOUT_ASTERISK 262 "lcall (%%esi)\n\t" 263 #else 264 "lcall *(%%esi)\n\t" 265 #endif 266 "jc 1f\n\t" 267 "xor %%ah, %%ah\n" 268 "1:" 269 : "=a" (ret) 270 : "0" (PCIBIOS_WRITE_CONFIG_WORD), 271 "c" (value), 272 "b" (bx), 273 "D" ((long) where), 274 "S" (&pci_indirect)); 275 restore_flags(flags); 276 return (int) (ret & 0xff00) >> 8; 277 } 278 279 int pcibios_write_config_dword (unsigned int bus, 280 unsigned int device_fn, unsigned int where, uint32_t value) 281 { 282 unsigned long ret; 283 unsigned long bx = (bus << 8) | device_fn; 284 unsigned long flags; 285 286 save_flags(flags); cli(); 287 __asm__( 288 #ifdef ABSOLUTE_WITHOUT_ASTERISK 289 "lcall (%%esi)\n\t" 290 #else 291 "lcall *(%%esi)\n\t" 292 #endif 293 "jc 1f\n\t" 294 "xor %%ah, %%ah\n" 295 "1:" 296 : "=a" (ret) 297 : "0" (PCIBIOS_WRITE_CONFIG_DWORD), 298 "c" (value), 299 "b" (bx), 300 "D" ((long) where), 301 "S" (&pci_indirect)); 302 restore_flags(flags); 303 return (int) (ret & 0xff00) >> 8; 304 } 305 306 static void check_pcibios(void) 307 { 308 unsigned long signature; 309 unsigned char present_status; 310 unsigned char major_revision; 311 unsigned char minor_revision; 312 unsigned long flags; 313 int pack; 314 315 if ((pcibios_entry = bios32_service(PCI_SERVICE))) { 316 pci_indirect.address = pcibios_entry; 317 318 save_flags(flags); 319 __asm__( 320 #ifdef ABSOLUTE_WITHOUT_ASTERISK 321 "lcall (%%edi)\n\t" 322 #else 323 "lcall *(%%edi)\n\t" 324 #endif 325 "jc 1f\n\t" 326 "xor %%ah, %%ah\n" 327 "1:\tshl $8, %%eax\n\t" 328 "movw %%bx, %%ax" 329 : "=d" (signature), 330 "=a" (pack) 331 : "1" (PCIBIOS_PCI_BIOS_PRESENT), 332 "D" (&pci_indirect) 333 : "bx", "cx"); 334 restore_flags(flags); 335 336 present_status = (pack >> 16) & 0xff; 337 major_revision = (pack >> 8) & 0xff; 338 minor_revision = pack & 0xff; 339 if (present_status || (signature != PCI_SIGNATURE)) { 340 printf("ERROR: BIOS32 says PCI BIOS, but no PCI " 341 "BIOS????\n"); 342 pcibios_entry = 0; 343 } 344 #if DEBUG 345 if (pcibios_entry) { 346 printf ("pcibios_init : PCI BIOS revision %hhX.%hhX" 347 " entry at %#X\n", major_revision, 348 minor_revision, pcibios_entry); 349 } 350 #endif 351 } 352 } 353 354 static void pcibios_init(void) 355 { 356 union bios32 *check; 357 unsigned char sum; 358 int i, length; 359 unsigned long bios32_entry = 0; 360 361 EnterFunction("pcibios_init"); 362 /* 363 * Follow the standard procedure for locating the BIOS32 Service 364 * directory by scanning the permissible address range from 365 * 0xe0000 through 0xfffff for a valid BIOS32 structure. 366 * 367 */ 368 369 for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) { 370 if (check->fields.signature != BIOS32_SIGNATURE) 371 continue; 372 length = check->fields.length * 16; 373 if (!length) 374 continue; 375 sum = 0; 376 for (i = 0; i < length ; ++i) 377 sum += check->chars[i]; 378 if (sum != 0) 379 continue; 380 if (check->fields.revision != 0) { 381 printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n", 382 check->fields.revision, check); 383 continue; 384 } 385 #if DEBUG 386 printf("pcibios_init : BIOS32 Service Directory " 387 "structure at %#X\n", check); 388 #endif 389 if (!bios32_entry) { 390 if (check->fields.entry >= 0x100000) { 391 printf("pcibios_init: entry in high " 392 "memory, giving up\n"); 393 return; 394 } else { 395 bios32_entry = check->fields.entry; 396 #if DEBUG 397 printf("pcibios_init : BIOS32 Service Directory" 398 " entry at %#X\n", bios32_entry); 399 #endif 400 bios32_indirect.address = bios32_entry; 401 } 402 } 403 } 404 if (bios32_entry) 405 check_pcibios(); 406 LeaveFunction("pcibios_init"); 407 } 408 409 #endif /* CONFIG_PCI_DIRECT not defined*/ 410 411 unsigned long pcibios_bus_base(unsigned int bus __unused) 412 { 413 /* architecturally this must be 0 */ 414 return 0; 415 } 416 417 void find_pci(int type, struct pci_device *dev) 418 { 419 EnterFunction("find_pci"); 420 #ifndef CONFIG_PCI_DIRECT 421 if (!pcibios_entry) { 422 pcibios_init(); 423 } 424 if (!pcibios_entry) { 425 printf("pci_init: no BIOS32 detected\n"); 426 return; 427 } 428 #endif 429 LeaveFunction("find_pci"); 430 return scan_pci_bus(type, dev); 431 } 432