diff options
Diffstat (limited to 'netboot/pci.c')
-rw-r--r-- | netboot/pci.c | 501 |
1 files changed, 0 insertions, 501 deletions
diff --git a/netboot/pci.c b/netboot/pci.c deleted file mode 100644 index 471c856..0000000 --- a/netboot/pci.c +++ /dev/null @@ -1,501 +0,0 @@ -/* -** Support for NE2000 PCI clones added David Monro June 1997 -** Generalised to other NICs by Ken Yap July 1997 -** -** Most of this is taken from: -** -** /usr/src/linux/drivers/pci/pci.c -** /usr/src/linux/include/linux/pci.h -** /usr/src/linux/arch/i386/bios32.c -** /usr/src/linux/include/linux/bios32.h -** /usr/src/linux/drivers/net/ne.c -*/ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - */ - -#include "etherboot.h" -#include "pci.h" - -/*#define DEBUG 1*/ -#define DEBUG 0 - -#ifdef CONFIG_PCI_DIRECT -#define PCIBIOS_SUCCESSFUL 0x00 - -/* - * Functions for accessing PCI configuration space with type 1 accesses - */ - -#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) - -int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, - unsigned int where, unsigned char *value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - *value = inb(0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_word (unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned short *value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - *value = inw(0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn, - unsigned int where, unsigned int *value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - *value = inl(0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, - unsigned int where, unsigned char value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - outb(value, 0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, - unsigned int where, unsigned short value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - outw(value, 0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value) -{ - outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - outl(value, 0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -#undef CONFIG_CMD - -#else /* CONFIG_PCI_DIRECT not defined */ - -static struct { - unsigned long address; - unsigned short segment; -} bios32_indirect = { 0, KERN_CODE_SEG }; - -static long pcibios_entry; -static struct { - unsigned long address; - unsigned short segment; -} pci_indirect = { 0, KERN_CODE_SEG }; - -static unsigned long bios32_service(unsigned long service) -{ - unsigned char return_code; /* %al */ - unsigned long address; /* %ebx */ - unsigned long length; /* %ecx */ - unsigned long entry; /* %edx */ - unsigned long flags; - - save_flags(flags); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%edi)" -#else - "lcall *(%%edi)" -#endif - : "=a" (return_code), - "=b" (address), - "=c" (length), - "=d" (entry) - : "0" (service), - "1" (0), - "D" (&bios32_indirect)); - restore_flags(flags); - - switch (return_code) { - case 0: - return address + entry; - case 0x80: /* Not present */ - printf("bios32_service(%d) : not present\n", service); - return 0; - default: /* Shouldn't happen */ - printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n", - service, return_code); - return 0; - } -} - -int pcibios_read_config_byte(unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned char *value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_BYTE), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -int pcibios_read_config_word(unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned short *value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_WORD), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -int pcibios_read_config_dword(unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned int *value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_DWORD), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -int pcibios_write_config_byte (unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned char value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); cli(); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_BYTE), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -int pcibios_write_config_word (unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned short value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); cli(); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_WORD), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -int pcibios_write_config_dword (unsigned int bus, - unsigned int device_fn, unsigned int where, unsigned int value) -{ - unsigned long ret; - unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - - save_flags(flags); cli(); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%esi)\n\t" -#else - "lcall *(%%esi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_DWORD), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - restore_flags(flags); - return (int) (ret & 0xff00) >> 8; -} - -static void check_pcibios(void) -{ - unsigned long signature; - unsigned char present_status; - unsigned char major_revision; - unsigned char minor_revision; - unsigned long flags; - int pack; - - if ((pcibios_entry = bios32_service(PCI_SERVICE))) { - pci_indirect.address = pcibios_entry; - - save_flags(flags); - __asm__( -#ifdef ABSOLUTE_WITHOUT_ASTERISK - "lcall (%%edi)\n\t" -#else - "lcall *(%%edi)\n\t" -#endif - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:\tshl $8, %%eax\n\t" - "movw %%bx, %%ax" - : "=d" (signature), - "=a" (pack) - : "1" (PCIBIOS_PCI_BIOS_PRESENT), - "D" (&pci_indirect) - : "bx", "cx"); - restore_flags(flags); - - present_status = (pack >> 16) & 0xff; - major_revision = (pack >> 8) & 0xff; - minor_revision = pack & 0xff; - if (present_status || (signature != PCI_SIGNATURE)) { - printf("ERROR: BIOS32 says PCI BIOS, but no PCI " - "BIOS????\n"); - pcibios_entry = 0; - } -#if DEBUG - if (pcibios_entry) { - printf ("pcibios_init : PCI BIOS revision %hhX.%hhX" - " entry at %#X\n", major_revision, - minor_revision, pcibios_entry); - } -#endif - } -} - -static void pcibios_init(void) -{ - union bios32 *check; - unsigned char sum; - int i, length; - unsigned long bios32_entry = 0; - - /* - * Follow the standard procedure for locating the BIOS32 Service - * directory by scanning the permissible address range from - * 0xe0000 through 0xfffff for a valid BIOS32 structure. - * - */ - - for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) { - if (check->fields.signature != BIOS32_SIGNATURE) - continue; - length = check->fields.length * 16; - if (!length) - continue; - sum = 0; - for (i = 0; i < length ; ++i) - sum += check->chars[i]; - if (sum != 0) - continue; - if (check->fields.revision != 0) { - printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n", - check->fields.revision, check); - continue; - } -#if DEBUG - printf("pcibios_init : BIOS32 Service Directory " - "structure at %#X\n", check); -#endif - if (!bios32_entry) { - if (check->fields.entry >= 0x100000) { - printf("pcibios_init: entry in high " - "memory, giving up\n"); - return; - } else { - bios32_entry = check->fields.entry; -#if DEBUG - printf("pcibios_init : BIOS32 Service Directory" - " entry at %#X\n", bios32_entry); -#endif - bios32_indirect.address = bios32_entry; - } - } - } - if (bios32_entry) - check_pcibios(); -} -#endif /* CONFIG_PCI_DIRECT not defined*/ - -static void scan_bus(struct pci_device *pcidev) -{ - unsigned int devfn, l, bus, buses; - unsigned char hdr_type = 0; - unsigned short vendor, device; - unsigned int membase, ioaddr, romaddr; - int i, reg; - unsigned int pci_ioaddr = 0; - - /* Scan all PCI buses, until we find our card. - * We could be smart only scan the required busses but that - * is error prone, and tricky. - * By scanning all possible pci busses in order we should find - * our card eventually. - */ - buses=256; - for (bus = 0; bus < buses; ++bus) { - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC (devfn) == 0) - pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); - else if (!(hdr_type & 0x80)) /* not a multi-function device */ - continue; - pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l); - /* some broken boards return 0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; - continue; - } - vendor = l & 0xffff; - device = (l >> 16) & 0xffff; - -#if DEBUG - printf("bus %hhX, function %hhX, vendor %hX, device %hX\n", - bus, devfn, vendor, device); -#endif - for (i = 0; pcidev[i].vendor != 0; i++) { - if (vendor != pcidev[i].vendor - || device != pcidev[i].dev_id) - continue; - pcidev[i].devfn = devfn; - pcidev[i].bus = bus; - for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { - pcibios_read_config_dword(bus, devfn, reg, &ioaddr); - - if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0) - continue; - /* Strip the I/O address out of the returned value */ - ioaddr &= PCI_BASE_ADDRESS_IO_MASK; - /* Get the memory base address */ - pcibios_read_config_dword(bus, devfn, - PCI_BASE_ADDRESS_1, &membase); - /* Get the ROM base address */ - pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); - romaddr >>= 10; - printf("Found %s at %#hx, ROM address %#hx\n", - pcidev[i].name, ioaddr, romaddr); - /* Take the first one or the one that matches in boot ROM address */ - if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) { - pcidev[i].membase = membase; - pcidev[i].ioaddr = ioaddr; - return; - } - } - } - } - } -} - -void eth_pci_init(struct pci_device *pcidev) -{ -#ifndef CONFIG_PCI_DIRECT - pcibios_init(); - if (!pcibios_entry) { - printf("pci_init: no BIOS32 detected\n"); - return; - } -#endif - scan_bus(pcidev); - /* return values are in pcidev structures */ -} - -/* - * Set device to be a busmaster in case BIOS neglected to do so. - * Also adjust PCI latency timer to a reasonable value, 32. - */ -void adjust_pci_device(struct pci_device *p) -{ - unsigned short new_command, pci_command; - unsigned char pci_latency; - - pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n", - pci_command, new_command, p->bus, p->devfn); - pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command); - } - pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency); - pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32); - } -} |