Home | History | Annotate | Download | only in netboot
      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 
     14 /*
     15  * This program is free software; you can redistribute it and/or
     16  * modify it under the terms of the GNU General Public License as
     17  * published by the Free Software Foundation; either version 2, or (at
     18  * your option) any later version.
     19  */
     20 
     21 #include "etherboot.h"
     22 #include "pci.h"
     23 
     24 /*#define	DEBUG	1*/
     25 #define DEBUG	0
     26 
     27 #ifdef	CONFIG_PCI_DIRECT
     28 #define  PCIBIOS_SUCCESSFUL                0x00
     29 
     30 /*
     31  * Functions for accessing PCI configuration space with type 1 accesses
     32  */
     33 
     34 #define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
     35 
     36 int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
     37 			       unsigned int where, unsigned char *value)
     38 {
     39     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     40     *value = inb(0xCFC + (where&3));
     41     return PCIBIOS_SUCCESSFUL;
     42 }
     43 
     44 int pcibios_read_config_word (unsigned int bus,
     45     unsigned int device_fn, unsigned int where, unsigned short *value)
     46 {
     47     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     48     *value = inw(0xCFC + (where&2));
     49     return PCIBIOS_SUCCESSFUL;
     50 }
     51 
     52 int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
     53 				 unsigned int where, unsigned int *value)
     54 {
     55     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     56     *value = inl(0xCFC);
     57     return PCIBIOS_SUCCESSFUL;
     58 }
     59 
     60 int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
     61 				 unsigned int where, unsigned char value)
     62 {
     63     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     64     outb(value, 0xCFC + (where&3));
     65     return PCIBIOS_SUCCESSFUL;
     66 }
     67 
     68 int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
     69 				 unsigned int where, unsigned short value)
     70 {
     71     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     72     outw(value, 0xCFC + (where&2));
     73     return PCIBIOS_SUCCESSFUL;
     74 }
     75 
     76 int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value)
     77 {
     78     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     79     outl(value, 0xCFC);
     80     return PCIBIOS_SUCCESSFUL;
     81 }
     82 
     83 #undef CONFIG_CMD
     84 
     85 #else	 /* CONFIG_PCI_DIRECT  not defined */
     86 
     87 static struct {
     88 	unsigned long address;
     89 	unsigned short segment;
     90 } bios32_indirect = { 0, KERN_CODE_SEG };
     91 
     92 static long pcibios_entry;
     93 static struct {
     94 	unsigned long address;
     95 	unsigned short segment;
     96 } pci_indirect = { 0, KERN_CODE_SEG };
     97 
     98 static unsigned long bios32_service(unsigned long service)
     99 {
    100 	unsigned char return_code;	/* %al */
    101 	unsigned long address;		/* %ebx */
    102 	unsigned long length;		/* %ecx */
    103 	unsigned long entry;		/* %edx */
    104 	unsigned long flags;
    105 
    106 	save_flags(flags);
    107 	__asm__(
    108 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    109 		"lcall (%%edi)"
    110 #else
    111 		"lcall *(%%edi)"
    112 #endif
    113 		: "=a" (return_code),
    114 		  "=b" (address),
    115 		  "=c" (length),
    116 		  "=d" (entry)
    117 		: "0" (service),
    118 		  "1" (0),
    119 		  "D" (&bios32_indirect));
    120 	restore_flags(flags);
    121 
    122 	switch (return_code) {
    123 		case 0:
    124 			return address + entry;
    125 		case 0x80:	/* Not present */
    126 			printf("bios32_service(%d) : not present\n", service);
    127 			return 0;
    128 		default: /* Shouldn't happen */
    129 			printf("bios32_service(%d) : returned %#X, mail drew (at) colorado.edu\n",
    130 				service, return_code);
    131 			return 0;
    132 	}
    133 }
    134 
    135 int pcibios_read_config_byte(unsigned int bus,
    136         unsigned int device_fn, unsigned int where, unsigned char *value)
    137 {
    138         unsigned long ret;
    139         unsigned long bx = (bus << 8) | device_fn;
    140         unsigned long flags;
    141 
    142         save_flags(flags);
    143         __asm__(
    144 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    145 		"lcall (%%esi)\n\t"
    146 #else
    147 		"lcall *(%%esi)\n\t"
    148 #endif
    149                 "jc 1f\n\t"
    150                 "xor %%ah, %%ah\n"
    151                 "1:"
    152                 : "=c" (*value),
    153                   "=a" (ret)
    154                 : "1" (PCIBIOS_READ_CONFIG_BYTE),
    155                   "b" (bx),
    156                   "D" ((long) where),
    157                   "S" (&pci_indirect));
    158         restore_flags(flags);
    159         return (int) (ret & 0xff00) >> 8;
    160 }
    161 
    162 int pcibios_read_config_word(unsigned int bus,
    163         unsigned int device_fn, unsigned int where, unsigned short *value)
    164 {
    165         unsigned long ret;
    166         unsigned long bx = (bus << 8) | device_fn;
    167         unsigned long flags;
    168 
    169         save_flags(flags);
    170         __asm__(
    171 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    172 		"lcall (%%esi)\n\t"
    173 #else
    174 		"lcall *(%%esi)\n\t"
    175 #endif
    176                 "jc 1f\n\t"
    177                 "xor %%ah, %%ah\n"
    178                 "1:"
    179                 : "=c" (*value),
    180                   "=a" (ret)
    181                 : "1" (PCIBIOS_READ_CONFIG_WORD),
    182                   "b" (bx),
    183                   "D" ((long) where),
    184                   "S" (&pci_indirect));
    185         restore_flags(flags);
    186         return (int) (ret & 0xff00) >> 8;
    187 }
    188 
    189 int pcibios_read_config_dword(unsigned int bus,
    190         unsigned int device_fn, unsigned int where, unsigned int *value)
    191 {
    192         unsigned long ret;
    193         unsigned long bx = (bus << 8) | device_fn;
    194         unsigned long flags;
    195 
    196         save_flags(flags);
    197         __asm__(
    198 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    199 		"lcall (%%esi)\n\t"
    200 #else
    201 		"lcall *(%%esi)\n\t"
    202 #endif
    203                 "jc 1f\n\t"
    204                 "xor %%ah, %%ah\n"
    205                 "1:"
    206                 : "=c" (*value),
    207                   "=a" (ret)
    208                 : "1" (PCIBIOS_READ_CONFIG_DWORD),
    209                   "b" (bx),
    210                   "D" ((long) where),
    211                   "S" (&pci_indirect));
    212         restore_flags(flags);
    213         return (int) (ret & 0xff00) >> 8;
    214 }
    215 
    216 int pcibios_write_config_byte (unsigned int bus,
    217 	unsigned int device_fn, unsigned int where, unsigned char value)
    218 {
    219 	unsigned long ret;
    220 	unsigned long bx = (bus << 8) | device_fn;
    221 	unsigned long flags;
    222 
    223 	save_flags(flags); cli();
    224 	__asm__(
    225 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    226 		"lcall (%%esi)\n\t"
    227 #else
    228 		"lcall *(%%esi)\n\t"
    229 #endif
    230 		"jc 1f\n\t"
    231 		"xor %%ah, %%ah\n"
    232 		"1:"
    233 		: "=a" (ret)
    234 		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
    235 		  "c" (value),
    236 		  "b" (bx),
    237 		  "D" ((long) where),
    238 		  "S" (&pci_indirect));
    239 	restore_flags(flags);
    240 	return (int) (ret & 0xff00) >> 8;
    241 }
    242 
    243 int pcibios_write_config_word (unsigned int bus,
    244 	unsigned int device_fn, unsigned int where, unsigned short value)
    245 {
    246 	unsigned long ret;
    247 	unsigned long bx = (bus << 8) | device_fn;
    248 	unsigned long flags;
    249 
    250 	save_flags(flags); cli();
    251 	__asm__(
    252 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    253 		"lcall (%%esi)\n\t"
    254 #else
    255 		"lcall *(%%esi)\n\t"
    256 #endif
    257 		"jc 1f\n\t"
    258 		"xor %%ah, %%ah\n"
    259 		"1:"
    260 		: "=a" (ret)
    261 		: "0" (PCIBIOS_WRITE_CONFIG_WORD),
    262 		  "c" (value),
    263 		  "b" (bx),
    264 		  "D" ((long) where),
    265 		  "S" (&pci_indirect));
    266 	restore_flags(flags);
    267 	return (int) (ret & 0xff00) >> 8;
    268 }
    269 
    270 int pcibios_write_config_dword (unsigned int bus,
    271 	unsigned int device_fn, unsigned int where, unsigned int value)
    272 {
    273 	unsigned long ret;
    274 	unsigned long bx = (bus << 8) | device_fn;
    275 	unsigned long flags;
    276 
    277 	save_flags(flags); cli();
    278 	__asm__(
    279 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    280 		"lcall (%%esi)\n\t"
    281 #else
    282 		"lcall *(%%esi)\n\t"
    283 #endif
    284 		"jc 1f\n\t"
    285 		"xor %%ah, %%ah\n"
    286 		"1:"
    287 		: "=a" (ret)
    288 		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
    289 		  "c" (value),
    290 		  "b" (bx),
    291 		  "D" ((long) where),
    292 		  "S" (&pci_indirect));
    293 	restore_flags(flags);
    294 	return (int) (ret & 0xff00) >> 8;
    295 }
    296 
    297 static void check_pcibios(void)
    298 {
    299 	unsigned long signature;
    300 	unsigned char present_status;
    301 	unsigned char major_revision;
    302 	unsigned char minor_revision;
    303 	unsigned long flags;
    304 	int pack;
    305 
    306 	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
    307 		pci_indirect.address = pcibios_entry;
    308 
    309 		save_flags(flags);
    310 		__asm__(
    311 #ifdef ABSOLUTE_WITHOUT_ASTERISK
    312 			"lcall (%%edi)\n\t"
    313 #else
    314 			"lcall *(%%edi)\n\t"
    315 #endif
    316 			"jc 1f\n\t"
    317 			"xor %%ah, %%ah\n"
    318 			"1:\tshl $8, %%eax\n\t"
    319 			"movw %%bx, %%ax"
    320 			: "=d" (signature),
    321 			  "=a" (pack)
    322 			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
    323 			  "D" (&pci_indirect)
    324 			: "bx", "cx");
    325 		restore_flags(flags);
    326 
    327 		present_status = (pack >> 16) & 0xff;
    328 		major_revision = (pack >> 8) & 0xff;
    329 		minor_revision = pack & 0xff;
    330 		if (present_status || (signature != PCI_SIGNATURE)) {
    331 			printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
    332 				"BIOS????\n");
    333 			pcibios_entry = 0;
    334 		}
    335 #if	DEBUG
    336 		if (pcibios_entry) {
    337 			printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
    338 				" entry at %#X\n", major_revision,
    339 				minor_revision, pcibios_entry);
    340 		}
    341 #endif
    342 	}
    343 }
    344 
    345 static void pcibios_init(void)
    346 {
    347 	union bios32 *check;
    348 	unsigned char sum;
    349 	int i, length;
    350 	unsigned long bios32_entry = 0;
    351 
    352 	/*
    353 	 * Follow the standard procedure for locating the BIOS32 Service
    354 	 * directory by scanning the permissible address range from
    355 	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
    356 	 *
    357 	 */
    358 
    359 	for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
    360 		if (check->fields.signature != BIOS32_SIGNATURE)
    361 			continue;
    362 		length = check->fields.length * 16;
    363 		if (!length)
    364 			continue;
    365 		sum = 0;
    366 		for (i = 0; i < length ; ++i)
    367 			sum += check->chars[i];
    368 		if (sum != 0)
    369 			continue;
    370 		if (check->fields.revision != 0) {
    371 			printf("pcibios_init : unsupported revision %d at %#X, mail drew (at) colorado.edu\n",
    372 				check->fields.revision, check);
    373 			continue;
    374 		}
    375 #if	DEBUG
    376 		printf("pcibios_init : BIOS32 Service Directory "
    377 			"structure at %#X\n", check);
    378 #endif
    379 		if (!bios32_entry) {
    380 			if (check->fields.entry >= 0x100000) {
    381 				printf("pcibios_init: entry in high "
    382 					"memory, giving up\n");
    383 				return;
    384 			} else {
    385 				bios32_entry = check->fields.entry;
    386 #if	DEBUG
    387 				printf("pcibios_init : BIOS32 Service Directory"
    388 					" entry at %#X\n", bios32_entry);
    389 #endif
    390 				bios32_indirect.address = bios32_entry;
    391 			}
    392 		}
    393 	}
    394 	if (bios32_entry)
    395 		check_pcibios();
    396 }
    397 #endif	/* CONFIG_PCI_DIRECT not defined*/
    398 
    399 static void scan_bus(struct pci_device *pcidev)
    400 {
    401 	unsigned int devfn, l, bus, buses;
    402 	unsigned char hdr_type = 0;
    403 	unsigned short vendor, device;
    404 	unsigned int membase, ioaddr, romaddr;
    405 	int i, reg;
    406 	unsigned int pci_ioaddr = 0;
    407 
    408 	/* Scan all PCI buses, until we find our card.
    409 	 * We could be smart only scan the required busses but that
    410 	 * is error prone, and tricky.
    411 	 * By scanning all possible pci busses in order we should find
    412 	 * our card eventually.
    413 	 */
    414 	buses=256;
    415 	for (bus = 0; bus < buses; ++bus) {
    416 		for (devfn = 0; devfn < 0xff; ++devfn) {
    417 			if (PCI_FUNC (devfn) == 0)
    418 				pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
    419 			else if (!(hdr_type & 0x80))	/* not a multi-function device */
    420 				continue;
    421 			pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l);
    422 			/* some broken boards return 0 if a slot is empty: */
    423 			if (l == 0xffffffff || l == 0x00000000) {
    424 				hdr_type = 0;
    425 				continue;
    426 			}
    427 			vendor = l & 0xffff;
    428 			device = (l >> 16) & 0xffff;
    429 
    430 #if	DEBUG
    431 			printf("bus %hhX, function %hhX, vendor %hX, device %hX\n",
    432 				bus, devfn, vendor, device);
    433 #endif
    434 			for (i = 0; pcidev[i].vendor != 0; i++) {
    435 				if (vendor != pcidev[i].vendor
    436 				    || device != pcidev[i].dev_id)
    437 					continue;
    438 				pcidev[i].devfn = devfn;
    439 				pcidev[i].bus = bus;
    440 				for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
    441 					pcibios_read_config_dword(bus, devfn, reg, &ioaddr);
    442 
    443 					if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)
    444 						continue;
    445 					/* Strip the I/O address out of the returned value */
    446 					ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
    447 					/* Get the memory base address */
    448 					pcibios_read_config_dword(bus, devfn,
    449 						PCI_BASE_ADDRESS_1, &membase);
    450 					/* Get the ROM base address */
    451 					pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
    452 					romaddr >>= 10;
    453 					printf("Found %s at %#hx, ROM address %#hx\n",
    454 						pcidev[i].name, ioaddr, romaddr);
    455 					/* Take the first one or the one that matches in boot ROM address */
    456 					if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) {
    457 						pcidev[i].membase = membase;
    458 						pcidev[i].ioaddr = ioaddr;
    459 						return;
    460 					}
    461 				}
    462 			}
    463 		}
    464 	}
    465 }
    466 
    467 void eth_pci_init(struct pci_device *pcidev)
    468 {
    469 #ifndef	CONFIG_PCI_DIRECT
    470 	pcibios_init();
    471 	if (!pcibios_entry) {
    472 		printf("pci_init: no BIOS32 detected\n");
    473 		return;
    474 	}
    475 #endif
    476 	scan_bus(pcidev);
    477 	/* return values are in pcidev structures */
    478 }
    479 
    480 /*
    481  *	Set device to be a busmaster in case BIOS neglected to do so.
    482  *	Also adjust PCI latency timer to a reasonable value, 32.
    483  */
    484 void adjust_pci_device(struct pci_device *p)
    485 {
    486 	unsigned short	new_command, pci_command;
    487 	unsigned char	pci_latency;
    488 
    489 	pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command);
    490 	new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
    491 	if (pci_command != new_command) {
    492 		printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",
    493 			   pci_command, new_command, p->bus, p->devfn);
    494 		pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command);
    495 	}
    496 	pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency);
    497 	if (pci_latency < 32) {
    498 		printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
    499 		pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32);
    500 	}
    501 }
    502