aboutsummaryrefslogtreecommitdiff
path: root/netboot/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'netboot/pci.c')
-rw-r--r--netboot/pci.c501
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);
- }
-}