/* * 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 "grub.h" #include "pci.h" unsigned long virt_offset = 0; unsigned long virt_to_phys(volatile const void *virt_addr) { return ((unsigned long)virt_addr) + virt_offset; } void *phys_to_virt(unsigned long phys_addr) { return (void *)(phys_addr - virt_offset); } #ifdef INCLUDE_3C595 extern struct pci_driver t595_driver; #endif /* INCLUDE_3C595 */ #ifdef INCLUDE_3C90X extern struct pci_driver a3c90x_driver; #endif /* INCLUDE_3C90X */ #ifdef INCLUDE_DAVICOM extern struct pci_driver davicom_driver; #endif /* INCLUDE_DAVICOM */ #ifdef INCLUDE_E1000 extern struct pci_driver e1000_driver; #endif /* INCLUDE_E1000 */ #ifdef INCLUDE_EEPRO100 extern struct pci_driver eepro100_driver; #endif /* INCLUDE_EEPRO100 */ #ifdef INCLUDE_EPIC100 extern struct pci_driver epic100_driver; #endif /* INCLUDE_EPIC100 */ #ifdef INCLUDE_FORCEDETH extern struct pci_driver forcedeth_driver; #endif /* INCLUDE_FORCEDETH */ #ifdef INCLUDE_NATSEMI extern struct pci_driver natsemi_driver; #endif /* INCLUDE_NATSEMI */ #ifdef INCLUDE_NS83820 extern struct pci_driver ns83820_driver; #endif /* INCLUDE_NS83820 */ #ifdef INCLUDE_NS8390 extern struct pci_driver nepci_driver; #endif /* INCLUDE_NS8390 */ #ifdef INCLUDE_PCNET32 extern struct pci_driver pcnet32_driver; #endif /* INCLUDE_PCNET32 */ #ifdef INCLUDE_PNIC extern struct pci_driver pnic_driver; #endif /* INCLUDE_PNIC */ #ifdef INCLUDE_RTL8139 extern struct pci_driver rtl8139_driver; #endif /* INCLUDE_RTL8139 */ #ifdef INCLUDE_SIS900 extern struct pci_driver sis900_driver; extern struct pci_driver sis_bridge_driver; #endif /* INCLUDE_SIS900 */ #ifdef INCLUDE_SUNDANCE extern struct pci_driver sundance_driver; #endif /* INCLUDE_SUNDANCE */ #ifdef INCLUDE_TG3 extern struct pci_driver tg3_driver; #endif /* INCLUDE_TG3 */ #ifdef INCLUDE_TLAN extern struct pci_driver tlan_driver; #endif /* INCLUDE_TLAN */ #ifdef INCLUDE_TULIP extern struct pci_driver tulip_driver; #endif /* INCLUDE_TULIP */ #ifdef INCLUDE_UNDI extern struct pci_driver undi_driver; #endif /* INCLUDE_UNDI */ #ifdef INCLUDE_VIA_RHINE extern struct pci_driver rhine_driver; #endif/* INCLUDE_VIA_RHINE */ #ifdef INCLUDE_W89C840 extern struct pci_driver w89c840_driver; #endif /* INCLUDE_W89C840 */ #ifdef INCLUDE_R8169 extern struct pci_driver r8169_driver; #endif /* INCLUDE_R8169 */ static const struct pci_driver *pci_drivers[] = { #ifdef INCLUDE_3C595 &t595_driver, #endif /* INCLUDE_3C595 */ #ifdef INCLUDE_3C90X &a3c90x_driver, #endif /* INCLUDE_3C90X */ #ifdef INCLUDE_DAVICOM &davicom_driver, #endif /* INCLUDE_DAVICOM */ #ifdef INCLUDE_E1000 &e1000_driver, #endif /* INCLUDE_E1000 */ #ifdef INCLUDE_EEPRO100 &eepro100_driver, #endif /* INCLUDE_EEPRO100 */ #ifdef INCLUDE_EPIC100 &epic100_driver, #endif /* INCLUDE_EPIC100 */ #ifdef INCLUDE_FORCEDETH &forcedeth_driver, #endif /* INCLUDE_FORCEDETH */ #ifdef INCLUDE_NATSEMI &natsemi_driver, #endif /* INCLUDE_NATSEMI */ #ifdef INCLUDE_NS83820 &ns83820_driver, #endif /* INCLUDE_NS83820 */ #ifdef INCLUDE_NS8390 &nepci_driver, #endif /* INCLUDE_NS8390 */ #ifdef INCLUDE_PCNET32 &pcnet32_driver, #endif /* INCLUDE_PCNET32 */ #ifdef INCLUDE_PNIC &pnic_driver, #endif /* INCLUDE_PNIC */ #ifdef INCLUDE_RTL8139 &rtl8139_driver, #endif /* INCLUDE_RTL8139 */ #ifdef INCLUDE_SIS900 &sis900_driver, &sis_bridge_driver, #endif /* INCLUDE_SIS900 */ #ifdef INCLUDE_SUNDANCE &sundance_driver, #endif /* INCLUDE_SUNDANCE */ #ifdef INCLUDE_TG3 & tg3_driver, #endif /* INCLUDE_TG3 */ #ifdef INCLUDE_TLAN &tlan_driver, #endif /* INCLUDE_TLAN */ #ifdef INCLUDE_TULIP & tulip_driver, #endif /* INCLUDE_TULIP */ #ifdef INCLUDE_VIA_RHINE &rhine_driver, #endif/* INCLUDE_VIA_RHINE */ #ifdef INCLUDE_W89C840 &w89c840_driver, #endif /* INCLUDE_W89C840 */ #ifdef INCLUDE_R8169 &r8169_driver, #endif /* INCLUDE_R8169 */ /* We must be the last one */ #ifdef INCLUDE_UNDI &undi_driver, #endif /* INCLUDE_UNDI */ 0 }; static void scan_drivers( int type, uint32_t class, uint16_t vendor, uint16_t device, const struct pci_driver *last_driver, struct pci_device *dev) { const struct pci_driver *skip_driver = last_driver; /* Assume there is only one match of the correct type */ const struct pci_driver *driver; int i, j; for(j = 0; pci_drivers[j] != 0; j++){ driver = pci_drivers[j]; if (driver->type != type) continue; if (skip_driver) { if (skip_driver == driver) skip_driver = 0; continue; } for(i = 0; i < driver->id_count; i++) { if ((vendor == driver->ids[i].vendor) && (device == driver->ids[i].dev_id)) { dev->driver = driver; dev->name = driver->ids[i].name; goto out; } } } if (!class) { goto out; } for(j = 0; pci_drivers[j] != 0; j++){ driver = pci_drivers[j]; if (driver->type != type) continue; if (skip_driver) { if (skip_driver == driver) skip_driver = 0; continue; } if (last_driver == driver) continue; if ((class >> 8) == driver->class) { dev->driver = driver; dev->name = driver->name; goto out; } } out: return; } void scan_pci_bus(int type, struct pci_device *dev) { unsigned int first_bus, first_devfn; const struct pci_driver *first_driver; unsigned int devfn, bus, buses; unsigned char hdr_type = 0; uint32_t class; uint16_t vendor, device; uint32_t l, membase, ioaddr, romaddr; int reg; EnterFunction("scan_pci_bus"); first_bus = 0; first_devfn = 0; first_driver = 0; if (dev->driver) { first_driver = dev->driver; first_bus = dev->bus; first_devfn = dev->devfn; /* Re read the header type on a restart */ pcibios_read_config_byte(first_bus, first_devfn & ~0x7, PCI_HEADER_TYPE, &hdr_type); dev->driver = 0; dev->bus = 0; dev->devfn = 0; } /* Scan all PCI buses, until we find our card. * We could be smart only scan the required buses but that * is error prone, and tricky. * By scanning all possible pci buses in order we should find * our card eventually. */ buses=256; for (bus = first_bus; bus < buses; ++bus) { for (devfn = first_devfn; devfn < 0xff; ++devfn, first_driver = 0) { 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) { continue; } vendor = l & 0xffff; device = (l >> 16) & 0xffff; pcibios_read_config_dword(bus, devfn, PCI_REVISION, &l); class = (l >> 8) & 0xffffff; #if DEBUG { int i; printf("%hhx:%hhx.%hhx [%hX/%hX] ---- ", bus, PCI_SLOT(devfn), PCI_FUNC(devfn), vendor, device); #if DEBUG > 1 for(i = 0; i < 256; i++) { unsigned char byte; if ((i & 0xf) == 0) { printf("%hhx: ", i); } pcibios_read_config_byte(bus, devfn, i, &byte); printf("%hhx ", byte); if ((i & 0xf) == 0xf) { printf("\n"); } } #endif } #endif scan_drivers(type, class, vendor, device, first_driver, dev); if (!dev->driver){ #if DEBUG printf("No driver fit.\n"); #endif continue; } #if DEBUG printf("Get Driver:\n"); #endif dev->devfn = devfn; dev->bus = bus; dev->class = class; dev->vendor = vendor; dev->dev_id = device; /* Get the ROM base address */ pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); romaddr >>= 10; dev->romaddr = romaddr; /* Get the ``membase'' */ pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &membase); dev->membase = membase; /* Get the ``ioaddr'' */ 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; /* Take the first one or the one that matches in boot ROM address */ dev->ioaddr = ioaddr; } #if DEBUG > 2 printf("Found %s ROM address %#hx\n", dev->name, romaddr); #endif LeaveFunction("scan_pci_bus"); return; } first_devfn = 0; } first_bus = 0; LeaveFunction("scan_pci_bus"); } /* * 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) { #if DEBUG > 0 printf( "The PCI BIOS has not enabled this device!\n" "Updating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n", pci_command, new_command, p->bus, p->devfn); #endif 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) { #if DEBUG > 0 printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency); #endif pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32); } } /* * Find the start of a pci resource. */ unsigned long pci_bar_start(struct pci_device *dev, unsigned int index) { uint32_t lo, hi; unsigned long bar; pci_read_config_dword(dev, index, &lo); if (lo & PCI_BASE_ADDRESS_SPACE_IO) { bar = lo & PCI_BASE_ADDRESS_IO_MASK; } else { bar = 0; if ((lo & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { pci_read_config_dword(dev, index + 4, &hi); if (hi) { if (sizeof(unsigned long) > sizeof(uint32_t)) { /* It's REALLY interesting:-) */ bar = (uint64_t)hi << 32; } else { printf("Unhandled 64bit BAR\n"); return -1UL; } } } bar |= lo & PCI_BASE_ADDRESS_MEM_MASK; } return bar + pcibios_bus_base(dev->bus); } /* * Find the size of a pci resource. */ unsigned long pci_bar_size(struct pci_device *dev, unsigned int bar) { uint32_t start, size; /* Save the original bar */ pci_read_config_dword(dev, bar, &start); /* Compute which bits can be set */ pci_write_config_dword(dev, bar, ~0); pci_read_config_dword(dev, bar, &size); /* Restore the original size */ pci_write_config_dword(dev, bar, start); /* Find the significant bits */ if (start & PCI_BASE_ADDRESS_SPACE_IO) { size &= PCI_BASE_ADDRESS_IO_MASK; } else { size &= PCI_BASE_ADDRESS_MEM_MASK; } /* Find the lowest bit set */ size = size & ~(size - 1); return size; } /** * pci_find_capability - query for devices' capabilities * @dev: PCI device to query * @cap: capability code * * Tell if a device supports a given PCI capability. * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not * support it. Possible values for @cap: * * %PCI_CAP_ID_PM Power Management * * %PCI_CAP_ID_AGP Accelerated Graphics Port * * %PCI_CAP_ID_VPD Vital Product Data * * %PCI_CAP_ID_SLOTID Slot Identification * * %PCI_CAP_ID_MSI Message Signalled Interrupts * * %PCI_CAP_ID_CHSWP CompactPCI HotSwap */ int pci_find_capability(struct pci_device *dev, int cap) { uint16_t status; uint8_t pos, id; uint8_t hdr_type; int ttl = 48; pci_read_config_word(dev, PCI_STATUS, &status); if (!(status & PCI_STATUS_CAP_LIST)) return 0; pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type); switch (hdr_type & 0x7F) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: default: pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos); break; case PCI_HEADER_TYPE_CARDBUS: pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos); break; } while (ttl-- && pos >= 0x40) { pos &= ~3; pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id); #if DEBUG > 0 printf("Capability: %d\n", id); #endif if (id == 0xff) break; if (id == cap) return pos; pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos); } return 0; }