From: Sepherosa Ziehau Date: Sat, 4 Jul 2009 03:32:50 +0000 (+0800) Subject: Sync PCI code with FreeBSD 7.2 X-Git-Tag: v2.3.2~36^2~43 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/4d28e78f7e70287ae03930ce9e16ba027ca69477 Sync PCI code with FreeBSD 7.2 Submitted-by: Alexander Polakov --- diff --git a/sys/bus/isa/isa_common.c b/sys/bus/isa/isa_common.c index cc07df872f..b18affdee3 100644 --- a/sys/bus/isa/isa_common.c +++ b/sys/bus/isa/isa_common.c @@ -1045,3 +1045,15 @@ DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0); DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0); #endif +/* + * Code common to ISA bridges. + */ +int +isab_attach(device_t dev) +{ + device_t child; + child = device_add_child(dev, "isa", 0); + if (child != NULL) + return (bus_generic_attach(dev)); + return (ENXIO); +} diff --git a/sys/bus/pci/amd64/pci_cfgreg.c b/sys/bus/pci/amd64/pci_cfgreg.c deleted file mode 100644 index 0502b7af9a..0000000000 --- a/sys/bus/pci/amd64/pci_cfgreg.c +++ /dev/null @@ -1,852 +0,0 @@ -/* - * Copyright (c) 1997, Stefan Esser - * Copyright (c) 2000, Michael Smith - * Copyright (c) 2000, BSDi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $ - * $DragonFly: src/sys/bus/pci/amd64/pci_cfgreg.c,v 1.1 2008/08/02 05:22:19 dillon Exp $ - * - */ - -#include /* XXX trim includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci_cfgreg.h" -#include -#include -#include - -#define PRVERB(a) do { \ - if (bootverbose) \ - kprintf a ; \ -} while(0) - -static int pci_disable_bios_route = 0; -SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD, - &pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS"); -TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route); - -static int cfgmech; -static int devmax; - -#if 0 -static int pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq); -static int pci_cfgintr_unique(struct PIR_entry *pe, int pin); -static int pci_cfgintr_linked(struct PIR_entry *pe, int pin); -static int pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin); -static int pci_cfgintr_virgin(struct PIR_entry *pe, int pin); -#endif - -static void pci_print_irqmask(u_int16_t irqs); -#if 0 -static void pci_print_route_table(struct PIR_table *prt, int size); -#endif -static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); -static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); -static int pcireg_cfgopen(void); - -static struct PIR_table *pci_route_table; -static int pci_route_count; - -/* - * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. Some use - * numbers in the range 128-254 to indicate something strange and - * apparently undocumented anywhere. Assume these are completely bogus - * and map them to 255, which means "none". - */ -static int -pci_map_intline(int line) -{ - if (line == 0 || line >= 128) - return (PCI_INVALID_IRQ); - return (line); -} - -#if 0 - -static u_int16_t -pcibios_get_version(void) -{ - struct bios_regs args; - - if (PCIbios.ventry == 0) { - PRVERB(("pcibios: No call entry point\n")); - return (0); - } - args.eax = PCIBIOS_BIOS_PRESENT; - if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { - PRVERB(("pcibios: BIOS_PRESENT call failed\n")); - return (0); - } - if (args.edx != 0x20494350) { - PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); - return (0); - } - return (args.ebx & 0xffff); -} - -#endif - -/* - * Initialise access to PCI configuration space - */ -int -pci_cfgregopen(void) -{ - static int opened = 0; - u_long sigaddr; - static struct PIR_table *pt; - u_int16_t v; - u_int8_t ck, *cv; - int i; - - if (opened) - return (1); - - if (pcireg_cfgopen() == 0) - return (0); - -#if 0 - v = pcibios_get_version(); - if (v > 0) - kprintf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, - v & 0xff); - /* - * Look for the interrupt routing table. - * - * We use PCI BIOS's PIR table if it's available $PIR is the - * standard way to do this. Sadly some machines are not - * standards conforming and have _PIR instead. We shrug and cope - * by looking for both. - */ - if (pcibios_get_version() >= 0x0210 && pt == NULL) { - sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); - if (sigaddr == 0) - sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); - if (sigaddr != 0) { - pt = (struct PIR_table *)(uintptr_t) - BIOS_PADDRTOVADDR(sigaddr); - for (cv = (u_int8_t *)pt, ck = 0, i = 0; - i < (pt->pt_header.ph_length); i++) - ck += cv[i]; - if (ck == 0 && pt->pt_header.ph_length > - sizeof(struct PIR_header)) { - pci_route_table = pt; - pci_route_count = (pt->pt_header.ph_length - - sizeof(struct PIR_header)) / - sizeof(struct PIR_entry); - kprintf("Using $PIR table, %d entries at %p\n", - pci_route_count, pci_route_table); - if (bootverbose) - pci_print_route_table(pci_route_table, - pci_route_count); - } - } - } -#endif - opened = 1; - return (1); -} - -/* - * Read configuration space register - */ -u_int32_t -pci_cfgregread(int bus, int slot, int func, int reg, int bytes) -{ - uint32_t line; -#ifdef APIC_IO - uint32_t pin; - - /* - * If we are using the APIC, the contents of the intline - * register will probably be wrong (since they are set up for - * use with the PIC. Rather than rewrite these registers - * (maybe that would be smarter) we trap attempts to read them - * and translate to our private vector numbers. - */ - if ((reg == PCIR_INTLINE) && (bytes == 1)) { - - pin = pcireg_cfgread(bus, slot, func, PCIR_INTPIN, 1); - line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); - - if (pin != 0) { - int airq; - - airq = pci_apic_irq(bus, slot, pin); - if (airq >= 0) { - /* PCI specific entry found in MP table */ - if (airq != line) - undirect_pci_irq(line); - return (airq); - } else { - /* - * PCI interrupts might be redirected to the - * ISA bus according to some MP tables. Use the - * same methods as used by the ISA devices - * devices to find the proper IOAPIC int pin. - */ - airq = isa_apic_irq(line); - if ((airq >= 0) && (airq != line)) { - /* XXX: undirect_pci_irq() ? */ - undirect_isa_irq(line); - return (airq); - } - } - } - return (line); - } -#else - /* - * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. The rest of - * the code uses 255 as an invalid IRQ. - */ - if (reg == PCIR_INTLINE && bytes == 1) { - line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); - return pci_map_intline(line); - } -#endif /* APIC_IO */ - return (pcireg_cfgread(bus, slot, func, reg, bytes)); -} - -/* - * Write configuration space register - */ -void -pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) -{ - pcireg_cfgwrite(bus, slot, func, reg, data, bytes); -} - -int -pci_cfgread(pcicfgregs *cfg, int reg, int bytes) -{ - return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes)); -} - -void -pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) -{ - pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes); -} - -/* - * XXX - */ -int -pci_cfgintr(int bus, int device, int pin, int oldirq) -{ - return (PCI_INVALID_IRQ); -} - -#if 0 - -/* - * Route a PCI interrupt - */ -int -pci_cfgintr(int bus, int device, int pin, int oldirq) -{ - struct PIR_entry *pe; - int i, irq; - struct bios_regs args; - u_int16_t v; - - int already = 0; - int errok = 0; - - v = pcibios_get_version(); - if (v < 0x0210) { - PRVERB(( - "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n", - (v & 0xff00) >> 8, v & 0xff)); - return (PCI_INVALID_IRQ); - } - if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || - (pin < 1) || (pin > 4)) - return (PCI_INVALID_IRQ); - - /* - * Scan the entry table for a contender - */ - for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; - i++, pe++) { - if ((bus != pe->pe_bus) || (device != pe->pe_device)) - continue; - - /* - * A link of 0 means that this intpin is not connected to - * any other device's interrupt pins and is not connected to - * any of the Interrupt Router's interrupt pins, so we can't - * route it. - */ - if (pe->pe_intpin[pin - 1].link == 0) - continue; - - if (pci_cfgintr_valid(pe, pin, oldirq)) { - kprintf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus, - device, 'A' + pin - 1, oldirq); - return (oldirq); - } - - /* - * We try to find a linked interrupt, then we look to see - * if the interrupt is uniquely routed, then we look for - * a virgin interrupt. The virgin interrupt should return - * an interrupt we can route, but if that fails, maybe we - * should try harder to route a different interrupt. - * However, experience has shown that that's rarely the - * failure mode we see. - */ - irq = pci_cfgintr_linked(pe, pin); - if (irq != PCI_INVALID_IRQ) - already = 1; - if (irq == PCI_INVALID_IRQ) { - irq = pci_cfgintr_unique(pe, pin); - if (irq != PCI_INVALID_IRQ) - errok = 1; - } - if (irq == PCI_INVALID_IRQ) - irq = pci_cfgintr_virgin(pe, pin); - - if (irq == PCI_INVALID_IRQ) - break; - - if (pci_disable_bios_route != 0) - break; - /* - * Ask the BIOS to route the interrupt. If we picked an - * interrupt that failed, we should really try other - * choices that the BIOS offers us. - * - * For uniquely routed interrupts, we need to try - * to route them on some machines. Yet other machines - * fail to route, so we have to pretend that in that - * case it worked. Isn't PC hardware fun? - * - * NOTE: if we want to whack hardware to do this, then - * I think the right way to do that would be to have - * bridge drivers that do this. I'm not sure that the - * $PIR table would be valid for those interrupt - * routers. - */ - args.eax = PCIBIOS_ROUTE_INTERRUPT; - args.ebx = (bus << 8) | (device << 3); - /* pin value is 0xa - 0xd */ - args.ecx = (irq << 8) | (0xa + pin -1); - if (!already && - bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) && - !errok) { - PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n")); - return (PCI_INVALID_IRQ); - } - kprintf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, - device, 'A' + pin - 1, irq); - return(irq); - } - - PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c oldirq=%d\n", bus, - device, 'A' + pin - 1, oldirq)); - return (PCI_INVALID_IRQ); -} - -/* - * Check to see if an existing IRQ setting is valid. - */ -static int -pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq) -{ - uint32_t irqmask; - - if (!PCI_INTERRUPT_VALID(irq)) - return (0); - irqmask = pe->pe_intpin[pin - 1].irqs; - if (irqmask & (1 << irq)) { - PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq)); - return (1); - } - return (0); -} - -/* - * Look to see if the routing table claims this pin is uniquely routed. - */ -static int -pci_cfgintr_unique(struct PIR_entry *pe, int pin) -{ - int irq; - uint32_t irqmask; - - irqmask = pe->pe_intpin[pin - 1].irqs; - if(irqmask != 0 && powerof2(irqmask)) { - irq = ffs(irqmask) - 1; - PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); - return (irq); - } - return (PCI_INVALID_IRQ); -} - -/* - * Look for another device which shares the same link byte and - * already has a unique IRQ, or which has had one routed already. - */ -static int -pci_cfgintr_linked(struct PIR_entry *pe, int pin) -{ - struct PIR_entry *oe; - struct PIR_intpin *pi; - int i, j, irq; - - /* - * Scan table slots. - */ - for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; - i++, oe++) { - /* scan interrupt pins */ - for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { - - /* don't look at the entry we're trying to match */ - if ((pe == oe) && (i == (pin - 1))) - continue; - /* compare link bytes */ - if (pi->link != pe->pe_intpin[pin - 1].link) - continue; - /* link destination mapped to a unique interrupt? */ - if (pi->irqs != 0 && powerof2(pi->irqs)) { - irq = ffs(pi->irqs) - 1; - PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", - pi->link, irq)); - return(irq); - } - - /* - * look for the real PCI device that matches this - * table entry - */ - irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, - j + 1, pin); - if (irq != PCI_INVALID_IRQ) - return (irq); - } - } - return (PCI_INVALID_IRQ); -} - -/* - * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and - * see if it has already been assigned an interrupt. - */ -static int -pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) -{ - devclass_t pci_devclass; - device_t *pci_devices; - int pci_count; - device_t *pci_children; - int pci_childcount; - device_t *busp, *childp; - int i, j, irq; - - /* - * Find all the PCI busses. - */ - pci_count = 0; - if ((pci_devclass = devclass_find("pci")) != NULL) - devclass_get_devices(pci_devclass, &pci_devices, &pci_count); - - /* - * Scan all the PCI busses/devices looking for this one. - */ - irq = PCI_INVALID_IRQ; - for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ); - i++, busp++) { - pci_childcount = 0; - device_get_children(*busp, &pci_children, &pci_childcount); - - for (j = 0, childp = pci_children; j < pci_childcount; j++, - childp++) { - if ((pci_get_bus(*childp) == bus) && - (pci_get_slot(*childp) == device) && - (pci_get_intpin(*childp) == matchpin)) { - irq = pci_map_intline(pci_get_irq(*childp)); - if (irq != PCI_INVALID_IRQ) - PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", - pe->pe_intpin[pin - 1].link, irq, - pci_get_bus(*childp), - pci_get_slot(*childp), - pci_get_function(*childp))); - break; - } - } - if (pci_children != NULL) - kfree(pci_children, M_TEMP); - } - if (pci_devices != NULL) - kfree(pci_devices, M_TEMP); - return (irq); -} - -/* - * Pick a suitable IRQ from those listed as routable to this device. - */ -static int -pci_cfgintr_virgin(struct PIR_entry *pe, int pin) -{ - int irq, ibit; - - /* - * first scan the set of PCI-only interrupts and see if any of these - * are routable - */ - for (irq = 0; irq < 16; irq++) { - ibit = (1 << irq); - - /* can we use this interrupt? */ - if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && - (pe->pe_intpin[pin - 1].irqs & ibit)) { - PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq)); - return (irq); - } - } - - /* life is tough, so just pick an interrupt */ - for (irq = 0; irq < 16; irq++) { - ibit = (1 << irq); - - if (pe->pe_intpin[pin - 1].irqs & ibit) { - PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq)); - return (irq); - } - } - return (PCI_INVALID_IRQ); -} - -static void -pci_print_irqmask(u_int16_t irqs) -{ - int i, first; - - if (irqs == 0) { - kprintf("none"); - return; - } - first = 1; - for (i = 0; i < 16; i++, irqs >>= 1) - if (irqs & 1) { - if (!first) - kprintf(" "); - else - first = 0; - kprintf("%d", i); - } -} - -/* - * Dump the contents of a PCI BIOS Interrupt Routing Table to the console. - */ -static void -pci_print_route_table(struct PIR_table *ptr, int size) -{ - struct PIR_entry *entry; - struct PIR_intpin *intpin; - int i, pin; - - kprintf("PCI-Only Interrupts: "); - pci_print_irqmask(ptr->pt_header.ph_pci_irqs); - kprintf("\nLocation Bus Device Pin Link IRQs\n"); - entry = &ptr->pt_entry[0]; - for (i = 0; i < size; i++, entry++) { - intpin = &entry->pe_intpin[0]; - for (pin = 0; pin < 4; pin++, intpin++) - if (intpin->link != 0) { - if (entry->pe_slot == 0) - kprintf("embedded "); - else - kprintf("slot %-3d ", entry->pe_slot); - kprintf(" %3d %3d %c 0x%02x ", - entry->pe_bus, entry->pe_device, - 'A' + pin, intpin->link); - pci_print_irqmask(intpin->irqs); - kprintf("\n"); - } - } -} - -/* - * See if any interrupts for a given PCI bus are routed in the PIR. Don't - * even bother looking if the BIOS doesn't support routing anyways. - */ -int -pci_probe_route_table(int bus) -{ - int i; - u_int16_t v; - - v = pcibios_get_version(); - if (v < 0x0210) - return (0); - for (i = 0; i < pci_route_count; i++) - if (pci_route_table->pt_entry[i].pe_bus == bus) - return (1); - return (0); -} - -#endif - -/* - * Configuration space access using direct register operations - */ - -/* enable configuration space accesses and return data port address */ -static int -pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) -{ - int dataport = 0; - - if (bus <= PCI_BUSMAX - && slot < devmax - && func <= PCI_FUNCMAX - && reg <= PCI_REGMAX - && bytes != 3 - && (unsigned) bytes <= 4 - && (reg & (bytes - 1)) == 0) { - switch (cfgmech) { - case 1: - outl(CONF1_ADDR_PORT, (1 << 31) - | (bus << 16) | (slot << 11) - | (func << 8) | (reg & ~0x03)); - dataport = CONF1_DATA_PORT + (reg & 0x03); - break; - case 2: - outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); - outb(CONF2_FORWARD_PORT, bus); - dataport = 0xc000 | (slot << 8) | reg; - break; - } - } - return (dataport); -} - -/* disable configuration space accesses */ -static void -pci_cfgdisable(void) -{ - switch (cfgmech) { - case 1: - outl(CONF1_ADDR_PORT, 0); - break; - case 2: - outb(CONF2_ENABLE_PORT, 0); - outb(CONF2_FORWARD_PORT, 0); - break; - } -} - -static int -pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) -{ - int data = -1; - int port; - - port = pci_cfgenable(bus, slot, func, reg, bytes); - if (port != 0) { - switch (bytes) { - case 1: - data = inb(port); - break; - case 2: - data = inw(port); - break; - case 4: - data = inl(port); - break; - } - pci_cfgdisable(); - } - return (data); -} - -static void -pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) -{ - int port; - - port = pci_cfgenable(bus, slot, func, reg, bytes); - if (port != 0) { - switch (bytes) { - case 1: - outb(port, data); - break; - case 2: - outw(port, data); - break; - case 4: - outl(port, data); - break; - } - pci_cfgdisable(); - } -} - -/* check whether the configuration mechanism has been correctly identified */ -static int -pci_cfgcheck(int maxdev) -{ - uint32_t id, class; - uint8_t header; - uint8_t device; - int port; - - if (bootverbose) - kprintf("pci_cfgcheck:\tdevice "); - - for (device = 0; device < maxdev; device++) { - if (bootverbose) - kprintf("%d ", device); - - port = pci_cfgenable(0, device, 0, 0, 4); - id = inl(port); - if (id == 0 || id == 0xffffffff) - continue; - - port = pci_cfgenable(0, device, 0, 8, 4); - class = inl(port) >> 8; - if (bootverbose) - kprintf("[class=%06x] ", class); - if (class == 0 || (class & 0xf870ff) != 0) - continue; - - port = pci_cfgenable(0, device, 0, 14, 1); - header = inb(port); - if (bootverbose) - kprintf("[hdr=%02x] ", header); - if ((header & 0x7e) != 0) - continue; - - if (bootverbose) - kprintf("is there (id=%08x)\n", id); - - pci_cfgdisable(); - return (1); - } - if (bootverbose) - kprintf("-- nothing found\n"); - - pci_cfgdisable(); - return (0); -} - -static int -pcireg_cfgopen(void) -{ - uint32_t mode1res,oldval1; - uint8_t mode2res,oldval2; - - oldval1 = inl(CONF1_ADDR_PORT); - - if (bootverbose) { - kprintf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", - oldval1); - } - - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - - cfgmech = 1; - devmax = 32; - - outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - DELAY(1); - mode1res = inl(CONF1_ADDR_PORT); - outl(CONF1_ADDR_PORT, oldval1); - - if (bootverbose) - kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); - - if (mode1res) { - if (pci_cfgcheck(32)) - return (cfgmech); - } - - outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); - mode1res = inl(CONF1_ADDR_PORT); - outl(CONF1_ADDR_PORT, oldval1); - - if (bootverbose) - kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); - - if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pci_cfgcheck(32)) - return (cfgmech); - } - } - - oldval2 = inb(CONF2_ENABLE_PORT); - - if (bootverbose) { - kprintf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", - oldval2); - } - - if ((oldval2 & 0xf0) == 0) { - - cfgmech = 2; - devmax = 16; - - outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); - mode2res = inb(CONF2_ENABLE_PORT); - outb(CONF2_ENABLE_PORT, oldval2); - - if (bootverbose) - kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); - - if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - kprintf("pci_open(2a):\tnow trying mechanism 2\n"); - - if (pci_cfgcheck(16)) - return (cfgmech); - } - } - - cfgmech = 0; - devmax = 0; - return (cfgmech); -} diff --git a/sys/bus/pci/amd64/pci_cfgreg.h b/sys/bus/pci/amd64/pci_cfgreg.h deleted file mode 100644 index 3fe6b44818..0000000000 --- a/sys/bus/pci/amd64/pci_cfgreg.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1997, Stefan Esser - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.4.2.1 2001/07/28 05:55:07 imp Exp $ - * $DragonFly: src/sys/bus/pci/amd64/pci_cfgreg.h,v 1.1 2008/08/02 05:22:19 dillon Exp $ - * - */ - -#ifndef _MACHINE_PCI_CFGREG_H_ -#define _MACHINE_PCI_CFGREG_H_ - -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc - -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7f000000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul - -#define CONF2_ENABLE_PORT 0x0cf8 -#define CONF2_FORWARD_PORT 0x0cfa - -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e - -int pci_cfgregopen(void); -u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); -void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); -int pci_cfgintr(int bus, int device, int pin, int oldirq); -int pci_probe_route_table(int bus); - -#define PCI_INVALID_IRQ 255 -#define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ) - -#endif diff --git a/sys/bus/pci/amd64/pcibus.c b/sys/bus/pci/amd64/pcibus.c deleted file mode 100644 index 9ffc9d960e..0000000000 --- a/sys/bus/pci/amd64/pcibus.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (c) 1997, Stefan Esser - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/isa/pcibus.c,v 1.57.2.12 2003/08/07 06:19:26 imp Exp $ - * $DragonFly: src/sys/bus/pci/amd64/pcibus.c,v 1.2 2008/09/05 10:39:36 hasso Exp $ - * - */ - -#include "opt_pci.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include "pcibus.h" -#include -#include "pci_cfgreg.h" -#include -#include - -#include "pcib_if.h" - -static u_int32_t nexus_pcib_read_config(device_t, int, int, int, int, int); - -/* - * Figure out if a PCI entity is a host bridge, return its name or NULL. - */ -static const char * -nexus_legacypci_is_host_bridge(int bus, int slot, int func, - u_int32_t id, u_int8_t class, u_int8_t subclass, - u_int8_t *busnum) -{ - const char *s = NULL; - static u_int8_t pxb[4]; /* hack for 450nx */ - - *busnum = 0; - - switch (id) { - case 0x12258086: - s = "Intel 824?? host to PCI bridge"; - /* XXX This is a guess */ - /* *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x41, 1); */ - *busnum = bus; - break; - case 0x71208086: - s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; - break; - case 0x71228086: - s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; - break; - case 0x71248086: - s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; - break; - case 0x71808086: - s = "Intel 82443LX (440 LX) host to PCI bridge"; - break; - case 0x71908086: - s = "Intel 82443BX (440 BX) host to PCI bridge"; - break; - case 0x71928086: - s = "Intel 82443BX host to PCI bridge (AGP disabled)"; - break; - case 0x71948086: - s = "Intel 82443MX host to PCI bridge"; - break; - case 0x71a08086: - s = "Intel 82443GX host to PCI bridge"; - break; - case 0x71a18086: - s = "Intel 82443GX host to AGP bridge"; - break; - case 0x71a28086: - s = "Intel 82443GX host to PCI bridge (AGP disabled)"; - break; - case 0x84c48086: - s = "Intel 82454KX/GX (Orion) host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x4a, 1); - break; - case 0x84ca8086: - /* - * For the 450nx chipset, there is a whole bundle of - * things pretending to be host bridges. The MIOC will - * be seen first and isn't really a pci bridge (the - * actual busses are attached to the PXB's). We need to - * read the registers of the MIOC to figure out the - * bus numbers for the PXB channels. - * - * Since the MIOC doesn't have a pci bus attached, we - * pretend it wasn't there. - */ - pxb[0] = nexus_pcib_read_config(0, bus, slot, func, - 0xd0, 1); /* BUSNO[0] */ - pxb[1] = nexus_pcib_read_config(0, bus, slot, func, - 0xd1, 1) + 1; /* SUBA[0]+1 */ - pxb[2] = nexus_pcib_read_config(0, bus, slot, func, - 0xd3, 1); /* BUSNO[1] */ - pxb[3] = nexus_pcib_read_config(0, bus, slot, func, - 0xd4, 1) + 1; /* SUBA[1]+1 */ - return NULL; - case 0x84cb8086: - switch (slot) { - case 0x12: - s = "Intel 82454NX PXB#0, Bus#A"; - *busnum = pxb[0]; - break; - case 0x13: - s = "Intel 82454NX PXB#0, Bus#B"; - *busnum = pxb[1]; - break; - case 0x14: - s = "Intel 82454NX PXB#1, Bus#A"; - *busnum = pxb[2]; - break; - case 0x15: - s = "Intel 82454NX PXB#1, Bus#B"; - *busnum = pxb[3]; - break; - } - break; - case 0x1A308086: - s = "Intel 82845 Host to PCI bridge"; - break; - - /* AMD -- vendor 0x1022 */ - case 0x30001022: - s = "AMD Elan SC520 host to PCI bridge"; -#ifdef CPU_ELAN - init_AMD_Elan_sc520(); -#else - kprintf("*** WARNING: kernel option CPU_ELAN missing"); - kprintf("-- timekeeping may be wrong\n"); -#endif - break; - case 0x70061022: - s = "AMD-751 host to PCI bridge"; - break; - case 0x700e1022: - s = "AMD-761 host to PCI bridge"; - break; - - /* SiS -- vendor 0x1039 */ - case 0x04961039: - s = "SiS 85c496"; - break; - case 0x04061039: - s = "SiS 85c501"; - break; - case 0x06011039: - s = "SiS 85c601"; - break; - case 0x55911039: - s = "SiS 5591 host to PCI bridge"; - break; - case 0x00011039: - s = "SiS 5591 host to AGP bridge"; - break; - - /* VLSI -- vendor 0x1004 */ - case 0x00051004: - s = "VLSI 82C592 Host to PCI bridge"; - break; - - /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ - /* totally. Please let me know if anything wrong. -F */ - /* XXX need info on the MVP3 -- any takers? */ - case 0x05981106: - s = "VIA 82C598MVP (Apollo MVP3) host bridge"; - break; - - /* AcerLabs -- vendor 0x10b9 */ - /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ - /* id is '10b9" but the register always shows "10b9". -Foxfair */ - case 0x154110b9: - s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; - break; - - /* OPTi -- vendor 0x1045 */ - case 0xc7011045: - s = "OPTi 82C700 host to PCI bridge"; - break; - case 0xc8221045: - s = "OPTi 82C822 host to PCI Bridge"; - break; - - /* ServerWorks -- vendor 0x1166 */ - case 0x00051166: - s = "ServerWorks NB6536 2.0HE host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - case 0x00061166: - /* FALLTHROUGH */ - case 0x00081166: - /* FALLTHROUGH */ - case 0x02011166: - /* FALLTHROUGH */ - case 0x010f1014: /* IBM re-badged ServerWorks chipset */ - /* FALLTHROUGH */ - s = "ServerWorks host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - case 0x00091166: - s = "ServerWorks NB6635 3.0LE host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - case 0x00101166: - s = "ServerWorks CIOB30 host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - case 0x00111166: - /* FALLTHROUGH */ - case 0x03021014: /* IBM re-badged ServerWorks chipset */ - s = "ServerWorks CMIC-HE host to PCI-X bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - /* XXX unknown chipset, but working */ - case 0x00171166: - /* FALLTHROUGH */ - case 0x01011166: - s = "ServerWorks host to PCI bridge(unknown chipset)"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); - break; - - /* Integrated Micro Solutions -- vendor 0x10e0 */ - case 0x884910e0: - s = "Integrated Micro Solutions VL Bridge"; - break; - - default: - if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) - s = "Host to PCI bridge"; - break; - } - - return s; -} - -/* - * Identify the existance of the first pci bus and install a child to - * nexus if we find it. Use an order of 1 so it gets probed after - * any ACPI device installed under nexus. To avoid boot-time confusion, - * we do not install any 'pcib' devices at this time. - * - * The identify method coupled with the driver spec of the same name - * automatically installs it under the nexus. - */ -static int -nexus_legacypci_identify(driver_t *driver, device_t parent) -{ - /* - * Basically a static device, there's no point reinstalling it - * on rescan. - */ - if (device_get_state(parent) == DS_ATTACHED) - return (0); - if (device_get_state(parent) == DS_INPROGRESS) - return (0); - - if (pci_cfgregopen() == 0) - return (ENXIO); - - BUS_ADD_CHILD(parent, parent, 100, "legacypci", 0); - return (0); -} - -/* - * Scan the first pci bus for host-pci bridges and add pcib instances - * to the nexus for each bridge. - */ -static int -nexus_legacypci_probe(device_t dev) -{ - int bus, slot, func; - u_int8_t hdrtype; - int found = 0; - int pcifunchigh; - int found824xx = 0; - device_t child; - - /* - * Do not install any pci busses ('pcib' devices) if the PCI - * subsystem has already been claimed by someone else. - */ - if (pcib_owner != NULL) { - device_printf(dev, "PCI subsystem owned by %s, skipping scan\n", - pcib_owner); - return (ENXIO); - } - pcib_owner = "legacypci"; - - if (pci_cfgregopen() == 0) - return (ENXIO); - - /* - * Scan away! - */ - bus = 0; - retry: - for (slot = 0; slot <= PCI_SLOTMAX; slot++) { - func = 0; - hdrtype = nexus_pcib_read_config(0, bus, slot, func, - PCIR_HDRTYPE, 1); - if ((hdrtype & ~PCIM_MFDEV) > 2) - continue; - if (hdrtype & PCIM_MFDEV) - pcifunchigh = 7; - else - pcifunchigh = 0; - for (func = 0; func <= pcifunchigh; func++) { - /* - * Read the IDs and class from the device. - */ - u_int32_t id; - u_int8_t class, subclass, busnum; - const char *s; - device_t *devs; - int ndevs, i; - - id = nexus_pcib_read_config(0, bus, slot, func, - PCIR_DEVVENDOR, 4); - if (id == -1) - continue; - class = nexus_pcib_read_config(0, bus, slot, func, - PCIR_CLASS, 1); - subclass = nexus_pcib_read_config(0, bus, slot, func, - PCIR_SUBCLASS, 1); - - s = nexus_legacypci_is_host_bridge(bus, slot, func, - id, class, subclass, - &busnum); - if (s == NULL) - continue; - - /* - * Check to see if the physical bus has already - * been seen. Eg: hybrid 32 and 64 bit host - * bridges to the same logical bus. - */ - if (device_get_children(dev, &devs, &ndevs) == 0) { - for (i = 0; s != NULL && i < ndevs; i++) { - if (strcmp(device_get_name(devs[i]), - "pcib") != 0) - continue; - if (nexus_get_pcibus(devs[i]) == busnum) - s = NULL; - } - kfree(devs, M_TEMP); - } - - if (s == NULL) - continue; - /* - * Add at priority 100+busnum to keep the scanning - * order sane in the boot dmesg output. - */ - child = BUS_ADD_CHILD(dev, dev, 100 + busnum, - "pcib", busnum); - device_set_desc(child, s); - nexus_set_pcibus(child, busnum); - - found = 1; - if (id == 0x12258086) - found824xx = 1; - } - } - if (found824xx && bus == 0) { - bus++; - goto retry; - } - -#if 0 - /* - * Now that we have installed the main PCI bridges, go - * probe and attach each one. - */ - bus_generic_attach(dev); -#endif - - /* - * Make sure we add at least one bridge since some old - * hardware doesn't actually have a host-pci bridge device. - * Note that pci_cfgregopen() thinks we have PCI devices.. - */ - if (!found) { - if (bootverbose) { - kprintf("nexus_pcib_identify: no bridge found, " - "adding pcib0 anyway\n"); - } - child = BUS_ADD_CHILD(dev, dev, 100, "pcib", 0); - nexus_set_pcibus(child, 0); - } - return (0); -} - -static int -nexus_legacypci_attach(device_t dev) -{ - bus_generic_attach(dev); - return (0); -} - -#ifdef PCI_MAP_FIXUP - -SYSCTL_DECL(_hw_pci); - -static unsigned long legacy_host_mem_start = 0xffffffff80000000; -/* XXX need TUNABLE_ULONG? */ -TUNABLE_INT("hw.pci.host_mem_start", (int *)&legacy_host_mem_start); -SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD, - &legacy_host_mem_start, 0x80000000, - "Limit the host bridge memory to being above this address. " - "Must be\n" - "set at boot via hw.pci.host_mem_start tunable."); - -static struct resource * -nexus_legacypci_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, - u_int flags) -{ - /* - * If no memory preference is given, use upper 32MB slot most - * bioses use for their memory window. Typically other bridges - * before us get in the way to assert their preferences on memory. - * Hardcoding like this sucks, so a more MD/MI way needs to be - * found to do it. This is typically only used on older laptops - * that don't have pci busses behind pci bridge, so assuming > 32MB - * is likely OK. - * - * However, this can cause problems for other chipsets, so we make - * this tunable by hw.pci.host_mem_start. - */ - if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) - start = legacy_host_mem_start; - if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) - start = 0x1000; - return bus_generic_alloc_resource(dev, child, type, rid, - start, end, count, flags); -} - -#endif /* PCI_MAP_FIXUP */ - -static device_method_t legacypci_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, nexus_legacypci_identify), - DEVMETHOD(device_probe, nexus_legacypci_probe), - DEVMETHOD(device_attach, nexus_legacypci_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* - * Bus interface - propogate through to the nexus. Note that - * this means devices under us will have nexus ivars. - */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), -#ifdef PCI_MAP_FIXUP - DEVMETHOD(bus_alloc_resource, nexus_legacypci_alloc_resource), -#else - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), -#endif - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - DEVMETHOD(bus_set_resource, bus_generic_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_get_resource), - DEVMETHOD(bus_delete_resource, bus_generic_delete_resource), - { 0, 0 } -}; - -static driver_t legacypci_driver = { - "legacypci", - legacypci_methods, - 1, -}; - -static devclass_t legacypci_devclass; - -DRIVER_MODULE(legacypci, nexus, legacypci_driver, legacypci_devclass, 0, 0); - -/* - * Legacypci Host-Bridge PCI BUS support. The underlying pcib devices - * will only exist if we actually control the PCI bus. The actual PCI - * bus driver is attached in our attach routine. - * - * There is no identify function because the legacypci placeholder will - * have already scanned and added PCIB devices for the host-bridges found. - */ -static int -nexus_pcib_maxslots(device_t dev) -{ - return 31; -} - -/* - * Read configuration space register. - */ -static u_int32_t -nexus_pcib_read_config(device_t dev, int bus, int slot, int func, - int reg, int bytes) -{ - return (pci_cfgregread(bus, slot, func, reg, bytes)); -} - -/* - * Write configuration space register. - */ -static void -nexus_pcib_write_config(device_t dev, int bus, int slot, int func, - int reg, u_int32_t data, int bytes) -{ - pci_cfgregwrite(bus, slot, func, reg, data, bytes); -} - -/* - * Stack a pci device on top of the pci bridge bus device. - */ -static int -nexus_pcib_probe(device_t dev) -{ - BUS_ADD_CHILD(dev, dev, 0, "pci", device_get_unit(dev)); - return (0); -} - -static int -nexus_pcib_attach(device_t dev) -{ - int error; - - error = bus_generic_attach(dev); - return (error); -} - -/* route interrupt */ - -static int -nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin) -{ - return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin, - pci_get_irq(dev))); -} - -static device_method_t nexus_pcib_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, nexus_pcib_probe), - DEVMETHOD(device_attach, nexus_pcib_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* - * Bus interface - propogate through to the nexus. Note - * that this means we will get nexus-managed ivars. - */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - /* pcib interface */ - DEVMETHOD(pcib_maxslots, nexus_pcib_maxslots), - DEVMETHOD(pcib_read_config, nexus_pcib_read_config), - DEVMETHOD(pcib_write_config, nexus_pcib_write_config), - DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt), - - { 0, 0 } -}; - -static driver_t nexus_pcib_driver = { - "pcib", - nexus_pcib_methods, - 1, -}; - -static devclass_t pcib_devclass; - -DRIVER_MODULE(pcib, legacypci, nexus_pcib_driver, pcib_devclass, 0, 0); - - -/* - * Provide a device to "eat" the host->pci bridges that we dug up above - * and stop them showing up twice on the probes. This also stops them - * showing up as 'none' in pciconf -l. - * - * Return an ultra-low priority so other devices can attach the bus before - * our dummy attach. - * - * XXX may have to disable the registration entirely to support module-loaded - * bridges such as agp.ko. - */ -static int -pci_hostb_probe(device_t dev) -{ - if (pci_get_class(dev) == PCIC_BRIDGE && - pci_get_subclass(dev) == PCIS_BRIDGE_HOST) { - device_set_desc(dev, "Host to PCI bridge"); - device_quiet(dev); - return -10000; - } - return (ENXIO); -} - -static int -pci_hostb_attach(device_t dev) -{ - return (0); -} - -static device_method_t pci_hostb_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pci_hostb_probe), - DEVMETHOD(device_attach, pci_hostb_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - { 0, 0 } -}; -static driver_t pci_hostb_driver = { - "hostb", - pci_hostb_methods, - 1, -}; -static devclass_t pci_hostb_devclass; - -DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0); - - -/* - * Install placeholder to claim the resources owned by the - * PCI bus interface. This could be used to extract the - * config space registers in the extreme case where the PnP - * ID is available and the PCI BIOS isn't, but for now we just - * eat the PnP ID and do nothing else. - * - * XXX we should silence this probe, as it will generally confuse - * people. - */ -static struct isa_pnp_id pcibus_pnp_ids[] = { - { 0x030ad041 /* PNP030A */, "PCI Bus" }, - { 0 } -}; - -static int -pcibus_pnp_probe(device_t dev) -{ - int result; - - if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0) - device_quiet(dev); - return (result); -} - -static int -pcibus_pnp_attach(device_t dev) -{ - return(0); -} - -static device_method_t pcibus_pnp_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pcibus_pnp_probe), - DEVMETHOD(device_attach, pcibus_pnp_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - { 0, 0 } -}; - -static driver_t pcibus_pnp_driver = { - "pcibus_pnp", - pcibus_pnp_methods, - 1, /* no softc */ -}; - -static devclass_t pcibus_pnp_devclass; - -DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); - diff --git a/sys/bus/pci/amd64/pcibus.h b/sys/bus/pci/amd64/pcibus.h deleted file mode 100644 index 6b5a362110..0000000000 --- a/sys/bus/pci/amd64/pcibus.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 1997, Stefan Esser - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/isa/pcibus.h,v 1.2 1999/08/28 00:44:59 peter Exp $ - * $DragonFly: src/sys/bus/pci/amd64/pcibus.h,v 1.1 2008/08/02 05:22:19 dillon Exp $ - * - */ - -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc - -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7f000000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul - -#define CONF2_ENABLE_PORT 0x0cf8 -#define CONF2_FORWARD_PORT 0x0cfa - -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e diff --git a/sys/bus/pci/dc21040reg.h b/sys/bus/pci/dc21040reg.h index a773c7eec3..6e5f54b774 100644 --- a/sys/bus/pci/dc21040reg.h +++ b/sys/bus/pci/dc21040reg.h @@ -419,7 +419,7 @@ typedef struct { #define TULIP_GP_ZX346_FULLDUPLEX 0x00000004 /* Full Duplex Sensed */ #define TULIP_GP_ZX34X_LB102 0x00000002 /* 100tx twister LB */ #define TULIP_GP_ZX34X_NLB101 0x00000001 /* PDT/PDR LB */ -#define TULIP_GP_ZX34X_INIT 0x00000009 +#define TULIP_GP_ZX34X_INIT 0x00000009 /* * Compex's OUI. We need to twiddle a bit on their 21041 card. diff --git a/sys/bus/pci/eisa_pci.c b/sys/bus/pci/eisa_pci.c new file mode 100644 index 0000000000..c348e41f29 --- /dev/null +++ b/sys/bus/pci/eisa_pci.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/eisa_pci.c,v 1.6.28.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * PCI:EISA bridge support + */ + +#include +#include +#include +#include + +#include +#include + +static int eisab_probe(device_t dev); +static int eisab_attach(device_t dev); + +static device_method_t eisab_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, eisab_probe), + DEVMETHOD(device_attach, eisab_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t eisab_driver = { + "eisab", + eisab_methods, + 0, +}; + +static devclass_t eisab_devclass; + +DRIVER_MODULE(eisab, pci, eisab_driver, eisab_devclass, 0, 0); + +static int +eisab_probe(device_t dev) +{ + int matched = 0; + + /* + * Generic match by class/subclass. + */ + if ((pci_get_class(dev) == PCIC_BRIDGE) && + (pci_get_subclass(dev) == PCIS_BRIDGE_EISA)) + matched = 1; + + /* + * Some bridges don't correctly report their class. + */ + switch (pci_get_devid(dev)) { + case 0x04828086: /* may show up as PCI-HOST or 0:0 */ + matched = 1; + break; + default: + break; + } + + if (matched) { + device_set_desc(dev, "PCI-EISA bridge"); + return(-10000); + } + return(ENXIO); +} + +static int +eisab_attach(device_t dev) +{ + /* + * Attach an EISA bus. Note that we can only have one EISA bus. + */ + if (!devclass_get_device(devclass_find("eisa"), 0)) + device_add_child(dev, "eisa", -1); + + /* + * Attach an ISA bus as well, since the EISA bus may have ISA + * cards installed, and we may have no EISA support in the system. + */ + if (!devclass_get_device(devclass_find("isa"), 0)) + device_add_child(dev, "isa", -1); + + bus_generic_attach(dev); + + return(0); +} diff --git a/sys/bus/pci/fixup_pci.c b/sys/bus/pci/fixup_pci.c new file mode 100644 index 0000000000..ecade927ee --- /dev/null +++ b/sys/bus/pci/fixup_pci.c @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/fixup_pci.c,v 1.7.8.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Chipset fixups. + * + * These routines are invoked during the probe phase for devices which + * typically don't have specific device drivers, but which require + * some cleaning up. + */ + +static int fixup_pci_probe(device_t dev); +static void fixwsc_natoma(device_t dev); +static void fixc1_nforce2(device_t dev); + +static device_method_t fixup_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fixup_pci_probe), + DEVMETHOD(device_attach, bus_generic_attach), + { 0, 0 } +}; + +static driver_t fixup_pci_driver = { + "fixup_pci", + fixup_pci_methods, + 0, +}; + +static devclass_t fixup_pci_devclass; + +DRIVER_MODULE(fixup_pci, pci, fixup_pci_driver, fixup_pci_devclass, 0, 0); + +static int +fixup_pci_probe(device_t dev) +{ + switch (pci_get_devid(dev)) { + case 0x12378086: /* Intel 82440FX (Natoma) */ + fixwsc_natoma(dev); + break; + case 0x01e010de: /* nVidia nForce2 */ + fixc1_nforce2(dev); + break; + } + return(ENXIO); +} + +static void +fixwsc_natoma(device_t dev) +{ + int pmccfg; + + pmccfg = pci_read_config(dev, 0x50, 2); +#if defined(SMP) + if (pmccfg & 0x8000) { + kprintf("Correcting Natoma config for SMP\n"); + pmccfg &= ~0x8000; + pci_write_config(dev, 0x50, pmccfg, 2); + } +#else + if ((pmccfg & 0x8000) == 0) { + kprintf("Correcting Natoma config for non-SMP\n"); + pmccfg |= 0x8000; + pci_write_config(dev, 0x50, pmccfg, 2); + } +#endif +} + +/* + * Set the SYSTEM_IDLE_TIMEOUT to 80 ns on nForce2 systems to work + * around a hang that is triggered when the CPU generates a very fast + * CONNECT/HALT cycle sequence. Specifically, the hang can result in + * the lapic timer being stopped. + * + * This requires changing the value for config register at offset 0x6c + * for the Host-PCI bridge at bus/dev/function 0/0/0: + * + * Chip Current Value New Value + * ---- ---------- ---------- + * C17 0x1F0FFF01 0x1F01FF01 + * C18D 0x9F0FFF01 0x9F01FF01 + * + * We do this by always clearing the bits in 0x000e0000. + * + * See also: http://lkml.org/lkml/2004/5/3/157 + */ +static void +fixc1_nforce2(device_t dev) +{ + uint32_t val; + + if (pci_get_bus(dev) == 0 && pci_get_slot(dev) == 0 && + pci_get_function(dev) == 0) { + val = pci_read_config(dev, 0x6c, 4); + if (val & 0x000e0000) { + kprintf("Correcting nForce2 C1 CPU disconnect hangs\n"); + val &= ~0x000e0000; + pci_write_config(dev, 0x6c, val, 4); + } + } +} diff --git a/sys/bus/pci/hostb_pci.c b/sys/bus/pci/hostb_pci.c new file mode 100644 index 0000000000..c960461b55 --- /dev/null +++ b/sys/bus/pci/hostb_pci.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1997, Stefan Esser + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/hostb_pci.c,v 1.1.8.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* + * Provide a device to "eat" the host->pci bridge devices that show up + * on PCI busses and stop them showing up twice on the probes. This also + * stops them showing up as 'none' in pciconf -l. If the host bridge + * provides an AGP capability then we create a child agp device for the + * agp GART driver to attach to. + */ +static int +pci_hostb_probe(device_t dev) +{ + u_int32_t id; + id = pci_get_devid(dev); + + switch (id) { + + /* VIA VT82C596 Power Managment Function */ + case 0x30501106: + return (ENXIO); + + default: + break; + } + + if (pci_get_class(dev) == PCIC_BRIDGE && + pci_get_subclass(dev) == PCIS_BRIDGE_HOST) { + device_set_desc(dev, "Host to PCI bridge"); + device_quiet(dev); + return (-10000); + } + return (ENXIO); +} + +static int +pci_hostb_attach(device_t dev) +{ + + bus_generic_probe(dev); + + /* + * If AGP capabilities are present on this device, then create + * an AGP child. + */ + if (pci_find_extcap(dev, PCIY_AGP, NULL) == 0) + device_add_child(dev, "agp", -1); + bus_generic_attach(dev); + return (0); +} + +/* Bus interface. */ + +static int +pci_hostb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + + return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result)); +} + +static int +pci_hostb_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + + return (EINVAL); +} + +static struct resource * +pci_hostb_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + + return (bus_alloc_resource(dev, type, rid, start, end, count, flags)); +} + +static int +pci_hostb_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + return (bus_release_resource(dev, type, rid, r)); +} + +/* PCI interface. */ + +static uint32_t +pci_hostb_read_config(device_t dev, device_t child, int reg, int width) +{ + + return (pci_read_config(dev, reg, width)); +} + +static void +pci_hostb_write_config(device_t dev, device_t child, int reg, + uint32_t val, int width) +{ + + pci_write_config(dev, reg, val, width); +} + +static int +pci_hostb_enable_busmaster(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_enable_busmaster\n", + device_get_nameunit(child)); + return (pci_enable_busmaster(dev)); +} + +static int +pci_hostb_disable_busmaster(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_disable_busmaster\n", + device_get_nameunit(child)); + return (pci_disable_busmaster(dev)); +} + +static int +pci_hostb_enable_io(device_t dev, device_t child, int space) +{ + + device_printf(dev, "child %s requested pci_enable_io\n", + device_get_nameunit(child)); + return (pci_enable_io(dev, space)); +} + +static int +pci_hostb_disable_io(device_t dev, device_t child, int space) +{ + + device_printf(dev, "child %s requested pci_disable_io\n", + device_get_nameunit(child)); + return (pci_disable_io(dev, space)); +} + +static int +pci_hostb_set_powerstate(device_t dev, device_t child, int state) +{ + + device_printf(dev, "child %s requested pci_set_powerstate\n", + device_get_nameunit(child)); + return (pci_set_powerstate(dev, state)); +} + +static int +pci_hostb_get_powerstate(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_get_powerstate\n", + device_get_nameunit(child)); + return (pci_get_powerstate(dev)); +} + +static int +pci_hostb_assign_interrupt(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_assign_interrupt\n", + device_get_nameunit(child)); + return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); +} + +static int +pci_hostb_find_extcap(device_t dev, device_t child, int capability, + int *capreg) +{ + + return (pci_find_extcap(dev, capability, capreg)); +} + +static device_method_t pci_hostb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pci_hostb_probe), + DEVMETHOD(device_attach, pci_hostb_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, pci_hostb_read_ivar), + DEVMETHOD(bus_write_ivar, pci_hostb_write_ivar), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + DEVMETHOD(bus_alloc_resource, pci_hostb_alloc_resource), + DEVMETHOD(bus_release_resource, pci_hostb_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + /* PCI interface */ + DEVMETHOD(pci_read_config, pci_hostb_read_config), + DEVMETHOD(pci_write_config, pci_hostb_write_config), + DEVMETHOD(pci_enable_busmaster, pci_hostb_enable_busmaster), + DEVMETHOD(pci_disable_busmaster, pci_hostb_disable_busmaster), + DEVMETHOD(pci_enable_io, pci_hostb_enable_io), + DEVMETHOD(pci_disable_io, pci_hostb_disable_io), + DEVMETHOD(pci_get_powerstate, pci_hostb_get_powerstate), + DEVMETHOD(pci_set_powerstate, pci_hostb_set_powerstate), + DEVMETHOD(pci_assign_interrupt, pci_hostb_assign_interrupt), + DEVMETHOD(pci_find_extcap, pci_hostb_find_extcap), + + { 0, 0 } +}; + +static driver_t pci_hostb_driver = { + "hostb", + pci_hostb_methods, + 1, +}; + +static devclass_t pci_hostb_devclass; + +DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0); diff --git a/sys/bus/pci/i386/legacy.c b/sys/bus/pci/i386/legacy.c new file mode 100644 index 0000000000..60645cb35a --- /dev/null +++ b/sys/bus/pci/i386/legacy.c @@ -0,0 +1,360 @@ +/*- + * Copyright 1998 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/i386/i386/legacy.c,v 1.63.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * This code implements a system driver for legacy systems that do not + * support ACPI or when ACPI support is not present in the kernel. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEV_MCA +#ifdef DEV_MCA +#include +#endif + +#include + +static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device"); +struct legacy_device { + int lg_pcibus; +}; + +#define DEVTOAT(dev) ((struct legacy_device *)device_get_ivars(dev)) + +static void legacy_identify(driver_t *driver, device_t parent); +static int legacy_probe(device_t); +static int legacy_attach(device_t); +static int legacy_print_child(device_t, device_t); +static device_t legacy_add_child(device_t bus, device_t parent, int order, const char *name, + int unit); +static int legacy_read_ivar(device_t, device_t, int, uintptr_t *); +static int legacy_write_ivar(device_t, device_t, int, uintptr_t); + +static device_method_t legacy_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, legacy_identify), + DEVMETHOD(device_probe, legacy_probe), + DEVMETHOD(device_attach, legacy_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, legacy_print_child), + DEVMETHOD(bus_add_child, legacy_add_child), + DEVMETHOD(bus_read_ivar, legacy_read_ivar), + DEVMETHOD(bus_write_ivar, legacy_write_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t legacy_driver = { + "legacy", + legacy_methods, + 1, /* no softc */ +}; +static devclass_t legacy_devclass; + +DRIVER_MODULE(legacy, nexus, legacy_driver, legacy_devclass, 0, 0); + +static void +legacy_identify(driver_t *driver, device_t parent) +{ + + /* + * Add child device with order of 11 so it gets probed + * after ACPI (which is at order 10). + */ + if (BUS_ADD_CHILD(parent, parent, 11, "legacy", 0) == NULL) + panic("legacy: could not attach"); +} + +static int +legacy_probe(device_t dev) +{ + device_t acpi; + + /* + * Fail to probe if ACPI is ok. + */ + acpi = devclass_get_device(devclass_find("acpi"), 0); + if (acpi != NULL && device_is_alive(acpi)) + return (ENXIO); + device_set_desc(dev, "legacy system"); + device_quiet(dev); + return (0); +} + +static int +legacy_attach(device_t dev) +{ + device_t child; + + /* + * Let our child drivers identify any child devices that they + * can find. Once that is done attach any devices that we + * found. + */ + bus_generic_probe(dev); + bus_generic_attach(dev); + +#ifndef PC98 + /* + * If we didn't see EISA or ISA on a pci bridge, create some + * connection points now so they show up "on motherboard". + */ + if (!devclass_get_device(devclass_find("eisa"), 0)) { + child = BUS_ADD_CHILD(dev, dev, 0, "eisa", 0); + if (child == NULL) + panic("legacy_attach eisa"); + device_probe_and_attach(child); + } +#endif +#ifdef DEV_MCA + if (MCA_system && !devclass_get_device(devclass_find("mca"), 0)) { + child = BUS_ADD_CHILD(dev, dev, 0, "mca", 0); + if (child == 0) + panic("legacy_probe mca"); + device_probe_and_attach(child); + } +#endif + if (!devclass_get_device(devclass_find("isa"), 0)) { + child = BUS_ADD_CHILD(dev, dev, 0, "isa", 0); + if (child == NULL) + panic("legacy_attach isa"); + device_probe_and_attach(child); + } + + return 0; +} + +static int +legacy_print_child(device_t bus, device_t child) +{ + struct legacy_device *atdev = DEVTOAT(child); + int retval = 0; + + retval += bus_print_child_header(bus, child); + if (atdev->lg_pcibus != -1) + retval += kprintf(" pcibus %d", atdev->lg_pcibus); + retval += kprintf(" on motherboard\n"); /* XXX "motherboard", ick */ + + return (retval); +} + +static device_t +legacy_add_child(device_t bus, device_t parent, int order, const char *name, int unit) +{ + device_t child; + struct legacy_device *atdev; + atdev = kmalloc(sizeof(struct legacy_device), M_LEGACYDEV, + M_NOWAIT | M_ZERO); + if (atdev == NULL) + return(NULL); + atdev->lg_pcibus = -1; + + child = device_add_child_ordered(bus, order, name, unit); + if (child == NULL) { + kfree(atdev, M_LEGACYDEV); + } + else { + /* should we kfree this in legacy_child_detached? */ + device_set_ivars(child, atdev); + } + return (child); +} + +static int +legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct legacy_device *atdev = DEVTOAT(child); + + switch (which) { + case LEGACY_IVAR_PCIDOMAIN: + *result = 0; + break; + case LEGACY_IVAR_PCIBUS: + *result = atdev->lg_pcibus; + break; + default: + return ENOENT; + } + return 0; +} + +static int +legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct legacy_device *atdev = DEVTOAT(child); + + switch (which) { + case LEGACY_IVAR_PCIDOMAIN: + return EINVAL; + case LEGACY_IVAR_PCIBUS: + atdev->lg_pcibus = value; + break; + default: + return ENOENT; + } + return 0; +} + +#ifdef notyet +/* + * Legacy CPU attachment when ACPI is not available. Drivers like + * cpufreq(4) hang off this. + */ +static void cpu_identify(driver_t *driver, device_t parent); +static int cpu_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result); +static device_t cpu_add_child(device_t bus, int order, const char *name, + int unit); +static struct resource_list *cpu_get_rlist(device_t dev, device_t child); + +struct cpu_device { + struct resource_list cd_rl; + struct pcpu *cd_pcpu; +}; + +static device_method_t cpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, cpu_identify), + DEVMETHOD(device_probe, bus_generic_probe), + DEVMETHOD(device_attach, bus_generic_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_add_child, cpu_add_child), + DEVMETHOD(bus_read_ivar, cpu_read_ivar), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_get_resource_list, cpu_get_rlist), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t cpu_driver = { + "cpu", + cpu_methods, + 1, /* no softc */ +}; +static devclass_t cpu_devclass; +DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0); + +static void +cpu_identify(driver_t *driver, device_t parent) +{ + device_t child; + int i; + + /* + * Attach a cpuX device for each CPU. We use an order of 150 + * so that these devices are attached after the Host-PCI + * bridges (which are added at order 100). + */ + for (i = 0; i <= mp_maxid; i++) + if (!CPU_ABSENT(i)) { + child = BUS_ADD_CHILD(parent, 150, "cpu", i); + if (child == NULL) + panic("legacy_attach cpu"); + } +} + +static device_t +cpu_add_child(device_t bus, int order, const char *name, int unit) +{ + struct cpu_device *cd; + device_t child; + struct pcpu *pc; + + if ((cd = kmalloc(sizeof(*cd), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) + return (NULL); + + resource_list_init(&cd->cd_rl); + pc = pcpu_find(device_get_unit(bus)); + cd->cd_pcpu = pc; + + child = device_add_child_ordered(bus, order, name, unit); + if (child != NULL) { + pc->pc_device = child; + device_set_ivars(child, cd); + } else + kfree(cd, M_DEVBUF); + return (child); +} + +static struct resource_list * +cpu_get_rlist(device_t dev, device_t child) +{ + struct cpu_device *cpdev; + + cpdev = device_get_ivars(child); + return (&cpdev->cd_rl); +} + +static int +cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct cpu_device *cpdev; + + if (index != CPU_IVAR_PCPU) + return (ENOENT); + cpdev = device_get_ivars(child); + *result = (uintptr_t)cpdev->cd_pcpu; + return (0); +} +#endif diff --git a/sys/bus/pci/i386/pcibus.c b/sys/bus/pci/i386/pci_bus.c similarity index 51% rename from sys/bus/pci/i386/pcibus.c rename to sys/bus/pci/i386/pci_bus.c index 0858091a05..ca8e7cc249 100644 --- a/sys/bus/pci/i386/pcibus.c +++ b/sys/bus/pci/i386/pci_bus.c @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1997, Stefan Esser +/*- + * Copyright (c) 1997, Stefan Esser * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,12 +22,11 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/isa/pcibus.c,v 1.57.2.12 2003/08/07 06:19:26 imp Exp $ - * $DragonFly: src/sys/bus/pci/i386/pcibus.c,v 1.21 2008/09/05 10:39:36 hasso Exp $ - * + * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_bus.c,v 1.128.8.1 2009/04/15 03:14:26 kensmith Exp $"); */ +#include + #include "opt_pci.h" #include @@ -35,30 +34,85 @@ #include #include #include +#include #include #include #include -#include "pcibus.h" +#include #include -#include "pci_cfgreg.h" #include -#include +#include +#include "pci_cfgreg.h" #include "pcib_if.h" -static u_int32_t nexus_pcib_read_config(device_t, int, int, int, int, int); +static int pcibios_pcib_route_interrupt(device_t pcib, device_t dev, + int pin); + +int +legacy_pcib_maxslots(device_t dev) +{ + return 31; +} + +/* read configuration space register */ + +u_int32_t +legacy_pcib_read_config(device_t dev, int bus, int slot, int func, + int reg, int bytes) +{ + return(pci_cfgregread(bus, slot, func, reg, bytes)); +} + +/* write configuration space register */ + +void +legacy_pcib_write_config(device_t dev, int bus, int slot, int func, + int reg, u_int32_t data, int bytes) +{ + pci_cfgregwrite(bus, slot, func, reg, data, bytes); +} + +/* Pass MSI requests up to the nexus. */ + +static int +legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, + int *irqs) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, + irqs)); +} + +static int +legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); +} + +static int +legacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, + uint32_t *data) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); +} -/* - * Figure out if a PCI entity is a host bridge, return its name or NULL. - */ static const char * -nexus_legacypci_is_host_bridge(int bus, int slot, int func, - u_int32_t id, u_int8_t class, u_int8_t subclass, - u_int8_t *busnum) +legacy_pcib_is_host_bridge(int bus, int slot, int func, + uint32_t id, uint8_t class, uint8_t subclass, + uint8_t *busnum) { const char *s = NULL; - static u_int8_t pxb[4]; /* hack for 450nx */ + static uint8_t pxb[4]; /* hack for 450nx */ *busnum = 0; @@ -66,7 +120,7 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, case 0x12258086: s = "Intel 824?? host to PCI bridge"; /* XXX This is a guess */ - /* *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x41, 1); */ + /* *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x41, 1); */ *busnum = bus; break; case 0x71208086: @@ -78,6 +132,9 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, case 0x71248086: s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; break; + case 0x11308086: + s = "Intel 82815 (i815 GMCH) Host To Hub bridge"; + break; case 0x71808086: s = "Intel 82443LX (440 LX) host to PCI bridge"; break; @@ -101,27 +158,27 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, break; case 0x84c48086: s = "Intel 82454KX/GX (Orion) host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x4a, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x4a, 1); break; case 0x84ca8086: /* * For the 450nx chipset, there is a whole bundle of - * things pretending to be host bridges. The MIOC will + * things pretending to be host bridges. The MIOC will * be seen first and isn't really a pci bridge (the - * actual busses are attached to the PXB's). We need to + * actual busses are attached to the PXB's). We need to * read the registers of the MIOC to figure out the * bus numbers for the PXB channels. * * Since the MIOC doesn't have a pci bus attached, we * pretend it wasn't there. */ - pxb[0] = nexus_pcib_read_config(0, bus, slot, func, + pxb[0] = legacy_pcib_read_config(0, bus, slot, func, 0xd0, 1); /* BUSNO[0] */ - pxb[1] = nexus_pcib_read_config(0, bus, slot, func, + pxb[1] = legacy_pcib_read_config(0, bus, slot, func, 0xd1, 1) + 1; /* SUBA[0]+1 */ - pxb[2] = nexus_pcib_read_config(0, bus, slot, func, + pxb[2] = legacy_pcib_read_config(0, bus, slot, func, 0xd3, 1); /* BUSNO[1] */ - pxb[3] = nexus_pcib_read_config(0, bus, slot, func, + pxb[3] = legacy_pcib_read_config(0, bus, slot, func, 0xd4, 1) + 1; /* SUBA[1]+1 */ return NULL; case 0x84cb8086: @@ -144,9 +201,6 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, break; } break; - case 0x1A308086: - s = "Intel 82845 Host to PCI bridge"; - break; /* AMD -- vendor 0x1022 */ case 0x30001022: @@ -154,8 +208,8 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, #ifdef CPU_ELAN init_AMD_Elan_sc520(); #else - kprintf("*** WARNING: kernel option CPU_ELAN missing"); - kprintf("-- timekeeping may be wrong\n"); + kprintf( +"*** WARNING: missing CPU_ELAN -- timekeeping may be wrong\n"); #endif break; case 0x70061022: @@ -212,9 +266,9 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, /* ServerWorks -- vendor 0x1166 */ case 0x00051166: s = "ServerWorks NB6536 2.0HE host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); break; - + case 0x00061166: /* FALLTHROUGH */ case 0x00081166: @@ -222,26 +276,25 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, case 0x02011166: /* FALLTHROUGH */ case 0x010f1014: /* IBM re-badged ServerWorks chipset */ - /* FALLTHROUGH */ s = "ServerWorks host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); break; case 0x00091166: s = "ServerWorks NB6635 3.0LE host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); break; case 0x00101166: s = "ServerWorks CIOB30 host to PCI bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); break; case 0x00111166: /* FALLTHROUGH */ case 0x03021014: /* IBM re-badged ServerWorks chipset */ s = "ServerWorks CMIC-HE host to PCI-X bridge"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); break; /* XXX unknown chipset, but working */ @@ -249,7 +302,13 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, /* FALLTHROUGH */ case 0x01011166: s = "ServerWorks host to PCI bridge(unknown chipset)"; - *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1); + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); + break; + + /* Compaq/HP -- vendor 0x0e11 */ + case 0x60100e11: + s = "Compaq/HP Model 6010 HotPlug PCI Bridge"; + *busnum = legacy_pcib_read_config(0, bus, slot, func, 0xc8, 1); break; /* Integrated Micro Solutions -- vendor 0x10e0 */ @@ -266,75 +325,51 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func, return s; } -/* - * Identify the existance of the first pci bus and install a child to - * nexus if we find it. Use an order of 1 so it gets probed after - * any ACPI device installed under nexus. To avoid boot-time confusion, - * we do not install any 'pcib' devices at this time. - * - * The identify method coupled with the driver spec of the same name - * automatically installs it under the nexus. - */ -static int -nexus_legacypci_identify(driver_t *driver, device_t parent) -{ - /* - * Basically a static device, there's no point reinstalling it - * on rescan. - */ - if (device_get_state(parent) == DS_ATTACHED) - return (0); - if (device_get_state(parent) == DS_INPROGRESS) - return (0); - - if (pci_cfgregopen() == 0) - return (ENXIO); - - BUS_ADD_CHILD(parent, parent, 100, "legacypci", 0); - return (0); -} - /* * Scan the first pci bus for host-pci bridges and add pcib instances * to the nexus for each bridge. */ -static int -nexus_legacypci_probe(device_t dev) +static void +legacy_pcib_identify(driver_t *driver, device_t parent) { int bus, slot, func; u_int8_t hdrtype; int found = 0; int pcifunchigh; int found824xx = 0; + int found_orion = 0; device_t child; + devclass_t pci_devclass; + if (pci_cfgregopen() == 0) + return; /* - * Do not install any pci busses ('pcib' devices) if the PCI - * subsystem has already been claimed by someone else. + * Check to see if we haven't already had a PCI bus added + * via some other means. If we have, bail since otherwise + * we're going to end up duplicating it. */ - if (pcib_owner != NULL) { - device_printf(dev, "PCI subsystem owned by %s, skipping scan\n", - pcib_owner); - return (ENXIO); - } - pcib_owner = "legacypci"; + if ((pci_devclass = devclass_find("pci")) && + devclass_get_device(pci_devclass, 0)) + return; - if (pci_cfgregopen() == 0) - return (ENXIO); - /* - * Scan away! - */ bus = 0; retry: for (slot = 0; slot <= PCI_SLOTMAX; slot++) { func = 0; - hdrtype = nexus_pcib_read_config(0, bus, slot, func, + hdrtype = legacy_pcib_read_config(0, bus, slot, func, PCIR_HDRTYPE, 1); - if ((hdrtype & ~PCIM_MFDEV) > 2) + /* + * When enumerating bus devices, the standard says that + * one should check the header type and ignore the slots whose + * header types that the software doesn't know about. We use + * this to filter out devices. + */ + if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; - if (hdrtype & PCIM_MFDEV) - pcifunchigh = 7; + if ((hdrtype & PCIM_MFDEV) && + (!found_orion || hdrtype != 0xff)) + pcifunchigh = PCI_FUNCMAX; else pcifunchigh = 0; for (func = 0; func <= pcifunchigh; func++) { @@ -347,16 +382,16 @@ nexus_legacypci_probe(device_t dev) device_t *devs; int ndevs, i; - id = nexus_pcib_read_config(0, bus, slot, func, + id = legacy_pcib_read_config(0, bus, slot, func, PCIR_DEVVENDOR, 4); if (id == -1) continue; - class = nexus_pcib_read_config(0, bus, slot, func, + class = legacy_pcib_read_config(0, bus, slot, func, PCIR_CLASS, 1); - subclass = nexus_pcib_read_config(0, bus, slot, func, + subclass = legacy_pcib_read_config(0, bus, slot, func, PCIR_SUBCLASS, 1); - s = nexus_legacypci_is_host_bridge(bus, slot, func, + s = legacy_pcib_is_host_bridge(bus, slot, func, id, class, subclass, &busnum); if (s == NULL) @@ -364,15 +399,15 @@ nexus_legacypci_probe(device_t dev) /* * Check to see if the physical bus has already - * been seen. Eg: hybrid 32 and 64 bit host + * been seen. Eg: hybrid 32 and 64 bit host * bridges to the same logical bus. */ - if (device_get_children(dev, &devs, &ndevs) == 0) { + if (device_get_children(parent, &devs, &ndevs) == 0) { for (i = 0; s != NULL && i < ndevs; i++) { if (strcmp(device_get_name(devs[i]), "pcib") != 0) continue; - if (nexus_get_pcibus(devs[i]) == busnum) + if (legacy_get_pcibus(devs[i]) == busnum) s = NULL; } kfree(devs, M_TEMP); @@ -380,18 +415,21 @@ nexus_legacypci_probe(device_t dev) if (s == NULL) continue; + /* - * Add at priority 100+busnum to keep the scanning - * order sane in the boot dmesg output. + * Add at priority 100 to make sure we + * go after any motherboard resources */ - child = BUS_ADD_CHILD(dev, dev, 100 + busnum, + child = BUS_ADD_CHILD(parent, parent, 100 + busnum, "pcib", busnum); device_set_desc(child, s); - nexus_set_pcibus(child, busnum); + legacy_set_pcibus(child, busnum); found = 1; if (id == 0x12258086) found824xx = 1; + if (id == 0x84c48086) + found_orion = 1; } } if (found824xx && bus == 0) { @@ -399,199 +437,126 @@ nexus_legacypci_probe(device_t dev) goto retry; } -#if 0 - /* - * Now that we have installed the main PCI bridges, go - * probe and attach each one. - */ - bus_generic_attach(dev); -#endif - /* * Make sure we add at least one bridge since some old * hardware doesn't actually have a host-pci bridge device. * Note that pci_cfgregopen() thinks we have PCI devices.. */ if (!found) { - if (bootverbose) { - kprintf("nexus_pcib_identify: no bridge found, " - "adding pcib0 anyway\n"); - } - child = BUS_ADD_CHILD(dev, dev, 100, "pcib", 0); - nexus_set_pcibus(child, 0); + if (bootverbose) + kprintf( + "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n"); + child = BUS_ADD_CHILD(parent, parent, 100, "pcib", 0); + legacy_set_pcibus(child, 0); } - return (0); } static int -nexus_legacypci_attach(device_t dev) +legacy_pcib_probe(device_t dev) { - bus_generic_attach(dev); - return (0); + if (pci_cfgregopen() == 0) + return ENXIO; + return -100; } -#ifdef PCI_MAP_FIXUP - -SYSCTL_DECL(_hw_pci); - -static unsigned long legacy_host_mem_start = 0x80000000; -/* XXX need TUNABLE_ULONG? */ -TUNABLE_INT("hw.pci.host_mem_start", (int *)&legacy_host_mem_start); -SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD, - &legacy_host_mem_start, 0x80000000, - "Limit the host bridge memory to being above this address. " - "Must be\n" - "set at boot via hw.pci.host_mem_start tunable."); - -static struct resource * -nexus_legacypci_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, - u_int flags) +static int +legacy_pcib_attach(device_t dev) { - /* - * If no memory preference is given, use upper 32MB slot most - * bioses use for their memory window. Typically other bridges - * before us get in the way to assert their preferences on memory. - * Hardcoding like this sucks, so a more MD/MI way needs to be - * found to do it. This is typically only used on older laptops - * that don't have pci busses behind pci bridge, so assuming > 32MB - * is likely OK. - * - * However, this can cause problems for other chipsets, so we make - * this tunable by hw.pci.host_mem_start. - */ - if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) - start = legacy_host_mem_start; - if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) - start = 0x1000; - return bus_generic_alloc_resource(dev, child, type, rid, - start, end, count, flags); -} - -#endif /* PCI_MAP_FIXUP */ - -static device_method_t legacypci_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, nexus_legacypci_identify), - DEVMETHOD(device_probe, nexus_legacypci_probe), - DEVMETHOD(device_attach, nexus_legacypci_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + device_t pir; + int bus; /* - * Bus interface - propogate through to the nexus. Note that - * this means devices under us will have nexus ivars. + * Look for a PCI BIOS interrupt routing table as that will be + * our method of routing interrupts if we have one. */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), -#ifdef PCI_MAP_FIXUP - DEVMETHOD(bus_alloc_resource, nexus_legacypci_alloc_resource), -#else - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), -#endif - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - DEVMETHOD(bus_set_resource, bus_generic_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_get_resource), - DEVMETHOD(bus_delete_resource, bus_generic_delete_resource), - { 0, 0 } -}; - -static driver_t legacypci_driver = { - "legacypci", - legacypci_methods, - 1, -}; - -static devclass_t legacypci_devclass; - -DRIVER_MODULE(legacypci, nexus, legacypci_driver, legacypci_devclass, 0, 0); - -/* - * Legacypci Host-Bridge PCI BUS support. The underlying pcib devices - * will only exist if we actually control the PCI bus. The actual PCI - * bus driver is attached in our attach routine. - * - * There is no identify function because the legacypci placeholder will - * have already scanned and added PCIB devices for the host-bridges found. - */ -static int -nexus_pcib_maxslots(device_t dev) -{ - return 31; -} - -/* - * Read configuration space register. - */ -static u_int32_t -nexus_pcib_read_config(device_t dev, int bus, int slot, int func, - int reg, int bytes) -{ - return (pci_cfgregread(bus, slot, func, reg, bytes)); + bus = pcib_get_bus(dev); + if (pci_pir_probe(bus, 0)) { + pir = BUS_ADD_CHILD(device_get_parent(dev), device_get_parent(dev), 0, "pir", 0); + if (pir != NULL) + device_probe_and_attach(pir); + } + device_add_child(dev, "pci", bus); + return bus_generic_attach(dev); } -/* - * Write configuration space register. - */ -static void -nexus_pcib_write_config(device_t dev, int bus, int slot, int func, - int reg, u_int32_t data, int bytes) +int +legacy_pcib_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result) { - pci_cfgregwrite(bus, slot, func, reg, data, bytes); -} -/* - * Stack a pci device on top of the pci bridge bus device. - */ -static int -nexus_pcib_probe(device_t dev) -{ - BUS_ADD_CHILD(dev, dev, 0, "pci", device_get_unit(dev)); - return (0); + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = 0; + return 0; + case PCIB_IVAR_BUS: + *result = legacy_get_pcibus(dev); + return 0; + } + return ENOENT; } -static int -nexus_pcib_attach(device_t dev) +int +legacy_pcib_write_ivar(device_t dev, device_t child, int which, + uintptr_t value) { - int error; - error = bus_generic_attach(dev); - return (error); + switch (which) { + case PCIB_IVAR_DOMAIN: + return EINVAL; + case PCIB_IVAR_BUS: + legacy_set_pcibus(dev, value); + return 0; + } + return ENOENT; } -/* route interrupt */ +SYSCTL_DECL(_hw_pci); -static int -nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin) +static unsigned long legacy_host_mem_start = 0x80000000; +TUNABLE_INT("hw.pci.host_mem_start", &legacy_host_mem_start); +SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD, + &legacy_host_mem_start, 0x80000000, + "Limit the host bridge memory to being above this address. Must be\n\ +set at boot via a tunable."); + +struct resource * +legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) { - return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin, - pci_get_irq(dev))); + /* + * If no memory preference is given, use upper 32MB slot most + * bioses use for their memory window. Typically other bridges + * before us get in the way to assert their preferences on memory. + * Hardcoding like this sucks, so a more MD/MI way needs to be + * found to do it. This is typically only used on older laptops + * that don't have pci busses behind pci bridge, so assuming > 32MB + * is liekly OK. + * + * However, this can cause problems for other chipsets, so we make + * this tunable by hw.pci.host_mem_start. + */ + if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) + start = legacy_host_mem_start; + if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) + start = 0x1000; + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, + count, flags)); } -static device_method_t nexus_pcib_methods[] = { +static device_method_t legacy_pcib_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, nexus_pcib_probe), - DEVMETHOD(device_attach, nexus_pcib_attach), + DEVMETHOD(device_identify, legacy_pcib_identify), + DEVMETHOD(device_probe, legacy_pcib_probe), + DEVMETHOD(device_attach, legacy_pcib_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), - /* - * Bus interface - propogate through to the nexus. Note - * that this means we will get nexus-managed ivars. - */ - DEVMETHOD(bus_add_child, bus_generic_add_child), + /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), + DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), + DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), @@ -599,86 +564,38 @@ static device_method_t nexus_pcib_methods[] = { DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ - DEVMETHOD(pcib_maxslots, nexus_pcib_maxslots), - DEVMETHOD(pcib_read_config, nexus_pcib_read_config), - DEVMETHOD(pcib_write_config, nexus_pcib_write_config), - DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt), - + DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), + DEVMETHOD(pcib_read_config, legacy_pcib_read_config), + DEVMETHOD(pcib_write_config, legacy_pcib_write_config), + DEVMETHOD(pcib_route_interrupt, pcibios_pcib_route_interrupt), +#ifdef notyet + DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), + DEVMETHOD(pcib_release_msi, pcib_release_msi), + DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), + DEVMETHOD(pcib_release_msix, pcib_release_msix), + DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi), +#endif { 0, 0 } }; -static driver_t nexus_pcib_driver = { - "pcib", - nexus_pcib_methods, - 1, -}; +static devclass_t hostb_devclass; -static devclass_t pcib_devclass; - -DRIVER_MODULE(pcib, legacypci, nexus_pcib_driver, pcib_devclass, 0, 0); - - -/* - * Provide a device to "eat" the host->pci bridges that we dug up above - * and stop them showing up twice on the probes. This also stops them - * showing up as 'none' in pciconf -l. - * - * Return an ultra-low priority so other devices can attach the bus before - * our dummy attach. - * - * XXX may have to disable the registration entirely to support module-loaded - * bridges such as agp.ko. - */ -static int -pci_hostb_probe(device_t dev) -{ - if (pci_get_class(dev) == PCIC_BRIDGE && - pci_get_subclass(dev) == PCIS_BRIDGE_HOST) { - device_set_desc(dev, "Host to PCI bridge"); - device_quiet(dev); - return -10000; - } - return (ENXIO); -} - -static int -pci_hostb_attach(device_t dev) -{ - return (0); -} - -static device_method_t pci_hostb_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pci_hostb_probe), - DEVMETHOD(device_attach, pci_hostb_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - { 0, 0 } -}; -static driver_t pci_hostb_driver = { - "hostb", - pci_hostb_methods, - 1, -}; -static devclass_t pci_hostb_devclass; - -DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0); +DEFINE_CLASS_0(pcib, legacy_pcib_driver, legacy_pcib_methods, 1); +DRIVER_MODULE(pcib, legacy, legacy_pcib_driver, hostb_devclass, 0, 0); /* * Install placeholder to claim the resources owned by the - * PCI bus interface. This could be used to extract the + * PCI bus interface. This could be used to extract the * config space registers in the extreme case where the PnP * ID is available and the PCI BIOS isn't, but for now we just * eat the PnP ID and do nothing else. * - * XXX we should silence this probe, as it will generally confuse + * XXX we should silence this probe, as it will generally confuse * people. */ static struct isa_pnp_id pcibus_pnp_ids[] = { - { 0x030ad041 /* PNP030A */, "PCI Bus" }, + { 0x030ad041 /* PNP0A03 */, "PCI Bus" }, { 0 } }; @@ -686,10 +603,10 @@ static int pcibus_pnp_probe(device_t dev) { int result; - + if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0) device_quiet(dev); - return (result); + return(result); } static int @@ -709,13 +626,78 @@ static device_method_t pcibus_pnp_methods[] = { { 0, 0 } }; -static driver_t pcibus_pnp_driver = { - "pcibus_pnp", - pcibus_pnp_methods, - 1, /* no softc */ -}; - static devclass_t pcibus_pnp_devclass; +DEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1); DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); + +/* + * Provide a PCI-PCI bridge driver for PCI busses behind PCI-PCI bridges + * that appear in the PCIBIOS Interrupt Routing Table to use the routing + * table for interrupt routing when possible. + */ +static int pcibios_pcib_probe(device_t bus); + +static device_method_t pcibios_pcib_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pcibios_pcib_probe), + DEVMETHOD(device_attach, pcib_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, pcib_read_ivar), + DEVMETHOD(bus_write_ivar, pcib_write_ivar), + DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_read_config, pcib_read_config), + DEVMETHOD(pcib_write_config, pcib_write_config), + DEVMETHOD(pcib_route_interrupt, pcibios_pcib_route_interrupt), + DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), + DEVMETHOD(pcib_release_msi, pcib_release_msi), + DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), + DEVMETHOD(pcib_release_msix, pcib_release_msix), + DEVMETHOD(pcib_map_msi, pcib_map_msi), + + {0, 0} +}; + +static devclass_t pcib_devclass; + +DEFINE_CLASS_0(pcib, pcibios_pcib_driver, pcibios_pcib_pci_methods, + sizeof(struct pcib_softc)); +DRIVER_MODULE(pcibios_pcib, pci, pcibios_pcib_driver, pcib_devclass, 0, 0); + +static int +pcibios_pcib_probe(device_t dev) +{ + int bus; + + if ((pci_get_class(dev) != PCIC_BRIDGE) || + (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) + return (ENXIO); + bus = pci_read_config(dev, PCIR_SECBUS_1, 1); + if (bus == 0) + return (ENXIO); + if (!pci_pir_probe(bus, 1)) + return (ENXIO); + device_set_desc(dev, "PCIBIOS PCI-PCI bridge"); + return (-2000); +} + +static int +pcibios_pcib_route_interrupt(device_t pcib, device_t dev, int pin) +{ + return (pci_pir_route_interrupt(pci_get_bus(dev), pci_get_slot(dev), + pci_get_function(dev), pin)); +} diff --git a/sys/bus/pci/i386/pci_cfgreg.c b/sys/bus/pci/i386/pci_cfgreg.c index 137d0fd4b6..ec81352d46 100644 --- a/sys/bus/pci/i386/pci_cfgreg.c +++ b/sys/bus/pci/i386/pci_cfgreg.c @@ -1,7 +1,8 @@ -/* - * Copyright (c) 1997, Stefan Esser - * Copyright (c) 2000, Michael Smith +/*- + * Copyright (c) 1997, Stefan Esser + * Copyright (c) 2000, Michael Smith * Copyright (c) 2000, BSDi + * Copyright (c) 2004, Scott Long * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,68 +25,86 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $ - * $DragonFly: src/sys/bus/pci/i386/pci_cfgreg.c,v 1.15 2008/08/02 05:22:20 dillon Exp $ - * + * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.2.6.1 2009/04/15 03:14:26 kensmith Exp $"); */ -#include /* XXX trim includes */ +#if defined(__DragonFly__) +#define mtx_init(a, b, c, d) spin_init(a) +#define mtx_lock_spin(a) spin_lock_wr(a) +#define mtx_unlock_spin(a) spin_unlock_wr(a) +#endif + +#include + +#include #include #include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include #include "pci_cfgreg.h" -#include #include -#include + +#include +#include +#include +#include +#include +#include #define PRVERB(a) do { \ if (bootverbose) \ kprintf a ; \ } while(0) -static int pci_disable_bios_route = 0; -SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD, - &pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS"); -TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route); - +#define PCIE_CACHE 8 +struct pcie_cfg_elem { + TAILQ_ENTRY(pcie_cfg_elem) elem; + vm_offset_t vapage; + vm_paddr_t papage; +}; + +enum { + CFGMECH_NONE = 0, + CFGMECH_1, + CFGMECH_2, + CFGMECH_PCIE, +}; + +static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; +static uint32_t pciebar; static int cfgmech; static int devmax; +#if defined(__DragonFly__) +static struct spinlock pcicfg_mtx; +#else +static struct mtx pcicfg_mtx; +#endif -static int pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq); -static int pci_cfgintr_unique(struct PIR_entry *pe, int pin); -static int pci_cfgintr_linked(struct PIR_entry *pe, int pin); -static int pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin); -static int pci_cfgintr_virgin(struct PIR_entry *pe, int pin); - -static void pci_print_irqmask(u_int16_t irqs); -static void pci_print_route_table(struct PIR_table *prt, int size); static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); static int pcireg_cfgopen(void); -static struct PIR_table *pci_route_table; -static int pci_route_count; +static int pciereg_cfgopen(void); +static int pciereg_cfgread(int bus, int slot, int func, int reg, + int bytes); +static void pciereg_cfgwrite(int bus, int slot, int func, int reg, + int data, int bytes); /* * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. Some use + * 0 in the intline rather than 255 to indicate none. Some use * numbers in the range 128-254 to indicate something strange and - * apparently undocumented anywhere. Assume these are completely bogus + * apparently undocumented anywhere. Assume these are completely bogus * and map them to 255, which means "none". */ -static int -pci_map_intline(int line) +static __inline int +pci_i386_map_intline(int line) { if (line == 0 || line >= 128) return (PCI_INVALID_IRQ); @@ -120,57 +139,47 @@ int pci_cfgregopen(void) { static int opened = 0; - u_long sigaddr; - static struct PIR_table *pt; + u_int16_t vid, did; u_int16_t v; - u_int8_t ck, *cv; - int i; - if (opened) - return (1); + return(1); if (pcireg_cfgopen() == 0) - return (0); + return(0); v = pcibios_get_version(); if (v > 0) - kprintf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, - v & 0xff); + PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, + v & 0xff)); + mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); + opened = 1; + + /* $PIR requires PCI BIOS 2.10 or greater. */ + if (v >= 0x0210) + pci_pir_open(); /* - * Look for the interrupt routing table. - * - * We use PCI BIOS's PIR table if it's available $PIR is the - * standard way to do this. Sadly some machines are not - * standards conforming and have _PIR instead. We shrug and cope - * by looking for both. + * Grope around in the PCI config space to see if this is a + * chipset that is capable of doing memory-mapped config cycles. + * This also implies that it can do PCIe extended config cycles. */ - if (pcibios_get_version() >= 0x0210 && pt == NULL) { - sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); - if (sigaddr == 0) - sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); - if (sigaddr != 0) { - pt = (struct PIR_table *)(uintptr_t) - BIOS_PADDRTOVADDR(sigaddr); - for (cv = (u_int8_t *)pt, ck = 0, i = 0; - i < (pt->pt_header.ph_length); i++) - ck += cv[i]; - if (ck == 0 && pt->pt_header.ph_length > - sizeof(struct PIR_header)) { - pci_route_table = pt; - pci_route_count = (pt->pt_header.ph_length - - sizeof(struct PIR_header)) / - sizeof(struct PIR_entry); - kprintf("Using $PIR table, %d entries at %p\n", - pci_route_count, pci_route_table); - if (bootverbose) - pci_print_route_table(pci_route_table, - pci_route_count); - } + + /* Check for supported chipsets */ + vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); + did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); + if (vid == 0x8086) { + if (did == 0x3590 || did == 0x3592) { + /* Intel 7520 or 7320 */ + pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; + pciereg_cfgopen(); + } else if (did == 0x2580 || did == 0x2584) { + /* Intel 915 or 925 */ + pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); + pciereg_cfgopen(); } } - opened = 1; - return (1); + + return(1); } /* @@ -180,48 +189,7 @@ u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes) { uint32_t line; -#ifdef APIC_IO - uint32_t pin; - /* - * If we are using the APIC, the contents of the intline - * register will probably be wrong (since they are set up for - * use with the PIC. Rather than rewrite these registers - * (maybe that would be smarter) we trap attempts to read them - * and translate to our private vector numbers. - */ - if ((reg == PCIR_INTLINE) && (bytes == 1)) { - - pin = pcireg_cfgread(bus, slot, func, PCIR_INTPIN, 1); - line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); - - if (pin != 0) { - int airq; - - airq = pci_apic_irq(bus, slot, pin); - if (airq >= 0) { - /* PCI specific entry found in MP table */ - if (airq != line) - undirect_pci_irq(line); - return (airq); - } else { - /* - * PCI interrupts might be redirected to the - * ISA bus according to some MP tables. Use the - * same methods as used by the ISA devices - * devices to find the proper IOAPIC int pin. - */ - airq = isa_apic_irq(line); - if ((airq >= 0) && (airq != line)) { - /* XXX: undirect_pci_irq() ? */ - undirect_isa_irq(line); - return (airq); - } - } - } - return (line); - } -#else /* * Some BIOS writers seem to want to ignore the spec and put * 0 in the intline rather than 255 to indicate none. The rest of @@ -229,9 +197,8 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) */ if (reg == PCIR_INTLINE && bytes == 1) { line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); - return pci_map_intline(line); + return (pci_i386_map_intline(line)); } -#endif /* APIC_IO */ return (pcireg_cfgread(bus, slot, func, reg, bytes)); } @@ -241,381 +208,52 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) { - pcireg_cfgwrite(bus, slot, func, reg, data, bytes); -} - -int -pci_cfgread(pcicfgregs *cfg, int reg, int bytes) -{ - return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes)); -} -void -pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) -{ - pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes); + pcireg_cfgwrite(bus, slot, func, reg, data, bytes); } - -/* - * Route a PCI interrupt +/* + * Configuration space access using direct register operations */ -int -pci_cfgintr(int bus, int device, int pin, int oldirq) -{ - struct PIR_entry *pe; - int i, irq; - struct bios_regs args; - u_int16_t v; - int already = 0; - int errok = 0; - - v = pcibios_get_version(); - if (v < 0x0210) { - PRVERB(( - "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n", - (v & 0xff00) >> 8, v & 0xff)); - return (PCI_INVALID_IRQ); - } - if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || - (pin < 1) || (pin > 4)) - return (PCI_INVALID_IRQ); - - /* - * Scan the entry table for a contender - */ - for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; - i++, pe++) { - if ((bus != pe->pe_bus) || (device != pe->pe_device)) - continue; +/* enable configuration space accesses and return data port address */ +static int +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; +#ifdef XBOX + if (arch_i386_is_xbox) { /* - * A link of 0 means that this intpin is not connected to - * any other device's interrupt pins and is not connected to - * any of the Interrupt Router's interrupt pins, so we can't - * route it. + * The Xbox MCPX chipset is a derivative of the nForce 1 + * chipset. It almost has the same bus layout; some devices + * cannot be used, because they have been removed. */ - if (pe->pe_intpin[pin - 1].link == 0) - continue; - - if (pci_cfgintr_valid(pe, pin, oldirq)) { - kprintf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus, - device, 'A' + pin - 1, oldirq); - return (oldirq); - } /* - * We try to find a linked interrupt, then we look to see - * if the interrupt is uniquely routed, then we look for - * a virgin interrupt. The virgin interrupt should return - * an interrupt we can route, but if that fails, maybe we - * should try harder to route a different interrupt. - * However, experience has shown that that's rarely the - * failure mode we see. + * Devices 00:00.1 and 00:00.2 used to be memory controllers on + * the nForce chipset, but on the Xbox, using them will lockup + * the chipset. */ - irq = pci_cfgintr_linked(pe, pin); - if (irq != PCI_INVALID_IRQ) - already = 1; - if (irq == PCI_INVALID_IRQ) { - irq = pci_cfgintr_unique(pe, pin); - if (irq != PCI_INVALID_IRQ) - errok = 1; - } - if (irq == PCI_INVALID_IRQ) - irq = pci_cfgintr_virgin(pe, pin); - - if (irq == PCI_INVALID_IRQ) - break; - - if (pci_disable_bios_route != 0) - break; + if (bus == 0 && slot == 0 && (func == 1 || func == 2)) + return dataport; + /* - * Ask the BIOS to route the interrupt. If we picked an - * interrupt that failed, we should really try other - * choices that the BIOS offers us. - * - * For uniquely routed interrupts, we need to try - * to route them on some machines. Yet other machines - * fail to route, so we have to pretend that in that - * case it worked. Isn't PC hardware fun? - * - * NOTE: if we want to whack hardware to do this, then - * I think the right way to do that would be to have - * bridge drivers that do this. I'm not sure that the - * $PIR table would be valid for those interrupt - * routers. + * Bus 1 only contains a VGA controller at 01:00.0. When you try + * to probe beyond that device, you only get garbage, which + * could cause lockups. */ - args.eax = PCIBIOS_ROUTE_INTERRUPT; - args.ebx = (bus << 8) | (device << 3); - /* pin value is 0xa - 0xd */ - args.ecx = (irq << 8) | (0xa + pin -1); - if (!already && - bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) && - !errok) { - PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n")); - return (PCI_INVALID_IRQ); - } - kprintf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, - device, 'A' + pin - 1, irq); - return(irq); - } - - PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c oldirq=%d\n", bus, - device, 'A' + pin - 1, oldirq)); - return (PCI_INVALID_IRQ); -} - -/* - * Check to see if an existing IRQ setting is valid. - */ -static int -pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq) -{ - uint32_t irqmask; - - if (!PCI_INTERRUPT_VALID(irq)) - return (0); - irqmask = pe->pe_intpin[pin - 1].irqs; - if (irqmask & (1 << irq)) { - PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq)); - return (1); - } - return (0); -} - -/* - * Look to see if the routing table claims this pin is uniquely routed. - */ -static int -pci_cfgintr_unique(struct PIR_entry *pe, int pin) -{ - int irq; - uint32_t irqmask; - - irqmask = pe->pe_intpin[pin - 1].irqs; - if(irqmask != 0 && powerof2(irqmask)) { - irq = ffs(irqmask) - 1; - PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); - return (irq); - } - return (PCI_INVALID_IRQ); -} - -/* - * Look for another device which shares the same link byte and - * already has a unique IRQ, or which has had one routed already. - */ -static int -pci_cfgintr_linked(struct PIR_entry *pe, int pin) -{ - struct PIR_entry *oe; - struct PIR_intpin *pi; - int i, j, irq; - - /* - * Scan table slots. - */ - for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; - i++, oe++) { - /* scan interrupt pins */ - for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { - - /* don't look at the entry we're trying to match */ - if ((pe == oe) && (j == (pin - 1))) - continue; - /* compare link bytes */ - if (pi->link != pe->pe_intpin[pin - 1].link) - continue; - /* link destination mapped to a unique interrupt? */ - if (pi->irqs != 0 && powerof2(pi->irqs)) { - irq = ffs(pi->irqs) - 1; - PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", - pi->link, irq)); - return(irq); - } - - /* - * look for the real PCI device that matches this - * table entry - */ - irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, - j + 1, pin); - if (irq != PCI_INVALID_IRQ) - return (irq); - } - } - return (PCI_INVALID_IRQ); -} - -/* - * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and - * see if it has already been assigned an interrupt. - */ -static int -pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) -{ - devclass_t pci_devclass; - device_t *pci_devices; - int pci_count; - device_t *pci_children; - int pci_childcount; - device_t *busp, *childp; - int i, j, irq; - - /* - * Find all the PCI busses. - */ - pci_count = 0; - if ((pci_devclass = devclass_find("pci")) != NULL) - devclass_get_devices(pci_devclass, &pci_devices, &pci_count); - - /* - * Scan all the PCI busses/devices looking for this one. - */ - irq = PCI_INVALID_IRQ; - for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ); - i++, busp++) { - pci_childcount = 0; - device_get_children(*busp, &pci_children, &pci_childcount); + if (bus == 1 && (slot != 0 || func != 0)) + return dataport; - for (j = 0, childp = pci_children; j < pci_childcount; j++, - childp++) { - if ((pci_get_bus(*childp) == bus) && - (pci_get_slot(*childp) == device) && - (pci_get_intpin(*childp) == matchpin)) { - irq = pci_map_intline(pci_get_irq(*childp)); - if (irq != PCI_INVALID_IRQ) - PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", - pe->pe_intpin[pin - 1].link, irq, - pci_get_bus(*childp), - pci_get_slot(*childp), - pci_get_function(*childp))); - break; - } - } - if (pci_children != NULL) - kfree(pci_children, M_TEMP); - } - if (pci_devices != NULL) - kfree(pci_devices, M_TEMP); - return (irq); -} - -/* - * Pick a suitable IRQ from those listed as routable to this device. - */ -static int -pci_cfgintr_virgin(struct PIR_entry *pe, int pin) -{ - int irq, ibit; - - /* - * first scan the set of PCI-only interrupts and see if any of these - * are routable - */ - for (irq = 0; irq < 16; irq++) { - ibit = (1 << irq); - - /* can we use this interrupt? */ - if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && - (pe->pe_intpin[pin - 1].irqs & ibit)) { - PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq)); - return (irq); - } - } - - /* life is tough, so just pick an interrupt */ - for (irq = 0; irq < 16; irq++) { - ibit = (1 << irq); - - if (pe->pe_intpin[pin - 1].irqs & ibit) { - PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq)); - return (irq); - } - } - return (PCI_INVALID_IRQ); -} - -static void -pci_print_irqmask(u_int16_t irqs) -{ - int i, first; - - if (irqs == 0) { - kprintf("none"); - return; - } - first = 1; - for (i = 0; i < 16; i++, irqs >>= 1) - if (irqs & 1) { - if (!first) - kprintf(" "); - else - first = 0; - kprintf("%d", i); - } -} - -/* - * Dump the contents of a PCI BIOS Interrupt Routing Table to the console. - */ -static void -pci_print_route_table(struct PIR_table *ptr, int size) -{ - struct PIR_entry *entry; - struct PIR_intpin *intpin; - int i, pin; - - kprintf("PCI-Only Interrupts: "); - pci_print_irqmask(ptr->pt_header.ph_pci_irqs); - kprintf("\nLocation Bus Device Pin Link IRQs\n"); - entry = &ptr->pt_entry[0]; - for (i = 0; i < size; i++, entry++) { - intpin = &entry->pe_intpin[0]; - for (pin = 0; pin < 4; pin++, intpin++) - if (intpin->link != 0) { - if (entry->pe_slot == 0) - kprintf("embedded "); - else - kprintf("slot %-3d ", entry->pe_slot); - kprintf(" %3d %3d %c 0x%02x ", - entry->pe_bus, entry->pe_device, - 'A' + pin, intpin->link); - pci_print_irqmask(intpin->irqs); - kprintf("\n"); - } + /* + * Bus 2 used to contain the AGP controller, but the Xbox MCPX + * doesn't have one. Probing it can cause lockups. + */ + if (bus >= 2) + return dataport; } -} - -/* - * See if any interrupts for a given PCI bus are routed in the PIR. Don't - * even bother looking if the BIOS doesn't support routing anyways. - */ -int -pci_probe_route_table(int bus) -{ - int i; - u_int16_t v; - - v = pcibios_get_version(); - if (v < 0x0210) - return (0); - for (i = 0; i < pci_route_count; i++) - if (pci_route_table->pt_entry[i].pe_bus == bus) - return (1); - return (0); -} - -/* - * Configuration space access using direct register operations - */ - -/* enable configuration space accesses and return data port address */ -static int -pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) -{ - int dataport = 0; +#endif if (bus <= PCI_BUSMAX && slot < devmax @@ -625,13 +263,13 @@ pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) && (unsigned) bytes <= 4 && (reg & (bytes - 1)) == 0) { switch (cfgmech) { - case 1: + case CFGMECH_1: outl(CONF1_ADDR_PORT, (1 << 31) - | (bus << 16) | (slot << 11) - | (func << 8) | (reg & ~0x03)); + | (bus << 16) | (slot << 11) + | (func << 8) | (reg & ~0x03)); dataport = CONF1_DATA_PORT + (reg & 0x03); break; - case 2: + case CFGMECH_2: outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); outb(CONF2_FORWARD_PORT, bus); dataport = 0xc000 | (slot << 8) | reg; @@ -646,12 +284,16 @@ static void pci_cfgdisable(void) { switch (cfgmech) { - case 1: - outl(CONF1_ADDR_PORT, 0); + case CFGMECH_1: + /* + * Do nothing for the config mechanism 1 case. + * Writing a 0 to the address port can apparently + * confuse some bridges and cause spurious + * access failures. + */ break; - case 2: + case CFGMECH_2: outb(CONF2_ENABLE_PORT, 0); - outb(CONF2_FORWARD_PORT, 0); break; } } @@ -662,6 +304,12 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) int data = -1; int port; + if (cfgmech == CFGMECH_PCIE) { + data = pciereg_cfgread(bus, slot, func, reg, bytes); + return (data); + } + + mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { switch (bytes) { @@ -677,6 +325,7 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) } pci_cfgdisable(); } + mtx_unlock_spin(&pcicfg_mtx); return (data); } @@ -685,6 +334,12 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) { int port; + if (cfgmech == CFGMECH_PCIE) { + pciereg_cfgwrite(bus, slot, func, reg, data, bytes); + return; + } + + mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { switch (bytes) { @@ -700,6 +355,7 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) } pci_cfgdisable(); } + mtx_unlock_spin(&pcicfg_mtx); } /* check whether the configuration mechanism has been correctly identified */ @@ -753,59 +409,58 @@ pci_cfgcheck(int maxdev) static int pcireg_cfgopen(void) { - uint32_t mode1res,oldval1; - uint8_t mode2res,oldval2; + uint32_t mode1res, oldval1; + uint8_t mode2res, oldval2; + /* Check for type #1 first. */ oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { kprintf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", - oldval1); + oldval1); } - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - - cfgmech = 1; - devmax = 32; + cfgmech = CFGMECH_1; + devmax = 32; - outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - DELAY(1); - mode1res = inl(CONF1_ADDR_PORT); - outl(CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + DELAY(1); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); - if (bootverbose) - kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + if (bootverbose) + kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", mode1res, + CONF1_ENABLE_CHK); - if (mode1res) { - if (pci_cfgcheck(32)) - return (cfgmech); - } + if (mode1res) { + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); - mode1res = inl(CONF1_ADDR_PORT); - outl(CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); - if (bootverbose) - kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + if (bootverbose) + kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", mode1res, + CONF1_ENABLE_CHK1); - if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pci_cfgcheck(32)) - return (cfgmech); - } + if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { + if (pci_cfgcheck(32)) + return (cfgmech); } + /* Type #1 didn't work, so try type #2. */ oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { kprintf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", - oldval2); + oldval2); } if ((oldval2 & 0xf0) == 0) { - cfgmech = 2; + cfgmech = CFGMECH_2; devmax = 16; outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); @@ -813,8 +468,8 @@ pcireg_cfgopen(void) outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { if (bootverbose) @@ -825,7 +480,165 @@ pcireg_cfgopen(void) } } - cfgmech = 0; + /* Nothing worked, so punt. */ + cfgmech = CFGMECH_NONE; devmax = 0; return (cfgmech); } + +static int +pciereg_cfgopen(void) +{ +#ifdef PCIE_CFG_MECH + struct pcie_cfg_list *pcielist; + struct pcie_cfg_elem *pcie_array, *elem; +#ifdef SMP + struct pcpu *pc; +#endif + vm_offset_t va; + int i; + + if (bootverbose) + kprintf("Setting up PCIe mappings for BAR 0x%x\n", pciebar); + +#ifdef SMP + SLIST_FOREACH(pc, &cpuhead, pc_allcpu) +#endif + { + + pcie_array = kmalloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE, + M_DEVBUF, M_NOWAIT); + if (pcie_array == NULL) + return (0); + + va = kmem_alloc_nofault(&kernel_map, PCIE_CACHE * PAGE_SIZE); + if (va == 0) { + kfree(pcie_array, M_DEVBUF); + return (0); + } + +#ifdef SMP + pcielist = &pcie_list[pc->pc_cpuid]; +#else + pcielist = &pcie_list[0]; +#endif + TAILQ_INIT(pcielist); + for (i = 0; i < PCIE_CACHE; i++) { + elem = &pcie_array[i]; + elem->vapage = va + (i * PAGE_SIZE); + elem->papage = 0; + TAILQ_INSERT_HEAD(pcielist, elem, elem); + } + } + + + cfgmech = CFGMECH_PCIE; + devmax = 32; + return (1); +#else /* !PCIE_CFG_MECH */ + return (0); +#endif /* PCIE_CFG_MECH */ +} + +#define PCIE_PADDR(bar, reg, bus, slot, func) \ + ((bar) | \ + (((bus) & 0xff) << 20) | \ + (((slot) & 0x1f) << 15) | \ + (((func) & 0x7) << 12) | \ + ((reg) & 0xfff)) + +/* + * Find an element in the cache that matches the physical page desired, or + * create a new mapping from the least recently used element. + * A very simple LRU algorithm is used here, does it need to be more + * efficient? + */ +static __inline struct pcie_cfg_elem * +pciereg_findelem(vm_paddr_t papage) +{ + struct pcie_cfg_list *pcielist; + struct pcie_cfg_elem *elem; + pcielist = &pcie_list[mycpuid]; + TAILQ_FOREACH(elem, pcielist, elem) { + if (elem->papage == papage) + break; + } + + if (elem == NULL) { + elem = TAILQ_LAST(pcielist, pcie_cfg_list); + if (elem->papage != 0) { + pmap_kremove(elem->vapage); + cpu_invlpg(&elem->vapage); + } + pmap_kenter(elem->vapage, papage); + elem->papage = papage; + } + + if (elem != TAILQ_FIRST(pcielist)) { + TAILQ_REMOVE(pcielist, elem, elem); + TAILQ_INSERT_HEAD(pcielist, elem, elem); + } + return (elem); +} + +static int +pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) +{ + struct pcie_cfg_elem *elem; + volatile vm_offset_t va; + vm_paddr_t pa, papage; + int data; + + crit_enter(); + pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + papage = pa & ~PAGE_MASK; + elem = pciereg_findelem(papage); + va = elem->vapage | (pa & PAGE_MASK); + + switch (bytes) { + case 4: + data = *(volatile uint32_t *)(va); + break; + case 2: + data = *(volatile uint16_t *)(va); + break; + case 1: + data = *(volatile uint8_t *)(va); + break; + default: + panic("pciereg_cfgread: invalid width"); + } + + crit_exit(); + return (data); +} + +static void +pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) +{ + struct pcie_cfg_elem *elem; + volatile vm_offset_t va; + vm_paddr_t pa, papage; + + crit_enter(); + pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + papage = pa & ~PAGE_MASK; + elem = pciereg_findelem(papage); + va = elem->vapage | (pa & PAGE_MASK); + + switch (bytes) { + case 4: + *(volatile uint32_t *)(va) = data; + break; + case 2: + *(volatile uint16_t *)(va) = data; + break; + case 1: + *(volatile uint8_t *)(va) = data; + break; + default: + panic("pciereg_cfgwrite: invalid width"); + } + + crit_exit(); +} diff --git a/sys/bus/pci/i386/pci_cfgreg.h b/sys/bus/pci/i386/pci_cfgreg.h index f30214a5d6..87bf5cfa6e 100644 --- a/sys/bus/pci/i386/pci_cfgreg.h +++ b/sys/bus/pci/i386/pci_cfgreg.h @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1997, Stefan Esser * All rights reserved. * @@ -23,14 +23,10 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.4.2.1 2001/07/28 05:55:07 imp Exp $ - * $DragonFly: src/sys/bus/pci/i386/pci_cfgreg.h,v 1.3 2007/08/14 20:09:13 dillon Exp $ + * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.14.20.1 2009/04/15 03:14:26 kensmith Exp $ * */ -#ifndef _MACHINE_PCI_CFGREG_H_ -#define _MACHINE_PCI_CFGREG_H_ - #define CONF1_ADDR_PORT 0x0cf8 #define CONF1_DATA_PORT 0x0cfc @@ -50,10 +46,6 @@ int pci_cfgregopen(void); u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); -int pci_cfgintr(int bus, int device, int pin, int oldirq); -int pci_probe_route_table(int bus); - -#define PCI_INVALID_IRQ 255 -#define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ) - -#endif +void pci_pir_open(void); +int pci_pir_probe(int bus, int require_parse); +int pci_pir_route_interrupt(int bus, int device, int func, int pin); diff --git a/sys/bus/pci/i386/pci_pir.c b/sys/bus/pci/i386/pci_pir.c new file mode 100644 index 0000000000..c459e0d084 --- /dev/null +++ b/sys/bus/pci/i386/pci_pir.c @@ -0,0 +1,747 @@ +/*- + * Copyright (c) 1997, Stefan Esser + * Copyright (c) 2000, Michael Smith + * Copyright (c) 2000, BSDi + * Copyright (c) 2004, John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_pir.c,v 1.120.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_cfgreg.h" +#include +#include + +#define NUM_ISA_INTERRUPTS 16 + +/* + * A link device. Loosely based on the ACPI PCI link device. This doesn't + * try to support priorities for different ISA interrupts. + */ +struct pci_link { + TAILQ_ENTRY(pci_link) pl_links; + uint8_t pl_id; + uint8_t pl_irq; + uint16_t pl_irqmask; + int pl_references; + int pl_routed; +}; + +struct pci_link_lookup { + struct pci_link **pci_link_ptr; + int bus; + int device; + int pin; +}; + +struct pci_dev_lookup { + uint8_t link; + int bus; + int device; + int pin; +}; + +typedef void pir_entry_handler(struct PIR_entry *entry, + struct PIR_intpin* intpin, void *arg); + +static void pci_print_irqmask(u_int16_t irqs); +static int pci_pir_biosroute(int bus, int device, int func, int pin, + int irq); +static int pci_pir_choose_irq(struct pci_link *pci_link, int irqmask); +static void pci_pir_create_links(struct PIR_entry *entry, + struct PIR_intpin *intpin, void *arg); +static void pci_pir_dump_links(void); +static struct pci_link *pci_pir_find_link(uint8_t link_id); +static void pci_pir_find_link_handler(struct PIR_entry *entry, + struct PIR_intpin *intpin, void *arg); +static void pci_pir_initial_irqs(struct PIR_entry *entry, + struct PIR_intpin *intpin, void *arg); +static void pci_pir_parse(void); +static uint8_t pci_pir_search_irq(int bus, int device, int pin); +static int pci_pir_valid_irq(struct pci_link *pci_link, int irq); +static void pci_pir_walk_table(pir_entry_handler *handler, void *arg); + +static MALLOC_DEFINE(M_PIR, "$PIR", "$PIR structures"); + +static struct PIR_table *pci_route_table; +static device_t pir_device; +static int pci_route_count, pir_bios_irqs, pir_parsed; +static TAILQ_HEAD(, pci_link) pci_links; +static int pir_interrupt_weight[NUM_ISA_INTERRUPTS]; + +/* sysctl vars */ +SYSCTL_DECL(_hw_pci); + +/* XXX this likely should live in a header file */ +#ifdef PC98 +/* IRQs 3, 5, 7, 9, 10, 11, 12, 13 */ +#define PCI_IRQ_OVERRIDE_MASK 0x3e68 +#else +/* IRQs 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15 */ +#define PCI_IRQ_OVERRIDE_MASK 0xdef8 +#endif + +static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK; +TUNABLE_INT("hw.pci.irq_override_mask", &pci_irq_override_mask); +SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RD, + &pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK, + "Mask of allowed irqs to try to route when it has no good clue about\n" + "which irqs it should use."); + +/* + * Look for the interrupt routing table. + * + * We use PCI BIOS's PIR table if it's available. $PIR is the standard way + * to do this. Sadly, some machines are not standards conforming and have + * _PIR instead. We shrug and cope by looking for both. + */ +void +pci_pir_open(void) +{ + struct PIR_table *pt; + uint32_t sigaddr; + int i; + uint8_t ck, *cv; + + /* Don't try if we've already found a table. */ + if (pci_route_table != NULL) + return; + + /* Look for $PIR and then _PIR. */ + sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); + if (sigaddr == 0) + sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); + if (sigaddr == 0) + return; + + /* If we found something, check the checksum and length. */ + /* XXX - Use pmap_mapdev()? */ + pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); + if (pt->pt_header.ph_length <= sizeof(struct PIR_header)) + return; + for (cv = (u_int8_t *)pt, ck = 0, i = 0; + i < (pt->pt_header.ph_length); i++) + ck += cv[i]; + if (ck != 0) + return; + + /* Ok, we've got a valid table. */ + pci_route_table = pt; + pci_route_count = (pt->pt_header.ph_length - + sizeof(struct PIR_header)) / + sizeof(struct PIR_entry); +} + +/* + * Find the pci_link structure for a given link ID. + */ +static struct pci_link * +pci_pir_find_link(uint8_t link_id) +{ + struct pci_link *pci_link; + + TAILQ_FOREACH(pci_link, &pci_links, pl_links) { + if (pci_link->pl_id == link_id) + return (pci_link); + } + return (NULL); +} + +/* + * Find the link device associated with a PCI device in the table. + */ +static void +pci_pir_find_link_handler(struct PIR_entry *entry, struct PIR_intpin *intpin, + void *arg) +{ + struct pci_link_lookup *lookup; + + lookup = (struct pci_link_lookup *)arg; + if (entry->pe_bus == lookup->bus && + entry->pe_device == lookup->device && + intpin - entry->pe_intpin == lookup->pin) + *lookup->pci_link_ptr = pci_pir_find_link(intpin->link); +} + +/* + * Check to see if a possible IRQ setting is valid. + */ +static int +pci_pir_valid_irq(struct pci_link *pci_link, int irq) +{ + + if (!PCI_INTERRUPT_VALID(irq)) + return (0); + return (pci_link->pl_irqmask & (1 << irq)); +} + +/* + * Walk the $PIR executing the worker function for each valid intpin entry + * in the table. The handler is passed a pointer to both the entry and + * the intpin in the entry. + */ +static void +pci_pir_walk_table(pir_entry_handler *handler, void *arg) +{ + struct PIR_entry *entry; + struct PIR_intpin *intpin; + int i, pin; + + entry = &pci_route_table->pt_entry[0]; + for (i = 0; i < pci_route_count; i++, entry++) { + intpin = &entry->pe_intpin[0]; + for (pin = 0; pin < 4; pin++, intpin++) + if (intpin->link != 0) + handler(entry, intpin, arg); + } +} + +static void +pci_pir_create_links(struct PIR_entry *entry, struct PIR_intpin *intpin, + void *arg) +{ + struct pci_link *pci_link; + + pci_link = pci_pir_find_link(intpin->link); + if (pci_link != NULL) { + pci_link->pl_references++; + if (intpin->irqs != pci_link->pl_irqmask) { + if (bootverbose) + kprintf( + "$PIR: Entry %d.%d.INT%c has different mask for link %#x, merging\n", + entry->pe_bus, entry->pe_device, + (intpin - entry->pe_intpin) + 'A', + pci_link->pl_id); + pci_link->pl_irqmask &= intpin->irqs; + } + } else { + pci_link = kmalloc(sizeof(struct pci_link), M_PIR, M_WAITOK); + pci_link->pl_id = intpin->link; + pci_link->pl_irqmask = intpin->irqs; + pci_link->pl_irq = PCI_INVALID_IRQ; + pci_link->pl_references = 1; + pci_link->pl_routed = 0; + TAILQ_INSERT_TAIL(&pci_links, pci_link, pl_links); + } +} + +/* + * Look to see if any of the function on the PCI device at bus/device have + * an interrupt routed to intpin 'pin' by the BIOS. + */ +static uint8_t +pci_pir_search_irq(int bus, int device, int pin) +{ + uint32_t value; + uint8_t func, maxfunc; + + /* See if we have a valid device at function 0. */ + value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1); + if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) + return (PCI_INVALID_IRQ); + if (value & PCIM_MFDEV) + maxfunc = PCI_FUNCMAX; + else + maxfunc = 0; + + /* Scan all possible functions at this device. */ + for (func = 0; func <= maxfunc; func++) { + value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4); + if (value == 0xffffffff) + continue; + value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1); + + /* + * See if it uses the pin in question. Note that the passed + * in pin uses 0 for A, .. 3 for D whereas the intpin + * register uses 0 for no interrupt, 1 for A, .. 4 for D. + */ + if (value != pin + 1) + continue; + value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1); + if (bootverbose) + kprintf( + "$PIR: Found matching pin for %d.%d.INT%c at func %d: %d\n", + bus, device, pin + 'A', func, value); + if (value != PCI_INVALID_IRQ) + return (value); + } + return (PCI_INVALID_IRQ); +} + +/* + * Try to initialize IRQ based on this device's IRQ. + */ +static void +pci_pir_initial_irqs(struct PIR_entry *entry, struct PIR_intpin *intpin, + void *arg) +{ + struct pci_link *pci_link; + uint8_t irq, pin; + + pin = intpin - entry->pe_intpin; + pci_link = pci_pir_find_link(intpin->link); + irq = pci_pir_search_irq(entry->pe_bus, entry->pe_device, pin); + if (irq == PCI_INVALID_IRQ || irq == pci_link->pl_irq) + return; + + /* Don't trust any BIOS IRQs greater than 15. */ + if (irq >= NUM_ISA_INTERRUPTS) { + kprintf( + "$PIR: Ignoring invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n", + irq, entry->pe_bus, entry->pe_device, pin + 'A', + pci_link->pl_id); + return; + } + + /* + * If we don't have an IRQ for this link yet, then we trust the + * BIOS, even if it seems invalid from the $PIR entries. + */ + if (pci_link->pl_irq == PCI_INVALID_IRQ) { + if (!pci_pir_valid_irq(pci_link, irq)) + kprintf( + "$PIR: Using invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n", + irq, entry->pe_bus, entry->pe_device, pin + 'A', + pci_link->pl_id); + pci_link->pl_irq = irq; + pci_link->pl_routed = 1; + return; + } + + /* + * We have an IRQ and it doesn't match the current IRQ for this + * link. If the new IRQ is invalid, then warn about it and ignore + * it. If the old IRQ is invalid and the new IRQ is valid, then + * prefer the new IRQ instead. If both IRQs are valid, then just + * use the first one. Note that if we ever get into this situation + * we are having to guess which setting the BIOS actually routed. + * Perhaps we should just give up instead. + */ + if (!pci_pir_valid_irq(pci_link, irq)) { + kprintf( + "$PIR: BIOS IRQ %d for %d.%d.INT%c is not valid for link %#x\n", + irq, entry->pe_bus, entry->pe_device, pin + 'A', + pci_link->pl_id); + } else if (!pci_pir_valid_irq(pci_link, pci_link->pl_irq)) { + kprintf( +"$PIR: Preferring valid BIOS IRQ %d from %d.%d.INT%c for link %#x to IRQ %d\n", + irq, entry->pe_bus, entry->pe_device, pin + 'A', + pci_link->pl_id, pci_link->pl_irq); + pci_link->pl_irq = irq; + pci_link->pl_routed = 1; + } else + kprintf( + "$PIR: BIOS IRQ %d for %d.%d.INT%c does not match link %#x irq %d\n", + irq, entry->pe_bus, entry->pe_device, pin + 'A', + pci_link->pl_id, pci_link->pl_irq); +} + +/* + * Parse $PIR to enumerate link devices and attempt to determine their + * initial state. This could perhaps be cleaner if we had drivers for the + * various interrupt routers as they could read the initial IRQ for each + * link. + */ +static void +pci_pir_parse(void) +{ + char tunable_buffer[64]; + struct pci_link *pci_link; + int i, irq; + + /* Only parse once. */ + if (pir_parsed) + return; + pir_parsed = 1; + + /* Enumerate link devices. */ + TAILQ_INIT(&pci_links); + pci_pir_walk_table(pci_pir_create_links, NULL); + if (bootverbose) { + kprintf("$PIR: Links after initial probe:\n"); + pci_pir_dump_links(); + } + + /* + * Check to see if the BIOS has already routed any of the links by + * checking each device connected to each link to see if it has a + * valid IRQ. + */ + pci_pir_walk_table(pci_pir_initial_irqs, NULL); + if (bootverbose) { + kprintf("$PIR: Links after initial IRQ discovery:\n"); + pci_pir_dump_links(); + } + + /* + * Allow the user to override the IRQ for a given link device. We + * allow invalid IRQs to be specified but warn about them. An IRQ + * of 255 or 0 clears any preset IRQ. + */ + i = 0; + TAILQ_FOREACH(pci_link, &pci_links, pl_links) { + ksnprintf(tunable_buffer, sizeof(tunable_buffer), + "hw.pci.link.%#x.irq", pci_link->pl_id); + if (kgetenv_int(tunable_buffer, &irq) == 0) + continue; + if (irq == 0) + irq = PCI_INVALID_IRQ; + if (irq != PCI_INVALID_IRQ && + !pci_pir_valid_irq(pci_link, irq) && bootverbose) + kprintf( + "$PIR: Warning, IRQ %d for link %#x is not listed as valid\n", + irq, pci_link->pl_id); + pci_link->pl_routed = 0; + pci_link->pl_irq = irq; + i = 1; + } + if (bootverbose && i) { + kprintf("$PIR: Links after tunable overrides:\n"); + pci_pir_dump_links(); + } + + /* + * Build initial interrupt weights as well as bitmap of "known-good" + * IRQs that the BIOS has already used for PCI link devices. + */ + TAILQ_FOREACH(pci_link, &pci_links, pl_links) { + if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) + continue; + pir_bios_irqs |= 1 << pci_link->pl_irq; + pir_interrupt_weight[pci_link->pl_irq] += + pci_link->pl_references; + } + if (bootverbose) { + kprintf("$PIR: IRQs used by BIOS: "); + pci_print_irqmask(pir_bios_irqs); + kprintf("\n"); + kprintf("$PIR: Interrupt Weights:\n[ "); + for (i = 0; i < NUM_ISA_INTERRUPTS; i++) + kprintf(" %3d", i); + kprintf(" ]\n[ "); + for (i = 0; i < NUM_ISA_INTERRUPTS; i++) + kprintf(" %3d", pir_interrupt_weight[i]); + kprintf(" ]\n"); + } +} + +/* + * Use the PCI BIOS to route an interrupt for a given device. + * + * Input: + * AX = PCIBIOS_ROUTE_INTERRUPT + * BH = bus + * BL = device [7:3] / function [2:0] + * CH = IRQ + * CL = Interrupt Pin (0x0A = A, ... 0x0D = D) + */ +static int +pci_pir_biosroute(int bus, int device, int func, int pin, int irq) +{ + struct bios_regs args; + + args.eax = PCIBIOS_ROUTE_INTERRUPT; + args.ebx = (bus << 8) | (device << 3) | func; + args.ecx = (irq << 8) | (0xa + pin); + return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))); +} + + +/* + * Route a PCI interrupt using a link device from the $PIR. + */ +int +pci_pir_route_interrupt(int bus, int device, int func, int pin) +{ + struct pci_link_lookup lookup; + struct pci_link *pci_link; + int error, irq; + + if (pci_route_table == NULL) + return (PCI_INVALID_IRQ); + + /* Lookup link device for this PCI device/pin. */ + pci_link = NULL; + lookup.bus = bus; + lookup.device = device; + lookup.pin = pin - 1; + lookup.pci_link_ptr = &pci_link; + pci_pir_walk_table(pci_pir_find_link_handler, &lookup); + if (pci_link == NULL) { + kprintf("$PIR: No matching entry for %d.%d.INT%c\n", bus, + device, pin - 1 + 'A'); + return (PCI_INVALID_IRQ); + } + + /* + * Pick a new interrupt if we don't have one already. We look + * for an interrupt from several different sets. First, if + * this link only has one valid IRQ, use that. Second, we + * check the set of PCI only interrupts from the $PIR. Third, + * we check the set of known-good interrupts that the BIOS has + * already used. Lastly, we check the "all possible valid + * IRQs" set. + */ + if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) { + if (pci_link->pl_irqmask != 0 && powerof2(pci_link->pl_irqmask)) + irq = ffs(pci_link->pl_irqmask) - 1; + else + irq = pci_pir_choose_irq(pci_link, + pci_route_table->pt_header.ph_pci_irqs); + if (!PCI_INTERRUPT_VALID(irq)) + irq = pci_pir_choose_irq(pci_link, pir_bios_irqs); + if (!PCI_INTERRUPT_VALID(irq)) + irq = pci_pir_choose_irq(pci_link, + pci_irq_override_mask); + if (!PCI_INTERRUPT_VALID(irq)) { + if (bootverbose) + kprintf( + "$PIR: Failed to route interrupt for %d:%d INT%c\n", + bus, device, pin - 1 + 'A'); + return (PCI_INVALID_IRQ); + } + pci_link->pl_irq = irq; + } + + /* Ask the BIOS to route this IRQ if we haven't done so already. */ + if (!pci_link->pl_routed) { + error = pci_pir_biosroute(bus, device, func, pin - 1, + pci_link->pl_irq); + + /* Ignore errors when routing a unique interrupt. */ + if (error && !powerof2(pci_link->pl_irqmask)) { + kprintf("$PIR: ROUTE_INTERRUPT failed.\n"); + return (PCI_INVALID_IRQ); + } + pci_link->pl_routed = 1; + + /* Ensure the interrupt is set to level/low trigger. */ + KASSERT(pir_device != NULL, ("missing pir device")); + BUS_CONFIG_INTR(pir_device, pci_link->pl_irq, + INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); + } + if (bootverbose) + kprintf("$PIR: %d:%d INT%c routed to irq %d\n", bus, device, + pin - 1 + 'A', pci_link->pl_irq); + return (pci_link->pl_irq); +} + +/* + * Try to pick an interrupt for the specified link from the interrupts + * set in the mask. + */ +static int +pci_pir_choose_irq(struct pci_link *pci_link, int irqmask) +{ + int i, irq, realmask; + + /* XXX: Need to have a #define of known bad IRQs to also mask out? */ + realmask = pci_link->pl_irqmask & irqmask; + if (realmask == 0) + return (PCI_INVALID_IRQ); + + /* Find IRQ with lowest weight. */ + irq = PCI_INVALID_IRQ; + for (i = 0; i < NUM_ISA_INTERRUPTS; i++) { + if (!(realmask & 1 << i)) + continue; + if (irq == PCI_INVALID_IRQ || + pir_interrupt_weight[i] < pir_interrupt_weight[irq]) + irq = i; + } + if (bootverbose && PCI_INTERRUPT_VALID(irq)) { + kprintf("$PIR: Found IRQ %d for link %#x from ", irq, + pci_link->pl_id); + pci_print_irqmask(realmask); + kprintf("\n"); + } + return (irq); +} + +static void +pci_print_irqmask(u_int16_t irqs) +{ + int i, first; + + if (irqs == 0) { + kprintf("none"); + return; + } + first = 1; + for (i = 0; i < 16; i++, irqs >>= 1) + if (irqs & 1) { + if (!first) + kprintf(" "); + else + first = 0; + kprintf("%d", i); + } +} + +/* + * Display link devices. + */ +static void +pci_pir_dump_links(void) +{ + struct pci_link *pci_link; + + kprintf("Link IRQ Rtd Ref IRQs\n"); + TAILQ_FOREACH(pci_link, &pci_links, pl_links) { + kprintf("%#4x %3d %c %3d ", pci_link->pl_id, + pci_link->pl_irq, pci_link->pl_routed ? 'Y' : 'N', + pci_link->pl_references); + pci_print_irqmask(pci_link->pl_irqmask); + kprintf("\n"); + } +} + +/* + * See if any interrupts for a given PCI bus are routed in the PIR. Don't + * even bother looking if the BIOS doesn't support routing anyways. If we + * are probing a PCI-PCI bridge, then require_parse will be true and we should + * only succeed if a host-PCI bridge has already attached and parsed the PIR. + */ +int +pci_pir_probe(int bus, int require_parse) +{ + int i; + if (pci_route_table == NULL || (require_parse && !pir_parsed)) + return (0); + for (i = 0; i < pci_route_count; i++) + if (pci_route_table->pt_entry[i].pe_bus == bus) + return (1); + return (0); +} + +/* + * The driver for the new-bus psuedo device pir0 for the $PIR table. + */ + +static int +pir_probe(device_t dev) +{ + char buf[64]; +kprintf("pir probe\n"); + ksnprintf(buf, sizeof(buf), "PCI Interrupt Routing Table: %d Entries", + pci_route_count); + device_set_desc_copy(dev, buf); + return (0); +} + +static int +pir_attach(device_t dev) +{ + + pci_pir_parse(); + KASSERT(pir_device == NULL, ("Multiple pir devices")); + pir_device = dev; + return (0); +} + +static void +pir_resume_find_device(struct PIR_entry *entry, struct PIR_intpin *intpin, + void *arg) +{ + struct pci_dev_lookup *pd; + + pd = (struct pci_dev_lookup *)arg; + if (intpin->link != pd->link || pd->bus != -1) + return; + pd->bus = entry->pe_bus; + pd->device = entry->pe_device; + pd->pin = intpin - entry->pe_intpin; +} + +static int +pir_resume(device_t dev) +{ + struct pci_dev_lookup pd; + struct pci_link *pci_link; + int error; + + /* Ask the BIOS to re-route each link that was already routed. */ + TAILQ_FOREACH(pci_link, &pci_links, pl_links) { + if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) { + KASSERT(!pci_link->pl_routed, + ("link %#x is routed but has invalid PCI IRQ", + pci_link->pl_id)); + continue; + } + if (pci_link->pl_routed) { + pd.bus = -1; + pd.link = pci_link->pl_id; + pci_pir_walk_table(pir_resume_find_device, &pd); + KASSERT(pd.bus != -1, + ("did not find matching entry for link %#x in the $PIR table", + pci_link->pl_id)); + if (bootverbose) + device_printf(dev, + "Using %d.%d.INT%c to route link %#x to IRQ %d\n", + pd.bus, pd.device, pd.pin + 'A', + pci_link->pl_id, pci_link->pl_irq); + error = pci_pir_biosroute(pd.bus, pd.device, 0, pd.pin, + pci_link->pl_irq); + if (error) + device_printf(dev, + "ROUTE_INTERRUPT on resume for link %#x failed.\n", + pci_link->pl_id); + } + } + return (0); +} + +static device_method_t pir_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pir_probe), + DEVMETHOD(device_attach, pir_attach), + DEVMETHOD(device_resume, pir_resume), + + { 0, 0 } +}; + +static driver_t pir_driver = { + "pir", + pir_methods, + 1, +}; + +static devclass_t pir_devclass; + +DRIVER_MODULE(pir, legacy, pir_driver, pir_devclass, 0, 0); diff --git a/sys/bus/pci/ignore_pci.c b/sys/bus/pci/ignore_pci.c new file mode 100644 index 0000000000..237b463fef --- /dev/null +++ b/sys/bus/pci/ignore_pci.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/ignore_pci.c,v 1.4.28.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * 'Ignore' driver - eats devices that show up errnoeously on PCI + * but shouldn't ever be listed or handled by a driver. + */ + +#include +#include +#include +#include + +#include + +static int ignore_pci_probe(device_t dev); + +static device_method_t ignore_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ignore_pci_probe), + DEVMETHOD(device_attach, bus_generic_attach), + { 0, 0 } +}; + +static driver_t ignore_pci_driver = { + "ignore_pci", + ignore_pci_methods, + 0, +}; + +static devclass_t ignore_pci_devclass; + +DRIVER_MODULE(ignore_pci, pci, ignore_pci_driver, ignore_pci_devclass, 0, 0); + +static int +ignore_pci_probe(device_t dev) +{ + switch (pci_get_devid(dev)) { + case 0x10001042ul: /* SMC 37C665 */ + device_set_desc(dev, "ignored"); + device_quiet(dev); + return(-10000); + } + return(ENXIO); +} diff --git a/sys/bus/pci/isa_pci.c b/sys/bus/pci/isa_pci.c new file mode 100644 index 0000000000..2818ab612c --- /dev/null +++ b/sys/bus/pci/isa_pci.c @@ -0,0 +1,151 @@ +/*- + * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/isa_pci.c,v 1.13.8.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * PCI:ISA bridge support + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static int isab_probe(device_t dev); + +#if 0 +int +isab_attach(device_t dev) +{ + return ENXIO; +} +#endif + +static device_method_t isab_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, isab_probe), + DEVMETHOD(device_attach, isab_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t isab_driver = { + "isab", + isab_methods, + 0, +}; + +devclass_t isab_devclass; + +DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); + +/* + * XXX we need to add a quirk list here for bridges that don't correctly + * report themselves. + */ +static int +isab_probe(device_t dev) +{ + int matched = 0; + + /* + * Try for a generic match based on class/subclass. + */ + if ((pci_get_class(dev) == PCIC_BRIDGE) && + (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) { + matched = 1; + } else { + /* + * These are devices that we *know* are PCI:ISA bridges. + * Sometimes, however, they don't report themselves as + * such. Check in case one of them is pretending to be + * something else. + */ + switch (pci_get_devid(dev)) { + case 0x04848086: /* Intel 82378ZB/82378IB */ + case 0x122e8086: /* Intel 82371FB */ + case 0x70008086: /* Intel 82371SB */ + case 0x71108086: /* Intel 82371AB */ + case 0x71988086: /* Intel 82443MX */ + case 0x24108086: /* Intel 82801AA (ICH) */ + case 0x24208086: /* Intel 82801AB (ICH0) */ + case 0x24408086: /* Intel 82801AB (ICH2) */ + case 0x00061004: /* VLSI 82C593 */ + case 0x05861106: /* VIA 82C586 */ + case 0x05961106: /* VIA 82C596 */ + case 0x06861106: /* VIA 82C686 */ + case 0x153310b9: /* AcerLabs M1533 */ + case 0x154310b9: /* AcerLabs M1543 */ + case 0x00081039: /* SiS 85c503 */ + case 0x00001078: /* Cyrix Cx5510 */ + case 0x01001078: /* Cyrix Cx5530 */ + case 0xc7001045: /* OPTi 82C700 (FireStar) */ + case 0x00011033: /* NEC 0001 (C-bus) */ + case 0x002c1033: /* NEC 002C (C-bus) */ + case 0x003b1033: /* NEC 003B (C-bus) */ + case 0x886a1060: /* UMC UM8886 ISA */ + case 0x02001166: /* ServerWorks IB6566 PCI */ + if (bootverbose) + kprintf("PCI-ISA bridge with incorrect subclass 0x%x\n", + pci_get_subclass(dev)); + matched = 1; + break; + + default: + break; + } + } + + if (matched) { + device_set_desc(dev, "PCI-ISA bridge"); + return(-10000); + } + return(ENXIO); +} diff --git a/sys/bus/pci/pci.c b/sys/bus/pci/pci.c index 721b25899e..c43b090b5d 100644 --- a/sys/bus/pci/pci.c +++ b/sys/bus/pci/pci.c @@ -1,5 +1,7 @@ -/* - * Copyright (c) 1997, Stefan Esser +/*- + * Copyright (c) 1997, Stefan Esser + * Copyright (c) 2000, Michael Smith + * Copyright (c) 2000, BSDi * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,28 +24,24 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/pci/pci.c,v 1.141.2.15 2002/04/30 17:48:18 tmm Exp $ - * $DragonFly: src/sys/bus/pci/pci.c,v 1.58 2008/11/16 18:44:00 swildner Exp $ - * + * __FBSDID("$FreeBSD: src/sys/dev/pci/pci.c,v 1.355.2.9.2.1 2009/04/15 03:14:26 kensmith Exp $"); */ -#include "opt_bus.h" -#include "opt_pci.h" +#include -#include "opt_compat_oldpci.h" +#include "opt_bus.h" #include #include #include #include +#include #include #include #include #include -#include #include -#include +#include #include #include @@ -51,68 +49,240 @@ #include #include -#include -#include "pci_cfgreg.h" +#include #include -#include "pcireg.h" -#include "pcivar.h" -#include "pci_private.h" +#include +#include +#include #include "pcib_if.h" +#include "pci_if.h" + +#ifdef __HAVE_ACPI +#include +#include "acpi_if.h" +#else +#define ACPI_PWR_FOR_SLEEP(x, y, z) +#endif + +static uint32_t pci_mapbase(unsigned mapreg); +static const char *pci_maptype(unsigned mapreg); +static int pci_mapsize(unsigned testval); +static int pci_maprange(unsigned mapreg); +static void pci_fixancient(pcicfgregs *cfg); + +static int pci_porten(device_t pcib, int b, int s, int f); +static int pci_memen(device_t pcib, int b, int s, int f); +static void pci_assign_interrupt(device_t bus, device_t dev, + int force_route); +static int pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, + struct resource_list *rl, int force, int prefetch); +static int pci_probe(device_t dev); +static int pci_attach(device_t dev); +static void pci_load_vendor_data(void); +static int pci_describe_parse_line(char **ptr, int *vendor, + int *device, char **desc); +static char *pci_describe_device(device_t dev); +static int pci_modevent(module_t mod, int what, void *arg); +static void pci_hdrtypedata(device_t pcib, int b, int s, int f, + pcicfgregs *cfg); +static void pci_read_extcap(device_t pcib, pcicfgregs *cfg); +static int pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, + int reg, uint32_t *data); +#if 0 +static int pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, + int reg, uint32_t data); +#endif +static void pci_read_vpd(device_t pcib, pcicfgregs *cfg); +static void pci_disable_msi(device_t dev); +static void pci_enable_msi(device_t dev, uint64_t address, + uint16_t data); +static void pci_enable_msix(device_t dev, u_int index, + uint64_t address, uint32_t data); +static void pci_mask_msix(device_t dev, u_int index); +static void pci_unmask_msix(device_t dev, u_int index); +static int pci_msi_blacklisted(void); +static void pci_resume_msi(device_t dev); +static void pci_resume_msix(device_t dev); + +static device_method_t pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pci_probe), + DEVMETHOD(device_attach, pci_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, pci_suspend), + DEVMETHOD(device_resume, pci_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, pci_print_child), + DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), + DEVMETHOD(bus_read_ivar, pci_read_ivar), + DEVMETHOD(bus_write_ivar, pci_write_ivar), + DEVMETHOD(bus_driver_added, pci_driver_added), + DEVMETHOD(bus_setup_intr, pci_setup_intr), + DEVMETHOD(bus_teardown_intr, pci_teardown_intr), + + DEVMETHOD(bus_get_resource_list,pci_get_resource_list), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_delete_resource, pci_delete_resource), + DEVMETHOD(bus_alloc_resource, pci_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), + DEVMETHOD(bus_child_location_str, pci_child_location_str_method), + + /* PCI interface */ + DEVMETHOD(pci_read_config, pci_read_config_method), + DEVMETHOD(pci_write_config, pci_write_config_method), + DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), + DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), + DEVMETHOD(pci_enable_io, pci_enable_io_method), + DEVMETHOD(pci_disable_io, pci_disable_io_method), + DEVMETHOD(pci_get_vpd_ident, pci_get_vpd_ident_method), + DEVMETHOD(pci_get_vpd_readonly, pci_get_vpd_readonly_method), + DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), + DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), + DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method), + DEVMETHOD(pci_find_extcap, pci_find_extcap_method), + DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method), + DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method), + DEVMETHOD(pci_remap_msix, pci_remap_msix_method), + DEVMETHOD(pci_release_msi, pci_release_msi_method), + DEVMETHOD(pci_msi_count, pci_msi_count_method), + DEVMETHOD(pci_msix_count, pci_msix_count_method), + + { 0, 0 } +}; + +DEFINE_CLASS_0(pci, pci_driver, pci_methods, 0); -devclass_t pci_devclass; -const char *pcib_owner; +static devclass_t pci_devclass; +DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); +MODULE_VERSION(pci, 1); + +static char *pci_vendordata; +static size_t pci_vendordata_size; -static void pci_read_capabilities(device_t dev, pcicfgregs *cfg); -static int pcie_slotimpl(const pcicfgregs *); struct pci_quirk { - u_int32_t devid; /* Vendor/device of the card */ + uint32_t devid; /* Vendor/device of the card */ int type; -#define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */ +#define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */ +#define PCI_QUIRK_DISABLE_MSI 2 /* MSI/MSI-X doesn't work */ int arg1; int arg2; }; struct pci_quirk pci_quirks[] = { - /* - * The Intel 82371AB and 82443MX has a map register at offset 0x90. - */ + /* The Intel 82371AB and 82443MX has a map register at offset 0x90. */ { 0x71138086, PCI_QUIRK_MAP_REG, 0x90, 0 }, { 0x719b8086, PCI_QUIRK_MAP_REG, 0x90, 0 }, /* As does the Serverworks OSB4 (the SMBus mapping register) */ { 0x02001166, PCI_QUIRK_MAP_REG, 0x90, 0 }, + /* + * MSI doesn't work with the ServerWorks CNB20-HE Host Bridge + * or the CMIC-SL (AKA ServerWorks GC_LE). + */ + { 0x00141166, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x00171166, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + + /* + * MSI doesn't work on earlier Intel chipsets including + * E7500, E7501, E7505, 845, 865, 875/E7210, and 855. + */ + { 0x25408086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x254c8086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x25508086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x25608086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x25708086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x25788086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0x35808086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + + /* + * MSI doesn't work with devices behind the AMD 8131 HT-PCIX + * bridge. + */ + { 0x74501022, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + { 0 } }; /* map register information */ -#define PCI_MAPMEM 0x01 /* memory map */ -#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ -#define PCI_MAPPORT 0x04 /* port map */ +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + +struct devlist pci_devq; +uint32_t pci_generation; +uint32_t pci_numdevs = 0; +static int pcie_chipset, pcix_chipset; + +/* sysctl vars */ +SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "PCI bus tuning parameters"); + +static int pci_enable_io_modes = 1; +TUNABLE_INT("hw.pci.enable_io_modes", &pci_enable_io_modes); +SYSCTL_INT(_hw_pci, OID_AUTO, enable_io_modes, CTLFLAG_RW, + &pci_enable_io_modes, 1, + "Enable I/O and memory bits in the config register. Some BIOSes do not\n\ +enable these bits correctly. We'd like to do this all the time, but there\n\ +are some peripherals that this causes problems with."); -static STAILQ_HEAD(devlist, pci_devinfo) pci_devq; -u_int32_t pci_numdevs = 0; -static u_int32_t pci_generation = 0; - -SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "pci parameters"); static int pci_do_power_nodriver = 0; TUNABLE_INT("hw.pci.do_power_nodriver", &pci_do_power_nodriver); SYSCTL_INT(_hw_pci, OID_AUTO, do_power_nodriver, CTLFLAG_RW, &pci_do_power_nodriver, 0, "Place a function into D3 state when no driver attaches to it. 0 means\n\ disable. 1 means conservatively place devices into D3 state. 2 means\n\ -aggressively place devices into D3 state. 3 means put absolutely everything\n\ +agressively place devices into D3 state. 3 means put absolutely everything\n\ in D3 state."); +static int pci_do_power_resume = 1; +TUNABLE_INT("hw.pci.do_power_resume", &pci_do_power_resume); +SYSCTL_INT(_hw_pci, OID_AUTO, do_power_resume, CTLFLAG_RW, + &pci_do_power_resume, 1, + "Transition from D3 -> D0 on resume."); + +static int pci_do_msi = 1; +TUNABLE_INT("hw.pci.enable_msi", &pci_do_msi); +SYSCTL_INT(_hw_pci, OID_AUTO, enable_msi, CTLFLAG_RW, &pci_do_msi, 1, + "Enable support for MSI interrupts"); + +static int pci_do_msix = 1; +TUNABLE_INT("hw.pci.enable_msix", &pci_do_msix); +SYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1, + "Enable support for MSI-X interrupts"); + +static int pci_honor_msi_blacklist = 1; +TUNABLE_INT("hw.pci.honor_msi_blacklist", &pci_honor_msi_blacklist); +SYSCTL_INT(_hw_pci, OID_AUTO, honor_msi_blacklist, CTLFLAG_RD, + &pci_honor_msi_blacklist, 1, "Honor chipset blacklist for MSI"); + +/* Find a device_t by bus/slot/function in domain 0 */ + +device_t +pci_find_bsf(uint8_t bus, uint8_t slot, uint8_t func) +{ + + return (pci_find_dbsf(0, bus, slot, func)); +} + +/* Find a device_t by domain/bus/slot/function */ + device_t -pci_find_bsf(u_int8_t bus, u_int8_t slot, u_int8_t func) +pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func) { struct pci_devinfo *dinfo; STAILQ_FOREACH(dinfo, &pci_devq, pci_links) { - if ((dinfo->cfg.bus == bus) && + if ((dinfo->cfg.domain == domain) && + (dinfo->cfg.bus == bus) && (dinfo->cfg.slot == slot) && (dinfo->cfg.func == func)) { return (dinfo->cfg.dev); @@ -122,8 +292,10 @@ pci_find_bsf(u_int8_t bus, u_int8_t slot, u_int8_t func) return (NULL); } +/* Find a device_t by vendor/device ID */ + device_t -pci_find_device(u_int16_t vendor, u_int16_t device) +pci_find_device(uint16_t vendor, uint16_t device) { struct pci_devinfo *dinfo; @@ -137,78 +309,35 @@ pci_find_device(u_int16_t vendor, u_int16_t device) return (NULL); } -int -pcie_slot_implemented(device_t dev) -{ - struct pci_devinfo *dinfo = device_get_ivars(dev); - - return pcie_slotimpl(&dinfo->cfg); -} - -void -pcie_set_max_readrq(device_t dev, uint16_t rqsize) -{ - uint8_t expr_ptr; - uint16_t val; - - rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK; - if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) { - panic("%s: invalid max read request size 0x%02x\n", - device_get_nameunit(dev), rqsize); - } - - expr_ptr = pci_get_pciecap_ptr(dev); - if (!expr_ptr) - panic("%s: not PCIe device\n", device_get_nameunit(dev)); - - val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2); - if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) { - if (bootverbose) - device_printf(dev, "adjust device control 0x%04x", val); - - val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK; - val |= rqsize; - pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2); - - if (bootverbose) - kprintf(" -> 0x%04x\n", val); - } -} - /* return base address of memory or port map */ -static u_int32_t -pci_mapbase(unsigned mapreg) +static uint32_t +pci_mapbase(uint32_t mapreg) { - int mask = 0x03; - if ((mapreg & 0x01) == 0) - mask = 0x0f; - return (mapreg & ~mask); + + if (PCI_BAR_MEM(mapreg)) + return (mapreg & PCIM_BAR_MEM_BASE); + else + return (mapreg & PCIM_BAR_IO_BASE); } /* return map type of memory or port map */ -static int +static const char * pci_maptype(unsigned mapreg) { - static u_int8_t maptype[0x10] = { - PCI_MAPMEM, PCI_MAPPORT, - PCI_MAPMEM, 0, - PCI_MAPMEM, PCI_MAPPORT, - 0, 0, - PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, - PCI_MAPMEM|PCI_MAPMEMP, 0, - PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, - 0, 0, - }; - return maptype[mapreg & 0x0f]; + if (PCI_BAR_IO(mapreg)) + return ("I/O Port"); + if (mapreg & PCIM_BAR_MEM_PREFETCH) + return ("Prefetchable Memory"); + return ("Memory"); } /* return log2 of map size decoded for memory or port map */ static int -pci_mapsize(unsigned testval) +pci_mapsize(uint32_t testval) { int ln2size; @@ -230,19 +359,21 @@ static int pci_maprange(unsigned mapreg) { int ln2range = 0; - switch (mapreg & 0x07) { - case 0x00: - case 0x01: - case 0x05: + + if (PCI_BAR_IO(mapreg)) ln2range = 32; - break; - case 0x02: - ln2range = 20; - break; - case 0x04: - ln2range = 64; - break; - } + else + switch (mapreg & PCIM_BAR_MEM_TYPE) { + case PCIM_BAR_MEM_32: + ln2range = 32; + break; + case PCIM_BAR_MEM_1MB: + ln2range = 20; + break; + case PCIM_BAR_MEM_64: + ln2range = 64; + break; + } return (ln2range); } @@ -259,82 +390,12 @@ pci_fixancient(pcicfgregs *cfg) cfg->hdrtype = 1; } -/* read config data specific to header type 1 device (PCI to PCI bridge) */ - -static void * -pci_readppb(device_t pcib, int b, int s, int f) -{ - pcih1cfgregs *p; - - p = kmalloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK | M_ZERO); - - p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_1, 2); - p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_1, 2); - - p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_1, 1); - - p->iobase = PCI_PPBIOBASE (PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_IOBASEH_1, 2), - PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_IOBASEL_1, 1)); - p->iolimit = PCI_PPBIOLIMIT (PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_IOLIMITH_1, 2), - PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_IOLIMITL_1, 1)); - - p->membase = PCI_PPBMEMBASE (0, - PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_MEMBASE_1, 2)); - p->memlimit = PCI_PPBMEMLIMIT (0, - PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_MEMLIMIT_1, 2)); - - p->pmembase = PCI_PPBMEMBASE ( - (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEH_1, 4), - PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEL_1, 2)); - - p->pmemlimit = PCI_PPBMEMLIMIT ( - (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f, - PCIR_PMLIMITH_1, 4), - PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMLIMITL_1, 2)); - - return (p); -} - -/* read config data specific to header type 2 device (PCI to CardBus bridge) */ - -static void * -pci_readpcb(device_t pcib, int b, int s, int f) -{ - pcih2cfgregs *p; - - p = kmalloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK | M_ZERO); - - p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_2, 2); - p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_2, 2); - - p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_2, 1); - - p->membase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE0_2, 4); - p->memlimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT0_2, 4); - p->membase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE1_2, 4); - p->memlimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT1_2, 4); - - p->iobase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE0_2, 4); - p->iolimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT0_2, 4); - p->iobase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE1_2, 4); - p->iolimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT1_2, 4); - - p->pccardif = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PCCARDIF_2, 4); - return p; -} - /* extract header type specific config data */ static void pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg) { -#define REG(n,w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) +#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) switch (cfg->hdrtype) { case 0: cfg->subvendor = REG(PCIR_SUBVEND_0, 2); @@ -342,32 +403,22 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg) cfg->nummaps = PCI_MAXMAPS_0; break; case 1: - cfg->subvendor = REG(PCIR_SUBVEND_1, 2); - cfg->subdevice = REG(PCIR_SUBDEV_1, 2); - cfg->secondarybus = REG(PCIR_SECBUS_1, 1); - cfg->subordinatebus = REG(PCIR_SUBBUS_1, 1); cfg->nummaps = PCI_MAXMAPS_1; - cfg->hdrspec = pci_readppb(pcib, b, s, f); break; case 2: cfg->subvendor = REG(PCIR_SUBVEND_2, 2); cfg->subdevice = REG(PCIR_SUBDEV_2, 2); - cfg->secondarybus = REG(PCIR_SECBUS_2, 1); - cfg->subordinatebus = REG(PCIR_SUBBUS_2, 1); cfg->nummaps = PCI_MAXMAPS_2; - cfg->hdrspec = pci_readpcb(pcib, b, s, f); break; } #undef REG } -/* read configuration header into pcicfgrect structure */ - +/* read configuration header into pcicfgregs structure */ struct pci_devinfo * -pci_read_device(device_t pcib, int b, int s, int f, size_t size) +pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size) { -#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) - +#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) pcicfgregs *cfg = NULL; struct pci_devinfo *devlist_entry; struct devlist *devlist_head; @@ -376,12 +427,14 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size) devlist_entry = NULL; - if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != -1) { - + if (REG(PCIR_DEVVENDOR, 4) != -1) { devlist_entry = kmalloc(size, M_DEVBUF, M_WAITOK | M_ZERO); + if (devlist_entry == NULL) + return (NULL); cfg = &devlist_entry->cfg; - + + cfg->domain = d; cfg->bus = b; cfg->slot = s; cfg->func = f; @@ -399,38 +452,6 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size) cfg->intpin = REG(PCIR_INTPIN, 1); cfg->intline = REG(PCIR_INTLINE, 1); -#ifdef APIC_IO - /* - * If using the APIC the intpin is probably wrong, since it - * is often setup by the BIOS with the PIC in mind. - */ - if (cfg->intpin != 0) { - int airq; - - airq = pci_apic_irq(cfg->bus, cfg->slot, cfg->intpin); - if (airq >= 0) { - /* PCI specific entry found in MP table */ - if (airq != cfg->intline) { - undirect_pci_irq(cfg->intline); - cfg->intline = airq; - } - } else { - /* - * PCI interrupts might be redirected to the - * ISA bus according to some MP tables. Use the - * same methods as used by the ISA devices - * devices to find the proper IOAPIC int pin. - */ - airq = isa_apic_irq(cfg->intline); - if ((airq >= 0) && (airq != cfg->intline)) { - /* XXX: undirect_pci_irq() ? */ - undirect_isa_irq(cfg->intline); - cfg->intline = airq; - } - } - } -#endif /* APIC_IO */ - cfg->mingnt = REG(PCIR_MINGNT, 1); cfg->maxlat = REG(PCIR_MAXLAT, 1); @@ -439,10 +460,13 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size) pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); - pci_read_capabilities(pcib, cfg); + + if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) + pci_read_extcap(pcib, cfg); STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links); + devlist_entry->conf.pc_sel.pc_domain = cfg->domain; devlist_entry->conf.pc_sel.pc_bus = cfg->bus; devlist_entry->conf.pc_sel.pc_dev = cfg->slot; devlist_entry->conf.pc_sel.pc_func = cfg->func; @@ -465,220 +489,1535 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size) #undef REG } -static int -pci_fixup_nextptr(int *nextptr0) -{ - int nextptr = *nextptr0; - - /* "Next pointer" is only one byte */ - KASSERT(nextptr <= 0xff, ("Illegal next pointer %d\n", nextptr)); - - if (nextptr & 0x3) { - /* - * PCI local bus spec 3.0: - * - * "... The bottom two bits of all pointers are reserved - * and must be implemented as 00b although software must - * mask them to allow for future uses of these bits ..." - */ - if (bootverbose) { - kprintf("Illegal PCI extended capability " - "offset, fixup 0x%02x -> 0x%02x\n", - nextptr, nextptr & ~0x3); - } - nextptr &= ~0x3; - } - *nextptr0 = nextptr; - - if (nextptr < 0x40) { - if (nextptr != 0) { - kprintf("Illegal PCI extended capability " - "offset 0x%02x", nextptr); - } - return 0; - } - return 1; -} - -static void -pci_read_cap_pmgt(device_t pcib, int ptr, pcicfgregs *cfg) -{ -#define REG(n, w) \ - PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) - - struct pcicfg_pmgt *pmgt = &cfg->pmgt; - - if (pmgt->pp_cap) - return; - - pmgt->pp_cap = REG(ptr + PCIR_POWER_CAP, 2); - pmgt->pp_status = ptr + PCIR_POWER_STATUS; - pmgt->pp_pmcsr = ptr + PCIR_POWER_PMCSR; - /* - * XXX - * Following way may be used to to test whether - * 'data' register exists: - * if 'data_select' register of - * PCIR_POWER_STATUS(bits[12,9]) is read-only - * then 'data' register is _not_ implemented. - */ - pmgt->pp_data = 0; - -#undef REG -} - -static int -pcie_slotimpl(const pcicfgregs *cfg) -{ - const struct pcicfg_expr *expr = &cfg->expr; - uint16_t port_type; - - /* - * Only version 1 can be parsed currently - */ - if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) - return 0; - - /* - * - Slot implemented bit is meaningful iff current port is - * root port or down stream port. - * - Testing for root port or down stream port is meanningful - * iff PCI configure has type 1 header. - */ - - if (cfg->hdrtype != 1) - return 0; - - port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE; - if (port_type != PCIE_ROOT_PORT && port_type != PCIE_DOWN_STREAM_PORT) - return 0; - - if (!(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) - return 0; - - return 1; -} - -static void -pci_read_cap_expr(device_t pcib, int ptr, pcicfgregs *cfg) -{ -#define REG(n, w) \ - PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) - - struct pcicfg_expr *expr = &cfg->expr; - - expr->expr_ptr = ptr; - expr->expr_cap = REG(ptr + PCIER_CAPABILITY, 2); - - /* - * Only version 1 can be parsed currently - */ - if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) - return; - - /* - * Read slot capabilities. Slot capabilities exists iff - * current port's slot is implemented - */ - if (pcie_slotimpl(cfg)) - expr->expr_slotcap = REG(ptr + PCIER_SLOTCAP, 4); - -#undef REG -} - static void -pci_read_capabilities(device_t pcib, pcicfgregs *cfg) +pci_read_extcap(device_t pcib, pcicfgregs *cfg) { -#define REG(n, w) \ - PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) - - int nextptr, ptrptr; - - if ((REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) == 0) { - /* No capabilities */ - return; - } +#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) +#define WREG(n, v, w) PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w) +#if defined(__i386__) || defined(__amd64__) + uint64_t addr; +#endif + uint32_t val; + int ptr, nextptr, ptrptr; - switch (cfg->hdrtype) { + switch (cfg->hdrtype & PCIM_HDRTYPE) { case 0: case 1: ptrptr = PCIR_CAP_PTR; break; case 2: - ptrptr = PCIR_CAP_PTR_2; + ptrptr = PCIR_CAP_PTR_2; /* cardbus capabilities ptr */ break; default: - return; /* No capabilities support */ + return; /* no extended capabilities support */ } - nextptr = REG(ptrptr, 1); + nextptr = REG(ptrptr, 1); /* sanity check? */ /* * Read capability entries. */ - while (pci_fixup_nextptr(&nextptr)) { - int ptr = nextptr; + while (nextptr != 0) { + /* Sanity check */ + if (nextptr > 255) { + kprintf("illegal PCI extended capability offset %d\n", + nextptr); + return; + } + /* Find the next entry */ + ptr = nextptr; + nextptr = REG(ptr + PCICAP_NEXTPTR, 1); /* Process this entry */ switch (REG(ptr + PCICAP_ID, 1)) { case PCIY_PMG: /* PCI power management */ - pci_read_cap_pmgt(pcib, ptr, cfg); + if (cfg->pp.pp_cap == 0) { + cfg->pp.pp_cap = REG(ptr + PCIR_POWER_CAP, 2); + cfg->pp.pp_status = ptr + PCIR_POWER_STATUS; + cfg->pp.pp_pmcsr = ptr + PCIR_POWER_PMCSR; + if ((nextptr - ptr) > PCIR_POWER_DATA) + cfg->pp.pp_data = ptr + PCIR_POWER_DATA; + } break; - case PCIY_PCIX: /* PCI-X */ - cfg->pcixcap_ptr = ptr; +#if notyet +#if defined(__i386__) || defined(__amd64__) + case PCIY_HT: /* HyperTransport */ + /* Determine HT-specific capability type. */ + val = REG(ptr + PCIR_HT_COMMAND, 2); + switch (val & PCIM_HTCMD_CAP_MASK) { + case PCIM_HTCAP_MSI_MAPPING: + if (!(val & PCIM_HTCMD_MSI_FIXED)) { + /* Sanity check the mapping window. */ + addr = REG(ptr + PCIR_HTMSI_ADDRESS_HI, + 4); + addr <<= 32; + addr |= REG(ptr + PCIR_HTMSI_ADDRESS_LO, + 4); + if (addr != MSI_INTEL_ADDR_BASE) + device_printf(pcib, + "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n", + cfg->domain, cfg->bus, + cfg->slot, cfg->func, + (long long)addr); + } else + addr = MSI_INTEL_ADDR_BASE; + + cfg->ht.ht_msimap = ptr; + cfg->ht.ht_msictrl = val; + cfg->ht.ht_msiaddr = addr; + break; + } + break; +#endif + case PCIY_MSI: /* PCI MSI */ + cfg->msi.msi_location = ptr; + cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2); + cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl & + PCIM_MSICTRL_MMC_MASK)>>1); break; - case PCIY_EXPRESS: /* PCI Express */ - pci_read_cap_expr(pcib, ptr, cfg); + case PCIY_MSIX: /* PCI MSI-X */ + cfg->msix.msix_location = ptr; + cfg->msix.msix_ctrl = REG(ptr + PCIR_MSIX_CTRL, 2); + cfg->msix.msix_msgnum = (cfg->msix.msix_ctrl & + PCIM_MSIXCTRL_TABLE_SIZE) + 1; + val = REG(ptr + PCIR_MSIX_TABLE, 4); + cfg->msix.msix_table_bar = PCIR_BAR(val & + PCIM_MSIX_BIR_MASK); + cfg->msix.msix_table_offset = val & ~PCIM_MSIX_BIR_MASK; + val = REG(ptr + PCIR_MSIX_PBA, 4); + cfg->msix.msix_pba_bar = PCIR_BAR(val & + PCIM_MSIX_BIR_MASK); + cfg->msix.msix_pba_offset = val & ~PCIM_MSIX_BIR_MASK; + break; +#endif + case PCIY_VPD: /* PCI Vital Product Data */ + cfg->vpd.vpd_reg = ptr; + break; + case PCIY_SUBVENDOR: + /* Should always be true. */ + if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) { + val = REG(ptr + PCIR_SUBVENDCAP_ID, 4); + cfg->subvendor = val & 0xffff; + cfg->subdevice = val >> 16; + } + break; + case PCIY_PCIX: /* PCI-X */ + /* + * Assume we have a PCI-X chipset if we have + * at least one PCI-PCI bridge with a PCI-X + * capability. Note that some systems with + * PCI-express or HT chipsets might match on + * this check as well. + */ + if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) + pcix_chipset = 1; break; - case PCIY_VPD: /* Vital Product Data */ - cfg->vpdcap_ptr = ptr; + case PCIY_EXPRESS: /* PCI-express */ + /* + * Assume we have a PCI-express chipset if we have + * at least one PCI-express device. + */ + pcie_chipset = 1; break; default: break; } - - /* Find the next entry */ - nextptr = REG(ptr + PCICAP_NEXTPTR, 1); } - -#undef REG +/* REG and WREG use carry through to next functions */ } -/* free pcicfgregs structure and all depending data structures */ +/* + * PCI Vital Product Data + */ + +#define PCI_VPD_TIMEOUT 1000000 -int -pci_freecfg(struct pci_devinfo *dinfo) +static int +pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t *data) { - struct devlist *devlist_head; + int count = PCI_VPD_TIMEOUT; - devlist_head = &pci_devq; + KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned")); - if (dinfo->cfg.hdrspec != NULL) - kfree(dinfo->cfg.hdrspec, M_DEVBUF); - /* XXX this hasn't been tested */ - STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); - kfree(dinfo, M_DEVBUF); + WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg, 2); - /* increment the generation count */ - pci_generation++; + while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) != 0x8000) { + if (--count < 0) + return (ENXIO); + DELAY(1); /* limit looping */ + } + *data = (REG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, 4)); - /* we're losing one device */ - pci_numdevs--; return (0); } - -/* - * PCI power manangement - */ -int -pci_set_powerstate_method(device_t dev, device_t child, int state) +#if 0 +static int +pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data) { - struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; + int count = PCI_VPD_TIMEOUT; + + KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned")); + + WREG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, data, 4); + WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg | 0x8000, 2); + while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) == 0x8000) { + if (--count < 0) + return (ENXIO); + DELAY(1); /* limit looping */ + } + + return (0); +} +#endif + +#undef PCI_VPD_TIMEOUT + +struct vpd_readstate { + device_t pcib; + pcicfgregs *cfg; + uint32_t val; + int bytesinval; + int off; + uint8_t cksum; +}; + +static int +vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data) +{ + uint32_t reg; + uint8_t byte; + + if (vrs->bytesinval == 0) { + if (pci_read_vpd_reg(vrs->pcib, vrs->cfg, vrs->off, ®)) + return (ENXIO); + vrs->val = le32toh(reg); + vrs->off += 4; + byte = vrs->val & 0xff; + vrs->bytesinval = 3; + } else { + vrs->val = vrs->val >> 8; + byte = vrs->val & 0xff; + vrs->bytesinval--; + } + + vrs->cksum += byte; + *data = byte; + return (0); +} + +void +pcie_set_max_readrq(device_t dev, uint16_t rqsize) +{ + int expr_ptr; + uint16_t val; + rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK; + if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) { + panic("%s: invalid max read request size 0x%02x\n", + device_get_nameunit(dev), rqsize); + } +#warning "this code is incorrect, I think" + pci_find_extcap_method(device_get_parent(dev), dev, PCIY_EXPRESS, &expr_ptr); + if(!expr_ptr) + panic("%s: not PCI Express\n", device_get_nameunit(dev)); + val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2); + if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) { + if (bootverbose) + device_printf(dev, "adjust device control 0x%04x", val); + val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK; + val |= rqsize; + pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2); + + if (bootverbose) + kprintf(" -> 0x%04x\n", val); + } +} + +static void +pci_read_vpd(device_t pcib, pcicfgregs *cfg) +{ + struct vpd_readstate vrs; + int state; + int name; + int remain; + int i; + int alloc, off; /* alloc/off for RO/W arrays */ + int cksumvalid; + int dflen; + uint8_t byte; + uint8_t byte2; + + /* init vpd reader */ + vrs.bytesinval = 0; + vrs.off = 0; + vrs.pcib = pcib; + vrs.cfg = cfg; + vrs.cksum = 0; + + state = 0; + name = remain = i = 0; /* shut up stupid gcc */ + alloc = off = 0; /* shut up stupid gcc */ + dflen = 0; /* shut up stupid gcc */ + cksumvalid = -1; + while (state >= 0) { + if (vpd_nextbyte(&vrs, &byte)) { + state = -2; + break; + } +#if 0 + kprintf("vpd: val: %#x, off: %d, bytesinval: %d, byte: %#hhx, " \ + "state: %d, remain: %d, name: %#x, i: %d\n", vrs.val, + vrs.off, vrs.bytesinval, byte, state, remain, name, i); +#endif + switch (state) { + case 0: /* item name */ + if (byte & 0x80) { + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + remain = byte2; + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + remain |= byte2 << 8; + if (remain > (0x7f*4 - vrs.off)) { + state = -1; + kprintf( + "pci%d:%d:%d:%d: invalid VPD data, remain %#x\n", + cfg->domain, cfg->bus, cfg->slot, + cfg->func, remain); + } + name = byte & 0x7f; + } else { + remain = byte & 0x7; + name = (byte >> 3) & 0xf; + } + switch (name) { + case 0x2: /* String */ + cfg->vpd.vpd_ident = kmalloc(remain + 1, + M_DEVBUF, M_WAITOK); + i = 0; + state = 1; + break; + case 0xf: /* End */ + state = -1; + break; + case 0x10: /* VPD-R */ + alloc = 8; + off = 0; + cfg->vpd.vpd_ros = kmalloc(alloc * + sizeof(*cfg->vpd.vpd_ros), M_DEVBUF, + M_WAITOK | M_ZERO); + state = 2; + break; + case 0x11: /* VPD-W */ + alloc = 8; + off = 0; + cfg->vpd.vpd_w = kmalloc(alloc * + sizeof(*cfg->vpd.vpd_w), M_DEVBUF, + M_WAITOK | M_ZERO); + state = 5; + break; + default: /* Invalid data, abort */ + state = -1; + break; + } + break; + + case 1: /* Identifier String */ + cfg->vpd.vpd_ident[i++] = byte; + remain--; + if (remain == 0) { + cfg->vpd.vpd_ident[i] = '\0'; + state = 0; + } + break; + + case 2: /* VPD-R Keyword Header */ + if (off == alloc) { + cfg->vpd.vpd_ros = kreallocf(cfg->vpd.vpd_ros, + (alloc *= 2) * sizeof(*cfg->vpd.vpd_ros), + M_DEVBUF, M_WAITOK | M_ZERO); + } + cfg->vpd.vpd_ros[off].keyword[0] = byte; + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + cfg->vpd.vpd_ros[off].keyword[1] = byte2; + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + dflen = byte2; + if (dflen == 0 && + strncmp(cfg->vpd.vpd_ros[off].keyword, "RV", + 2) == 0) { + /* + * if this happens, we can't trust the rest + * of the VPD. + */ + kprintf( + "pci%d:%d:%d:%d: bad keyword length: %d\n", + cfg->domain, cfg->bus, cfg->slot, + cfg->func, dflen); + cksumvalid = 0; + state = -1; + break; + } else if (dflen == 0) { + cfg->vpd.vpd_ros[off].value = kmalloc(1 * + sizeof(*cfg->vpd.vpd_ros[off].value), + M_DEVBUF, M_WAITOK); + cfg->vpd.vpd_ros[off].value[0] = '\x00'; + } else + cfg->vpd.vpd_ros[off].value = kmalloc( + (dflen + 1) * + sizeof(*cfg->vpd.vpd_ros[off].value), + M_DEVBUF, M_WAITOK); + remain -= 3; + i = 0; + /* keep in sync w/ state 3's transistions */ + if (dflen == 0 && remain == 0) + state = 0; + else if (dflen == 0) + state = 2; + else + state = 3; + break; + + case 3: /* VPD-R Keyword Value */ + cfg->vpd.vpd_ros[off].value[i++] = byte; + if (strncmp(cfg->vpd.vpd_ros[off].keyword, + "RV", 2) == 0 && cksumvalid == -1) { + if (vrs.cksum == 0) + cksumvalid = 1; + else { + if (bootverbose) + kprintf( + "pci%d:%d:%d:%d: bad VPD cksum, remain %hhu\n", + cfg->domain, cfg->bus, + cfg->slot, cfg->func, + vrs.cksum); + cksumvalid = 0; + state = -1; + break; + } + } + dflen--; + remain--; + /* keep in sync w/ state 2's transistions */ + if (dflen == 0) + cfg->vpd.vpd_ros[off++].value[i++] = '\0'; + if (dflen == 0 && remain == 0) { + cfg->vpd.vpd_rocnt = off; + cfg->vpd.vpd_ros = kreallocf(cfg->vpd.vpd_ros, + off * sizeof(*cfg->vpd.vpd_ros), + M_DEVBUF, M_WAITOK | M_ZERO); + state = 0; + } else if (dflen == 0) + state = 2; + break; + + case 4: + remain--; + if (remain == 0) + state = 0; + break; + + case 5: /* VPD-W Keyword Header */ + if (off == alloc) { + cfg->vpd.vpd_w = kreallocf(cfg->vpd.vpd_w, + (alloc *= 2) * sizeof(*cfg->vpd.vpd_w), + M_DEVBUF, M_WAITOK | M_ZERO); + } + cfg->vpd.vpd_w[off].keyword[0] = byte; + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + cfg->vpd.vpd_w[off].keyword[1] = byte2; + if (vpd_nextbyte(&vrs, &byte2)) { + state = -2; + break; + } + cfg->vpd.vpd_w[off].len = dflen = byte2; + cfg->vpd.vpd_w[off].start = vrs.off - vrs.bytesinval; + cfg->vpd.vpd_w[off].value = kmalloc((dflen + 1) * + sizeof(*cfg->vpd.vpd_w[off].value), + M_DEVBUF, M_WAITOK); + remain -= 3; + i = 0; + /* keep in sync w/ state 6's transistions */ + if (dflen == 0 && remain == 0) + state = 0; + else if (dflen == 0) + state = 5; + else + state = 6; + break; + + case 6: /* VPD-W Keyword Value */ + cfg->vpd.vpd_w[off].value[i++] = byte; + dflen--; + remain--; + /* keep in sync w/ state 5's transistions */ + if (dflen == 0) + cfg->vpd.vpd_w[off++].value[i++] = '\0'; + if (dflen == 0 && remain == 0) { + cfg->vpd.vpd_wcnt = off; + cfg->vpd.vpd_w = kreallocf(cfg->vpd.vpd_w, + off * sizeof(*cfg->vpd.vpd_w), + M_DEVBUF, M_WAITOK | M_ZERO); + state = 0; + } else if (dflen == 0) + state = 5; + break; + + default: + kprintf("pci%d:%d:%d:%d: invalid state: %d\n", + cfg->domain, cfg->bus, cfg->slot, cfg->func, + state); + state = -1; + break; + } + } + + if (cksumvalid == 0 || state < -1) { + /* read-only data bad, clean up */ + if (cfg->vpd.vpd_ros != NULL) { + for (off = 0; cfg->vpd.vpd_ros[off].value; off++) + kfree(cfg->vpd.vpd_ros[off].value, M_DEVBUF); + kfree(cfg->vpd.vpd_ros, M_DEVBUF); + cfg->vpd.vpd_ros = NULL; + } + } + if (state < -1) { + /* I/O error, clean up */ + kprintf("pci%d:%d:%d:%d: failed to read VPD data.\n", + cfg->domain, cfg->bus, cfg->slot, cfg->func); + if (cfg->vpd.vpd_ident != NULL) { + kfree(cfg->vpd.vpd_ident, M_DEVBUF); + cfg->vpd.vpd_ident = NULL; + } + if (cfg->vpd.vpd_w != NULL) { + for (off = 0; cfg->vpd.vpd_w[off].value; off++) + kfree(cfg->vpd.vpd_w[off].value, M_DEVBUF); + kfree(cfg->vpd.vpd_w, M_DEVBUF); + cfg->vpd.vpd_w = NULL; + } + } + cfg->vpd.vpd_cached = 1; +#undef REG +#undef WREG +} + +int +pci_get_vpd_ident_method(device_t dev, device_t child, const char **identptr) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + + if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) + pci_read_vpd(device_get_parent(dev), cfg); + + *identptr = cfg->vpd.vpd_ident; + + if (*identptr == NULL) + return (ENXIO); + + return (0); +} + +int +pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw, + const char **vptr) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + int i; + + if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) + pci_read_vpd(device_get_parent(dev), cfg); + + for (i = 0; i < cfg->vpd.vpd_rocnt; i++) + if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword, + sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) { + *vptr = cfg->vpd.vpd_ros[i].value; + } + + if (i != cfg->vpd.vpd_rocnt) + return (0); + + *vptr = NULL; + return (ENXIO); +} + +/* + * Return the offset in configuration space of the requested extended + * capability entry or 0 if the specified capability was not found. + */ +int +pci_find_extcap_method(device_t dev, device_t child, int capability, + int *capreg) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + u_int32_t status; + u_int8_t ptr; + + /* + * Check the CAP_LIST bit of the PCI status register first. + */ + status = pci_read_config(child, PCIR_STATUS, 2); + if (!(status & PCIM_STATUS_CAPPRESENT)) + return (ENXIO); + + /* + * Determine the start pointer of the capabilities list. + */ + switch (cfg->hdrtype & PCIM_HDRTYPE) { + case 0: + case 1: + ptr = PCIR_CAP_PTR; + break; + case 2: + ptr = PCIR_CAP_PTR_2; + break; + default: + /* XXX: panic? */ + return (ENXIO); /* no extended capabilities support */ + } + ptr = pci_read_config(child, ptr, 1); + + /* + * Traverse the capabilities list. + */ + while (ptr != 0) { + if (pci_read_config(child, ptr + PCICAP_ID, 1) == capability) { + if (capreg != NULL) + *capreg = ptr; + return (0); + } + ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1); + } + + return (ENOENT); +} + +/* + * Support for MSI-X message interrupts. + */ +void +pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + uint32_t offset; + + KASSERT(msix->msix_table_len > index, ("bogus index")); + offset = msix->msix_table_offset + index * 16; + bus_write_4(msix->msix_table_res, offset, address & 0xffffffff); + bus_write_4(msix->msix_table_res, offset + 4, address >> 32); + bus_write_4(msix->msix_table_res, offset + 8, data); + + /* Enable MSI -> HT mapping. */ + pci_ht_map_msi(dev, address); +} + +void +pci_mask_msix(device_t dev, u_int index) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + uint32_t offset, val; + + KASSERT(msix->msix_msgnum > index, ("bogus index")); + offset = msix->msix_table_offset + index * 16 + 12; + val = bus_read_4(msix->msix_table_res, offset); + if (!(val & PCIM_MSIX_VCTRL_MASK)) { + val |= PCIM_MSIX_VCTRL_MASK; + bus_write_4(msix->msix_table_res, offset, val); + } +} + +void +pci_unmask_msix(device_t dev, u_int index) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + uint32_t offset, val; + + KASSERT(msix->msix_table_len > index, ("bogus index")); + offset = msix->msix_table_offset + index * 16 + 12; + val = bus_read_4(msix->msix_table_res, offset); + if (val & PCIM_MSIX_VCTRL_MASK) { + val &= ~PCIM_MSIX_VCTRL_MASK; + bus_write_4(msix->msix_table_res, offset, val); + } +} + +int +pci_pending_msix(device_t dev, u_int index) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + uint32_t offset, bit; + + KASSERT(msix->msix_table_len > index, ("bogus index")); + offset = msix->msix_pba_offset + (index / 32) * 4; + bit = 1 << index % 32; + return (bus_read_4(msix->msix_pba_res, offset) & bit); +} + +/* + * Restore MSI-X registers and table during resume. If MSI-X is + * enabled then walk the virtual table to restore the actual MSI-X + * table. + */ +static void +pci_resume_msix(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + struct msix_table_entry *mte; + struct msix_vector *mv; + int i; + + if (msix->msix_alloc > 0) { + /* First, mask all vectors. */ + for (i = 0; i < msix->msix_msgnum; i++) + pci_mask_msix(dev, i); + + /* Second, program any messages with at least one handler. */ + for (i = 0; i < msix->msix_table_len; i++) { + mte = &msix->msix_table[i]; + if (mte->mte_vector == 0 || mte->mte_handlers == 0) + continue; + mv = &msix->msix_vectors[mte->mte_vector - 1]; + pci_enable_msix(dev, i, mv->mv_address, mv->mv_data); + pci_unmask_msix(dev, i); + } + } + pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL, + msix->msix_ctrl, 2); +} + +/* + * Attempt to allocate *count MSI-X messages. The actual number allocated is + * returned in *count. After this function returns, each message will be + * available to the driver as SYS_RES_IRQ resources starting at rid 1. + */ +int +pci_alloc_msix_method(device_t dev, device_t child, int *count) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + struct resource_list_entry *rle; + int actual, error, i, irq, max; + + /* Don't let count == 0 get us into trouble. */ + if (*count == 0) + return (EINVAL); + + /* If rid 0 is allocated, then fail. */ + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0); + if (rle != NULL && rle->res != NULL) + return (ENXIO); + + /* Already have allocated messages? */ + if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0) + return (ENXIO); + + /* If MSI is blacklisted for this system, fail. */ + if (pci_msi_blacklisted()) + return (ENXIO); + + /* MSI-X capability present? */ + if (cfg->msix.msix_location == 0 || !pci_do_msix) + return (ENODEV); + + /* Make sure the appropriate BARs are mapped. */ + rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, + cfg->msix.msix_table_bar); + if (rle == NULL || rle->res == NULL || + !(rman_get_flags(rle->res) & RF_ACTIVE)) + return (ENXIO); + cfg->msix.msix_table_res = rle->res; + if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) { + rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, + cfg->msix.msix_pba_bar); + if (rle == NULL || rle->res == NULL || + !(rman_get_flags(rle->res) & RF_ACTIVE)) + return (ENXIO); + } + cfg->msix.msix_pba_res = rle->res; + + if (bootverbose) + device_printf(child, + "attempting to allocate %d MSI-X vectors (%d supported)\n", + *count, cfg->msix.msix_msgnum); + max = min(*count, cfg->msix.msix_msgnum); + for (i = 0; i < max; i++) { + /* Allocate a message. */ + error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq); + if (error) + break; + resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq, + irq, 1); + } + actual = i; + + if (bootverbose) { + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1); + if (actual == 1) + device_printf(child, "using IRQ %lu for MSI-X\n", + rle->start); + else { + int run; + + /* + * Be fancy and try to print contiguous runs of + * IRQ values as ranges. 'irq' is the previous IRQ. + * 'run' is true if we are in a range. + */ + device_printf(child, "using IRQs %lu", rle->start); + irq = rle->start; + run = 0; + for (i = 1; i < actual; i++) { + rle = resource_list_find(&dinfo->resources, + SYS_RES_IRQ, i + 1); + + /* Still in a run? */ + if (rle->start == irq + 1) { + run = 1; + irq++; + continue; + } + + /* Finish previous range. */ + if (run) { + kprintf("-%d", irq); + run = 0; + } + + /* Start new range. */ + kprintf(",%lu", rle->start); + irq = rle->start; + } + + /* Unfinished range? */ + if (run) + kprintf("-%d", irq); + kprintf(" for MSI-X\n"); + } + } + + /* Mask all vectors. */ + for (i = 0; i < cfg->msix.msix_msgnum; i++) + pci_mask_msix(child, i); + + /* Allocate and initialize vector data and virtual table. */ + cfg->msix.msix_vectors = kmalloc(sizeof(struct msix_vector) * actual, + M_DEVBUF, M_WAITOK | M_ZERO); + cfg->msix.msix_table = kmalloc(sizeof(struct msix_table_entry) * actual, + M_DEVBUF, M_WAITOK | M_ZERO); + for (i = 0; i < actual; i++) { + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); + cfg->msix.msix_vectors[i].mv_irq = rle->start; + cfg->msix.msix_table[i].mte_vector = i + 1; + } + + /* Update control register to enable MSI-X. */ + cfg->msix.msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; + pci_write_config(child, cfg->msix.msix_location + PCIR_MSIX_CTRL, + cfg->msix.msix_ctrl, 2); + + /* Update counts of alloc'd messages. */ + cfg->msix.msix_alloc = actual; + cfg->msix.msix_table_len = actual; + *count = actual; + return (0); +} + +/* + * By default, pci_alloc_msix() will assign the allocated IRQ + * resources consecutively to the first N messages in the MSI-X table. + * However, device drivers may want to use different layouts if they + * either receive fewer messages than they asked for, or they wish to + * populate the MSI-X table sparsely. This method allows the driver + * to specify what layout it wants. It must be called after a + * successful pci_alloc_msix() but before any of the associated + * SYS_RES_IRQ resources are allocated via bus_alloc_resource(). + * + * The 'vectors' array contains 'count' message vectors. The array + * maps directly to the MSI-X table in that index 0 in the array + * specifies the vector for the first message in the MSI-X table, etc. + * The vector value in each array index can either be 0 to indicate + * that no vector should be assigned to a message slot, or it can be a + * number from 1 to N (where N is the count returned from a + * succcessful call to pci_alloc_msix()) to indicate which message + * vector (IRQ) to be used for the corresponding message. + * + * On successful return, each message with a non-zero vector will have + * an associated SYS_RES_IRQ whose rid is equal to the array index + + * 1. Additionally, if any of the IRQs allocated via the previous + * call to pci_alloc_msix() are not used in the mapping, those IRQs + * will be kfreed back to the system automatically. + * + * For example, suppose a driver has a MSI-X table with 6 messages and + * asks for 6 messages, but pci_alloc_msix() only returns a count of + * 3. Call the three vectors allocated by pci_alloc_msix() A, B, and + * C. After the call to pci_alloc_msix(), the device will be setup to + * have an MSI-X table of ABC--- (where - means no vector assigned). + * If the driver ten passes a vector array of { 1, 0, 1, 2, 0, 2 }, + * then the MSI-X table will look like A-AB-B, and the 'C' vector will + * be kfreed back to the system. This device will also have valid + * SYS_RES_IRQ rids of 1, 3, 4, and 6. + * + * In any case, the SYS_RES_IRQ rid X will always map to the message + * at MSI-X table index X - 1 and will only be valid if a vector is + * assigned to that table entry. + */ +int +pci_remap_msix_method(device_t dev, device_t child, int count, + const u_int *vectors) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + struct resource_list_entry *rle; + int i, irq, j, *used; + + /* + * Have to have at least one message in the table but the + * table can't be bigger than the actual MSI-X table in the + * device. + */ + if (count == 0 || count > msix->msix_msgnum) + return (EINVAL); + + /* Sanity check the vectors. */ + for (i = 0; i < count; i++) + if (vectors[i] > msix->msix_alloc) + return (EINVAL); + + /* + * Make sure there aren't any holes in the vectors to be used. + * It's a big pain to support it, and it doesn't really make + * sense anyway. Also, at least one vector must be used. + */ + used = kmalloc(sizeof(int) * msix->msix_alloc, M_DEVBUF, M_WAITOK | + M_ZERO); + for (i = 0; i < count; i++) + if (vectors[i] != 0) + used[vectors[i] - 1] = 1; + for (i = 0; i < msix->msix_alloc - 1; i++) + if (used[i] == 0 && used[i + 1] == 1) { + kfree(used, M_DEVBUF); + return (EINVAL); + } + if (used[0] != 1) { + kfree(used, M_DEVBUF); + return (EINVAL); + } + + /* Make sure none of the resources are allocated. */ + for (i = 0; i < msix->msix_table_len; i++) { + if (msix->msix_table[i].mte_vector == 0) + continue; + if (msix->msix_table[i].mte_handlers > 0) + return (EBUSY); + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); + KASSERT(rle != NULL, ("missing resource")); + if (rle->res != NULL) + return (EBUSY); + } + + /* Free the existing resource list entries. */ + for (i = 0; i < msix->msix_table_len; i++) { + if (msix->msix_table[i].mte_vector == 0) + continue; + resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); + } + + /* + * Build the new virtual table keeping track of which vectors are + * used. + */ + kfree(msix->msix_table, M_DEVBUF); + msix->msix_table = kmalloc(sizeof(struct msix_table_entry) * count, + M_DEVBUF, M_WAITOK | M_ZERO); + for (i = 0; i < count; i++) + msix->msix_table[i].mte_vector = vectors[i]; + msix->msix_table_len = count; + + /* Free any unused IRQs and resize the vectors array if necessary. */ + j = msix->msix_alloc - 1; + if (used[j] == 0) { + struct msix_vector *vec; + + while (used[j] == 0) { + PCIB_RELEASE_MSIX(device_get_parent(dev), child, + msix->msix_vectors[j].mv_irq); + j--; + } + vec = kmalloc(sizeof(struct msix_vector) * (j + 1), M_DEVBUF, + M_WAITOK); + bcopy(msix->msix_vectors, vec, sizeof(struct msix_vector) * + (j + 1)); + kfree(msix->msix_vectors, M_DEVBUF); + msix->msix_vectors = vec; + msix->msix_alloc = j + 1; + } + kfree(used, M_DEVBUF); + + /* Map the IRQs onto the rids. */ + for (i = 0; i < count; i++) { + if (vectors[i] == 0) + continue; + irq = msix->msix_vectors[vectors[i]].mv_irq; + resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq, + irq, 1); + } + + if (bootverbose) { + device_printf(child, "Remapped MSI-X IRQs as: "); + for (i = 0; i < count; i++) { + if (i != 0) + kprintf(", "); + if (vectors[i] == 0) + kprintf("---"); + else + kprintf("%d", + msix->msix_vectors[vectors[i]].mv_irq); + } + kprintf("\n"); + } + + return (0); +} + +static int +pci_release_msix(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + struct resource_list_entry *rle; + int i; + + /* Do we have any messages to release? */ + if (msix->msix_alloc == 0) + return (ENODEV); + + /* Make sure none of the resources are allocated. */ + for (i = 0; i < msix->msix_table_len; i++) { + if (msix->msix_table[i].mte_vector == 0) + continue; + if (msix->msix_table[i].mte_handlers > 0) + return (EBUSY); + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); + KASSERT(rle != NULL, ("missing resource")); + if (rle->res != NULL) + return (EBUSY); + } + + /* Update control register to disable MSI-X. */ + msix->msix_ctrl &= ~PCIM_MSIXCTRL_MSIX_ENABLE; + pci_write_config(child, msix->msix_location + PCIR_MSIX_CTRL, + msix->msix_ctrl, 2); + + /* Free the resource list entries. */ + for (i = 0; i < msix->msix_table_len; i++) { + if (msix->msix_table[i].mte_vector == 0) + continue; + resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); + } + kfree(msix->msix_table, M_DEVBUF); + msix->msix_table_len = 0; + + /* Release the IRQs. */ + for (i = 0; i < msix->msix_alloc; i++) + PCIB_RELEASE_MSIX(device_get_parent(dev), child, + msix->msix_vectors[i].mv_irq); + kfree(msix->msix_vectors, M_DEVBUF); + msix->msix_alloc = 0; + return (0); +} + +/* + * Return the max supported MSI-X messages this device supports. + * Basically, assuming the MD code can alloc messages, this function + * should return the maximum value that pci_alloc_msix() can return. + * Thus, it is subject to the tunables, etc. + */ +int +pci_msix_count_method(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + + if (pci_do_msix && msix->msix_location != 0) + return (msix->msix_msgnum); + return (0); +} + +/* + * HyperTransport MSI mapping control + */ +void +pci_ht_map_msi(device_t dev, uint64_t addr) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_ht *ht = &dinfo->cfg.ht; + + if (!ht->ht_msimap) + return; + + if (addr && !(ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) && + ht->ht_msiaddr >> 20 == addr >> 20) { + /* Enable MSI -> HT mapping. */ + ht->ht_msictrl |= PCIM_HTCMD_MSI_ENABLE; + pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, + ht->ht_msictrl, 2); + } + + if (!addr && ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) { + /* Disable MSI -> HT mapping. */ + ht->ht_msictrl &= ~PCIM_HTCMD_MSI_ENABLE; + pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, + ht->ht_msictrl, 2); + } +} + +/* + * Support for MSI message signalled interrupts. + */ +void +pci_enable_msi(device_t dev, uint64_t address, uint16_t data) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + + /* Write data and address values. */ + pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR, + address & 0xffffffff, 4); + if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) { + pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR_HIGH, + address >> 32, 4); + pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT, + data, 2); + } else + pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data, + 2); + + /* Enable MSI in the control register. */ + msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE; + pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, + 2); + + /* Enable MSI -> HT mapping. */ + pci_ht_map_msi(dev, address); +} + +void +pci_disable_msi(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + + /* Disable MSI -> HT mapping. */ + pci_ht_map_msi(dev, 0); + + /* Disable MSI in the control register. */ + msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE; + pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, + 2); +} + +/* + * Restore MSI registers during resume. If MSI is enabled then + * restore the data and address registers in addition to the control + * register. + */ +static void +pci_resume_msi(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + uint64_t address; + uint16_t data; + + if (msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE) { + address = msi->msi_addr; + data = msi->msi_data; + pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR, + address & 0xffffffff, 4); + if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) { + pci_write_config(dev, msi->msi_location + + PCIR_MSI_ADDR_HIGH, address >> 32, 4); + pci_write_config(dev, msi->msi_location + + PCIR_MSI_DATA_64BIT, data, 2); + } else + pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, + data, 2); + } + pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, + 2); +} + +int +pci_remap_msi_irq(device_t dev, u_int irq) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + struct resource_list_entry *rle; + struct msix_table_entry *mte; + struct msix_vector *mv; + device_t bus; + uint64_t addr; + uint32_t data; + int error, i, j; + + bus = device_get_parent(dev); + + /* + * Handle MSI first. We try to find this IRQ among our list + * of MSI IRQs. If we find it, we request updated address and + * data registers and apply the results. + */ + if (cfg->msi.msi_alloc > 0) { + + /* If we don't have any active handlers, nothing to do. */ + if (cfg->msi.msi_handlers == 0) + return (0); + for (i = 0; i < cfg->msi.msi_alloc; i++) { + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, + i + 1); + if (rle->start == irq) { + error = PCIB_MAP_MSI(device_get_parent(bus), + dev, irq, &addr, &data); + if (error) + return (error); + pci_disable_msi(dev); + dinfo->cfg.msi.msi_addr = addr; + dinfo->cfg.msi.msi_data = data; + pci_enable_msi(dev, addr, data); + return (0); + } + } + return (ENOENT); + } + + /* + * For MSI-X, we check to see if we have this IRQ. If we do, + * we request the updated mapping info. If that works, we go + * through all the slots that use this IRQ and update them. + */ + if (cfg->msix.msix_alloc > 0) { + for (i = 0; i < cfg->msix.msix_alloc; i++) { + mv = &cfg->msix.msix_vectors[i]; + if (mv->mv_irq == irq) { + error = PCIB_MAP_MSI(device_get_parent(bus), + dev, irq, &addr, &data); + if (error) + return (error); + mv->mv_address = addr; + mv->mv_data = data; + for (j = 0; j < cfg->msix.msix_table_len; j++) { + mte = &cfg->msix.msix_table[j]; + if (mte->mte_vector != i + 1) + continue; + if (mte->mte_handlers == 0) + continue; + pci_mask_msix(dev, j); + pci_enable_msix(dev, j, addr, data); + pci_unmask_msix(dev, j); + } + } + } + return (ENOENT); + } + + return (ENOENT); +} + +/* + * Returns true if the specified device is blacklisted because MSI + * doesn't work. + */ +int +pci_msi_device_blacklisted(device_t dev) +{ + struct pci_quirk *q; + + if (!pci_honor_msi_blacklist) + return (0); + + for (q = &pci_quirks[0]; q->devid; q++) { + if (q->devid == pci_get_devid(dev) && + q->type == PCI_QUIRK_DISABLE_MSI) + return (1); + } + return (0); +} + +/* + * Determine if MSI is blacklisted globally on this sytem. Currently, + * we just check for blacklisted chipsets as represented by the + * host-PCI bridge at device 0:0:0. In the future, it may become + * necessary to check other system attributes, such as the kenv values + * that give the motherboard manufacturer and model number. + */ +static int +pci_msi_blacklisted(void) +{ + device_t dev; + + if (!pci_honor_msi_blacklist) + return (0); + + /* Blacklist all non-PCI-express and non-PCI-X chipsets. */ + if (!(pcie_chipset || pcix_chipset)) + return (1); + + dev = pci_find_bsf(0, 0, 0); + if (dev != NULL) + return (pci_msi_device_blacklisted(dev)); + return (0); +} + +/* + * Attempt to allocate *count MSI messages. The actual number allocated is + * returned in *count. After this function returns, each message will be + * available to the driver as SYS_RES_IRQ resources starting at a rid 1. + */ +int +pci_alloc_msi_method(device_t dev, device_t child, int *count) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + struct resource_list_entry *rle; + int actual, error, i, irqs[32]; + uint16_t ctrl; + + /* Don't let count == 0 get us into trouble. */ + if (*count == 0) + return (EINVAL); + + /* If rid 0 is allocated, then fail. */ + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0); + if (rle != NULL && rle->res != NULL) + return (ENXIO); + + /* Already have allocated messages? */ + if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0) + return (ENXIO); + + /* If MSI is blacklisted for this system, fail. */ + if (pci_msi_blacklisted()) + return (ENXIO); + + /* MSI capability present? */ + if (cfg->msi.msi_location == 0 || !pci_do_msi) + return (ENODEV); + + if (bootverbose) + device_printf(child, + "attempting to allocate %d MSI vectors (%d supported)\n", + *count, cfg->msi.msi_msgnum); + + /* Don't ask for more than the device supports. */ + actual = min(*count, cfg->msi.msi_msgnum); + + /* Don't ask for more than 32 messages. */ + actual = min(actual, 32); + + /* MSI requires power of 2 number of messages. */ + if (!powerof2(actual)) + return (EINVAL); + + for (;;) { + /* Try to allocate N messages. */ + error = PCIB_ALLOC_MSI(device_get_parent(dev), child, actual, + cfg->msi.msi_msgnum, irqs); + if (error == 0) + break; + if (actual == 1) + return (error); + + /* Try N / 2. */ + actual >>= 1; + } + + /* + * We now have N actual messages mapped onto SYS_RES_IRQ + * resources in the irqs[] array, so add new resources + * starting at rid 1. + */ + for (i = 0; i < actual; i++) + resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, + irqs[i], irqs[i], 1); + + if (bootverbose) { + if (actual == 1) + device_printf(child, "using IRQ %d for MSI\n", irqs[0]); + else { + int run; + + /* + * Be fancy and try to print contiguous runs + * of IRQ values as ranges. 'run' is true if + * we are in a range. + */ + device_printf(child, "using IRQs %d", irqs[0]); + run = 0; + for (i = 1; i < actual; i++) { + + /* Still in a run? */ + if (irqs[i] == irqs[i - 1] + 1) { + run = 1; + continue; + } + + /* Finish previous range. */ + if (run) { + kprintf("-%d", irqs[i - 1]); + run = 0; + } + + /* Start new range. */ + kprintf(",%d", irqs[i]); + } + + /* Unfinished range? */ + if (run) + kprintf("-%d", irqs[actual - 1]); + kprintf(" for MSI\n"); + } + } + + /* Update control register with actual count. */ + ctrl = cfg->msi.msi_ctrl; + ctrl &= ~PCIM_MSICTRL_MME_MASK; + ctrl |= (ffs(actual) - 1) << 4; + cfg->msi.msi_ctrl = ctrl; + pci_write_config(child, cfg->msi.msi_location + PCIR_MSI_CTRL, ctrl, 2); + + /* Update counts of alloc'd messages. */ + cfg->msi.msi_alloc = actual; + cfg->msi.msi_handlers = 0; + *count = actual; + return (0); +} + +/* Release the MSI messages associated with this device. */ +int +pci_release_msi_method(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + struct resource_list_entry *rle; + int error, i, irqs[32]; + + /* Try MSI-X first. */ + error = pci_release_msix(dev, child); + if (error != ENODEV) + return (error); + + /* Do we have any messages to release? */ + if (msi->msi_alloc == 0) + return (ENODEV); + KASSERT(msi->msi_alloc <= 32, ("more than 32 alloc'd messages")); + + /* Make sure none of the resources are allocated. */ + if (msi->msi_handlers > 0) + return (EBUSY); + for (i = 0; i < msi->msi_alloc; i++) { + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); + KASSERT(rle != NULL, ("missing MSI resource")); + if (rle->res != NULL) + return (EBUSY); + irqs[i] = rle->start; + } + + /* Update control register with 0 count. */ + KASSERT(!(msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE), + ("%s: MSI still enabled", __func__)); + msi->msi_ctrl &= ~PCIM_MSICTRL_MME_MASK; + pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, + msi->msi_ctrl, 2); + + /* Release the messages. */ + PCIB_RELEASE_MSI(device_get_parent(dev), child, msi->msi_alloc, irqs); + for (i = 0; i < msi->msi_alloc; i++) + resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); + + /* Update alloc count. */ + msi->msi_alloc = 0; + msi->msi_addr = 0; + msi->msi_data = 0; + return (0); +} + +/* + * Return the max supported MSI messages this device supports. + * Basically, assuming the MD code can alloc messages, this function + * should return the maximum value that pci_alloc_msi() can return. + * Thus, it is subject to the tunables, etc. + */ +int +pci_msi_count_method(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct pcicfg_msi *msi = &dinfo->cfg.msi; + + if (pci_do_msi && msi->msi_location != 0) + return (msi->msi_msgnum); + return (0); +} + +/* kfree pcicfgregs structure and all depending data structures */ + +int +pci_freecfg(struct pci_devinfo *dinfo) +{ + struct devlist *devlist_head; + int i; + + devlist_head = &pci_devq; + + if (dinfo->cfg.vpd.vpd_reg) { + kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF); + for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++) + kfree(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF); + kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF); + for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++) + kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); + kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF); + } + STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); + kfree(dinfo, M_DEVBUF); + + /* increment the generation count */ + pci_generation++; + + /* we're losing one device */ + pci_numdevs--; + return (0); +} + +/* + * PCI power manangement + */ +int +pci_set_powerstate_method(device_t dev, device_t child, int state) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; uint16_t status; int result, oldstate, highest, delay; - if (cfg->pmgt.pp_cap == 0) + if (cfg->pp.pp_cap == 0) return (EOPNOTSUPP); /* @@ -709,7 +2048,7 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) delay = 200; else delay = 0; - status = PCI_READ_CONFIG(dev, child, cfg->pmgt.pp_status, 2) + status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2) & ~PCIM_PSTAT_DMASK; result = 0; switch (state) { @@ -717,12 +2056,12 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) status |= PCIM_PSTAT_D0; break; case PCI_POWERSTATE_D1: - if ((cfg->pmgt.pp_cap & PCIM_PCAP_D1SUPP) == 0) + if ((cfg->pp.pp_cap & PCIM_PCAP_D1SUPP) == 0) return (EOPNOTSUPP); status |= PCIM_PSTAT_D1; break; case PCI_POWERSTATE_D2: - if ((cfg->pmgt.pp_cap & PCIM_PCAP_D2SUPP) == 0) + if ((cfg->pp.pp_cap & PCIM_PCAP_D2SUPP) == 0) return (EOPNOTSUPP); status |= PCIM_PSTAT_D2; break; @@ -735,11 +2074,11 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) if (bootverbose) kprintf( - "pci%d:%d:%d: Transition from D%d to D%d\n", - dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func, - oldstate, state); + "pci%d:%d:%d:%d: Transition from D%d to D%d\n", + dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot, + dinfo->cfg.func, oldstate, state); - PCI_WRITE_CONFIG(dev, child, cfg->pmgt.pp_status, status, 2); + PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_status, status, 2); if (delay) DELAY(delay); return (0); @@ -753,8 +2092,8 @@ pci_get_powerstate_method(device_t dev, device_t child) uint16_t status; int result; - if (cfg->pmgt.pp_cap != 0) { - status = PCI_READ_CONFIG(dev, child, cfg->pmgt.pp_status, 2); + if (cfg->pp.pp_cap != 0) { + status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2); switch (status & PCIM_PSTAT_DMASK) { case PCIM_PSTAT_D0: result = PCI_POWERSTATE_D0; @@ -784,739 +2123,160 @@ pci_get_powerstate_method(device_t dev, device_t child) */ static __inline void -pci_set_command_bit(device_t dev, device_t child, u_int16_t bit) +pci_set_command_bit(device_t dev, device_t child, uint16_t bit) { - u_int16_t command; + uint16_t command; - command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); - command |= bit; - PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); + command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); + command |= bit; + PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); } static __inline void -pci_clear_command_bit(device_t dev, device_t child, u_int16_t bit) -{ - u_int16_t command; - - command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); - command &= ~bit; - PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); -} - -int -pci_enable_busmaster_method(device_t dev, device_t child) -{ - pci_set_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); - return(0); -} - -int -pci_disable_busmaster_method(device_t dev, device_t child) -{ - pci_clear_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); - return(0); -} - -int -pci_enable_io_method(device_t dev, device_t child, int space) -{ - uint16_t command; - uint16_t bit; - char *error; - - bit = 0; - error = NULL; - - switch(space) { - case SYS_RES_IOPORT: - bit = PCIM_CMD_PORTEN; - error = "port"; - break; - case SYS_RES_MEMORY: - bit = PCIM_CMD_MEMEN; - error = "memory"; - break; - default: - return(EINVAL); - } - pci_set_command_bit(dev, child, bit); - command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); - if (command & bit) - return(0); - device_printf(child, "failed to enable %s mapping!\n", error); - return(ENXIO); -} - -int -pci_disable_io_method(device_t dev, device_t child, int space) -{ - uint16_t command; - uint16_t bit; - char *error; - - bit = 0; - error = NULL; - - switch(space) { - case SYS_RES_IOPORT: - bit = PCIM_CMD_PORTEN; - error = "port"; - break; - case SYS_RES_MEMORY: - bit = PCIM_CMD_MEMEN; - error = "memory"; - break; - default: - return (EINVAL); - } - pci_clear_command_bit(dev, child, bit); - command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); - if (command & bit) { - device_printf(child, "failed to disable %s mapping!\n", error); - return (ENXIO); - } - return (0); -} - -/* - * This is the user interface to PCI configuration space. - */ - -static int -pci_open(struct dev_open_args *ap) -{ - if ((ap->a_oflags & FWRITE) && securelevel > 0) { - return EPERM; - } - return 0; -} - -static int -pci_close(struct dev_close_args *ap) -{ - return 0; -} - -/* - * Match a single pci_conf structure against an array of pci_match_conf - * structures. The first argument, 'matches', is an array of num_matches - * pci_match_conf structures. match_buf is a pointer to the pci_conf - * structure that will be compared to every entry in the matches array. - * This function returns 1 on failure, 0 on success. - */ -static int -pci_conf_match(struct pci_match_conf *matches, int num_matches, - struct pci_conf *match_buf) -{ - int i; - - if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) - return(1); - - for (i = 0; i < num_matches; i++) { - /* - * I'm not sure why someone would do this...but... - */ - if (matches[i].flags == PCI_GETCONF_NO_MATCH) - continue; - - /* - * Look at each of the match flags. If it's set, do the - * comparison. If the comparison fails, we don't have a - * match, go on to the next item if there is one. - */ - if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) - && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) - && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) - && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) - && (match_buf->pc_vendor != matches[i].pc_vendor)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) - && (match_buf->pc_device != matches[i].pc_device)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) - && (match_buf->pc_class != matches[i].pc_class)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) - && (match_buf->pd_unit != matches[i].pd_unit)) - continue; - - if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) - && (strncmp(matches[i].pd_name, match_buf->pd_name, - sizeof(match_buf->pd_name)) != 0)) - continue; - - return(0); - } - - return(1); -} - -/* - * Locate the parent of a PCI device by scanning the PCI devlist - * and return the entry for the parent. - * For devices on PCI Bus 0 (the host bus), this is the PCI Host. - * For devices on secondary PCI busses, this is that bus' PCI-PCI Bridge. - */ - -pcicfgregs * -pci_devlist_get_parent(pcicfgregs *cfg) -{ - struct devlist *devlist_head; - struct pci_devinfo *dinfo; - pcicfgregs *bridge_cfg; - int i; - - dinfo = STAILQ_FIRST(devlist_head = &pci_devq); - - /* If the device is on PCI bus 0, look for the host */ - if (cfg->bus == 0) { - for (i = 0; (dinfo != NULL) && (i < pci_numdevs); - dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { - bridge_cfg = &dinfo->cfg; - if (bridge_cfg->baseclass == PCIC_BRIDGE - && bridge_cfg->subclass == PCIS_BRIDGE_HOST - && bridge_cfg->bus == cfg->bus) { - return bridge_cfg; - } - } - } - - /* If the device is not on PCI bus 0, look for the PCI-PCI bridge */ - if (cfg->bus > 0) { - for (i = 0; (dinfo != NULL) && (i < pci_numdevs); - dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { - bridge_cfg = &dinfo->cfg; - if (bridge_cfg->baseclass == PCIC_BRIDGE - && bridge_cfg->subclass == PCIS_BRIDGE_PCI - && bridge_cfg->secondarybus == cfg->bus) { - return bridge_cfg; - } - } - } - - return NULL; -} - -static int -pci_ioctl(struct dev_ioctl_args *ap) -{ - device_t pci, pcib; - struct pci_io *io; - const char *name; - int error; - - if (!(ap->a_fflag & FWRITE)) - return EPERM; - - switch(ap->a_cmd) { - case PCIOCGETCONF: - { - struct pci_devinfo *dinfo; - struct pci_conf_io *cio; - struct devlist *devlist_head; - struct pci_match_conf *pattern_buf; - int num_patterns; - size_t iolen; - int ionum, i; - - cio = (struct pci_conf_io *)ap->a_data; - - num_patterns = 0; - dinfo = NULL; - - /* - * Hopefully the user won't pass in a null pointer, but it - * can't hurt to check. - */ - if (cio == NULL) { - error = EINVAL; - break; - } - - /* - * If the user specified an offset into the device list, - * but the list has changed since they last called this - * ioctl, tell them that the list has changed. They will - * have to get the list from the beginning. - */ - if ((cio->offset != 0) - && (cio->generation != pci_generation)){ - cio->num_matches = 0; - cio->status = PCI_GETCONF_LIST_CHANGED; - error = 0; - break; - } - - /* - * Check to see whether the user has asked for an offset - * past the end of our list. - */ - if (cio->offset >= pci_numdevs) { - cio->num_matches = 0; - cio->status = PCI_GETCONF_LAST_DEVICE; - error = 0; - break; - } - - /* get the head of the device queue */ - devlist_head = &pci_devq; - - /* - * Determine how much room we have for pci_conf structures. - * Round the user's buffer size down to the nearest - * multiple of sizeof(struct pci_conf) in case the user - * didn't specify a multiple of that size. - */ - iolen = min(cio->match_buf_len - - (cio->match_buf_len % sizeof(struct pci_conf)), - pci_numdevs * sizeof(struct pci_conf)); - - /* - * Since we know that iolen is a multiple of the size of - * the pciconf union, it's okay to do this. - */ - ionum = iolen / sizeof(struct pci_conf); - - /* - * If this test is true, the user wants the pci_conf - * structures returned to match the supplied entries. - */ - if ((cio->num_patterns > 0) - && (cio->pat_buf_len > 0)) { - /* - * pat_buf_len needs to be: - * num_patterns * sizeof(struct pci_match_conf) - * While it is certainly possible the user just - * allocated a large buffer, but set the number of - * matches correctly, it is far more likely that - * their kernel doesn't match the userland utility - * they're using. It's also possible that the user - * forgot to initialize some variables. Yes, this - * may be overly picky, but I hazard to guess that - * it's far more likely to just catch folks that - * updated their kernel but not their userland. - */ - if ((cio->num_patterns * - sizeof(struct pci_match_conf)) != cio->pat_buf_len){ - /* The user made a mistake, return an error*/ - cio->status = PCI_GETCONF_ERROR; - kprintf("pci_ioctl: pat_buf_len %d != " - "num_patterns (%d) * sizeof(struct " - "pci_match_conf) (%d)\npci_ioctl: " - "pat_buf_len should be = %d\n", - cio->pat_buf_len, cio->num_patterns, - (int)sizeof(struct pci_match_conf), - (int)sizeof(struct pci_match_conf) * - cio->num_patterns); - kprintf("pci_ioctl: do your headers match your " - "kernel?\n"); - cio->num_matches = 0; - error = EINVAL; - break; - } - - /* - * Check the user's buffer to make sure it's readable. - */ - if (!useracc((caddr_t)cio->patterns, - cio->pat_buf_len, VM_PROT_READ)) { - kprintf("pci_ioctl: pattern buffer %p, " - "length %u isn't user accessible for" - " READ\n", cio->patterns, - cio->pat_buf_len); - error = EACCES; - break; - } - /* - * Allocate a buffer to hold the patterns. - */ - pattern_buf = kmalloc(cio->pat_buf_len, M_TEMP, - M_WAITOK); - error = copyin(cio->patterns, pattern_buf, - cio->pat_buf_len); - if (error != 0) - break; - num_patterns = cio->num_patterns; - - } else if ((cio->num_patterns > 0) - || (cio->pat_buf_len > 0)) { - /* - * The user made a mistake, spit out an error. - */ - cio->status = PCI_GETCONF_ERROR; - cio->num_matches = 0; - kprintf("pci_ioctl: invalid GETCONF arguments\n"); - error = EINVAL; - break; - } else - pattern_buf = NULL; - - /* - * Make sure we can write to the match buffer. - */ - if (!useracc((caddr_t)cio->matches, - cio->match_buf_len, VM_PROT_WRITE)) { - kprintf("pci_ioctl: match buffer %p, length %u " - "isn't user accessible for WRITE\n", - cio->matches, cio->match_buf_len); - error = EACCES; - break; - } - - /* - * Go through the list of devices and copy out the devices - * that match the user's criteria. - */ - for (cio->num_matches = 0, error = 0, i = 0, - dinfo = STAILQ_FIRST(devlist_head); - (dinfo != NULL) && (cio->num_matches < ionum) - && (error == 0) && (i < pci_numdevs); - dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { - - if (i < cio->offset) - continue; - - /* Populate pd_name and pd_unit */ - name = NULL; - if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0') - name = device_get_name(dinfo->cfg.dev); - if (name) { - strncpy(dinfo->conf.pd_name, name, - sizeof(dinfo->conf.pd_name)); - dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; - dinfo->conf.pd_unit = - device_get_unit(dinfo->cfg.dev); - } - - if ((pattern_buf == NULL) || - (pci_conf_match(pattern_buf, num_patterns, - &dinfo->conf) == 0)) { - - /* - * If we've filled up the user's buffer, - * break out at this point. Since we've - * got a match here, we'll pick right back - * up at the matching entry. We can also - * tell the user that there are more matches - * left. - */ - if (cio->num_matches >= ionum) - break; - - error = copyout(&dinfo->conf, - &cio->matches[cio->num_matches], - sizeof(struct pci_conf)); - cio->num_matches++; - } - } - - /* - * Set the pointer into the list, so if the user is getting - * n records at a time, where n < pci_numdevs, - */ - cio->offset = i; - - /* - * Set the generation, the user will need this if they make - * another ioctl call with offset != 0. - */ - cio->generation = pci_generation; - - /* - * If this is the last device, inform the user so he won't - * bother asking for more devices. If dinfo isn't NULL, we - * know that there are more matches in the list because of - * the way the traversal is done. - */ - if (dinfo == NULL) - cio->status = PCI_GETCONF_LAST_DEVICE; - else - cio->status = PCI_GETCONF_MORE_DEVS; - - if (pattern_buf != NULL) - kfree(pattern_buf, M_TEMP); - - break; - } - case PCIOCREAD: - io = (struct pci_io *)ap->a_data; - switch(io->pi_width) { - case 4: - case 2: - case 1: - /* - * Assume that the user-level bus number is - * actually the pciN instance number. We map - * from that to the real pcib+bus combination. - */ - pci = devclass_get_device(pci_devclass, - io->pi_sel.pc_bus); - if (pci) { - /* - * pci is the pci device and may contain - * several children (for each function code). - * The governing pci bus is the parent to - * the pci device. - */ - int b; - - pcib = device_get_parent(pci); - b = pcib_get_bus(pcib); - io->pi_data = - PCIB_READ_CONFIG(pcib, - b, - io->pi_sel.pc_dev, - io->pi_sel.pc_func, - io->pi_reg, - io->pi_width); - error = 0; - } else { - error = ENODEV; - } - break; - default: - error = ENODEV; - break; - } - break; - - case PCIOCWRITE: - io = (struct pci_io *)ap->a_data; - switch(io->pi_width) { - case 4: - case 2: - case 1: - /* - * Assume that the user-level bus number is - * actually the pciN instance number. We map - * from that to the real pcib+bus combination. - */ - pci = devclass_get_device(pci_devclass, - io->pi_sel.pc_bus); - if (pci) { - /* - * pci is the pci device and may contain - * several children (for each function code). - * The governing pci bus is the parent to - * the pci device. - */ - int b; - - pcib = device_get_parent(pci); - b = pcib_get_bus(pcib); - PCIB_WRITE_CONFIG(pcib, - b, - io->pi_sel.pc_dev, - io->pi_sel.pc_func, - io->pi_reg, - io->pi_data, - io->pi_width); - error = 0; - } else { - error = ENODEV; - } - break; - default: - error = ENODEV; - break; - } - break; - - default: - error = ENOTTY; - break; - } +pci_clear_command_bit(device_t dev, device_t child, uint16_t bit) +{ + uint16_t command; - return (error); + command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); + command &= ~bit; + PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); } -#define PCI_CDEV 78 - -static struct dev_ops pcic_ops = { - { "pci", PCI_CDEV, 0 }, - .d_open = pci_open, - .d_close = pci_close, - .d_ioctl = pci_ioctl, -}; +int +pci_enable_busmaster_method(device_t dev, device_t child) +{ + pci_set_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); + return (0); +} -#include "pci_if.h" +int +pci_disable_busmaster_method(device_t dev, device_t child) +{ + pci_clear_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); + return (0); +} -/* - * New style pci driver. Parent device is either a pci-host-bridge or a - * pci-pci-bridge. Both kinds are represented by instances of pcib. - */ -const char * -pci_class_to_string(int baseclass) +int +pci_enable_io_method(device_t dev, device_t child, int space) { - const char *name; + uint16_t command; + uint16_t bit; + char *error; - switch(baseclass) { - case PCIC_OLD: - name = "OLD"; - break; - case PCIC_STORAGE: - name = "STORAGE"; - break; - case PCIC_NETWORK: - name = "NETWORK"; - break; - case PCIC_DISPLAY: - name = "DISPLAY"; - break; - case PCIC_MULTIMEDIA: - name = "MULTIMEDIA"; - break; - case PCIC_MEMORY: - name = "MEMORY"; - break; - case PCIC_BRIDGE: - name = "BRIDGE"; - break; - case PCIC_SIMPLECOMM: - name = "SIMPLECOMM"; - break; - case PCIC_BASEPERIPH: - name = "BASEPERIPH"; - break; - case PCIC_INPUTDEV: - name = "INPUTDEV"; - break; - case PCIC_DOCKING: - name = "DOCKING"; - break; - case PCIC_PROCESSOR: - name = "PROCESSOR"; - break; - case PCIC_SERIALBUS: - name = "SERIALBUS"; - break; - case PCIC_WIRELESS: - name = "WIRELESS"; - break; - case PCIC_I2O: - name = "I20"; - break; - case PCIC_SATELLITE: - name = "SATELLITE"; - break; - case PCIC_CRYPTO: - name = "CRYPTO"; - break; - case PCIC_SIGPROC: - name = "SIGPROC"; + bit = 0; + error = NULL; + + switch(space) { + case SYS_RES_IOPORT: + bit = PCIM_CMD_PORTEN; + error = "port"; break; - case PCIC_OTHER: - name = "OTHER"; + case SYS_RES_MEMORY: + bit = PCIM_CMD_MEMEN; + error = "memory"; break; default: - name = "?"; - break; + return (EINVAL); } - return(name); + pci_set_command_bit(dev, child, bit); + /* Some devices seem to need a brief stall here, what do to? */ + command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); + if (command & bit) + return (0); + device_printf(child, "failed to enable %s mapping!\n", error); + return (ENXIO); } -static void -pci_print_verbose_expr(const pcicfgregs *cfg) +int +pci_disable_io_method(device_t dev, device_t child, int space) { - const struct pcicfg_expr *expr = &cfg->expr; - const char *port_name; - uint16_t port_type; - - if (!bootverbose) - return; - - if (expr->expr_ptr == 0) /* No PCI Express capability */ - return; - - kprintf("\tPCI Express ver.%d cap=0x%04x", - expr->expr_cap & PCIEM_CAP_VER_MASK, expr->expr_cap); - if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) - goto back; + uint16_t command; + uint16_t bit; + char *error; - port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE; + bit = 0; + error = NULL; - switch (port_type) { - case PCIE_END_POINT: - port_name = "DEVICE"; - break; - case PCIE_LEG_END_POINT: - port_name = "LEGDEV"; - break; - case PCIE_ROOT_PORT: - port_name = "ROOT"; - break; - case PCIE_UP_STREAM_PORT: - port_name = "UPSTREAM"; - break; - case PCIE_DOWN_STREAM_PORT: - port_name = "DOWNSTRM"; + switch(space) { + case SYS_RES_IOPORT: + bit = PCIM_CMD_PORTEN; + error = "port"; break; - case PCIE_PCIE2PCI_BRIDGE: - port_name = "PCIE2PCI"; - break; - case PCIE_PCI2PCIE_BRIDGE: - port_name = "PCI2PCIE"; + case SYS_RES_MEMORY: + bit = PCIM_CMD_MEMEN; + error = "memory"; break; default: - port_name = NULL; - break; + return (EINVAL); } - if ((port_type == PCIE_ROOT_PORT || - port_type == PCIE_DOWN_STREAM_PORT) && - !(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) - port_name = NULL; - if (port_name != NULL) - kprintf("[%s]", port_name); - - if (pcie_slotimpl(cfg)) { - kprintf(", slotcap=0x%08x", expr->expr_slotcap); - if (expr->expr_slotcap & PCIEM_SLTCAP_HP_CAP) - kprintf("[HOTPLUG]"); + pci_clear_command_bit(dev, child, bit); + command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); + if (command & bit) { + device_printf(child, "failed to disable %s mapping!\n", error); + return (ENXIO); } -back: - kprintf("\n"); + return (0); } +/* + * New style pci driver. Parent device is either a pci-host-bridge or a + * pci-pci-bridge. Both kinds are represented by instances of pcib. + */ + void pci_print_verbose(struct pci_devinfo *dinfo) { + if (bootverbose) { pcicfgregs *cfg = &dinfo->cfg; - kprintf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", - cfg->vendor, cfg->device, cfg->revid); - kprintf("\tbus=%d, slot=%d, func=%d\n", - cfg->bus, cfg->slot, cfg->func); - kprintf("\tclass=[%s]%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", - pci_class_to_string(cfg->baseclass), - cfg->baseclass, cfg->subclass, cfg->progif, - cfg->hdrtype, cfg->mfdev); - kprintf("\tsubordinatebus=%x \tsecondarybus=%x\n", - cfg->subordinatebus, cfg->secondarybus); -#ifdef PCI_DEBUG - kprintf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", - cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + kprintf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", + cfg->vendor, cfg->device, cfg->revid); + kprintf("\tdomain=%d, bus=%d, slot=%d, func=%d\n", + cfg->domain, cfg->bus, cfg->slot, cfg->func); + kprintf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", + cfg->baseclass, cfg->subclass, cfg->progif, cfg->hdrtype, + cfg->mfdev); + kprintf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); kprintf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", - cfg->lattimer, cfg->lattimer * 30, - cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); -#endif /* PCI_DEBUG */ + cfg->lattimer, cfg->lattimer * 30, cfg->mingnt, + cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); if (cfg->intpin > 0) - kprintf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); - - pci_print_verbose_expr(cfg); + kprintf("\tintpin=%c, irq=%d\n", + cfg->intpin +'a' -1, cfg->intline); + if (cfg->pp.pp_cap) { + uint16_t status; + + status = pci_read_config(cfg->dev, cfg->pp.pp_status, 2); + kprintf("\tpowerspec %d supports D0%s%s D3 current D%d\n", + cfg->pp.pp_cap & PCIM_PCAP_SPEC, + cfg->pp.pp_cap & PCIM_PCAP_D1SUPP ? " D1" : "", + cfg->pp.pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "", + status & PCIM_PSTAT_DMASK); + } + if (cfg->msi.msi_location) { + int ctrl; + + ctrl = cfg->msi.msi_ctrl; + kprintf("\tMSI supports %d message%s%s%s\n", + cfg->msi.msi_msgnum, + (cfg->msi.msi_msgnum == 1) ? "" : "s", + (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", + (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks":""); + } + if (cfg->msix.msix_location) { + kprintf("\tMSI-X supports %d message%s ", + cfg->msix.msix_msgnum, + (cfg->msix.msix_msgnum == 1) ? "" : "s"); + if (cfg->msix.msix_table_bar == cfg->msix.msix_pba_bar) + kprintf("in map 0x%x\n", + cfg->msix.msix_table_bar); + else + kprintf("in maps 0x%x and 0x%x\n", + cfg->msix.msix_table_bar, + cfg->msix.msix_pba_bar); + } } } @@ -1539,96 +2299,161 @@ pci_memen(device_t pcib, int b, int s, int f) * register is a 32bit map register or 2 if it is a 64bit register. */ static int -pci_add_map(device_t pcib, int b, int s, int f, int reg, - struct resource_list *rl) -{ - u_int32_t map; - u_int64_t base; - u_int8_t ln2size; - u_int8_t ln2range; - u_int32_t testval; - - -#ifdef PCI_ENABLE_IO_MODES - u_int16_t cmd; -#endif +pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, struct resource_list *rl, int force, + int prefetch) +{ + uint32_t map; + pci_addr_t base; + pci_addr_t start, end, count; + uint8_t ln2size; + uint8_t ln2range; + uint32_t testval; + uint16_t cmd; int type; + int barlen; + struct resource *res; map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); - - if (map == 0 || map == 0xffffffff) - return 1; /* skip invalid entry */ - PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4); testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4); - base = pci_mapbase(map); - if (pci_maptype(map) & PCI_MAPMEM) + if (PCI_BAR_MEM(map)) { type = SYS_RES_MEMORY; - else + if (map & PCIM_BAR_MEM_PREFETCH) + prefetch = 1; + } else type = SYS_RES_IOPORT; ln2size = pci_mapsize(testval); ln2range = pci_maprange(testval); - if (ln2range == 64) { + base = pci_mapbase(map); + barlen = ln2range == 64 ? 2 : 1; + + /* + * For I/O registers, if bottom bit is set, and the next bit up + * isn't clear, we know we have a BAR that doesn't conform to the + * spec, so ignore it. Also, sanity check the size of the data + * areas to the type of memory involved. Memory must be at least + * 16 bytes in size, while I/O ranges must be at least 4. + */ + if (PCI_BAR_IO(testval) && (testval & PCIM_BAR_IO_RESERVED) != 0) + return (barlen); + if ((type == SYS_RES_MEMORY && ln2size < 4) || + (type == SYS_RES_IOPORT && ln2size < 2)) + return (barlen); + + if (ln2range == 64) /* Read the other half of a 64bit map register */ - base |= (u_int64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg+4, 4); + base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32; + if (bootverbose) { + kprintf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", + reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size); + if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) + kprintf(", port disabled\n"); + else if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) + kprintf(", memory disabled\n"); + else + kprintf(", enabled\n"); } /* - * This code theoretically does the right thing, but has - * undesirable side effects in some cases where - * peripherals respond oddly to having these bits - * enabled. Leave them alone by default. + * If base is 0, then we have problems. It is best to ignore + * such entries for the moment. These will be allocated later if + * the driver specifically requests them. However, some + * removable busses look better when all resources are allocated, + * so allow '0' to be overriden. + * + * Similarly treat maps whose values is the same as the test value + * read back. These maps have had all f's written to them by the + * BIOS in an attempt to disable the resources. */ -#ifdef PCI_ENABLE_IO_MODES - if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) { - cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); - cmd |= PCIM_CMD_PORTEN; - PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); + if (!force && (base == 0 || map == testval)) + return (barlen); + if ((u_long)base != base) { + device_printf(bus, + "pci%d:%d:%d:%d bar %#x too many address bits", + pci_get_domain(dev), b, s, f, reg); + return (barlen); } - if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) { - cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); - cmd |= PCIM_CMD_MEMEN; - PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); - } -#else - if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) - return 1; - if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) - return 1; -#endif - resource_list_add(rl, type, reg, - base, base + (1 << ln2size) - 1, - (1 << ln2size)); + /* + * This code theoretically does the right thing, but has + * undesirable side effects in some cases where peripherals + * respond oddly to having these bits enabled. Let the user + * be able to turn them off (since pci_enable_io_modes is 1 by + * default). + */ + if (pci_enable_io_modes) { + /* Turn on resources that have been left off by a lazy BIOS */ + if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) { + cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); + cmd |= PCIM_CMD_PORTEN; + PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); + } + if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) { + cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); + cmd |= PCIM_CMD_MEMEN; + PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); + } + } else { + if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) + return (barlen); + if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) + return (barlen); + } - if (bootverbose) { - kprintf("\tmap[%02x]: type %x, range %2d, base %08x, size %2d\n", - reg, pci_maptype(base), ln2range, - (unsigned int) base, ln2size); + count = 1 << ln2size; + if (base == 0 || base == pci_mapbase(testval)) { + start = 0; /* Let the parent decide. */ + end = ~0ULL; + } else { + start = base; + end = base + (1 << ln2size) - 1; } + resource_list_add(rl, type, reg, start, end, count); - return (ln2range == 64) ? 2 : 1; + /* + * Try to allocate the resource for this BAR from our parent + * so that this resource range is already reserved. The + * driver for this device will later inherit this resource in + * pci_alloc_resource(). + */ + res = resource_list_alloc(rl, bus, dev, type, ®, start, end, count, + prefetch ? RF_PREFETCHABLE : 0); + if (res == NULL) { + /* + * If the allocation fails, clear the BAR and delete + * the resource list entry to force + * pci_alloc_resource() to allocate resources from the + * parent. + */ + resource_list_delete(rl, type, reg); + start = 0; + } else + start = rman_get_start(res); + pci_write_config(dev, reg, start, 4); + if (ln2range == 64) + pci_write_config(dev, reg + 4, start >> 32, 4); + return (barlen); } -#ifdef PCI_MAP_FIXUP /* - * For ATA devices we need to decide early on what addressing mode to use. + * For ATA devices we need to decide early what addressing mode to use. * Legacy demands that the primary and secondary ATA ports sits on the * same addresses that old ISA hardware did. This dictates that we use - * those addresses and ignore the BARs if we cannot set PCI native + * those addresses and ignore the BAR's if we cannot set PCI native * addressing mode. */ static void -pci_ata_maps(device_t pcib, device_t bus, device_t dev, int b, int s, int f, - struct resource_list *rl) +pci_ata_maps(device_t pcib, device_t bus, device_t dev, int b, + int s, int f, struct resource_list *rl, int force, uint32_t prefetchmask) { int rid, type, progif; #if 0 /* if this device supports PCI native addressing use it */ progif = pci_read_config(dev, PCIR_PROGIF, 1); - if ((progif &0x8a) == 0x8a) { + if ((progif & 0x8a) == 0x8a) { if (pci_mapbase(pci_read_config(dev, PCIR_BAR(0), 4)) && pci_mapbase(pci_read_config(dev, PCIR_BAR(2), 4))) { kprintf("Trying ATA native PCI addressing mode\n"); @@ -1636,108 +2461,167 @@ pci_ata_maps(device_t pcib, device_t bus, device_t dev, int b, int s, int f, } } #endif - /* - * Because we return any preallocated resources for lazy - * allocation for PCI devices in pci_alloc_resource(), we can - * allocate our legacy resources here. - */ progif = pci_read_config(dev, PCIR_PROGIF, 1); type = SYS_RES_IOPORT; if (progif & PCIP_STORAGE_IDE_MODEPRIM) { - pci_add_map(pcib, b, s, f, PCIR_BAR(0), rl); - pci_add_map(pcib, b, s, f, PCIR_BAR(1), rl); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(0), rl, force, + prefetchmask & (1 << 0)); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(1), rl, force, + prefetchmask & (1 << 1)); } else { rid = PCIR_BAR(0); resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8); resource_list_alloc(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, 8, - 0); + 0); rid = PCIR_BAR(1); resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1); resource_list_alloc(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, 1, - 0); + 0); } if (progif & PCIP_STORAGE_IDE_MODESEC) { - pci_add_map(pcib, b, s, f, PCIR_BAR(2), rl); - pci_add_map(pcib, b, s, f, PCIR_BAR(3), rl); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(2), rl, force, + prefetchmask & (1 << 2)); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(3), rl, force, + prefetchmask & (1 << 3)); } else { rid = PCIR_BAR(2); resource_list_add(rl, type, rid, 0x170, 0x177, 8); resource_list_alloc(rl, bus, dev, type, &rid, 0x170, 0x177, 8, - 0); + 0); rid = PCIR_BAR(3); resource_list_add(rl, type, rid, 0x376, 0x376, 1); resource_list_alloc(rl, bus, dev, type, &rid, 0x376, 0x376, 1, - 0); + 0); } - pci_add_map(pcib, b, s, f, PCIR_BAR(4), rl); - pci_add_map(pcib, b, s, f, PCIR_BAR(5), rl); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(4), rl, force, + prefetchmask & (1 << 4)); + pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(5), rl, force, + prefetchmask & (1 << 5)); } -#endif /* PCI_MAP_FIXUP */ static void -pci_add_resources(device_t pcib, device_t bus, device_t dev) +pci_assign_interrupt(device_t bus, device_t dev, int force_route) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + char tunable_name[64]; + int irq; + + /* Has to have an intpin to have an interrupt. */ + if (cfg->intpin == 0) + return; + + /* Let the user override the IRQ with a tunable. */ + irq = PCI_INVALID_IRQ; + ksnprintf(tunable_name, sizeof(tunable_name), + "hw.pci%d.%d.%d.INT%c.irq", + cfg->domain, cfg->bus, cfg->slot, cfg->intpin + 'A' - 1); + if (TUNABLE_INT_FETCH(tunable_name, &irq) && (irq >= 255 || irq <= 0)) + irq = PCI_INVALID_IRQ; + + /* + * If we didn't get an IRQ via the tunable, then we either use the + * IRQ value in the intline register or we ask the bus to route an + * interrupt for us. If force_route is true, then we only use the + * value in the intline register if the bus was unable to assign an + * IRQ. + */ + if (!PCI_INTERRUPT_VALID(irq)) { + if (!PCI_INTERRUPT_VALID(cfg->intline) || force_route) + irq = PCI_ASSIGN_INTERRUPT(bus, dev); + if (!PCI_INTERRUPT_VALID(irq)) + irq = cfg->intline; + } + + /* If after all that we don't have an IRQ, just bail. */ + if (!PCI_INTERRUPT_VALID(irq)) + return; + + /* Update the config register if it changed. */ + if (irq != cfg->intline) { + cfg->intline = irq; + pci_write_config(dev, PCIR_INTLINE, irq, 1); + } + + /* Add this IRQ as rid 0 interrupt resource. */ + resource_list_add(&dinfo->resources, SYS_RES_IRQ, 0, irq, irq, 1); +} + +void +pci_add_resources(device_t pcib, device_t bus, device_t dev, int force, uint32_t prefetchmask) { struct pci_devinfo *dinfo = device_get_ivars(dev); pcicfgregs *cfg = &dinfo->cfg; struct resource_list *rl = &dinfo->resources; struct pci_quirk *q; int b, i, f, s; -#if 0 /* WILL BE USED WITH ADDITIONAL IMPORT FROM FREEBSD-5 XXX */ - int irq; -#endif b = cfg->bus; s = cfg->slot; f = cfg->func; -#ifdef PCI_MAP_FIXUP - /* atapci devices in legacy mode need special map treatment */ + + /* ATA devices needs special map treatment */ if ((pci_get_class(dev) == PCIC_STORAGE) && (pci_get_subclass(dev) == PCIS_STORAGE_IDE) && ((pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) || (!pci_read_config(dev, PCIR_BAR(0), 4) && !pci_read_config(dev, PCIR_BAR(2), 4))) ) - pci_ata_maps(pcib, bus, dev, b, s, f, rl); + pci_ata_maps(pcib, bus, dev, b, s, f, rl, force, prefetchmask); else -#endif /* PCI_MAP_FIXUP */ - for (i = 0; i < cfg->nummaps;) { - i += pci_add_map(pcib, b, s, f, PCIR_BAR(i),rl); - } + for (i = 0; i < cfg->nummaps;) + i += pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(i), + rl, force, prefetchmask & (1 << i)); + /* + * Add additional, quirked resources. + */ for (q = &pci_quirks[0]; q->devid; q++) { if (q->devid == ((cfg->device << 16) | cfg->vendor) && q->type == PCI_QUIRK_MAP_REG) - pci_add_map(pcib, b, s, f, q->arg1, rl); + pci_add_map(pcib, bus, dev, b, s, f, q->arg1, rl, + force, 0); } - if (cfg->intpin > 0 && cfg->intline != 255) - resource_list_add(rl, SYS_RES_IRQ, 0, - cfg->intline, cfg->intline, 1); + if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { +#ifdef __PCI_REROUTE_INTERRUPT + /* + * Try to re-route interrupts. Sometimes the BIOS or + * firmware may leave bogus values in these registers. + * If the re-route fails, then just stick with what we + * have. + */ + pci_assign_interrupt(bus, dev, 1); +#else + pci_assign_interrupt(bus, dev, 0); +#endif + } } void -pci_add_children(device_t dev, int busno, size_t dinfo_size) +pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) { -#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w) +#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w) device_t pcib = device_get_parent(dev); struct pci_devinfo *dinfo; int maxslots; int s, f, pcifunchigh; uint8_t hdrtype; - KKASSERT(dinfo_size >= sizeof(struct pci_devinfo)); - + KASSERT(dinfo_size >= sizeof(struct pci_devinfo), + ("dinfo_size too small")); maxslots = PCIB_MAXSLOTS(pcib); - for (s = 0; s <= maxslots; s++) { pcifunchigh = 0; f = 0; + DELAY(1); hdrtype = REG(PCIR_HDRTYPE, 1); if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; if (hdrtype & PCIM_MFDEV) pcifunchigh = PCI_FUNCMAX; for (f = 0; f <= pcifunchigh; f++) { - dinfo = pci_read_device(pcib, busno, s, f, dinfo_size); + dinfo = pci_read_device(pcib, domain, busno, s, f, + dinfo_size); if (dinfo != NULL) { pci_add_child(dev, dinfo); } @@ -1746,10 +2630,6 @@ pci_add_children(device_t dev, int busno, size_t dinfo_size) #undef REG } -/* - * The actual PCI child that we add has a NULL driver whos parent - * device will be "pci". The child contains the ivars, not the parent. - */ void pci_add_child(device_t bus, struct pci_devinfo *dinfo) { @@ -1758,79 +2638,329 @@ pci_add_child(device_t bus, struct pci_devinfo *dinfo) pcib = device_get_parent(bus); dinfo->cfg.dev = device_add_child(bus, NULL, -1); device_set_ivars(dinfo->cfg.dev, dinfo); + resource_list_init(&dinfo->resources); pci_cfg_save(dinfo->cfg.dev, dinfo, 0); pci_cfg_restore(dinfo->cfg.dev, dinfo); - pci_add_resources(pcib, bus, dinfo->cfg.dev); pci_print_verbose(dinfo); + pci_add_resources(pcib, bus, dinfo->cfg.dev, 0, 0); } -/* - * Probe the PCI bus. Note: probe code is not supposed to add children - * or call attach. - */ static int pci_probe(device_t dev) { device_set_desc(dev, "PCI bus"); - /* Allow other subclasses to override this driver */ - return(-1000); + /* Allow other subclasses to override this driver. */ + return (-1000); } static int pci_attach(device_t dev) { - int busno; - int lunit = device_get_unit(dev); + int busno, domain; + + /* + * Since there can be multiple independantly numbered PCI + * busses on systems with multiple PCI domains, we can't use + * the unit number to decide which bus we are probing. We ask + * the parent pcib what our domain and bus numbers are. + */ + domain = pcib_get_domain(dev); + busno = pcib_get_bus(dev); + if (bootverbose) + device_printf(dev, "domain=%d, physical bus=%d\n", + domain, busno); - dev_ops_add(&pcic_ops, -1, lunit); - make_dev(&pcic_ops, lunit, UID_ROOT, GID_WHEEL, 0644, "pci%d", lunit); + pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo)); - /* - * Since there can be multiple independantly numbered PCI - * busses on some large alpha systems, we can't use the unit - * number to decide what bus we are probing. We ask the parent - * pcib what our bus number is. - * - * pcib_get_bus() must act on the pci bus device, not on the pci - * device, because it uses badly hacked nexus-based ivars to - * store and retrieve the physical bus number. XXX - */ - busno = pcib_get_bus(device_get_parent(dev)); - if (bootverbose) - device_printf(dev, "pci_attach() physical bus=%d\n", busno); + return (bus_generic_attach(dev)); +} + +int +pci_suspend(device_t dev) +{ + int dstate, error, i, numdevs; + device_t acpi_dev, child, *devlist; + struct pci_devinfo *dinfo; + + /* + * Save the PCI configuration space for each child and set the + * device in the appropriate power state for this sleep state. + */ + acpi_dev = NULL; + if (pci_do_power_resume) + acpi_dev = devclass_get_device(devclass_find("acpi"), 0); + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = (struct pci_devinfo *) device_get_ivars(child); + pci_cfg_save(child, dinfo, 0); + } - pci_add_children(dev, busno, sizeof(struct pci_devinfo)); + /* Suspend devices before potentially powering them down. */ + error = bus_generic_suspend(dev); + if (error) { + kfree(devlist, M_TEMP); + return (error); + } - return (bus_generic_attach(dev)); + /* + * Always set the device to D3. If ACPI suggests a different + * power state, use it instead. If ACPI is not present, the + * firmware is responsible for managing device power. Skip + * children who aren't attached since they are powered down + * separately. Only manage type 0 devices for now. + */ + for (i = 0; acpi_dev && i < numdevs; i++) { + child = devlist[i]; + dinfo = (struct pci_devinfo *) device_get_ivars(child); + if (device_is_attached(child) && dinfo->cfg.hdrtype == 0) { + dstate = PCI_POWERSTATE_D3; + ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate); + pci_set_powerstate(child, dstate); + } + } + kfree(devlist, M_TEMP); + return (0); } -static int -pci_print_resources(struct resource_list *rl, const char *name, int type, - const char *format) +int +pci_resume(device_t dev) { - struct resource_list_entry *rle; - int printed, retval; - - printed = 0; - retval = 0; - /* Yes, this is kinda cheating */ - SLIST_FOREACH(rle, rl, link) { - if (rle->type == type) { - if (printed == 0) - retval += kprintf(" %s ", name); - else if (printed > 0) - retval += kprintf(","); - printed++; - retval += kprintf(format, rle->start); - if (rle->count > 1) { - retval += kprintf("-"); - retval += kprintf(format, rle->start + - rle->count - 1); + int i, numdevs; + device_t acpi_dev, child, *devlist; + struct pci_devinfo *dinfo; + + /* + * Set each child to D0 and restore its PCI configuration space. + */ + acpi_dev = NULL; + if (pci_do_power_resume) + acpi_dev = devclass_get_device(devclass_find("acpi"), 0); + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + /* + * Notify ACPI we're going to D0 but ignore the result. If + * ACPI is not present, the firmware is responsible for + * managing device power. Only manage type 0 devices for now. + */ + child = devlist[i]; + dinfo = (struct pci_devinfo *) device_get_ivars(child); + if (acpi_dev && device_is_attached(child) && + dinfo->cfg.hdrtype == 0) { + ACPI_PWR_FOR_SLEEP(acpi_dev, child, NULL); + pci_set_powerstate(child, PCI_POWERSTATE_D0); + } + + /* Now the device is powered up, restore its config space. */ + pci_cfg_restore(child, dinfo); + } + kfree(devlist, M_TEMP); + return (bus_generic_resume(dev)); +} + +static void +pci_load_vendor_data(void) +{ + caddr_t vendordata, info; + + if ((vendordata = preload_search_by_type("pci_vendor_data")) != NULL) { + info = preload_search_info(vendordata, MODINFO_ADDR); + pci_vendordata = *(char **)info; + info = preload_search_info(vendordata, MODINFO_SIZE); + pci_vendordata_size = *(size_t *)info; + /* terminate the database */ + pci_vendordata[pci_vendordata_size] = '\n'; + } +} + +void +pci_driver_added(device_t dev, driver_t *driver) +{ + int numdevs; + device_t *devlist; + device_t child; + struct pci_devinfo *dinfo; + int i; + + if (bootverbose) + device_printf(dev, "driver added\n"); + DEVICE_IDENTIFY(driver, dev); + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + if (device_get_state(child) != DS_NOTPRESENT) + continue; + dinfo = device_get_ivars(child); + pci_print_verbose(dinfo); + if (bootverbose) + kprintf("pci%d:%d:%d:%d: reprobing on driver added\n", + dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot, + dinfo->cfg.func); + pci_cfg_restore(child, dinfo); + if (device_probe_and_attach(child) != 0) + pci_cfg_save(child, dinfo, 1); + } + kfree(devlist, M_TEMP); +} + +int +pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, + driver_intr_t *intr, void *arg, void **cookiep, lwkt_serialize_t serializer) +{ +#ifdef MSI + struct pci_devinfo *dinfo; + struct msix_table_entry *mte; + struct msix_vector *mv; + uint64_t addr; + uint32_t data; +#endif + int error, rid; + void *cookie; + error = bus_generic_setup_intr(dev, child, irq, flags, intr, + arg, &cookie, serializer); + if (error) + return (error); + + /* If this is not a direct child, just bail out. */ + if (device_get_parent(child) != dev) { + *cookiep = cookie; + return(0); + } + + pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); +#ifdef MSI + rid = rman_get_rid(irq); + if (rid == 0) { + /* Make sure that INTx is enabled */ + pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); + } else { + /* + * Check to see if the interrupt is MSI or MSI-X. + * Ask our parent to map the MSI and give + * us the address and data register values. + * If we fail for some reason, teardown the + * interrupt handler. + */ + dinfo = device_get_ivars(child); + if (dinfo->cfg.msi.msi_alloc > 0) { + if (dinfo->cfg.msi.msi_addr == 0) { + KASSERT(dinfo->cfg.msi.msi_handlers == 0, + ("MSI has handlers, but vectors not mapped")); + error = PCIB_MAP_MSI(device_get_parent(dev), + child, rman_get_start(irq), &addr, &data); + if (error) + goto bad; + dinfo->cfg.msi.msi_addr = addr; + dinfo->cfg.msi.msi_data = data; + pci_enable_msi(child, addr, data); } + dinfo->cfg.msi.msi_handlers++; + } else { + KASSERT(dinfo->cfg.msix.msix_alloc > 0, + ("No MSI or MSI-X interrupts allocated")); + KASSERT(rid <= dinfo->cfg.msix.msix_table_len, + ("MSI-X index too high")); + mte = &dinfo->cfg.msix.msix_table[rid - 1]; + KASSERT(mte->mte_vector != 0, ("no message vector")); + mv = &dinfo->cfg.msix.msix_vectors[mte->mte_vector - 1]; + KASSERT(mv->mv_irq == rman_get_start(irq), + ("IRQ mismatch")); + if (mv->mv_address == 0) { + KASSERT(mte->mte_handlers == 0, + ("MSI-X table entry has handlers, but vector not mapped")); + error = PCIB_MAP_MSI(device_get_parent(dev), + child, rman_get_start(irq), &addr, &data); + if (error) + goto bad; + mv->mv_address = addr; + mv->mv_data = data; + } + if (mte->mte_handlers == 0) { + pci_enable_msix(child, rid - 1, mv->mv_address, + mv->mv_data); + pci_unmask_msix(child, rid - 1); + } + mte->mte_handlers++; + } + + /* Make sure that INTx is disabled if we are using MSI/MSIX */ + pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); + bad: + if (error) { + (void)bus_generic_teardown_intr(dev, child, irq, + cookie); + return (error); + } + } +#endif + *cookiep = cookie; + return (0); +} + +int +pci_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie) +{ +#ifdef MSI + struct msix_table_entry *mte; + struct resource_list_entry *rle; + struct pci_devinfo *dinfo; +#endif + int error, rid; + + if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE)) + return (EINVAL); + + /* If this isn't a direct child, just bail out */ + if (device_get_parent(child) != dev) + return(bus_generic_teardown_intr(dev, child, irq, cookie)); + + pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); +#ifdef MSI + rid = rman_get_rid(irq); + if (rid == 0) { + /* Mask INTx */ + pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); + } else { + /* + * Check to see if the interrupt is MSI or MSI-X. If so, + * decrement the appropriate handlers count and mask the + * MSI-X message, or disable MSI messages if the count + * drops to 0. + */ + dinfo = device_get_ivars(child); + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid); + if (rle->res != irq) + return (EINVAL); + if (dinfo->cfg.msi.msi_alloc > 0) { + KASSERT(rid <= dinfo->cfg.msi.msi_alloc, + ("MSI-X index too high")); + if (dinfo->cfg.msi.msi_handlers == 0) + return (EINVAL); + dinfo->cfg.msi.msi_handlers--; + if (dinfo->cfg.msi.msi_handlers == 0) + pci_disable_msi(child); + } else { + KASSERT(dinfo->cfg.msix.msix_alloc > 0, + ("No MSI or MSI-X interrupts allocated")); + KASSERT(rid <= dinfo->cfg.msix.msix_table_len, + ("MSI-X index too high")); + mte = &dinfo->cfg.msix.msix_table[rid - 1]; + if (mte->mte_handlers == 0) + return (EINVAL); + mte->mte_handlers--; + if (mte->mte_handlers == 0) + pci_mask_msix(child, rid - 1); } } - return retval; + error = bus_generic_teardown_intr(dev, child, irq, cookie); + if (rid > 0) + KASSERT(error == 0, + ("%s: generic teardown failed for MSI/MSI-X", __func__)); +#endif + error = bus_generic_teardown_intr(dev, child, irq, cookie); + return (error); } int @@ -1838,66 +2968,286 @@ pci_print_child(device_t dev, device_t child) { struct pci_devinfo *dinfo; struct resource_list *rl; - pcicfgregs *cfg; int retval = 0; dinfo = device_get_ivars(child); - cfg = &dinfo->cfg; rl = &dinfo->resources; retval += bus_print_child_header(dev, child); - retval += pci_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); - retval += pci_print_resources(rl, "mem", SYS_RES_MEMORY, "%#lx"); - retval += pci_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); + retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); if (device_get_flags(dev)) retval += kprintf(" flags %#x", device_get_flags(dev)); retval += kprintf(" at device %d.%d", pci_get_slot(child), - pci_get_function(child)); + pci_get_function(child)); retval += bus_print_child_footer(dev, child); return (retval); } +static struct +{ + int class; + int subclass; + char *desc; +} pci_nomatch_tab[] = { + {PCIC_OLD, -1, "old"}, + {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, + {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, + {PCIC_STORAGE, -1, "mass storage"}, + {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, + {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, + {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, + {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, + {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, + {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, + {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, + {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, + {PCIC_NETWORK, -1, "network"}, + {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, + {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, + {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, + {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, + {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, + {PCIC_DISPLAY, -1, "display"}, + {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, + {PCIC_MULTIMEDIA, -1, "multimedia"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, + {PCIC_MEMORY, -1, "memory"}, + {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, + {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, + {PCIC_BRIDGE, -1, "bridge"}, + {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, + {PCIC_SIMPLECOMM, -1, "simple comms"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, + {PCIC_BASEPERIPH, -1, "base peripheral"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, + {PCIC_INPUTDEV, -1, "input device"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, + {PCIC_DOCKING, -1, "docking station"}, + {PCIC_PROCESSOR, -1, "processor"}, + {PCIC_SERIALBUS, -1, "serial bus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, + {PCIC_WIRELESS, -1, "wireless controller"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, + {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, + {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, + {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, + {PCIC_SATCOM, -1, "satellite communication"}, + {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, + {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, + {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, + {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, + {PCIC_CRYPTO, -1, "encrypt/decrypt"}, + {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, + {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, "entertainment crypto"}, + {PCIC_DASP, -1, "dasp"}, + {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, + {0, 0, NULL} +}; + void pci_probe_nomatch(device_t dev, device_t child) { - struct pci_devinfo *dinfo; - pcicfgregs *cfg; - const char *desc; - int unknown; + int i; + char *cp, *scp, *device; - unknown = 0; - dinfo = device_get_ivars(child); - cfg = &dinfo->cfg; - desc = pci_ata_match(child); - if (!desc) desc = pci_usb_match(child); - if (!desc) desc = pci_vga_match(child); - if (!desc) desc = pci_chip_match(child); - if (!desc) { - desc = "unknown card"; - unknown++; - } - device_printf(dev, "<%s>", desc); - if (bootverbose || unknown) { - kprintf(" (vendor=0x%04x, dev=0x%04x)", - cfg->vendor, - cfg->device); - } - kprintf(" at %d.%d", - pci_get_slot(child), - pci_get_function(child)); - if (cfg->intpin > 0 && cfg->intline != 255) { - kprintf(" irq %d", cfg->intline); - } - kprintf("\n"); + /* + * Look for a listing for this device in a loaded device database. + */ + if ((device = pci_describe_device(child)) != NULL) { + device_printf(dev, "<%s>", device); + kfree(device, M_DEVBUF); + } else { + /* + * Scan the class/subclass descriptions for a general + * description. + */ + cp = "unknown"; + scp = NULL; + for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { + if (pci_nomatch_tab[i].class == pci_get_class(child)) { + if (pci_nomatch_tab[i].subclass == -1) { + cp = pci_nomatch_tab[i].desc; + } else if (pci_nomatch_tab[i].subclass == + pci_get_subclass(child)) { + scp = pci_nomatch_tab[i].desc; + } + } + } + device_printf(dev, "<%s%s%s>", + cp ? cp : "", + ((cp != NULL) && (scp != NULL)) ? ", " : "", + scp ? scp : ""); + } + kprintf(" at device %d.%d (no driver attached)\n", + pci_get_slot(child), pci_get_function(child)); pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1); - return; } +/* + * Parse the PCI device database, if loaded, and return a pointer to a + * description of the device. + * + * The database is flat text formatted as follows: + * + * Any line not in a valid format is ignored. + * Lines are terminated with newline '\n' characters. + * + * A VENDOR line consists of the 4 digit (hex) vendor code, a TAB, then + * the vendor name. + * + * A DEVICE line is entered immediately below the corresponding VENDOR ID. + * - devices cannot be listed without a corresponding VENDOR line. + * A DEVICE line consists of a TAB, the 4 digit (hex) device code, + * another TAB, then the device name. + */ + +/* + * Assuming (ptr) points to the beginning of a line in the database, + * return the vendor or device and description of the next entry. + * The value of (vendor) or (device) inappropriate for the entry type + * is set to -1. Returns nonzero at the end of the database. + * + * Note that this is slightly unrobust in the face of corrupt data; + * we attempt to safeguard against this by spamming the end of the + * database with a newline when we initialise. + */ +static int +pci_describe_parse_line(char **ptr, int *vendor, int *device, char **desc) +{ + char *cp = *ptr; + int left; + + *device = -1; + *vendor = -1; + **desc = '\0'; + for (;;) { + left = pci_vendordata_size - (cp - pci_vendordata); + if (left <= 0) { + *ptr = cp; + return(1); + } + + /* vendor entry? */ + if (*cp != '\t' && + ksscanf(cp, "%x\t%80[^\n]", vendor, *desc) == 2) + break; + /* device entry? */ + if (*cp == '\t' && + ksscanf(cp, "%x\t%80[^\n]", device, *desc) == 2) + break; + + /* skip to next line */ + while (*cp != '\n' && left > 0) { + cp++; + left--; + } + if (*cp == '\n') { + cp++; + left--; + } + } + /* skip to next line */ + while (*cp != '\n' && left > 0) { + cp++; + left--; + } + if (*cp == '\n' && left > 0) + cp++; + *ptr = cp; + return(0); +} + +static char * +pci_describe_device(device_t dev) +{ + int vendor, device; + char *desc, *vp, *dp, *line; + + desc = vp = dp = NULL; + + /* + * If we have no vendor data, we can't do anything. + */ + if (pci_vendordata == NULL) + goto out; + + /* + * Scan the vendor data looking for this device + */ + line = pci_vendordata; + if ((vp = kmalloc(80, M_DEVBUF, M_NOWAIT)) == NULL) + goto out; + for (;;) { + if (pci_describe_parse_line(&line, &vendor, &device, &vp)) + goto out; + if (vendor == pci_get_vendor(dev)) + break; + } + if ((dp = kmalloc(80, M_DEVBUF, M_NOWAIT)) == NULL) + goto out; + for (;;) { + if (pci_describe_parse_line(&line, &vendor, &device, &dp)) { + *dp = 0; + break; + } + if (vendor != -1) { + *dp = 0; + break; + } + if (device == pci_get_device(dev)) + break; + } + if (dp[0] == '\0') + ksnprintf(dp, 80, "0x%x", pci_get_device(dev)); + if ((desc = kmalloc(strlen(vp) + strlen(dp) + 3, M_DEVBUF, M_NOWAIT)) != + NULL) + ksprintf(desc, "%s, %s", vp, dp); + out: + if (vp != NULL) + kfree(vp, M_DEVBUF); + if (dp != NULL) + kfree(dp, M_DEVBUF); + return(desc); +} + int pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { @@ -1908,6 +3258,13 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) cfg = &dinfo->cfg; switch (which) { + case PCI_IVAR_ETHADDR: + /* + * The generic accessor doesn't deal with failure, so + * we set the return value, then return an error. + */ + *((uint8_t **) result) = NULL; + return (EINVAL); case PCI_IVAR_SUBVENDOR: *result = cfg->subvendor; break; @@ -1941,6 +3298,9 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case PCI_IVAR_IRQ: *result = cfg->intline; break; + case PCI_IVAR_DOMAIN: + *result = cfg->domain; + break; case PCI_IVAR_BUS: *result = cfg->bus; break; @@ -1950,44 +3310,39 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case PCI_IVAR_FUNCTION: *result = cfg->func; break; - case PCI_IVAR_SECONDARYBUS: - *result = cfg->secondarybus; + case PCI_IVAR_CMDREG: + *result = cfg->cmdreg; break; - case PCI_IVAR_SUBORDINATEBUS: - *result = cfg->subordinatebus; + case PCI_IVAR_CACHELNSZ: + *result = cfg->cachelnsz; break; - case PCI_IVAR_ETHADDR: - /* - * The generic accessor doesn't deal with failure, so - * we set the return value, then return an error. - */ - *result = 0; - return (EINVAL); - case PCI_IVAR_PCIXCAP_PTR: - *result = cfg->pcixcap_ptr; + case PCI_IVAR_MINGNT: + *result = cfg->mingnt; break; - case PCI_IVAR_PCIECAP_PTR: - *result = cfg->expr.expr_ptr; + case PCI_IVAR_MAXLAT: + *result = cfg->maxlat; break; - case PCI_IVAR_VPDCAP_PTR: - *result = cfg->vpdcap_ptr; + case PCI_IVAR_LATTIMER: + *result = cfg->lattimer; break; default: - return ENOENT; + return (ENOENT); } - return 0; + return (0); } int pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) { struct pci_devinfo *dinfo; - pcicfgregs *cfg; dinfo = device_get_ivars(child); - cfg = &dinfo->cfg; switch (which) { + case PCI_IVAR_INTPIN: + dinfo->cfg.intpin = value; + return (0); + case PCI_IVAR_ETHADDR: case PCI_IVAR_SUBVENDOR: case PCI_IVAR_SUBDEVICE: case PCI_IVAR_VENDOR: @@ -1997,72 +3352,119 @@ pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) case PCI_IVAR_SUBCLASS: case PCI_IVAR_PROGIF: case PCI_IVAR_REVID: - case PCI_IVAR_INTPIN: case PCI_IVAR_IRQ: + case PCI_IVAR_DOMAIN: case PCI_IVAR_BUS: case PCI_IVAR_SLOT: case PCI_IVAR_FUNCTION: - case PCI_IVAR_ETHADDR: - case PCI_IVAR_PCIXCAP_PTR: - case PCI_IVAR_PCIECAP_PTR: - return EINVAL; /* disallow for now */ + return (EINVAL); /* disallow for now */ - case PCI_IVAR_SECONDARYBUS: - cfg->secondarybus = value; - break; - case PCI_IVAR_SUBORDINATEBUS: - cfg->subordinatebus = value; - break; default: - return ENOENT; + return (ENOENT); + } +} +#ifdef notyet +#include "opt_ddb.h" +#ifdef DDB +#include +#include + +/* + * List resources based on pci map registers, used for within ddb + */ + +DB_SHOW_COMMAND(pciregs, db_pci_dump) +{ + struct pci_devinfo *dinfo; + struct devlist *devlist_head; + struct pci_conf *p; + const char *name; + int i, error, none_count; + + none_count = 0; + /* get the head of the device queue */ + devlist_head = &pci_devq; + + /* + * Go through the list of devices and print out devices + */ + for (error = 0, i = 0, + dinfo = STAILQ_FIRST(devlist_head); + (dinfo != NULL) && (error == 0) && (i < pci_numdevs) && !db_pager_quit; + dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { + + /* Populate pd_name and pd_unit */ + name = NULL; + if (dinfo->cfg.dev) + name = device_get_name(dinfo->cfg.dev); + + p = &dinfo->conf; + db_kprintf("%s%d@pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x " + "chip=0x%08x rev=0x%02x hdr=0x%02x\n", + (name && *name) ? name : "none", + (name && *name) ? (int)device_get_unit(dinfo->cfg.dev) : + none_count++, + p->pc_sel.pc_domain, p->pc_sel.pc_bus, p->pc_sel.pc_dev, + p->pc_sel.pc_func, (p->pc_class << 16) | + (p->pc_subclass << 8) | p->pc_progif, + (p->pc_subdevice << 16) | p->pc_subvendor, + (p->pc_device << 16) | p->pc_vendor, + p->pc_revid, p->pc_hdr); } - return 0; } +#endif /* DDB */ +#endif -#ifdef PCI_MAP_FIXUP static struct resource * -pci_alloc_map(device_t dev, device_t child, int type, int *rid, u_long start, - u_long end, u_long count, u_int flags) +pci_alloc_map(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) { struct pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; struct resource_list_entry *rle; struct resource *res; - uint32_t map, testval; + pci_addr_t map, testval; int mapsize; /* * Weed out the bogons, and figure out how large the BAR/map - * is. BARs that read back 0 here are bogus and unimplemented. - * + * is. Bars that read back 0 here are bogus and unimplemented. * Note: atapci in legacy mode are special and handled elsewhere - * in the code. If you have an atapci device in legacy mode and + * in the code. If you have a atapci device in legacy mode and * it fails here, that other code is broken. */ res = NULL; map = pci_read_config(child, *rid, 4); pci_write_config(child, *rid, 0xffffffff, 4); testval = pci_read_config(child, *rid, 4); + if (pci_maprange(testval) == 64) + map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32; if (pci_mapbase(testval) == 0) goto out; - if (pci_maptype(testval) & PCI_MAPMEM) { + + /* + * Restore the original value of the BAR. We may have reprogrammed + * the BAR of the low-level console device and when booting verbose, + * we need the console device addressable. + */ + pci_write_config(child, *rid, map, 4); + + if (PCI_BAR_MEM(testval)) { if (type != SYS_RES_MEMORY) { if (bootverbose) - device_printf(dev, "child %s requested type %d" - " for rid %#x, but the BAR says " - "it is a memio\n", - device_get_nameunit(child), type, - *rid); + device_printf(dev, + "child %s requested type %d for rid %#x," + " but the BAR says it is an memio\n", + device_get_nameunit(child), type, *rid); goto out; } } else { if (type != SYS_RES_IOPORT) { if (bootverbose) - device_printf(dev, "child %s requested type %d" - " for rid %#x, but the BAR says " - "it is an ioport\n", - device_get_nameunit(child), type, - *rid); + device_printf(dev, + "child %s requested type %d for rid %#x," + " but the BAR says it is an ioport\n", + device_get_nameunit(child), type, *rid); goto out; } } @@ -2074,19 +3476,22 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, u_long start, * another driver, which won't work. */ mapsize = pci_mapsize(testval); - count = 1 << mapsize; + count = 1UL << mapsize; if (RF_ALIGNMENT(flags) < mapsize) - flags = (flags & ~RF_ALIGNMENT_MASK) | - RF_ALIGNMENT_LOG2(mapsize); + flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); + if (PCI_BAR_MEM(testval) && (testval & PCIM_BAR_MEM_PREFETCH)) + flags |= RF_PREFETCHABLE; + /* * Allocate enough resource, and then write back the - * appropriate BAR for that resource. + * appropriate bar for that resource. */ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, - start, end, count, flags); + start, end, count, flags); if (res == NULL) { - device_printf(child, "%#lx bytes at rid %#x res %d failed " - "(%#lx, %#lx)\n", count, *rid, type, start, end); + device_printf(child, + "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n", + count, *rid, type, start, end); goto out; } resource_list_add(rl, type, *rid, start, end, count); @@ -2098,15 +3503,17 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, u_long start, rle->end = rman_get_end(res); rle->count = count; if (bootverbose) - device_printf(child, "lazy allocation of %#lx bytes rid %#x " - "type %d at %#lx\n", count, *rid, type, - rman_get_start(res)); + device_printf(child, + "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", + count, *rid, type, rman_get_start(res)); map = rman_get_start(res); out:; pci_write_config(child, *rid, map, 4); - return res; + if (pci_maprange(testval) == 64) + pci_write_config(child, *rid + 4, map >> 32, 4); + return (res); } -#endif /* PCI_MAP_FIXUP */ + struct resource * pci_alloc_resource(device_t dev, device_t child, int type, int *rid, @@ -2114,39 +3521,34 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid, { struct pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; -#ifdef PCI_MAP_FIXUP struct resource_list_entry *rle; -#endif /* PCI_MAP_FIXUP */ pcicfgregs *cfg = &dinfo->cfg; - +//kprintf("%s on %s: requesting resource\n", device_get_desc(child), device_get_desc(dev)); /* * Perform lazy resource allocation */ if (device_get_parent(child) == dev) { switch (type) { case SYS_RES_IRQ: -#if defined(__i386__) || defined(__amd64__) - /* - * If device doesn't have an interrupt routed, and is - * deserving of an interrupt, try to assign it one. - */ - if ((cfg->intline == 255 || cfg->intline == 0) && - (cfg->intpin != 0) && - (start == 0) && (end == ~0UL)) { - cfg->intline = PCIB_ROUTE_INTERRUPT( - device_get_parent(dev), child, - cfg->intpin); - if (cfg->intline != 255) { - pci_write_config(child, PCIR_INTLINE, - cfg->intline, 1); - resource_list_add(rl, SYS_RES_IRQ, 0, - cfg->intline, cfg->intline, 1); - } - } - break; + /* + * Can't alloc legacy interrupt once MSI messages + * have been allocated. + */ +#ifdef MSI + if (*rid == 0 && (cfg->msi.msi_alloc > 0 || + cfg->msix.msix_alloc > 0)) + return (NULL); #endif + /* + * If the child device doesn't have an + * interrupt routed and is deserving of an + * interrupt, try to assign it one. + */ + if (*rid == 0 && !PCI_INTERRUPT_VALID(cfg->intline) && + (cfg->intpin != 0)) + pci_assign_interrupt(dev, child, 0); + break; case SYS_RES_IOPORT: - /* FALLTHROUGH */ case SYS_RES_MEMORY: if (*rid < PCIR_BAR(cfg->nummaps)) { /* @@ -2159,141 +3561,116 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid, if (PCI_ENABLE_IO(dev, child, type)) return (NULL); } -#ifdef PCI_MAP_FIXUP rle = resource_list_find(rl, type, *rid); if (rle == NULL) - return pci_alloc_map(dev, child, type, rid, - start, end, count, flags); -#endif /* PCI_MAP_FIXUP */ + return (pci_alloc_map(dev, child, type, rid, + start, end, count, flags)); break; } -#ifdef PCI_MAP_FIXUP /* * If we've already allocated the resource, then - * return it now. But first we may need to activate + * return it now. But first we may need to activate * it, since we don't allocate the resource as active - * above. Normally this would be done down in the + * above. Normally this would be done down in the * nexus, but since we short-circuit that path we have - * to do its job here. Not sure if we should free the + * to do its job here. Not sure if we should kfree the * resource if it fails to activate. - * - * Note: this also finds and returns resources for - * atapci devices in legacy mode as allocated in - * pci_ata_maps(). */ rle = resource_list_find(rl, type, *rid); if (rle != NULL && rle->res != NULL) { if (bootverbose) - device_printf(child, "reserved %#lx bytes for " - "rid %#x type %d at %#lx\n", - rman_get_size(rle->res), *rid, - type, rman_get_start(rle->res)); + device_printf(child, + "Reserved %#lx bytes for rid %#x type %d at %#lx\n", + rman_get_size(rle->res), *rid, type, + rman_get_start(rle->res)); if ((flags & RF_ACTIVE) && bus_generic_activate_resource(dev, child, type, - *rid, rle->res) != 0) - return NULL; - return rle->res; + *rid, rle->res) != 0) + return (NULL); + return (rle->res); } -#endif /* PCI_MAP_FIXUP */ } - return resource_list_alloc(rl, dev, child, type, rid, - start, end, count, flags); -} - -static int -pci_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct pci_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; - - return resource_list_release(rl, dev, child, type, rid, r); -} - -static int -pci_set_resource(device_t dev, device_t child, int type, int rid, - u_long start, u_long count) -{ - struct pci_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; - - resource_list_add(rl, type, rid, start, start + count - 1, count); - return 0; + return (resource_list_alloc(rl, dev, child, type, rid, + start, end, count, flags)); } -static int -pci_get_resource(device_t dev, device_t child, int type, int rid, - u_long *startp, u_long *countp) +void +pci_delete_resource(device_t dev, device_t child, int type, int rid) { - struct pci_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; + struct pci_devinfo *dinfo; + struct resource_list *rl; struct resource_list_entry *rle; - rle = resource_list_find(rl, type, rid); - if (!rle) - return ENOENT; - - if (startp) - *startp = rle->start; - if (countp) - *countp = rle->count; - - return 0; -} + if (device_get_parent(child) != dev) + return; -void -pci_delete_resource(device_t dev, device_t child, int type, int rid) -{ - kprintf("pci_delete_resource: PCI resources can not be deleted\n"); + dinfo = device_get_ivars(child); + rl = &dinfo->resources; + rle = resource_list_find(rl, type, rid); + if (rle) { + if (rle->res) { + if (rman_get_device(rle->res) != dev || + rman_get_flags(rle->res) & RF_ACTIVE) { + device_printf(dev, "delete_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + return; + } + bus_release_resource(dev, type, rid, rle->res); + } + resource_list_delete(rl, type, rid); + } + /* + * Why do we turn off the PCI configuration BAR when we delete a + * resource? -- imp + */ + pci_write_config(child, rid, 0, 4); + BUS_DELETE_RESOURCE(device_get_parent(dev), child, type, rid); } struct resource_list * pci_get_resource_list (device_t dev, device_t child) { - struct pci_devinfo *dinfo = device_get_ivars(child); + struct pci_devinfo *dinfo = device_get_ivars(child); - if (dinfo == NULL) - return (NULL); return (&dinfo->resources); } -u_int32_t +uint32_t pci_read_config_method(device_t dev, device_t child, int reg, int width) { struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; - return PCIB_READ_CONFIG(device_get_parent(dev), - cfg->bus, cfg->slot, cfg->func, - reg, width); + return (PCIB_READ_CONFIG(device_get_parent(dev), + cfg->bus, cfg->slot, cfg->func, reg, width)); } void pci_write_config_method(device_t dev, device_t child, int reg, - u_int32_t val, int width) + uint32_t val, int width) { struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; PCIB_WRITE_CONFIG(device_get_parent(dev), - cfg->bus, cfg->slot, cfg->func, - reg, val, width); + cfg->bus, cfg->slot, cfg->func, reg, val, width); } int -pci_child_location_str_method(device_t cbdev, device_t child, char *buf, +pci_child_location_str_method(device_t dev, device_t child, char *buf, size_t buflen) { - struct pci_devinfo *dinfo; - dinfo = device_get_ivars(child); ksnprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child), pci_get_function(child)); return (0); } int -pci_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, +pci_child_pnpinfo_str_method(device_t dev, device_t child, char *buf, size_t buflen) { struct pci_devinfo *dinfo; @@ -2310,26 +3687,36 @@ pci_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, int pci_assign_interrupt_method(device_t dev, device_t child) -{ - struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - - return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, - cfg->intpin)); +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + + return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, + cfg->intpin)); } static int pci_modevent(module_t mod, int what, void *arg) { + static struct cdev *pci_cdev; + extern struct dev_ops pcic_ops; + switch (what) { case MOD_LOAD: STAILQ_INIT(&pci_devq); + pci_generation = 0; + dev_ops_add(&pcic_ops, -1, 0); + pci_cdev = make_dev(&pcic_ops, 0, UID_ROOT, GID_WHEEL, 0644, + "pci%d", 0); + pci_load_vendor_data(); break; + case MOD_UNLOAD: + destroy_dev(pci_cdev); break; } - return 0; + return (0); } void @@ -2370,13 +3757,12 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1); pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1); pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1); -#if 0 + /* Restore MSI and MSI-X configurations if they are present. */ if (dinfo->cfg.msi.msi_location != 0) pci_resume_msi(dev); if (dinfo->cfg.msix.msix_location != 0) pci_resume_msix(dev); -#endif } void @@ -2436,7 +3822,6 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) cls = pci_get_class(dev); if (!setstate) return; - switch (pci_do_power_nodriver) { case 0: /* NO powerdown at all */ @@ -2453,10 +3838,6 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) case 3: /* Power down everything */ break; } - - if (cls == PCIC_STORAGE) - return; - /* * PCI spec says we can only go into D3 state from D0 state. * Transition from D[12] into D0 before going to D3 state. @@ -2467,121 +3848,3 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3) pci_set_powerstate(dev, PCI_POWERSTATE_D3); } - -int -pci_resume(device_t dev) -{ - int numdevs; - int i; - device_t *children; - device_t child; - struct pci_devinfo *dinfo; - pcicfgregs *cfg; - - device_get_children(dev, &children, &numdevs); - - for (i = 0; i < numdevs; i++) { - child = children[i]; - - dinfo = device_get_ivars(child); - cfg = &dinfo->cfg; - if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { - cfg->intline = PCI_ASSIGN_INTERRUPT(dev, child); - if (PCI_INTERRUPT_VALID(cfg->intline)) { - pci_write_config(child, PCIR_INTLINE, - cfg->intline, 1); - } - } - } - - kfree(children, M_TEMP); - - return (bus_generic_resume(dev)); -} - -void -pci_driver_added(device_t dev, driver_t *driver) -{ - int numdevs; - device_t *devlist; - device_t child; - struct pci_devinfo *dinfo; - int i; - - if (bootverbose) - device_printf(dev, "driver added\n"); - DEVICE_IDENTIFY(driver, dev); - device_get_children(dev, &devlist, &numdevs); - for (i = 0; i < numdevs; i++) { - child = devlist[i]; - if (device_get_state(child) != DS_NOTPRESENT) - continue; - dinfo = device_get_ivars(child); - pci_print_verbose(dinfo); - if (bootverbose) - kprintf("pci%d:%d:%d: reprobing on driver added\n", - dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func); - pci_cfg_restore(child, dinfo); - if (device_probe_and_attach(child) != 0) - pci_cfg_save(child, dinfo, 1); - } - kfree(devlist, M_TEMP); -} - -static void -pci_child_detached(device_t parent __unused, device_t child) { - /* Turn child's power off */ - pci_cfg_save(child, device_get_ivars(child), 1); -} - -static device_method_t pci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pci_probe), - DEVMETHOD(device_attach, pci_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, pci_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, pci_print_child), - DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), - DEVMETHOD(bus_read_ivar, pci_read_ivar), - DEVMETHOD(bus_write_ivar, pci_write_ivar), - DEVMETHOD(bus_driver_added, pci_driver_added), - DEVMETHOD(bus_child_detached, pci_child_detached), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - DEVMETHOD(bus_get_resource_list,pci_get_resource_list), - DEVMETHOD(bus_set_resource, pci_set_resource), - DEVMETHOD(bus_get_resource, pci_get_resource), - DEVMETHOD(bus_delete_resource, pci_delete_resource), - DEVMETHOD(bus_alloc_resource, pci_alloc_resource), - DEVMETHOD(bus_release_resource, pci_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), - DEVMETHOD(bus_child_location_str, pci_child_location_str_method), - - /* PCI interface */ - DEVMETHOD(pci_read_config, pci_read_config_method), - DEVMETHOD(pci_write_config, pci_write_config_method), - DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), - DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), - DEVMETHOD(pci_enable_io, pci_enable_io_method), - DEVMETHOD(pci_disable_io, pci_disable_io_method), - DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), - DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), - DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method), - - { 0, 0 } -}; - -driver_t pci_driver = { - "pci", - pci_methods, - 1, /* no softc */ -}; - -DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); -MODULE_VERSION(pci, 1); diff --git a/sys/bus/pci/pci_compat.c b/sys/bus/pci/pci_compat.c deleted file mode 100644 index e194780bb8..0000000000 --- a/sys/bus/pci/pci_compat.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 1997, Stefan Esser - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/pci/pci_compat.c,v 1.35.2.1 2001/10/14 21:14:14 luigi Exp $ - * $DragonFly: src/sys/bus/pci/pci_compat.c,v 1.14 2007/05/13 18:33:56 swildner Exp $ - * - */ - -#include "opt_bus.h" - -/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include "pcireg.h" -#include "pcivar.h" - -struct pci_compat_driver { - driver_t driver; - struct pci_device *dvp; -}; - -/* ------------------------------------------------------------------------- */ - -u_long -pci_conf_read(pcici_t cfg, u_long reg) -{ - return (pci_read_config(cfg->dev, reg, 4)); -} - -void -pci_conf_write(pcici_t cfg, u_long reg, u_long data) -{ - pci_write_config(cfg->dev, reg, data, 4); -} - -int -pci_map_port(pcici_t cfg, u_long reg, pci_port_t* pa) -{ - int rid; - struct resource *res; - - rid = reg; - res = bus_alloc_resource(cfg->dev, SYS_RES_IOPORT, &rid, - 0, ~0, 1, RF_ACTIVE); - if (res) { - *pa = rman_get_start(res); - return (1); - } - return (0); -} - -int -pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) -{ - int rid; - struct resource *res; - - rid = reg; - res = bus_alloc_resource(cfg->dev, SYS_RES_MEMORY, &rid, - 0, ~0, 1, RF_ACTIVE); - if (res) { - *pa = rman_get_start(res); - *va = (vm_offset_t) rman_get_virtual(res); - return (1); - } - return (0); -} - -int -pci_map_int(pcici_t cfg, pci_inthand_t *handler, void *arg) -{ - return (pci_map_int_right(cfg, handler, arg, 0)); -} - -int -pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, u_int intflags) -{ - int error; -#ifdef APIC_IO - int nextpin, muxcnt; -#endif - if (cfg->intpin != 0) { - int irq = cfg->intline; - int rid = 0; - struct resource *res; - int flags = 0; - int resflags = RF_SHAREABLE|RF_ACTIVE; - void *ih; - - if (intflags & INTR_FAST) - flags |= INTR_FAST; - if (intflags & INTR_EXCL) - resflags &= ~RF_SHAREABLE; - - res = bus_alloc_resource(cfg->dev, SYS_RES_IRQ, &rid, - irq, irq, 1, resflags); - if (!res) { - kprintf("pci_map_int: can't allocate interrupt\n"); - return 0; - } - - /* - * This is ugly. Translate the mask into an interrupt type. - */ - - error = BUS_SETUP_INTR(device_get_parent(cfg->dev), cfg->dev, - res, flags, handler, arg, &ih, NULL); - if (error != 0) - return 0; - -#ifdef NEW_BUS_PCI - /* - * XXX this apic stuff looks totally busted. It should - * move to the nexus code which actually registers the - * interrupt. - */ -#endif - -#ifdef APIC_IO - nextpin = next_apic_irq(irq); - - if (nextpin < 0) - return 1; - - /* - * Attempt handling of some broken mp tables. - * - * It's OK to yell (since the mp tables are broken). - * - * Hanging in the boot is not OK - */ - - muxcnt = 2; - nextpin = next_apic_irq(nextpin); - while (muxcnt < 5 && nextpin >= 0) { - muxcnt++; - nextpin = next_apic_irq(nextpin); - } - if (muxcnt >= 5) { - kprintf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); - return 0; - } - - kprintf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); - - nextpin = next_apic_irq(irq); - while (nextpin >= 0) { - rid = 0; - res = bus_alloc_resource(cfg->dev, SYS_RES_IRQ, &rid, - nextpin, nextpin, 1, - resflags); - if (!res) { - kprintf("pci_map_int: can't allocate extra interrupt\n"); - return 0; - } - error = BUS_SETUP_INTR(device_get_parent(cfg->dev), - cfg->dev, res, flags, - handler, arg, &ih, NULL); - if (error != 0) { - kprintf("pci_map_int: BUS_SETUP_INTR failed\n"); - return 0; - } - kprintf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); - nextpin = next_apic_irq(nextpin); - } -#endif - } - return (1); -} - -int -pci_unmap_int(pcici_t cfg) -{ - return (0); /* not supported, yet, since cfg doesn't know about idesc */ -} - -pcici_t -pci_get_parent_from_tag(pcici_t tag) -{ - return (pcici_t)pci_devlist_get_parent(tag); -} - -int -pci_get_bus_from_tag(pcici_t tag) -{ - return tag->bus; -} - -/* - * A simple driver to wrap the old pci driver mechanism for back-compat. - */ - -static int -pci_compat_probe(device_t dev) -{ - struct pci_device *dvp; - struct pci_devinfo *dinfo; - pcicfgregs *cfg; - const char *name; - int error; - - dinfo = device_get_ivars(dev); - cfg = &dinfo->cfg; - dvp = ((struct pci_compat_driver *)device_get_driver(dev))->dvp; - - /* - * Do the wrapped probe. - */ - error = ENXIO; - if (dvp && dvp->pd_probe) { - name = dvp->pd_probe(cfg, (cfg->device << 16) + cfg->vendor); - if (name) { - device_set_desc_copy(dev, name); - /* Allow newbus drivers to match "better" */ - error = -200; - } - } - - return error; -} - -static int -pci_compat_attach(device_t dev) -{ - struct pci_device *dvp; - struct pci_devinfo *dinfo; - pcicfgregs *cfg; - int unit; - - dinfo = device_get_ivars(dev); - cfg = &dinfo->cfg; - dvp = ((struct pci_compat_driver *)device_get_driver(dev))->dvp; - - unit = device_get_unit(dev); - if (unit > *dvp->pd_count) - *dvp->pd_count = unit; - if (dvp->pd_attach) - dvp->pd_attach(cfg, unit); - device_printf(dev, "driver is using old-style compatibility shims\n"); - return 0; -} - -static device_method_t pci_compat_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pci_compat_probe), - DEVMETHOD(device_attach, pci_compat_attach), - - { 0, 0 } -}; - -/* - * Create a new style driver around each old pci driver. - */ -int -compat_pci_handler(module_t mod, int type, void *data) -{ - struct pci_device *dvp = (struct pci_device *)data; - struct pci_compat_driver *driver; - devclass_t pci_devclass = devclass_find("pci"); - - switch (type) { - case MOD_LOAD: - driver = kmalloc(sizeof(struct pci_compat_driver), M_DEVBUF, M_WAITOK | M_ZERO); - driver->driver.name = dvp->pd_name; - driver->driver.methods = pci_compat_methods; - driver->driver.size = sizeof(struct pci_devinfo *); - driver->dvp = dvp; - devclass_add_driver(pci_devclass, (driver_t *)driver); - break; - case MOD_UNLOAD: - kprintf("%s: module unload not supported!\n", dvp->pd_name); - return EOPNOTSUPP; - default: - break; - } - return 0; -} diff --git a/sys/bus/pci/pci_if.m b/sys/bus/pci/pci_if.m index 9d09104cd8..38c3e0fa43 100644 --- a/sys/bus/pci/pci_if.m +++ b/sys/bus/pci/pci_if.m @@ -1,4 +1,4 @@ -# +#- # Copyright (c) 1998 Doug Rabson # All rights reserved. # @@ -23,14 +23,22 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $FreeBSD: src/sys/pci/pci_if.m,v 1.2.2.1 2001/07/21 22:40:26 imp Exp $ -# $DragonFly: src/sys/bus/pci/pci_if.m,v 1.5 2005/01/17 20:24:46 joerg Exp $ +# $FreeBSD: src/sys/dev/pci/pci_if.m,v 1.12.8.1 2009/04/15 03:14:26 kensmith Exp $ # #include INTERFACE pci; +CODE { + static int + null_msi_count(device_t dev, device_t child) + { + return (0); + } +}; + + METHOD u_int32_t read_config { device_t dev; device_t child; @@ -57,6 +65,19 @@ METHOD int set_powerstate { int state; }; +METHOD int get_vpd_ident { + device_t dev; + device_t child; + const char **identptr; +}; + +METHOD int get_vpd_readonly { + device_t dev; + device_t child; + const char *kw; + const char **vptr; +}; + METHOD int enable_busmaster { device_t dev; device_t child; @@ -80,6 +101,47 @@ METHOD int disable_io { }; METHOD int assign_interrupt { - device_t dev; - device_t child; + device_t dev; + device_t child; +}; + +METHOD int find_extcap { + device_t dev; + device_t child; + int capability; + int *capreg; +}; + +METHOD int alloc_msi { + device_t dev; + device_t child; + int *count; +}; + +METHOD int alloc_msix { + device_t dev; + device_t child; + int *count; +}; + +METHOD int remap_msix { + device_t dev; + device_t child; + int count; + const u_int *vectors; }; + +METHOD int release_msi { + device_t dev; + device_t child; +}; + +METHOD int msi_count { + device_t dev; + device_t child; +} DEFAULT null_msi_count; + +METHOD int msix_count { + device_t dev; + device_t child; +} DEFAULT null_msi_count; diff --git a/sys/bus/pci/pci_isab.c b/sys/bus/pci/pci_isab.c deleted file mode 100644 index fe763f926a..0000000000 --- a/sys/bus/pci/pci_isab.c +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright (c) 2004, Joerg Sonnenberger - * All rights reserved. - * Copyright (c) 1994,1995 Stefan Esser. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $DragonFly: src/sys/bus/pci/pci_isab.c,v 1.8 2006/12/22 23:12:17 swildner Exp $ - */ - -#include "opt_pci.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "pcib_private.h" - -static void chipset_attach(device_t dev, int unit); - -#ifndef PCI_QUIET - -struct condmsg { - unsigned char port; - unsigned char mask; - unsigned char value; - char flags; - const char *text; -}; - -#define M_XX 0 /* end of list */ -#define M_EQ 1 /* mask and return true if equal */ -#define M_NE 2 /* mask and return true if not equal */ -#define M_TR 3 /* don't read config, always true */ -#define M_EN 4 /* mask and print "enabled" if true, "disabled" if false */ -#define M_NN 5 /* opposite sense of M_EN */ - -static const struct condmsg conf82425ex[] = -{ - { 0x00, 0x00, 0x00, M_TR, "\tClock " }, - { 0x50, 0x06, 0x00, M_EQ, "25" }, - { 0x50, 0x06, 0x02, M_EQ, "33" }, - { 0x50, 0x04, 0x04, M_EQ, "??", }, - { 0x00, 0x00, 0x00, M_TR, "MHz, L1 Cache " }, - { 0x50, 0x01, 0x00, M_EQ, "Disabled\n" }, - { 0x50, 0x09, 0x01, M_EQ, "Write-through\n" }, - { 0x50, 0x09, 0x09, M_EQ, "Write-back\n" }, - - { 0x00, 0x00, 0x00, M_TR, "\tL2 Cache " }, - { 0x52, 0x07, 0x00, M_EQ, "Disabled" }, - { 0x52, 0x0f, 0x01, M_EQ, "64KB Write-through" }, - { 0x52, 0x0f, 0x02, M_EQ, "128KB Write-through" }, - { 0x52, 0x0f, 0x03, M_EQ, "256KB Write-through" }, - { 0x52, 0x0f, 0x04, M_EQ, "512KB Write-through" }, - { 0x52, 0x0f, 0x01, M_EQ, "64KB Write-back" }, - { 0x52, 0x0f, 0x02, M_EQ, "128KB Write-back" }, - { 0x52, 0x0f, 0x03, M_EQ, "256KB Write-back" }, - { 0x52, 0x0f, 0x04, M_EQ, "512KB Write-back" }, - { 0x53, 0x01, 0x00, M_EQ, ", 3-" }, - { 0x53, 0x01, 0x01, M_EQ, ", 2-" }, - { 0x53, 0x06, 0x00, M_EQ, "3-3-3" }, - { 0x53, 0x06, 0x02, M_EQ, "2-2-2" }, - { 0x53, 0x06, 0x04, M_EQ, "1-1-1" }, - { 0x53, 0x06, 0x06, M_EQ, "?-?-?" }, - { 0x53, 0x18, 0x00, M_EQ, "/4-2-2-2\n" }, - { 0x53, 0x18, 0x08, M_EQ, "/3-2-2-2\n" }, - { 0x53, 0x18, 0x10, M_EQ, "/?-?-?-?\n" }, - { 0x53, 0x18, 0x18, M_EQ, "/2-1-1-1\n" }, - - { 0x56, 0x00, 0x00, M_TR, "\tDRAM: " }, - { 0x56, 0x02, 0x02, M_EQ, "Fast Code Read, " }, - { 0x56, 0x04, 0x04, M_EQ, "Fast Data Read, " }, - { 0x56, 0x08, 0x08, M_EQ, "Fast Write, " }, - { 0x57, 0x20, 0x20, M_EQ, "Pipelined CAS" }, - { 0x57, 0x2e, 0x00, M_NE, "\n\t" }, - { 0x57, 0x00, 0x00, M_TR, "Timing: RAS: " }, - { 0x57, 0x07, 0x00, M_EQ, "4" }, - { 0x57, 0x07, 0x01, M_EQ, "3" }, - { 0x57, 0x07, 0x02, M_EQ, "2" }, - { 0x57, 0x07, 0x04, M_EQ, "1.5" }, - { 0x57, 0x07, 0x05, M_EQ, "1" }, - { 0x57, 0x00, 0x00, M_TR, " Clocks, CAS Read: " }, - { 0x57, 0x18, 0x00, M_EQ, "3/1", }, - { 0x57, 0x18, 0x00, M_EQ, "2/1", }, - { 0x57, 0x18, 0x00, M_EQ, "1.5/0.5", }, - { 0x57, 0x18, 0x00, M_EQ, "1/1", }, - { 0x57, 0x00, 0x00, M_TR, ", CAS Write: " }, - { 0x57, 0x20, 0x00, M_EQ, "2/1", }, - { 0x57, 0x20, 0x20, M_EQ, "1/1", }, - { 0x57, 0x00, 0x00, M_TR, "\n" }, - - { 0x40, 0x01, 0x01, M_EQ, "\tCPU-to-PCI Byte Merging\n" }, - { 0x40, 0x02, 0x02, M_EQ, "\tCPU-to-PCI Bursting\n" }, - { 0x40, 0x04, 0x04, M_EQ, "\tPCI Posted Writes\n" }, - { 0x40, 0x20, 0x00, M_EQ, "\tDRAM Parity Disabled\n" }, - - { 0x48, 0x03, 0x01, M_EQ, "\tPCI IDE controller: Primary (1F0h-1F7h,3F6h,3F7h)" }, - { 0x48, 0x03, 0x02, M_EQ, "\tPCI IDE controller: Secondary (170h-177h,376h,377h)" }, - { 0x4d, 0x01, 0x01, M_EQ, "\tRTC (70-77h)\n" }, - { 0x4d, 0x02, 0x02, M_EQ, "\tKeyboard (60,62,64,66h)\n" }, - { 0x4d, 0x08, 0x08, M_EQ, "\tIRQ12/M Mouse Function\n" }, - -/* end marker */ - { 0 } -}; - -static const struct condmsg conf82424zx[] = -{ - { 0x00, 0x00, 0x00, M_TR, "\tCPU: " }, - { 0x50, 0xe0, 0x00, M_EQ, "486DX" }, - { 0x50, 0xe0, 0x20, M_EQ, "486SX" }, - { 0x50, 0xe0, 0x40, M_EQ, "486DX2 or 486DX4" }, - { 0x50, 0xe0, 0x80, M_EQ, "Overdrive (writeback)" }, - - { 0x00, 0x00, 0x00, M_TR, ", bus=" }, - { 0x50, 0x03, 0x00, M_EQ, "25MHz" }, - { 0x50, 0x03, 0x01, M_EQ, "33MHz" }, - { 0x53, 0x01, 0x01, M_TR, ", CPU->Memory posting "}, - { 0x53, 0x01, 0x00, M_EQ, "OFF" }, - { 0x53, 0x01, 0x01, M_EQ, "ON" }, - - { 0x56, 0x30, 0x00, M_NE, "\n\tWarning:" }, - { 0x56, 0x20, 0x00, M_NE, " NO cache parity!" }, - { 0x56, 0x10, 0x00, M_NE, " NO DRAM parity!" }, - { 0x55, 0x04, 0x04, M_EQ, "\n\tWarning: refresh OFF! " }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tCache: " }, - { 0x52, 0x01, 0x00, M_EQ, "None" }, - { 0x52, 0xc1, 0x01, M_EQ, "64KB" }, - { 0x52, 0xc1, 0x41, M_EQ, "128KB" }, - { 0x52, 0xc1, 0x81, M_EQ, "256KB" }, - { 0x52, 0xc1, 0xc1, M_EQ, "512KB" }, - { 0x52, 0x03, 0x01, M_EQ, " writethrough" }, - { 0x52, 0x03, 0x03, M_EQ, " writeback" }, - - { 0x52, 0x01, 0x01, M_EQ, ", cache clocks=" }, - { 0x52, 0x05, 0x01, M_EQ, "3-1-1-1" }, - { 0x52, 0x05, 0x05, M_EQ, "2-1-1-1" }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tDRAM:" }, - { 0x55, 0x43, 0x00, M_NE, " page mode" }, - { 0x55, 0x02, 0x02, M_EQ, " code fetch" }, - { 0x55, 0x43, 0x43, M_EQ, "," }, - { 0x55, 0x43, 0x42, M_EQ, " and" }, - { 0x55, 0x40, 0x40, M_EQ, " read" }, - { 0x55, 0x03, 0x03, M_EQ, " and" }, - { 0x55, 0x43, 0x41, M_EQ, " and" }, - { 0x55, 0x01, 0x01, M_EQ, " write" }, - { 0x55, 0x43, 0x00, M_NE, "," }, - - { 0x00, 0x00, 0x00, M_TR, " memory clocks=" }, - { 0x55, 0x20, 0x00, M_EQ, "X-2-2-2" }, - { 0x55, 0x20, 0x20, M_EQ, "X-1-2-1" }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tCPU->PCI: posting " }, - { 0x53, 0x02, 0x00, M_NE, "ON" }, - { 0x53, 0x02, 0x00, M_EQ, "OFF" }, - { 0x00, 0x00, 0x00, M_TR, ", burst mode " }, - { 0x54, 0x02, 0x00, M_NE, "ON" }, - { 0x54, 0x02, 0x00, M_EQ, "OFF" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tPCI->Memory: posting " }, - { 0x54, 0x01, 0x00, M_NE, "ON" }, - { 0x54, 0x01, 0x00, M_EQ, "OFF" }, - - { 0x00, 0x00, 0x00, M_TR, "\n" }, - -/* end marker */ - { 0 } -}; - -static const struct condmsg conf82434lx[] = -{ - { 0x00, 0x00, 0x00, M_TR, "\tCPU: " }, - { 0x50, 0xe3, 0x82, M_EQ, "Pentium, 60MHz" }, - { 0x50, 0xe3, 0x83, M_EQ, "Pentium, 66MHz" }, - { 0x50, 0xe3, 0xa2, M_EQ, "Pentium, 90MHz" }, - { 0x50, 0xe3, 0xa3, M_EQ, "Pentium, 100MHz" }, - { 0x50, 0xc2, 0x82, M_NE, "(unknown)" }, - { 0x50, 0x04, 0x00, M_EQ, " (primary cache OFF)" }, - - { 0x53, 0x01, 0x01, M_TR, ", CPU->Memory posting "}, - { 0x53, 0x01, 0x01, M_NE, "OFF" }, - { 0x53, 0x01, 0x01, M_EQ, "ON" }, - - { 0x53, 0x08, 0x00, M_NE, ", read around write"}, - - { 0x70, 0x04, 0x00, M_EQ, "\n\tWarning: Cache parity disabled!" }, - { 0x57, 0x20, 0x00, M_NE, "\n\tWarning: DRAM parity mask!" }, - { 0x57, 0x01, 0x00, M_EQ, "\n\tWarning: refresh OFF! " }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tCache: " }, - { 0x52, 0x01, 0x00, M_EQ, "None" }, - { 0x52, 0x81, 0x01, M_EQ, "" }, - { 0x52, 0xc1, 0x81, M_EQ, "256KB" }, - { 0x52, 0xc1, 0xc1, M_EQ, "512KB" }, - { 0x52, 0x03, 0x01, M_EQ, " writethrough" }, - { 0x52, 0x03, 0x03, M_EQ, " writeback" }, - - { 0x52, 0x01, 0x01, M_EQ, ", cache clocks=" }, - { 0x52, 0x21, 0x01, M_EQ, "3-2-2-2/4-2-2-2" }, - { 0x52, 0x21, 0x21, M_EQ, "3-1-1-1" }, - - { 0x52, 0x01, 0x01, M_EQ, "\n\tCache flags: " }, - { 0x52, 0x11, 0x11, M_EQ, " cache-all" }, - { 0x52, 0x09, 0x09, M_EQ, " byte-control" }, - { 0x52, 0x05, 0x05, M_EQ, " powersaver" }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tDRAM:" }, - { 0x57, 0x10, 0x00, M_EQ, " page mode" }, - - { 0x00, 0x00, 0x00, M_TR, " memory clocks=" }, - { 0x57, 0xc0, 0x00, M_EQ, "X-4-4-4 (70ns)" }, - { 0x57, 0xc0, 0x40, M_EQ, "X-4-4-4/X-3-3-3 (60ns)" }, - { 0x57, 0xc0, 0x80, M_EQ, "???" }, - { 0x57, 0xc0, 0xc0, M_EQ, "X-3-3-3 (50ns)" }, - { 0x58, 0x02, 0x02, M_EQ, ", RAS-wait" }, - { 0x58, 0x01, 0x01, M_EQ, ", CAS-wait" }, - - { 0x00, 0x00, 0x00, M_TR, "\n\tCPU->PCI: posting " }, - { 0x53, 0x02, 0x02, M_EQ, "ON" }, - { 0x53, 0x02, 0x00, M_EQ, "OFF" }, - { 0x00, 0x00, 0x00, M_TR, ", burst mode " }, - { 0x54, 0x02, 0x00, M_NE, "ON" }, - { 0x54, 0x02, 0x00, M_EQ, "OFF" }, - { 0x54, 0x04, 0x00, M_TR, ", PCI clocks=" }, - { 0x54, 0x04, 0x00, M_EQ, "2-2-2-2" }, - { 0x54, 0x04, 0x00, M_NE, "2-1-1-1" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tPCI->Memory: posting " }, - { 0x54, 0x01, 0x00, M_NE, "ON" }, - { 0x54, 0x01, 0x00, M_EQ, "OFF" }, - - { 0x57, 0x01, 0x01, M_EQ, "\n\tRefresh:" }, - { 0x57, 0x03, 0x03, M_EQ, " CAS#/RAS#(Hidden)" }, - { 0x57, 0x03, 0x01, M_EQ, " RAS#Only" }, - { 0x57, 0x05, 0x05, M_EQ, " BurstOf4" }, - - { 0x00, 0x00, 0x00, M_TR, "\n" }, - -/* end marker */ - { 0 } -}; - -static const struct condmsg conf82378[] = -{ - { 0x00, 0x00, 0x00, M_TR, "\tBus Modes:" }, - { 0x41, 0x04, 0x04, M_EQ, " Bus Park," }, - { 0x41, 0x02, 0x02, M_EQ, " Bus Lock," }, - { 0x41, 0x02, 0x00, M_EQ, " Resource Lock," }, - { 0x41, 0x01, 0x01, M_EQ, " GAT" }, - { 0x4d, 0x20, 0x20, M_EQ, "\n\tCoprocessor errors enabled" }, - { 0x4d, 0x10, 0x10, M_EQ, "\n\tMouse function enabled" }, - - { 0x4e, 0x30, 0x10, M_EQ, "\n\tIDE controller: Primary (1F0h-1F7h,3F6h,3F7h)" }, - { 0x4e, 0x30, 0x30, M_EQ, "\n\tIDE controller: Secondary (170h-177h,376h,377h)" }, - { 0x4e, 0x28, 0x08, M_EQ, "\n\tFloppy controller: 3F0h,3F1h " }, - { 0x4e, 0x24, 0x04, M_EQ, "\n\tFloppy controller: 3F2h-3F7h " }, - { 0x4e, 0x28, 0x28, M_EQ, "\n\tFloppy controller: 370h,371h " }, - { 0x4e, 0x24, 0x24, M_EQ, "\n\tFloppy controller: 372h-377h " }, - { 0x4e, 0x02, 0x02, M_EQ, "\n\tKeyboard controller: 60h,62h,64h,66h" }, - { 0x4e, 0x01, 0x01, M_EQ, "\n\tRTC: 70h-77h" }, - - { 0x4f, 0x80, 0x80, M_EQ, "\n\tConfiguration RAM: 0C00h,0800h-08FFh" }, - { 0x4f, 0x40, 0x40, M_EQ, "\n\tPort 92: enabled" }, - { 0x4f, 0x03, 0x00, M_EQ, "\n\tSerial Port A: COM1 (3F8h-3FFh)" }, - { 0x4f, 0x03, 0x01, M_EQ, "\n\tSerial Port A: COM2 (2F8h-2FFh)" }, - { 0x4f, 0x0c, 0x00, M_EQ, "\n\tSerial Port B: COM1 (3F8h-3FFh)" }, - { 0x4f, 0x0c, 0x04, M_EQ, "\n\tSerial Port B: COM2 (2F8h-2FFh)" }, - { 0x4f, 0x30, 0x00, M_EQ, "\n\tParallel Port: LPT1 (3BCh-3BFh)" }, - { 0x4f, 0x30, 0x04, M_EQ, "\n\tParallel Port: LPT2 (378h-37Fh)" }, - { 0x4f, 0x30, 0x20, M_EQ, "\n\tParallel Port: LPT3 (278h-27Fh)" }, - { 0x00, 0x00, 0x00, M_TR, "\n" }, - -/* end marker */ - { 0 } -}; - -static const struct condmsg conf82437fx[] = -{ - /* PCON -- PCI Control Register */ - { 0x00, 0x00, 0x00, M_TR, "\tCPU Inactivity timer: " }, - { 0x50, 0xe0, 0xe0, M_EQ, "8" }, - { 0x50, 0xe0, 0xd0, M_EQ, "7" }, - { 0x50, 0xe0, 0xc0, M_EQ, "6" }, - { 0x50, 0xe0, 0xb0, M_EQ, "5" }, - { 0x50, 0xe0, 0xa0, M_EQ, "4" }, - { 0x50, 0xe0, 0x90, M_EQ, "3" }, - { 0x50, 0xe0, 0x80, M_EQ, "2" }, - { 0x50, 0xe0, 0x00, M_EQ, "1" }, - { 0x00, 0x00, 0x00, M_TR, " clocks\n\tPeer Concurrency: " }, - { 0x50, 0x08, 0x08, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tCPU-to-PCI Write Bursting: " }, - { 0x50, 0x04, 0x00, M_NN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tPCI Streaming: " }, - { 0x50, 0x02, 0x00, M_NN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tBus Concurrency: " }, - { 0x50, 0x01, 0x00, M_NN, 0 }, - - /* CC -- Cache Control Regsiter */ - { 0x00, 0x00, 0x00, M_TR, "\n\tCache:" }, - { 0x52, 0xc0, 0x80, M_EQ, " 512K" }, - { 0x52, 0xc0, 0x40, M_EQ, " 256K" }, - { 0x52, 0xc0, 0x00, M_EQ, " NO" }, - { 0x52, 0x30, 0x00, M_EQ, " pipelined-burst" }, - { 0x52, 0x30, 0x10, M_EQ, " burst" }, - { 0x52, 0x30, 0x20, M_EQ, " asynchronous" }, - { 0x52, 0x30, 0x30, M_EQ, " dual-bank pipelined-burst" }, - { 0x00, 0x00, 0x00, M_TR, " secondary; L1 " }, - { 0x52, 0x01, 0x00, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n" }, - - /* DRAMC -- DRAM Control Register */ - { 0x57, 0x07, 0x00, M_EQ, "Warning: refresh OFF!\n" }, - { 0x00, 0x00, 0x00, M_TR, "\tDRAM:" }, - { 0x57, 0xc0, 0x00, M_EQ, " no memory hole" }, - { 0x57, 0xc0, 0x40, M_EQ, " 512K-640K memory hole" }, - { 0x57, 0xc0, 0x80, M_EQ, " 15M-16M memory hole" }, - { 0x57, 0x07, 0x01, M_EQ, ", 50 MHz refresh" }, - { 0x57, 0x07, 0x02, M_EQ, ", 60 MHz refresh" }, - { 0x57, 0x07, 0x03, M_EQ, ", 66 MHz refresh" }, - - /* DRAMT = DRAM Timing Register */ - { 0x00, 0x00, 0x00, M_TR, "\n\tRead burst timing: " }, - { 0x58, 0x60, 0x00, M_EQ, "x-4-4-4/x-4-4-4" }, - { 0x58, 0x60, 0x20, M_EQ, "x-3-3-3/x-4-4-4" }, - { 0x58, 0x60, 0x40, M_EQ, "x-2-2-2/x-3-3-3" }, - { 0x58, 0x60, 0x60, M_EQ, "???" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tWrite burst timing: " }, - { 0x58, 0x18, 0x00, M_EQ, "x-4-4-4" }, - { 0x58, 0x18, 0x08, M_EQ, "x-3-3-3" }, - { 0x58, 0x18, 0x10, M_EQ, "x-2-2-2" }, - { 0x58, 0x18, 0x18, M_EQ, "???" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tRAS-CAS delay: " }, - { 0x58, 0x04, 0x00, M_EQ, "3" }, - { 0x58, 0x04, 0x04, M_EQ, "2" }, - { 0x00, 0x00, 0x00, M_TR, " clocks\n" }, - - /* end marker */ - { 0 } -}; - -static const struct condmsg conf82437vx[] = -{ - /* PCON -- PCI Control Register */ - { 0x00, 0x00, 0x00, M_TR, "\n\tPCI Concurrency: " }, - { 0x50, 0x08, 0x08, M_EN, 0 }, - - /* CC -- Cache Control Regsiter */ - { 0x00, 0x00, 0x00, M_TR, "\n\tCache:" }, - { 0x52, 0xc0, 0x80, M_EQ, " 512K" }, - { 0x52, 0xc0, 0x40, M_EQ, " 256K" }, - { 0x52, 0xc0, 0x00, M_EQ, " NO" }, - { 0x52, 0x30, 0x00, M_EQ, " pipelined-burst" }, - { 0x52, 0x30, 0x10, M_EQ, " burst" }, - { 0x52, 0x30, 0x20, M_EQ, " asynchronous" }, - { 0x52, 0x30, 0x30, M_EQ, " dual-bank pipelined-burst" }, - { 0x00, 0x00, 0x00, M_TR, " secondary; L1 " }, - { 0x52, 0x01, 0x00, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n" }, - - /* DRAMC -- DRAM Control Register */ - { 0x57, 0x07, 0x00, M_EQ, "Warning: refresh OFF!\n" }, - { 0x00, 0x00, 0x00, M_TR, "\tDRAM:" }, - { 0x57, 0xc0, 0x00, M_EQ, " no memory hole" }, - { 0x57, 0xc0, 0x40, M_EQ, " 512K-640K memory hole" }, - { 0x57, 0xc0, 0x80, M_EQ, " 15M-16M memory hole" }, - { 0x57, 0x07, 0x01, M_EQ, ", 50 MHz refresh" }, - { 0x57, 0x07, 0x02, M_EQ, ", 60 MHz refresh" }, - { 0x57, 0x07, 0x03, M_EQ, ", 66 MHz refresh" }, - - /* DRAMT = DRAM Timing Register */ - { 0x00, 0x00, 0x00, M_TR, "\n\tRead burst timing: " }, - { 0x58, 0x60, 0x00, M_EQ, "x-4-4-4/x-4-4-4" }, - { 0x58, 0x60, 0x20, M_EQ, "x-3-3-3/x-4-4-4" }, - { 0x58, 0x60, 0x40, M_EQ, "x-2-2-2/x-3-3-3" }, - { 0x58, 0x60, 0x60, M_EQ, "???" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tWrite burst timing: " }, - { 0x58, 0x18, 0x00, M_EQ, "x-4-4-4" }, - { 0x58, 0x18, 0x08, M_EQ, "x-3-3-3" }, - { 0x58, 0x18, 0x10, M_EQ, "x-2-2-2" }, - { 0x58, 0x18, 0x18, M_EQ, "???" }, - { 0x00, 0x00, 0x00, M_TR, "\n\tRAS-CAS delay: " }, - { 0x58, 0x04, 0x00, M_EQ, "3" }, - { 0x58, 0x04, 0x04, M_EQ, "2" }, - { 0x00, 0x00, 0x00, M_TR, " clocks\n" }, - - /* end marker */ - { 0 } -}; - -static const struct condmsg conf82371fb[] = -{ - /* IORT -- ISA I/O Recovery Timer Register */ - { 0x00, 0x00, 0x00, M_TR, "\tI/O Recovery Timing: 8-bit " }, - { 0x4c, 0x40, 0x00, M_EQ, "3.5" }, - { 0x4c, 0x78, 0x48, M_EQ, "1" }, - { 0x4c, 0x78, 0x50, M_EQ, "2" }, - { 0x4c, 0x78, 0x58, M_EQ, "3" }, - { 0x4c, 0x78, 0x60, M_EQ, "4" }, - { 0x4c, 0x78, 0x68, M_EQ, "5" }, - { 0x4c, 0x78, 0x70, M_EQ, "6" }, - { 0x4c, 0x78, 0x78, M_EQ, "7" }, - { 0x4c, 0x78, 0x40, M_EQ, "8" }, - { 0x00, 0x00, 0x00, M_TR, " clocks, 16-bit " }, - { 0x4c, 0x04, 0x00, M_EQ, "3.5" }, - { 0x4c, 0x07, 0x05, M_EQ, "1" }, - { 0x4c, 0x07, 0x06, M_EQ, "2" }, - { 0x4c, 0x07, 0x07, M_EQ, "3" }, - { 0x4c, 0x07, 0x04, M_EQ, "4" }, - { 0x00, 0x00, 0x00, M_TR, " clocks\n" }, - - /* XBCS -- X-Bus Chip Select Register */ - { 0x00, 0x00, 0x00, M_TR, "\tExtended BIOS: " }, - { 0x4e, 0x80, 0x80, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tLower BIOS: " }, - { 0x4e, 0x40, 0x40, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tCoprocessor IRQ13: " }, - { 0x4e, 0x20, 0x20, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tMouse IRQ12: " }, - { 0x4e, 0x10, 0x10, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n" }, - - { 0x00, 0x00, 0x00, M_TR, "\tInterrupt Routing: " }, -#define PIRQ(x, n) \ - { 0x00, 0x00, 0x00, M_TR, n ": " }, \ - { x, 0x80, 0x80, M_EQ, "disabled" }, \ - { x, 0xc0, 0x40, M_EQ, "[shared] " }, \ - { x, 0x8f, 0x03, M_EQ, "IRQ3" }, \ - { x, 0x8f, 0x04, M_EQ, "IRQ4" }, \ - { x, 0x8f, 0x05, M_EQ, "IRQ5" }, \ - { x, 0x8f, 0x06, M_EQ, "IRQ6" }, \ - { x, 0x8f, 0x07, M_EQ, "IRQ7" }, \ - { x, 0x8f, 0x09, M_EQ, "IRQ9" }, \ - { x, 0x8f, 0x0a, M_EQ, "IRQ10" }, \ - { x, 0x8f, 0x0b, M_EQ, "IRQ11" }, \ - { x, 0x8f, 0x0c, M_EQ, "IRQ12" }, \ - { x, 0x8f, 0x0e, M_EQ, "IRQ14" }, \ - { x, 0x8f, 0x0f, M_EQ, "IRQ15" } - - /* Interrupt routing */ - PIRQ(0x60, "A"), - PIRQ(0x61, ", B"), - PIRQ(0x62, ", C"), - PIRQ(0x63, ", D"), - PIRQ(0x70, "\n\t\tMB0"), - PIRQ(0x71, ", MB1"), - - { 0x00, 0x00, 0x00, M_TR, "\n" }, - -#undef PIRQ - - /* XXX - do DMA routing, too? */ - { 0 } -}; - -static const struct condmsg conf82371fb2[] = -{ - /* IDETM -- IDE Timing Register */ - { 0x00, 0x00, 0x00, M_TR, "\tPrimary IDE: " }, - { 0x41, 0x80, 0x80, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n\tSecondary IDE: " }, - { 0x43, 0x80, 0x80, M_EN, 0 }, - { 0x00, 0x00, 0x00, M_TR, "\n" }, - - /* end of list */ - { 0 } -}; - -static void -writeconfig (device_t dev, const struct condmsg *tbl) -{ - while (tbl->flags != M_XX) { - const char *text = 0; - - if (tbl->flags == M_TR) { - text = tbl->text; - } else { - unsigned char v = pci_read_config(dev, tbl->port, 1); - switch (tbl->flags) { - case M_EQ: - if ((v & tbl->mask) == tbl->value) text = tbl->text; - break; - case M_NE: - if ((v & tbl->mask) != tbl->value) text = tbl->text; - break; - case M_EN: - text = (v & tbl->mask) ? "enabled" : "disabled"; - break; - case M_NN: - text = (v & tbl->mask) ? "disabled" : "enabled"; - } - } - if (text) kprintf ("%s", text); - tbl++; - } -} - -#endif /* PCI_QUIET */ - -static void -chipset_attach (device_t dev, int unit) -{ -#ifndef PCI_QUIET - if (!bootverbose) - return; - - switch (pci_get_devid(dev)) { - case 0x04868086: - writeconfig (dev, conf82425ex); - break; - case 0x04838086: - writeconfig (dev, conf82424zx); - break; - case 0x04a38086: - writeconfig (dev, conf82434lx); - break; - case 0x04848086: - writeconfig (dev, conf82378); - break; - case 0x122d8086: - writeconfig (dev, conf82437fx); - break; - case 0x70308086: - writeconfig (dev, conf82437vx); - break; - case 0x70008086: - case 0x122e8086: - writeconfig (dev, conf82371fb); - break; - case 0x70108086: - case 0x12308086: - writeconfig (dev, conf82371fb2); - break; -#if 0 - case 0x00011011: /* DEC 21050 */ - case 0x00221014: /* IBM xxx */ - writeconfig (dev, conf_pci2pci); - break; -#endif - }; -#endif /* PCI_QUIET */ -} - -static const char * -eisab_match(device_t dev) -{ - switch (pci_get_devid(dev)) { - case 0x04828086: - /* Recognize this specifically, it has PCI-HOST class (!) */ - return ("Intel 82375EB PCI-EISA bridge"); - } - if (pci_get_class(dev) == PCIC_BRIDGE - && pci_get_subclass(dev) == PCIS_BRIDGE_EISA) - return pci_bridge_type(dev); - - return NULL; -} - -static const char * -isab_match(device_t dev) -{ - unsigned rev; - - switch (pci_get_devid(dev)) { - case 0x04848086: - rev = pci_get_revid(dev); - if (rev == 3) - return ("Intel 82378ZB PCI to ISA bridge"); - return ("Intel 82378IB PCI to ISA bridge"); - case 0x122e8086: - return ("Intel 82371FB PCI to ISA bridge"); - case 0x70008086: - return ("Intel 82371SB PCI to ISA bridge"); - case 0x71108086: - return ("Intel 82371AB PCI to ISA bridge"); - case 0x71988086: - return ("Intel 82443MX PCI to ISA bridge"); - case 0x24108086: - return ("Intel 82801AA (ICH) PCI to LPC bridge"); - case 0x24208086: - return ("Intel 82801AB (ICH0) PCI to LPC bridge"); - case 0x24408086: - return ("Intel 82801BA/BAM (ICH2) PCI to LPC bridge"); - case 0x26408086: - return ("Intel 82801FB/FBW (ICH6) PCI to LPC bridge"); - case 0x26428086: - return ("Intel 82801FR/FRW (ICH6) PCI to LPC bridge"); - - /* NVIDIA -- vendor 0x10de */ - case 0x006010de: - return ("NVIDIA nForce2 PCI to ISA bridge"); - - /* VLSI -- vendor 0x1004 */ - case 0x00061004: - return ("VLSI 82C593 PCI to ISA bridge"); - - /* VIA Technologies -- vendor 0x1106 */ - case 0x05861106: /* south bridge section */ - return ("VIA 82C586 PCI-ISA bridge"); - case 0x05961106: - return ("VIA 82C596B PCI-ISA bridge"); - case 0x06861106: - return ("VIA 82C686 PCI-ISA bridge"); - - /* AcerLabs -- vendor 0x10b9 */ - /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ - /* id is '10b9" but the register always shows "10b9". -Foxfair */ - case 0x153310b9: - return ("AcerLabs M1533 portable PCI-ISA bridge"); - case 0x154310b9: - return ("AcerLabs M1543 desktop PCI-ISA bridge"); - - /* SiS -- vendor 0x1039 */ - case 0x00081039: - return ("SiS 85c503 PCI-ISA bridge"); - - /* Cyrix -- vendor 0x1078 */ - case 0x00001078: - return ("Cyrix Cx5510 PCI-ISA bridge"); - case 0x01001078: - return ("Cyrix Cx5530 PCI-ISA bridge"); - - /* UMC United Microelectronics 0x1060 */ - case 0x886a1060: - return ("UMC UM8886 ISA Bridge with EIDE"); - - /* Cypress -- vendor 0x1080 */ - case 0xc6931080: - if (pci_get_class(dev) == PCIC_BRIDGE - && pci_get_subclass(dev) == PCIS_BRIDGE_ISA) - return ("Cypress 82C693 PCI-ISA bridge"); - break; - - /* ServerWorks -- vendor 0x1166 */ - case 0x02001166: - return ("ServerWorks IB6566 PCI to ISA bridge"); - } - - if (pci_get_class(dev) == PCIC_BRIDGE - && pci_get_subclass(dev) == PCIS_BRIDGE_ISA) - return pci_bridge_type(dev); - - return NULL; -} - -static int -isab_probe(device_t dev) -{ - const char *desc; - int is_eisa; - - is_eisa = 0; - desc = eisab_match(dev); - if (desc) - is_eisa = 1; - else - desc = isab_match(dev); - if (desc) { - /* - * For a PCI-EISA bridge, add both eisa and isa. - * Only add one instance of eisa or isa for now. - */ - device_set_desc_copy(dev, desc); - if (is_eisa && !devclass_get_device(devclass_find("eisa"), 0)) - device_add_child(dev, "eisa", -1); - - if (!devclass_get_device(devclass_find("isa"), 0)) - device_add_child(dev, "isa", -1); - return -1000; - } - return ENXIO; -} - -int -isab_attach(device_t dev) -{ - chipset_attach(dev, device_get_unit(dev)); - return bus_generic_attach(dev); -} - -static device_method_t isab_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, isab_probe), - DEVMETHOD(device_attach, isab_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - { 0, 0 } -}; - -static driver_t isab_driver = { - "isab", - isab_methods, - 1, -}; - -devclass_t isab_devclass; - -DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); diff --git a/sys/bus/pci/pci_pci.c b/sys/bus/pci/pci_pci.c new file mode 100644 index 0000000000..0532cdd50d --- /dev/null +++ b/sys/bus/pci/pci_pci.c @@ -0,0 +1,714 @@ +/*- + * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier + * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000 BSDi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.50.2.2.4.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * PCI:PCI bridge support. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pcib_if.h" + +static int pcib_probe(device_t dev); + +static device_method_t pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pcib_probe), + DEVMETHOD(device_attach, pcib_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, pcib_read_ivar), + DEVMETHOD(bus_write_ivar, pcib_write_ivar), + DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_read_config, pcib_read_config), + DEVMETHOD(pcib_write_config, pcib_write_config), + DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), + DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), + DEVMETHOD(pcib_release_msi, pcib_release_msi), + DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), + DEVMETHOD(pcib_release_msix, pcib_release_msix), + DEVMETHOD(pcib_map_msi, pcib_map_msi), + + { 0, 0 } +}; + +static devclass_t pcib_devclass; + +DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); +DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); + +/* + * Is the prefetch window open (eg, can we allocate memory in it?) + */ +static int +pcib_is_prefetch_open(struct pcib_softc *sc) +{ + return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); +} + +/* + * Is the nonprefetch window open (eg, can we allocate memory in it?) + */ +static int +pcib_is_nonprefetch_open(struct pcib_softc *sc) +{ + return (sc->membase > 0 && sc->membase < sc->memlimit); +} + +/* + * Is the io window open (eg, can we allocate ports in it?) + */ +static int +pcib_is_io_open(struct pcib_softc *sc) +{ + return (sc->iobase > 0 && sc->iobase < sc->iolimit); +} + +/* + * Generic device interface + */ +static int +pcib_probe(device_t dev) +{ + if ((pci_get_class(dev) == PCIC_BRIDGE) && + (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { + device_set_desc(dev, "PCI-PCI bridge"); + return(-10000); + } + return(ENXIO); +} + +void +pcib_attach_common(device_t dev) +{ + struct pcib_softc *sc; + uint8_t iolow; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* + * Get current bridge configuration. + */ + sc->command = pci_read_config(dev, PCIR_COMMAND, 1); + sc->domain = pci_get_domain(dev); + sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); + sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); + sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); + sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); + sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); + + /* + * Determine current I/O decode. + */ + if (sc->command & PCIM_CMD_PORTEN) { + iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); + if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { + sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), + pci_read_config(dev, PCIR_IOBASEL_1, 1)); + } else { + sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); + } + + iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); + if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { + sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), + pci_read_config(dev, PCIR_IOLIMITL_1, 1)); + } else { + sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); + } + } + + /* + * Determine current memory decode. + */ + if (sc->command & PCIM_CMD_MEMEN) { + sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); + sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); + iolow = pci_read_config(dev, PCIR_PMBASEL_1, 1); + if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) + sc->pmembase = PCI_PPBMEMBASE( + pci_read_config(dev, PCIR_PMBASEH_1, 4), + pci_read_config(dev, PCIR_PMBASEL_1, 2)); + else + sc->pmembase = PCI_PPBMEMBASE(0, + pci_read_config(dev, PCIR_PMBASEL_1, 2)); + iolow = pci_read_config(dev, PCIR_PMLIMITL_1, 1); + if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) + sc->pmemlimit = PCI_PPBMEMLIMIT( + pci_read_config(dev, PCIR_PMLIMITH_1, 4), + pci_read_config(dev, PCIR_PMLIMITL_1, 2)); + else + sc->pmemlimit = PCI_PPBMEMLIMIT(0, + pci_read_config(dev, PCIR_PMLIMITL_1, 2)); + } + + /* + * Quirk handling. + */ + switch (pci_get_devid(dev)) { + case 0x12258086: /* Intel 82454KX/GX (Orion) */ + { + uint8_t supbus; + + supbus = pci_read_config(dev, 0x41, 1); + if (supbus != 0xff) { + sc->secbus = supbus + 1; + sc->subbus = supbus + 1; + } + break; + } + + /* + * The i82380FB mobile docking controller is a PCI-PCI bridge, + * and it is a subtractive bridge. However, the ProgIf is wrong + * so the normal setting of PCIB_SUBTRACTIVE bit doesn't + * happen. There's also a Toshiba bridge that behaves this + * way. + */ + case 0x124b8086: /* Intel 82380FB Mobile */ + case 0x060513d7: /* Toshiba ???? */ + sc->flags |= PCIB_SUBTRACTIVE; + break; + + /* Compaq R3000 BIOS sets wrong subordinate bus number. */ + case 0x00dd10de: + { + char *cp; + + if ((cp = kgetenv("smbios.planar.maker")) == NULL) + break; + if (strncmp(cp, "Compal", 6) != 0) { + kfreeenv(cp); + break; + } + kfreeenv(cp); + if ((cp = kgetenv("smbios.planar.product")) == NULL) + break; + if (strncmp(cp, "08A0", 4) != 0) { + kfreeenv(cp); + break; + } + kfreeenv(cp); + if (sc->subbus < 0xa) { + pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); + sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); + } + break; + } + } + + if (pci_msi_device_blacklisted(dev)) + sc->flags |= PCIB_DISABLE_MSI; + + /* + * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, + * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, + * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. + * This means they act as if they were subtractively decoding + * bridges and pass all transactions. Mark them and real ProgIf 1 + * parts as subtractive. + */ + if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || + pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) + sc->flags |= PCIB_SUBTRACTIVE; + + if (bootverbose) { + device_printf(dev, " domain %d\n", sc->domain); + device_printf(dev, " secondary bus %d\n", sc->secbus); + device_printf(dev, " subordinate bus %d\n", sc->subbus); + device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); + if (pcib_is_nonprefetch_open(sc)) + device_printf(dev, " memory decode 0x%jx-0x%jx\n", + (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); + if (pcib_is_prefetch_open(sc)) + device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", + (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); + else + device_printf(dev, " no prefetched decode\n"); + if (sc->flags & PCIB_SUBTRACTIVE) + device_printf(dev, " Subtractively decoded bridge.\n"); + } + + /* + * XXX If the secondary bus number is zero, we should assign a bus number + * since the BIOS hasn't, then initialise the bridge. + */ + + /* + * XXX If the subordinate bus number is less than the secondary bus number, + * we should pick a better value. One sensible alternative would be to + * pick 255; the only tradeoff here is that configuration transactions + * would be more widely routed than absolutely necessary. + */ +} + +int +pcib_attach(device_t dev) +{ + struct pcib_softc *sc; + device_t child; + + pcib_attach_common(dev); + sc = device_get_softc(dev); + if (sc->secbus != 0) { + child = device_add_child(dev, "pci", sc->secbus); + if (child != NULL) + return(bus_generic_attach(dev)); + } + + /* no secondary bus; we should have fixed this */ + return(0); +} + +int +pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct pcib_softc *sc = device_get_softc(dev); + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = sc->domain; + return(0); + case PCIB_IVAR_BUS: + *result = sc->secbus; + return(0); + } + return(ENOENT); +} + +int +pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct pcib_softc *sc = device_get_softc(dev); + + switch (which) { + case PCIB_IVAR_DOMAIN: + return(EINVAL); + case PCIB_IVAR_BUS: + sc->secbus = value; + return(0); + } + return(ENOENT); +} + +/* + * We have to trap resource allocation requests and ensure that the bridge + * is set up to, or capable of handling them. + */ +struct resource * +pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct pcib_softc *sc = device_get_softc(dev); + const char *name, *suffix; + int ok; + + /* + * Fail the allocation for this range if it's not supported. + */ + name = device_get_nameunit(child); + if (name == NULL) { + name = ""; + suffix = ""; + } else + suffix = " "; + switch (type) { + case SYS_RES_IOPORT: + ok = 0; + if (!pcib_is_io_open(sc)) + break; + ok = (start >= sc->iobase && end <= sc->iolimit); + + /* + * Make sure we allow access to VGA I/O addresses when the + * bridge has the "VGA Enable" bit set. + */ + if (!ok && pci_is_vga_ioport_range(start, end)) + ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; + + if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { + if (!ok) { + if (start < sc->iobase) + start = sc->iobase; + if (end > sc->iolimit) + end = sc->iolimit; + if (start < end) + ok = 1; + } + } else { + ok = 1; +#if 1 + if (start < sc->iobase && end > sc->iolimit) { + start = sc->iobase; + end = sc->iolimit; + } +#endif + } + if (end < start) { + device_printf(dev, "ioport: end (%lx) < start (%lx)\n", + end, start); + start = 0; + end = 0; + ok = 0; + } + if (!ok) { + device_printf(dev, "%s%srequested unsupported I/O " + "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", + name, suffix, start, end, sc->iobase, sc->iolimit); + return (NULL); + } + if (bootverbose) + device_printf(dev, + "%s%srequested I/O range 0x%lx-0x%lx: in range\n", + name, suffix, start, end); + break; + + case SYS_RES_MEMORY: + ok = 0; + if (pcib_is_nonprefetch_open(sc)) + ok = ok || (start >= sc->membase && end <= sc->memlimit); + if (pcib_is_prefetch_open(sc)) + ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); + + /* + * Make sure we allow access to VGA memory addresses when the + * bridge has the "VGA Enable" bit set. + */ + if (!ok && pci_is_vga_memory_range(start, end)) + ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; + + if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { + if (!ok) { + ok = 1; + if (flags & RF_PREFETCHABLE) { + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase) + start = sc->pmembase; + if (end > sc->pmemlimit) + end = sc->pmemlimit; + } else { + ok = 0; + } + } else { /* non-prefetchable */ + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase) + start = sc->membase; + if (end > sc->memlimit) + end = sc->memlimit; + } else { + ok = 0; + } + } + } + } else if (!ok) { + ok = 1; /* subtractive bridge: always ok */ +#if 1 + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase && end > sc->memlimit) { + start = sc->membase; + end = sc->memlimit; + } + } + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase && end > sc->pmemlimit) { + start = sc->pmembase; + end = sc->pmemlimit; + } + } +#endif + } + if (end < start) { + device_printf(dev, "memory: end (%lx) < start (%lx)\n", + end, start); + start = 0; + end = 0; + ok = 0; + } + if (!ok && bootverbose) + device_printf(dev, + "%s%srequested unsupported memory range %#lx-%#lx " + "(decoding %#jx-%#jx, %#jx-%#jx)\n", + name, suffix, start, end, + (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, + (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); + if (!ok) + return (NULL); + if (bootverbose) + device_printf(dev,"%s%srequested memory range " + "0x%lx-0x%lx: good\n", + name, suffix, start, end); + break; + + default: + break; + } + /* + * Bridge is OK decoding this resource, so pass it up. + */ + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, + count, flags)); +} + +/* + * PCIB interface. + */ +int +pcib_maxslots(device_t dev) +{ + return(PCI_SLOTMAX); +} + +/* + * Since we are a child of a PCI bus, its parent must support the pcib interface. + */ +uint32_t +pcib_read_config(device_t dev, int b, int s, int f, int reg, int width) +{ + return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); +} + +void +pcib_write_config(device_t dev, int b, int s, int f, int reg, uint32_t val, int width) +{ + PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); +} + +/* + * Route an interrupt across a PCI bridge. + */ +int +pcib_route_interrupt(device_t pcib, device_t dev, int pin) +{ + device_t bus; + int parent_intpin; + int intnum; + + /* + * + * The PCI standard defines a swizzle of the child-side device/intpin to + * the parent-side intpin as follows. + * + * device = device on child bus + * child_intpin = intpin on child bus slot (0-3) + * parent_intpin = intpin on parent bus slot (0-3) + * + * parent_intpin = (device + child_intpin) % 4 + */ + parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; + + /* + * Our parent is a PCI bus. Its parent must export the pcib interface + * which includes the ability to route interrupts. + */ + bus = device_get_parent(pcib); + intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); + if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { + device_printf(pcib, "slot %d INT%c is routed to irq %d\n", + pci_get_slot(dev), 'A' + pin - 1, intnum); + } + return(intnum); +} + +/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ +int +pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) +{ + struct pcib_softc *sc = device_get_softc(pcib); + device_t bus; + + if (sc->flags & PCIB_DISABLE_MSI) + return (ENXIO); + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, + irqs)); +} + +/* Pass request to release MSI/MSI-X messages up to the parent bridge. */ +int +pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); +} + +/* Pass request to alloc an MSI-X message up to the parent bridge. */ +int +pcib_alloc_msix(device_t pcib, device_t dev, int *irq) +{ + struct pcib_softc *sc = device_get_softc(pcib); + device_t bus; + + if (sc->flags & PCIB_DISABLE_MSI) + return (ENXIO); + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); +} + +/* Pass request to release an MSI-X message up to the parent bridge. */ +int +pcib_release_msix(device_t pcib, device_t dev, int irq) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); +} + +/* Pass request to map MSI/MSI-X message up to parent bridge. */ +int +pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, + uint32_t *data) +{ + device_t bus; + int error; + + bus = device_get_parent(pcib); + error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); + if (error) + return (error); + + pci_ht_map_msi(pcib, *addr); + return (0); +} + +/* + * Try to read the bus number of a host-PCI bridge using appropriate config + * registers. + */ +int +host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, + uint8_t *busnum) +{ + uint32_t id; + + id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); + if (id == 0xffffffff) + return (0); + + switch (id) { + case 0x12258086: + /* Intel 824?? */ + /* XXX This is a guess */ + /* *busnum = read_config(bus, slot, func, 0x41, 1); */ + *busnum = bus; + break; + case 0x84c48086: + /* Intel 82454KX/GX (Orion) */ + *busnum = read_config(bus, slot, func, 0x4a, 1); + break; + case 0x84ca8086: + /* + * For the 450nx chipset, there is a whole bundle of + * things pretending to be host bridges. The MIOC will + * be seen first and isn't really a pci bridge (the + * actual busses are attached to the PXB's). We need to + * read the registers of the MIOC to figure out the + * bus numbers for the PXB channels. + * + * Since the MIOC doesn't have a pci bus attached, we + * pretend it wasn't there. + */ + return (0); + case 0x84cb8086: + switch (slot) { + case 0x12: + /* Intel 82454NX PXB#0, Bus#A */ + *busnum = read_config(bus, 0x10, func, 0xd0, 1); + break; + case 0x13: + /* Intel 82454NX PXB#0, Bus#B */ + *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; + break; + case 0x14: + /* Intel 82454NX PXB#1, Bus#A */ + *busnum = read_config(bus, 0x10, func, 0xd3, 1); + break; + case 0x15: + /* Intel 82454NX PXB#1, Bus#B */ + *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; + break; + } + break; + + /* ServerWorks -- vendor 0x1166 */ + case 0x00051166: + case 0x00061166: + case 0x00081166: + case 0x00091166: + case 0x00101166: + case 0x00111166: + case 0x00171166: + case 0x01011166: + case 0x010f1014: + case 0x02011166: + case 0x03021014: + *busnum = read_config(bus, slot, func, 0x44, 1); + break; + + /* Compaq/HP -- vendor 0x0e11 */ + case 0x60100e11: + *busnum = read_config(bus, slot, func, 0xc8, 1); + break; + default: + /* Don't know how to read bus number. */ + return 0; + } + + return 1; +} diff --git a/sys/bus/pci/pci_pcib.c b/sys/bus/pci/pci_pcib.c deleted file mode 100644 index b687438ca5..0000000000 --- a/sys/bus/pci/pci_pcib.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright (c) 2004, Joerg Sonnenberger - * All rights reserved. - * Copyright (c) 1994,1995 Stefan Esser. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $DragonFly: src/sys/bus/pci/pci_pcib.c,v 1.8 2007/11/28 11:35:40 sephe Exp $ - */ - -#include "opt_pci.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "pcib_if.h" -#include "pcib_private.h" - -static devclass_t pcib_devclass; - -/* - * Attach a pci bus device to a motherboard or pci-to-pci bridge bus. - * Due to probe recursion it is possible for pci-to-pci bridges (such as - * on the DELL2550) to attach before all the motherboard bridges have - * attached. We must call device_add_child() with the secondary id - * rather then -1 in order to ensure that we do not accidently use - * a motherboard PCI id, otherwise the device probe will believe that - * the later motherboard bridge bus has already been probed and refuse - * to probe it. The result: disappearing busses! - * - * Bridges will cause recursions or duplicate attach attempts. If - * we have already attached this bus we don't do it again! - * - * NOTE THE DEVICE TOPOLOGY! - * - * [pcibX]->[pciX]->[pciX.Y] - * [pcibZ] - * - * When attaching a new bus device note that the PCI methods are - * based in the parent device, but the device ivars for those methods - * are based in our sub-device. The PCI accessor functions all assume - * you are passing-in the sub-device. - */ -void -pcib_attach_common(device_t dev) -{ - struct pcib_softc *sc; - uint8_t iolow; - - sc = device_get_softc(dev); - sc->dev = dev; - - /* - * Get current bridge configuration. - */ - sc->command = pci_read_config(dev, PCIR_COMMAND, 1); - sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); - sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); - sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); - sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); - sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); - - /* - * Determine current I/O decode. - */ - if (sc->command & PCIM_CMD_PORTEN) { - iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); - if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { - sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), - pci_read_config(dev, PCIR_IOBASEL_1, 1)); - } else { - sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); - } - - iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); - if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { - sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), - pci_read_config(dev, PCIR_IOLIMITL_1, 1)); - } else { - sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); - } - } - - /* - * Determine current memory decode. - */ - if (sc->command & PCIM_CMD_MEMEN) { - sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); - sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); - sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4), - pci_read_config(dev, PCIR_PMBASEL_1, 2)); - sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4), - pci_read_config(dev, PCIR_PMLIMITL_1, 2)); - } - - /* - * Quirk handling. - */ - switch (pci_get_devid(dev)) { - case 0x12258086: /* Intel 82454KX/GX (Orion) */ - { - uint8_t supbus; - - supbus = pci_read_config(dev, 0x41, 1); - if (supbus != 0xff) { - sc->secbus = supbus + 1; - sc->subbus = supbus + 1; - } - break; - } - - /* - * The i82380FB mobile docking controller is a PCI-PCI bridge, - * and it is a subtractive bridge. However, the ProgIf is wrong - * so the normal setting of PCIB_SUBTRACTIVE bit doesn't - * happen. There's also a Toshiba bridge that behaves this - * way. - */ - case 0x124b8086: /* Intel 82380FB Mobile */ - case 0x060513d7: /* Toshiba ???? */ - sc->flags |= PCIB_SUBTRACTIVE; - break; - } - - /* - * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, - * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, - * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. - * This means they act as if they were subtractively decoding - * bridges and pass all transactions. Mark them and real ProgIf 1 - * parts as subtractive. - */ - if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || - pci_read_config(dev, PCIR_PROGIF, 1) == 1) - sc->flags |= PCIB_SUBTRACTIVE; - - if (bootverbose) { - device_printf(dev, " secondary bus %d\n", sc->secbus); - device_printf(dev, " subordinate bus %d\n", sc->subbus); - device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); - device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); - device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); - if (sc->flags & PCIB_SUBTRACTIVE) - device_printf(dev, " Subtractively decoded bridge.\n"); - } - - if (pci_is_pcie(dev) && pcie_slot_implemented(dev)) { - uint16_t slot_ctrl; - uint8_t ptr; - - /* - * XXX - * Before proper PCI Express hot-plug support is in place, - * disable all hot-plug interrupts on the PCI Express root - * port or down stream port for now. - */ -#define HPINTRS (PCIEM_SLTCTL_HPINTR_MASK | PCIEM_SLTCTL_HPINTR_EN) - - ptr = pci_get_pciecap_ptr(dev); - slot_ctrl = pci_read_config(dev, ptr + PCIER_SLOTCTRL, 2); - if (slot_ctrl & HPINTRS) { - device_printf(dev, "Disable PCI Express hot-plug " - "interrupts(0x%04x)\n", slot_ctrl & HPINTRS); - slot_ctrl &= ~HPINTRS; - pci_write_config(dev, ptr + PCIER_SLOTCTRL, slot_ctrl, 2); - } - -#undef HPINTRS - } - - /* - * XXX If the secondary bus number is zero, we should assign a bus number - * since the BIOS hasn't, then initialise the bridge. - */ - - /* - * XXX If the subordinate bus number is less than the secondary bus number, - * we should pick a better value. One sensible alternative would be to - * pick 255; the only tradeoff here is that configuration transactions - * would be more widely routed than absolutely necessary. - */ -} - -/* - * Called with the bridge candidate, which is under a PCI slot device. - * Note that the ivars are stored in the candidate. - */ -static const char * -pci_match_bridge(device_t dev) -{ - switch (pci_get_devid(dev)) { - /* Intel -- vendor 0x8086 */ - case 0x71818086: - return ("Intel 82443LX (440 LX) PCI-PCI (AGP) bridge"); - case 0x71918086: - return ("Intel 82443BX (440 BX) PCI-PCI (AGP) bridge"); - case 0x71A18086: - return ("Intel 82443GX (440 GX) PCI-PCI (AGP) bridge"); - case 0x84cb8086: - return ("Intel 82454NX PCI Expander Bridge"); - case 0x11318086: - return ("Intel 82801BA/BAM (ICH2) PCI-PCI (AGP) bridge"); - case 0x124b8086: - return ("Intel 82380FB mobile PCI to PCI bridge"); - case 0x24188086: - return ("Intel 82801AA (ICH) Hub to PCI bridge"); - case 0x24288086: - return ("Intel 82801AB (ICH0) Hub to PCI bridge"); - case 0x244e8086: - return ("Intel 82801BA/CA/DB/EB/FB (ICH2/3/4/5/6) Hub to PCI bridge"); - case 0x1a318086: - return ("Intel 82845 PCI-PCI (AGP) bridge"); - - /* VLSI -- vendor 0x1004 */ - case 0x01021004: - return ("VLSI 82C534 Eagle II PCI Bus bridge"); - case 0x01031004: - return ("VLSI 82C538 Eagle II PCI Docking bridge"); - - /* VIA Technologies -- vendor 0x1106 */ - case 0x83051106: - return ("VIA 8363 (Apollo KT133) PCI-PCI (AGP) bridge"); - case 0x85981106: - return ("VIA 82C598MVP (Apollo MVP3) PCI-PCI (AGP) bridge"); - /* Exclude the ACPI function of VT82Cxxx series */ - case 0x30401106: - case 0x30501106: - case 0x30571106: - return NULL; - - /* AcerLabs -- vendor 0x10b9 */ - /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ - /* id is '10b9" but the register always shows "10b9". -Foxfair */ - case 0x524710b9: - return ("AcerLabs M5247 PCI-PCI(AGP Supported) bridge"); - case 0x524310b9:/* 5243 seems like 5247, need more info to divide*/ - return ("AcerLabs M5243 PCI-PCI bridge"); - - /* AMD -- vendor 0x1022 */ - case 0x70071022: - return ("AMD-751 PCI-PCI (1x/2x AGP) bridge"); - case 0x700f1022: - return ("AMD-761 PCI-PCI (4x AGP) bridge"); - - /* DEC -- vendor 0x1011 */ - case 0x00011011: - return ("DEC 21050 PCI-PCI bridge"); - case 0x00211011: - return ("DEC 21052 PCI-PCI bridge"); - case 0x00221011: - return ("DEC 21150 PCI-PCI bridge"); - case 0x00241011: - return ("DEC 21152 PCI-PCI bridge"); - case 0x00251011: - return ("DEC 21153 PCI-PCI bridge"); - case 0x00261011: - return ("DEC 21154 PCI-PCI bridge"); - - /* NVIDIA -- vendor 0x10de */ - case 0x006c10de: - case 0x01e810de: - return ("NVIDIA nForce2 PCI-PCI bridge"); - - /* Others */ - case 0x00221014: - return ("IBM 82351 PCI-PCI bridge"); - /* UMC United Microelectronics 0x1060 */ - case 0x88811060: - return ("UMC UM8881 HB4 486 PCI Chipset"); - }; - - if (pci_get_class(dev) == PCIC_BRIDGE - && pci_get_subclass(dev) == PCIS_BRIDGE_PCI) { - return pci_bridge_type(dev); - } - - return NULL; -} - -/* - * bus/pci/i386/pcibus.c added "pcib" devices under "pci" (slot) devices, - * causing us to probe and attach here. - * - * Note that the parent "pci" device has stored ivars in our device. We - * are both a "pci" device and potentially a "pcib" device. - */ -static int -pcib_probe(device_t dev) -{ - const char *desc; - - desc = pci_match_bridge(dev); - if (desc) { - device_set_desc_copy(dev, desc); - return -1000; - } - - return ENXIO; -} - -/* - * Note that the "pci" device ivars are stored in the ivar data field - * for our device. The "pcib" device ivars are stored in the softc - * structure. - */ -int -pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct pcib_softc *sc = device_get_softc(dev); - - switch (which) { - case PCIB_IVAR_BUS: - *result = sc->secbus; - return (0); - } - return (ENOENT); -} - -int -pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) -{ - struct pcib_softc *sc = device_get_softc(dev); - - switch (which) { - case PCIB_IVAR_BUS: - sc->secbus = value; - return (0); - } - return (ENOENT); -} - -int -pcib_attach(device_t dev) -{ - struct pcib_softc *sc; - - pcib_attach_common(dev); - sc = device_get_softc(dev); - /*chipset_attach(dev, device_get_unit(dev));*/ - - /* - * The pcib unit is not really under our control because - * we have are not (XXX) using the identify interface to - * assign the bridge driver, instead letting subr_bus do - * it via the probe mechanism. However, we *do* directly - * create the "pci" children and we can control the unit - * number we assign for those. We assign the secondary bus - * id as the unit number. - */ - if (sc->secbus != 0) { - if (devclass_find_unit("pci", sc->secbus)) { - device_printf(dev, "Duplicate secondary bus %d, " - "cannot attach bridge\n", - sc->secbus); - - } else { - device_add_child(dev, "pci", sc->secbus); - bus_generic_attach(dev); - } - } - return 0; -} - -/* - * Is the prefetch window open (eg, can we allocate memory in it?) - */ -static int -pcib_is_prefetch_open(struct pcib_softc *sc) -{ - return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); -} - -/* - * Is the nonprefetch window open (eg, can we allocate memory in it?) - */ -static int -pcib_is_nonprefetch_open(struct pcib_softc *sc) -{ - return (sc->membase > 0 && sc->membase < sc->memlimit); -} - -/* - * Is the io window open (eg, can we allocate ports in it?) - */ -static int -pcib_is_io_open(struct pcib_softc *sc) -{ - return (sc->iobase > 0 && sc->iobase < sc->iolimit); -} - -/* - * We have to trap resource allocation requests and ensure that the bridge - * is set up to, or capable of handling them. - */ -struct resource * -pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - struct pcib_softc *sc = device_get_softc(dev); - int ok; - - /* - * Fail the allocation for this range if it's not supported. - */ - switch (type) { - case SYS_RES_IOPORT: - ok = 0; - if (!pcib_is_io_open(sc)) - break; - ok = (start >= sc->iobase && end <= sc->iolimit); - if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { - if (!ok) { - if (start < sc->iobase) - start = sc->iobase; - if (end > sc->iolimit) - end = sc->iolimit; - if (start < end) - ok = 1; - } - } else { - ok = 1; -#ifdef PCI_MAP_FIXUP - if (start < sc->iobase && end > sc->iolimit) { - start = sc->iobase; - end = sc->iolimit; - } -#endif - } - if (end < start) { - device_printf(dev, "ioport: end (%lx) < start (%lx)\n", end, start); - start = 0; - end = 0; - ok = 0; - } - if (!ok) { - device_printf(dev, "device %s requested unsupported I/O " - "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", - device_get_nameunit(child), start, end, - sc->iobase, sc->iolimit); - return (NULL); - } - if (bootverbose) - device_printf(dev, "device %s requested decoded I/O range 0x%lx-0x%lx\n", - device_get_nameunit(child), start, end); - break; - - case SYS_RES_MEMORY: - ok = 0; - if (pcib_is_nonprefetch_open(sc)) - ok = ok || (start >= sc->membase && end <= sc->memlimit); - if (pcib_is_prefetch_open(sc)) - ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); - if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { - if (!ok) { - ok = 1; - if (flags & RF_PREFETCHABLE) { - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase) - start = sc->pmembase; - if (end > sc->pmemlimit) - end = sc->pmemlimit; - } else { - ok = 0; - } - } else { /* non-prefetchable */ - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase) - start = sc->membase; - if (end > sc->memlimit) - end = sc->memlimit; - } else { - ok = 0; - } - } - } - } else if (!ok) { - ok = 1; /* subtractive bridge: always ok */ -#ifdef PCI_MAP_FIXUP - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase && end > sc->memlimit) { - start = sc->membase; - end = sc->memlimit; - } - } - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase && end > sc->pmemlimit) { - start = sc->pmembase; - end = sc->pmemlimit; - } - } -#endif - } - if (end < start) { - device_printf(dev, "memory: end (%lx) < start (%lx)\n", end, start); - start = 0; - end = 0; - ok = 0; - } - if (!ok && bootverbose) - device_printf(dev, - "device %s requested unsupported memory range " - "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", - device_get_nameunit(child), start, end, - sc->membase, sc->memlimit, sc->pmembase, - sc->pmemlimit); - if (!ok) - return (NULL); - if (bootverbose) - device_printf(dev,"device %s requested decoded memory range 0x%lx-0x%lx\n", - device_get_nameunit(child), start, end); - break; - - default: - break; - } - /* - * Bridge is OK decoding this resource, so pass it up. - */ - return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); -} - -int -pcib_maxslots(device_t dev) -{ - return (31); -} - -u_int32_t -pcib_read_config(device_t dev, int b, int s, int f, - int reg, int width) -{ - /* - * Pass through to the next ppb up the chain (i.e. our - * grandparent). - * - * [pcibX]->[pciX]->[pciX.Y] - * [pcibY] - * ^ - * getting back to this point. - */ - return PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), - b, s, f, reg, width); -} - -void -pcib_write_config(device_t dev, int b, int s, int f, - int reg, uint32_t val, int width) -{ - /* - * Pass through to the next ppb up the chain (i.e. our - * grandparent). - */ - PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), - b, s, f, reg, val, width); -} - -/* - * Route an interrupt across a PCI bridge. - * - * pcib - is the pci bridge device - * dev - is the device - */ -int -pcib_route_interrupt(device_t pcib, device_t dev, int pin) -{ - device_t bus; - int parent_intpin; - int intnum; - - /* - * - * The PCI standard defines a swizzle of the child-side device/intpin - * to the parent-side intpin as follows. - * - * device = device on child bus - * child_intpin = intpin on child bus slot (0-3) - * parent_intpin = intpin on parent bus slot (0-3) - * - * parent_intpin = (device + child_intpin) % 4 - */ - parent_intpin = (pci_get_slot(pcib) + (pin - 1)) % 4; - - /* - * Our parent is a PCI bus. Its parent must export the pci interface - * which includes the ability to route interrupts. - */ - bus = device_get_parent(pcib); - intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, - parent_intpin + 1); - device_printf(pcib, "routed slot %d INT%c to irq %d\n", - pci_get_slot(dev), 'A' + pin - 1, intnum); - return(intnum); -} - -/* - * Try to read the bus number of a host-PCI bridge using appropriate config - * registers. - */ -int -host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, - uint8_t *busnum) -{ - uint32_t id; - - id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); - if (id == 0xffffffff) - return (0); - - switch (id) { - case 0x12258086: - /* Intel 824?? */ - /* XXX This is a guess */ - /* *busnum = read_config(bus, slot, func, 0x41, 1); */ - *busnum = bus; - break; - case 0x84c48086: - /* Intel 82454KX/GX (Orion) */ - *busnum = read_config(bus, slot, func, 0x4a, 1); - break; - case 0x84ca8086: - /* - * For the 450nx chipset, there is a whole bundle of - * things pretending to be host bridges. The MIOC will - * be seen first and isn't really a pci bridge (the - * actual busses are attached to the PXB's). We need to - * read the registers of the MIOC to figure out the - * bus numbers for the PXB channels. - * - * Since the MIOC doesn't have a pci bus attached, we - * pretend it wasn't there. - */ - return (0); - case 0x84cb8086: - switch (slot) { - case 0x12: - /* Intel 82454NX PXB#0, Bus#A */ - *busnum = read_config(bus, 0x10, func, 0xd0, 1); - break; - case 0x13: - /* Intel 82454NX PXB#0, Bus#B */ - *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; - break; - case 0x14: - /* Intel 82454NX PXB#1, Bus#A */ - *busnum = read_config(bus, 0x10, func, 0xd3, 1); - break; - case 0x15: - /* Intel 82454NX PXB#1, Bus#B */ - *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; - break; - } - break; - - /* ServerWorks -- vendor 0x1166 */ - case 0x00051166: - case 0x00061166: - case 0x00081166: - case 0x00091166: - case 0x00101166: - case 0x00111166: - case 0x00171166: - case 0x01011166: - case 0x010f1014: - case 0x02011166: - case 0x03021014: - *busnum = read_config(bus, slot, func, 0x44, 1); - break; - default: - /* Don't know how to read bus number. */ - return 0; - } - - return 1; -} - -static device_method_t pcib_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pcib_probe), - DEVMETHOD(device_attach, pcib_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, pcib_read_ivar), - DEVMETHOD(bus_write_ivar, pcib_write_ivar), - DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - /* pcib interface */ - DEVMETHOD(pcib_maxslots, pcib_maxslots), - DEVMETHOD(pcib_read_config, pcib_read_config), - DEVMETHOD(pcib_write_config, pcib_write_config), - DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), - - { 0, 0 } -}; - -static driver_t pcib_driver = { - "pcib", - pcib_methods, - sizeof(struct pcib_softc) -}; - -DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); diff --git a/sys/bus/pci/pci_private.h b/sys/bus/pci/pci_private.h index 6729da8b29..ae6cff7f5f 100644 --- a/sys/bus/pci/pci_private.h +++ b/sys/bus/pci/pci_private.h @@ -1,5 +1,7 @@ -/* - * Copyright (c) 2004, Joerg Sonnenberger +/*- + * Copyright (c) 1997, Stefan Esser + * Copyright (c) 2000, Michael Smith + * Copyright (c) 2000, BSDi * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,58 +25,88 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $DragonFly: src/sys/bus/pci/pci_private.h,v 1.6 2008/09/05 10:39:36 hasso Exp $ + * $FreeBSD: src/sys/dev/pci/pci_private.h,v 1.25.8.1 2009/04/15 03:14:26 kensmith Exp $ * */ -extern devclass_t pci_devclass; - -struct pci_devinfo *pci_read_device(device_t, int, int, int, size_t); -struct resource_list *pci_get_resource_list (device_t dev, device_t child); -struct resource *pci_alloc_resource(device_t dev, device_t child, - int type, int *rid, u_long start, u_long end, - u_long count, u_int flags); - +#ifndef _PCI_PRIVATE_H_ +#define _PCI_PRIVATE_H_ -u_int32_t pci_read_config_method(device_t dev, device_t child, - int reg, int width); -void pci_write_config_method(device_t dev, device_t child, - int reg, u_int32_t val, int width); - -const char *pci_class_to_string(int class); -void pci_delete_resource(device_t dev, device_t child, int type, int rid); -void pci_print_verbose(struct pci_devinfo *); -void pci_probe_nomatch(device_t dev, device_t child); -void pci_add_children(device_t dev, int busno, size_t dinfo_size); -void pci_add_child(device_t bus, struct pci_devinfo *dinfo); -void pci_driver_added(device_t dev, driver_t *driver); -int pci_freecfg(struct pci_devinfo *); -int pci_read_ivar(device_t, device_t, int, uintptr_t *); -int pci_write_ivar(device_t, device_t, int, uintptr_t); -int pci_resume(device_t dev); -int pci_print_child(device_t dev, device_t child); -int pci_assign_interrupt_method(device_t dev, device_t child); -int pci_set_powerstate_method(device_t dev, device_t child, int state); -int pci_get_powerstate_method(device_t dev, device_t child); -int pci_enable_busmaster_method(device_t dev, device_t child); -int pci_disable_busmaster_method(device_t dev, device_t child); -int pci_enable_io_method(device_t dev, device_t child, int space); -int pci_disable_io_method(device_t dev, device_t child, int space); +/* + * Export definitions of the pci bus so that we can more easily share + * it with "subclass" busses. + */ +DECLARE_CLASS(pci_driver); -int pci_child_pnpinfo_str_method(device_t cbdev, device_t child, - char *buf, size_t buflen); -int pci_child_location_str_method(device_t cbdev, device_t child, - char *buf, size_t buflen); +void pci_add_children(device_t dev, int domain, int busno, + size_t dinfo_size); +void pci_add_child(device_t bus, struct pci_devinfo *dinfo); +void pci_add_resources(device_t pcib, device_t bus, device_t dev, int force, + uint32_t prefetchmask); +void pci_driver_added(device_t dev, driver_t *driver); +int pci_print_child(device_t dev, device_t child); +void pci_probe_nomatch(device_t dev, device_t child); +int pci_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result); +int pci_write_ivar(device_t dev, device_t child, int which, + uintptr_t value); +int pci_setup_intr(device_t dev, device_t child, + struct resource *irq, int flags, + driver_intr_t *intr, void *arg, void **cookiep, lwkt_serialize_t serializer); +int pci_teardown_intr(device_t dev, device_t child, + struct resource *irq, void *cookie); +int pci_get_vpd_ident_method(device_t dev, device_t child, + const char **identptr); +int pci_get_vpd_readonly_method(device_t dev, device_t child, + const char *kw, const char **vptr); +int pci_set_powerstate_method(device_t dev, device_t child, + int state); +int pci_get_powerstate_method(device_t dev, device_t child); +uint32_t pci_read_config_method(device_t dev, device_t child, + int reg, int width); +void pci_write_config_method(device_t dev, device_t child, + int reg, uint32_t val, int width); +int pci_enable_busmaster_method(device_t dev, device_t child); +int pci_disable_busmaster_method(device_t dev, device_t child); +int pci_enable_io_method(device_t dev, device_t child, int space); +int pci_disable_io_method(device_t dev, device_t child, int space); +int pci_find_extcap_method(device_t dev, device_t child, + int capability, int *capreg); +int pci_alloc_msi_method(device_t dev, device_t child, int *count); +int pci_alloc_msix_method(device_t dev, device_t child, int *count); +int pci_remap_msix_method(device_t dev, device_t child, + int count, const u_int *vectors); +int pci_release_msi_method(device_t dev, device_t child); +int pci_msi_count_method(device_t dev, device_t child); +int pci_msix_count_method(device_t dev, device_t child); +struct resource *pci_alloc_resource(device_t dev, device_t child, + int type, int *rid, u_long start, u_long end, u_long count, + u_int flags); +void pci_delete_resource(device_t dev, device_t child, + int type, int rid); +struct resource_list *pci_get_resource_list (device_t dev, device_t child); +struct pci_devinfo *pci_read_device(device_t pcib, int d, int b, int s, int f, + size_t size); +void pci_print_verbose(struct pci_devinfo *dinfo); +int pci_freecfg(struct pci_devinfo *dinfo); +int pci_child_location_str_method(device_t cbdev, device_t child, + char *buf, size_t buflen); +int pci_child_pnpinfo_str_method(device_t cbdev, device_t child, + char *buf, size_t buflen); +int pci_assign_interrupt_method(device_t dev, device_t child); +int pci_resume(device_t dev); +int pci_suspend(device_t dev); /** Restore the config register state. The state must be previously * saved with pci_cfg_save. However, the pci bus driver takes care of * that. This function will also return the device to PCI_POWERSTATE_D0 * if it is currently in a lower power mode. */ -void pci_cfg_restore(device_t, struct pci_devinfo *); +void pci_cfg_restore(device_t, struct pci_devinfo *); /** Save the config register state. Optionally set the power state to D3 * if the third argument is non-zero. */ -void pci_cfg_save(device_t, struct pci_devinfo *, int); +void pci_cfg_save(device_t, struct pci_devinfo *, int); +#endif /* _PCI_PRIVATE_H_ */ diff --git a/sys/bus/pci/pci_user.c b/sys/bus/pci/pci_user.c new file mode 100644 index 0000000000..9ed71ed460 --- /dev/null +++ b/sys/bus/pci/pci_user.c @@ -0,0 +1,751 @@ +/*- + * Copyright (c) 1997, Stefan Esser + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/pci_user.c,v 1.22.2.4.2.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +#include "opt_bus.h" /* XXX trim includes */ +#include "opt_compat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pcib_if.h" +#include "pci_if.h" + +/* + * This is the user interface to PCI configuration space. + */ + +#if 0 +static d_open_t pci_open; +static d_close_t pci_close; +static int pci_conf_match(struct pci_match_conf *matches, int num_matches, + struct pci_conf *match_buf); +static d_ioctl_t pci_ioctl; +static struct cdevsw pcicdev = { + .d_open = pci_open, + .d_close = pci_close, + .d_ioctl = pci_ioctl, + .d_name = "pci", +}; +#endif + +static int +pci_open(struct dev_open_args *ap) +{ +#if 0 + int error; + if (oflags & FWRITE) { + error = securelevel_gt(td->td_ucred, 0); + if (error) + return (error); + } +#endif + return (0); +} + +static int +pci_close(struct dev_close_args *ap) +{ + return 0; +} + +/* + * Match a single pci_conf structure against an array of pci_match_conf + * structures. The first argument, 'matches', is an array of num_matches + * pci_match_conf structures. match_buf is a pointer to the pci_conf + * structure that will be compared to every entry in the matches array. + * This function returns 1 on failure, 0 on success. + */ +static int +pci_conf_match(struct pci_match_conf *matches, int num_matches, + struct pci_conf *match_buf) +{ + int i; + + if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) + return(1); + + for (i = 0; i < num_matches; i++) { + /* + * I'm not sure why someone would do this...but... + */ + if (matches[i].flags == PCI_GETCONF_NO_MATCH) + continue; + + /* + * Look at each of the match flags. If it's set, do the + * comparison. If the comparison fails, we don't have a + * match, go on to the next item if there is one. + */ + if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) + && (match_buf->pc_sel.pc_domain != + matches[i].pc_sel.pc_domain)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) + && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) + && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) + && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) + && (match_buf->pc_vendor != matches[i].pc_vendor)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) + && (match_buf->pc_device != matches[i].pc_device)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) + && (match_buf->pc_class != matches[i].pc_class)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) + && (match_buf->pd_unit != matches[i].pd_unit)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) + && (strncmp(matches[i].pd_name, match_buf->pd_name, + sizeof(match_buf->pd_name)) != 0)) + continue; + + return(0); + } + + return(1); +} + +#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ + defined(COMPAT_FREEBSD6) || defined(__DragonFly__) +#define PRE7_COMPAT + +typedef enum { + PCI_GETCONF_NO_MATCH_OLD = 0x00, + PCI_GETCONF_MATCH_BUS_OLD = 0x01, + PCI_GETCONF_MATCH_DEV_OLD = 0x02, + PCI_GETCONF_MATCH_FUNC_OLD = 0x04, + PCI_GETCONF_MATCH_NAME_OLD = 0x08, + PCI_GETCONF_MATCH_UNIT_OLD = 0x10, + PCI_GETCONF_MATCH_VENDOR_OLD = 0x20, + PCI_GETCONF_MATCH_DEVICE_OLD = 0x40, + PCI_GETCONF_MATCH_CLASS_OLD = 0x80 +} pci_getconf_flags_old; + +struct pcisel_old { + u_int8_t pc_bus; /* bus number */ + u_int8_t pc_dev; /* device on this bus */ + u_int8_t pc_func; /* function on this device */ +}; + +struct pci_conf_old { + struct pcisel_old pc_sel; /* bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_long pd_unit; /* device unit number */ +}; + +struct pci_match_conf_old { + struct pcisel_old pc_sel; /* bus+slot+function */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_long pd_unit; /* Unit number */ + u_int16_t pc_vendor; /* PCI Vendor ID */ + u_int16_t pc_device; /* PCI Device ID */ + u_int8_t pc_class; /* PCI class */ + pci_getconf_flags_old flags; /* Matching expression */ +}; + +struct pci_io_old { + struct pcisel_old pi_sel; /* device to operate on */ + int pi_reg; /* configuration register to examine */ + int pi_width; /* width (in bytes) of read or write */ + u_int32_t pi_data; /* data to write or result of read */ +}; + +#define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io) +#define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old) +#define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old) + +static int pci_conf_match_old(struct pci_match_conf_old *matches, + int num_matches, struct pci_conf *match_buf); + +static int +pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches, + struct pci_conf *match_buf) +{ + int i; + + if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) + return(1); + + for (i = 0; i < num_matches; i++) { + if (match_buf->pc_sel.pc_domain != 0) + continue; + + /* + * I'm not sure why someone would do this...but... + */ + if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) + continue; + + /* + * Look at each of the match flags. If it's set, do the + * comparison. If the comparison fails, we don't have a + * match, go on to the next item if there is one. + */ + if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) + && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) + && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) + && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) + && (match_buf->pc_vendor != matches[i].pc_vendor)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) + && (match_buf->pc_device != matches[i].pc_device)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) + && (match_buf->pc_class != matches[i].pc_class)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) + && (match_buf->pd_unit != matches[i].pd_unit)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) + && (strncmp(matches[i].pd_name, match_buf->pd_name, + sizeof(match_buf->pd_name)) != 0)) + continue; + + return(0); + } + + return(1); +} + +#endif + +static int +pci_ioctl(struct dev_ioctl_args *ap) +{ + device_t pcidev, brdev; + void *confdata; + const char *name; + struct devlist *devlist_head; + struct pci_conf_io *cio; + struct pci_devinfo *dinfo; + struct pci_io *io; + struct pci_bar_io *bio; + struct pci_match_conf *pattern_buf; + struct resource_list_entry *rle; + uint32_t value; + size_t confsz, iolen, pbufsz; + int error, ionum, i, num_patterns; +#ifdef PRE7_COMPAT + struct pci_conf_old conf_old; + struct pci_io iodata; + struct pci_io_old *io_old; + struct pci_match_conf_old *pattern_buf_old; + + io_old = NULL; + pattern_buf_old = NULL; + + if (!(ap->a_fflag & FWRITE) && ap->a_cmd != PCIOCGETBAR && + ap->a_cmd != PCIOCGETCONF && ap->a_cmd != PCIOCGETCONF_OLD) + return EPERM; +#else + if (!(ap->a_fflag & FWRITE) && ap->a_cmd != PCIOCGETBAR && ap->a_cmd != PCIOCGETCONF) + return EPERM; +#endif + + switch(ap->a_cmd) { +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: + /* FALLTHROUGH */ +#endif + case PCIOCGETCONF: + cio = (struct pci_conf_io *)ap->a_data; + + pattern_buf = NULL; + num_patterns = 0; + dinfo = NULL; + + cio->num_matches = 0; + + /* + * If the user specified an offset into the device list, + * but the list has changed since they last called this + * ioctl, tell them that the list has changed. They will + * have to get the list from the beginning. + */ + if ((cio->offset != 0) + && (cio->generation != pci_generation)){ + cio->status = PCI_GETCONF_LIST_CHANGED; + error = 0; + break; + } + + /* + * Check to see whether the user has asked for an offset + * past the end of our list. + */ + if (cio->offset >= pci_numdevs) { + cio->status = PCI_GETCONF_LAST_DEVICE; + error = 0; + break; + } + + /* get the head of the device queue */ + devlist_head = &pci_devq; + + /* + * Determine how much room we have for pci_conf structures. + * Round the user's buffer size down to the nearest + * multiple of sizeof(struct pci_conf) in case the user + * didn't specify a multiple of that size. + */ +#ifdef PRE7_COMPAT + if (ap->a_cmd == PCIOCGETCONF_OLD) + confsz = sizeof(struct pci_conf_old); + else +#endif + confsz = sizeof(struct pci_conf); + iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), + pci_numdevs * confsz); + + /* + * Since we know that iolen is a multiple of the size of + * the pciconf union, it's okay to do this. + */ + ionum = iolen / confsz; + + /* + * If this test is true, the user wants the pci_conf + * structures returned to match the supplied entries. + */ + if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs) + && (cio->pat_buf_len > 0)) { + /* + * pat_buf_len needs to be: + * num_patterns * sizeof(struct pci_match_conf) + * While it is certainly possible the user just + * allocated a large buffer, but set the number of + * matches correctly, it is far more likely that + * their kernel doesn't match the userland utility + * they're using. It's also possible that the user + * forgot to initialize some variables. Yes, this + * may be overly picky, but I hazard to guess that + * it's far more likely to just catch folks that + * updated their kernel but not their userland. + */ +#ifdef PRE7_COMPAT + if (ap->a_cmd == PCIOCGETCONF_OLD) + pbufsz = sizeof(struct pci_match_conf_old); + else +#endif + pbufsz = sizeof(struct pci_match_conf); + if (cio->num_patterns * pbufsz != cio->pat_buf_len) { + /* The user made a mistake, return an error. */ + cio->status = PCI_GETCONF_ERROR; + error = EINVAL; + break; + } + + /* + * Allocate a buffer to hold the patterns. + */ +#ifdef PRE7_COMPAT + if (ap->a_cmd == PCIOCGETCONF_OLD) { + pattern_buf_old = kmalloc(cio->pat_buf_len, + M_TEMP, M_WAITOK); + error = copyin(cio->patterns, + pattern_buf_old, cio->pat_buf_len); + } else +#endif + { + pattern_buf = kmalloc(cio->pat_buf_len, M_TEMP, + M_WAITOK); + error = copyin(cio->patterns, pattern_buf, + cio->pat_buf_len); + } + if (error != 0) { + error = EINVAL; + goto getconfexit; + } + num_patterns = cio->num_patterns; + } else if ((cio->num_patterns > 0) + || (cio->pat_buf_len > 0)) { + /* + * The user made a mistake, spit out an error. + */ + cio->status = PCI_GETCONF_ERROR; + error = EINVAL; + break; + } + + /* + * Go through the list of devices and copy out the devices + * that match the user's criteria. + */ + for (cio->num_matches = 0, error = 0, i = 0, + dinfo = STAILQ_FIRST(devlist_head); + (dinfo != NULL) && (cio->num_matches < ionum) + && (error == 0) && (i < pci_numdevs) && (dinfo != NULL); + dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { + + if (i < cio->offset) + continue; + + /* Populate pd_name and pd_unit */ + name = NULL; + if (dinfo->cfg.dev) + name = device_get_name(dinfo->cfg.dev); + if (name) { + strncpy(dinfo->conf.pd_name, name, + sizeof(dinfo->conf.pd_name)); + dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; + dinfo->conf.pd_unit = + device_get_unit(dinfo->cfg.dev); + } else { + dinfo->conf.pd_name[0] = '\0'; + dinfo->conf.pd_unit = 0; + } + +#ifdef PRE7_COMPAT + if ((ap->a_cmd == PCIOCGETCONF_OLD && + (pattern_buf_old == NULL || + pci_conf_match_old(pattern_buf_old, num_patterns, + &dinfo->conf) == 0)) || + (ap->a_cmd == PCIOCGETCONF && + (pattern_buf == NULL || + pci_conf_match(pattern_buf, num_patterns, + &dinfo->conf) == 0))) { +#else + if (pattern_buf == NULL || + pci_conf_match(pattern_buf, num_patterns, + &dinfo->conf) == 0) { +#endif + /* + * If we've filled up the user's buffer, + * break out at this point. Since we've + * got a match here, we'll pick right back + * up at the matching entry. We can also + * tell the user that there are more matches + * left. + */ + if (cio->num_matches >= ionum) + break; + +#ifdef PRE7_COMPAT + if (ap->a_cmd == PCIOCGETCONF_OLD) { + conf_old.pc_sel.pc_bus = + dinfo->conf.pc_sel.pc_bus; + conf_old.pc_sel.pc_dev = + dinfo->conf.pc_sel.pc_dev; + conf_old.pc_sel.pc_func = + dinfo->conf.pc_sel.pc_func; + conf_old.pc_hdr = dinfo->conf.pc_hdr; + conf_old.pc_subvendor = + dinfo->conf.pc_subvendor; + conf_old.pc_subdevice = + dinfo->conf.pc_subdevice; + conf_old.pc_vendor = + dinfo->conf.pc_vendor; + conf_old.pc_device = + dinfo->conf.pc_device; + conf_old.pc_class = + dinfo->conf.pc_class; + conf_old.pc_subclass = + dinfo->conf.pc_subclass; + conf_old.pc_progif = + dinfo->conf.pc_progif; + conf_old.pc_revid = + dinfo->conf.pc_revid; + strncpy(conf_old.pd_name, + dinfo->conf.pd_name, + sizeof(conf_old.pd_name)); + conf_old.pd_name[PCI_MAXNAMELEN] = 0; + conf_old.pd_unit = + dinfo->conf.pd_unit; + confdata = &conf_old; + } else +#endif + confdata = &dinfo->conf; + /* Only if we can copy it out do we count it. */ + if (!(error = copyout(confdata, + (caddr_t)cio->matches + + confsz * cio->num_matches, confsz))) + cio->num_matches++; + } + } + + /* + * Set the pointer into the list, so if the user is getting + * n records at a time, where n < pci_numdevs, + */ + cio->offset = i; + + /* + * Set the generation, the user will need this if they make + * another ioctl call with offset != 0. + */ + cio->generation = pci_generation; + + /* + * If this is the last device, inform the user so he won't + * bother asking for more devices. If dinfo isn't NULL, we + * know that there are more matches in the list because of + * the way the traversal is done. + */ + if (dinfo == NULL) + cio->status = PCI_GETCONF_LAST_DEVICE; + else + cio->status = PCI_GETCONF_MORE_DEVS; + +getconfexit: + if (pattern_buf != NULL) + kfree(pattern_buf, M_TEMP); +#ifdef PRE7_COMPAT + if (pattern_buf_old != NULL) + kfree(pattern_buf_old, M_TEMP); +#endif + + break; + +#ifdef PRE7_COMPAT + case PCIOCREAD_OLD: + case PCIOCWRITE_OLD: + io_old = (struct pci_io_old *)ap->a_data; + iodata.pi_sel.pc_domain = 0; + iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus; + iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev; + iodata.pi_sel.pc_func = io_old->pi_sel.pc_func; + iodata.pi_reg = io_old->pi_reg; + iodata.pi_width = io_old->pi_width; + iodata.pi_data = io_old->pi_data; + ap->a_data = (caddr_t)&iodata; + /* FALLTHROUGH */ +#endif + case PCIOCREAD: + case PCIOCWRITE: + io = (struct pci_io *)ap->a_data; + switch(io->pi_width) { + case 4: + case 2: + case 1: + /* Make sure register is in bounds and aligned. */ + if (io->pi_reg < 0 || + io->pi_reg + io->pi_width > PCI_REGMAX + 1 || + io->pi_reg & (io->pi_width - 1)) { + error = EINVAL; + break; + } + /* + * Assume that the user-level bus number is + * in fact the physical PCI bus number. + * Look up the grandparent, i.e. the bridge device, + * so that we can issue configuration space cycles. + */ + pcidev = pci_find_dbsf(io->pi_sel.pc_domain, + io->pi_sel.pc_bus, io->pi_sel.pc_dev, + io->pi_sel.pc_func); + if (pcidev) { + brdev = device_get_parent( + device_get_parent(pcidev)); + +#ifdef PRE7_COMPAT + if (ap->a_cmd == PCIOCWRITE || ap->a_cmd == PCIOCWRITE_OLD) +#else + if (ap->a_cmd == PCIOCWRITE) +#endif + PCIB_WRITE_CONFIG(brdev, + io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func, + io->pi_reg, + io->pi_data, + io->pi_width); +#ifdef PRE7_COMPAT + else if (ap->a_cmd == PCIOCREAD_OLD) + io_old->pi_data = + PCIB_READ_CONFIG(brdev, + io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func, + io->pi_reg, + io->pi_width); +#endif + else + io->pi_data = + PCIB_READ_CONFIG(brdev, + io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func, + io->pi_reg, + io->pi_width); + error = 0; + } else { +#ifdef COMPAT_FREEBSD4 + if (cmd == PCIOCREAD_OLD) { + io_old->pi_data = -1; + error = 0; + } else +#endif + error = ENODEV; + } + break; + default: + error = EINVAL; + break; + } + break; + + case PCIOCGETBAR: + bio = (struct pci_bar_io *)ap->a_data; + + /* + * Assume that the user-level bus number is + * in fact the physical PCI bus number. + */ + pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain, + bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev, + bio->pbi_sel.pc_func); + if (pcidev == NULL) { + error = ENODEV; + break; + } + dinfo = device_get_ivars(pcidev); + + /* + * Look for a resource list entry matching the requested BAR. + * + * XXX: This will not find BARs that are not initialized, but + * maybe that is ok? + */ + rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, + bio->pbi_reg); + if (rle == NULL) + rle = resource_list_find(&dinfo->resources, + SYS_RES_IOPORT, bio->pbi_reg); + if (rle == NULL || rle->res == NULL) { + error = EINVAL; + break; + } + + /* + * Ok, we have a resource for this BAR. Read the lower + * 32 bits to get any flags. + */ + value = pci_read_config(pcidev, bio->pbi_reg, 4); + if (PCI_BAR_MEM(value)) { + if (rle->type != SYS_RES_MEMORY) { + error = EINVAL; + break; + } + value &= ~PCIM_BAR_MEM_BASE; + } else { + if (rle->type != SYS_RES_IOPORT) { + error = EINVAL; + break; + } + value &= ~PCIM_BAR_IO_BASE; + } + bio->pbi_base = rman_get_start(rle->res) | value; + bio->pbi_length = rman_get_size(rle->res); + + /* + * Check the command register to determine if this BAR + * is enabled. + */ + value = pci_read_config(pcidev, PCIR_COMMAND, 2); + if (rle->type == SYS_RES_MEMORY) + bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0; + else + bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0; + error = 0; + break; + default: + error = ENOTTY; + break; + } + + return (error); +} + + +#define PCI_CDEV 78 +struct dev_ops pcic_ops = { + { "pci", PCI_CDEV, 0 }, + .d_open = pci_open, + .d_close = pci_close, + .d_ioctl = pci_ioctl, +}; diff --git a/sys/bus/pci/pcib_if.m b/sys/bus/pci/pcib_if.m index 42166ad839..6cb4235fba 100644 --- a/sys/bus/pci/pcib_if.m +++ b/sys/bus/pci/pcib_if.m @@ -1,4 +1,4 @@ -# +#- # Copyright (c) 2000 Doug Rabson # All rights reserved. # @@ -23,14 +23,22 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $FreeBSD: src/sys/pci/pcib_if.m,v 1.2 2000/10/16 19:43:44 imp Exp $ -# $DragonFly: src/sys/bus/pci/pcib_if.m,v 1.1 2004/01/15 18:22:22 joerg Exp $ +# $FreeBSD: src/sys/dev/pci/pcib_if.m,v 1.11.8.1 2009/04/15 03:14:26 kensmith Exp $ # #include +#include INTERFACE pcib; +CODE { + static int + null_route_interrupt(device_t pcib, device_t dev, int pin) + { + return (PCI_INVALID_IRQ); + } +}; + # # Return the number of slots on the attached PCI bus. # @@ -47,10 +55,10 @@ METHOD int maxslots { # METHOD u_int32_t read_config { device_t dev; - int bus; - int slot; - int func; - int reg; + u_int bus; + u_int slot; + u_int func; + u_int reg; int width; }; @@ -63,10 +71,10 @@ METHOD u_int32_t read_config { # METHOD void write_config { device_t dev; - int bus; - int slot; - int func; - int reg; + u_int bus; + u_int slot; + u_int func; + u_int reg; u_int32_t value; int width; }; @@ -76,7 +84,63 @@ METHOD void write_config { # a device's interrupt register. # METHOD int route_interrupt { - device_t bus; - device_t device; - int pin; + device_t pcib; + device_t dev; + int pin; +} DEFAULT null_route_interrupt; + +# +# Allocate 'count' MSI messsages mapped onto 'count' IRQs. 'irq' points +# to an array of at least 'count' ints. The max number of messages this +# device supports is included so that the MD code can take that into +# account when assigning resources so that the proper number of low bits +# are clear in the resulting message data value. +# +METHOD int alloc_msi { + device_t pcib; + device_t dev; + int count; + int maxcount; + int *irqs; +}; + +# +# Release 'count' MSI messages mapped onto 'count' IRQs stored in the +# array pointed to by 'irqs'. +# +METHOD int release_msi { + device_t pcib; + device_t dev; + int count; + int *irqs; +}; + +# +# Allocate a single MSI-X message mapped onto '*irq'. +# +METHOD int alloc_msix { + device_t pcib; + device_t dev; + int *irq; +}; + +# +# Release a single MSI-X message mapped onto 'irq'. +# +METHOD int release_msix { + device_t pcib; + device_t dev; + int irq; +}; + +# +# Determine the MSI/MSI-X message address and data for 'irq'. The address +# is returned in '*addr', and the data in '*data'. +# +METHOD int map_msi { + device_t pcib; + device_t dev; + int irq; + uint64_t *addr; + uint32_t *data; }; diff --git a/sys/bus/pci/pcib_private.h b/sys/bus/pci/pcib_private.h index bde054b29e..4ff6edc9e5 100644 --- a/sys/bus/pci/pcib_private.h +++ b/sys/bus/pci/pcib_private.h @@ -27,8 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/pci/pcib_private.h,v 1.6 2004/01/11 06:52:31 imp Exp $ - * $DragonFly: src/sys/bus/pci/pcib_private.h,v 1.3 2006/09/30 20:03:44 swildner Exp $ + * $FreeBSD: src/sys/dev/pci/pcib_private.h,v 1.13.8.1 2009/04/15 03:14:26 kensmith Exp $ */ #ifndef __PCIB_PRIVATE_H__ @@ -46,8 +45,10 @@ struct pcib_softc { device_t dev; uint32_t flags; /* flags */ -#define PCIB_SUBTRACTIVE 0x1 +#define PCIB_SUBTRACTIVE 0x1 +#define PCIB_DISABLE_MSI 0x2 uint16_t command; /* command register */ + uint32_t domain; /* domain number */ uint8_t secbus; /* secondary bus number */ uint8_t subbus; /* subordinate bus number */ pci_addr_t pmembase; /* base address of prefetchable memory */ @@ -75,7 +76,10 @@ int pcib_maxslots(device_t dev); uint32_t pcib_read_config(device_t dev, int b, int s, int f, int reg, int width); void pcib_write_config(device_t dev, int b, int s, int f, int reg, uint32_t val, int width); int pcib_route_interrupt(device_t pcib, device_t dev, int pin); - -const char * pci_bridge_type(device_t dev); +int pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs); +int pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs); +int pcib_alloc_msix(device_t pcib, device_t dev, int *irq); +int pcib_release_msix(device_t pcib, device_t dev, int irq); +int pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data); #endif diff --git a/sys/bus/pci/pcibus.h b/sys/bus/pci/pcibus.h index 0033b7db1c..e857ace721 100644 --- a/sys/bus/pci/pcibus.h +++ b/sys/bus/pci/pcibus.h @@ -1,13 +1,13 @@ /* * Copyright (c) 2008 The DragonFly Project. All rights reserved. - * + * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright @@ -17,7 +17,7 @@ * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS @@ -30,7 +30,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * * $DragonFly: src/sys/bus/pci/pcibus.h,v 1.1 2008/08/02 01:14:40 dillon Exp $ */ @@ -46,4 +46,3 @@ #endif #endif - diff --git a/sys/bus/pci/pcidevs b/sys/bus/pci/pcidevs deleted file mode 100644 index dd6678c17a..0000000000 --- a/sys/bus/pci/pcidevs +++ /dev/null @@ -1,3111 +0,0 @@ -$DragonFly: src/sys/bus/pci/pcidevs,v 1.35 2008/09/13 02:21:56 sephe Exp $ -/* $NetBSD: pcidevs,v 1.606 2004/01/06 19:44:17 matt Exp $ */ - -/* - * Copyright (c) 1995, 1996 Christopher G. Demetriou - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christopher G. Demetriou - * for the NetBSD Project. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * NOTE: a fairly complete list of PCI codes can be found at: - * - * http://www.yourvote.com/pci/ - * - * (but it doesn't always seem to match vendor documentation) - */ - -/* - * List of known PCI vendors - */ - -vendor PEAK 0x001c Peak System Technik -vendor MARTINMARIETTA 0x003d Martin-Marietta Corporation -vendor HAUPPAUGE 0x0070 Hauppauge Computer Works -vendor TTTECH 0x0357 TTTech -vendor DYNALINK 0x0675 Dynalink -vendor COMPAQ 0x0e11 Compaq -vendor SYMBIOS 0x1000 Symbios Logic -vendor ATI 0x1002 ATI Technologies -vendor ULSI 0x1003 ULSI Systems -vendor VLSI 0x1004 VLSI Technology -vendor AVANCE 0x1005 Avance Logic -vendor REPLY 0x1006 Reply Group -vendor NETFRAME 0x1007 NetFrame Systems -vendor EPSON 0x1008 Epson -vendor PHOENIX 0x100a Phoenix Technologies -vendor NS 0x100b National Semiconductor -vendor TSENG 0x100c Tseng Labs -vendor AST 0x100d AST Research -vendor WEITEK 0x100e Weitek -vendor VIDEOLOGIC 0x1010 Video Logic -vendor DEC 0x1011 Digital Equipment -vendor MICRONICS 0x1012 Micronics Computers -vendor CIRRUS 0x1013 Cirrus Logic -vendor IBM 0x1014 IBM -vendor LSIL 0x1015 LSI Logic Corp of Canada -vendor ICLPERSONAL 0x1016 ICL Personal Systems -vendor SPEA 0x1017 SPEA Software -vendor UNISYS 0x1018 Unisys Systems -vendor ELITEGROUP 0x1019 Elitegroup Computer Systems -vendor NCR 0x101a AT&T Global Information Systems -vendor VITESSE 0x101b Vitesse Semiconductor -vendor WD 0x101c Western Digital -vendor AMI 0x101e American Megatrends -vendor PICTURETEL 0x101f PictureTel -vendor HITACHICOMP 0x1020 Hitachi Computer Products -vendor OKI 0x1021 OKI Electric Industry -vendor AMD 0x1022 Advanced Micro Devices -vendor TRIDENT 0x1023 Trident Microsystems -vendor ZENITH 0x1024 Zenith Data Systems -vendor ACER 0x1025 Acer -vendor DELL 0x1028 Dell Computer -vendor SNI 0x1029 Siemens Nixdorf AG -vendor LSILOGIC 0x102a LSI Logic, Headland div. -vendor MATROX 0x102b Matrox -vendor CHIPS 0x102c Chips and Technologies -vendor WYSE 0x102d WYSE Technology -vendor OLIVETTI 0x102e Olivetti Advanced Technology -vendor TOSHIBA 0x102f Toshiba America -vendor TMCRESEARCH 0x1030 TMC Research -vendor MIRO 0x1031 Miro Computer Products -vendor COMPAQ2 0x1032 Compaq (2nd PCI Vendor ID) -vendor NEC 0x1033 NEC -vendor BURNDY 0x1034 Burndy -vendor COMPCOMM 0x1035 Comp. & Comm. Research Lab -vendor FUTUREDOMAIN 0x1036 Future Domain -vendor HITACHIMICRO 0x1037 Hitach Microsystems -vendor AMP 0x1038 AMP -vendor SIS 0x1039 Silicon Integrated System -vendor SEIKOEPSON 0x103a Seiko Epson -vendor TATUNGAMERICA 0x103b Tatung Co. of America -vendor HP 0x103c Hewlett-Packard -vendor SOLLIDAY 0x103e Solliday Engineering -vendor LOGICMODELLING 0x103f Logic Modeling -vendor KPC 0x1040 Kubota Pacific -vendor COMPUTREND 0x1041 Computrend -vendor PCTECH 0x1042 PC Technology -vendor ASUSTEK 0x1043 Asustek Computer -vendor DPT 0x1044 Distributed Processing Technology -vendor OPTI 0x1045 Opti -vendor IPCCORP 0x1046 IPC Corporation -vendor GENOA 0x1047 Genoa Systems -vendor ELSA 0x1048 Elsa -vendor FOUNTAINTECH 0x1049 Fountain Technology -vendor SGSTHOMSON 0x104a SGS-Thomson Microelectronics -vendor BUSLOGIC 0x104b BusLogic -vendor TI 0x104c Texas Instruments -vendor SONY 0x104d Sony -vendor OAKTECH 0x104e Oak Technology -vendor COTIME 0x104f Co-time Computer -vendor WINBOND 0x1050 Winbond Electronics -vendor ANIGMA 0x1051 Anigma -vendor YOUNGMICRO 0x1052 Young Micro Systems -vendor HITACHI 0x1054 Hitachi -vendor EFARMICRO 0x1055 Efar Microsystems -vendor ICL 0x1056 ICL -vendor MOT 0x1057 Motorola -vendor ETR 0x1058 Electronics & Telec. RSH -vendor TEKNOR 0x1059 Teknor Microsystems -vendor PROMISE 0x105a Promise Technology -vendor FOXCONN 0x105b Foxconn International -vendor WIPRO 0x105c Wipro Infotech -vendor NUMBER9 0x105d Number 9 Computer Company -vendor VTECH 0x105e Vtech Computers -vendor INFOTRONIC 0x105f Infotronic America -vendor UMC 0x1060 United Microelectronics -vendor ITT 0x1061 I. T. T. -vendor MASPAR 0x1062 MasPar Computer -vendor OCEANOA 0x1063 Ocean Office Automation -vendor ALCATEL 0x1064 Alcatel CIT -vendor TEXASMICRO 0x1065 Texas Microsystems -vendor PICOPOWER 0x1066 Picopower Technology -vendor MITSUBISHI 0x1067 Mitsubishi Electronics -vendor DIVERSIFIED 0x1068 Diversified Technology -vendor MYLEX 0x1069 Mylex -vendor ATEN 0x106a Aten Research -vendor APPLE 0x106b Apple Computer -vendor HYUNDAI 0x106c Hyundai Electronics America -vendor SEQUENT 0x106d Sequent -vendor DFI 0x106e DFI -vendor CITYGATE 0x106f City Gate Development -vendor DAEWOO 0x1070 Daewoo Telecom -vendor MITAC 0x1071 Mitac -vendor GIT 0x1072 GIT Co. -vendor YAMAHA 0x1073 Yamaha -vendor NEXGEN 0x1074 NexGen Microsystems -vendor AIR 0x1075 Advanced Integration Research -vendor CHAINTECH 0x1076 Chaintech Computer -vendor QLOGIC 0x1077 Q Logic -vendor CYRIX 0x1078 Cyrix Corporation -vendor IBUS 0x1079 I-Bus -vendor NETWORTH 0x107a NetWorth -vendor GATEWAY 0x107b Gateway 2000 -vendor GOLDSTART 0x107c Goldstar -vendor LEADTEK 0x107d LeadTek Research -vendor INTERPHASE 0x107e Interphase -vendor DATATECH 0x107f Data Technology Corporation -vendor CONTAQ 0x1080 Contaq Microsystems -vendor SUPERMAC 0x1081 Supermac Technology -vendor EFA 0x1082 EFA Corporation of America -vendor FOREX 0x1083 Forex Computer -vendor PARADOR 0x1084 Parador -vendor TULIP 0x1085 Tulip Computers -vendor JBOND 0x1086 J. Bond Computer Systems -vendor CACHECOMP 0x1087 Cache Computer -vendor MICROCOMP 0x1088 Microcomputer Systems -vendor DG 0x1089 Data General Corporation -vendor BIT3 0x108a Bit3 Computer Corp. -vendor ELONEX 0x108c Elonex PLC c/o Oakleigh Systems -vendor OLICOM 0x108d Olicom -vendor SUN 0x108e Sun Microsystems, Inc. -vendor SYSTEMSOFT 0x108f Systemsoft -vendor ENCORE 0x1090 Encore Computer -vendor INTERGRAPH 0x1091 Intergraph -vendor DIAMOND 0x1092 Diamond Computer Systems -vendor NATIONALINST 0x1093 National Instruments -vendor FICOMP 0x1094 First Int'l Computers -vendor SII 0x1095 Silicon Image -vendor CMDTECH 0x1095 CMD Technology -vendor ALACRON 0x1096 Alacron -vendor APPIAN 0x1097 Appian Technology -vendor QUANTUMDESIGNS 0x1098 Quantum Designs -vendor SAMSUNGELEC 0x1099 Samsung Electronics -vendor PACKARDBELL 0x109a Packard Bell -vendor GEMLIGHT 0x109b Gemlight Computer -vendor MEGACHIPS 0x109c Megachips -vendor ZIDA 0x109d Zida Technologies -vendor BROOKTREE 0x109e Brooktree -vendor TRIGEM 0x109f Trigem Computer -vendor MEIDENSHA 0x10a0 Meidensha -vendor JUKO 0x10a1 Juko Electronics -vendor QUANTUM 0x10a2 Quantum -vendor EVEREX 0x10a3 Everex Systems -vendor GLOBE 0x10a4 Globe Manufacturing Sales -vendor RACAL 0x10a5 Racal Interlan -vendor INFORMTECH 0x10a6 Informtech Industrial -vendor BENCHMARQ 0x10a7 Benchmarq Microelectronics -vendor SIERRA 0x10a8 Sierra Semiconductor -vendor SGI 0x10a9 Silicon Graphics -vendor ACC 0x10aa ACC Microelectronics -vendor DIGICOM 0x10ab Digicom -vendor HONEYWELL 0x10ac Honeywell IASD -vendor SYMPHONY 0x10ad Symphony Labs -vendor CORNERSTONE 0x10ae Cornerstone Technology -vendor MICROCOMPSON 0x10af Micro Computer Sysytems (M) SON -vendor CARDEXPER 0x10b0 CardExpert Technology -vendor CABLETRON 0x10b1 Cabletron Systems -vendor RAYETHON 0x10b2 Raytheon -vendor DATABOOK 0x10b3 Databook -vendor STB 0x10b4 STB Systems -vendor PLX 0x10b5 PLX Technology -vendor MADGE 0x10b6 Madge Networks -vendor 3COM 0x10b7 3Com -vendor SMC 0x10b8 Standard Microsystems -vendor ALI 0x10b9 Acer Labs -vendor MITSUBISHIELEC 0x10ba Mitsubishi Electronics -vendor DAPHA 0x10bb Dapha Electronics -vendor ALR 0x10bc Advanced Logic Research -vendor SURECOM 0x10bd Surecom Technology -vendor TSENGLABS 0x10be Tseng Labs International -vendor MOST 0x10bf Most -vendor BOCA 0x10c0 Boca Research -vendor ICM 0x10c1 ICM -vendor AUSPEX 0x10c2 Auspex Systems -vendor SAMSUNGSEMI 0x10c3 Samsung Semiconductors -vendor AWARD 0x10c4 Award Software Int'l -vendor XEROX 0x10c5 Xerox -vendor RAMBUS 0x10c6 Rambus -vendor MEDIAVIS 0x10c7 Media Vision -vendor NEOMAGIC 0x10c8 Neomagic -vendor DATAEXPERT 0x10c9 Dataexpert -vendor FUJITSU 0x10ca Fujitsu -vendor OMRON 0x10cb Omron -vendor MENTOR 0x10cc Mentor ARC -vendor ADVSYS 0x10cd Advanced System Products -vendor RADIUS 0x10ce Radius -vendor CITICORP 0x10cf Citicorp TTI -vendor FUJITSU2 0x10d0 Fujitsu Limited (2nd PCI Vendor ID) -vendor FUTUREPLUS 0x10d1 Future+ Systems -vendor MOLEX 0x10d2 Molex -vendor JABIL 0x10d3 Jabil Circuit -vendor HAULON 0x10d4 Hualon Microelectronics -vendor AUTOLOGIC 0x10d5 Autologic -vendor CETIA 0x10d6 Cetia -vendor BCM 0x10d7 BCM Advanced -vendor APL 0x10d8 Advanced Peripherals Labs -vendor MACRONIX 0x10d9 Macronix -vendor THOMASCONRAD 0x10da Thomas-Conrad -vendor ROHM 0x10db Rohm Research -vendor CERN 0x10dc CERN/ECP/EDU -vendor ES 0x10dd Evans & Sutherland -vendor NVIDIA 0x10de Nvidia Corporation -vendor EMULEX 0x10df Emulex -vendor IMS 0x10e0 Integrated Micro Solutions -vendor TEKRAM 0x10e1 Tekram Technology (1st PCI Vendor ID) -vendor APTIX 0x10e2 Aptix Corporation -vendor NEWBRIDGE 0x10e3 Newbridge Microsystems / Tundra Semiconductor -vendor TANDEM 0x10e4 Tandem Computers -vendor MICROINDUSTRIES 0x10e5 Micro Industries -vendor GAINBERY 0x10e6 Gainbery Computer Products -vendor VADEM 0x10e7 Vadem -vendor AMCIRCUITS 0x10e8 Applied Micro Circuits -vendor ALPSELECTIC 0x10e9 Alps Electric -vendor INTEGRAPHICS 0x10ea Integraphics Systems -vendor ARTISTSGRAPHICS 0x10eb Artists Graphics -vendor REALTEK 0x10ec Realtek Semiconductor -vendor ASCIICORP 0x10ed ASCII Corporation -vendor XILINX 0x10ee Xilinx -vendor RACORE 0x10ef Racore Computer Products -vendor PERITEK 0x10f0 Peritek -vendor TYAN 0x10f1 Tyan Computer -vendor ACHME 0x10f2 Achme Computer -vendor ALARIS 0x10f3 Alaris -vendor SMOS 0x10f4 S-MOS Systems -vendor NKK 0x10f5 NKK Corporation -vendor CREATIVE 0x10f6 Creative Electronic Systems -vendor MATSUSHITA 0x10f7 Matsushita -vendor ALTOS 0x10f8 Altos India -vendor PCDIRECT 0x10f9 PC Direct -vendor TRUEVISIO 0x10fa Truevision -vendor THESYS 0x10fb Thesys Ges. F. Mikroelektronik -vendor IODATA 0x10fc I-O Data Device -vendor SOYO 0x10fd Soyo Technology -vendor FAST 0x10fe Fast Electronic -vendor NCUBE 0x10ff NCube -vendor JAZZ 0x1100 Jazz Multimedia -vendor INITIO 0x1101 Initio -vendor CREATIVELABS 0x1102 Creative Labs -vendor TRIONES 0x1103 Triones Technologies -vendor RASTEROPS 0x1104 RasterOps -vendor SIGMA 0x1105 Sigma Designs -vendor VIATECH 0x1106 VIA Technologies -vendor STRATIS 0x1107 Stratus Computer -vendor PROTEON 0x1108 Proteon -vendor COGENT 0x1109 Cogent Data Technologies -vendor SIEMENS 0x110a Siemens AG / Siemens Nixdorf AG -vendor XENON 0x110b Xenon Microsystems -vendor MINIMAX 0x110c Mini-Max Technology -vendor ZNYX 0x110d Znyx Advanced Systems -vendor CPUTECH 0x110e CPU Technology -vendor ROSS 0x110f Ross Technology -vendor POWERHOUSE 0x1110 Powerhouse Systems -vendor SCO 0x1111 Santa Cruz Operation -vendor RNS 0x1112 RNS -vendor ACCTON 0x1113 Accton Technology -vendor ATMEL 0x1114 Atmel -vendor DUPONT 0x1115 DuPont Pixel Systems -vendor DATATRANSLATION 0x1116 Data Translation -vendor DATACUBE 0x1117 Datacube -vendor BERG 0x1118 Berg Electronics -vendor VORTEX 0x1119 Vortex Computer Systems -vendor EFFICIENTNETS 0x111a Efficent Networks -vendor TELEDYNE 0x111b Teledyne Electronic Systems -vendor TRICORD 0x111c Tricord Systems -vendor IDT 0x111d IDT -vendor ELDEC 0x111e Eldec -vendor PDI 0x111f Prescision Digital Images -vendor EMC 0x1120 Emc -vendor ZILOG 0x1121 Zilog -vendor MULTITECH 0x1122 Multi-tech Systems -vendor LEUTRON 0x1124 Leutron Vision -vendor EUROCORE 0x1125 Eurocore/Vigra -vendor VIGRA 0x1126 Vigra -vendor FORE 0x1127 FORE Systems -vendor FIRMWORKS 0x1129 Firmworks -vendor HERMES 0x112a Hermes Electronics -vendor LINOTYPE 0x112b Linotype -vendor RAVICAD 0x112d Ravicad -vendor INFOMEDIA 0x112e Infomedia Microelectronics -vendor IMAGINGTECH 0x112f Imaging Technlogy -vendor COMPUTERVISION 0x1130 Computervision -vendor PHILIPS 0x1131 Philips -vendor MITEL 0x1132 Mitel -vendor EICON 0x1133 Eicon Technology -vendor MCS 0x1134 Mercury Computer Systems -vendor FUJIXEROX 0x1135 Fuji Xerox -vendor MOMENTUM 0x1136 Momentum Data Systems -vendor CISCO 0x1137 Cisco Systems -vendor ZIATECH 0x1138 Ziatech -vendor DYNPIC 0x1139 Dynamic Pictures -vendor FWB 0x113a FWB -vendor CYCLONE 0x113c Cyclone Micro -vendor LEADINGEDGE 0x113d Leading Edge -vendor SANYO 0x113e Sanyo Electric -vendor EQUINOX 0x113f Equinox Systems -vendor INTERVOICE 0x1140 Intervoice -vendor CREST 0x1141 Crest Microsystem -vendor ALLIANCE 0x1142 Alliance Semiconductor -vendor NETPOWER 0x1143 NetPower -vendor CINMILACRON 0x1144 Cincinnati Milacron -vendor WORKBIT 0x1145 Workbit -vendor FORCE 0x1146 Force Computers -vendor INTERFACE 0x1147 Interface -vendor SCHNEIDERKOCH 0x1148 Schneider & Koch -vendor WINSYSTEM 0x1149 Win System -vendor VMIC 0x114a VMIC -vendor CANOPUS 0x114b Canopus -vendor ANNABOOKS 0x114c Annabooks -vendor IC 0x114d IC Corporation -vendor NIKON 0x114e Nikon Systems -vendor DIGI 0x114f Digi International -vendor TMC 0x1150 Thinking Machines -vendor JAE 0x1151 JAE Electronics -vendor MEGATEK 0x1152 Megatek -vendor LANDWIN 0x1153 Land Win Electronic -vendor MELCO 0x1154 Melco -vendor PINETECH 0x1155 Pine Technology -vendor PERISCOPE 0x1156 Periscope Engineering -vendor AVSYS 0x1157 Avsys -vendor VOARX 0x1158 Voarx R & D -vendor MUTECH 0x1159 Mutech -vendor HARLEQUIN 0x115a Harlequin -vendor PARALLAX 0x115b Parallax Graphics -vendor XIRCOM 0x115d Xircom -vendor PEERPROTO 0x115e Peer Protocols -vendor MAXTOR 0x115f Maxtor -vendor MEGASOFT 0x1160 Megasoft -vendor PFU 0x1161 PFU Limited -vendor OALAB 0x1162 OA Laboratory -vendor RENDITION 0x1163 Rendition, Inc. -vendor APT 0x1164 Advanced Peripherals Technologies -vendor IMAGRAPH 0x1165 Imagraph -vendor SERVERWORKS 0x1166 ServerWorks -vendor MUTOH 0x1167 Mutoh Industries -vendor THINE 0x1168 Thine Electronics -vendor CDAC 0x1169 Centre for Dev. of Advanced Computing -vendor POLARIS 0x116a Polaris Communications -vendor CONNECTWARE 0x116b Connectware -vendor WSTECH 0x116f Workstation Technology -vendor INVENTEC 0x1170 Inventec -vendor LOUGHSOUND 0x1171 Loughborough Sound Images -vendor ALTERA 0x1172 Altera Corperation -vendor ADOBE 0x1173 Adobe Systems -vendor BRIDGEPORT 0x1174 Bridgeport Machines -vendor MIRTRON 0x1175 Mitron Computer -vendor SBE 0x1176 SBE -vendor SILICONENG 0x1177 Silicon Engineering -vendor ALFA 0x1178 Alfa -vendor TOSHIBA2 0x1179 Toshiba -vendor ATREND 0x117a A-Trend Technology -vendor ATTO 0x117c Atto Technology -vendor TR 0x117e T/R Systems -vendor RICOH 0x1180 Ricoh -vendor TELEMATICS 0x1181 Telematics International -vendor FUJIKURA 0x1183 Fujikura -vendor FORKS 0x1184 Forks -vendor DATAWORLD 0x1185 Dataworld -vendor DLINK 0x1186 D-Link Systems -vendor ATL 0x1187 Advanced Techonoloy Labratories -vendor SHIMA 0x1188 Shima Seiki Manufacturing -vendor MATSUSHITA2 0x1189 Matsushita Electronics (2nd PCI Vendor ID) -vendor HILEVEL 0x118a HiLevel Technology -vendor COROLLARY 0x118c Corrollary -vendor BITFLOW 0x118d BitFlow -vendor HERMSTEDT 0x118e Hermstedt -vendor ACARD 0x1191 Acard -vendor DENSAN 0x1192 Densan -vendor ZEINET 0x1193 Zeinet -vendor TOUCAN 0x1194 Toucan Technology -vendor RATOC 0x1195 Ratoc Systems -vendor HYTEC 0x1196 Hytec Electronic -vendor GAGE 0x1197 Gage Applied Sciences -vendor LAMBDA 0x1198 Lambda Systems -vendor DCA 0x1199 Digital Communications Associates -vendor MINDSHARE 0x119a Mind Share -vendor OMEGA 0x119b Omega Micro -vendor ITI 0x119c Information Technology Institute -vendor BUG 0x119d Bug Sapporo -vendor FUJITSU3 0x119e Fujitsu (3th PCI Vendor ID) -vendor BULL 0x119f Bull Hn Information Systems -vendor CONVEX 0x11a0 Convex Computer -vendor HAMAMATSU 0x11a1 Hamamatsu Photonics -vendor SIERRA2 0x11a2 Sierra Research & Technology (2nd PCI Vendor ID) -vendor BARCO 0x11a4 Barco -vendor MICROUNITY 0x11a5 MicroUnity Systems Engineering -vendor PUREDATA 0x11a6 Pure Data -vendor POWERCC 0x11a7 Power Computing -vendor INNOSYS 0x11a9 InnoSys -vendor ACTEL 0x11aa Actel -vendor MARVELL 0x11ab Marvell (was Galileo Technology) -vendor CANNON 0x11ac Cannon IS -vendor LITEON 0x11ad Lite-On Communications -vendor SCITEX 0x11ae Scitex Corporation -vendor PROLOG 0x11af Pro-Log Corporation -vendor V3 0x11b0 V3 Semiconductor -vendor APRICOT 0x11b1 Apricot Computer -vendor KODAK 0x11b2 Eastman Kodak -vendor BARR 0x11b3 Barr Systems -vendor LEITECH 0x11b4 Leitch Technology -vendor RADSTONE 0x11b5 Radstone Technology -vendor UNITEDVIDEO 0x11b6 United Video -vendor MOT2 0x11b7 Motorola (2nd PCI Vendor ID) -vendor XPOINT 0x11b8 Xpoint Technologies -vendor PATHLIGHT 0x11b9 Pathlight Technology -vendor VIDEOTRON 0x11ba VideoTron -vendor PYRAMID 0x11bb Pyramid Technologies -vendor NETPERIPH 0x11bc Network Peripherals -vendor PINNACLE 0x11bd Pinnacle Systems -vendor IMI 0x11be International Microcircuts -vendor LUCENT 0x11c1 Lucent Technologies -vendor NEC2 0x11c3 NEC (2nd PCI Vendor ID) -vendor DOCTECH 0x11c4 Document Technologies -vendor SHIVA 0x11c5 Shiva -vendor DCMDATA 0x11c7 DCM Data Systems -vendor DOLPHIN 0x11c8 Dolphin Interconnect Solutions -vendor MRTMAGMA 0x11c9 Mesa Ridge Technologies (MAGMA) -vendor LSISYS 0x11ca LSI Systems -vendor SPECIALIX 0x11cb Specialix Research -vendor MKC 0x11cc Michels & Kleberhoff Computer -vendor HAL 0x11cd HAL Computer Systems -vendor AURAVISION 0x11d1 Auravision -vendor ANALOG 0x11d4 Analog Devices -vendor SEGA 0x11db SEGA Enterprises -vendor ZORAN 0x11de Zoran Corporation -vendor COMPEX 0x11f6 Compex -vendor PMCSIERRA 0x11f8 PMC-Sierra -vendor COMTROL 0x11fe Comtrol -vendor CYCLADES 0x120e Cyclades -vendor ESSENTIAL 0x120f Essential Communications -vendor O2MICRO 0x1217 O2 Micro, Inc. -vendor 3DFX 0x121a 3Dfx Interactive -vendor ARIEL 0x1220 Ariel -vendor HEURICON 0x1223 Heurikon/Computer Products -vendor AZTECH 0x122d Aztech -vendor 3DO 0x1239 The 3D0 Company -vendor CCUBE 0x123f C-Cube Microsystems -vendor AVM 0x1244 AVM -vendor SAMSUNGELEC2 0x1249 Samsung Electronics Co. Ltd. (2nd vendor ID) -vendor STALLION 0x124d Stallion Technologies -vendor LINEARSYS 0x1254 Linear Systems -vendor ASIX 0x125b ASIX Electronics -vendor AURORA 0x125c Aurora Technologies -vendor ESSTECH 0x125d ESS Technology, Inc. -vendor COREGA 0x1259 Corega -vendor INTERSIL 0x1260 Intersil -vendor NORTEL 0x126c Nortel Networks (Northern Telecom) -vendor SILMOTION 0x126f Silicon Motion, Inc. -vendor ENSONIQ 0x1274 Ensoniq -vendor NETAPP 0x1275 Network Appliance -vendor TRANSMETA 0x1279 Transmeta Corp -vendor ROCKWELL 0x127a Rockwell Semiconductor Systems -vendor DAVICOM 0x1282 Davicom Semiconductor -vendor ITE 0x1283 Integrated Technology Express, Inc. -vendor ESSTECH2 0x1285 ESS Technology, Inc. -vendor TRITECH 0x1292 TriTech Microelectronics -vendor KOFAX 0x1296 Kofax Image Products -vendor ALTEON 0x12ae Alteon -vendor RISCOM 0x12aa RISCom -vendor USR 0x12b9 US Robotics (3Com) -vendor USR2 0x16ec US Robotics -vendor PICTUREEL 0x12c5 Picture Elements -vendor NVIDIA_SGS 0x12d2 Nvidia Corporation & SGS-Thomson Microelectronics -vendor RAINBOW 0x12de Rainbow Technologies -vendor AUREAL 0x12eb Aureal Semiconductor -vendor ADMTEK 0x1317 ADMtek -vendor FORTEMEDIA 0x1319 Forte Media -vendor SIIG 0x131f Siig, Inc. -vendor DOMEX 0x134a Domex -vendor CNET 0x1371 CNet -vendor LMC 0x1376 LAN Media Corporation -vendor NETGEAR 0x1385 Netgear -vendor LEVELONE 0x1394 Level One -vendor COLOGNECHIP 0x1397 Cologne Chip Designs -vendor HIFN 0x13a3 Hifn -vendor 3WARE 0x13c1 3ware -vendor NETBOOST 0x13dc NetBoost -vendor SUNDANCETI 0x13f0 Sundance Technology -vendor CMEDIA 0x13f6 C-Media Electronics, Inc. -vendor LAVA 0x1407 Lava Semiconductor Manufacturing, Inc. -vendor ETIMEDIA 0x1409 eTIMedia Technology Co. Ltd. -vendor OXFORDSEMI 0x1415 Oxford Semiconductor Ltd. -vendor TAMARACK 0x143d Tamarack Microelectronics, Inc. -vendor SAMSUNGELEC3 0x144d Samsung Electronics Co. Ltd. (3rd vendor ID) -vendor ASKEY 0x144f Askey Computer Corp. -vendor AVERMEDIA 0x1461 Avermedia Technologies -vendor AIRONET 0x14b9 Aironet Wireless Communications -vendor COMPAL 0x14c0 COMPAL Electronics, Inc. -vendor TITAN 0x14d2 Titan Electronics, Inc. -vendor AVLAB 0x14db Avlab Technology, Inc. -vendor INVERTEX 0x14e1 Invertex -vendor BROADCOM 0x14e4 Broadcom Corporation -vendor PLANEX 0x14ea Planex Communications -vendor CONEXANT 0x14f1 Conexant Systems -vendor DELTA 0x1500 Delta Electronics -vendor MYSON 0x1516 Myson-Century Technology -vendor ENE 0x1524 ENE Technology, Inc. -vendor TERRATEC 0x153b TerraTec Electronic -vendor SOLIDUM 0x1588 Solidum Systems Corp. -vendor GEOCAST 0x15a1 Geocast Network Systems -vendor BLUESTEEL 0x15ab Bluesteel Networks -vendor AGILENT 0x15bc Agilent Technologies -vendor NDC 0x15e8 National Datacomm Corp. -vendor EUMITCOM 0x1638 Eumitcom -vendor NETSEC 0x1660 NetSec -vendor ACTIONTEC 0x1668 Action Tec Electronics, Inc. -vendor SIBYTE 0x166d Broadcom Corp. (SiByte) -vendor ATHEROS 0x168c Atheros Communications, Inc. -vendor GLOBALSUN 0x16ab Global Sun Tech -vendor LINKSYS 0x1737 Linksys -vendor ALTIMA 0x173b Altima -vendor PEPPERCON 0x1743 Peppercon AG -vendor ANTARES 0x1754 Antares Microsystems, Inc. -vendor CAVIUM 0x177d Cavium -vendor FZJZEL 0x1796 FZ Juelich / ZEL -vendor BELKIN 0x1799 Belkin -vendor SANDBURST 0x17ba Sandburst, Inc. -vendor RALINK 0x1814 Ralink Technologies -vendor SILAN 0x1904 Hangzhou Silan Microelectronics -vendor JMICRON 0x197b JMicron Technology Corporation -vendor SYMPHONY2 0x1c1c Symphony Labs (2nd PCI Vendor ID) -vendor TEKRAM2 0x1de1 Tekram Technology (2nd PCI Vendor ID) -vendor HINT 0x3388 HiNT -vendor 3DLABS 0x3d3d 3D Labs -vendor AVANCE2 0x4005 Avance Logic (2nd PCI Vendor ID) -vendor ADDTRON 0x4033 Addtron Technology -vendor ICOMPRESSION 0x4444 Conexant (iCompression) -vendor INDCOMPSRC 0x494f Industrial Computer Source -vendor NETVIN 0x4a14 NetVin -vendor BUSLOGIC2 0x4b10 Buslogic (2nd PCI Vendor ID) -vendor MEDIAQ 0x4d51 MediaQ, Inc. -vendor GUILLEMOT 0x5046 Guillemot -vendor S3 0x5333 S3 -vendor NETPOWER2 0x5700 NetPower (2nd PCI Vendor ID) -vendor C4T 0x6374 c't Magazin -vendor KURUSUGAWA 0x6809 Kurusugawa Electronics, Inc. -vendor PCHDTV 0x7063 pcHDTV -vendor QUANCM 0x8008 Quancm Electronic GmbH -vendor INTEL 0x8086 Intel -vendor TRIGEM2 0x8800 Trigem Computer (2nd PCI Vendor ID) -vendor PROLAN 0x8c4a ProLAN -vendor COMPUTONE 0x8e0e Computone Corperation -vendor KTI 0x8e2e KTI -vendor ADP 0x9004 Adaptec -vendor ADP2 0x9005 Adaptec (2nd PCI Vendor ID) -vendor ATRONICS 0x907f Atronics -vendor NETMOS 0x9710 Netmos -vendor 3COM2 0xa727 3Com -vendor CHRYSALIS 0xcafe Chrysalis-ITS -vendor MIDDLE_DIGITAL 0xdeaf Middle Digital, Inc. -vendor ARC 0xedd8 ARC Logic -vendor INVALID 0xffff INVALID VENDOR ID - -/* - * List of known products. Grouped by vendor. - */ - -/* 3COM Products */ -product 3COM 3C985 0x0001 3c985 Gigabit Ethernet -product 3COM 3C996 0x0003 3c996 10/100/1000 Ethernet -product 3COM 3CRDAG675 0x0013 3CRDAG675 (Atheros AR5212) -product 3COM2 3CRPAG175 0x0013 3CRPAG175 (Atheros AR5212) -product 3COM 3C556MODEM 0x1007 3c556 V.90 MiniPCI Modem -product 3COM 3C940 0x1700 3c940 Gigabit Ethernet -product 3COM 3C450TX 0x4500 3c450-TX 10/100 Ethernet -product 3COM 3C590 0x5900 3c590 Ethernet -product 3COM 3C595TX 0x5950 3c595-TX 10/100 Ethernet -product 3COM 3C595T4 0x5951 3c595-T4 10/100 Ethernet -product 3COM 3C595MII 0x5952 3c595-MII 10/100 Ethernet -product 3COM 3C555 0x5055 3c555 10/100 MiniPCI Ethernet -product 3COM 3C556 0x6055 3c556 10/100 MiniPCI Ethernet -product 3COM 3C556B 0x6056 3c556B 10/100 MiniPCI Ethernet -product 3COM 3CSOHO100TX 0x7646 3cSOHO100-TX 10/100 Ethernet -product 3COM 3CRWE777A 0x7770 3crwe777a AirConnect -product 3COM 3C940B 0x80eb 3c940B Gigabit Ethernet -product 3COM 3C900TPO 0x9000 3c900-TPO Ethernet -product 3COM 3C900COMBO 0x9001 3c900-COMBO Ethernet -product 3COM 3C905TX 0x9050 3c905-TX 10/100 Ethernet -product 3COM 3C905T4 0x9051 3c905-T4 10/100 Ethernet -product 3COM 3C900BTPO 0x9004 3c900B-TPO Ethernet -product 3COM 3C900BCOMBO 0x9005 3c900B-COMBO Ethernet -product 3COM 3C900BTPC 0x9006 3c900B-TPC Ethernet -product 3COM 3C905BTX 0x9055 3c905B-TX 10/100 Ethernet -product 3COM 3C905BT4 0x9056 3c905B-T4 10/100 Ethernet -product 3COM 3C905BCOMBO 0x9058 3c905B-COMBO 10/100 Ethernet -product 3COM 3C905BFX 0x905a 3c905B-FX 100 Ethernet -product 3COM 3C905CTX 0x9200 3c905C-TX 10/100 Ethernet with mngmt -product 3COM 3C905CXTX 0x9201 3c905CX-TX 10/100 Ethernet with mngmt -product 3COM 3C910SOHOB 0x9300 3c910 OfficeConnect 10/100B Ethernet -product 3COM 3C980SRV 0x9800 3c980 Server Adapter 10/100 Ethernet -product 3COM 3C980CTXM 0x9805 3c980C-TXM 10/100 Ethernet -product 3COM 3CR990 0x9900 3c990-TX 10/100 Ethernet with 3XP -product 3COM 3CR990TX95 0x9902 3CR990-TX-95 10/100 Ethernet with 3XP -product 3COM 3CR990TX97 0x9903 3CR990-TX-97 10/100 Ethernet with 3XP -product 3COM 3C990B 0x9904 3c990B 10/100 Ethernet with 3XP -product 3COM 3CR990FX 0x9905 3CR990-FX 100 Ethernet with 3XP -product 3COM 3CR990SVR95 0x9908 3CR990-SVR-95 10/100 Ethernet with 3XP -product 3COM 3CR990SVR97 0x9909 3CR990-SVR-97 10/100 Ethernet with 3XP -product 3COM 3C990BSVR 0x990a 3c990BSVR 10/100 Ethernet with 3XP - -/* 3Dfx Interactive products */ -product 3DFX VOODOO 0x0001 Voodoo -product 3DFX VOODOO2 0x0002 Voodoo2 -product 3DFX BANSHEE 0x0003 Banshee -product 3DFX VOODOO3 0x0005 Voodoo3 -product 3DFX VOODOO5 0x0009 Voodoo 4/5 - -/* 3D Labs products */ -product 3DLABS 300SX 0x0001 GLINT 300SX -product 3DLABS 500TX 0x0002 GLINT 500TX -product 3DLABS DELTA 0x0003 GLINT DELTA -product 3DLABS PERMEDIA 0x0004 GLINT Permedia -product 3DLABS 500MX 0x0006 GLINT 500MX -product 3DLABS PERMEDIA2 0x0007 GLINT Permedia 2 -product 3DLABS GAMMA 0x0008 GLINT GAMMA -product 3DLABS PERMEDIA2V 0x0009 GLINT Permedia 2V -product 3DLABS PERMEDIA3 0x000a GLINT Permedia 3 - -/* 3ware products */ -product 3WARE ESCALADE 0x1000 Escalade IDE RAID -product 3WARE ESCALADE_ASIC 0x1001 Escalade IDE RAID (ASIC) - -/* ACC Products */ -product ACC 2188 0x0000 ACCM 2188 VL-PCI Bridge -product ACC 2051_HB 0x2051 2051 PCI Single Chip Solution (host bridge) -product ACC 2051_ISA 0x5842 2051 PCI Single Chip Solution (ISA bridge) - -/* Acard products */ -product ACARD ATP850U 0x0005 ATP850U/UF UDMA IDE Controller -product ACARD ATP860 0x0006 ATP860 UDMA IDE Controller -product ACARD ATP860A 0x0007 ATP860-A UDMA IDE Controller -product ACARD ATP865 0x0008 ATP865 UDMA IDE Controller -product ACARD ATP865A 0x0009 ATP865-A UDMA IDE Controller -product ACARD AEC6710 0x8002 AEC6710 SCSI -product ACARD AEC6712UW 0x8010 AEC6712UW SCSI -product ACARD AEC6712U 0x8020 AEC6712U SCSI -product ACARD AEC6712S 0x8030 AEC6712S SCSI -product ACARD AEC6710D 0x8040 AEC6710D SCSI -product ACARD AEC6715UW 0x8050 AEC6715UW SCSI - -/* Accton products */ -product ACCTON MPX5030 0x1211 MPX 5030/5038 Ethernet -product ACCTON EN2242 0x1216 EN2242 10/100 Ethernet - -/* Acer products */ -product ACER M1435 0x1435 M1435 VL-PCI Bridge - -/* Acer Labs products */ -product ALI M1445 0x1445 M1445 VL-PCI Bridge -product ALI M1449 0x1449 M1449 PCI-ISA Bridge -product ALI M1451 0x1451 M1451 Host-PCI Bridge -product ALI M1461 0x1461 M1461 Host-PCI Bridge -product ALI M1531 0x1531 M1531 Host-PCI Bridge -product ALI M1541 0x1541 M1541 Host-PCI Bridge -product ALI M1543 0x1533 M1543 PCI-ISA Bridge -product ALI M3309 0x3309 M3309 MPEG Decoder -product ALI M4803 0x5215 M4803 -product ALI M5229 0x5229 M5229 UDMA IDE Controller -product ALI M5237 0x5237 M5237 USB Host Controller -product ALI M5243 0x5243 M5243 PCI-AGP Bridge -product ALI M5451 0x5451 M5451 AC-Link Controller Audio Device -product ALI M5453 0x5453 M5453 AC-Link Controller Modem Device -product ALI M7101 0x7101 M7101 Power Management Controller - -/* Adaptec products */ -product ADP AIC7850 0x5078 AIC-7850 -product ADP AIC7855 0x5578 AIC-7855 -product ADP AIC5900 0x5900 AIC-5900 ATM -product ADP AIC5905 0x5905 AIC-5905 ATM -product ADP AIC6915 0x6915 AIC-6915 10/100 Ethernet -product ADP AIC7860 0x6078 AIC-7860 -product ADP APA1480 0x6075 APA-1480 Ultra -product ADP 2940AU 0x6178 AHA-2940A Ultra -product ADP AIC7870 0x7078 AIC-7870 -product ADP 2940 0x7178 AHA-2940 -product ADP 3940 0x7278 AHA-3940 -product ADP 3985 0x7378 AHA-3985 -product ADP 2944 0x7478 AHA-2944 -product ADP AIC7895 0x7895 AIC-7895 Ultra -product ADP AIC7880 0x8078 AIC-7880 Ultra -product ADP 2940U 0x8178 AHA-2940 Ultra -product ADP 3940U 0x8278 AHA-3940 Ultra -product ADP 389XU 0x8378 AHA-389X Ultra -product ADP 2944U 0x8478 AHA-2944 Ultra -product ADP 2940UP 0x8778 AHA-2940 Ultra Pro - -product ADP2 2940U2 0x0010 AHA-2940U2 U2 -product ADP2 2930U2 0x0011 AHA-2930U2 U2 -product ADP2 AIC7890 0x001f AIC-7890/1 U2 -product ADP2 3950U2B 0x0050 AHA-3950U2B U2 -product ADP2 3950U2D 0x0051 AHA-3950U2D U2 -product ADP2 AIC7896 0x005f AIC-7896/7 U2 -product ADP2 AIC7892A 0x0080 AIC-7892A U160 -product ADP2 AIC7892B 0x0081 AIC-7892B U160 -product ADP2 AIC7892D 0x0083 AIC-7892D U160 -product ADP2 AIC7892P 0x008f AIC-7892P U160 -product ADP2 AIC7899A 0x00c0 AIC-7899A U160 -product ADP2 AIC7899B 0x00c1 AIC-7899B U160 -product ADP2 AIC7899D 0x00c3 AIC-7899D U160 -product ADP2 AIC7899F 0x00c5 AIC-7899F RAID -product ADP2 AIC7899P 0x00cf AIC-7899P U160 -product ADP2 AAC2622 0x0282 AAC-2622 -product ADP2 ASR2200S 0x0285 ASR-2200S -product ADP2 ASR2120S 0x0286 ASR-2120S -product ADP2 AAC364 0x0364 AAC-364 -product ADP2 ASR5400S 0x0365 ASR-5400S -product ADP2 PERC_2QC 0x1364 Dell PERC 2/QC -/* XXX guess */ -product ADP2 PERC_3QC 0x1365 Dell PERC 3/QC - -/* Addtron Products */ -product ADDTRON RHINEII 0x1320 Rhine II 10/100 Ethernet -product ADDTRON 8139 0x1360 8139 Ethernet - -/* ADMtek products */ -product ADMTEK AL981 0x0981 ADMtek AL981 10/100 Ethernet -product ADMTEK AN985 0x0985 ADMtek AN985 10/100 Ethernet -product ADMTEK ADM8211 0x8201 ADMtek ADM8211 11Mbps 802.11b WLAN - -/* Advanced System Products */ -product ADVSYS 1200A 0x1100 -product ADVSYS 1200B 0x1200 -product ADVSYS ULTRA 0x1300 ABP-930/40UA -product ADVSYS WIDE 0x2300 ABP-940UW -product ADVSYS U2W 0x2500 ASB-3940U2W -product ADVSYS U3W 0x2700 ASB-3940U3W - -/* Agilent Technologies Products */ -product AGILENT TACHYON_DX2 0x0100 Tachyon DX2 FC controller - -/* Aironet Wireless Communicasions products */ -product AIRONET PC4xxx 0x0001 Aironet PC4500/PC4800 Wireless LAN Adapter -product AIRONET 350 0x0350 Aironet 350 Wireless LAN Adapter -product AIRONET MPI350 0xa504 Aironet 350 miniPCI Wireless LAN Adapter -product AIRONET PC4500 0x4500 Aironet PC4500 Wireless LAN Adapter -product AIRONET PC4800 0x4800 Aironet PC4800 Wireless LAN Adapter - -/* Alliance products */ -product ALLIANCE AT24 0x6424 AT24 -product ALLIANCE AT25 0x643d AT25 - -/* Alteon products */ -product ALTEON ACENIC 0x0001 ACEnic 1000baseSX Gigabit Ethernet -product ALTEON ACENIC_COPPER 0x0002 ACEnic 1000baseT Gigabit Ethernet -product ALTEON BCM5700 0x0003 ACEnic BCM5700 10/100/1000 Ethernet -product ALTEON BCM5701 0x0004 ACEnic BCM5701 10/100/1000 Ethernet - -/* Altima products */ -product ALTIMA AC1000 0x03e8 AC1000 Gigabit Ethernet -product ALTIMA AC1001 0x03e9 AC1001 Gigabit Ethernet -product ALTIMA AC9100 0x03ea AC9100 Gigabit Ethernet - -/* AMD products */ -product AMD AMD64_HT 0x1100 AMD64 HyperTransport configuration -product AMD AMD64_ADDR 0x1101 AMD64 Address Map configuration -product AMD AMD64_DRAM 0x1102 AMD64 DRAM configuration -product AMD AMD64_MISC 0x1103 AMD64 Miscellaneous configuration -product AMD PCNET_PCI 0x2000 PCnet-PCI Ethernet -product AMD PCNET_HOME 0x2001 PCnet-Home HomePNA Ethernet -product AMD PCSCSI_PCI 0x2020 PCscsi-PCI SCSI -product AMD SC520_SC 0x3000 Elan SC520 System Controller -product AMD SC751_SC 0x7006 AMD751 System Controller -product AMD SC751_PPB 0x7007 AMD751 PCI-to-PCI Bridge -product AMD PBC756_ISA 0x7408 AMD756 PCI-to-ISA Bridge -product AMD PBC756_IDE 0x7409 AMD756 IDE controller -product AMD PBC756_PMC 0x740b AMD756 Power Management Controller -product AMD PBC756_USB 0x740c AMD756 USB Host Controller -product AMD SC762_NB 0x700c AMD762 NorthBridge -product AMD SC762_PPB 0x700d AMD762 AGP Bridge -product AMD SC761_SC 0x700e AMD761 System Controller -product AMD SC761_PPB 0x700f AMD761 PCI-to-PCI Bridge -product AMD PBC766_ISA 0x7410 AMD766 SouthBridge -product AMD PBC766_IDE 0x7411 AMD766 IDE controller -product AMD PBC766_PMC 0x7413 AMD766 Power Management Controller -product AMD PBC766_USB 0x7414 AMD766 USB Host Controller -product AMD PBC768_ISA 0x7440 AMD768 PCI to ISA/LPC Bridge -product AMD PBC768_IDE 0x7441 AMD768 EIDE Controller -product AMD PBC768_PMC 0x7443 AMD768 Power Management Controller -product AMD PBC768_AC 0x7445 AMD768 AC97 Audio -product AMD PBC768_MD 0x7446 AMD768 AC97 Modem -product AMD PBC768_PPB 0x7448 AMD768 PCI to PCI Bridge -product AMD PBC768_USB 0x7449 AMD768 USB Controller -product AMD PCIX8131_PPB 0x7450 PCI-X Tunnel -product AMD PCIX8131_APIC 0x7451 IO Apic -product AMD PBC8111 0x7460 AMD8111 I/O Hub -product AMD PBC8111_USB 0x7464 AMD8111 USB Host Controller -product AMD PBC8111_LPC 0x7468 AMD8111 LPC Controller -product AMD PBC8111_IDE 0x7469 AMD8111 IDE Controller -product AMD PBC8111_SMB 0x746a AMD8111 SMBus Controller -product AMD PBC8111_ACPI 0x746b AMD8111 ACPI Controller -product AMD PBC8111_AC 0x746d AMD8111 AC97 Audio - -/* American Megatrends products */ -product AMI MEGARAID 0x9010 MegaRAID -product AMI MEGARAID2 0x9060 MegaRAID 2 -product AMI MEGARAID3 0x1960 MegaRAID 3 - -/* Analog Devices, Inc. products */ -product ANALOG SAFENET 0x2f44 SafeNet Crypto Accelerator ADSP-2141 - -/* Antares Microsystems, Inc. products */ -product ANTARES TC9021 0x1021 Antares Gigabit Ethernet - -/* Apple products */ -product APPLE BANDIT 0x0001 Bandit Host-PCI Bridge -product APPLE GC 0x0002 Grand Central I/O Controller -product APPLE CONTROL 0x0003 Control -product APPLE PLANB 0x0004 PlanB -product APPLE OHARE 0x0007 OHare I/O Controller -product APPLE BANDIT2 0x0008 Bandit Host-PCI Bridge -product APPLE HEATHROW 0x0010 MAC-IO I/O Controller (Heathrow) -product APPLE PADDINGTON 0x0017 MAC-IO I/O Controller (Paddington) -product APPLE KEYLARGO_USB 0x0019 KeyLargo USB Controller -product APPLE UNINORTH1 0x001e UniNorth Host-PCI Bridge -product APPLE UNINORTH2 0x001f UniNorth Host-PCI Bridge -product APPLE UNINORTH_AGP 0x0020 UniNorth AGP Interface -product APPLE GMAC 0x0021 GMAC Ethernet -product APPLE KEYLARGO 0x0022 MAC-IO I/O Controller (KeyLargo) -product APPLE GMAC2 0x0024 GMAC Ethernet -product APPLE PANGEA_MACIO 0x0025 MAC-IO I/O Controller (Pangea) -product APPLE PANGEA_USB 0x0026 Pangea USB Controller -product APPLE PANGEA_AGP 0x0027 Pangea AGP Interface -product APPLE PANGEA_PCI1 0x0028 Pangea Host-PCI Bridge -product APPLE PANGEA_PCI2 0x0029 Pangea Host-PCI Bridge -product APPLE UNINORTH_AGP2 0x002d UniNorth AGP Interface -product APPLE UNINORTH3 0x002e UniNorth Host-PCI Bridge -product APPLE UNINORTH4 0x002f UniNorth Host-PCI Bridge -product APPLE PANGEA_FW 0x0030 Pangea Firewire -product APPLE UNINORTH_FW 0x0031 UniNorth Firewire -product APPLE GMAC3 0x0032 GMAC Ethernet -product APPLE UNINORTH_ATA 0x0033 UniNorth ATA/100 Controller -product APPLE UNINORTH_AGP3 0x0034 UniNorth AGP Bridge -product APPLE UNINORTH5 0x0035 UniNorth Host-PCI Bridge -product APPLE UNINORTH6 0x0036 UniNorth Host-PCI Bridge -product APPLE KAUAI 0x003b Kauai ATA Controller -product APPLE INTREPID 0x003e MAC-IO I/O Controller (Intrepid) -product APPLE BCM5701 0x1645 BCM5701 - -/* ARC Logic products */ -product ARC 1000PV 0xa091 1000PV -product ARC 2000PV 0xa099 2000PV -product ARC 2000MT 0xa0a1 2000MT - -/* ASIX Electronics products */ -product ASIX AX88140A 0x1400 AX88140A 10/100 Ethernet - -/* Asustek products */ -product ASUSTEK HFCPCI 0x0675 Asustek ISDN - -/* ATI products */ -product ATI RADEON_A3 0x4136 Radeon Mobility A3 -product ATI RADEON_9600XT 0x4152 Radeon 9600XT -product ATI MACH32 0x4158 Mach32 -product ATI RADEON_9600XT_S 0x4172 Radeon 9600XT Secondary -product ATI RADEON_IGP_320M 0x4336 Radeon IGP 320M -product ATI RADEON_M6_U2 0x4337 Radeon Mobility M6 -product ATI MACH64_CT 0x4354 Mach64 CT -product ATI MACH64_CX 0x4358 Mach64 CX -product ATI SB600_SATA 0x4380 SB600 SATA -product ATI RAGE_PRO_AGP 0x4742 3D Rage Pro (AGP) -product ATI RAGE_PRO_AGP1X 0x4744 3D Rage Pro (AGP 1x) -product ATI RAGE_PRO_PCI_B 0x4749 3D Rage Pro Turbo -product ATI RAGE_XC_PCI66 0x474c Rage XC (PCI66) -product ATI RAGE_XL_AGP 0x474d Rage XL (AGP) -product ATI RAGE_XC_AGP 0x474e Rage XC (AGP) -product ATI RAGE_XL_PCI66 0x474f Rage XL (PCI66) -product ATI RAGE_PRO_PCI_P 0x4750 3D Rage Pro -product ATI RAGE_PRO_PCI_L 0x4751 3D Rage Pro (limited 3D) -product ATI RAGE_XL_PCI 0x4752 Rage XL -product ATI RAGE_XC_PCI 0x4753 Rage XC -product ATI RAGE_II 0x4754 3D Rage I/II -product ATI RAGE_IIP 0x4755 3D Rage II+ -product ATI RAGE_IIC_PCI 0x4756 3D Rage IIC -product ATI RAGE_IIC_AGP_B 0x4757 3D Rage IIC (AGP) -product ATI MACH64_GX 0x4758 Mach64 GX -product ATI RAGE_IIC 0x4759 3D Rage IIC -product ATI RAGE_IIC_AGP_P 0x475a 3D Rage IIC (AGP) -product ATI RAGE_LT_PRO_AGP 0x4c42 3D Rage LT Pro (AGP 133MHz) -product ATI RAGE_LT_PRO_AGP66 0x4c44 3D Rage LT Pro (AGP 66MHz) -product ATI RAGE_MOB_M3_PCI 0x4c45 Rage Mobility M3 -product ATI RAGE_MOB_M3_AGP 0x4c46 Rage Mobility M3 (AGP) -product ATI RAGE_LT 0x4c47 3D Rage LT -product ATI RAGE_LT_PRO_PCI 0x4c49 3D Rage LT Pro -product ATI RAGE_MOBILITY 0x4c4d Rage Mobility -product ATI RAGE_L_MOBILITY 0x4c4e Rage L Mobility -product ATI RAGE_LT_PRO 0x4c50 3D Rage LT Pro -product ATI RAGE_LT_PRO2 0x4c51 3D Rage LT Pro -product ATI RAGE_MOB_M1_PCI 0x4c52 Rage Mobility M1 (PCI) -product ATI RAGE_L_MOB_M1_PCI 0x4c53 Rage L Mobility (PCI) -product ATI RADEON_M7_AGP 0x4c57 Radeon Mobility M7 LW (AGP) -product ATI FIREGL_MOB 0x4c58 FireGL Mobility -product ATI RADEON_M6_AGP 0x4c59 Radeon Mobility M6 LY (AGP) -product ATI RADEON_M6_LZ 0x4c5a Radeon Mobility M6 LZ -product ATI RADEON_M9_GL 0x4c64 Radeon Mobility M9 GL -product ATI RADEON_M9 0x4c66 Radeon Mobility M9 -product ATI RADEON_128_AGP4X 0x4d46 Radeon Mobility 128 AGP 4x -product ATI RADEON_128_AGP2X 0x4d4c Radeon Mobility 128 AGP 2x -product ATI RADEON_9700_9500 0x4e44 Radeon 9700/9500 Series -product ATI RADEON_9700_9500_2 0x4e45 Radeon 9700/9500 Series -product ATI RADEON_9600 0x4e46 Radeon 9600TX -product ATI RADEON_9700_9500_S 0x4e64 Radeon 9700/9500 Series Secondary -product ATI RADEON_9700_9500_S2 0x4e65 Radeon 9700/9500 Series Secondary -product ATI RADEON_9600_2 0x4e66 Radeon 9600TX Secondary -product ATI RAGE1PCI 0x5041 Rage 128 Pro PCI -product ATI RAGE1AGP2X 0x5042 Rage 128 Pro AGP 2x -product ATI RAGE1AGP4X 0x5043 Rage 128 Pro AGP 4x -product ATI RAGE1PCIT 0x5044 Rage 128 Pro PCI (TMDS) -product ATI RAGE1AGP2XT 0x5045 Rage 128 Pro AGP 2x (TMDS) -product ATI RAGE1AGP4XT 0x5046 Rage Fury MAXX AGP 4x (TMDS) -product ATI RAGE2PCI 0x5047 Rage 128 Pro PCI -product ATI RAGE2AGP2X 0x5048 Rage 128 Pro AGP 2x -product ATI RAGE2AGP4X 0x5049 Rage 128 Pro AGP 4x -product ATI RAGE2PCIT 0x504a Rage 128 Pro PCI (TMDS) -product ATI RAGE2AGP2XT 0x504b Rage 128 Pro AGP 2x (TMDS) -product ATI RAGE2AGP4XT 0x504c Rage 128 Pro AGP 4x (TMDS) -product ATI RAGE3PCI 0x504d Rage 128 Pro PCI -product ATI RAGE3AGP2X 0x504e Rage 128 Pro AGP 2x -product ATI RAGE3AGP4X 0x504f Rage 128 Pro AGP 4x -product ATI RAGE3PCIT 0x5050 Rage 128 Pro PCI (TMDS) -product ATI RAGE3AGP2XT 0x5051 Rage 128 Pro AGP 2x (TMDS) -product ATI RAGE3AGP4XT 0x5052 Rage 128 Pro AGP 4x (TMDS) -product ATI RAGE4PCI 0x5053 Rage 128 Pro PCI -product ATI RAGE4AGP2X 0x5054 Rage 128 Pro AGP 2x -product ATI RAGE4AGP4X 0x5055 Rage 128 Pro AGP 4x -product ATI RAGE4PCIT 0x5056 Rage 128 Pro PCI (TMDS) -product ATI RAGE4AGP2XT 0x5057 Rage 128 Pro AGP 2x (TMDS) -product ATI RAGE4AGP4XT 0x5058 Rage 128 Pro AGP 4x (TMDS) -product ATI RADEON_7200 0x5144 Radeon 7200 -product ATI RADEON_8500 0x514c Radeon 8500/8500LE -product ATI RADEON_9100 0x514d Radeon 9100 Series -product ATI RADEON_7500 0x5157 Radeon 7500 -product ATI RADEON_7000 0x5159 Radeon 7000/VE -product ATI RADEON_9100_S 0x516d Radeon 9100 Series Secondary -product ATI RAGEGLPCI 0x5245 Rage 128 GL PCI -product ATI RAGEGLAGP 0x5246 Rage 128 GL AGP 2x -product ATI RAGEVRPCI 0x524b Rage 128 VR PCI -product ATI RAGEVRAGP 0x524c Rage 128 VR AGP 2x -product ATI RAGE4XPCI 0x5345 Rage 128 4x PCI -product ATI RAGE4XA2X 0x5346 Rage 128 4x AGP 2x -product ATI RAGE4XA4X 0x5347 Rage 128 4x AGP 4x -product ATI RAGE4X 0x5348 Rage 128 4x -product ATI RAGE24XPCI 0x534b Rage 128 4x PCI -product ATI RAGE24XA2X 0x534c Rage 128 4x AGP 2x -product ATI RAGE24XA4X 0x534d Rage 128 4x AGP 4x -product ATI RAGE24X 0x534e Rage 128 4x -product ATI MACH64_VT 0x5654 Mach64 VT -product ATI MACH64_VTB 0x5655 Mach64 VTB -product ATI MACH64_VT4 0x5656 Mach64 VT4 -product ATI RADEON_9200 0x5961 Radeon 9200 -product ATI RADEON_9200SE 0x5964 Radeon 9200SE - -/* Auravision products */ -product AURAVISION VXP524 0x01f7 VxP524 PCI Video Processor - -/* Aureal Semiconductor */ -product AUREAL AU8820 0x0001 AU8820 Vortex Digital Audio Processor - -/* Applied Micro Circuts products */ -product AMCIRCUITS S5933 0x4750 S5933 PCI Matchmaker -product AMCIRCUITS LANAI 0x8043 Myrinet LANai Interface -product AMCIRCUITS CAMAC 0x812d FZJ/ZEL CAMAC controller -product AMCIRCUITS VICBUS 0x812e FZJ/ZEL VICBUS interface -product AMCIRCUITS PCISYNC 0x812f FZJ/ZEL Synchronisation module -product AMCIRCUITS S5920 0x5920 S5920 PCI Target - -/* Atheros products */ -product ATHEROS AR5210 0x0007 AR5210 -product ATHEROS AR5311 0x0011 AR5211 -product ATHEROS AR5211 0x0012 AR5211 -product ATHEROS AR5212 0x0013 AR5212 -product ATHEROS AR5210_AP 0x0207 AR5210 (Early) -product ATHEROS AR5212_IBM 0x1014 AR5212 (IBM MiniPCI) -product ATHEROS AR5210_DEFAULT 0x1107 AR5210 (no eeprom) -product ATHEROS AR5212_DEFAULT 0x1113 AR5212 (no eeprom) -product ATHEROS AR5211_DEFAULT 0x1112 AR5211 (no eeprom) -product ATHEROS AR5212_FPGA 0xf013 AR5212 (emulation board) -product ATHEROS AR5211_FPGA11B 0xf11b AR5211Ref -product ATHEROS AR5211_LEGACY 0xff12 AR5211Ref - -/* Atronics products */ -product ATRONICS IDE_2015PL 0x2015 IDE-2015PL - -/* Avance Logic products */ -product AVANCE AVL2301 0x2301 AVL2301 -product AVANCE AVG2302 0x2302 AVG2302 -product AVANCE2 ALG2301 0x2301 ALG2301 -product AVANCE2 ALG2302 0x2302 ALG2302 -product AVANCE2 ALS4000 0x4000 ALS4000 Audio - -/* Avlab Technology products */ -product AVLAB LPPCI4S 0x2150 Low Profile PCI 4 Serial - -/* Belkin products */ -product BELKIN F5D6001 0x6001 F5D6001 802.11b - -/* CCUBE products */ -product CCUBE CINEMASTER 0x8888 Cinemaster C 3.0 DVD Decoder - -/* AVM products */ -product AVM FRITZ_CARD 0x0a00 Fritz! Card ISDN Interface -product AVM FRITZ_PCI_V2_ISDN 0x0e00 Fritz!PCI v2.0 ISDN Interface -product AVM B1 0x0700 Basic Rate B1 ISDN Interface -product AVM T1 0x1200 Primary Rate T1 ISDN Interface - -/* Stallion products */ -product STALLION EC8_32 0x0000 EC8/32 -product STALLION EC8_64 0x0002 EC8/64 -product STALLION EASYIO 0x0003 EasyIO - -/* Bit3 products */ -product BIT3 PCIVME617 0x0001 PCI-VME Interface Mod. 617 -product BIT3 PCIVME618 0x0010 PCI-VME Interface Mod. 618 -product BIT3 PCIVME2706 0x0300 PCI-VME Interface Mod. 2706 - -/* Bluesteel Networks */ -product BLUESTEEL 5501 0x0000 5501 -product BLUESTEEL 5601 0x5601 5601 - -/* Broadcom Corporation products */ -product BROADCOM BCM5752 0x1600 BCM5752 10/100/1000 Ethernet -product BROADCOM BCM5752M 0x1601 BCM5752M -product BROADCOM BCM5709 0x1639 BCM5709 -product BROADCOM BCM5700 0x1644 BCM5700 10/100/1000 Ethernet -product BROADCOM BCM5701 0x1645 BCM5701 10/100/1000 Ethernet -product BROADCOM BCM5702 0x1646 BCM5702 10/100/1000 Ethernet -product BROADCOM BCM5703 0x1647 BCM5703 10/100/1000 Ethernet -product BROADCOM BCM5704C 0x1648 BCM5704C Gigabit Ethernet (1000BASE-T) -product BROADCOM BCM5704S_ALT 0x1649 BCM5704S Alt -product BROADCOM BCM5706 0x164a BCM5706 -product BROADCOM BCM5708 0x164c BCM5708 -product BROADCOM BCM5702FE 0x164d BCM5702FE 10/100 Ethernet -product BROADCOM BCM5705 0x1653 BCM5705 10/100/1000 Ethernet -product BROADCOM BCM5705K 0x1654 BCM5705K 10/100/1000 Ethetnet -product BROADCOM BCM5720 0x1658 BCM5720 -product BROADCOM BCM5721 0x1659 BCM5721 10/100/1000 Ethernet -product BROADCOM BCM5722 0x165a BCM5722 -product BROADCOM BCM5705M 0x165d BCM5705M 10/100/1000 Ethernet -product BROADCOM BCM5705M_ALT 0x165e BCM5705M 10/100/1000 Ethernet -product BROADCOM BCM5714 0x1668 BCM5714 1000baseT Ethernet -product BROADCOM BCM5714S 0x1669 BCM5714S -product BROADCOM BCM5780 0x166a BCM5780 -product BROADCOM BCM5780S 0x166b BCM5780S -product BROADCOM BCM5705F 0x166e BCM5705F -product BROADCOM BCM5754M 0x1672 BCM5754M -product BROADCOM BCM5755M 0x1673 BCM5755M -product BROADCOM BCM5756 0x1674 BCM5756 -product BROADCOM BCM5750 0x1676 BCM5750 10/100/1000 Ethernet -product BROADCOM BCM5751 0x1677 BCM5751 10/100/1000 Ethernet -product BROADCOM BCM5715 0x1678 BCM5715 -product BROADCOM BCM5715S 0x1679 BCM5715S -product BROADCOM BCM5754 0x167a BCM5754 -product BROADCOM BCM5755 0x167b BCM5755 -product BROADCOM BCM5750M 0x167c BCM5750M 10/100/1000 Ethernet -product BROADCOM BCM5751M 0x167d BCM5751M 10/100/1000 Ethernet -product BROADCOM BCM5751F 0x167e BCM5751F -product BROADCOM BCM5787F 0x167f BCM5787F -product BROADCOM BCM5787M 0x1693 BCM5787M -product BROADCOM BCM5782 0x1696 BCM5782 10/100/1000 Ethernet -product BROADCOM BCM5786 0x169a BCM5786 -product BROADCOM BCM5787 0x169b BCM5787 -product BROADCOM BCM5788 0x169c BCM5788 10/100/1000 Enternet -product BROADCOM BCM5789 0x169d BCM5789 10/100/1000 Enternet -product BROADCOM BCM5702X 0x16a6 BCM5702X 10/100/1000 Ethernet -product BROADCOM BCM5703X 0x16a7 BCM5703X 10/100/1000 Ethernet -product BROADCOM BCM5704S 0x16a8 BCM5704S Gigabit Ethernet (1000BASE-X) -product BROADCOM BCM5706S 0x16aa BCM5706S -product BROADCOM BCM5708S 0x16ac BCM5708S -product BROADCOM BCM5702_ALT 0x16c6 BCM5702 10/100/1000 Ethernet -product BROADCOM BCM5703A3 0x16c7 BCM5703 10/100/1000 Ethernet -product BROADCOM BCM5781 0x16dd BCM5781 -product BROADCOM BCM5753 0x16f7 BCM5753 -product BROADCOM BCM5753M 0x16fd BCM5753M -product BROADCOM BCM5753F 0x16fe BCM5753F -product BROADCOM BCM5903M 0x16ff BCM5903M -product BROADCOM BCM4401B0 0x170c BCM4401-B0 10/100 Ethernet -product BROADCOM BCM5901 0x170d BCM5901 10/100 Ethernet -product BROADCOM BCM5901A2 0x170e BCM5901A 10/100 Ethernet -product BROADCOM BCM5906 0x1712 BCM5906 -product BROADCOM BCM5906M 0x1713 BCM5906M -product BROADCOM BCM4301 0x4301 BCM4301 802.11b Wireless Lan -product BROADCOM BCM4307 0x4307 BCM4307 802.11b Wireless Lan -product BROADCOM BCM4311 0x4311 BCM4311 802.11a/b/g Wireless Lan -product BROADCOM BCM4312 0x4312 BCM4312 802.11a/b/g Wireless Lan -product BROADCOM BCM4318 0x4318 BCM4318 802.11b/g Wireless Lan -product BROADCOM BCM4319 0x4319 BCM4319 802.11a/b/g Wireless Lan -product BROADCOM BCM4306_1 0x4320 BCM4306 802.11b/g Wireless Lan -product BROADCOM BCM4306_2 0x4321 BCM4306 802.11a Wireless Lan -product BROADCOM BCM4309 0x4324 BCM4309 802.11a/b/g Wireless Lan -product BROADCOM BCM4306_3 0x4325 BCM4306 802.11b/g Wireless Lan -product BROADCOM BCM4401 0x4401 BCM4401 10/100 Ethernet -product BROADCOM BCM4402 0x4402 BCM4402 10/100 Ethernet -product BROADCOM 5801 0x5801 5801 Security processor -product BROADCOM 5802 0x5802 5802 Security processor -product BROADCOM 5805 0x5805 5805 Security processor -product BROADCOM 5820 0x5820 5820 Security processor -product BROADCOM 5821 0x5821 5821 Security processor -product BROADCOM 5822 0x5822 5822 Security processor -product BROADCOM 5823 0x5823 5823 Security processor - -/* Brooktree products */ -product BROOKTREE BT848 0x0350 Bt848 Video Capture -product BROOKTREE BT849 0x0351 Bt849 Video Capture -product BROOKTREE BT878 0x036e Bt878 Video Capture -product BROOKTREE BT879 0x036f Bt879 Video Capture -product BROOKTREE BT880 0x0370 Bt880 Video Capture -product BROOKTREE BT878A 0x0878 Bt878 Video Capture (Audio Section) -product BROOKTREE BT879A 0x0879 Bt879 Video Capture (Audio Section) -product BROOKTREE BT880A 0x0880 Bt880 Video Capture (Audio Section) -product BROOKTREE BT8474 0x8474 Bt8474 Multichannel HDLC Controller - -/* BusLogic products */ -product BUSLOGIC MULTIMASTER_NC 0x0140 MultiMaster NC -product BUSLOGIC MULTIMASTER 0x1040 MultiMaster -product BUSLOGIC FLASHPOINT 0x8130 FlashPoint - -/* c't Magazin products */ -product C4T GPPCI 0x6773 GPPCI - -/* Cavium products */ -product CAVIUM NITROX 0x0001 Nitrox XL - -/* Chips and Technologies products */ -product CHIPS 64310 0x00b8 64310 -product CHIPS 69000 0x00c0 69000 -product CHIPS 65545 0x00d8 65545 -product CHIPS 65548 0x00dc 65548 -product CHIPS 65550 0x00e0 65550 -product CHIPS 65554 0x00e4 65554 -product CHIPS 69030 0x0c30 69030 - -/* Chrysalis products */ -product CHRYSALIS LUNAVPN 0x0001 LunaVPN - -/* Cirrus Logic products */ -product CIRRUS CL_GD7548 0x0038 CL-GD7548 -product CIRRUS CL_GD5430 0x00a0 CL-GD5430 -product CIRRUS CL_GD5434_4 0x00a4 CL-GD5434-4 -product CIRRUS CL_GD5434_8 0x00a8 CL-GD5434-8 -product CIRRUS CL_GD5436 0x00ac CL-GD5436 -product CIRRUS CL_GD5446 0x00b8 CL-GD5446 -product CIRRUS CL_GD5480 0x00bc CL-GD5480 -product CIRRUS CL_PD6729 0x1100 CL-PD6729 -product CIRRUS CL_PD6832 0x1110 CL-PD6832 PCI-CardBus Bridge -product CIRRUS CL_PD6833 0x1113 CL-PD6833 PCI-CardBus Bridge -product CIRRUS CL_GD7542 0x1200 CL-GD7542 -product CIRRUS CL_GD7543 0x1202 CL-GD7543 -product CIRRUS CL_GD7541 0x1204 CL-GD7541 -product CIRRUS CL_CD4400 0x4400 CL-CD4400 Communications Controller -product CIRRUS CS4610 0x6001 CS4610 SoundFusion Audio Accelerator -product CIRRUS CS4280 0x6003 CS4280 CrystalClear Audio Interface -product CIRRUS CS4281 0x6005 CS4281 CrystalClear Audio Interface - -product SII 3132 0x3132 Sii3132 - -/* Adaptec's AAR-1210SA serial ATA RAID controller uses the CMDTECH chip */ -product CMDTECH AAR_1210SA 0x0240 AAR-1210SA serial ATA RAID controller -/* CMD Technology products -- info gleaned from their web site */ -product CMDTECH 640 0x0640 PCI0640 -/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ -product CMDTECH 642 0x0642 PCI0642 -/* datasheets available from www.cmd.com for the followings */ -product CMDTECH 643 0x0643 PCI0643 -product CMDTECH 646 0x0646 PCI0646 -product CMDTECH 647 0x0647 PCI0647 -product CMDTECH 648 0x0648 PCI0648 -product CMDTECH 649 0x0649 PCI0649 - -/* Inclusion of 'A' in the following entry is probably wrong. */ -/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ -product CMDTECH 650A 0x0650 PCI0650A -product CMDTECH 670 0x0670 USB0670 -product CMDTECH 673 0x0673 USB0673 -product CMDTECH 680 0x0680 SiI0680 -product CMDTECH 3112 0x3112 SiI3112 SATALink -product CMDTECH 3114 0x3114 SiI3114 SATALink -product CMDTECH 3124 0x3124 SiI3124 SATALink - -/* C-Media products */ -product CMEDIA CMI8338A 0x0100 CMI8338A PCI Audio Device -product CMEDIA CMI8338B 0x0101 CMI8338B PCI Audio Device -product CMEDIA CMI8738 0x0111 CMI8738/C3DX PCI Audio Device -product CMEDIA CMI8738B 0x0112 CMI8738B PCI Audio Device -product CMEDIA HSP56 0x0211 HSP56 Audiomodem Riser - -/* CNet produts */ -product CNET GIGACARD 0x434e GigaCard - -/* Cogent Data Technologies products */ -product COGENT EM110TX 0x1400 EX110TX PCI Fast Ethernet Adapter - -/* Cologne Chip Designs */ -product COLOGNECHIP HFC 0x2bd0 HFC-S - -/* COMPAL products */ -product COMPAL 38W2 0x0011 COMPAL 38W2 OEM Notebook - -/* Compaq products */ -product COMPAQ PCI_EISA_BRIDGE 0x0001 PCI-EISA Bridge -product COMPAQ PCI_ISA_BRIDGE 0x0002 PCI-ISA Bridge -product COMPAQ TRIFLEX1 0x1000 Triflex Host-PCI Bridge -product COMPAQ TRIFLEX2 0x2000 Triflex Host-PCI Bridge -product COMPAQ QVISION_V0 0x3032 QVision -product COMPAQ QVISION_1280P 0x3033 QVision 1280/p -product COMPAQ QVISION_V2 0x3034 QVision -product COMPAQ TRIFLEX4 0x4000 Triflex Host-PCI Bridge -product COMPAQ CSA5300 0x4070 Smart Array 5300 -product COMPAQ CSA5i 0x4080 Smart Array 5i -product COMPAQ CSA532 0x4082 Smart Array 532 -product COMPAQ USB 0x7020 USB Controller -/* MediaGX Cx55x0 built-in OHCI seems to have this ID */ -product COMPAQ USB_MEDIAGX 0xa0f8 USB Controller -product COMPAQ SMART2P 0xae10 SMART2P RAID -product COMPAQ N100TX 0xae32 Netelligent 10/100 TX -product COMPAQ N10T 0xae34 Netelligent 10 T -product COMPAQ IntNF3P 0xae35 Integrated NetFlex 3/P -product COMPAQ DPNet100TX 0xae40 Dual Port Netelligent 10/100 TX -product COMPAQ IntPL100TX 0xae43 ProLiant Integrated Netelligent 10/100 TX -product COMPAQ DP4000 0xb011 Deskpro 4000 5233MMX -product COMPAQ M700 0xb112 Armada M700 -product COMPAQ NF3P_BNC 0xf150 NetFlex 3/P w/ BNC -product COMPAQ NF3P 0xf130 NetFlex 3/P - -/* Compex products - XXX better descriptions */ -product COMPEX NE2KETHER 0x1401 Ethernet -product COMPEX RL100ATX 0x2011 RL100-ATX 10/100 Ethernet -product COMPEX RL100TX 0x9881 RL100-TX 10/100 Ethernet - -/* Comtrol products */ -product COMTROL ROCKETPORT32EXT 0x0001 RocketPort 32 port external -product COMTROL ROCKETPORT8EXT 0x0002 RocketPort 8 port external -product COMTROL ROCKETPORT16EXT 0x0003 RocketPort 16 port external -product COMTROL ROCKETPORT4QUAD 0x0004 RocketPort 4 port w/ quad cable -product COMTROL ROCKETPORT8OCTA 0x0005 RocketPort 8 port w/ octa cable -product COMTROL ROCKETPORT8RJ 0x0006 RocketPort 8 port w/ RJ11s -product COMTROL ROCKETPORT4RJ 0x0007 RocketPort 4 port w/ RJ11s -product COMTROL ROCKETMODEM6 0x000c RocketModem 6 port -product COMTROL ROCKETMODEM4 0x000d RocketModem 4 port - -/* Conexant Systems products */ -product CONEXANT SOFTK56 0x2443 SoftK56 PCI Software Modem -product CONEXANT 56KFAXMODEM 0x1085 HW 56K Fax Modem - -/* Contaq Microsystems products */ -product CONTAQ 82C599 0x0600 82C599 PCI-VLB Bridge -product CONTAQ 82C693 0xc693 82C693 PCI-ISA Bridge - -/* Corega products */ -product COREGA CB_TXD 0xa117 FEther CB-TXD 10/100 Ethernet -product COREGA 2CB_TXD 0xa11e FEther II CB-TXD 10/100 Ethernet -product COREGA CG_LAPCIGT 0xc017 CG-LAPCIGT 10/100/1000 Ethernet - -/* Corollary Products */ -product COROLLARY CBUSII_PCIB 0x0014 \"C-Bus II\"-PCI Bridge - -/* Creative Labs products */ -product CREATIVELABS SBLIVE 0x0002 SBLive! EMU 10000 -product CREATIVELABS SBJOY 0x7002 PCI Gameport Joystick -product CREATIVELABS EV1938 0x8938 Ectiva 1938 - -/* Cyclades products */ -product CYCLADES CYCLOMY_1 0x0100 Cyclom-Y below 1M -product CYCLADES CYCLOMY_2 0x0101 Cyclom-Y above 1M -product CYCLADES CYCLOM4Y_1 0x0102 Cyclom-4Y below 1M -product CYCLADES CYCLOM4Y_2 0x0103 Cyclom-4Y above 1M -product CYCLADES CYCLOM8Y_1 0x0104 Cyclom-8Y below 1M -product CYCLADES CYCLOM8Y_2 0x0105 Cyclom-8Y above 1M -product CYCLADES CYCLOMZ_1 0x0200 Cyclom-Z below 1M -product CYCLADES CYCLOMZ_2 0x0201 Cyclom-Z above 1M - -/* Cyclone Microsystems products */ -product CYCLONE PCI_700 0x0700 IQ80310 (PCI-700) - -/* Cyrix (now National) products */ -product CYRIX MEDIAGX_PCHB 0x0001 MediaGX Built-in PCI Host Controller -product CYRIX CX5520_PCIB 0x0002 Cx5520 I/O Companion -product CYRIX CX5530_PCIB 0x0100 Cx5530 I/O Companion Multi-Function South Bridge -product CYRIX CX5530_SMI 0x0101 Cx5530 I/O Companion (SMI Status and ACPI Timer) -product CYRIX CX5530_IDE 0x0102 Cx5530 I/O Companion (IDE Controller) -product CYRIX CX5530_AUDIO 0x0103 Cx5530 I/O Companion (XpressAUDIO) -product CYRIX CX5530_VIDEO 0x0104 Cx5530 I/O Companion (Video Controller) - -/* Davicom Semiconductor products */ -product DAVICOM DM9102 0x9102 Davicom DM9102 10/100 Ethernet - -/* DEC products */ -product DEC 21050 0x0001 DECchip 21050 PCI-PCI Bridge -product DEC 21040 0x0002 DECchip 21040 (\"Tulip\") Ethernet -product DEC 21030 0x0004 DECchip 21030 (\"TGA\") -product DEC NVRAM 0x0007 Zephyr NV-RAM -product DEC KZPSA 0x0008 KZPSA -product DEC 21140 0x0009 DECchip 21140 (\"FasterNet\") 10/100 Ethernet -product DEC PBXGB 0x000d TGA2 -product DEC DEFPA 0x000f DEFPA -/* product DEC ??? 0x0010 ??? VME Interface */ -product DEC 21041 0x0014 DECchip 21041 (\"Tulip Plus\") Ethernet -product DEC DGLPB 0x0016 DGLPB (\"OPPO\") -product DEC 21142 0x0019 DECchip 21142/21143 10/100 Ethernet -product DEC 21052 0x0021 DECchip 21052 PCI-PCI Bridge -product DEC 21150 0x0022 DECchip 21150 PCI-PCI Bridge -product DEC 21152 0x0024 DECchip 21152 PCI-PCI Bridge -product DEC 21153 0x0025 DECchip 21153 PCI-PCI Bridge -product DEC 21154 0x0026 DECchip 21154 PCI-PCI Bridge -product DEC 21554 0x0046 DECchip 21554 PCI-PCI Bridge -product DEC SWXCR 0x1065 SWXCR RAID - -/* Dell Computer products */ -product DELL PERC_2SI 0x0001 PERC 2/Si -product DELL PERC_3DI 0x0002 PERC 3/Di -product DELL PERC_3SI 0x0003 PERC 3/Si -product DELL PERC_3SI_2 0x0004 PERC 3/Si -product DELL PERC_3DI_2 0x0008 PERC 3/Di -product DELL PERC_3DI_3 0x000a PERC 3/Di -product DELL PERC_4DI 0x000e PERC 4/Di -product DELL PERC_4DI_2 0x000f PERC 4/Di -product DELL PERC_3DI_2_SUB 0x00cf PERC 3/Di -product DELL PERC_3SI_2_SUB 0x00d0 PERC 3/Si -product DELL PERC_3DI_SUB2 0x00d1 PERC 3/Di -product DELL PERC_3DI_SUB3 0x00d9 PERC 3/Di -product DELL PERC_3DI_3_SUB 0x0106 PERC 3/Di -product DELL PERC_3DI_3_SUB2 0x011b PERC 3/Di -product DELL PERC_3DI_3_SUB3 0x0121 PERC 3/Di - -/* Delta products */ -product DELTA RHINEII 0x1320 Rhine II 10/100 Ethernet -product DELTA 8139 0x1360 8139 Ethernet - -/* Diamond products */ -product DIAMOND VIPER 0x9001 Viper/PCI - -/* Digi International products */ -product DIGI SYNC570I_2PB1 0x5010 SYNC/570i-PCI 2 port (mapped below 1M) -product DIGI SYNC570I_4PB1 0x5011 SYNC/570i-PCI 4 port (mapped below 1M) -product DIGI SYNC570I_2P 0x5012 SYNC/570i-PCI 2 port -product DIGI SYNC570I_4P 0x5013 SYNC/570i-PCI 4 port - -/* D-Link Systems products */ -product DLINK DL1002 0x1002 DL-1002 10/100 Ethernet -product DLINK DFE530TXPLUS 0x1300 DFE-530TXPLUS 10/100 Ethernet -product DLINK DFE690TXD 0x1340 DFE-690TXD 10/100 Ethernet -product DLINK DL4000 0x4000 DL-4000 Gigabit Ethernet -product DLINK DGE528T 0x4300 DGE-528T Gigabit Ethernet -product DLINK DGE560T 0x4b00 DGE-560T -product DLINK DGE530T_B1 0x4b01 DGE-530T B1 -product DLINK DGE530T_A1 0x4c00 DGE-530T A1 - -/* Distributed Processing Technology products */ -product DPT SC_RAID 0xa400 SmartCache/SmartRAID (EATA) -product DPT I960_PPB 0xa500 PCI-PCI Bridge -product DPT RAID_I2O 0xa501 SmartRAID (I2O) -product DPT RAID_2005S 0xa511 Zero Channel SmartRAID (I2O) -product DPT MEMCTLR 0x1012 Memory Controller - -/* Dolphin products */ -product DOLPHIN PCISCI 0x0658 PCI-SCI Bridge - -/* Domex products */ -product DOMEX PCISCSI 0x0001 DMX-3191D - -/* Dynalink products */ -product DYNALINK IS64PH 0x1702 Dynalink IS64PH ISDN Adapter - -/* ELSA products */ -product ELSA QS1PCI 0x1000 QuickStep 1000 ISDN card - -/* Emulex products */ -product EMULEX LPPFC 0x10df \"Light Pulse\" FibreChannel adapter - -/* ENE Technology, Inc. products */ -product ENE CB710 0x710 CB710 Cardbus Controller -product ENE CB720 0x720 CB720 Cardbus Controller -product ENE CB1211 0x1211 CB1211 Cardbus Controller -product ENE CB1225 0x1225 CB1225 Cardbus Controller -product ENE CB1410 0x1410 CB1410 Cardbus Controller -product ENE CB1420 0x1420 CB1420 Cardbus Controller - -/* Ensoniq products */ -product ENSONIQ AUDIOPCI 0x5000 AudioPCI -product ENSONIQ AUDIOPCI97 0x1371 AudioPCI 97 -product ENSONIQ CT5880 0x5880 CT5880 - -/* Equinox Systems product */ -product EQUINOX SST64P 0x0808 SST-64P adapter -product EQUINOX SST128P 0x1010 SST-128P adapter -product EQUINOX SST16P_1 0x80c0 SST-16P adapter -product EQUINOX SST16P_2 0x80c4 SST-16P adapter -product EQUINOX SST16P_3 0x80c8 SST-16P adapter -product EQUINOX SST4P 0x8888 SST-4P adapter -product EQUINOX SST8P 0x9090 SST-8P adapter - -/* Essential Communications products */ -product ESSENTIAL RR_HIPPI 0x0001 RoadRunner HIPPI Interface -product ESSENTIAL RR_GIGE 0x0005 RoadRunner Gig-E Interface - -/* ESS Technology, Inc. products */ -product ESSTECH MAESTRO1 0x0100 Maestro 1 PCI Audio Accelerator -product ESSTECH MAESTRO2 0x1968 Maestro 2 PCI Audio Accelerator -product ESSTECH SOLO1 0x1969 Solo-1 PCI AudioDrive -product ESSTECH MAESTRO2E 0x1978 Maestro 2E PCI Audio Accelerator -product ESSTECH ALLEGRO1 0x1988 Allegro-1 PCI Audio Accelerator -product ESSTECH MAESTRO3 0x1998 Maestro 3 PCI Audio Accelerator -product ESSTECH MAESTRO3MODEM 0x1999 Maestro 3 Modem -product ESSTECH MAESTRO3_2 0x199a Maestro 3 PCI Audio Accelerator - -/* ESS Technology, Inc. products */ -product ESSTECH2 MAESTRO1 0x0100 Maestro 1 PCI Audio Accelerator - -/* Eumitcom products */ -product EUMITCOM WL11000P 0x1100 WL11000P PCI WaveLAN/IEEE 802.11 - -/* O2 Micro, Inc. */ -product O2MICRO OZ6729 0x6729 OZ6729 PCI-PCMCIA Bridge -product O2MICRO OZ6730 0x673A OZ6730 PCI-PCMCIA Bridge -product O2MICRO OZ6832 0x6832 OZ6832/OZ6833 PCI-CardBus Bridge -product O2MICRO OZ6836 0x6836 OZ6836/OZ6860 PCI-Cardbus Bridge -product O2MICRO OZ6872 0x6872 OZ6812/OZ6872 PCI-Cardbus Bridge -product O2MICRO OZ6922 0x6925 OZ6922 PCI-Cardbus Bridge -product O2MICRO OZ6933 0x6933 OZ6933 PCI-Cardbus Bridge -product O2MICRO OZ6972 0x6972 OZ6912/OZ6972 PCI-Cardbus Bridge - -/* Evans & Sutherland products */ -product ES FREEDOM 0x0001 Freedom PCI-GBus Interface - -/* FORE products */ -product FORE PCA200 0x0210 ATM PCA-200 -product FORE PCA200E 0x0300 ATM PCA-200e - -/* Forte Media products */ -product FORTEMEDIA FM801 0x0801 Forte Media 801 Sound -product FORTEMEDIA PCIJOY 0x0802 PCI Gameport Joystick - -/* Future Domain products */ -product FUTUREDOMAIN TMC_18C30 0x0000 TMC-18C30 (36C70) - -/* FZ Juelich / ZEL products */ -product FZJZEL GIGALINK 0x0001 Gigabit link / STR1100 -product FZJZEL PLXHOTLINK 0x0002 HOTlink interface -product FZJZEL COUNTTIME 0x0003 Counter / Timer -product FZJZEL PLXCAMAC 0x0004 CAMAC controller -product FZJZEL PROFIBUS 0x0005 PROFIBUS interface -product FZJZEL AMCCHOTLINK 0x0006 old HOTlink interface - -/* Efficient Networks products */ -product EFFICIENTNETS ENI155PF 0x0000 155P-MF1 ATM (FPGA) -product EFFICIENTNETS ENI155PA 0x0002 155P-MF1 ATM (ASIC) -product EFFICIENTNETS ENI25P 0x0003 SpeedStream ENI-25p -product EFFICIENTNETS SS3000 0x0005 SpeedStream 3000 - -/* Marvell (was Galileo Technology) products */ -product MARVELL GT64010A 0x0146 GT-64010A System Controller -product MARVELL GT64115 0x4111 GT-64115 System Controller -product MARVELL GT64011 0x4146 GT-64011 System Controller -product MARVELL YUKON 0x4320 Yukon 88E8001/8003/8010 -product MARVELL YUKONII_8021CU 0x4340 Yukon-II 88E8021CU -product MARVELL YUKONII_8022CU 0x4341 Yukon-II 88E8022CU -product MARVELL YUKONII_8061CU 0x4342 Yukon-II 88E8061CU -product MARVELL YUKONII_8062CU 0x4343 Yukon-II 88E8062CU -product MARVELL YUKONII_8021X 0x4344 Yukon-II 88E8021X -product MARVELL YUKONII_8022X 0x4345 Yukon-II 88E8022X -product MARVELL YUKONII_8061X 0x4346 Yukon-II 88E8061X -product MARVELL YUKONII_8062X 0x4347 Yukon-II 88E8062X -product MARVELL YUKON_8035 0x4350 Yukon 88E8035 -product MARVELL YUKON_8036 0x4351 Yukon 88E8036 -product MARVELL YUKON_8038 0x4352 Yukon 88E8038 -product MARVELL YUKON_8052 0x4360 Yukon 88E8052 -product MARVELL YUKON_8050 0x4361 Yukon 88E8050 -product MARVELL YUKON_8053 0x4362 Yukon 88E8053 -product MARVELL YUKON_3 0x4363 Yukon -product MARVELL GT64120 0x4620 GT-64120 System Controller -product MARVELL YUKON_BELKIN 0x5005 Yukon (Belkin F5D5005) -product MARVELL GT64130 0x6320 GT-64130 System Controller -product MARVELL GT64260 0x6430 GT-64260 System Controller - -/* Global Sun Tech products */ -product GLOBALSUN GL24110P 0x1101 GL24110P PCI IEEE 802.11b -product GLOBALSUN GL24110P02 0x1102 GL24110P PCI IEEE 802.11b - -/* Guillemot products */ -product GUILLEMOT MAXIRADIO 0x1001 MAXIRADIO - -/* Heuricon products */ -product HEURICON PMPPC 0x000e PM/PPC - -/* Hewlett-Packard products */ -product HP A4977A 0x1005 A4977A Visualize EG -product HP TACHYON_TL 0x1028 Tachyon TL FC controller -product HP TACHYON_TS 0x102A Tachyon TS FC controller -product HP TACHYON_XL2 0x1030 Tachyon XL2 FC controller -product HP J2585A 0x1030 J2585A -product HP J2585B 0x1031 J2585B -product HP 82557B 0x1200 82557B 10/100 NIC -product HP NETRAID_4M 0x10c2 NetRaid-4M - -/* Hifn products */ -product HIFN 7751 0x0005 7751 -product HIFN 6500 0x0006 6500 -product HIFN 7811 0x0007 7811 -product HIFN 7951 0x0012 7951 -product HIFN 7955 0x0020 7954/7955 -product HIFN 7956 0x001d 7956 -product HIFN 78XX 0x0014 7814/7851/7854 -product HIFN 8065 0x0016 8065 -product HIFN 8165 0x0017 8165 -product HIFN 8154 0x0018 8154 - -/* HiNT products */ -product HINT HB1 0x0021 HB1 PCI-PCI Bridge -product HINT HB4 0x0022 HB4 PCI-PCI Bridge - -/* IBM products */ -product IBM MCABRIDGE 0x0002 MCA Bridge -product IBM ALTALITE 0x0005 CPU Bridge - Alta Lite -product IBM ALTAMP 0x0007 CPU Bridge - Alta MP -product IBM ISABRIDGE 0x000a ISA Bridge w/PnP -product IBM CPUBRIDGE 0x0017 CPU Bridge -product IBM LANSTREAMER 0x0018 Auto LANStreamer -product IBM GXT150P 0x001b GXT-150P 2D Accelerator -product IBM MCABRIDGE2 0x0020 MCA Bridge -product IBM 82351 0x0022 82351 PCI-PCI Bridge -product IBM SERVERAID 0x002e ServeRAID -product IBM OLYMPIC 0x003e Token Ring -product IBM MIAMI 0x0036 Miami/PCI -product IBM 82660 0x0037 82660 PowerPC to PCI Bridge and Memory Controller -product IBM MPIC 0x0046 MPIC -product IBM TURBOWAYS25 0x0053 Turboways 25 ATM -product IBM GXT800P 0x005e GXT-800P -product IBM 405GP 0x0156 PPC 405GP PCI Bridge -product IBM 133PCIX 0x01a7 133 PCI-X Bridge -product IBM MPIC2 0xffff MPIC-II - -/* Conexant (iCompression, GlobeSpan) products */ -product ICOMPRESSION ITVC16 0x0016 iTVC16 MPEG2 codec -product ICOMPRESSION ITVC15 0x0803 iTVC15 MPEG2 codec - -/* IDT products */ -product IDT 77201 0x0001 77201/77211 ATM (\"NICStAR\") -product IDT RC32334 0x0204 RC32334 System Controller -product IDT RC32332 0x0205 RC32332 System Controller - -/* Industrial Computer Source */ -product INDCOMPSRC WDT50x 0x22c0 PCI-WDT50x Watchdog Timer - -/* Initio products */ -product INITIO I920 0x0002 INIC-920 SCSI -product INITIO I850 0x0850 INIC-850 SCSI -product INITIO I1060 0x1060 INIC-1060 SCSI -product INITIO I940 0x9400 INIC-940 SCSI -product INITIO I935 0x9401 INIC-935 SCSI -product INITIO I950 0x9500 INIC-950 SCSI - -/* Integraphics Systems products */ -product INTEGRAPHICS IGA1680 0x1680 IGA 1680 -product INTEGRAPHICS IGA1682 0x1682 IGA 1682 -product INTEGRAPHICS CYBERPRO2000 0x2000 CyberPro 2000 -product INTEGRAPHICS CYBERPRO2010 0x2010 CyberPro 2010 - -/* Integrated Micro Solutions products */ -product IMS 8849 0x8849 8849 -product IMS TT128M 0x9128 TwinTurbo 128M - -/* Intel products */ -product INTEL 80312 0x030d 80312 I/O Companion Chip -product INTEL 80321 0x0319 80321 I/O Processor -product INTEL PCEB 0x0482 82375EB/SB PCI-EISA Bridge (PCEB) -product INTEL CDC 0x0483 82424ZX Cache and DRAM controller (CDC) -product INTEL SIO 0x0484 82378ZB System I/O (SIO) -product INTEL 82426EX 0x0486 82426EX PCI-to-ISA Bridge (PCIB) -product INTEL PCMC 0x04a3 82434LX/NX PCI, Cache and Memory Controller (PCMC) -product INTEL GDT_RAID1 0x0600 GDT RAID -product INTEL GDT_RAID2 0x061f GDT RAID -product INTEL 80960RM 0x0962 i960 RM PCI-PCI -product INTEL 80960RN 0x0964 i960 RN PCI-PCI -product INTEL 82542 0x1000 i82542 Gigabit Ethernet -product INTEL 82543GC_FIBER 0x1001 i82453GC Gigabit Ethernet (1000BASE-X) -product INTEL 82543GC_COPPER 0x1004 i82543GC Gigabit Ethernet (1000BASE-T) -product INTEL 82544EI_COPPER 0x1008 i82544EI Gigabit Ethernet (1000BASE-T) -product INTEL 82544EI_FIBER 0x1009 i82544EI Gigabit Ethernet (1000BASE-X) -product INTEL 82544GC_COPPER 0x100c i82544GC Gigabit Ethernet (1000BASE-T) -product INTEL 82544GC_LOM 0x100d i82544GC (LOM) Gigabit Ethernet -product INTEL 82540EM 0x100e i82540EM Gigabit Ethernet (1000BASE-T) -product INTEL 82545EM_COPPER 0x100f i82545EM Gigabit Ethernet (1000BASE-T) -product INTEL 82546EB_COPPER 0x1010 i82546EB Gigabit Ethernet (1000BASE-T) -product INTEL 82545EM_FIBER 0x1011 i82545EM Gigabit Ethernet (1000BASE-X) -product INTEL 82546EB_FIBER 0x1012 i82546EB Gigabit Ethernet (1000BASE-X) -product INTEL 82541EI 0x1013 i82541EI Gigabit Ethernet -product INTEL 82540EM_LOM 0x1015 i82540EM (LOM) Gigabit Ethernet -product INTEL 82540EP_LOM 0x1016 i82540EP (LOM) Gigabit Ethernet -product INTEL 82540EP 0x1017 i82540EP Gigabit Ethernet -product INTEL 82541EI_MOBILE 0x1018 i82541EI Mobile Gigabit Ethernet -product INTEL 82547EI 0x1019 i82547EI Gigabit Ethernet -product INTEL 82546EB_QUAD 0x101d i82546EB Gigabit Ethernet (1000BASE-T) -product INTEL 82540EP_LP 0x101e i82540EP Gigabit Ethernet -product INTEL 82545GM_COPPER 0x1026 i82545GM Gigabit Ethernet (1000BASE-T) -product INTEL 82545GM_FIBER 0x1027 i82545GM Gigabit Ethernet (1000BASE-X) -product INTEL 82545GM_SERDES 0x1028 i82545GM Gigabit Ethernet (SERDES) -product INTEL IN_BUSINESS 0x1030 InBusiness Fast Ethernet LAN Controller -product INTEL PRO_100_VE_0 0x1031 PRO/100 VE Network Controller -product INTEL PRO_100_VE_1 0x1032 PRO/100 VE Network Controller -product INTEL PRO_100_VM_0 0x1033 PRO/100 VM Network Controller -product INTEL PRO_100_VM_1 0x1034 PRO/100 VM Network Controller -product INTEL 82562EH_HPNA_0 0x1035 82562EH HomePNA Network Controller -product INTEL 82562EH_HPNA_1 0x1036 82562EH HomePNA Network Controller -product INTEL 82562EH_HPNA_2 0x1037 82562EH HomePNA Network Controller -product INTEL PRO_100_VM_2 0x1038 PRO/100 VM Network Controller -product INTEL PRO_100_VE_2 0x1039 PRO/100 VE Network Controller with 82562ET/EZ PHY -product INTEL PRO_100_VE_3 0x103a PRO/100 VE Network Controller with 82562ET/EZ (CNR) PHY -product INTEL PRO_100_VM_3 0x103b PRO/100 VM Network Controller with 82562EM/EX PHY -product INTEL PRO_100_VM_4 0x103c PRO/100 VM Network Controller with 82562EM/EX (CNR) PHY -product INTEL PRO_100_VE_4 0x103d PRO/100 VE (MOB) Network Controller -product INTEL PRO_100_VM_5 0x103e PRO/100 VM (MOB) Network Controller -product INTEL PRO_WL_2100 0x1043 PRO/Wireless LAN 2100 3B Mini PCI Adapter -product INTEL 82597EX 0x1048 PRO/10GbE LR Server Adapter -product INTEL PRO_100_VM_6 0x1050 PRO/100 VM Network Controller with 82562ET/EZ PHY -product INTEL PRO_100_M 0x1059 PRO/100 M Network Controller -product INTEL PRO_100_VE_5 0x1064 PRO/100 VE (LOM) Ethernet Controller with 82562ET/EZ/GT/GZ -product INTEL 82547GI 0x1075 i82547GI Gigabit Ethernet -product INTEL 82541GI 0x1076 i82541GI Gigabit Ethernet -product INTEL 82541GI_MOBILE 0x1077 i82541GI Mobile Gigabit Ethernet -product INTEL 82541ER 0x1078 i82541ER Gigabit Ethernet -product INTEL 82546GB_COPPER 0x1079 i82546GB Gigabit Ethernet (1000BASE-T) -product INTEL 82546GB_FIBER 0x107a i82546GB Gigabit Ethernet (1000BASE-X) -product INTEL 82546GB_SERDES 0x107b i82546GB Gigabit Ethernet (SERDES) -product INTEL 82815_DC100_HUB 0x1100 82815 Hub -product INTEL 82815_DC100_AGP 0x1101 82815 AGP -product INTEL 82815_DC100_GRAPH 0x1102 82815 Graphics -product INTEL 82815_NOAGP_HUB 0x1110 82815 Hub -product INTEL 82815_NOAGP_GRAPH 0x1112 82815 Graphics -product INTEL 82815_NOGRAPH_HUB 0x1120 82815 Hub -product INTEL 82815_NOGRAPH_AGP 0x1121 82815 AGP -product INTEL 82815_FULL_HUB 0x1130 82815 Hub -product INTEL 82815_FULL_AGP 0x1131 82815 AGP -product INTEL 82815_FULL_GRAPH 0x1132 82815 Graphics -product INTEL 82806AA 0x1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller -product INTEL ADI_BECC 0x1162 ADI i80200 Big Endian Companion Chip -product INTEL IXP1200 0x1200 IXP1200 Network Processor -product INTEL 82559ER 0x1209 82559ER Fast Ethernet LAN Controller -product INTEL 82092AA 0x1222 82092AA IDE controller -product INTEL SAA7116 0x1223 SAA7116 -product INTEL 82452_PB 0x1225 82452KX/GX Orion Extended Express Processor to PCI Bridge -product INTEL 82596 0x1226 82596 LAN Controller -product INTEL EEPRO100 0x1227 EE Pro 100 10/100 Fast Ethernet -product INTEL EEPRO100S 0x1228 EE Pro 100 Smart 10/100 Fast Ethernet -product INTEL 82557 0x1229 82557 Fast Ethernet LAN Controller -product INTEL 82437FX 0x122d 82437FX System Controller (TSC) -product INTEL 82371FB_ISA 0x122e 82371FB PCI-to-ISA Bridge (PIIX) -product INTEL 82371FB_IDE 0x1230 82371FB IDE controller (PIIX) -product INTEL 82371MX 0x1234 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) -product INTEL 82437MX 0x1235 82437MX Mobile System Controller (MTSC) -product INTEL 82441FX 0x1237 82441FX PCI and Memory Controller (PMC) -product INTEL 82380AB 0x123c 82380AB Mobile PCI-to-ISA Bridge (MISA) -product INTEL 82380FB 0x124b 82380FB Mobile PCI-to-PCI Bridge (MPCI2) -product INTEL 82439HX 0x1250 82439HX System Controller (TXC) -product INTEL 82870P2_PPB 0x1460 82870P2 P64H2 PCI-to-PCI Bridge -product INTEL 82870P2_IOxAPIC 0x1461 82870P2 P64H2 IOxAPIC -product INTEL 82870P2_HPLUG 0x1462 82870P2 P64H2 Hot Plug Controller -product INTEL 80960_RP 0x1960 ROB-in i960RP Microprocessor -product INTEL 80960RM_2 0x1962 i960 RM PCI-PCI -product INTEL 82840_HB 0x1a21 82840 Host -product INTEL 82840_AGP 0x1a23 82840 AGP -product INTEL 82840_PCI 0x1a24 82840 PCI -product INTEL 82845_HB 0x1a30 82845 Host -product INTEL 82845_AGP 0x1a31 82845 AGP -product INTEL 82801AA_LPC 0x2410 82801AA LPC Interface Bridge -product INTEL 82801AA_IDE 0x2411 82801AA IDE Controller -product INTEL 82801AA_USB 0x2412 82801AA USB Controller -product INTEL 82801AA_SMB 0x2413 82801AA SMBus Controller -product INTEL 82801AA_ACA 0x2415 82801AA AC-97 Audio Controller -product INTEL 82801AA_ACM 0x2416 82801AA AC-97 PCI Modem -product INTEL 82801AA_HPB 0x2418 82801AA Hub-to-PCI Bridge -product INTEL 82801AB_LPC 0x2420 82801AB LPC Interface Bridge -product INTEL 82801AB_IDE 0x2421 82801AB IDE Controller -product INTEL 82801AB_USB 0x2422 82801AB USB Controller -product INTEL 82801AB_SMB 0x2423 82801AB SMBus Controller -product INTEL 82801AB_ACA 0x2425 82801AB AC-97 Audio Controller -product INTEL 82801AB_ACM 0x2426 82801AB AC-97 PCI Modem -product INTEL 82801AB_HPB 0x2428 82801AB Hub-to-PCI Bridge -product INTEL 82801BA_LPC 0x2440 82801BA LPC Interface Bridge -product INTEL 82801BA_USB1 0x2442 82801BA USB Controller -product INTEL 82801BA_SMB 0x2443 82801BA SMBus Controller -product INTEL 82801BA_USB2 0x2444 82801BA USB Controller -product INTEL 82801BA_ACA 0x2445 82801BA AC-97 Audio Controller -product INTEL 82801BA_ACM 0x2446 82801BA AC-97 PCI Modem -product INTEL 82801BAM_HPB 0x2448 82801BAM Hub-to-PCI Bridge -product INTEL 82801BA_LAN 0x2449 82801BA LAN Controller -product INTEL 82801BAM_IDE 0x244a 82801BAM IDE Controller -product INTEL 82801BA_IDE 0x244b 82801BA IDE Controller -product INTEL 82801BAM_LPC 0x244c 82801BAM LPC Interface Bridge -product INTEL 82801BA_HPB 0x244e 82801BA Hub-to-PCI Bridge -product INTEL 82801E_SMB 0x2453 82801E SMBus Controller -product INTEL 82801E_LAN_1 0x2459 82801E LAN Controller -product INTEL 82801E_LAN_2 0x245d 82801E LAN Controller -product INTEL 82801CA_LPC 0x2480 82801CA LPC Interface -product INTEL 82801CA_USB_1 0x2482 82801CA/CAM USB Controller -product INTEL 82801CA_SMB 0x2483 82801CA/CAM SMBus Controller -product INTEL 82801CA_USB_2 0x2484 82801CA/CAM USB Controller -product INTEL 82801CA_AC 0x2485 82801CA/CAM AC'97 Audio Controller -product INTEL 82801CA_MOD 0x2486 82801CA/CAM Modem -product INTEL 82801CA_USBC 0x2487 82801CA/CAM USB Controller -product INTEL 82801CA_IDE_1 0x248A 82801CA IDE Controller -product INTEL 82801CA_IDE_2 0x248B 82801CA IDE Controller -product INTEL 82801CAM_LPC 0x248C 82801CAM LPC Interface -product INTEL 82801DB_LPC 0x24C0 82801DB LPC Interface Bridge -product INTEL 82801DB_USB_1 0x24C2 82801DB/DBM USB UHCI Controller #1 -product INTEL 82801DB_SMB 0x24C3 82801DB/DBM SMBus Controller -product INTEL 82801DB_USB_2 0x24C4 82801DB/DBM USB UHCI Controller #2 -product INTEL 82801DB_AC 0x24C5 82801DB/DBM AC97 Audio Controller -product INTEL 82801DB_MOD 0x24C6 82801DB/DBM AC97 Modem Controller -product INTEL 82801DB_USB_3 0x24C7 82801DB/DBM USB UHCI Controller #3 -product INTEL 82801DBM_IDE 0x24CA 82801DBM IDE Controller -product INTEL 82801DB_IDE 0x24CB 82801DB IDE Controller (UltraATA/100) -product INTEL 82801DB_ISA 0x24CC 82801DB ISA Bridge -product INTEL 82801DB_USBC 0x24CD 82801DB/DBM USB EHCI Controller -product INTEL 82801EB_LPC 0x24D0 82801EB LPC Interface Bridge -product INTEL 82801EB_SATA 0x24D1 82801EB Serial ATA Controller -product INTEL 82801EB_USB_0 0x24D2 82801EB/ER USB UHCI Controller #0 -product INTEL 82801EB_SMB 0x24D3 82801EB/ER SMBus Controller -product INTEL 82801EB_USB_1 0x24D4 82801EB/ER USB UHCI Controller #1 -product INTEL 82801EB_AC 0x24D5 82801EB/ER AC'97 Audio Controller -product INTEL 82801EB_MOD 0x24D6 82801EB/ER AC'97 Modem Controller -product INTEL 82801EB_USB_2 0x24D7 82801EB/ER USB UHCI Controller #2 -product INTEL 82801EB_IDE 0x24DB 82801EB/ER IDE Controller -product INTEL 82801EB_EHCI 0x24DD 82801EB/ER USB EHCI Controller -product INTEL 82801EB_USB_3 0x24DE 82801EB/ER USB UHCI Controller #3 -product INTEL 82801ER_SATA 0x24DF 82801ER Serial ATA Controller -product INTEL 82820_MCH 0x2501 82820 MCH (Camino) -product INTEL 82820_AGP 0x250f 82820 AGP -product INTEL 82850_HB 0x2530 82850 Host -product INTEL 82860_HB 0x2531 82860 Host -product INTEL 82850_AGP 0x2532 82850/82860 AGP -product INTEL 82860_PCI1 0x2533 82860 PCI-PCI -product INTEL 82860_PCI2 0x2534 82860 PCI-PCI -product INTEL 82860_PCI3 0x2535 82860 PCI-PCI -product INTEL 82860_PCI4 0x2536 82860 PCI-PCI -product INTEL E7500_HB 0x2540 E7500 MCH Host -product INTEL E7500_DRAM 0x2541 E7500 MCH DRAM Controller -product INTEL E7500_HI_B1 0x2543 E7500 MCH HI_B vppb 1 -product INTEL E7500_HI_B2 0x2544 E7500 MCH HI_B vppb 2 -product INTEL E7500_HI_C1 0x2545 E7500 MCH HI_C vppb 1 -product INTEL E7500_HI_C2 0x2546 E7500 MCH HI_C vppb 2 -product INTEL E7500_HI_D1 0x2547 E7500 MCH HI_D vppb 1 -product INTEL E7500_HI_D2 0x2548 E7500 MCH HI_D vppb 2 -product INTEL E7505_HB 0x2550 E7505 MCH Host -product INTEL E7505_RAS 0x2551 E7505 MCH RAS Controller -product INTEL E7505_AGP 0x2552 E7505 MCH Host-to-AGP Bridge -product INTEL E7505_HI_B1 0x2553 E7505 MCH HI_B PCI-to-PCI -product INTEL E7505_HI_B2 0x2554 E7505 MCH HI_B PCI-to-PCI Error Reporting -product INTEL E7205_MC 0x255d E7205 Memory Controller Hub -product INTEL 82845G_DRAM 0x2560 82845G/GE/GL/GV/PE DRAM Controller/Host-Hub Interface -product INTEL 82845G_AGP 0x2561 82845G/GE/GL/GV/PE Host-to-AGP Bridge -product INTEL 82845G_IGD 0x2562 82845G/GE/GL/GV Integrated Graphics Device -product INTEL 82865_HB 0x2570 82848P/82865G/GV/P/PE DRAM Controller/Host-Hub Interface -product INTEL 82865_AGP 0x2571 82848P/82865G/P/PE PCI-to-AGP Bridge -product INTEL 82865_IGD 0x2572 82865G/GV Integrated Graphics Device -product INTEL 82865_CSA 0x2573 82848P/82865G/GV/P/PE PCI-to-CSA Bridge -product INTEL 82865_OVERFLOW 0x2576 82848P/82865G/GV/P/PE Overflow Device -product INTEL 82875P_HB 0x2578 82875P DRAM Controller/Host-Hub Interface -product INTEL 82875P_AGP 0x2579 82875P PCI-to-AGP Bridge -product INTEL 82875P_CSA 0x257b 82875P PCI-to-CSA Bridge -product INTEL 82875P_OVERFLOW 0x257e 82875P Overflow Device -product INTEL 915G_DRAM 0x2580 910GL/915G/GV/P/925X/XE DRAM Controller -product INTEL 915G_PCIE 0x2581 915G/P/925X/XE Host-to-PCI Express Graphics Bridge -product INTEL 915G_IGD 0x2582 910GL/915G/GV Integrated Graphics Device -product INTEL 82801FB_LPC 0x2640 82801FB/FR LPC Interface Bridge -product INTEL 82801FB_S1 0x2651 ICH6 AHCI Controller -product INTEL 82801FB_R1 0x2652 ICH6 AHCI Controller -product INTEL 82801FBM 0x2653 ICH6M AHCI Controller -product INTEL 82801FB_UHCI 0x265b 82801FB/FR/FW/FRW USB UHCI Controller -product INTEL 82801FB_EHCI 0x265c 82801FB/FR/FW/FRW USB EHCI Controller -product INTEL 82801FB_SMB 0x266a 82801FB/FR/FW/FRW SMBus Controller - -product INTEL 82801GB_S1 0x27c0 82801GBS1 ICH7 AHCI Controller -product INTEL 82801GB_AH 0x27c1 82801GBAH ICH7 AHCI Controller -product INTEL 82801GB_R1 0x27c3 82801GBR1 ICH7 AHCI Controller -product INTEL 82801GBM_S1 0x27c4 82801GBS1 ICH7M AHCI Controller -product INTEL 82801GBM_AH 0x27c5 82801GBAH ICH7M AHCI Controller -product INTEL 82801GBM_R1 0x27c6 82801GBR1 ICH7M AHCI Controller - -product INTEL 31244 0x3200 31244 Serial ATA Controller -product INTEL 82855PM_DDR 0x3340 82855PM MCH Host Controller -product INTEL 82855PM_AGP 0x3341 82855PM Host-to-AGP Bridge -product INTEL 82855PM_PM 0x3342 82855PM Power Management Controller -product INTEL 82855GM_MCH 0x3580 82855GM Host-to-Hub Controller -product INTEL 82855GM_IGD 0x3582 82855GM GMCH Integrated Graphics Device -product INTEL 82855GM_MC 0x3584 82855GM GMCH Memory Controller -product INTEL 82855GM_CP 0x3585 82855GM GMCH Configuration Process -product INTEL 82830MP_IO_1 0x3575 82830MP CPU to I/O Bridge 1 -product INTEL 82830MP_AGP 0x3576 82830MP CPU to AGP Bridge -product INTEL 82830MP_IV 0x3577 82830MP Integrated Video -product INTEL 82830MP_IO_2 0x3578 82830MP CPU to I/O Bridge 2 -product INTEL E7520_MC 0x3590 E7520 Memory Controller Hub -product INTEL E7520_MCER 0x3591 E7520 Memory Controller Hub Error Reporting -product INTEL E7525_MCER 0x3593 E7525 Memory Controller Hub Error Reporting -product INTEL E7520_DMA 0x3594 E7520 DMA Controller -product INTEL E7520_PCIEA 0x3595 E7520/E7525 PCI Express Port A/A0 -product INTEL E7520_PCIEA1 0x3596 E7520/E7525 PCI Express Port A1 -product INTEL E7520_PCIEB 0x3597 E7520/E7525 PCI Express Port B/B0 -product INTEL E7520_PCIEB1 0x3598 E7520 PCI Express Port B1 -product INTEL E7520_PCIEC 0x3599 E7520 PCI Express Port C/C0 -product INTEL E7520_PCIEC1 0x359a E7520 PCI Express Port C1 -product INTEL E7520_EC 0x359b E7520/E7525 Extended Configuration -product INTEL E7525_MC 0x359e E7525 Memory Controller Hub -product INTEL PRO_WL_2200BG 0x4220 PRO/Wireless LAN 2200BG Mini-PCI Adapter -product INTEL PRO_WL_2225BG 0x4221 PRO/Wireless LAN 2225BG Mini-PCI Adapter -product INTEL PRO_WL_2915ABG_1 0x4223 PRO/Wireless LAN 2915ABG Mini-PCI Adapter -product INTEL PRO_WL_3945ABG_1 0x4222 PRO/Wireless LAN 3945ABG Mini-PCI Adapter -product INTEL PRO_WL_2915ABG_2 0x4224 PRO/Wireless LAN 2915ABG Mini-PCI Adapter -product INTEL PRO_WL_3945ABG_2 0x4227 PRO/Wireless LAN 3945ABG Mini-PCI Adapter -product INTEL 80312_ATU 0x530d 80310 ATU -product INTEL 82371SB_ISA 0x7000 82371SB PCI-to-ISA Bridge (PIIX3) -product INTEL 82371SB_IDE 0x7010 82371SB IDE Interface (PIIX3) -product INTEL 82371SB_USB 0x7020 82371SB USB Host Controller (PIIX3) -product INTEL 82437VX 0x7030 82437VX System Controller (TVX) -product INTEL 82439TX 0x7100 82439TX System Controller (MTXC) -product INTEL 82371AB_ISA 0x7110 82371AB PCI-to-ISA Bridge (PIIX4) -product INTEL 82371AB_IDE 0x7111 82371AB IDE controller (PIIX4) -product INTEL 82371AB_USB 0x7112 82371AB USB Host Controller (PIIX4) -product INTEL 82371AB_PMC 0x7113 82371AB Power Management Controller (PIIX4) -product INTEL 82810_MCH 0x7120 82810 Memory Controller Hub -product INTEL 82810_GC 0x7121 82810 Graphics Controller -product INTEL 82810_DC100_MCH 0x7122 82810-DC100 Memory Controller Hub -product INTEL 82810_DC100_GC 0x7123 82810-DC100 Graphics Controller -product INTEL 82810E_MCH 0x7124 82810E Memory Controller Hub -product INTEL 82810E_GC 0x7125 82810E Graphics Controller -product INTEL 82443LX 0x7180 82443LX PCI AGP Controller (PAC) -product INTEL 82443LX_AGP 0x7181 82443LX AGP Interface (PAC) -product INTEL 82443BX 0x7190 82443BX Host Bridge/Controller -product INTEL 82443BX_AGP 0x7191 82443BX AGP Interface -product INTEL 82443BX_NOAGP 0x7192 82443BX Host Bridge/Controller (AGP disabled) -product INTEL 82440MX 0x7194 82443MX Host Bridge/Controller -product INTEL 82440MX_ACA 0x7195 82443MX AC-97 Audio Controller -product INTEL 82440MX_ISA 0x7198 82443MX PCI-to-ISA Bridge -product INTEL 82440MX_IDE 0x7199 82443MX IDE Controller -product INTEL 82440MX_USB 0x719a 82443MX USB Host Controller -product INTEL 82440MX_PMC 0x719b 82443MX Power Management Controller -product INTEL 82443GX 0x71a0 82443GX Host Bridge/Controller -product INTEL 82443GX_AGP 0x71a1 82443GX AGP Interface -product INTEL 82443GX_NOAGP 0x71a2 82443GX Host Bridge/Controller (AGP disabled) -product INTEL I740 0x7800 i740 Graphics Accelerator -product INTEL PCI450_PB 0x84c4 82454KX/GX PCI Bridge (PB) -product INTEL PCI450_MC 0x84c5 82451KX/GX Memory Controller (MC) -product INTEL 82451NX_MIOC 0x84ca 82451NX Memory & I/O Controller (MIOC) -product INTEL 82451NX_PXB 0x84cb 82451NX PCI Expander Bridge (PXB) -product INTEL 21152 0xb152 S21152BB PCI to PCI Bridge -product INTEL 21154 0xb154 S21152BA,S21154AE/BE PCI to PCI Bridge -product INTEL 21555 0xb555 21555 Non-Transparent PCI-PCI Bridge - -/* Intergraph products */ -product INTERGRAPH 4D50T 0x00e4 Powerstorm 4D50T - -/* Intersil products */ -product INTERSIL MINI_PCI_WLAN 0x3873 Intersil PRISM2.5 Mini-PCI WLAN -product INTERSIL MINI_PCI_P54 0x3890 Intersil PRISM-54 Mini-PCI WLAN - -/* Invertex */ -product INVERTEX AEON 0x0005 AEON - -/* ITE products */ -product ITE IT8152 0x8152 IT8152 Host Bridge - -/* I. T. T. products */ -product ITT AGX016 0x0001 AGX016 -product ITT ITT3204 0x0002 ITT3204 MPEG Decoder - -/* JMicron Technology Corporation products */ -product JMICRON JMC250 0x0250 JMC250 PCI Express Gigabit Ethernet -product JMICRON JMC260 0x0260 JMC260 PCI Express Fast Ethernet - -/* KTI products - XXX better descriptions */ -product KTI NE2KETHER 0x3000 Ethernet - -/* LAN Media Corporation */ -product LMC HSSI 0x0003 HSSI Interface -product LMC DS3 0x0004 DS3 Interface -product LMC SSI 0x0005 SSI -product LMC DS1 0x0006 DS1 - -/* LeadTek Research */ -product LEADTEK S3_805 0x0000 S3 805 - -/* Level One products */ -product LEVELONE LXT1001 0x0001 LXT-1001 10/100/1000 Ethernet - -/* Linear Systems / CompuModules */ -product LINEARSYS DVB_TX 0x7629 DVB Transmitter -product LINEARSYS DVB_RX 0x7630 DVB Receiver - -/* Linksys products */ -product LINKSYS EG1032 0x1032 EG1032 v2 Instant Gigabit Network Adapter -product LINKSYS EG1064 0x1064 EG1064 v2 Instant Gigabit Network Adapter -/* Lite-On products */ -product LITEON 82C168 0x0002 82C168/82C169 (PNIC) 10/100 Ethernet -product LITEON 82C115 0xc115 82C115 (PNIC II) 10/100 Ethernet - -/* Lucent Technologies products */ -product LUCENT LTMODEM_0440 0x0440 K56flex DSVD LTMODEM -product LUCENT LTMODEM_0441 0x0441 LTMODEM -product LUCENT LTMODEM_0442 0x0442 LTMODEM -product LUCENT LTMODEM_0443 0x0443 LTMODEM -product LUCENT LTMODEM_0444 0x0444 LTMODEM -product LUCENT LTMODEM_0445 0x0445 LTMODEM -product LUCENT LTMODEM_0446 0x0446 LTMODEM -product LUCENT LTMODEM_0447 0x0447 LTMODEM -product LUCENT LTMODEM_0448 0x0448 LTMODEM -product LUCENT LTMODEM_0449 0x0449 LTMODEM -product LUCENT LTMODEM_044a 0x044a LTMODEM -product LUCENT LTMODEM_044b 0x044b LTMODEM -product LUCENT LTMODEM_044c 0x044c LTMODEM -product LUCENT LTMODEM_044d 0x044d LTMODEM -product LUCENT LTMODEM_044e 0x044e LTMODEM -product LUCENT LTMODEM_0450 0x0450 LTMODEM -product LUCENT LTMODEM_0451 0x0451 LTMODEM -product LUCENT LTMODEM_0452 0x0452 LTMODEM -product LUCENT LTMODEM_0453 0x0453 LTMODEM -product LUCENT LTMODEM_0454 0x0454 LTMODEM -product LUCENT LTMODEM_0455 0x0455 LTMODEM -product LUCENT LTMODEM_0456 0x0456 LTMODEM -product LUCENT LTMODEM_0457 0x0457 LTMODEM -product LUCENT LTMODEM_0458 0x0458 LTMODEM -product LUCENT LTMODEM_0459 0x0459 LTMODEM -product LUCENT LTMODEM_045a 0x045a LTMODEM -product LUCENT OR3LP26 0x5400 Lucent ORCA FPGA w/32-bit PCI ASIC core -product LUCENT OR3TP12 0x5401 Lucent ORCA FPGA w/64-bit PCI ASIC core -product LUCENT USBHC 0x5801 USB Host Controller -product LUCENT FW322_323 0x5811 FW322/323 IEEE 1394 OHCI Controller -product LUCENT ET1310 0xed00 ET1310 10/100/1000M Ethernet -product LUCENT ET1310_FAST 0xed01 ET1310 10/100M Ethernet - -/* Macronix */ -product MACRONIX MX98713 0x0512 MX98713 (PMAC) 10/100 Ethernet -product MACRONIX MX987x5 0x0531 MX987x5 (PMAC) 10/100 Ethernet - -/* Madge Networks products */ -product MADGE SMARTRN2 0x0002 Smart 16/4 PCI Ringnode Mk2 -product MADGE COLLAGE25 0x1000 Collage 25 ATM adapter -product MADGE COLLAGE155 0x1001 Collage 155 ATM adapter - -/* Matrox products */ -product MATROX ATLAS 0x0518 MGA PX2085 (\"Atlas\") -product MATROX MILLENNIUM 0x0519 MGA Millennium 2064W (\"Storm\") -product MATROX MYSTIQUE 0x051a MGA Mystique 1064SG -product MATROX MILLENNIUM2 0x051b MGA Millennium II 2164W -product MATROX MILLENNIUM2_AGP 0x051f MGA Millennium II 2164WA-B AGP -product MATROX G200_PCI 0x0520 MGA G200 PCI -product MATROX G200_AGP 0x0521 MGA G200 AGP -product MATROX G400_AGP 0x0525 MGA G400 AGP -product MATROX IMPRESSION 0x0d10 MGA Impression -product MATROX G100_PCI 0x1000 MGA G100 PCI -product MATROX G100_AGP 0x1001 MGA G100 AGP -product MATROX G550_AGP 0x2527 MGA G550 AGP - -/* MediaQ, Inc. products */ -product MEDIAQ MQ200 0x0200 MQ200 - -/* Middle Digital, Inc. products */ -product MIDDLE_DIGITAL WEASEL_VGA 0x9050 Weasel Virtual VGA -product MIDDLE_DIGITAL WEASEL_SERIAL 0x9051 Weasel Serial Port -product MIDDLE_DIGITAL WEASEL_CONTROL 0x9052 Weasel Control - -/* Motorola products */ -product MOT MPC105 0x0001 MPC105 \"Eagle\" Host Bridge -product MOT MPC106 0x0002 MPC106 \"Grackle\" Host Bridge -product MOT MPC8240 0x0003 MPC8240 \"Kahlua\" Host Bridge -product MOT MPC107 0x0004 MPC107 \"Chaparral\" Host Bridge -product MOT MPC8245 0x0006 MPC8245 \"Kahlua II\" Host Bridge -product MOT RAVEN 0x4801 Raven Host Bridge & Multi-Processor Interrupt Controller -product MOT FALCON 0x4802 Falcon ECC Memory Controller Chip Set -product MOT HAWK 0x4803 Hawk System Memory Controller & PCI Host Bridge - -/* Mylex products */ -product MYLEX RAID_V2 0x0001 DAC960 RAID (v2 interface) -product MYLEX RAID_V3 0x0002 DAC960 RAID (v3 interface) -product MYLEX RAID_V4 0x0010 DAC960 RAID (v4 interface) -product MYLEX RAID_V5 0x0020 DAC960 RAID (v5 interface) -product MYLEX ACCELERAID 0x0050 AcceleRAID (i960) -product MYLEX EXTREMERAID 0xba56 eXtremeRAID (StrongARM) - -/* Mylex subsystem IDs */ -product MYLEX ACCELERAID_352 0x0050 AcceleRAID 352 -product MYLEX ACCELERAID_170 0x0052 AcceleRAID 170 -product MYLEX ACCELERAID_160 0x0054 AcceleRAID 160 -product MYLEX EXTREMERAID_2000 0x0040 eXtremeRAID 2000 -product MYLEX EXTREMERAID_3000 0x0030 eXtremeRAID 3000 - -/* Mutech products */ -product MUTECH MV1000 0x0001 MV1000 - -/* Myson-Century Technology products */ -product MYSON MTD803 0x0803 MTD803 3-in-1 Fast Ethernet Controller - -/* National Datacomm Corp. products */ -product NDC NCP130 0x0130 NCP130 Wireless NIC -product NDC NCP130A2 0x0131 NCP130 rev A2 Wireless NIC - -/* NetVin products - XXX better descriptions */ -product NETVIN 5000 0x5000 5000 Ethernet - -/* NetBoost (now Intel) products */ -product NETBOOST POLICY 0x0000 Policy Accelerator - -/* Newbridge / Tundra products */ -product NEWBRIDGE CA91CX42 0x0000 Universe VME bridge -product NEWBRIDGE CA91L826A 0x0826 QSpan II PCI bridge -product NEWBRIDGE CA91L8260 0x8260 PowerSpan PCI bridge -product NEWBRIDGE CA91L8261 0x8261 PowerSpan II PCI bridge - -/* National Instruments products */ -product NATIONALINST MXI3 0x2c30 MXI-3 PCI extender - -/* National Semiconductor products */ -product NS DP83810 0x0001 DP83810 10/100 Ethernet -product NS DP83815 0x0020 DP83815 10/100 Ethernet -product NS DP83820 0x0022 DP83820 10/100/1000 Ethernet -product NS NS87410 0xd001 NS87410 -product NS SC1100_ISA 0x0510 SC1100 PCI-ISA bridge -product NS SC1100_ACPI 0x0511 SC1100 SMI/ACPI -product NS SC1100_IDE 0x0512 SC1100 PCI IDE -product NS SC1100_AUDIO 0x0513 SC1100 XpressAUDIO -product NS SC1100_XBUS 0x0515 SC1100 X-Bus - -/* Philips products */ -product PHILIPS SAA7130HL 0x7130 SAA7130HL PCI video broadcast decoder -product PHILIPS SAA7133HL 0x7133 SAA7133HL PCI A/V broadcast decoder -product PHILIPS SAA7134HL 0x7134 SAA7134HL PCI A/V broadcast decoder -product PHILIPS SAA7135HL 0x7135 SAA7135HL PCI A/V broadcast decoder -product PHILIPS SAA7146AH 0x7146 SAA7146AH PCI Multimedia bridge - -/* NCR/Symbios Logic products */ -product SYMBIOS 810 0x0001 53c810 -product SYMBIOS 820 0x0002 53c820 -product SYMBIOS 825 0x0003 53c825 -product SYMBIOS 815 0x0004 53c815 -product SYMBIOS 810AP 0x0005 53c810AP -product SYMBIOS 860 0x0006 53c860 -product SYMBIOS 1510D 0x000a 53c1510D -product SYMBIOS 896 0x000b 53c896 -product SYMBIOS 895 0x000c 53c895 -product SYMBIOS 885 0x000d 53c885 -product SYMBIOS 875 0x000f 53c875/876 -product SYMBIOS 1510 0x0010 53c1510 -product SYMBIOS 895A 0x0012 53c895A -product SYMBIOS 875A 0x0013 53c875A -product SYMBIOS 1010 0x0020 53c1010 -product SYMBIOS 1010_2 0x0021 53c1010 (66MHz) -product SYMBIOS 1030 0x0030 53c1030 -product SYMBIOS 1030R 0x1030 53c1030R -product SYMBIOS 875J 0x008f 53c875J -product SYMBIOS FC909 0x0620 FC909 -product SYMBIOS FC909A 0x0621 FC909A -product SYMBIOS FC929 0x0622 FC929 -product SYMBIOS FC929_1 0x0623 FC929 -product SYMBIOS FC919 0x0624 FC919 -product SYMBIOS FC919_1 0x0625 FC919 -product SYMBIOS FC929X 0x0626 FC929X - -/* Packet Engines products */ -product SYMBIOS PE_GNIC 0x0702 Packet Engines G-NIC Ethernet - -/* NEC products */ -product NEC USB 0x0035 USB Host Controller -product NEC VRC4173_CARDU 0x003e VRC4173 PC-Card Unit -product NEC POWERVR2 0x0046 PowerVR PCX2 -product NEC PD72872 0x0063 uPD72872 IEEE 1394 OHCI Host Controller -product NEC VRC4173_BCU 0x00a5 VRC4173 Bus Control Unit -product NEC VRC4173_AC97U 0x00a6 VRC4173 AC97 Unit -product NEC PD72870 0x00cd uPD72870 IEEE 1394 OHCI Host Controller -product NEC PD72871 0x00ce uPD72871 IEEE 1394 OHCI Host Controller -product NEC PD720100A 0x00e0 USB Host Controller -product NEC VA26D 0x803c NEC Versa Pro LX VA26D -product NEC VERSALX 0x8058 NEC Versa LX - -/* Neomagic products */ -product NEOMAGIC NMMG2070 0x0001 MagicGraph NM2070 -product NEOMAGIC NMMG128V 0x0002 MagicGraph 128V -product NEOMAGIC NMMG128ZV 0x0003 MagicGraph 128ZV -product NEOMAGIC NMMG2160 0x0004 MagicGraph 128XD -product NEOMAGIC NMMM256AV_VGA 0x0005 MagicMedia 256AV VGA -product NEOMAGIC NMMM256ZX_VGA 0x0006 MagicMedia 256ZX VGA -product NEOMAGIC NMMM256XLP_AU 0x0016 MagicMedia 256XL+ Audio -product NEOMAGIC NMMM256AV_AU 0x8005 MagicMedia 256AV Audio -product NEOMAGIC NMMM256ZX_AU 0x8006 MagicMedia 256ZX Audio - -/* Netgear products */ -product NETGEAR GA620 0x620a GA620 1000baseSX Gigabit Ethernet -product NETGEAR GA620T 0x630a GA620 1000baseT Gigabit Ethernet -product NETGEAR MA301 0x4100 MA301 PCI IEEE 802.11b - -/* Netmos products */ -product NETMOS NM9805 0x9805 1284 Printer port -product NETMOS NM9815 0x9815 Dual 1284 Printer port -product NETMOS NM9835 0x9835 Dual UART and 1284 Printer port -product NETMOS NM9845 0x9845 Quad UART and 1284 Printer port - -/* Network Security Technologies, Inc. */ -product NETSEC 7751 0x7751 7751 - -/* NexGen products */ -product NEXGEN NX82C501 0x4e78 NX82C501 Host-PCI Bridge - -/* NKK products */ -product NKK NDR4600 0xa001 NDR4600 Host-PCI Bridge - -/* Nortel products */ -product NORTEL BAYSTACK_21 0x1211 Baystack 21 (Accton MPX EN5038) - -/* Number Nine products */ -product NUMBER9 I128 0x2309 Imagine-128 -product NUMBER9 I128_2 0x2339 Imagine-128 II - -/* Nvidia Corporation products */ -product NVIDIA EDGE3D 0x0008 Edge 3D -product NVIDIA EDGE3D2 0x0009 Edge 3D -product NVIDIA RIVA128 0x0018 Riva 128 -product NVIDIA RIVA128ZX 0x0019 Riva 128ZX -product NVIDIA RIVATNT 0x0020 Riva TNT -product NVIDIA RIVATNT2 0x0028 Riva TNT2 -product NVIDIA RIVATNT2U 0x0029 Riva TNT2 Ultra -product NVIDIA RIVATNT2_2 0x002a Riva TNT2 -product NVIDIA VANTA 0x002c Vanta -product NVIDIA RIVATNT2M64 0x002d RIVA TNT2 Model 64 -product NVIDIA MCP04_LAN1 0x0037 MCP04 Lan -product NVIDIA MCP04_LAN2 0x0038 MCP04 Lan -product NVIDIA GEFORCE6800U 0x0040 GeForce 6800 Ultra -product NVIDIA GEFORCE6800 0x0041 GeForce 6800 -product NVIDIA GEFORCE6800LE 0x0042 GeForce 6800 LE -product NVIDIA GEFORCE6800GT 0x0045 GeForce 6800 GT -product NVIDIA QUADROFX4000 0x004e Quadro FX 4000 -product NVIDIA CK804_LAN1 0x0056 CK804 Lan -product NVIDIA CK804_LAN2 0x0057 CK804 Lan -product NVIDIA NFORCE2_MCP2ISA 0x0060 nForce2 MCP2 ISA Bridge -product NVIDIA NFORCE2_MCPTSMB 0x0064 nForce2 MCP-T SMBus Controller -product NVIDIA NFORCE2_ATA133 0x0065 nForce2 ATA133 IDE -product NVIDIA NFORCE2_LAN 0x0066 nForce2 Lan -product NVIDIA NFORCE2_MCPT_AC 0x006a nForce2 MCP-T AC-97 -product NVIDIA NFORCE_MCPT_AC 0x006b nForce MCP-T AC-97 -product NVIDIA NFORCE_PCIB 0x006c nForce PCI-to-PCI Bridge -product NVIDIA NFORCE3_LAN2 0x0086 nForce3 Lan -product NVIDIA NFORCE3_LAN3 0x008c nForce3 Lan -product NVIDIA ALADDINTNT2 0x00a0 Aladdin TNT2 -product NVIDIA NFORCE3_PCHB 0x00d1 nForce3 Host-PCI bridge -product NVIDIA NFORCE3_PCIB 0x00d0 nForce3 PCI-ISA bridge -product NVIDIA NFORCE3_SMBUS 0x00d4 nForce3 SMBus controller -product NVIDIA NFORCE3_ATA133 0x00d5 nForce3 ATA133 IDE -product NVIDIA NFORCE3_LAN1 0x00d6 nForce3 Lan -product NVIDIA NFORCE3_OHCI 0x00d7 nForce3 USB Host Controller -product NVIDIA NFORCE3_EHCI 0x00d8 nForce3 USB2 Host Controller -product NVIDIA NFORCE3_MCPT_AC 0x00da nForce3 MCP-T AC-97 -product NVIDIA NFORCE3_PPB 0x00dd nForce3 PCI-PCI bridge -product NVIDIA NFORCE3_LAN4 0x00df nForce3 Lan -product NVIDIA NFORCE3_LAN5 0x00e6 nForce3 Lan -product NVIDIA QUADROFX3400 0x00f8 Quadro FX 3400 -product NVIDIA GEFORCE6800U2 0x00f9 GeForce 6800 Ultra -product NVIDIA GEFORCEPCX5750 0x00fa GeForce PCX 5750 -product NVIDIA GEFORCEPCX5900 0x00fb GeForce PCX 5900 -product NVIDIA GEFORCEPCX5300 0x00fc GeForce PCX 5300 -product NVIDIA QUADROPCIE 0x00fd Quadro PCI-E Series -product NVIDIA QUADROFX13000 0x00fe Quadro FX 13000 -product NVIDIA GEFORCEPCX4300 0x00ff GeForce PCX 4300 -product NVIDIA GEFORCE256 0x0100 GeForce 256 -product NVIDIA GEFORCEDDR 0x0101 GeForce DDR -product NVIDIA QUADRO 0x0103 Quadro -product NVIDIA GEFORCE2MX 0x0110 GeForce2 MX -product NVIDIA GEFORCE2MX200 0x0111 GeForce2 MX 100/200 -product NVIDIA GEFORCE2GO 0x0112 GeForce2 Go -product NVIDIA QUADRO2_MXR 0x0113 Quadro2 MXR/EX -product NVIDIA GEFORCE2 0x0150 GeForce2 GTS -product NVIDIA GEFORCE2DDR 0x0151 GeForce2 GTS (DDR) -product NVIDIA GEFORCE2BR 0x0152 GeForce2 GTS -product NVIDIA QUADRO2 0x0153 Quadro2 -product NVIDIA GEFORCE4_MX460 0x0170 GeForce4 MX 460 -product NVIDIA GEFORCE4_MX440 0x0171 GeForce4 MX 440 -product NVIDIA GEFORCE4_MX420 0x0172 GeForce4 MX 420 -product NVIDIA GF4_MX440_SE 0x0173 GeForce4 MX 440 SE -product NVIDIA QUADRO4_500XGL 0x0178 Quadro4 500 XGL -product NVIDIA QUADRO4_200NVS 0x017a Quadro4 200/400NVS -product NVIDIA GF4_MX440_8X 0x0181 GeForce4 MX 440 (AGP8X) -product NVIDIA GF4_MX440_SE_8X 0x0182 GeForce4 MX 440 SE (AGP8X) -product NVIDIA GF4_MX420_8X 0x0183 GeForce4 MX 420 (AGP8X) -product NVIDIA GEFORCE4_448GO 0x0186 GeForce4 448 Go -product NVIDIA QUADRO4_580XGL 0x0188 Quadro4 580 XGL -product NVIDIA QUADRO4_280NVS 0x018a Quadro4 280 NVS -product NVIDIA QUADRO4_380XGL 0x018b Quadro4 380 XGL -product NVIDIA GEFORCE4_448GO2 0x018d GeForce4 448 Go -product NVIDIA GEFORCE2_IGP 0x01a0 GeForce2 Integrated GPU -product NVIDIA NFORCE_MCP_AC 0x01b1 nForce MCP AC-97 -product NVIDIA NFORCE_ATA100 0x01bc nForce ATA100 IDE -product NVIDIA NFORCE_LAN 0x01c3 nForce Lan -product NVIDIA NFORCE2_AGP 0x01e0 nForce2 AGP Controller -product NVIDIA NFORCE2_AGP2 0x01e1 nForce2 AGP Controller -product NVIDIA NFORCE2_PCI 0x01e8 nForce2 Host-to-PCI Bridge -product NVIDIA NFORCE2_MEM0 0x01ea nForce2 Memory Controller #0 -product NVIDIA NFORCE2_MEM1 0x01eb nForce2 Memory Controller #1 -product NVIDIA NFORCE2_MEM2 0x01ec nForce2 Memory Controller #2 -product NVIDIA NFORCE2_MEM3 0x01ed nForce2 Memory Controller #3 -product NVIDIA NFORCE2_MEM4 0x01ee nForce2 Memory Controller #4 -product NVIDIA NFORCE2_MEM5 0x01ef nForce2 Memory Controller #5 -product NVIDIA GF4_MX_IGP 0x01f0 GeForce4 MX Integrated GPU -product NVIDIA GEFORCE3 0x0200 GeForce3 -product NVIDIA GEFORCE3_TI200 0x0201 GeForce3 Ti 200 -product NVIDIA GEFORCE3_TI500 0x0202 GeForce3 Ti 500 -product NVIDIA QUADRO_DCC 0x0203 Quadro DCC -product NVIDIA GEFORCE4_TI4600 0x0250 GeForce4 Ti 4600 -product NVIDIA GEFORCE4_TI4400 0x0251 GeForce4 Ti 4400 -product NVIDIA GEFORCE4_TI4200 0x0253 GeForce4 Ti 4200 -product NVIDIA QUADRO4_900XGL 0x0258 Quadro4 900 XGL -product NVIDIA QUADRO4_750XGL 0x0259 Quadro4 750 XGL -product NVIDIA QUADRO4_700XGL 0x025b Quadro4 700 XGL -product NVIDIA MCP51_LAN1 0x0268 MCP51 Lan -product NVIDIA MCP51_LAN2 0x0269 MCP51 Lan -product NVIDIA GF4_TI_4800 0x0280 GeForce4 Ti 4800 -product NVIDIA GF4_TI_4200_8X 0x0281 GeForce4 Ti 4200 (AGP8X) -product NVIDIA GF4_TI_4800_SE 0x0282 GeForce4 Ti 4800 SE -product NVIDIA GF4_4200GO 0x0286 GeForce4 4200 Go -product NVIDIA QUADRO4_980_XGL 0x0288 Quadro4 980 XGL -product NVIDIA QUADRO4_780_XGL 0x0289 Quadro4 780 XGL -product NVIDIA QUADRO4_700_GGL 0x028c Quadro4 700 GoGL -product NVIDIA GEFORCE_FX5800U 0x0301 GeForce FX 5800 Ultra -product NVIDIA GEFORCE_FX5800 0x0302 GeForce FX 5800 -product NVIDIA QUADRO_FX_2000 0x0308 Quadro FX 2000 -product NVIDIA QUADRO_FX_1000 0x0309 Quadro FX 1000 -product NVIDIA ICEFX2000 0x030a ICE FX 2000 -product NVIDIA GF_FX5600U 0x0311 GeForce FX 5600 Ultra -product NVIDIA GF_FX5600 0x0312 GeForce FX 5600 -product NVIDIA GF_FX5600_SE 0x0314 GeForce FX 5600 SE -product NVIDIA GF_FX5200U 0x0321 GeForce FX 5200 Ultra -product NVIDIA GF_FX5200 0x0322 GeForce FX 5200 -product NVIDIA GF_FX5200SE 0x0323 GeForce FX 5200 SE -product NVIDIA GF_FXGO5250 0x0325 GeForce FX Go 5250 -product NVIDIA GF_FX5500 0x0326 GeForce FX 5500 -product NVIDIA GF_FX5100 0x0327 GeForce FX 5100 -product NVIDIA QUADRO_FX_500 0x032b Quadro FX 500 -product NVIDIA GF_FXGO5100 0x032d GeForce FX Go5100 -product NVIDIA GF_FX5900U 0x0330 GeForce FX 5900 Ultra -product NVIDIA GF_FX5900 0x0331 GeForce FX 5900 -product NVIDIA GF_FX5900XT 0x0332 GeForce FX 5900 XT -product NVIDIA GF_FX5950U 0x0333 GeForce FX 5950 Ultra -product NVIDIA GF_FX5900ZT 0x0334 GeForce FX 5900 ZT -product NVIDIA QUADRO_FX_3000 0x0338 Quadro FX 3000 -product NVIDIA GF_FX5700U 0x0342 GeForce FX 5700 Ultra -product NVIDIA GF_FX5700 0x0342 GeForce FX 5700 -product NVIDIA GF_FX5700LE 0x0343 GeForce FX 5700 LE -product NVIDIA GF_FX5700VE 0x0344 GeForce FX 5700 VE -product NVIDIA NV365 0x0345 NV36.5 -product NVIDIA GF_FXGO5600 0x0348 GeForce FX Go5600 -product NVIDIA QUADRO_FX_1100 0x034e Quadro FX 1100 -product NVIDIA MCP55_LAN1 0x0372 MCP55 Lan -product NVIDIA MCP55_LAN2 0x0373 MCP55 Lan -product NVIDIA MCP61_LAN1 0x03e5 MCP61 Lan -product NVIDIA MCP61_LAN2 0x03e6 MCP61 Lan -product NVIDIA MCP61_LAN3 0x03ee MCP61 Lan -product NVIDIA MCP61_LAN4 0x03ef MCP61 Lan -product NVIDIA MCP65_AHCI_1 0x044c MCP65 AHCI -product NVIDIA MCP65_AHCI_2 0x044d MCP65 AHCI -product NVIDIA MCP65_AHCI_3 0x044e MCP65 AHCI -product NVIDIA MCP65_AHCI_4 0x044f MCP65 AHCI -product NVIDIA MCP65_LAN1 0x0450 MCP65 Lan -product NVIDIA MCP65_LAN2 0x0451 MCP65 Lan -product NVIDIA MCP65_LAN3 0x0452 MCP65 Lan -product NVIDIA MCP65_LAN4 0x0453 MCP65 Lan -product NVIDIA MCP67_LAN1 0x054c MCP67 Lan -product NVIDIA MCP67_LAN2 0x054d MCP67 Lan -product NVIDIA MCP67_LAN3 0x054e MCP67 Lan -product NVIDIA MCP67_LAN4 0x054f MCP67 Lan -product NVIDIA MCP67_SATA 0x0550 MCP67 SATA -product NVIDIA MCP67_SATA2 0x0551 MCP67 SATA -product NVIDIA MCP67_SATA3 0x0552 MCP67 SATA -product NVIDIA MCP67_SATA4 0x0553 MCP67 SATA -product NVIDIA MCP67_AHCI_1 0x0554 MCP67 AHCI -product NVIDIA MCP67_AHCI_2 0x0555 MCP67 AHCI -product NVIDIA MCP67_AHCI_3 0x0556 MCP67 AHCI -product NVIDIA MCP67_AHCI_4 0x0557 MCP67 AHCI -product NVIDIA MCP67_AHCI_5 0x0558 MCP67 AHCI -product NVIDIA MCP67_AHCI_6 0x0559 MCP67 AHCI -product NVIDIA MCP67_AHCI_7 0x055a MCP67 AHCI -product NVIDIA MCP67_AHCI_8 0x055b MCP67 AHCI -product NVIDIA MCP77_LAN1 0x0760 MCP77 Lan -product NVIDIA MCP77_LAN2 0x0761 MCP77 Lan -product NVIDIA MCP77_LAN3 0x0762 MCP77 Lan -product NVIDIA MCP77_LAN4 0x0763 MCP77 Lan -product NVIDIA MCP73_LAN1 0x07dc MCP73 Lan -product NVIDIA MCP73_LAN2 0x07dd MCP73 Lan -product NVIDIA MCP73_LAN3 0x07de MCP73 Lan -product NVIDIA MCP73_LAN4 0x07df MCP73 Lan -product NVIDIA MCP73_AHCI_1 0x07f0 MCP73 AHCI -product NVIDIA MCP73_AHCI_2 0x07f1 MCP73 AHCI -product NVIDIA MCP73_AHCI_3 0x07f2 MCP73 AHCI -product NVIDIA MCP73_AHCI_4 0x07f3 MCP73 AHCI -product NVIDIA MCP73_AHCI_5 0x07f4 MCP73 AHCI -product NVIDIA MCP73_AHCI_6 0x07f5 MCP73 AHCI -product NVIDIA MCP73_AHCI_7 0x07f6 MCP73 AHCI -product NVIDIA MCP73_AHCI_8 0x07f7 MCP73 AHCI -product NVIDIA MCP73_AHCI_9 0x07f8 MCP73 AHCI -product NVIDIA MCP73_AHCI_10 0x07f9 MCP73 AHCI -product NVIDIA MCP73_AHCI_11 0x07fa MCP73 AHCI -product NVIDIA MCP73_AHCI_12 0x07fb MCP73 AHCI -product NVIDIA MCP79_LAN1 0x0ab0 MCP79 Lan -product NVIDIA MCP79_LAN2 0x0ab1 MCP79 Lan -product NVIDIA MCP79_LAN3 0x0ab2 MCP79 Lan -product NVIDIA MCP79_LAN4 0x0ab3 MCP79 Lan -product NVIDIA MCP77_AHCI_1 0x0ad0 MCP77 AHCI -product NVIDIA MCP77_AHCI_2 0x0ad1 MCP77 AHCI -product NVIDIA MCP77_AHCI_3 0x0ad2 MCP77 AHCI -product NVIDIA MCP77_AHCI_4 0x0ad3 MCP77 AHCI -product NVIDIA MCP77_AHCI_5 0x0ad4 MCP77 AHCI -product NVIDIA MCP77_AHCI_6 0x0ad5 MCP77 AHCI -product NVIDIA MCP77_AHCI_7 0x0ad6 MCP77 AHCI -product NVIDIA MCP77_AHCI_8 0x0ad7 MCP77 AHCI -product NVIDIA MCP77_AHCI_9 0x0ad8 MCP77 AHCI -product NVIDIA MCP77_AHCI_10 0x0ad9 MCP77 AHCI -product NVIDIA MCP77_AHCI_11 0x0ada MCP77 AHCI -product NVIDIA MCP77_AHCI_12 0x0adb MCP77 AHCI - - -/* Nvidia Corporation & SGS-Thomson Microelectronics */ -product NVIDIA_SGS RIVA128 0x0018 Riva 128 - -/* Oak Technologies products */ -product OAKTECH OTI1007 0x0107 OTI107 - -/* Olicom products */ -product OLICOM OC2183 0x0013 Olicom OC-2183/2185 Ethernet -product OLICOM OC2325 0x0012 Olicom OC-2325 Ethernet -product OLICOM OC2326 0x0014 Olicom OC-2326 10/100-TX Ethernet - -/* Opti products */ -product OPTI 82C557 0xc557 82C557 -product OPTI 82C558 0xc558 82C558 -product OPTI 82C568 0xc568 82C568 -product OPTI 82D568 0xd568 82D568 -product OPTI 82C621 0xc621 82C621 -product OPTI 82C822 0xc822 82C822 -product OPTI RM861HA 0xc861 RM861HA -product OPTI 82C700 0xc700 82C700 -product OPTI 82C701 0xc701 82C701 - -/* pcHDTV products */ -product PCHDTV HD2000 0x2000 HD-2000 HDTV video capture - -/* PC Tech products */ -product PCTECH RZ1000 0x1000 RZ1000 - -/* Peak System Technik products */ -product PEAK PCAN 0x0001 PCAN CAN controller - -/* Peppercon products */ -product PEPPERCON ROLF 0x8139 ROL/F-100 Fast Ethernet Adapter with ROL - -/* Planex products */ -product PLANEX FNW_3800_TX 0xab07 FNW-3800-TX 10/100 Ethernet - -/* PLX Technology products */ -product PLX 9060ES 0x906e 9060ES PCI bus controller -product PLX 9656 0x9656 9656 I/O Accelerator - -/* Powerhouse Systems products */ -product POWERHOUSE POWERTOP 0x6037 PowerTop PowerPC system controller -product POWERHOUSE POWERPRO 0x6073 PowerPro PowerPC system controller - -/* ProLAN products - XXX better descriptions */ -product PROLAN NE2KETHER 0x1980 Ethernet - -/* Promise products */ -product PROMISE PDC20246 0x4d33 PDC20246 Ultra/33 IDE controller -product PROMISE PDC20262 0x4d38 PDC20262 Ultra/66 IDE controller -product PROMISE PDC20263 0x0d38 PDC20263 Ultra/66 IDE controller -product PROMISE PDC20265 0x0d30 PDC20265 Ultra/100 IDE controller -product PROMISE PDC20267 0x4d30 PDC20267 Ultra/100 IDE controller -product PROMISE PDC20268 0x4d68 PDC20268 Ultra/100 IDE controller -product PROMISE PDC20269 0x4d69 PDC20269 Ultra/133 IDE controller -product PROMISE PDC20270 0x6268 PDC20270 Ultra/100 IDE controller -product PROMISE PDC20271 0x6269 PDC20271 Ultra/133 IDE controller -product PROMISE PDC20275 0x1275 PDC20275 Ultra/133 IDE controller -product PROMISE PDC20276 0x5275 PDC20276 Ultra/133 IDE controller -product PROMISE PDC20277 0x7275 PDC20277 Ultra/133 IDE controller -product PROMISE PDC20318 0x3318 PDC20318 SATA/150 IDE controller -product PROMISE PDC20319 0x3319 PDC20319 SATA/150 IDE controller -product PROMISE PDC20371 0x3371 PDC20371 SATA/150 IDE controller -product PROMISE PDC20375 0x3375 PDC20375 SATA/150 IDE controller -product PROMISE PDC20376 0x3376 PDC20376 SATA/150 IDE controller -product PROMISE PDC20377 0x3377 PDC20377 SATA/150 IDE controller -product PROMISE PDC20378 0x3373 PDC20378 SATA/150 IDE controller -product PROMISE PDC20379 0x3372 PDC20379 SATA/150 IDE controller -product PROMISE PDC20617 0x6617 PDC20617 dual Ultra/133 IDE controller -product PROMISE PDC20618 0x6626 PDC20618 dual Ultra/133 IDE controller -product PROMISE PDC20619 0x6629 PDC20619 dual Ultra/133 IDE controller -product PROMISE PDC20620 0x6620 PDC20620 dual Ultra/133 IDE controller -product PROMISE PDC20621 0x6621 PDC20621 dual Ultra/133 IDE controller - -/* QLogic products */ -product QLOGIC ISP1020 0x1020 ISP1020 -product QLOGIC ISP1022 0x1022 ISP1022 -product QLOGIC ISP1080 0x1080 ISP1080 -product QLOGIC ISP1240 0x1240 ISP1240 -product QLOGIC ISP2100 0x2100 ISP2100 - -/* Quantum Designs products */ -product QUANTUMDESIGNS 8500 0x0001 8500 -product QUANTUMDESIGNS 8580 0x0002 8580 - -/* Rainbow Technologies products */ -product RAINBOW CS200 0x0200 CryptoSwift 200 PKI Accelerator - -/* Ralink Technologies products */ -product RALINK RT2560 0x0201 RT2560 802.11b/g -product RALINK RT2561S 0x0301 RT2561S 802.11b/g -product RALINK RT2561 0x0302 RT2561 802.11b/g -product RALINK RT2661 0x0401 RT2661 802.11b/g/n - -/* RATOC Systems products */ -product RATOC REXPCI31 0x0853 REX PCI-31/33 SCSI - -/* Realtek (Creative Labs?) products */ -product REALTEK RT8029 0x8029 8029 Ethernet -product REALTEK RT8129 0x8129 8129 10/100 Ethernet -product REALTEK RT8101E 0x8136 8101E PCIe 10/10 Ethernet -product REALTEK RT8139B 0x8138 8139B 10/100 Ethernet -product REALTEK RT8139 0x8139 8139 10/100 Ethernet -product REALTEK RT8169SC 0x8167 8169SC/8110SC Single-chip Gigabit Ethernet -product REALTEK RT8168 0x8168 8168/8111B PCIe Gigabit Ethernet -product REALTEK RT8169 0x8169 8169 10/100/1000 Ethernet -product REALTEK RT8180 0x8180 8180 802.11b - -/* RICOH products */ -product RICOH Rx5C465 0x0465 5C465 PCI-CardBus bridge -product RICOH Rx5C466 0x0466 5C466 PCI-CardBus bridge -product RICOH Rx5C475 0x0475 5C475 PCI-CardBus bridge -product RICOH RL5C476 0x0476 5C476 PCI-CardBus bridge -product RICOH Rx5C477 0x0477 5C477 PCI-CardBus bridge -product RICOH Rx5C478 0x0478 5C478 PCI-CardBus bridge -product RICOH Rx5C551 0x0551 5C551 PCI-CardBus bridge/Firewire -product RICOH Rx5C552 0x0552 5C552 PCI-CardBus bridge/Firewire - -/* RISCom (SDL Communications, Inc?) products */ -product RISCOM N2 0x5568 N2 - -/* RNS products */ -product RNS FDDI 0x2200 2200 FDDI - -/* S3 products */ -product S3 VIRGE 0x5631 ViRGE -product S3 TRIO32 0x8810 Trio32 -product S3 TRIO64 0x8811 Trio32/64 -product S3 AURORA64P 0x8812 Aurora64V+ -product S3 TRIO64UVP 0x8814 Trio64UV+ -product S3 VIRGE_VX 0x883d ViRGE/VX -product S3 868 0x8880 868 -product S3 928 0x88b0 86C928 -product S3 864_0 0x88c0 86C864-0 (\"Vision864\") -product S3 864_1 0x88c1 86C864-1 (\"Vision864\") -product S3 864_2 0x88c2 86C864-2 (\"Vision864\") -product S3 864_3 0x88c3 86C864-3 (\"Vision864\") -product S3 964_0 0x88d0 86C964-0 (\"Vision964\") -product S3 964_1 0x88d1 86C964-1 (\"Vision964\") -product S3 964_2 0x88d2 86C964-2 (\"Vision964\") -product S3 964_3 0x88d3 86C964-3 (\"Vision964\") -product S3 968_0 0x88f0 86C968-0 (\"Vision968\") -product S3 968_1 0x88f1 86C968-1 (\"Vision968\") -product S3 968_2 0x88f2 86C968-2 (\"Vision968\") -product S3 968_3 0x88f3 86C968-3 (\"Vision968\") -product S3 TRIO64V2_DX 0x8901 Trio64V2/DX -product S3 PLATO_PX 0x8901 Plato/PX -product S3 TRIO3D 0x8904 86C365 Trio3D -product S3 VIRGE_DX 0x8a01 ViRGE/DX -product S3 VIRGE_GX2 0x8a10 ViRGE/GX2 -product S3 TRIO3D2X 0x8a13 Trio3D/2X -product S3 SAVAGE3D 0x8a20 Savage3D -product S3 SAVAGE3D_MV 0x8a21 Savage3D+MV -product S3 SAVAGE4 0x8a22 Savage4 -product S3 VIRGE_MX 0x8c01 ViRGE/MX -product S3 VIRGE_MXP 0x8c03 ViRGE/MXP -product S3 SAVAGE_MX_MV 0x8c10 Savage/MX+MV -product S3 SAVAGE_MX 0x8c11 Savage/MX -product S3 SAVAGE_IX_MV 0x8c12 Savage/IX+MV -product S3 SAVAGE_IX 0x8c13 Savage/IX -product S3 SAVAGE_IXC 0x8c2e Savage/IXC -product S3 SAVAGE2000 0x9102 Savage2000 -product S3 SONICVIBES 0xca00 SonicVibes - -/* Samsung Semiconductor products */ -product SAMSUNGSEMI KS8920 0x8920 KS8920 10/100 Ethernet - -/* Sandburst products */ -product SANDBURST QE1000 0x0180 QE1000 -product SANDBURST FE1000 0x0200 FE1000 -/*product SANDBURST SE1600 0x0100 SE1600*/ - -/* SEGA Enterprises products */ -product SEGA BROADBAND 0x1234 Broadband Adapter - -/* ServerWorks products */ -product SERVERWORKS XX5 0x0005 PCIHB5 -product SERVERWORKS CIOB20 0x0006 I/O Bridge -product SERVERWORKS XX7 0x0007 PCIHB7 -product SERVERWORKS CNB20HE 0x0008 CNB20HE Host -product SERVERWORKS CNB20LE 0x0009 CNB20LE Host -product SERVERWORKS CIOB30 0x0010 CIOB30 -product SERVERWORKS CMIC_HE 0x0011 CMIC_HE Host -product SERVERWORKS CMIC_LE 0x0012 CMIC_LE Host -product SERVERWORKS CMIC_SL 0x0017 CMIC_SL Host -product SERVERWORKS CIOBX2 0x0101 CIOB-X2 -product SERVERWORKS OSB4 0x0200 OSB4 SouthBridge -product SERVERWORKS CSB5 0x0201 CSB5 SouthBridge -product SERVERWORKS CSB6 0x0203 CSB6 SouthBridge -product SERVERWORKS OSB4_IDE 0x0211 OSB4 IDE -product SERVERWORKS CSB5_IDE 0x0212 CSB5 IDE -product SERVERWORKS CSB6_RAID 0x0213 CSB6 RAID/IDE -product SERVERWORKS CSB6_IDE 0x0217 CSB6 IDE -product SERVERWORKS OSB4_USB 0x0220 OSB4/CSB5 USB Host Controller -product SERVERWORKS CSB6_USB 0x0221 CSB6 USB Host Controller -product SERVERWORKS CSB6_IB 0x0227 CSB6 ISA bridge - -/* SGI products */ -product SGI IOC3 0x0003 IOC3 -product SGI RAD1 0x0005 PsiTech RAD1 -product SGI TIGON 0x0009 Tigon Gigabit Ethernet - -/* SGS-Thomson products */ -product SGSTHOMSON 2000 0x0008 STG 2000X -product SGSTHOMSON 1764 0x1746 STG 1764X - -/* Broadcom Corp. (SiByte) products */ -product SIBYTE BCM1250_PCIHB 0x0001 BCM1250 PCI Host Bridge -product SIBYTE BCM1250_LDTHB 0x0002 BCM1250 LDT Host Bridge - -/* Sigma Designs products */ -product SIGMA HOLLYWOODPLUS 0x8300 REALmagic Hollywood-Plus MPEG-2 Decoder - -/* SIIG Inc products */ -product SIIG CYBER10_S550 0x1000 Cyber10x Serial 16550 PCI -product SIIG CYBER10_S650 0x1001 Cyber10x Serial 16650 PCI -product SIIG CYBER10_S850 0x1002 Cyber10x Serial 16850 PCI -product SIIG CYBER10_IO550 0x1010 Cyber10x I/O 16550 PCI -product SIIG CYBER10_IO650 0x1011 Cyber10x I/O 16650 PCI -product SIIG CYBER10_IO850 0x1010 Cyber10x I/O 16850 PCI -product SIIG CYBER10_P 0x1020 Cyber10x Parallel PCI -product SIIG CYBER10_2P 0x1021 Cyber10x Parallel Dual PCI -product SIIG CYBER10_2S550 0x1030 Cyber10x Serial Dual 16550 PCI -product SIIG CYBER10_2S650 0x1031 Cyber10x Serial Dual 16650 PCI -product SIIG CYBER10_2S850 0x1032 Cyber10x Serial Dual 16850 PCI -product SIIG CYBER10_2S1P550 0x1034 Cyber10x 2S1P 16550 PCI -product SIIG CYBER10_2S1P650 0x1035 Cyber10x 2S1P 16650 PCI -product SIIG CYBER10_2S1P850 0x1036 Cyber10x 2S1P 16850 PCI -product SIIG CYBER10_4S550 0x1050 Cyber10x 4S 16550 PCI -product SIIG CYBER10_4S650 0x1051 Cyber10x 4S 16650 PCI -product SIIG CYBER10_4S850 0x1052 Cyber10x 4S 16850 PCI -product SIIG CYBER20_S550 0x2000 Cyber20x Serial 16550 PCI -product SIIG CYBER20_S650 0x2001 Cyber20x Serial 16650 PCI -product SIIG CYBER20_S850 0x2002 Cyber20x Serial 16850 PCI -product SIIG CYBER20_IO550 0x2010 Cyber20x I/O 16550 PCI -product SIIG CYBER20_IO650 0x2011 Cyber20x I/O 16650 PCI -product SIIG CYBER20_IO850 0x2010 Cyber20x I/O 16850 PCI -product SIIG CYBER20_P 0x2020 Cyber20x Parallel PCI -product SIIG CYBER20_2P 0x2021 Cyber20x Parallel Dual PCI -product SIIG CYBER20_2S550 0x2030 Cyber20x Serial Dual 16550 PCI -product SIIG CYBER20_2S650 0x2031 Cyber20x Serial Dual 16650 PCI -product SIIG CYBER20_2S850 0x2032 Cyber20x Serial Dual 16850 PCI -product SIIG CYBER20_2P1S550 0x2040 Cyber20x 2P1S 16550 PCI -product SIIG CYBER20_2P1S650 0x2041 Cyber20x 2P1S 16650 PCI -product SIIG CYBER20_2P1S850 0x2042 Cyber20x 2P1S 16850 PCI -product SIIG CYBER20_4S550 0x2050 Cyber20x 4S 16550 PCI -product SIIG CYBER20_4S650 0x2051 Cyber20x 4S 16650 PCI -product SIIG CYBER20_4S850 0x2052 Cyber20x 4S 16850 PCI -product SIIG CYBER20_2S1P550 0x2060 Cyber20x 2S1P 16550 PCI -product SIIG CYBER20_2S1P650 0x2061 Cyber20x 2S1P 16650 PCI -product SIIG CYBER20_2S1P850 0x2062 Cyber20x 2S1P 16850 PCI - -/* Hangzhou Silan Microelectronics products */ -product SILAN SC92031 0x2031 SC92031 based fast ethernet adapter -product SILAN 8139D 0x8139 8139D fast ethernet adapter - -/* Silicon Integrated System products */ -product SIS 86C201 0x0001 86C201 -product SIS 86C202 0x0002 86C202 -product SIS 86C205 0x0005 86C205 -product SIS 85C503 0x0008 85C503 or 5597/5598 ISA bridge -product SIS 600PMC 0x0009 600 Power Mngmt Controller -product SIS 5597_VGA 0x0200 5597/5598 integrated VGA -product SIS 85C501 0x0406 85C501 -product SIS 85C496 0x0496 85C496 -product SIS 530HB 0x0530 530 Host to PCI Bridge -product SIS 540HB 0x0540 540 Host to PCI Bridge -product SIS 550HB 0x0550 550 Host to PCI Bridge -product SIS 85C601 0x0601 85C601 -product SIS 620 0x0620 SiS 620 Host Bridge -product SIS 630 0x0630 SiS 630 Host Bridge -product SIS 633 0x0633 SiS 633 Host Bridge -product SIS 635 0x0635 SiS 635 Host Bridge -product SIS 640 0x0640 SiS 640 Host Bridge -product SIS 645 0x0645 SiS 645 Host Bridge -product SIS 646 0x0646 SiS 646 Host Bridge -product SIS 648 0x0648 SiS 648 Host Bridge -product SIS 650 0x0650 SiS 650 Host Bridge -product SIS 651 0x0651 SiS 651 Host Bridge -product SIS 652 0x0652 SiS 652 Host Bridge -product SIS 655 0x0655 SiS 655 Host Bridge -product SIS 658 0x0658 SiS 658 Host Bridge -product SIS 730 0x0730 SiS 730 Host Bridge -product SIS 733 0x0733 SiS 733 Host Bridge -product SIS 735 0x0735 SiS 735 Host Bridge -product SIS 740 0x0740 SiS 740 Host Bridge -product SIS 745 0x0745 SiS 745 Host Bridge -product SIS 746 0x0746 SiS 746 Host Bridge -product SIS 748 0x0748 SiS 748 Host Bridge -product SIS 750 0x0750 SiS 750 Host Bridge -product SIS 751 0x0751 SiS 751 Host Bridge -product SIS 752 0x0752 SiS 752 Host Bridge -product SIS 755 0x0755 SiS 755 Host Bridge -product SIS 900 0x0900 SiS 900 10/100 Ethernet -product SIS 961 0x0961 SiS 961 Host Bridge -product SIS 962 0x0962 SiS 962 Host Bridge -product SIS 963 0x0963 SiS 963 Host Bridge -product SIS 5597_IDE 0x5513 5597/5598 IDE controller -product SIS 5597_HB 0x5597 5597/5598 host bridge -product SIS 530VGA 0x6306 530 GUI Accelerator+3D -product SIS 6325 0x6325 6325 AGP VGA -product SIS 6326 0x6326 6326 AGP VGA -product SIS 5597_USB 0x7001 5597/5598 USB host controller -product SIS 7002 0x7002 7002 USB 2.0 host controller -product SIS 7012_AC 0x7012 SiS 7012 AC-97 Sound -product SIS 7016 0x7016 SiS 7016 10/100 Ethernet -product SIS 7018 0x7018 SiS 7018 Sound - -/* Silicon Motion, Inc. products */ -product SILMOTION SM710 0x0710 LynxEM -product SILMOTION SM712 0x0712 LynxEM+ -product SILMOTION SM720 0x0720 Lynx3DM -product SILMOTION SM810 0x0810 LynxE -product SILMOTION SM811 0x0811 LynxE -product SILMOTION SM820 0x0820 Lynx3D -product SILMOTION SM910 0x0910 Lynx - -/* SMC products */ -product SMC 37C665 0x1000 FDC 37C665 -product SMC 37C922 0x1001 FDC 37C922 -product SMC 83C170 0x0005 83C170 (\"EPIC/100\") Fast Ethernet -product SMC 83C175 0x0006 83C175 (\"EPIC/100\") Fast Ethernet - -/* Solidum Systems Corporation */ -product SOLIDUM AMD971 0x2000 SNP8023: AMD 971 -product SOLIDUM CLASS802 0x8023 SNP8023: Classifier Engine -product SOLIDUM PAXWARE1100 0x1100 PAX.ware 1100 dual Gb Classifier Engine - -/* Sony products */ -product SONY CXD1947A 0x8009 CXD1947A IEEE 1394 Host Controller -product SONY CXD3222 0x8039 CXD3222 OHCI IEEE 1394 Host Controller -product SONY MEMSTICK 0x808a Memory Stick I/F Controller - -/* Sun Microsystems, Inc. products */ -product SUN EBUS 0x1000 PCIO Ebus2 -product SUN HMENETWORK 0x1001 PCIO Happy Meal Ethernet -product SUN EBUSIII 0x1100 PCIO Ebus2 (US III) -product SUN ERINETWORK 0x1101 ERI Ethernet -product SUN FIREWIRE 0x1102 FireWire controller -product SUN USB 0x1103 USB controller -product SUN GEMNETWORK 0x2bad GEM Gigabit Ethernet -product SUN SIMBA 0x5000 Simba PCI bridge -product SUN 5821 0x5454 Sun bcm5821 -product SUN SCA1K 0x5455 Crypto Accelerator 1000 -product SUN PSYCHO 0x8000 psycho PCI controller -product SUN MS_IIep 0x9000 microSPARC IIep PCI -product SUN US_IIi 0xa000 UltraSPARC IIi PCI -product SUN US_IIe 0xa001 UltraSPARC IIe PCI - -/* Sundance Technology products */ -product SUNDANCETI ST201 0x0201 ST201 10/100 Ethernet -product SUNDANCETI ST2021 0x2021 ST2021 Gigabit Ethernet - -/* Surecom Technology products */ -product SURECOM NE34 0x0e34 NE-34 Ethernet - -/* Symphony Labs products */ -product SYMPHONY 82C101 0x0001 82C101 -product SYMPHONY 82C103 0x0103 82C103 -product SYMPHONY 82C105 0x0105 82C105 -product SYMPHONY2 82C101 0x0001 82C101 -product SYMPHONY 83C553 0x0565 83C553 PCI-ISA Bridge - -/* Schneider & Koch (really SysKonnect) products */ -product SCHNEIDERKOCH SKNET_FDDI 0x4000 SK-NET FDDI-xP -product SCHNEIDERKOCH SKNET_GE 0x4300 SK-NET GE -product SCHNEIDERKOCH SK9821v2 0x4320 SK-9821 v2.0 -product SCHNEIDERKOCH SK_9DX1 0x4400 SK-NET SK-9DX1 Gigabit Ethernet -product SCHNEIDERKOCH SK9Sxx 0x9000 SK-9Sxx -product SCHNEIDERKOCH SK9Exx 0x9e00 SK-9Exx -/* These next two are are really subsystem IDs */ -product SCHNEIDERKOCH SK_9D21 0x4421 SK-9D21 1000BASE-T -product SCHNEIDERKOCH SK_9D41 0x4441 SK-9D41 1000BASE-X - -/* TTTech */ -product TTTECH MC322 0x000a MC322 - -/* Tamarack Microelectronics, Inc. */ -product TAMARACK TC9021 0x1021 Tamarack TC9021 Gigabit Ethernet -product TAMARACK TC9021_ALT 0x9021 Tamarack TC9021 Gigabit Ethernet (alt ID) - -/* Tandem Computers */ -product TANDEM SERVERNETII 0x0005 ServerNet II VIA adapter - -/* Tekram Technology products (1st PCI Vendor ID) */ -product TEKRAM DC290 0xdc29 DC-290(M) - -/* Tekram Technology products (2nd PCI Vendor ID) */ -product TEKRAM2 DC690C 0x690c DC-690C -product TEKRAM2 DC315 0x0391 DC-315/DC-395 - -/* Texas Instruments products */ -product TI TLAN 0x0500 TLAN -product TI TVP4020 0x3d07 TVP4020 Permedia 2 -product TI TSB12LV21 0x8000 TSB12LV21 IEEE 1394 Host Controller -product TI TSB12LV22 0x8009 TSB12LV22 OHCI IEEE 1394 Host Controller -product TI PCI4450LYNX 0x8011 PCI4450 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI PCI4410LYNX 0x8017 PCI4410 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI TSB12LV23 0x8019 TSB12LV23 OHCI IEEE 1394 Host Controller -product TI TSB12LV26 0x8020 TSB12LV26 OHCI IEEE 1394 Host Controller -product TI TSB43AA22 0x8021 TSB43AA22 OHCI IEEE 1394 Host Controller -product TI TSB43AA22A 0x8023 TSB43AA22/A OHCI IEEE 1394 Host Controller -product TI TSB43AA23 0x8024 TSB43AA23 OHCI IEEE 1394 Host Controller -product TI TSB43AB21 0x8026 TSB43AA21 OHCI IEEE 1394 Host Controller -product TI PCI4451LYNX 0x8027 PCI4451 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI PCI4510LYNX 0x8029 PCI4510 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI PCI4520LYNX 0x802A PCI4520 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI PCI7410LYNX 0x802B PCI7[4-6]10 OHCI IEEE 1394 HOST Controller w/ PCI-CardBus Bridge -product TI ACX100A 0x8400 ACX100A 802.11b -product TI ACX100B 0x8401 ACX100B 802.11b -product TI ACX111 0x9066 ACX111 802.11b/g -product TI PCI1130 0xac12 PCI1130 PCI-CardBus Bridge -product TI PCI1031 0xac13 PCI1031 PCI-PCMCIA Bridge -product TI PCI1131 0xac15 PCI1131 PCI-CardBus Bridge -product TI PCI1250 0xac16 PCI1250 PCI-CardBus Bridge -product TI PCI1220 0xac17 PCI1220 PCI-CardBus Bridge -product TI PCI1221 0xac19 PCI1221 PCI-CardBus Bridge -product TI PCI1210 0xac1a PCI1210 PCI-CardBus Bridge -product TI PCI1450 0xac1b PCI1450 PCI-CardBus Bridge -product TI PCI1225 0xac1c PCI1225 PCI-CardBus Bridge -product TI PCI1251 0xac1d PCI1251 PCI-CardBus Bridge -product TI PCI1211 0xac1e PCI1211 PCI-CardBus Bridge -product TI PCI1251B 0xac1f PCI1251B PCI-CardBus Bridge -product TI PCI2030 0xac20 PCI2030 PCI-PCI Bridge -product TI PCI2050 0xac28 PCI2050 PCI-PCI Bridge -product TI PCI4450YENTA 0xac40 PCI4450 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI4410YENTA 0xac41 PCI4410 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI4451YENTA 0xac42 PCI4451 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI4510YENTA 0xac44 PCI4510 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI4520YENTA 0xac46 PCI4520 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI7510YENTA 0xac47 PCI7510 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI7610YENTA 0xac48 PCI7610 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI7410YENTA 0xac49 PCI7410 PCI-CardBus Bridge w/ OHCI IEEE 1394 Controller -product TI PCI7610SM 0xac4A PCI7610 PCI-CardBus Bridge (Smart Card mode) -product TI PCI7410SD 0xac4B PCI7[46]10 PCI-CardBus Bridge (SD/MMC mode) -product TI PCI7410MS 0xac4C PCI7[46]10 PCI-CardBus Bridge (Memory stick mode) -product TI PCI1410 0xac50 PCI1410 PCI-CardBus Bridge -product TI PCI1420 0xac51 PCI1420 PCI-CardBus Bridge -product TI PCI1451 0xac52 PCI1451 PCI-CardBus Bridge -product TI PCI1421 0xac53 PCI1421 PCI-CardBus Bridge -product TI PCI1620 0xac54 PCI1620 PCI-CardBus Bridge -product TI PCI1520 0xac55 PCI1520 PCI-CardBus Bridge -product TI PCI1510 0xac56 PCI1510 PCI-CardBus Bridge -product TI PCI1530 0xac57 PCI1530 PCI-CardBus Bridge -product TI PCI1515 0xac58 PCI1515 PCI-CardBus Bridge -product TI PCI2040 0xac60 PCI2040 PCI-to-DSP Bridge - -/* Titan Electronics products */ -product TITAN PCI800L 0x8080 PCI-800L -product TITAN PCI800H 0xa003 PCI-800H -product TITAN PCI100H 0xa001 PCI-100H - -/* Toshiba America products */ -product TOSHIBA R4X00 0x0009 R4x00 Host-PCI Bridge -product TOSHIBA TC35856F 0x0020 TC35856F ATM (\"Meteor\") - -/* Toshiba products */ -product TOSHIBA2 PORTEGE 0x0001 Portege Notebook -product TOSHIBA2 HOST 0x0601 Host Bridge/Controller -product TOSHIBA2 ISA 0x0602 ISA Bridge -product TOSHIBA2 ToPIC95 0x0603 ToPIC95 CardBus-PCI Bridge -product TOSHIBA2 ToPIC95B 0x060a ToPIC95B CardBus-PCI Bridge -product TOSHIBA2 ToPIC97 0x060f ToPIC97 CardBus-PCI Bridge -product TOSHIBA2 SMCARD 0x0804 Smart Media Controller -product TOSHIBA2 SDCARD 0x0805 Secure Digital Card Controller Type-A -product TOSHIBA2 ToPIC100 0x0617 ToPIC100 CardBus-PCI Bridge -product TOSHIBA2 OBOE 0x0701 Fast Infrared Type O -product TOSHIBA2 DONAUOBOE 0x0d01 Fast Infrared Type DO - -/* Transmeta products */ -product TRANSMETA NORTHBRIDGE 0x0295 Virtual Northbridge -product TRANSMETA LONGRUN 0x0395 LongRun Northbridge -product TRANSMETA SDRAM 0x0396 SDRAM Controller -product TRANSMETA BIOS_SCRATCH 0x0397 BIOS Scratchpad - -/* Trident products */ -product TRIDENT 4DWAVE_DX 0x2000 4DWAVE DX -product TRIDENT 4DWAVE_NX 0x2001 4DWAVE NX -product TRIDENT CYBERBLADE_I7 0x8420 CyberBlade i7 -product TRIDENT TGUI_9320 0x9320 TGUI 9320 -product TRIDENT TGUI_9350 0x9350 TGUI 9350 -product TRIDENT TGUI_9360 0x9360 TGUI 9360 -product TRIDENT CYBER_9397 0x9397 CYBER 9397 -product TRIDENT CYBER_9397DVD 0x939a CYBER 9397DVD -product TRIDENT CYBER_9525 0x9525 CYBER 9525 -product TRIDENT TGUI_9420 0x9420 TGUI 9420 -product TRIDENT TGUI_9440 0x9440 TGUI 9440 -product TRIDENT TGUI_9660 0x9660 TGUI 9660 -product TRIDENT TGUI_9680 0x9680 TGUI 9680 -product TRIDENT TGUI_9682 0x9682 TGUI 9682 -product TRIDENT CYBERBLADE 0x9910 CyberBlade - -/* Triones Technologies products */ -/* The 366 and 370 controllers have the same product ID */ -product TRIONES HPT343 0x0003 HPT343/345 IDE Controller -product TRIONES HPT366 0x0004 HPT366/370/372 IDE Controller -product TRIONES HPT372A 0x0005 HPT372A IDE Controller -product TRIONES HPT302 0x0006 HPT302 IDE Controller -product TRIONES HPT371 0x0007 HPT371 IDE Controller -product TRIONES HPT374 0x0008 HPT374 IDE Controller -product TRIONES HPT372N 0x0009 HPT372N IDE Controller - -/* TriTech Microelectronics products*/ -product TRITECH TR25202 0xfc02 Pyramid3D TR25202 - -/* Tseng Labs products */ -product TSENG ET4000_W32P_A 0x3202 ET4000w32p rev A -product TSENG ET4000_W32P_B 0x3205 ET4000w32p rev B -product TSENG ET4000_W32P_C 0x3206 ET4000w32p rev C -product TSENG ET4000_W32P_D 0x3207 ET4000w32p rev D -product TSENG ET6000 0x3208 ET6000 - -/* UMC products */ -product UMC UM82C881 0x0001 UM82C881 486 Chipset -product UMC UM82C886 0x0002 UM82C886 ISA Bridge -product UMC UM8673F 0x0101 UM8673F EIDE Controller -product UMC UM8881 0x0881 UM8881 HB4 486 PCI Chipset -product UMC UM82C891 0x0891 UM82C891 -product UMC UM886A 0x1001 UM886A -product UMC UM8886BF 0x673a UM8886BF -product UMC UM8710 0x8710 UM8710 -product UMC UM8886 0x886a UM8886 -product UMC UM8881F 0x8881 UM8881F PCI-Host bridge -product UMC UM8886F 0x8886 UM8886F PCI-ISA bridge -product UMC UM8886A 0x888a UM8886A -product UMC UM8891A 0x8891 UM8891A -product UMC UM9017F 0x9017 UM9017F -product UMC UM8886N 0xe88a UM8886N -product UMC UM8891N 0xe891 UM8891N - -/* ULSI Systems products */ -product ULSI US201 0x0201 US201 - -/* US Robotics products */ -product USR 3C2884A 0x1007 56K Voice Internal PCI Modem (WinModem) -product USR 3CP5609 0x1008 3CP5609 PCI 16550 Modem -product USR2 2415 0x3685 Wireless PCI-PCMCIA adapter -product USR2 997902 0x0116 Robotics 997902 Gigabit Ethernet - -/* V3 Semiconductor products */ -product V3 V292PBC 0x0292 V292PBC AMD290x0 Host-PCI Bridge -product V3 V960PBC 0x0960 V960PBC i960 Host-PCI Bridge -product V3 V96DPC 0xc960 V96DPC i960 (Dual) Host-PCI Bridge - -/* VIA Technologies products, from http://www.via.com.tw/ */ -product VIATECH VT6305 0x0130 VT6305 OHCI IEEE 1394 Controller -product VIATECH VT8363_HB 0x0305 VT8363 KT133 System Controller -product VIATECH VT8371_HB 0x0391 VT8371 (Apollo KX133) Host Bridge -product VIATECH VT8501_MVP4 0x0501 VT8501 MVP4 System Controller -product VIATECH VT82C505 0x0505 VT82C505 (Pluto) -product VIATECH VT82C561 0x0561 VT82C561 -product VIATECH VT82C586A_IDE 0x0571 VT82C586A IDE Controller -product VIATECH VT82C576 0x0576 VT82C576 3V -product VIATECH VT82C580VP 0x0585 VT82C580 (Apollo VP) Host-PCI Bridge -product VIATECH VT82C586_ISA 0x0586 VT82C586 (Apollo VP) PCI-ISA Bridge -product VIATECH VT82C595 0x0595 VT82C595 (Apollo VP2) Host-PCI Bridge -product VIATECH VT82C596A 0x0596 VT82C596A (Apollo Pro) PCI-ISA Bridge -product VIATECH VT82C597 0x0597 VT82C597 (Apollo VP3) Host-PCI Bridge -product VIATECH VT82C598PCI 0x0598 VT82C598 (Apollo MVP3) Host-PCI Bridge -product VIATECH VT8605PCI 0x0605 VT8605 (Apollo ProMedia 133) Host-PCI Bridge -product VIATECH VT82C686A_ISA 0x0686 VT82C686A (Apollo KX133) PCI-ISA Bridge -product VIATECH VT82C691 0x0691 VT82C691 (Apollo Pro) Host-PCI -product VIATECH VT82C693 0x0693 VT82C693 (Apollo Pro Plus) Host-PCI -product VIATECH VT86C926 0x0926 VT86C926 Amazon PCI-Ethernet Controller -product VIATECH VT82C570M 0x1000 VT82C570M (Apollo) Host-PCI Bridge -product VIATECH VT82C570MV 0x1006 VT82C570M (Apollo) PCI-ISA Bridge -product VIATECH VT82C586_IDE 0x1571 VT82C586 (Apollo VP) IDE Controller -product VIATECH VT82C595_2 0x1595 VT82C595 (Apollo VP2) Host-PCI Bridge -product VIATECH VT83C572 0x3038 VT83C572 USB Controller -product VIATECH VT82C586_PWR 0x3040 VT82C586 (Apollo VP) Power Management Controller -product VIATECH VT3043 0x3043 VT3043 (Rhine) 10/100 Ethernet -product VIATECH VT6306 0x3044 VT3606 OHCI IEEE 1394 Controller -product VIATECH VT6105M 0x3053 VT6105M (Rhine III) 10/100 Ethernet -product VIATECH VT82C686A_SMB 0x3057 VT82C686A SMBus Controller -product VIATECH VT82C686A_AC97 0x3058 VT82C686A AC-97 Audio Controller -product VIATECH VT8233_AC97 0x3059 VT8233/VT8235 AC-97 Audio Controller -product VIATECH VT6102 0x3065 VT6102 (Rhine II) 10/100 Ethernet -product VIATECH VT82C686A_MC97 0x3068 VT82C686A MC-97 Modem Controller -product VIATECH VT8233 0x3074 VT8233 PCI-ISA Bridge -product VIATECH VT8366 0x3099 VT8366 (Apollo KT266) CPU-PCI Bridge -product VIATECH VT8653 0x3101 VT8653 (Apollo Pro 266T) CPU-PCI Bridge -product VIATECH VT8237_EHCI 0x3104 VT8237 EHCI USB Controller -product VIATECH VT6105 0x3106 VT6105 (Rhine III) 10/100 Ethernet -product VIATECH VT612X 0x3119 VT612X 10/100/1000 Ethernet -product VIATECH VT8623_VGA 0x3122 VT8623 (Apollo CLE266) VGA Controller -product VIATECH VT8623 0x3123 VT8623 (Apollo CLE266) CPU-PCI Bridge -product VIATECH VT8233A 0x3147 VT8233A PCI-ISA Bridge -product VIATECH VT8237_SATA 0x3149 VT8237 Integrated SATA Controller -product VIATECH VT8235 0x3177 VT8235 (Apollo KT400) PCI-ISA Bridge -product VIATECH VT8377 0x3189 VT8377 Apollo KT400 CPU to PCI Bridge -product VIATECH VT8237 0x3227 VT8237 (Apollo KT600) PCI-ISA Bridge -product VIATECH VT8251_SATA 0x3349 VT8251 SATA -product VIATECH VT86C100A 0x6100 VT86C100A (Rhine-II) 10/100 Ethernet -product VIATECH VT8231 0x8231 VT8231 IDE Controller -product VIATECH VT8363_PPB 0x8305 VT8363 KT133 PCI to AGP Bridge -product VIATECH VT8371_PPB 0x8391 VT8371 (Apollo KX133) PCI-PCI Bridge -product VIATECH VT8501AGP 0x8501 VT8501 CPU-AGP Bridge -product VIATECH VT82C597AGP 0x8597 VT82C597 (Apollo VP3) CPU-AGP Bridge -product VIATECH VT82C598AGP 0x8598 VT82C598 (Apollo MVP3) CPU-AGP Bridge -product VIATECH VT8605AGP 0x8605 VT8605 (Apollo ProMedia 133) Host-AGP Bridge -product VIATECH VT8633AGP 0xb091 VT8633 (Apollo Pro 266) CPU-AGP Bridge -product VIATECH VT8366AGP 0xb099 VT8366 CPU-AGP Bridge -product VIATECH VT8377AGP 0xb168 VT8377 CPU-AGP Bridge -product VIATECH VT8377CEAGP 0xb198 VT8377CE CPU-AGP Bridge (KT600) - -/* Vortex Computer Systems products */ -product VORTEX GDT_60x0 0x0000 GDT6000/6020/6050 -product VORTEX GDT_6000B 0x0001 GDT6000B/6010 -product VORTEX GDT_6x10 0x0002 GDT6110/6510 -product VORTEX GDT_6x20 0x0003 GDT6120/6520 -product VORTEX GDT_6530 0x0004 GDT6530 -product VORTEX GDT_6550 0x0005 GDT6550 -product VORTEX GDT_6x17 0x0006 GDT6117/6517 -product VORTEX GDT_6x27 0x0007 GDT6127/6527 -product VORTEX GDT_6537 0x0008 GDT6537 -product VORTEX GDT_6557 0x0009 GDT6557/6557-ECC -product VORTEX GDT_6x15 0x000a GDT6115/6515 -product VORTEX GDT_6x25 0x000b GDT6125/6525 -product VORTEX GDT_6535 0x000c GDT6535 -product VORTEX GDT_6555 0x000d GDT6555/6555-ECC -product VORTEX GDT_6x17RP 0x0100 GDT6[15]17RP -product VORTEX GDT_6x27RP 0x0101 GDT6[15]27RP -product VORTEX GDT_6537RP 0x0102 GDT6537RP -product VORTEX GDT_6557RP 0x0103 GDT6557RP -product VORTEX GDT_6x11RP 0x0104 GDT6[15]11RP -product VORTEX GDT_6x21RP 0x0105 GDT6[15]21RP -product VORTEX GDT_6x17RD 0x0110 GDT6[15]17RD -product VORTEX GDT_6x27RD 0x0111 GDT6[5]127RD -product VORTEX GDT_6537RD 0x0112 GDT6537RD -product VORTEX GDT_6557RD 0x0113 GDT6557RD -product VORTEX GDT_6x11RD 0x0114 GDT6[15]11RD -product VORTEX GDT_6x21RD 0x0115 GDT6[15]21RD -product VORTEX GDT_6x18RD 0x0118 GDT6[156]18RD -product VORTEX GDT_6x28RD 0x0119 GDT6[156]28RD -product VORTEX GDT_6x38RD 0x011a GDT6[56]38RD -product VORTEX GDT_6x58RD 0x011b GDT6[56]58RD -product VORTEX GDT_6x17RP2 0x0120 GDT6[15]17RP2 -product VORTEX GDT_6x27RP2 0x0121 GDT6[15]27RP2 -product VORTEX GDT_6537RP2 0x0123 GDT6537RP2 -product VORTEX GDT_6x11RP2 0x0124 GDT6[15]11RP2 -product VORTEX GDT_6x21RP2 0x0125 GDT6[15]21RP2 -product VORTEX GDT_6x13RS 0x0136 GDT6513RS -product VORTEX GDT_6x23RS 0x0137 GDT6523RS -product VORTEX GDT_6518RS 0x0138 GDT6518RS -product VORTEX GDT_6x28RS 0x0139 GDT6x28RS -product VORTEX GDT_6x38RS 0x013a GDT6x38RS -product VORTEX GDT_6x58RS 0x013b GDT6x58RS -product VORTEX GDT_6x33RS 0x013c GDT6x33RS -product VORTEX GDT_6x43RS 0x013d GDT6x43RS -product VORTEX GDT_6x53RS 0x013e GDT6x53RS -product VORTEX GDT_6x63RS 0x013f GDT6x63RS -product VORTEX GDT_7x13RN 0x0166 GDT7x13RN -product VORTEX GDT_7x23RN 0x0167 GDT7x23RN -product VORTEX GDT_7x18RN 0x0168 GDT7[156]18RN -product VORTEX GDT_7x28RN 0x0169 GDT7[156]28RN -product VORTEX GDT_7x38RN 0x016a GDT7[56]38RN -product VORTEX GDT_7x58RN 0x016b GDT7[56]58RN -product VORTEX GDT_7x43RN 0x016d GDT7[56]43RN -product VORTEX GDT_7x53RN 0x016E GDT7x53RN -product VORTEX GDT_7x63RN 0x016F GDT7x63RN -product VORTEX GDT_4x13RZ 0x01D6 GDT4x13RZ -product VORTEX GDT_4x23RZ 0x01D7 GDT4x23RZ -product VORTEX GDT_8x13RZ 0x01F6 GDT8x13RZ -product VORTEX GDT_8x23RZ 0x01F7 GDT8x23RZ -product VORTEX GDT_8x33RZ 0x01FC GDT8x33RZ -product VORTEX GDT_8x43RZ 0x01FD GDT8x43RZ -product VORTEX GDT_8x53RZ 0x01FE GDT8x53RZ -product VORTEX GDT_8x63RZ 0x01FF GDT8x63RZ -product VORTEX GDT_6x19RD 0x0210 GDT6[56]19RD -product VORTEX GDT_6x29RD 0x0211 GDT6[56]29RD -product VORTEX GDT_7x19RN 0x0260 GDT7[56]19RN -product VORTEX GDT_7x29RN 0x0261 GDT7[56]29RN -product VORTEX GDT_ICP 0x0300 ICP - -/* VLSI products */ -product VLSI 82C592 0x0005 82C592 CPU Bridge -product VLSI 82C593 0x0006 82C593 ISA Bridge -product VLSI 82C594 0x0007 82C594 Wildcat System Controller -product VLSI 82C596597 0x0008 82C596/597 Wildcat ISA Bridge -product VLSI 82C541 0x000c 82C541 -product VLSI 82C543 0x000d 82C543 -product VLSI 82C532 0x0101 82C532 -product VLSI 82C534 0x0102 82C534 -product VLSI 82C535 0x0104 82C535 -product VLSI 82C147 0x0105 82C147 -product VLSI 82C975 0x0200 82C975 -product VLSI 82C925 0x0280 82C925 - -/* Weitek products */ -product WEITEK P9000 0x9001 P9000 -product WEITEK P9100 0x9100 P9100 - -/* Western Digital products */ -product WD WD33C193A 0x0193 WD33C193A -product WD WD33C196A 0x0196 WD33C196A -product WD WD33C197A 0x0197 WD33C197A -product WD WD7193 0x3193 WD7193 -product WD WD7197 0x3197 WD7197 -product WD WD33C296A 0x3296 WD33C296A -product WD WD34C296 0x4296 WD34C296 -product WD 90C 0xc24a 90C - -/* Winbond Electronics products */ -product WINBOND W83769F 0x0001 W83769F -product WINBOND W83C553F_0 0x0565 W83C553F PCI-ISA Bridge -product WINBOND W83C553F_1 0x0105 W83C553F IDE Controller -product WINBOND W89C840F 0x0840 W89C840F 10/100 Ethernet -product WINBOND W89C940F 0x0940 W89C940F Ethernet -product WINBOND W89C940F_1 0x5a5a W89C940F Ethernet -product WINBOND W6692 0x6692 W6692 ISDN - -/* Xircom products */ -/* is the `-3' here just indicating revision 3, or is it really part - of the device name? */ -product XIRCOM X3201_3 0x0002 X3201-3 Fast Ethernet Controller -/* this is the device id `indicating 21143 driver compatibility' */ -product XIRCOM X3201_3_21143 0x0003 X3201-3 Fast Ethernet Controller (21143) -product XIRCOM WINGLOBAL 0x000c WinGlobal Modem - -/* Yamaha products */ -product YAMAHA YMF724 0x0004 724 Audio -product YAMAHA YMF740 0x000a 740 Audio -product YAMAHA YMF740C 0x000c 740C (DS-1) Audio -product YAMAHA YMF724F 0x000d 724F (DS-1) Audio -product YAMAHA YMF744B 0x0010 744 (DS-1S) Audio -product YAMAHA YMF754 0x0012 754 (DS-1E) Audio - -/* Zeinet products */ -product ZEINET 1221 0x0001 1221 - -/* Ziatech products */ -product ZIATECH ZT8905 0x8905 PCI-ST32 Bridge - -/* Zoran products */ -product ZORAN ZR36120 0x6120 Video Controller diff --git a/sys/bus/pci/pcireg.h b/sys/bus/pci/pcireg.h index 98a0fdd3f6..d7f9d1641b 100644 --- a/sys/bus/pci/pcireg.h +++ b/sys/bus/pci/pcireg.h @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1997, Stefan Esser * All rights reserved. * @@ -23,30 +23,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/pcireg.h,v 1.24.2.5 2002/08/31 10:06:51 gibbs Exp $ - * $DragonFly: src/sys/bus/pci/pcireg.h,v 1.18 2008/07/06 05:47:14 sephe Exp $ + * $FreeBSD: src/sys/dev/pci/pcireg.h,v 1.64.2.4.2.1 2009/04/15 03:14:26 kensmith Exp $ * */ -#ifndef _BUS_PCI_PCIREG_H_ -#define _BUS_PCI_PCIREG_H_ +#ifndef _PCIREG_H_ +#define _PCIREG_H_ -#ifndef _SYS_TYPES_H_ #include -#endif typedef u_int16_t pci_vendor_id_t; typedef u_int16_t pci_product_id_t; - typedef u_int8_t pci_class_t; typedef u_int8_t pci_subclass_t; typedef u_int8_t pci_interface_t; typedef u_int8_t pci_revision_t; - typedef u_int8_t pci_intr_pin_t; typedef u_int8_t pci_intr_line_t; - -typedef u_int32_t pcireg_t; /* ~typical configuration space */ +typedef u_int32_t pcireg_t; /* ~typical configuration space */ /* * PCIM_xxx: mask to locate subfield in register @@ -61,483 +55,588 @@ typedef u_int32_t pcireg_t; /* ~typical configuration space */ /* some PCI bus constants */ -#define PCI_BUSMAX 255 -#define PCI_SLOTMAX 31 -#define PCI_FUNCMAX 7 -#define PCI_REGMAX 255 -#define PCI_MAXHDRTYPE 2 +#define PCI_BUSMAX 255 +#define PCI_SLOTMAX 31 +#define PCI_FUNCMAX 7 +#define PCI_REGMAX 255 +#define PCI_MAXHDRTYPE 2 /* PCI config header registers for all devices */ -#define PCIR_DEVVENDOR 0x00 -#define PCIR_VENDOR 0x00 -#define PCIR_DEVICE 0x02 - -#define PCIR_COMMAND 0x04 -#define PCIM_CMD_PORTEN 0x0001 -#define PCIM_CMD_MEMEN 0x0002 -#define PCIM_CMD_BUSMASTEREN 0x0004 -#define PCIM_CMD_MWRICEN 0x0010 -#define PCIM_CMD_PERRESPEN 0x0040 +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIR_CARDBUSCIS 0x28 +#define PCIM_CMD_PORTEN 0x0001 +#define PCIM_CMD_MEMEN 0x0002 +#define PCIM_CMD_BUSMASTEREN 0x0004 +#define PCIM_CMD_SPECIALEN 0x0008 +#define PCIM_CMD_MWRICEN 0x0010 +#define PCIM_CMD_PERRESPEN 0x0040 #define PCIM_CMD_SERRESPEN 0x0100 - -#define PCIR_STATUS 0x06 -#define PCIM_STATUS_CAPPRESENT 0x0010 -#define PCIM_STATUS_66CAPABLE 0x0020 -#define PCIM_STATUS_BACKTOBACK 0x0080 -#define PCIM_STATUS_PERRREPORT 0x0100 -#define PCIM_STATUS_SEL_FAST 0x0000 -#define PCIM_STATUS_SEL_MEDIMUM 0x0200 -#define PCIM_STATUS_SEL_SLOW 0x0400 -#define PCIM_STATUS_SEL_MASK 0x0600 -#define PCIM_STATUS_STABORT 0x0800 -#define PCIM_STATUS_RTABORT 0x1000 -#define PCIM_STATUS_RMABORT 0x2000 -#define PCIM_STATUS_SERR 0x4000 -#define PCIM_STATUS_PERR 0x8000 - -#define PCIR_REVID 0x08 -#define PCIR_PROGIF 0x09 -#define PCIR_SUBCLASS 0x0a -#define PCIR_CLASS 0x0b -#define PCIR_CACHELNSZ 0x0c -#define PCIR_LATTIMER 0x0d - -#define PCIR_HDRTYPE 0x0e -#define PCIM_HDRTYPE 0x7f -#define PCIM_HDRTYPE_NORMAL 0x00 -#define PCIM_HDRTYPE_BRIDGE 0x01 -#define PCIM_HDRTYPE_CARDBUS 0x02 -#define PCIM_MFDEV 0x80 - -#define PCIR_BIST 0x0f +#define PCIM_CMD_BACKTOBACK 0x0200 +#define PCIM_CMD_INTxDIS 0x0400 +#define PCIR_STATUS 0x06 +#define PCIM_STATUS_CAPPRESENT 0x0010 +#define PCIM_STATUS_66CAPABLE 0x0020 +#define PCIM_STATUS_BACKTOBACK 0x0080 +#define PCIM_STATUS_PERRREPORT 0x0100 +#define PCIM_STATUS_SEL_FAST 0x0000 +#define PCIM_STATUS_SEL_MEDIMUM 0x0200 +#define PCIM_STATUS_SEL_SLOW 0x0400 +#define PCIM_STATUS_SEL_MASK 0x0600 +#define PCIM_STATUS_STABORT 0x0800 +#define PCIM_STATUS_RTABORT 0x1000 +#define PCIM_STATUS_RMABORT 0x2000 +#define PCIM_STATUS_SERR 0x4000 +#define PCIM_STATUS_PERR 0x8000 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HDRTYPE 0x0e +#define PCIM_HDRTYPE 0x7f +#define PCIM_HDRTYPE_NORMAL 0x00 +#define PCIM_HDRTYPE_BRIDGE 0x01 +#define PCIM_HDRTYPE_CARDBUS 0x02 +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f /* Capability Register Offsets */ -#define PCICAP_ID 0x0 -#define PCICAP_NEXTPTR 0x1 - -/* Capability Identification Numbers */ -#define PCIY_PMG 0x01 /* PCI Power Management */ -#define PCIY_AGP 0x02 /* AGP */ -#define PCIY_VPD 0x03 /* Vital Product Data */ -#define PCIY_SLOTID 0x04 /* Slot Identification */ -#define PCIY_MSI 0x05 /* Message Signaled Interrupts */ -#define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */ -#define PCIY_PCIX 0x07 /* PCI-X */ -#define PCIY_HT 0x08 /* HyperTransport */ -#define PCIY_VENDOR 0x09 /* Vendor Unique */ -#define PCIY_DEBUG 0x0a /* Debug port */ -#define PCIY_CRES 0x0b /* CompactPCI central resource control */ -#define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */ -#define PCIY_AGP8X 0x0e /* AGP 8x */ -#define PCIY_SECDEV 0x0f /* Secure Device */ -#define PCIY_EXPRESS 0x10 /* PCI Express */ -#define PCIY_MSIX 0x11 /* MSI-X */ - -/* config registers for header type 0 devices */ - -#define PCIR_BARS 0x10 -#define PCIR_BAR(x) (PCIR_BARS + (x) * 4) -#define PCIR_MAPS PCIR_BARS /* DEPRECATED XXX */ -#define PCIR_CARDBUSCIS 0x28 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e -#define PCIR_BIOS 0x30 -#define PCIM_BIOS_ENABLE 0x01 -#define PCIR_CAP_PTR 0x34 -#define PCIR_INTLINE 0x3c -#define PCIR_INTPIN 0x3d -#define PCIR_MINGNT 0x3e -#define PCIR_MAXLAT 0x3f - -/* config registers for header type 1 devices */ - -#define PCIR_SECSTAT_1 0x1e - -#define PCIR_PRIBUS_1 0x18 -#define PCIR_SECBUS_1 0x19 -#define PCIR_SUBBUS_1 0x1a -#define PCIR_SECLAT_1 0x1b -#define PCIR_IOBASEL_1 0x1c -#define PCIR_IOLIMITL_1 0x1d -#define PCIR_IOBASEH_1 0x30 -#define PCIR_IOLIMITH_1 0x32 -#define PCIM_BRIO_16 0x0 -#define PCIM_BRIO_32 0x1 -#define PCIM_BRIO_MASK 0xf +#define PCICAP_ID 0x0 +#define PCICAP_NEXTPTR 0x1 -#define PCIR_MEMBASE_1 0x20 -#define PCIR_MEMLIMIT_1 0x22 - -#define PCIR_PMBASEL_1 0x24 -#define PCIR_PMLIMITL_1 0x26 -#define PCIR_PMBASEH_1 0x28 -#define PCIR_PMLIMITH_1 0x2c - -#define PCIR_BRIDGECTL_1 0x3e - -#define PCIR_SUBVEND_1 0x34 -#define PCIR_SUBDEV_1 0x36 - -/* config registers for header type 2 (Cardbus) devices */ - -#define PCIR_CAP_PTR_2 0x14 -#define PCIR_SECSTAT_2 0x16 - -#define PCIR_PRIBUS_2 0x18 -#define PCIR_SECBUS_2 0x19 -#define PCIR_SUBBUS_2 0x1a -#define PCIR_SECLAT_2 0x1b - -#define PCIR_MEMBASE0_2 0x1c -#define PCIR_MEMLIMIT0_2 0x20 -#define PCIR_MEMBASE1_2 0x24 -#define PCIR_MEMLIMIT1_2 0x28 -#define PCIR_IOBASE0_2 0x2c -#define PCIR_IOLIMIT0_2 0x30 -#define PCIR_IOBASE1_2 0x34 -#define PCIR_IOLIMIT1_2 0x38 +/* Capability Identification Numbers */ -#define PCIR_BRIDGECTL_2 0x3e +#define PCIY_PMG 0x01 /* PCI Power Management */ +#define PCIY_AGP 0x02 /* AGP */ +#define PCIY_VPD 0x03 /* Vital Product Data */ +#define PCIY_SLOTID 0x04 /* Slot Identification */ +#define PCIY_MSI 0x05 /* Message Signaled Interrupts */ +#define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */ +#define PCIY_PCIX 0x07 /* PCI-X */ +#define PCIY_HT 0x08 /* HyperTransport */ +#define PCIY_VENDOR 0x09 /* Vendor Unique */ +#define PCIY_DEBUG 0x0a /* Debug port */ +#define PCIY_CRES 0x0b /* CompactPCI central resource control */ +#define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */ +#define PCIY_SUBVENDOR 0x0d /* PCI-PCI bridge subvendor ID */ +#define PCIY_AGP8X 0x0e /* AGP 8x */ +#define PCIY_SECDEV 0x0f /* Secure Device */ +#define PCIY_EXPRESS 0x10 /* PCI Express */ +#define PCIY_MSIX 0x11 /* MSI-X */ -#define PCIR_SUBVEND_2 0x40 -#define PCIR_SUBDEV_2 0x42 +/* config registers for header type 0 devices */ -#define PCIR_PCCARDIF_2 0x44 +#define PCIR_BARS 0x10 +#define PCIR_MAPS PCIR_BARS +#define PCIR_BAR(x) (PCIR_BARS + (x) * 4) +#define PCIR_MAX_BAR_0 5 +#define PCI_RID2BAR(rid) (((rid) - PCIR_BARS) / 4) +#define PCI_BAR_IO(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) +#define PCI_BAR_MEM(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE) +#define PCIM_BAR_SPACE 0x00000001 +#define PCIM_BAR_MEM_SPACE 0 +#define PCIM_BAR_IO_SPACE 1 +#define PCIM_BAR_MEM_TYPE 0x00000006 +#define PCIM_BAR_MEM_32 0 +#define PCIM_BAR_MEM_1MB 2 /* Locate below 1MB in PCI <= 2.1 */ +#define PCIM_BAR_MEM_64 4 +#define PCIM_BAR_MEM_PREFETCH 0x00000008 +#define PCIM_BAR_MEM_BASE 0xfffffff0 +#define PCIM_BAR_IO_RESERVED 0x00000002 +#define PCIM_BAR_IO_BASE 0xfffffffc +#define PCIR_CIS 0x28 +#define PCIM_CIS_ASI_MASK 0x7 +#define PCIM_CIS_ASI_CONFIG 0 +#define PCIM_CIS_ASI_BAR0 1 +#define PCIM_CIS_ASI_BAR1 2 +#define PCIM_CIS_ASI_BAR2 3 +#define PCIM_CIS_ASI_BAR3 4 +#define PCIM_CIS_ASI_BAR4 5 +#define PCIM_CIS_ASI_BAR5 6 +#define PCIM_CIS_ASI_ROM 7 +#define PCIM_CIS_ADDR_MASK 0x0ffffff8 +#define PCIM_CIS_ROM_MASK 0xf0000000 +#define PCIM_CIS_CONFIG_MASK 0xff +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e +#define PCIR_BIOS 0x30 +#define PCIM_BIOS_ENABLE 0x01 +#define PCIM_BIOS_ADDR_MASK 0xfffff800 +#define PCIR_CAP_PTR 0x34 +#define PCIR_INTLINE 0x3c +#define PCIR_INTPIN 0x3d +#define PCIR_MINGNT 0x3e +#define PCIR_MAXLAT 0x3f + +/* config registers for header type 1 (PCI-to-PCI bridge) devices */ + +#define PCIR_MAX_BAR_1 1 +#define PCIR_SECSTAT_1 0x1e + +#define PCIR_PRIBUS_1 0x18 +#define PCIR_SECBUS_1 0x19 +#define PCIR_SUBBUS_1 0x1a +#define PCIR_SECLAT_1 0x1b + +#define PCIR_IOBASEL_1 0x1c +#define PCIR_IOLIMITL_1 0x1d +#define PCIR_IOBASEH_1 0x30 +#define PCIR_IOLIMITH_1 0x32 +#define PCIM_BRIO_16 0x0 +#define PCIM_BRIO_32 0x1 +#define PCIM_BRIO_MASK 0xf + +#define PCIR_MEMBASE_1 0x20 +#define PCIR_MEMLIMIT_1 0x22 + +#define PCIR_PMBASEL_1 0x24 +#define PCIR_PMLIMITL_1 0x26 +#define PCIR_PMBASEH_1 0x28 +#define PCIR_PMLIMITH_1 0x2c +#define PCIM_BRPM_32 0x0 +#define PCIM_BRPM_64 0x1 +#define PCIM_BRPM_MASK 0xf + +#define PCIR_BRIDGECTL_1 0x3e + +/* config registers for header type 2 (CardBus) devices */ + +#define PCIR_MAX_BAR_2 0 +#define PCIR_CAP_PTR_2 0x14 +#define PCIR_SECSTAT_2 0x16 + +#define PCIR_PRIBUS_2 0x18 +#define PCIR_SECBUS_2 0x19 +#define PCIR_SUBBUS_2 0x1a +#define PCIR_SECLAT_2 0x1b + +#define PCIR_MEMBASE0_2 0x1c +#define PCIR_MEMLIMIT0_2 0x20 +#define PCIR_MEMBASE1_2 0x24 +#define PCIR_MEMLIMIT1_2 0x28 +#define PCIR_IOBASE0_2 0x2c +#define PCIR_IOLIMIT0_2 0x30 +#define PCIR_IOBASE1_2 0x34 +#define PCIR_IOLIMIT1_2 0x38 + +#define PCIR_BRIDGECTL_2 0x3e + +#define PCIR_SUBVEND_2 0x40 +#define PCIR_SUBDEV_2 0x42 + +#define PCIR_PCCARDIF_2 0x44 /* PCI device class, subclass and programming interface definitions */ -#define PCIC_OLD 0x00 -#define PCIS_OLD_NONVGA 0x00 -#define PCIS_OLD_VGA 0x01 - -#define PCIC_STORAGE 0x01 -#define PCIS_STORAGE_SCSI 0x00 -#define PCIS_STORAGE_IDE 0x01 -#define PCIP_STORAGE_IDE_MODEPRIM 0x01 -#define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 -#define PCIP_STORAGE_IDE_MODESEC 0x04 -#define PCIP_STORAGE_IDE_PROGINDSEC 0x08 -#define PCIP_STORAGE_IDE_MASTERDEV 0x80 -#define PCIS_STORAGE_FLOPPY 0x02 -#define PCIS_STORAGE_IPI 0x03 -#define PCIS_STORAGE_RAID 0x04 -#define PCIS_STORAGE_ATA 0x05 -#define PCIP_STORAGE_ATA_SINGLEDMA 0x20 -#define PCIP_STORAGE_ATA_CHAINDMA 0x30 -#define PCIS_STORAGE_SATA 0x06 -#define PCIP_STORAGE_SATA_AHCI_1_0 0x01 -#define PCIS_STORAGE_SAS 0x07 -#define PCIP_STORAGE_SAS_VENDOR 0x00 -#define PCIP_STORAGE_SAS_SSB 0x01 -#define PCIS_STORAGE_OTHER 0x80 - -#define PCIC_NETWORK 0x02 -#define PCIS_NETWORK_ETHERNET 0x00 -#define PCIS_NETWORK_TOKENRING 0x01 -#define PCIS_NETWORK_FDDI 0x02 -#define PCIS_NETWORK_ATM 0x03 -#define PCIS_NETWORK_ISDN 0x04 -#define PCIS_NETWORK_WORLDFIP 0x05 -#define PCIS_NETWORK_PICMG 0x06 -#define PCIS_NETWORK_OTHER 0x80 - -#define PCIC_DISPLAY 0x03 -#define PCIS_DISPLAY_VGA 0x00 -#define PCIP_DISPLAY_VGA_COMP 0x00 -#define PCIP_DISPLAY_VGA_8514 0x01 -#define PCIS_DISPLAY_XGA 0x01 -#define PCIS_DISPLAY_3D 0x02 -#define PCIS_DISPLAY_OTHER 0x80 - -#define PCIC_MULTIMEDIA 0x04 -#define PCIS_MULTIMEDIA_VIDEO 0x00 -#define PCIS_MULTIMEDIA_AUDIO 0x01 -#define PCIS_MULTIMEDIA_TEL 0x02 -#define PCIS_MULTIMEDIA_OTHER 0x80 - -#define PCIC_MEMORY 0x05 -#define PCIS_MEMORY_RAM 0x00 -#define PCIS_MEMORY_FLASH 0x01 -#define PCIS_MEMORY_OTHER 0x80 - -#define PCIC_BRIDGE 0x06 -#define PCIS_BRIDGE_HOST 0x00 -#define PCIS_BRIDGE_ISA 0x01 -#define PCIS_BRIDGE_EISA 0x02 -#define PCIS_BRIDGE_MCA 0x03 -#define PCIS_BRIDGE_PCI 0x04 -#define PCIS_BRIDGE_PCMCIA 0x05 -#define PCIS_BRIDGE_NUBUS 0x06 -#define PCIS_BRIDGE_CARDBUS 0x07 -#define PCIS_BRIDGE_RACEWAY 0x08 -#define PCIS_BRIDGE_SEMITRANS 0x09 -#define PCIS_BRIDGE_INFINI 0x0a -#define PCIS_BRIDGE_OTHER 0x80 - -#define PCIC_SIMPLECOMM 0x07 -#define PCIS_SIMPLECOMM_UART 0x00 -#define PCIP_SIMPLECOMM_UART_16550A 0x02 -#define PCIS_SIMPLECOMM_PAR 0x01 -#define PCIS_SIMPLECOMM_MULTSER 0x02 -#define PCIS_SIMPLECOMM_MODEM 0x03 -#define PCIS_SIMPLECOMM_GPIB 0x04 -#define PCIS_SIMPLECOMM_SMART 0x05 -#define PCIS_SIMPLECOMM_OTHER 0x80 - -#define PCIC_BASEPERIPH 0x08 -#define PCIS_BASEPERIPH_PIC 0x00 -#define PCIS_BASEPERIPH_DMA 0x01 -#define PCIS_BASEPERIPH_TIMER 0x02 -#define PCIS_BASEPERIPH_RTC 0x03 -#define PCIS_BASEPERIPH_HOTPLUG 0x04 -#define PCIS_BASEPERIPH_OTHER 0x80 - -#define PCIC_INPUTDEV 0x09 -#define PCIS_INPUTDEV_KEYBOARD 0x00 -#define PCIS_INPUTDEV_DIGITIZER 0x01 -#define PCIS_INPUTDEV_MOUSE 0x02 -#define PCIS_INPUTDEV_SCANNER 0x03 -#define PCIS_INPUTDEV_GAMEPORT 0x04 -#define PCIS_INPUTDEV_OTHER 0x80 - -#define PCIC_DOCKING 0x0a -#define PCIS_DOCKING_GENERIC 0x00 -#define PCIS_DOCKING_OTHER 0x80 - -#define PCIC_PROCESSOR 0x0b -#define PCIS_PROCESSOR_386 0x00 -#define PCIS_PROCESSOR_486 0x01 -#define PCIS_PROCESSOR_PENTIUM 0x02 -#define PCIS_PROCESSOR_ALPHA 0x10 -#define PCIS_PROCESSOR_POWERPC 0x20 -#define PCIS_PROCESSOR_MIPS 0x30 -#define PCIS_PROCESSOR_COPROC 0x40 - -#define PCIC_SERIALBUS 0x0c -#define PCIS_SERIALBUS_FW 0x00 -#define PCIS_SERIALBUS_ACCESS 0x01 -#define PCIS_SERIALBUS_SSA 0x02 -#define PCIS_SERIALBUS_USB 0x03 -#define PCIS_SERIALBUS_FC 0x04 -#define PCIS_SERIALBUS_SMBUS 0x05 -#define PCIS_SERIALBUS_INFINI 0x06 -#define PCIS_SERIALBUS_IPMI 0x07 -#define PCIS_SERIALBUS_SERCOS 0x08 -#define PCIS_SERIALBUS_CANBUS 0x09 - -#define PCIC_WIRELESS 0x0d -#define PCIS_WIRELESS_IRDA 0x00 -#define PCIS_WIRELESS_IR 0x01 -#define PCIS_WIRELESS_RF 0x10 -#define PCIS_WIRELESS_BLUETOOTH 0x11 -#define PCIS_WIRELESS_BROADBAND 0x12 -#define PCIS_WIRELESS_80211A 0x20 -#define PCIS_WIRELESS_80211B 0x21 -#define PCIS_WIRELESS_OTHER 0x80 - -#define PCIC_I2O 0x0e -#define PCIS_I2O_10 0x00 - -#define PCIC_SATELLITE 0x0f -#define PCIS_SATELLITE_TV 0x01 -#define PCIS_SATELLITE_AUDIO 0x02 -#define PCIS_SATELLITE_VOICE 0x03 -#define PCIS_SATELLITE_DATA 0x04 - -#define PCIC_CRYPTO 0x10 -#define PCIS_CRYPTO_NETWORK 0x00 -#define PCIS_CRYPTO_ENTERTAIN 0x10 -#define PCIS_CRYPTO_OTHER 0x80 - -#define PCIC_SIGPROC 0x11 -#define PCIS_SIGPROC_DPIO 0x00 -#define PCIS_SIGPROC_PERFCOUNT 0x01 -#define PCIS_SIGPROC_COMMSYNC 0x10 -#define PCIS_SIGPROC_MANAGEMENT 0x20 -#define PCIS_SIGPROC_OTHER 0x80 - -#define PCIC_OTHER 0xff +#define PCIC_OLD 0x00 +#define PCIS_OLD_NONVGA 0x00 +#define PCIS_OLD_VGA 0x01 + +#define PCIC_STORAGE 0x01 +#define PCIS_STORAGE_SCSI 0x00 +#define PCIS_STORAGE_IDE 0x01 +#define PCIP_STORAGE_IDE_MODEPRIM 0x01 +#define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 +#define PCIP_STORAGE_IDE_MODESEC 0x04 +#define PCIP_STORAGE_IDE_PROGINDSEC 0x08 +#define PCIP_STORAGE_IDE_MASTERDEV 0x80 +#define PCIS_STORAGE_FLOPPY 0x02 +#define PCIS_STORAGE_IPI 0x03 +#define PCIS_STORAGE_RAID 0x04 +#define PCIS_STORAGE_ATA_ADMA 0x05 +#define PCIS_STORAGE_SATA 0x06 +#define PCIP_STORAGE_SATA_AHCI_1_0 0x01 +#define PCIS_STORAGE_SAS 0x07 +#define PCIS_STORAGE_OTHER 0x80 + +#define PCIC_NETWORK 0x02 +#define PCIS_NETWORK_ETHERNET 0x00 +#define PCIS_NETWORK_TOKENRING 0x01 +#define PCIS_NETWORK_FDDI 0x02 +#define PCIS_NETWORK_ATM 0x03 +#define PCIS_NETWORK_ISDN 0x04 +#define PCIS_NETWORK_WORLDFIP 0x05 +#define PCIS_NETWORK_PICMG 0x06 +#define PCIS_NETWORK_OTHER 0x80 + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 +#define PCIS_DISPLAY_XGA 0x01 +#define PCIS_DISPLAY_3D 0x02 +#define PCIS_DISPLAY_OTHER 0x80 + +#define PCIC_MULTIMEDIA 0x04 +#define PCIS_MULTIMEDIA_VIDEO 0x00 +#define PCIS_MULTIMEDIA_AUDIO 0x01 +#define PCIS_MULTIMEDIA_TELE 0x02 +#define PCIS_MULTIMEDIA_HDA 0x03 +#define PCIS_MULTIMEDIA_OTHER 0x80 + +#define PCIC_MEMORY 0x05 +#define PCIS_MEMORY_RAM 0x00 +#define PCIS_MEMORY_FLASH 0x01 +#define PCIS_MEMORY_OTHER 0x80 + +#define PCIC_BRIDGE 0x06 +#define PCIS_BRIDGE_HOST 0x00 +#define PCIS_BRIDGE_ISA 0x01 +#define PCIS_BRIDGE_EISA 0x02 +#define PCIS_BRIDGE_MCA 0x03 +#define PCIS_BRIDGE_PCI 0x04 +#define PCIP_BRIDGE_PCI_SUBTRACTIVE 0x01 +#define PCIS_BRIDGE_PCMCIA 0x05 +#define PCIS_BRIDGE_NUBUS 0x06 +#define PCIS_BRIDGE_CARDBUS 0x07 +#define PCIS_BRIDGE_RACEWAY 0x08 +#define PCIS_BRIDGE_PCI_TRANSPARENT 0x09 +#define PCIS_BRIDGE_INFINIBAND 0x0a +#define PCIS_BRIDGE_OTHER 0x80 + +#define PCIC_SIMPLECOMM 0x07 +#define PCIS_SIMPLECOMM_UART 0x00 +#define PCIP_SIMPLECOMM_UART_8250 0x00 +#define PCIP_SIMPLECOMM_UART_16450A 0x01 +#define PCIP_SIMPLECOMM_UART_16550A 0x02 +#define PCIP_SIMPLECOMM_UART_16650A 0x03 +#define PCIP_SIMPLECOMM_UART_16750A 0x04 +#define PCIP_SIMPLECOMM_UART_16850A 0x05 +#define PCIP_SIMPLECOMM_UART_16950A 0x06 +#define PCIS_SIMPLECOMM_PAR 0x01 +#define PCIS_SIMPLECOMM_MULSER 0x02 +#define PCIS_SIMPLECOMM_MODEM 0x03 +#define PCIS_SIMPLECOMM_GPIB 0x04 +#define PCIS_SIMPLECOMM_SMART_CARD 0x05 +#define PCIS_SIMPLECOMM_OTHER 0x80 + +#define PCIC_BASEPERIPH 0x08 +#define PCIS_BASEPERIPH_PIC 0x00 +#define PCIP_BASEPERIPH_PIC_8259A 0x00 +#define PCIP_BASEPERIPH_PIC_ISA 0x01 +#define PCIP_BASEPERIPH_PIC_EISA 0x02 +#define PCIP_BASEPERIPH_PIC_IO_APIC 0x10 +#define PCIP_BASEPERIPH_PIC_IOX_APIC 0x20 +#define PCIS_BASEPERIPH_DMA 0x01 +#define PCIS_BASEPERIPH_TIMER 0x02 +#define PCIS_BASEPERIPH_RTC 0x03 +#define PCIS_BASEPERIPH_PCIHOT 0x04 +#define PCIS_BASEPERIPH_SDHC 0x05 +#define PCIS_BASEPERIPH_OTHER 0x80 + +#define PCIC_INPUTDEV 0x09 +#define PCIS_INPUTDEV_KEYBOARD 0x00 +#define PCIS_INPUTDEV_DIGITIZER 0x01 +#define PCIS_INPUTDEV_MOUSE 0x02 +#define PCIS_INPUTDEV_SCANNER 0x03 +#define PCIS_INPUTDEV_GAMEPORT 0x04 +#define PCIS_INPUTDEV_OTHER 0x80 + +#define PCIC_DOCKING 0x0a +#define PCIS_DOCKING_GENERIC 0x00 +#define PCIS_DOCKING_OTHER 0x80 + +#define PCIC_PROCESSOR 0x0b +#define PCIS_PROCESSOR_386 0x00 +#define PCIS_PROCESSOR_486 0x01 +#define PCIS_PROCESSOR_PENTIUM 0x02 +#define PCIS_PROCESSOR_ALPHA 0x10 +#define PCIS_PROCESSOR_POWERPC 0x20 +#define PCIS_PROCESSOR_MIPS 0x30 +#define PCIS_PROCESSOR_COPROC 0x40 + +#define PCIC_SERIALBUS 0x0c +#define PCIS_SERIALBUS_FW 0x00 +#define PCIS_SERIALBUS_ACCESS 0x01 +#define PCIS_SERIALBUS_SSA 0x02 +#define PCIS_SERIALBUS_USB 0x03 +#define PCIP_SERIALBUS_USB_UHCI 0x00 +#define PCIP_SERIALBUS_USB_OHCI 0x10 +#define PCIP_SERIALBUS_USB_EHCI 0x20 +#define PCIP_SERIALBUS_USB_DEVICE 0xfe +#define PCIS_SERIALBUS_FC 0x04 +#define PCIS_SERIALBUS_SMBUS 0x05 +#define PCIS_SERIALBUS_INFINIBAND 0x06 +#define PCIS_SERIALBUS_IPMI 0x07 +#define PCIP_SERIALBUS_IPMI_SMIC 0x00 +#define PCIP_SERIALBUS_IPMI_KCS 0x01 +#define PCIP_SERIALBUS_IPMI_BT 0x02 +#define PCIS_SERIALBUS_SERCOS 0x08 +#define PCIS_SERIALBUS_CANBUS 0x09 + +#define PCIC_WIRELESS 0x0d +#define PCIS_WIRELESS_IRDA 0x00 +#define PCIS_WIRELESS_IR 0x01 +#define PCIS_WIRELESS_RF 0x10 +#define PCIS_WIRELESS_BLUETOOTH 0x11 +#define PCIS_WIRELESS_BROADBAND 0x12 +#define PCIS_WIRELESS_80211A 0x20 +#define PCIS_WIRELESS_80211B 0x21 +#define PCIS_WIRELESS_OTHER 0x80 + +#define PCIC_INTELLIIO 0x0e +#define PCIS_INTELLIIO_I2O 0x00 + +#define PCIC_SATCOM 0x0f +#define PCIS_SATCOM_TV 0x01 +#define PCIS_SATCOM_AUDIO 0x02 +#define PCIS_SATCOM_VOICE 0x03 +#define PCIS_SATCOM_DATA 0x04 + +#define PCIC_CRYPTO 0x10 +#define PCIS_CRYPTO_NETCOMP 0x00 +#define PCIS_CRYPTO_ENTERTAIN 0x10 +#define PCIS_CRYPTO_OTHER 0x80 + +#define PCIC_DASP 0x11 +#define PCIS_DASP_DPIO 0x00 +#define PCIS_DASP_PERFCNTRS 0x01 +#define PCIS_DASP_COMM_SYNC 0x10 +#define PCIS_DASP_MGMT_CARD 0x20 +#define PCIS_DASP_OTHER 0x80 + +#define PCIC_OTHER 0xff + +/* Bridge Control Values. */ +#define PCIB_BCR_PERR_ENABLE 0x0001 +#define PCIB_BCR_SERR_ENABLE 0x0002 +#define PCIB_BCR_ISA_ENABLE 0x0004 +#define PCIB_BCR_VGA_ENABLE 0x0008 +#define PCIB_BCR_MASTER_ABORT_MODE 0x0020 +#define PCIB_BCR_SECBUS_RESET 0x0040 +#define PCIB_BCR_SECBUS_BACKTOBACK 0x0080 +#define PCIB_BCR_PRI_DISCARD_TIMEOUT 0x0100 +#define PCIB_BCR_SEC_DISCARD_TIMEOUT 0x0200 +#define PCIB_BCR_DISCARD_TIMER_STATUS 0x0400 +#define PCIB_BCR_DISCARD_TIMER_SERREN 0x0800 /* PCI power manangement */ - -#define PCIR_POWER_CAP 0x2 -#define PCIM_PCAP_SPEC 0x0007 -#define PCIM_PCAP_PMEREQCLK 0x0008 -#define PCIM_PCAP_PMEREQPWR 0x0010 -#define PCIM_PCAP_DEVSPECINIT 0x0020 -#define PCIM_PCAP_DYNCLOCK 0x0040 -#define PCIM_PCAP_SECCLOCK 0x00c0 -#define PCIM_PCAP_CLOCKMASK 0x00c0 -#define PCIM_PCAP_REQFULLCLOCK 0x0100 -#define PCIM_PCAP_D1SUPP 0x0200 -#define PCIM_PCAP_D2SUPP 0x0400 -#define PCIM_PCAP_D0PME 0x1000 -#define PCIM_PCAP_D1PME 0x2000 -#define PCIM_PCAP_D2PME 0x4000 - -#define PCIR_POWER_STATUS 0x4 -#define PCIM_PSTAT_D0 0x0000 -#define PCIM_PSTAT_D1 0x0001 -#define PCIM_PSTAT_D2 0x0002 -#define PCIM_PSTAT_D3 0x0003 -#define PCIM_PSTAT_DMASK 0x0003 -#define PCIM_PSTAT_REPENABLE 0x0010 -#define PCIM_PSTAT_PMEENABLE 0x0100 -#define PCIM_PSTAT_D0POWER 0x0000 -#define PCIM_PSTAT_D1POWER 0x0200 -#define PCIM_PSTAT_D2POWER 0x0400 -#define PCIM_PSTAT_D3POWER 0x0600 -#define PCIM_PSTAT_D0HEAT 0x0800 -#define PCIM_PSTAT_D1HEAT 0x1000 -#define PCIM_PSTAT_D2HEAT 0x1200 -#define PCIM_PSTAT_D3HEAT 0x1400 -#define PCIM_PSTAT_DATAUNKN 0x0000 -#define PCIM_PSTAT_DATADIV10 0x2000 -#define PCIM_PSTAT_DATADIV100 0x4000 -#define PCIM_PSTAT_DATADIV1000 0x6000 -#define PCIM_PSTAT_DATADIVMASK 0x6000 -#define PCIM_PSTAT_PME 0x8000 - -#define PCIR_POWER_PMCSR 0x6 -#define PCIM_PMCSR_DCLOCK 0x10 -#define PCIM_PMCSR_B2SUPP 0x20 -#define PCIM_BMCSR_B3SUPP 0x40 -#define PCIM_BMCSR_BPCE 0x80 - -#define PCIR_POWER_DATA 0x7 +#define PCIR_POWER_CAP 0x2 +#define PCIM_PCAP_SPEC 0x0007 +#define PCIM_PCAP_PMEREQCLK 0x0008 +#define PCIM_PCAP_PMEREQPWR 0x0010 +#define PCIM_PCAP_DEVSPECINIT 0x0020 +#define PCIM_PCAP_DYNCLOCK 0x0040 +#define PCIM_PCAP_SECCLOCK 0x00c0 +#define PCIM_PCAP_CLOCKMASK 0x00c0 +#define PCIM_PCAP_REQFULLCLOCK 0x0100 +#define PCIM_PCAP_D1SUPP 0x0200 +#define PCIM_PCAP_D2SUPP 0x0400 +#define PCIM_PCAP_D0PME 0x0800 +#define PCIM_PCAP_D1PME 0x1000 +#define PCIM_PCAP_D2PME 0x2000 +#define PCIM_PCAP_D3PME_HOT 0x4000 +#define PCIM_PCAP_D3PME_COLD 0x8000 + +#define PCIR_POWER_STATUS 0x4 +#define PCIM_PSTAT_D0 0x0000 +#define PCIM_PSTAT_D1 0x0001 +#define PCIM_PSTAT_D2 0x0002 +#define PCIM_PSTAT_D3 0x0003 +#define PCIM_PSTAT_DMASK 0x0003 +#define PCIM_PSTAT_REPENABLE 0x0010 +#define PCIM_PSTAT_PMEENABLE 0x0100 +#define PCIM_PSTAT_D0POWER 0x0000 +#define PCIM_PSTAT_D1POWER 0x0200 +#define PCIM_PSTAT_D2POWER 0x0400 +#define PCIM_PSTAT_D3POWER 0x0600 +#define PCIM_PSTAT_D0HEAT 0x0800 +#define PCIM_PSTAT_D1HEAT 0x1000 +#define PCIM_PSTAT_D2HEAT 0x1200 +#define PCIM_PSTAT_D3HEAT 0x1400 +#define PCIM_PSTAT_DATAUNKN 0x0000 +#define PCIM_PSTAT_DATADIV10 0x2000 +#define PCIM_PSTAT_DATADIV100 0x4000 +#define PCIM_PSTAT_DATADIV1000 0x6000 +#define PCIM_PSTAT_DATADIVMASK 0x6000 +#define PCIM_PSTAT_PME 0x8000 + +#define PCIR_POWER_PMCSR 0x6 +#define PCIM_PMCSR_DCLOCK 0x10 +#define PCIM_PMCSR_B2SUPP 0x20 +#define PCIM_BMCSR_B3SUPP 0x40 +#define PCIM_BMCSR_BPCE 0x80 + +#define PCIR_POWER_DATA 0x7 /* VPD capability registers */ -#define PCIR_VPD_ADDR 0x2 -#define PCIR_VPD_DATA 0x4 +#define PCIR_VPD_ADDR 0x2 +#define PCIR_VPD_DATA 0x4 /* PCI Message Signalled Interrupts (MSI) */ -#define PCIR_MSI_CTRL 0x2 -#define PCIM_MSICTRL_VECTOR 0x0100 -#define PCIM_MSICTRL_64BIT 0x0080 -#define PCIM_MSICTRL_MME_MASK 0x0070 -#define PCIM_MSICTRL_MME_1 0x0000 -#define PCIM_MSICTRL_MME_2 0x0010 -#define PCIM_MSICTRL_MME_4 0x0020 -#define PCIM_MSICTRL_MME_8 0x0030 -#define PCIM_MSICTRL_MME_16 0x0040 -#define PCIM_MSICTRL_MME_32 0x0050 -#define PCIM_MSICTRL_MMC_MASK 0x000E -#define PCIM_MSICTRL_MMC_1 0x0000 -#define PCIM_MSICTRL_MMC_2 0x0002 -#define PCIM_MSICTRL_MMC_4 0x0004 -#define PCIM_MSICTRL_MMC_8 0x0006 -#define PCIM_MSICTRL_MMC_16 0x0008 -#define PCIM_MSICTRL_MMC_32 0x000A -#define PCIM_MSICTRL_MSI_ENABLE 0x0001 -#define PCIR_MSI_ADDR 0x4 -#define PCIR_MSI_ADDR_HIGH 0x8 -#define PCIR_MSI_DATA 0x8 -#define PCIR_MSI_DATA_64BIT 0xc -#define PCIR_MSI_MASK 0x10 -#define PCIR_MSI_PENDING 0x14 +#define PCIR_MSI_CTRL 0x2 +#define PCIM_MSICTRL_VECTOR 0x0100 +#define PCIM_MSICTRL_64BIT 0x0080 +#define PCIM_MSICTRL_MME_MASK 0x0070 +#define PCIM_MSICTRL_MME_1 0x0000 +#define PCIM_MSICTRL_MME_2 0x0010 +#define PCIM_MSICTRL_MME_4 0x0020 +#define PCIM_MSICTRL_MME_8 0x0030 +#define PCIM_MSICTRL_MME_16 0x0040 +#define PCIM_MSICTRL_MME_32 0x0050 +#define PCIM_MSICTRL_MMC_MASK 0x000E +#define PCIM_MSICTRL_MMC_1 0x0000 +#define PCIM_MSICTRL_MMC_2 0x0002 +#define PCIM_MSICTRL_MMC_4 0x0004 +#define PCIM_MSICTRL_MMC_8 0x0006 +#define PCIM_MSICTRL_MMC_16 0x0008 +#define PCIM_MSICTRL_MMC_32 0x000A +#define PCIM_MSICTRL_MSI_ENABLE 0x0001 +#define PCIR_MSI_ADDR 0x4 +#define PCIR_MSI_ADDR_HIGH 0x8 +#define PCIR_MSI_DATA 0x8 +#define PCIR_MSI_DATA_64BIT 0xc +#define PCIR_MSI_MASK 0x10 +#define PCIR_MSI_PENDING 0x14 /* PCI-X definitions */ -#define PCIXR_COMMAND 0x96 -#define PCIXR_DEVADDR 0x98 -#define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */ -#define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */ -#define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */ -#define PCIXR_STATUS 0x9A -#define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */ -#define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */ -#define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */ -#define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */ -#define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */ -#define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */ -#define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */ -#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ -#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ - -/* - * PCI Express definitions - * According to - * PCI Express base specification, REV. 1.0a - */ - -/* PCI Express capabilities, 16bits */ -#define PCIER_CAPABILITY 0x2 -#define PCIEM_CAP_VER_MASK 0x000f /* Version */ -#define PCIEM_CAP_VER_1 0x0001 -#define PCIEM_CAP_PORT_TYPE 0x00f0 /* Port type mask */ -#define PCIEM_CAP_SLOT_IMPL 0x0100 /* Slot implemented, - * valid only for root port and - * switch downstream port - */ - /* PCI Express port types */ -#define PCIE_END_POINT 0x0000 /* Endpoint device */ -#define PCIE_LEG_END_POINT 0x0010 /* Legacy endpoint device */ -#define PCIE_ROOT_PORT 0x0040 /* Root port */ -#define PCIE_UP_STREAM_PORT 0x0050 /* Switch upstream port */ -#define PCIE_DOWN_STREAM_PORT 0x0060 /* Switch downstream port */ -#define PCIE_PCIE2PCI_BRIDGE 0x0070 /* PCI Express to PCI/PCI-X bridge */ -#define PCIE_PCI2PCIE_BRIDGE 0x0080 /* PCI/PCI-X to PCI Express bridge */ - -/* PCI Express device control, 16bits */ -#define PCIER_DEVCTRL 0x08 -#define PCIEM_DEVCTL_MAX_READRQ_MASK 0x7000 /* Max read request size */ -#define PCIEM_DEVCTL_MAX_READRQ_128 0x0000 -#define PCIEM_DEVCTL_MAX_READRQ_256 0x1000 -#define PCIEM_DEVCTL_MAX_READRQ_512 0x2000 -#define PCIEM_DEVCTL_MAX_READRQ_1024 0x3000 -#define PCIEM_DEVCTL_MAX_READRQ_2048 0x4000 -#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 - -/* PCI Express slot capabilities, 32bits */ -#define PCIER_SLOTCAP 0x14 -#define PCIEM_SLTCAP_ATTEN_BTN 0x00000001 /* Attention button present */ -#define PCIEM_SLTCAP_PWR_CTRL 0x00000002 /* Power controller present */ -#define PCIEM_SLTCAP_MRL_SNS 0x00000004 /* MRL sensor present */ -#define PCIEM_SLTCAP_ATTEN_IND 0x00000008 /* Attention indicator present */ -#define PCIEM_SLTCAP_PWR_IND 0x00000010 /* Power indicator present */ -#define PCIEM_SLTCAP_HP_SURP 0x00000020 /* Hot-Plug surprise */ -#define PCIEM_SLTCAP_HP_CAP 0x00000040 /* Hot-Plug capable */ -#define PCIEM_SLTCAP_HP_MASK 0x0000007f /* Hot-Plug related bits */ - -/* PCI Express slot control, 16bits */ -#define PCIER_SLOTCTRL 0x18 -#define PCIEM_SLTCTL_HPINTR_MASK 0x001f /* Hot-plug interrupts mask */ -#define PCIEM_SLTCTL_HPINTR_EN 0x0020 /* Enable hot-plug interrupts */ - /* PCI Expres hot-plug interrupts */ -#define PCIE_HPINTR_ATTEN_BTN 0x0001 /* Attention button intr */ -#define PCIE_HPINTR_PWR_FAULT 0x0002 /* Power fault intr */ -#define PCIE_HPINTR_MRL_SNS 0x0004 /* MRL sensor changed intr */ -#define PCIE_HPINTR_PRSN_DETECT 0x0008 /* Presence detect intr */ -#define PCIE_HPINTR_CMD_COMPL 0x0010 /* Command completed intr */ - -/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */ - -#if defined(_KERNEL) && !defined(KLD_MODULE) -#include "opt_compat_oldpci.h" -#endif -#ifdef COMPAT_OLDPCI - -#define PCI_ID_REG 0x00 -#define PCI_COMMAND_STATUS_REG 0x04 -#define PCI_COMMAND_IO_ENABLE 0x00000001 -#define PCI_COMMAND_MEM_ENABLE 0x00000002 -#define PCI_CLASS_REG 0x08 -#define PCI_CLASS_MASK 0xff000000 -#define PCI_SUBCLASS_MASK 0x00ff0000 -#define PCI_REVISION_MASK 0x000000ff -#define PCI_CLASS_PREHISTORIC 0x00000000 -#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 -#define PCI_CLASS_MASS_STORAGE 0x01000000 -#define PCI_CLASS_DISPLAY 0x03000000 -#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000 -#define PCI_CLASS_BRIDGE 0x06000000 -#define PCI_MAP_REG_START 0x10 -#define PCI_MAP_REG_END 0x28 -#define PCI_MAP_IO 0x00000001 -#define PCI_INTERRUPT_REG 0x3c - -#endif /* COMPAT_OLDPCI */ +/* For header type 0 devices */ +#define PCIXR_COMMAND 0x2 +#define PCIXM_COMMAND_DPERR_E 0x0001 /* Data Parity Error Recovery */ +#define PCIXM_COMMAND_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCIXM_COMMAND_MAX_READ 0x000c /* Maximum Burst Read Count */ +#define PCIXM_COMMAND_MAX_READ_512 0x0000 +#define PCIXM_COMMAND_MAX_READ_1024 0x0004 +#define PCIXM_COMMAND_MAX_READ_2048 0x0008 +#define PCIXM_COMMAND_MAX_READ_4096 0x000c +#define PCIXM_COMMAND_MAX_SPLITS 0x0070 /* Maximum Split Transactions */ +#define PCIXM_COMMAND_MAX_SPLITS_1 0x0000 +#define PCIXM_COMMAND_MAX_SPLITS_2 0x0010 +#define PCIXM_COMMAND_MAX_SPLITS_3 0x0020 +#define PCIXM_COMMAND_MAX_SPLITS_4 0x0030 +#define PCIXM_COMMAND_MAX_SPLITS_8 0x0040 +#define PCIXM_COMMAND_MAX_SPLITS_12 0x0050 +#define PCIXM_COMMAND_MAX_SPLITS_16 0x0060 +#define PCIXM_COMMAND_MAX_SPLITS_32 0x0070 +#define PCIXM_COMMAND_VERSION 0x3000 +#define PCIXR_STATUS 0x4 +#define PCIXM_STATUS_DEVFN 0x000000FF +#define PCIXM_STATUS_BUS 0x0000FF00 +#define PCIXM_STATUS_64BIT 0x00010000 +#define PCIXM_STATUS_133CAP 0x00020000 +#define PCIXM_STATUS_SC_DISCARDED 0x00040000 +#define PCIXM_STATUS_UNEXP_SC 0x00080000 +#define PCIXM_STATUS_COMPLEX_DEV 0x00100000 +#define PCIXM_STATUS_MAX_READ 0x00600000 +#define PCIXM_STATUS_MAX_READ_512 0x00000000 +#define PCIXM_STATUS_MAX_READ_1024 0x00200000 +#define PCIXM_STATUS_MAX_READ_2048 0x00400000 +#define PCIXM_STATUS_MAX_READ_4096 0x00600000 +#define PCIXM_STATUS_MAX_SPLITS 0x03800000 +#define PCIXM_STATUS_MAX_SPLITS_1 0x00000000 +#define PCIXM_STATUS_MAX_SPLITS_2 0x00800000 +#define PCIXM_STATUS_MAX_SPLITS_3 0x01000000 +#define PCIXM_STATUS_MAX_SPLITS_4 0x01800000 +#define PCIXM_STATUS_MAX_SPLITS_8 0x02000000 +#define PCIXM_STATUS_MAX_SPLITS_12 0x02800000 +#define PCIXM_STATUS_MAX_SPLITS_16 0x03000000 +#define PCIXM_STATUS_MAX_SPLITS_32 0x03800000 +#define PCIXM_STATUS_MAX_CUM_READ 0x1C000000 +#define PCIXM_STATUS_RCVD_SC_ERR 0x20000000 +#define PCIXM_STATUS_266CAP 0x40000000 +#define PCIXM_STATUS_533CAP 0x80000000 + +/* For header type 1 devices (PCI-X bridges) */ +#define PCIXR_SEC_STATUS 0x2 +#define PCIXM_SEC_STATUS_64BIT 0x0001 +#define PCIXM_SEC_STATUS_133CAP 0x0002 +#define PCIXM_SEC_STATUS_SC_DISC 0x0004 +#define PCIXM_SEC_STATUS_UNEXP_SC 0x0008 +#define PCIXM_SEC_STATUS_SC_OVERRUN 0x0010 +#define PCIXM_SEC_STATUS_SR_DELAYED 0x0020 +#define PCIXM_SEC_STATUS_BUS_MODE 0x03c0 +#define PCIXM_SEC_STATUS_VERSION 0x3000 +#define PCIXM_SEC_STATUS_266CAP 0x4000 +#define PCIXM_SEC_STATUS_533CAP 0x8000 +#define PCIXR_BRIDGE_STATUS 0x4 +#define PCIXM_BRIDGE_STATUS_DEVFN 0x000000FF +#define PCIXM_BRIDGE_STATUS_BUS 0x0000FF00 +#define PCIXM_BRIDGE_STATUS_64BIT 0x00010000 +#define PCIXM_BRIDGE_STATUS_133CAP 0x00020000 +#define PCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000 +#define PCIXM_BRIDGE_STATUS_UNEXP_SC 0x00080000 +#define PCIXM_BRIDGE_STATUS_SC_OVERRUN 0x00100000 +#define PCIXM_BRIDGE_STATUS_SR_DELAYED 0x00200000 +#define PCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000 +#define PCIXM_BRIDGE_STATUS_266CAP 0x40000000 +#define PCIXM_BRIDGE_STATUS_533CAP 0x80000000 + +/* HT (HyperTransport) Capability definitions */ +#define PCIR_HT_COMMAND 0x2 +#define PCIM_HTCMD_CAP_MASK 0xf800 /* Capability type. */ +#define PCIM_HTCAP_SLAVE 0x0000 /* 000xx */ +#define PCIM_HTCAP_HOST 0x2000 /* 001xx */ +#define PCIM_HTCAP_SWITCH 0x4000 /* 01000 */ +#define PCIM_HTCAP_INTERRUPT 0x8000 /* 10000 */ +#define PCIM_HTCAP_REVISION_ID 0x8800 /* 10001 */ +#define PCIM_HTCAP_UNITID_CLUMPING 0x9000 /* 10010 */ +#define PCIM_HTCAP_EXT_CONFIG_SPACE 0x9800 /* 10011 */ +#define PCIM_HTCAP_ADDRESS_MAPPING 0xa000 /* 10100 */ +#define PCIM_HTCAP_MSI_MAPPING 0xa800 /* 10101 */ +#define PCIM_HTCAP_DIRECT_ROUTE 0xb000 /* 10110 */ +#define PCIM_HTCAP_VCSET 0xb800 /* 10111 */ +#define PCIM_HTCAP_RETRY_MODE 0xc000 /* 11000 */ +#define PCIM_HTCAP_X86_ENCODING 0xc800 /* 11001 */ + +/* HT MSI Mapping Capability definitions. */ +#define PCIM_HTCMD_MSI_ENABLE 0x0001 +#define PCIM_HTCMD_MSI_FIXED 0x0002 +#define PCIR_HTMSI_ADDRESS_LO 0x4 +#define PCIR_HTMSI_ADDRESS_HI 0x8 + +/* PCI Vendor capability definitions */ +#define PCIR_VENDOR_LENGTH 0x2 +#define PCIR_VENDOR_DATA 0x3 + +/* PCI EHCI Debug Port definitions */ +#define PCIR_DEBUG_PORT 0x2 +#define PCIM_DEBUG_PORT_OFFSET 0x1FFF +#define PCIM_DEBUG_PORT_BAR 0xe000 + +/* PCI-PCI Bridge Subvendor definitions */ +#define PCIR_SUBVENDCAP_ID 0x4 + +/* PCI Express definitions */ +#define PCIR_EXPRESS_FLAGS 0x2 +#define PCIM_EXP_FLAGS_VERSION 0x000F +#define PCIM_EXP_FLAGS_TYPE 0x00F0 +#define PCIM_EXP_TYPE_ENDPOINT 0x0000 +#define PCIM_EXP_TYPE_LEGACY_ENDPOINT 0x0010 +#define PCIM_EXP_TYPE_ROOT_PORT 0x0040 +#define PCIM_EXP_TYPE_UPSTREAM_PORT 0x0050 +#define PCIM_EXP_TYPE_DOWNSTREAM_PORT 0x0060 +#define PCIM_EXP_TYPE_PCI_BRIDGE 0x0070 +#define PCIM_EXP_FLAGS_SLOT 0x0100 +#define PCIM_EXP_FLAGS_IRQ 0x3e00 +#define PCIER_DEVCTRL 0x08 +/* MSI-X definitions */ +#define PCIR_MSIX_CTRL 0x2 +#define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 +#define PCIM_MSIXCTRL_FUNCTION_MASK 0x4000 +#define PCIM_MSIXCTRL_TABLE_SIZE 0x07FF +#define PCIR_MSIX_TABLE 0x4 +#define PCIR_MSIX_PBA 0x8 +#define PCIM_MSIX_BIR_MASK 0x7 +#define PCIM_MSIX_BIR_BAR_10 0 +#define PCIM_MSIX_BIR_BAR_14 1 +#define PCIM_MSIX_BIR_BAR_18 2 +#define PCIM_MSIX_BIR_BAR_1C 3 +#define PCIM_MSIX_BIR_BAR_20 4 +#define PCIM_MSIX_BIR_BAR_24 5 +#define PCIM_MSIX_VCTRL_MASK 0x1 + +#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 +#define PCIEM_DEVCTL_MAX_READRQ_MASK 0x7000 /* Max read request size */ +#define PCIEM_DEVCTL_MAX_READRQ_128 0x0000 +#define PCIEM_DEVCTL_MAX_READRQ_256 0x1000 +#define PCIEM_DEVCTL_MAX_READRQ_512 0x2000 +#define PCIEM_DEVCTL_MAX_READRQ_1024 0x3000 +#define PCIEM_DEVCTL_MAX_READRQ_2048 0x4000 +#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 #endif diff --git a/sys/bus/pci/pcisupport.c b/sys/bus/pci/pcisupport.c deleted file mode 100644 index 903a19d859..0000000000 --- a/sys/bus/pci/pcisupport.c +++ /dev/null @@ -1,1037 +0,0 @@ -/************************************************************************** -** -** $FreeBSD: src/sys/pci/pcisupport.c,v 1.154.2.15 2003/04/29 15:55:06 simokawa Exp $ -** $DragonFly: src/sys/bus/pci/pcisupport.c,v 1.20 2006/12/22 23:12:17 swildner Exp $ -** -** Device driver for DEC/INTEL PCI chipsets. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Written for FreeBSD by -** wolf@cologne.de Wolfgang Stanglmeier -** se@mi.Uni-Koeln.de Stefan Esser -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994,1995 Stefan Esser. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -*************************************************************************** -*/ - -#include "opt_bus.h" -#include "opt_pci.h" - -#include -#include -#include -#include -#include -#include - -#include "pcivar.h" -#include "pcireg.h" - -#include -#include -#include - -#include "pcib_if.h" -#include "pcib_private.h" - -/*--------------------------------------------------------- -** -** Intel chipsets for 486 / Pentium processor -** -**--------------------------------------------------------- -*/ - -static void -fixbushigh_i1225(device_t dev) -{ - int sublementarybus; - - sublementarybus = pci_read_config(dev, 0x41, 1); - if (sublementarybus != 0xff) { - pci_set_secondarybus(dev, sublementarybus + 1); - pci_set_subordinatebus(dev, sublementarybus + 1); - } -} - -static void -fixwsc_natoma(device_t dev) -{ - int pmccfg; - - pmccfg = pci_read_config(dev, 0x50, 2); -#if defined(SMP) - if (pmccfg & 0x8000) { - kprintf("Correcting Natoma config for SMP\n"); - pmccfg &= ~0x8000; - pci_write_config(dev, 0x50, pmccfg, 2); - } -#else - if ((pmccfg & 0x8000) == 0) { - kprintf("Correcting Natoma config for non-SMP\n"); - pmccfg |= 0x8000; - pci_write_config(dev, 0x50, pmccfg, 2); - } -#endif -} - -/* - * Set the SYSTEM_IDLE_TIMEOUT to 80 ns on nForce2 systems to work - * around a hang that is triggered when the CPU generates a very fast - * CONNECT/HALT cycle sequence. Specifically, the hang can result in - * the lapic timer being stopped. - * - * This requires changing the value for config register at offset 0x6c - * for the Host-PCI bridge at bus/dev/function 0/0/0: - * - * Chip Current Value New Value - * ---- ---------- ---------- - * C17 0x1F0FFF01 0x1F01FF01 - * C18D 0x9F0FFF01 0x9F01FF01 - * - * We do this by always clearing the bits in 0x000e0000. - * - * See also: http://lkml.org/lkml/2004/5/3/157 - */ -static void -fixc1_nforce2(device_t dev) -{ - uint32_t val; - - if (pci_get_bus(dev) == 0 && pci_get_slot(dev) == 0 && - pci_get_function(dev) == 0) { - val = pci_read_config(dev, 0x6c, 4); - if (val & 0x000e0000) { - kprintf("Correcting nForce2 C1 CPU disconnect hangs\n"); - val &= ~0x000e0000; - pci_write_config(dev, 0x6c, val, 4); - } - } -} - -const char * -pci_bridge_type(device_t dev) -{ - char *descr, tmpbuf[120]; - - if (pci_get_class(dev) != PCIC_BRIDGE) - return NULL; - - switch (pci_get_subclass(dev)) { - case PCIS_BRIDGE_HOST: strcpy(tmpbuf, "Host to PCI"); break; - case PCIS_BRIDGE_ISA: strcpy(tmpbuf, "PCI to ISA"); break; - case PCIS_BRIDGE_EISA: strcpy(tmpbuf, "PCI to EISA"); break; - case PCIS_BRIDGE_MCA: strcpy(tmpbuf, "PCI to MCA"); break; - case PCIS_BRIDGE_PCI: strcpy(tmpbuf, "PCI to PCI"); break; - case PCIS_BRIDGE_PCMCIA: strcpy(tmpbuf, "PCI to PCMCIA"); break; - case PCIS_BRIDGE_NUBUS: strcpy(tmpbuf, "PCI to NUBUS"); break; - case PCIS_BRIDGE_CARDBUS: strcpy(tmpbuf, "PCI to CardBus"); break; - case PCIS_BRIDGE_OTHER: strcpy(tmpbuf, "PCI to Other"); break; - default: - ksnprintf(tmpbuf, sizeof(tmpbuf), - "PCI to 0x%x", pci_get_subclass(dev)); - break; - } - ksnprintf(tmpbuf+strlen(tmpbuf), sizeof(tmpbuf)-strlen(tmpbuf), - " bridge (vendor=%04x device=%04x)", - pci_get_vendor(dev), pci_get_device(dev)); - descr = kmalloc (strlen(tmpbuf) +1, M_DEVBUF, M_WAITOK); - strcpy(descr, tmpbuf); - return descr; -} - -const char * -pci_usb_match(device_t dev) -{ - switch (pci_get_devid(dev)) { - - /* Intel -- vendor 0x8086 */ - case 0x70208086: - return ("Intel 82371SB (PIIX3) USB controller"); - case 0x71128086: - return ("Intel 82371AB/EB (PIIX4) USB controller"); - case 0x24128086: - return ("Intel 82801AA (ICH) USB controller"); - case 0x24228086: - return ("Intel 82801AB (ICH0) USB controller"); - case 0x24428086: - return ("Intel 82801BA/BAM (ICH2) USB controller USB-A"); - case 0x24448086: - return ("Intel 82801BA/BAM (ICH2) USB controller USB-B"); - - /* VIA Technologies -- vendor 0x1106 (0x1107 on the Apollo Master) */ - case 0x30381106: - return ("VIA 83C572 USB controller"); - - /* AcerLabs -- vendor 0x10b9 */ - case 0x523710b9: - return ("AcerLabs M5237 (Aladdin-V) USB controller"); - - /* OPTi -- vendor 0x1045 */ - case 0xc8611045: - return ("OPTi 82C861 (FireLink) USB controller"); - - /* NEC -- vendor 0x1033 */ - case 0x00351033: - return ("NEC uPD 9210 USB controller"); - - /* CMD Tech -- vendor 0x1095 */ - case 0x06701095: - return ("CMD Tech 670 (USB0670) USB controller"); - case 0x06731095: - return ("CMD Tech 673 (USB0673) USB controller"); - } - - if (pci_get_class(dev) == PCIC_SERIALBUS - && pci_get_subclass(dev) == PCIS_SERIALBUS_USB) { - if (pci_get_progif(dev) == 0x00 /* UHCI */ ) { - return ("UHCI USB controller"); - } else if (pci_get_progif(dev) == 0x10 /* OHCI */ ) { - return ("OHCI USB controller"); - } else { - return ("USB controller"); - } - } - return NULL; -} - -const char * -pci_ata_match(device_t dev) -{ - - switch (pci_get_devid(dev)) { - - /* Intel -- vendor 0x8086 */ - case 0x12308086: - return ("Intel PIIX ATA controller"); - case 0x70108086: - return ("Intel PIIX3 ATA controller"); - case 0x71118086: - return ("Intel PIIX4 ATA controller"); - case 0x12348086: - return ("Intel 82371MX mobile PCI ATA accelerator (MPIIX)"); - - /* Promise -- vendor 0x105a */ - case 0x4d33105a: - return ("Promise Ultra/33 ATA controller"); - case 0x4d38105a: - return ("Promise Ultra/66 ATA controller"); - - /* AcerLabs -- vendor 0x10b9 */ - case 0x522910b9: - return ("AcerLabs Aladdin ATA controller"); - - /* VIA Technologies -- vendor 0x1106 (0x1107 on the Apollo Master) */ - case 0x05711106: - switch (pci_read_config(dev, 0x08, 1)) { - case 1: - return ("VIA 85C586 ATA controller"); - case 6: - return ("VIA 85C586 ATA controller"); - } - /* FALL THROUGH */ - case 0x15711106: - return ("VIA Apollo ATA controller"); - - /* CMD Tech -- vendor 0x1095 */ - case 0x06401095: - return ("CMD 640 ATA controller"); - case 0x06461095: - return ("CMD 646 ATA controller"); - - /* Cypress -- vendor 0x1080 */ - case 0xc6931080: - return ("Cypress 82C693 ATA controller"); - - /* Cyrix -- vendor 0x1078 */ - case 0x01021078: - return ("Cyrix 5530 ATA controller"); - - /* SiS -- vendor 0x1039 */ - case 0x55131039: - return ("SiS 5591 ATA controller"); - - /* Highpoint tech -- vendor 0x1103 */ - case 0x00041103: - return ("HighPoint HPT366 ATA controller"); - } - - if (pci_get_class(dev) == PCIC_STORAGE && - pci_get_subclass(dev) == PCIS_STORAGE_IDE) - return ("Unknown PCI ATA controller"); - - return NULL; -} - - -const char* -pci_chip_match(device_t dev) -{ - unsigned rev; - - switch (pci_get_devid(dev)) { - /* Intel -- vendor 0x8086 */ - case 0x00088086: - /* Silently ignore this one! What is it, anyway ??? */ - return (""); - case 0x71108086: - /* - * On my laptop (Tecra 8000DVD), this device has a - * bogus subclass 0x80 so make sure that it doesn't - * match the generic 'chip' driver by accident. - */ - return NULL; - case 0x12258086: - fixbushigh_i1225(dev); - return ("Intel 824?? host to PCI bridge"); - case 0x71808086: - return ("Intel 82443LX (440 LX) host to PCI bridge"); - case 0x71908086: - return ("Intel 82443BX (440 BX) host to PCI bridge"); - case 0x71928086: - return ("Intel 82443BX host to PCI bridge (AGP disabled)"); - case 0x71a08086: - return ("Intel 82443GX host to PCI bridge"); - case 0x71a18086: - return ("Intel 82443GX host to AGP bridge"); - case 0x71a28086: - return ("Intel 82443GX host to PCI bridge (AGP disabled)"); - case 0x84c48086: - return ("Intel 82454KX/GX (Orion) host to PCI bridge"); - case 0x84ca8086: - return ("Intel 82451NX Memory and I/O controller"); - case 0x04868086: - return ("Intel 82425EX PCI system controller"); - case 0x04838086: - return ("Intel 82424ZX (Saturn) cache DRAM controller"); - case 0x04a38086: - rev = pci_get_revid(dev); - if (rev == 16 || rev == 17) - return ("Intel 82434NX (Neptune) PCI cache memory controller"); - return ("Intel 82434LX (Mercury) PCI cache memory controller"); - case 0x122d8086: - return ("Intel 82437FX PCI cache memory controller"); - case 0x12358086: - return ("Intel 82437MX mobile PCI cache memory controller"); - case 0x12508086: - return ("Intel 82439HX PCI cache memory controller"); - case 0x70308086: - return ("Intel 82437VX PCI cache memory controller"); - case 0x71008086: - return ("Intel 82439TX System controller (MTXC)"); - case 0x71138086: - return ("Intel 82371AB Power management controller"); - case 0x719b8086: - return ("Intel 82443MX Power management controller"); - case 0x12378086: - fixwsc_natoma(dev); - return ("Intel 82440FX (Natoma) PCI and memory controller"); - case 0x84c58086: - return ("Intel 82453KX/GX (Orion) PCI memory controller"); - case 0x71208086: - return ("Intel 82810 (i810 GMCH) Host To Hub bridge"); - case 0x71228086: - return ("Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"); - case 0x71248086: - return ("Intel 82810E (i810E GMCH) Host To Hub bridge"); - case 0x24158086: - return ("Intel 82801AA (ICH) AC'97 Audio Controller"); - case 0x24258086: - return ("Intel 82801AB (ICH0) AC'97 Audio Controller"); - - /* Sony -- vendor 0x104d */ - case 0x8009104d: - return ("Sony CXD1947A FireWire Host Controller"); - - /* SiS -- vendor 0x1039 */ - case 0x04961039: - return ("SiS 85c496 PCI/VL Bridge"); - case 0x04061039: - return ("SiS 85c501"); - case 0x06011039: - return ("SiS 85c601"); - case 0x55911039: - return ("SiS 5591 host to PCI bridge"); - case 0x00011039: - return ("SiS 5591 host to AGP bridge"); - - /* VLSI -- vendor 0x1004 */ - case 0x00051004: - return ("VLSI 82C592 Host to PCI bridge"); - case 0x01011004: - return ("VLSI 82C532 Eagle II Peripheral controller"); - case 0x01041004: - return ("VLSI 82C535 Eagle II System controller"); - case 0x01051004: - return ("VLSI 82C147 IrDA controller"); - - /* VIA Technologies -- vendor 0x1106 (0x1107 on the Apollo Master) */ - case 0x15761107: - return ("VIA 82C570 (Apollo Master) system controller"); - case 0x05851106: - return ("VIA 82C585 (Apollo VP1/VPX) system controller"); - case 0x05951106: - case 0x15951106: - return ("VIA 82C595 (Apollo VP2) system controller"); - case 0x05971106: - return ("VIA 82C597 (Apollo VP3) system controller"); - /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ - /* totally. Please let me know if anything wrong. -F */ - /* XXX need info on the MVP3 -- any takers? */ - case 0x05981106: - return ("VIA 82C598MVP (Apollo MVP3) host bridge"); - case 0x30401106: - case 0x30501106: - case 0x30571106: - return NULL; - case 0x30581106: - return ("VIA 82C686 AC97 Audio"); - case 0x30681106: - return ("VIA 82C686 AC97 Modem"); - - /* AMD -- vendor 0x1022 */ - case 0x70061022: - return ("AMD-751 host to PCI bridge"); - case 0x700e1022: - return ("AMD-761 host to PCI bridge"); - - /* AcerLabs -- vendor 0x10b9 */ - /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ - /* id is '10b9" but the register always shows "10b9". -Foxfair */ - case 0x154110b9: - return ("AcerLabs M1541 (Aladdin-V) PCI host bridge"); - case 0x710110b9: - return ("AcerLabs M15x3 Power Management Unit"); - - /* OPTi -- vendor 0x1045 */ - case 0xc5571045: - return ("Opti 82C557 (Viper-M) host to PCI bridge"); - case 0xc5581045: - return ("Opti 82C558 (Viper-M) ISA+IDE"); - case 0xc8221045: - return ("OPTi 82C822 host to PCI Bridge"); - - /* Texas Instruments -- vendor 0x104c */ - case 0xac1c104c: - return ("Texas Instruments PCI1225 CardBus controller"); - case 0xac50104c: - return ("Texas Instruments PCI1410 CardBus controller"); - case 0xac51104c: - return ("Texas Instruments PCI1420 CardBus controller"); - case 0xac1b104c: - return ("Texas Instruments PCI1450 CardBus controller"); - case 0xac52104c: - return ("Texas Instruments PCI1451 CardBus controller"); - - /* NeoMagic -- vendor 0x10c8 */ - case 0x800510c8: - return ("NeoMagic MagicMedia 256AX Audio controller"); - case 0x800610c8: - return ("NeoMagic MagicMedia 256ZX Audio controller"); - - /* NVidia -- vendor 0x10de */ - case 0x01e010de: - fixc1_nforce2(dev); - return ("NVidia nForce2 AGP controller"); - - /* ESS Technology Inc -- vendor 0x125d */ - case 0x1978125d: - return ("ESS Technology Maestro 2E Audio controller"); - - /* Toshiba -- vendor 0x1179 */ - case 0x07011179: - return ("Toshiba Fast Infra Red controller"); - }; - - if (pci_get_class(dev) == PCIC_BRIDGE - && pci_get_subclass(dev) != PCIS_BRIDGE_PCI - && pci_get_subclass(dev) != PCIS_BRIDGE_ISA - && pci_get_subclass(dev) != PCIS_BRIDGE_EISA) - return pci_bridge_type(dev); - - return NULL; -} - -/*--------------------------------------------------------- -** -** Catchall driver for VGA devices -** -** By Garrett Wollman -** -** -**--------------------------------------------------------- -*/ - -const char * -pci_vga_match(device_t dev) -{ - u_int id = pci_get_devid(dev); - const char *vendor, *chip, *type; - - vendor = chip = type = 0; - switch (id & 0xffff) { - case 0x003d: - vendor = "Real 3D"; - switch (id >> 16) { - case 0x00d1: - chip = "i740"; break; - } - break; - case 0x10c8: - vendor = "NeoMagic"; - switch (id >> 16) { - case 0x0003: - chip = "MagicGraph 128ZV"; break; - case 0x0004: - chip = "MagicGraph 128XD"; break; - case 0x0005: - chip = "MagicMedia 256AV"; break; - case 0x0006: - chip = "MagicMedia 256ZX"; break; - } - break; - case 0x121a: - vendor = "3Dfx"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x0001: - chip = "Voodoo"; break; - case 0x0002: - chip = "Voodoo 2"; break; - case 0x0003: - chip = "Voodoo Banshee"; break; - case 0x0005: - chip = "Voodoo 3"; break; - } - break; - case 0x102b: - vendor = "Matrox"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x0518: - chip = "MGA 2085PX"; break; - case 0x0519: - chip = "MGA Millennium 2064W"; break; - case 0x051a: - chip = "MGA 1024SG/1064SG/1164SG"; break; - case 0x051b: - chip = "MGA Millennium II 2164W"; break; - case 0x051f: - chip = "MGA Millennium II 2164WA-B AG"; break; - case 0x0520: - chip = "MGA G200"; break; - case 0x0521: - chip = "MGA G200 AGP"; break; - case 0x0525: - chip = "MGA G400 AGP"; break; - case 0x0d10: - chip = "MGA Impression"; break; - case 0x1000: - chip = "MGA G100"; break; - case 0x1001: - chip = "MGA G100 AGP"; break; - case 0x2527: - chip = "MGA G550 AGP"; break; - - } - break; - case 0x1002: - vendor = "ATI"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x4158: - chip = "Mach32"; break; - case 0x4354: - chip = "Mach64-CT"; break; - case 0x4358: - chip = "Mach64-CX"; break; - case 0x4554: - chip = "Mach64-ET"; break; - case 0x4654: - case 0x5654: - chip = "Mach64-VT"; break; - case 0x4742: - chip = "Mach64-GB"; break; - case 0x4744: - chip = "Mach64-GD"; break; - case 0x4749: - chip = "Mach64-GI"; break; - case 0x474d: - chip = "Mach64-GM"; break; - case 0x474e: - chip = "Mach64-GN"; break; - case 0x474f: - chip = "Mach64-GO"; break; - case 0x4750: - chip = "Mach64-GP"; break; - case 0x4751: - chip = "Mach64-GQ"; break; - case 0x4752: - chip = "Mach64-GR"; break; - case 0x4753: - chip = "Mach64-GS"; break; - case 0x4754: - chip = "Mach64-GT"; break; - case 0x4755: - chip = "Mach64-GU"; break; - case 0x4756: - chip = "Mach64-GV"; break; - case 0x4757: - chip = "Mach64-GW"; break; - case 0x4758: - chip = "Mach64-GX"; break; - case 0x4c4d: - chip = "Mobility-1"; break; - case 0x4c52: - chip = "RageMobility-P/M"; break; - case 0x475a: - chip = "Mach64-GZ"; break; - case 0x5245: - chip = "Rage128-RE"; break; - case 0x5246: - chip = "Rage128-RF"; break; - case 0x524b: - chip = "Rage128-RK"; break; - case 0x524c: - chip = "Rage128-RL"; break; - } - break; - case 0x1005: - vendor = "Avance Logic"; - switch (id >> 16) { - case 0x2301: - chip = "ALG2301"; break; - case 0x2302: - chip = "ALG2302"; break; - } - break; - case 0x100c: - vendor = "Tseng Labs"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x3202: - case 0x3205: - case 0x3206: - case 0x3207: - chip = "ET4000 W32P"; break; - case 0x3208: - chip = "ET6000/ET6100"; break; - case 0x4702: - chip = "ET6300"; break; - } - break; - case 0x100e: - vendor = "Weitek"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x9001: - chip = "P9000"; break; - case 0x9100: - chip = "P9100"; break; - } - break; - case 0x1013: - vendor = "Cirrus Logic"; - switch (id >> 16) { - case 0x0038: - chip = "GD7548"; break; - case 0x0040: - chip = "GD7555"; break; - case 0x004c: - chip = "GD7556"; break; - case 0x00a0: - chip = "GD5430"; break; - case 0x00a4: - case 0x00a8: - chip = "GD5434"; break; - case 0x00ac: - chip = "GD5436"; break; - case 0x00b8: - chip = "GD5446"; break; - case 0x00bc: - chip = "GD5480"; break; - case 0x00d0: - chip = "GD5462"; break; - case 0x00d4: - case 0x00d5: - chip = "GD5464"; break; - case 0x00d6: - chip = "GD5465"; break; - case 0x1200: - chip = "GD7542"; break; - case 0x1202: - chip = "GD7543"; break; - case 0x1204: - chip = "GD7541"; break; - } - break; - case 0x1023: - vendor = "Trident"; - break; /* let default deal with it */ - case 0x102c: - vendor = "Chips & Technologies"; - switch (id >> 16) { - case 0x00b8: - chip = "64310"; break; - case 0x00d8: - chip = "65545"; break; - case 0x00dc: - chip = "65548"; break; - case 0x00c0: - chip = "69000"; break; - case 0x00e0: - chip = "65550"; break; - case 0x00e4: - chip = "65554"; break; - case 0x00e5: - chip = "65555"; break; - case 0x00f4: - chip = "68554"; break; - } - break; - case 0x1039: - vendor = "SiS"; - switch (id >> 16) { - case 0x0001: - chip = "86c201"; break; - case 0x0002: - chip = "86c202"; break; - case 0x0205: - chip = "86c205"; break; - case 0x0215: - chip = "86c215"; break; - case 0x0225: - chip = "86c225"; break; - case 0x0200: - chip = "5597/98"; break; - case 0x6326: - chip = "6326"; break; - case 0x6306: - chip = "530/620"; break; - } - break; - case 0x105d: - vendor = "Number Nine"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x2309: - chip = "Imagine 128"; break; - case 0x2339: - chip = "Imagine 128 II"; break; - } - break; - case 0x1142: - vendor = "Alliance"; - switch (id >> 16) { - case 0x3210: - chip = "PM6410"; break; - case 0x6422: - chip = "PM6422"; break; - case 0x6424: - chip = "PMAT24"; break; - } - break; - case 0x1163: - vendor = "Rendition Verite"; - switch (id >> 16) { - case 0x0001: - chip = "V1000"; break; - case 0x2000: - chip = "V2000"; break; - } - break; - case 0x1236: - vendor = "Sigma Designs"; - if ((id >> 16) == 0x6401) - chip = "REALmagic64/GX"; - break; - case 0x5333: - vendor = "S3"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x8811: - chip = "Trio"; break; - case 0x8812: - chip = "Aurora 64"; break; - case 0x8814: - chip = "Trio 64UV+"; break; - case 0x8901: - chip = "Trio 64V2/DX/GX"; break; - case 0x8902: - chip = "Plato"; break; - case 0x8904: - chip = "Trio3D"; break; - case 0x8880: - chip = "868"; break; - case 0x88b0: - chip = "928"; break; - case 0x88c0: - case 0x88c1: - chip = "864"; break; - case 0x88d0: - case 0x88d1: - chip = "964"; break; - case 0x88f0: - chip = "968"; break; - case 0x5631: - chip = "ViRGE"; break; - case 0x883d: - chip = "ViRGE VX"; break; - case 0x8a01: - chip = "ViRGE DX/GX"; break; - case 0x8a10: - chip = "ViRGE GX2"; break; - case 0x8a13: - chip = "Trio3D/2X"; break; - case 0x8a20: - case 0x8a21: - chip = "Savage3D"; break; - case 0x8a22: - chip = "Savage 4"; break; - case 0x8c01: - chip = "ViRGE MX"; break; - case 0x8c03: - chip = "ViRGE MX+"; break; - } - break; - case 0xedd8: - vendor = "ARK Logic"; - switch (id >> 16) { - case 0xa091: - chip = "1000PV"; break; - case 0xa099: - chip = "2000PV"; break; - case 0xa0a1: - chip = "2000MT"; break; - case 0xa0a9: - chip = "2000MI"; break; - } - break; - case 0x3d3d: - vendor = "3D Labs"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x0001: - chip = "300SX"; break; - case 0x0002: - chip = "500TX"; break; - case 0x0003: - chip = "Delta"; break; - case 0x0004: - chip = "PerMedia"; break; - } - break; - case 0x10de: - vendor = "NVidia"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x0008: - chip = "NV1"; break; - case 0x0020: - chip = "Riva TNT"; break; - case 0x0028: - chip = "Riva TNT2"; break; - case 0x0029: - chip = "Riva Ultra TNT2"; break; - case 0x002c: - chip = "Riva Vanta TNT2"; break; - case 0x002d: - chip = "Riva Ultra Vanta TNT2"; break; - case 0x00a0: - chip = "Riva Integrated TNT2"; break; - case 0x0100: - chip = "GeForce 256"; break; - case 0x0101: - chip = "GeForce DDR"; break; - case 0x0103: - chip = "Quadro"; break; - case 0x0150: - case 0x0151: - case 0x0152: - chip = "GeForce2 GTS"; break; - case 0x0153: - chip = "Quadro2"; break; - } - break; - case 0x12d2: - vendor = "NVidia/SGS-Thomson"; - type = "graphics accelerator"; - switch (id >> 16) { - case 0x0018: - chip = "Riva128"; break; - } - break; - case 0x104a: - vendor = "SGS-Thomson"; - switch (id >> 16) { - case 0x0008: - chip = "STG2000"; break; - } - break; - case 0x8086: - vendor = "Intel"; - switch (id >> 16) { - case 0x7121: - chip = "82810 (i810 GMCH)"; break; - case 0x7123: - chip = "82810-DC100 (i810-DC100 GMCH)"; break; - case 0x7125: - chip = "82810E (i810E GMCH)"; break; - case 0x7800: - chip = "i740 AGP"; break; - } - break; - case 0x10ea: - vendor = "Intergraphics"; - switch (id >> 16) { - case 0x1680: - chip = "IGA-1680"; break; - case 0x1682: - chip = "IGA-1682"; break; - } - break; - } - - if (vendor && chip) { - char *buf; - int len; - - if (type == 0) - type = "SVGA controller"; - - len = strlen(vendor) + strlen(chip) + strlen(type) + 4; - MALLOC(buf, char *, len, M_TEMP, M_WAITOK); - ksprintf(buf, "%s %s %s", vendor, chip, type); - return buf; - } - - switch (pci_get_class(dev)) { - - case PCIC_OLD: - if (pci_get_subclass(dev) != PCIS_OLD_VGA) - return 0; - if (type == 0) - type = "VGA-compatible display device"; - break; - - case PCIC_DISPLAY: - if (type == 0) { - if (pci_get_subclass(dev) == PCIS_DISPLAY_VGA) - type = "VGA-compatible display device"; - else { - /* - * If it isn't a vga display device, - * don't pretend we found one. - */ - return 0; - } - } - break; - - default: - return 0; - }; - /* - * If we got here, we know for sure it's some sort of display - * device, but we weren't able to identify it specifically. - * At a minimum we can return the type, but we'd like to - * identify the vendor and chip ID if at all possible. - * (Some of the checks above intentionally don't bother for - * vendors where we know the chip ID is the same as the - * model number.) - */ - if (vendor) { - char *buf; - int len; - - len = strlen(vendor) + 7 + 4 + 1 + strlen(type) + 1; - MALLOC(buf, char *, len, M_TEMP, M_WAITOK); - ksprintf(buf, "%s model %04x %s", vendor, id >> 16, type); - return buf; - } - return type; -} - -/*--------------------------------------------------------- -** -** Devices to ignore -** -**--------------------------------------------------------- -*/ - -static const char* -ign_match(device_t dev) -{ - switch (pci_get_devid(dev)) { - - case 0x10001042ul: /* wd */ - return ("SMC FDC 37c665"); - }; - - return NULL; -} - -static int -ign_probe(device_t dev) -{ - const char *s; - - s = ign_match(dev); - if (s) { - device_set_desc(dev, s); - device_quiet(dev); - return -1000; - } - return ENXIO; -} - -static int -ign_attach(device_t dev) -{ - return 0; -} - -static device_method_t ign_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ign_probe), - DEVMETHOD(device_attach, ign_attach), - - { 0, 0 } -}; - -static driver_t ign_driver = { - "ign", - ign_methods, - 1, -}; - -static devclass_t ign_devclass; - -DRIVER_MODULE(ign, pci, ign_driver, ign_devclass, 0, 0); diff --git a/sys/bus/pci/pcivar.h b/sys/bus/pci/pcivar.h index 4d524c9d94..9687528b33 100644 --- a/sys/bus/pci/pcivar.h +++ b/sys/bus/pci/pcivar.h @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1997, Stefan Esser * All rights reserved. * @@ -23,141 +23,188 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/pcivar.h,v 1.48 2000/09/28 00:37:32 peter Exp $ - * $DragonFly: src/sys/bus/pci/pcivar.h,v 1.17 2008/10/19 09:13:58 sephe Exp $ + * $FreeBSD: src/sys/dev/pci/pcivar.h,v 1.80.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $ * */ #ifndef _PCIVAR_H_ -#define _PCIVAR_H_ +#define _PCIVAR_H_ #include +#include +extern const char *pcib_owner; /* arbitrate who owns the pci device arch */ /* some PCI bus constants */ -#define PCI_BUSMAX 255 /* highest supported bus number */ -#define PCI_SLOTMAX 31 /* highest supported slot number */ -#define PCI_FUNCMAX 7 /* highest supported function number */ -#define PCI_REGMAX 255 /* highest supported config register addr. */ +#define PCI_DOMAINMAX 65535 /* highest supported domain number */ +#define PCI_BUSMAX 255 /* highest supported bus number */ +#define PCI_SLOTMAX 31 /* highest supported slot number */ +#define PCI_FUNCMAX 7 /* highest supported function number */ +#define PCI_REGMAX 255 /* highest supported config register addr. */ -#define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */ -#define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */ -#define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */ +#define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */ +#define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */ +#define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */ -/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */ +typedef uint64_t pci_addr_t; -#ifdef PCI_A64 -typedef u_int64_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ -#else -typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ -#endif - -/* config values for PCI power management capability */ -struct pcicfg_pmgt { - u_int16_t pp_cap; /* PCI power management capabilities */ - u_int8_t pp_status; /* config space address of PCI power status reg */ - u_int8_t pp_pmcsr; /* config space address of PMCSR reg */ - u_int8_t pp_data; /* config space address of PCI power data reg */ +/* Interesting values for PCI power management */ +struct pcicfg_pp { + uint16_t pp_cap; /* PCI power management capabilities */ + uint8_t pp_status; /* config space address of PCI power status reg */ + uint8_t pp_pmcsr; /* config space address of PMCSR reg */ + uint8_t pp_data; /* config space address of PCI power data reg */ }; - -/* config values for PCI Express capability */ -struct pcicfg_expr { - uint8_t expr_ptr; /* capability ptr */ - uint16_t expr_cap; /* capabilities */ - uint32_t expr_slotcap; /* slot capabilities */ + +struct vpd_readonly { + char keyword[2]; + char *value; }; -/* config header information common to all header types */ - -typedef struct pcicfg { - struct device *dev; /* device which owns this */ - void *hdrspec; /* pointer to header type specific data */ - - uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ - uint32_t bios; /* BIOS mapping */ +struct vpd_write { + char keyword[2]; + char *value; + int start; + int len; +}; - u_int16_t subvendor; /* card vendor ID */ - u_int16_t subdevice; /* card device ID, assigned by card vendor */ - u_int16_t vendor; /* chip vendor ID */ - u_int16_t device; /* chip device ID, assigned by chip vendor */ +struct pcicfg_vpd { + uint8_t vpd_reg; /* base register, + 2 for addr, + 4 data */ + char vpd_cached; + char *vpd_ident; /* string identifier */ + int vpd_rocnt; + struct vpd_readonly *vpd_ros; + int vpd_wcnt; + struct vpd_write *vpd_w; +}; - u_int16_t cmdreg; /* disable/enable chip and PCI options */ - u_int16_t statreg; /* supported PCI features and error state */ +/* Interesting values for PCI MSI */ +struct pcicfg_msi { + uint16_t msi_ctrl; /* Message Control */ + uint8_t msi_location; /* Offset of MSI capability registers. */ + uint8_t msi_msgnum; /* Number of messages */ + int msi_alloc; /* Number of allocated messages. */ + uint64_t msi_addr; /* Contents of address register. */ + uint16_t msi_data; /* Contents of data register. */ + u_int msi_handlers; +}; - u_int8_t baseclass; /* chip PCI class */ - u_int8_t subclass; /* chip PCI subclass */ - u_int8_t progif; /* chip PCI programming interface */ - u_int8_t revid; /* chip revision ID */ +/* Interesting values for PCI MSI-X */ +struct msix_vector { + uint64_t mv_address; /* Contents of address register. */ + uint32_t mv_data; /* Contents of data register. */ + int mv_irq; +}; - u_int8_t hdrtype; /* chip config header type */ - u_int8_t cachelnsz; /* cache line size in 4byte units */ - u_int8_t intpin; /* PCI interrupt pin */ - u_int8_t intline; /* interrupt line (IRQ for PC arch) */ +struct msix_table_entry { + u_int mte_vector; /* 1-based index into msix_vectors array. */ + u_int mte_handlers; +}; - u_int8_t mingnt; /* min. useful bus grant time in 250ns units */ - u_int8_t maxlat; /* max. tolerated bus grant latency in 250ns */ - u_int8_t lattimer; /* latency timer in units of 30ns bus cycles */ +struct pcicfg_msix { + uint16_t msix_ctrl; /* Message Control */ + uint16_t msix_msgnum; /* Number of messages */ + uint8_t msix_location; /* Offset of MSI-X capability registers. */ + uint8_t msix_table_bar; /* BAR containing vector table. */ + uint8_t msix_pba_bar; /* BAR containing PBA. */ + uint32_t msix_table_offset; + uint32_t msix_pba_offset; + int msix_alloc; /* Number of allocated vectors. */ + int msix_table_len; /* Length of virtual table. */ + struct msix_table_entry *msix_table; /* Virtual table. */ + struct msix_vector *msix_vectors; /* Array of allocated vectors. */ + struct resource *msix_table_res; /* Resource containing vector table. */ + struct resource *msix_pba_res; /* Resource containing PBA. */ +}; - u_int8_t mfdev; /* multi-function device (from hdrtype reg) */ - u_int8_t nummaps; /* actual number of PCI maps used */ +/* Interesting values for HyperTransport */ +struct pcicfg_ht { + uint8_t ht_msimap; /* Offset of MSI mapping cap registers. */ + uint16_t ht_msictrl; /* MSI mapping control */ + uint64_t ht_msiaddr; /* MSI mapping base address */ +}; - u_int8_t bus; /* config space bus address */ - u_int8_t slot; /* config space slot address */ - u_int8_t func; /* config space function number */ +/* config header information common to all header types */ +typedef struct pcicfg { + struct device *dev; /* device which owns this */ - u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ - u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ + uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ + uint32_t bios; /* BIOS mapping */ - struct pcicfg_pmgt pmgt; /* power management capability */ - struct pcicfg_expr expr; /* PCI Express capability */ - u_int8_t pcixcap_ptr; /* PCI-X capability PTR */ - u_int8_t vpdcap_ptr; /* Vital Product Data capability */ + uint16_t subvendor; /* card vendor ID */ + uint16_t subdevice; /* card device ID, assigned by card vendor */ + uint16_t vendor; /* chip vendor ID */ + uint16_t device; /* chip device ID, assigned by chip vendor */ + + uint16_t cmdreg; /* disable/enable chip and PCI options */ + uint16_t statreg; /* supported PCI features and error state */ + + uint8_t baseclass; /* chip PCI class */ + uint8_t subclass; /* chip PCI subclass */ + uint8_t progif; /* chip PCI programming interface */ + uint8_t revid; /* chip revision ID */ + + uint8_t hdrtype; /* chip config header type */ + uint8_t cachelnsz; /* cache line size in 4byte units */ + uint8_t intpin; /* PCI interrupt pin */ + uint8_t intline; /* interrupt line (IRQ for PC arch) */ + + uint8_t mingnt; /* min. useful bus grant time in 250ns units */ + uint8_t maxlat; /* max. tolerated bus grant latency in 250ns */ + uint8_t lattimer; /* latency timer in units of 30ns bus cycles */ + + uint8_t mfdev; /* multi-function device (from hdrtype reg) */ + uint8_t nummaps; /* actual number of PCI maps used */ + + uint32_t domain; /* PCI domain */ + uint8_t bus; /* config space bus address */ + uint8_t slot; /* config space slot address */ + uint8_t func; /* config space function number */ + + struct pcicfg_pp pp; /* pci power management */ + struct pcicfg_vpd vpd; /* pci vital product data */ + struct pcicfg_msi msi; /* pci msi */ + struct pcicfg_msix msix; /* pci msi-x */ + struct pcicfg_ht ht; /* HyperTransport */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ -#ifdef PCI_A64 -#define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff) -#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff) -#else -#define PCI_PPBMEMBASE(h,l) (((l)<<16) & ~0xfffff) -#define PCI_PPBMEMLIMIT(h,l) (((l)<<16) | 0xfffff) -#endif /* PCI_A64 */ - -#define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) -#define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) +#define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff) +#define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) +#define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) typedef struct { pci_addr_t pmembase; /* base address of prefetchable memory */ pci_addr_t pmemlimit; /* topmost address of prefetchable memory */ - u_int32_t membase; /* base address of memory window */ - u_int32_t memlimit; /* topmost address of memory window */ - u_int32_t iobase; /* base address of port window */ - u_int32_t iolimit; /* topmost address of port window */ - u_int16_t secstat; /* secondary bus status register */ - u_int16_t bridgectl; /* bridge control register */ - u_int8_t seclat; /* CardBus latency timer */ + uint32_t membase; /* base address of memory window */ + uint32_t memlimit; /* topmost address of memory window */ + uint32_t iobase; /* base address of port window */ + uint32_t iolimit; /* topmost address of port window */ + uint16_t secstat; /* secondary bus status register */ + uint16_t bridgectl; /* bridge control register */ + uint8_t seclat; /* CardBus latency timer */ } pcih1cfgregs; /* additional type 2 device config header information (CardBus bridge) */ typedef struct { - u_int32_t membase0; /* base address of memory window */ - u_int32_t memlimit0; /* topmost address of memory window */ - u_int32_t membase1; /* base address of memory window */ - u_int32_t memlimit1; /* topmost address of memory window */ - u_int32_t iobase0; /* base address of port window */ - u_int32_t iolimit0; /* topmost address of port window */ - u_int32_t iobase1; /* base address of port window */ - u_int32_t iolimit1; /* topmost address of port window */ - u_int32_t pccardif; /* PC Card 16bit IF legacy more base addr. */ - u_int16_t secstat; /* secondary bus status register */ - u_int16_t bridgectl; /* bridge control register */ - u_int8_t seclat; /* CardBus latency timer */ + uint32_t membase0; /* base address of memory window */ + uint32_t memlimit0; /* topmost address of memory window */ + uint32_t membase1; /* base address of memory window */ + uint32_t memlimit1; /* topmost address of memory window */ + uint32_t iobase0; /* base address of port window */ + uint32_t iolimit0; /* topmost address of port window */ + uint32_t iobase1; /* base address of port window */ + uint32_t iolimit1; /* topmost address of port window */ + uint32_t pccardif; /* PC Card 16bit IF legacy more base addr. */ + uint16_t secstat; /* secondary bus status register */ + uint16_t bridgectl; /* bridge control register */ + uint8_t seclat; /* CardBus latency timer */ } pcih2cfgregs; -extern u_int32_t pci_numdevs; -extern const char *pcib_owner; /* arbitrate who owns the pci device arch */ +extern uint32_t pci_numdevs; /* Only if the prerequisites are present */ #if defined(_SYS_BUS_H_) && defined(_SYS_PCIIO_H_) @@ -169,21 +216,6 @@ struct pci_devinfo { }; #endif -/* externally visible functions */ - -const char *pci_ata_match(struct device *dev); -const char *pci_usb_match(struct device *dev); -const char *pci_vga_match(struct device *dev); -const char *pci_chip_match(struct device *dev); - -/* low level PCI config register functions provided by pcibus.c */ - -int pci_cfgread (pcicfgregs *cfg, int reg, int bytes); -void pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes); - -/* low level devlist operations for the 2.2 compatibility code in pci.c */ -pcicfgregs * pci_devlist_get_parent(pcicfgregs *cfg); - #ifdef _SYS_BUS_H_ #include "pci_if.h" @@ -192,131 +224,165 @@ pcicfgregs * pci_devlist_get_parent(pcicfgregs *cfg); * Define pci-specific resource flags for accessing memory via dense * or bwx memory spaces. These flags are ignored on i386. */ -#define PCI_RF_DENSE 0x10000 -#define PCI_RF_BWX 0x20000 +#define PCI_RF_DENSE 0x10000 +#define PCI_RF_BWX 0x20000 enum pci_device_ivars { - PCI_IVAR_SUBVENDOR, - PCI_IVAR_SUBDEVICE, - PCI_IVAR_VENDOR, - PCI_IVAR_DEVICE, - PCI_IVAR_DEVID, - PCI_IVAR_CLASS, - PCI_IVAR_SUBCLASS, - PCI_IVAR_PROGIF, - PCI_IVAR_REVID, - PCI_IVAR_INTPIN, - PCI_IVAR_IRQ, - PCI_IVAR_BUS, - PCI_IVAR_SLOT, - PCI_IVAR_FUNCTION, - PCI_IVAR_SECONDARYBUS, - PCI_IVAR_SUBORDINATEBUS, - PCI_IVAR_ETHADDR, - PCI_IVAR_PCIXCAP_PTR, - PCI_IVAR_PCIECAP_PTR, - PCI_IVAR_VPDCAP_PTR + PCI_IVAR_SUBVENDOR, + PCI_IVAR_SUBDEVICE, + PCI_IVAR_VENDOR, + PCI_IVAR_DEVICE, + PCI_IVAR_DEVID, + PCI_IVAR_CLASS, + PCI_IVAR_SUBCLASS, + PCI_IVAR_PROGIF, + PCI_IVAR_REVID, + PCI_IVAR_INTPIN, + PCI_IVAR_IRQ, + PCI_IVAR_DOMAIN, + PCI_IVAR_BUS, + PCI_IVAR_SLOT, + PCI_IVAR_FUNCTION, + PCI_IVAR_ETHADDR, + PCI_IVAR_CMDREG, + PCI_IVAR_CACHELNSZ, + PCI_IVAR_MINGNT, + PCI_IVAR_MAXLAT, + PCI_IVAR_LATTIMER, }; /* * Simplified accessors for pci devices - * - * The PCI device passed in actually represents a PCI function number - * for the current slot. The parent of dev is the "pci" slot device. - * Each function number has its own set of ivars. */ -#define PCI_ACCESSOR(A, B, T) \ - \ -static __inline T pci_get_ ## A(device_t dev) \ -{ \ - uintptr_t v; \ - BUS_READ_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, &v); \ - return (T) v; \ -} \ - \ -static __inline void pci_set_ ## A(device_t dev, T t) \ -{ \ - uintptr_t v = (uintptr_t) t; \ - BUS_WRITE_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, v); \ -} - -PCI_ACCESSOR(subvendor, SUBVENDOR, u_int16_t) -PCI_ACCESSOR(subdevice, SUBDEVICE, u_int16_t) -PCI_ACCESSOR(vendor, VENDOR, u_int16_t) -PCI_ACCESSOR(device, DEVICE, u_int16_t) -PCI_ACCESSOR(devid, DEVID, u_int32_t) -PCI_ACCESSOR(class, CLASS, u_int8_t) -PCI_ACCESSOR(subclass, SUBCLASS, u_int8_t) -PCI_ACCESSOR(progif, PROGIF, u_int8_t) -PCI_ACCESSOR(revid, REVID, u_int8_t) -PCI_ACCESSOR(intpin, INTPIN, u_int8_t) -PCI_ACCESSOR(irq, IRQ, u_int8_t) -PCI_ACCESSOR(bus, BUS, u_int8_t) -PCI_ACCESSOR(slot, SLOT, u_int8_t) -PCI_ACCESSOR(function, FUNCTION, u_int8_t) -PCI_ACCESSOR(secondarybus, SECONDARYBUS, u_int8_t) -PCI_ACCESSOR(subordinatebus, SUBORDINATEBUS, u_int8_t) +#define PCI_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(pci, var, PCI, ivar, type) + +PCI_ACCESSOR(subvendor, SUBVENDOR, uint16_t) +PCI_ACCESSOR(subdevice, SUBDEVICE, uint16_t) +PCI_ACCESSOR(vendor, VENDOR, uint16_t) +PCI_ACCESSOR(device, DEVICE, uint16_t) +PCI_ACCESSOR(devid, DEVID, uint32_t) +PCI_ACCESSOR(class, CLASS, uint8_t) +PCI_ACCESSOR(subclass, SUBCLASS, uint8_t) +PCI_ACCESSOR(progif, PROGIF, uint8_t) +PCI_ACCESSOR(revid, REVID, uint8_t) +PCI_ACCESSOR(intpin, INTPIN, uint8_t) +PCI_ACCESSOR(irq, IRQ, uint8_t) +PCI_ACCESSOR(domain, DOMAIN, uint32_t) +PCI_ACCESSOR(bus, BUS, uint8_t) +PCI_ACCESSOR(slot, SLOT, uint8_t) +PCI_ACCESSOR(function, FUNCTION, uint8_t) PCI_ACCESSOR(ether, ETHADDR, uint8_t *) -PCI_ACCESSOR(pcixcap_ptr, PCIXCAP_PTR, uint8_t) -PCI_ACCESSOR(pciecap_ptr, PCIECAP_PTR, uint8_t) -PCI_ACCESSOR(vpdcap_ptr, VPDCAP_PTR, uint8_t) +PCI_ACCESSOR(cmdreg, CMDREG, uint8_t) +PCI_ACCESSOR(cachelnsz, CACHELNSZ, uint8_t) +PCI_ACCESSOR(mingnt, MINGNT, uint8_t) +PCI_ACCESSOR(maxlat, MAXLAT, uint8_t) +PCI_ACCESSOR(lattimer, LATTIMER, uint8_t) #undef PCI_ACCESSOR -static __inline u_int32_t +/* + * Operations on configuration space. + */ +static __inline uint32_t pci_read_config(device_t dev, int reg, int width) { return PCI_READ_CONFIG(device_get_parent(dev), dev, reg, width); } static __inline void -pci_write_config(device_t dev, int reg, u_int32_t val, int width) +pci_write_config(device_t dev, int reg, uint32_t val, int width) { PCI_WRITE_CONFIG(device_get_parent(dev), dev, reg, val, width); } +/* + * Ivars for pci bridges. + */ + +/*typedef enum pci_device_ivars pcib_device_ivars;*/ +enum pcib_device_ivars { + PCIB_IVAR_DOMAIN, + PCIB_IVAR_BUS +}; + +#define PCIB_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(pcib, var, PCIB, ivar, type) + +PCIB_ACCESSOR(domain, DOMAIN, uint32_t) +PCIB_ACCESSOR(bus, BUS, uint32_t) + +#undef PCIB_ACCESSOR + +/* + * PCI interrupt validation. Invalid interrupt values such as 0 or 128 + * on i386 or other platforms should be mapped out in the MD pcireadconf + * code and not here, since the only MI invalid IRQ is 255. + */ +#define PCI_INVALID_IRQ 255 +#define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ) + /* * Convenience functions. * * These should be used in preference to manually manipulating * configuration space. */ -static __inline void +static __inline int pci_enable_busmaster(device_t dev) { - PCI_ENABLE_BUSMASTER(device_get_parent(dev), dev); + return(PCI_ENABLE_BUSMASTER(device_get_parent(dev), dev)); } -static __inline void +static __inline int pci_disable_busmaster(device_t dev) { - PCI_DISABLE_BUSMASTER(device_get_parent(dev), dev); + return(PCI_DISABLE_BUSMASTER(device_get_parent(dev), dev)); } -static __inline void +static __inline int pci_enable_io(device_t dev, int space) { - PCI_ENABLE_IO(device_get_parent(dev), dev, space); + return(PCI_ENABLE_IO(device_get_parent(dev), dev, space)); } -static __inline void +static __inline int pci_disable_io(device_t dev, int space) { - PCI_DISABLE_IO(device_get_parent(dev), dev, space); + return(PCI_DISABLE_IO(device_get_parent(dev), dev, space)); } static __inline int -pci_is_pcie(device_t dev) +pci_get_vpd_ident(device_t dev, const char **identptr) { - return (pci_get_pciecap_ptr(dev) != 0); + return(PCI_GET_VPD_IDENT(device_get_parent(dev), dev, identptr)); } static __inline int -pci_is_pcix(device_t dev) +pci_get_vpd_readonly(device_t dev, const char *kw, const char **identptr) +{ + return(PCI_GET_VPD_READONLY(device_get_parent(dev), dev, kw, identptr)); +} + +/* + * Check if the address range falls within the VGA defined address range(s) + */ +static __inline int +pci_is_vga_ioport_range(u_long start, u_long end) +{ + + return (((start >= 0x3b0 && end <= 0x3bb) || + (start >= 0x3c0 && end <= 0x3df)) ? 1 : 0); +} + +static __inline int +pci_is_vga_memory_range(u_long start, u_long end) { - return (pci_get_pcixcap_ptr(dev) != 0); + + return ((start >= 0xa0000 && end <= 0xbffff) ? 1 : 0); } +void pcie_set_max_readrq(device_t, uint16_t); /* * PCI power states are as defined by ACPI: * @@ -324,19 +390,19 @@ pci_is_pcix(device_t dev) * power from the system and delivering full functionality to the user. * D1 Class-specific low-power state in which device context may or may not * be lost. Buses in D1 cannot do anything to the bus that would force - * devices on that bus to loose context. + * devices on that bus to lose context. * D2 Class-specific low-power state in which device context may or may * not be lost. Attains greater power savings than D1. Buses in D2 - * can cause devices on that bus to loose some context. Devices in D2 + * can cause devices on that bus to lose some context. Devices in D2 * must be prepared for the bus to be in D2 or higher. * D3 State in which the device is off and not running. Device context is * lost. Power can be removed from the device. */ -#define PCI_POWERSTATE_D0 0 -#define PCI_POWERSTATE_D1 1 -#define PCI_POWERSTATE_D2 2 -#define PCI_POWERSTATE_D3 3 -#define PCI_POWERSTATE_UNKNOWN -1 +#define PCI_POWERSTATE_D0 0 +#define PCI_POWERSTATE_D1 1 +#define PCI_POWERSTATE_D2 2 +#define PCI_POWERSTATE_D3 3 +#define PCI_POWERSTATE_UNKNOWN -1 static __inline int pci_set_powerstate(device_t dev, int state) @@ -350,97 +416,119 @@ pci_get_powerstate(device_t dev) return PCI_GET_POWERSTATE(device_get_parent(dev), dev); } -/* - * Ivars for pci bridges. - * - * Whereas PCI devices are arranged [pciX]->[pciX.Y] with the pci driver - * functions in [pciX] but the individual ivars in [pciX.Y], PCI bridges - * are installed in [pciX.Y] and store their ivars in a softc. This - * is why the accessor functions for a bridge do not call device_get_parent(). - */ -/*typedef enum pci_device_ivars pcib_device_ivars;*/ -enum pcib_device_ivars { - PCIB_IVAR_BUS, -}; +static __inline int +pci_find_extcap(device_t dev, int capability, int *capreg) +{ + return PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg); +} + +static __inline int +pci_is_pcie(device_t dev) +{ + int reg; + return (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0); +} -#define PCIB_ACCESSOR(A, B, T) \ - \ -static __inline T pcib_get_ ## A(device_t dev) \ -{ \ - uintptr_t v; \ - BUS_READ_IVAR(dev, dev, PCIB_IVAR_ ## B, &v); \ - return (T) v; \ -} \ - \ -static __inline void pcib_set_ ## A(device_t dev, T t) \ -{ \ - uintptr_t v = (uintptr_t) t; \ - BUS_WRITE_IVAR(dev, dev, PCIB_IVAR_ ## B, v); \ +static __inline int +pci_is_pcix(device_t dev) +{ + int reg; + return (pci_find_extcap(dev, PCIY_PCIX, ®) == 0); } -PCIB_ACCESSOR(bus, BUS, u_int32_t) +#warning "this code is probably incorrect" +static __inline int* +pci_get_vpdcap_ptr(device_t dev) +{ + int *reg; + pci_find_extcap(dev, PCIY_VPD, reg); + return reg; +} -#undef PCIB_ACCESSOR +static __inline int* +pci_get_pciecap_ptr(device_t dev) +{ + int *reg; + pci_find_extcap(dev, PCIY_EXPRESS, reg); + return reg; +} -device_t pci_find_bsf(u_int8_t, u_int8_t, u_int8_t); -device_t pci_find_device(u_int16_t, u_int16_t); -int pcie_slot_implemented(device_t); -void pcie_set_max_readrq(device_t, uint16_t); -#endif -/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */ +static __inline int* +pci_get_pcixcap_ptr(device_t dev) +{ + int *reg; + pci_find_extcap(dev, PCIY_PCIX, reg); + return reg; +} -#if defined(_KERNEL) && !defined(KLD_MODULE) -#include "opt_compat_oldpci.h" -#endif -#ifdef COMPAT_OLDPCI -/* all this is going some day */ +static __inline int +pci_alloc_msi(device_t dev, int *count) +{ + return (PCI_ALLOC_MSI(device_get_parent(dev), dev, count)); +} + +static __inline int +pci_alloc_msix(device_t dev, int *count) +{ + return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count)); +} -typedef pcicfgregs *pcici_t; -typedef unsigned pcidi_t; -typedef void pci_inthand_t(void *arg); +static __inline int +pci_remap_msix(device_t dev, int count, const u_int *vectors) +{ + return (PCI_REMAP_MSIX(device_get_parent(dev), dev, count, vectors)); +} -#define pci_max_burst_len (3) +static __inline int +pci_release_msi(device_t dev) +{ + return (PCI_RELEASE_MSI(device_get_parent(dev), dev)); +} -/* just copied from old PCI code for now ... */ +static __inline int +pci_msi_count(device_t dev) +{ + return (PCI_MSI_COUNT(device_get_parent(dev), dev)); +} -struct pci_device { - char* pd_name; - const char* (*pd_probe ) (pcici_t tag, pcidi_t type); - void (*pd_attach) (pcici_t tag, int unit); - u_long *pd_count; - int (*pd_shutdown) (int, int); -}; +static __inline int +pci_msix_count(device_t dev) +{ + return (PCI_MSIX_COUNT(device_get_parent(dev), dev)); +} -#ifdef __i386__ -typedef u_short pci_port_t; -#else -typedef u_int pci_port_t; -#endif +device_t pci_find_bsf(uint8_t, uint8_t, uint8_t); +device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t); +device_t pci_find_device(uint16_t, uint16_t); + +/* + * Can be used by MD code to request the PCI bus to re-map an MSI or + * MSI-X message. + */ +int pci_remap_msi_irq(device_t dev, u_int irq); + +/* Can be used by drivers to manage the MSI-X table. */ +int pci_pending_msix(device_t dev, u_int index); + +int pci_msi_device_blacklisted(device_t dev); + +void pci_ht_map_msi(device_t dev, uint64_t addr); + +#endif /* _SYS_BUS_H_ */ + +/* + * cdev switch for control device, initialised in generic PCI code + */ +extern struct cdevsw pcicdev; + +/* + * List of all PCI devices, generation count for the list. + */ +STAILQ_HEAD(devlist, pci_devinfo); + +extern struct devlist pci_devq; +extern uint32_t pci_generation; -u_long pci_conf_read (pcici_t tag, u_long reg); -void pci_conf_write (pcici_t tag, u_long reg, u_long data); -int pci_map_port (pcici_t tag, u_long reg, pci_port_t* pa); -int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); -int pci_map_int (pcici_t tag, pci_inthand_t *handler, void *arg); -int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, - u_int flags); -int pci_unmap_int (pcici_t tag); - -pcici_t pci_get_parent_from_tag(pcici_t tag); -int pci_get_bus_from_tag(pcici_t tag); - -struct module; -int compat_pci_handler (struct module *, int, void *); -#define COMPAT_PCI_DRIVER(name, pcidata) \ -static moduledata_t name##_mod = { \ - #name, \ - compat_pci_handler, \ - &pcidata \ -}; \ -DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_ANY) - - -#endif /* COMPAT_OLDPCI */ #endif /* _PCIVAR_H_ */ diff --git a/sys/bus/pci/vga_pci.c b/sys/bus/pci/vga_pci.c new file mode 100644 index 0000000000..8d2444be21 --- /dev/null +++ b/sys/bus/pci/vga_pci.c @@ -0,0 +1,255 @@ +/*- + * Copyright (c) 2005 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * __FBSDID("$FreeBSD: src/sys/dev/pci/vga_pci.c,v 1.5.8.1 2009/04/15 03:14:26 kensmith Exp $"); + */ + +#include + +/* + * Simple driver for PCI VGA display devices. Drivers such as agp(4) and + * drm(4) should attach as children of this device. + * + * XXX: The vgapci name is a hack until we somehow merge the isa vga driver + * in or rename it. + */ + +#include +#include +#include +#include + +#include +#include + +static int +vga_pci_probe(device_t dev) +{ + + switch (pci_get_class(dev)) { + case PCIC_DISPLAY: + break; + case PCIC_OLD: + if (pci_get_subclass(dev) != PCIS_OLD_VGA) + return (ENXIO); + break; + default: + return (ENXIO); + } + device_set_desc(dev, "VGA-compatible display"); + return (BUS_PROBE_GENERIC); +} + +static int +vga_pci_attach(device_t dev) +{ + + bus_generic_probe(dev); + + /* Always create a drm child for now to make it easier on drm. */ + device_add_child(dev, "drm", -1); + bus_generic_attach(dev); + return (0); +} + +static int +vga_pci_suspend(device_t dev) +{ + + return (bus_generic_suspend(dev)); +} + +static int +vga_pci_resume(device_t dev) +{ + + return (bus_generic_resume(dev)); +} + +/* Bus interface. */ + +static int +vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + + return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result)); +} + +static int +vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + + return (EINVAL); +} + +static struct resource * +vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + + return (bus_alloc_resource(dev, type, rid, start, end, count, flags)); +} + +static int +vga_pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + return (bus_release_resource(dev, type, rid, r)); +} + +/* PCI interface. */ + +static uint32_t +vga_pci_read_config(device_t dev, device_t child, int reg, int width) +{ + + return (pci_read_config(dev, reg, width)); +} + +static void +vga_pci_write_config(device_t dev, device_t child, int reg, + uint32_t val, int width) +{ + + pci_write_config(dev, reg, val, width); +} + +static int +vga_pci_enable_busmaster(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_enable_busmaster\n", + device_get_nameunit(child)); + return (pci_enable_busmaster(dev)); +} + +static int +vga_pci_disable_busmaster(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_disable_busmaster\n", + device_get_nameunit(child)); + return (pci_disable_busmaster(dev)); +} + +static int +vga_pci_enable_io(device_t dev, device_t child, int space) +{ + + device_printf(dev, "child %s requested pci_enable_io\n", + device_get_nameunit(child)); + return (pci_enable_io(dev, space)); +} + +static int +vga_pci_disable_io(device_t dev, device_t child, int space) +{ + + device_printf(dev, "child %s requested pci_disable_io\n", + device_get_nameunit(child)); + return (pci_disable_io(dev, space)); +} + +static int +vga_pci_set_powerstate(device_t dev, device_t child, int state) +{ + + device_printf(dev, "child %s requested pci_set_powerstate\n", + device_get_nameunit(child)); + return (pci_set_powerstate(dev, state)); +} + +static int +vga_pci_get_powerstate(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_get_powerstate\n", + device_get_nameunit(child)); + return (pci_get_powerstate(dev)); +} + +static int +vga_pci_assign_interrupt(device_t dev, device_t child) +{ + + device_printf(dev, "child %s requested pci_assign_interrupt\n", + device_get_nameunit(child)); + return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); +} + +static int +vga_pci_find_extcap(device_t dev, device_t child, int capability, + int *capreg) +{ + + return (pci_find_extcap(dev, capability, capreg)); +} + +static device_method_t vga_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, vga_pci_probe), + DEVMETHOD(device_attach, vga_pci_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, vga_pci_suspend), + DEVMETHOD(device_resume, vga_pci_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, vga_pci_read_ivar), + DEVMETHOD(bus_write_ivar, vga_pci_write_ivar), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + DEVMETHOD(bus_alloc_resource, vga_pci_alloc_resource), + DEVMETHOD(bus_release_resource, vga_pci_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + /* PCI interface */ + DEVMETHOD(pci_read_config, vga_pci_read_config), + DEVMETHOD(pci_write_config, vga_pci_write_config), + DEVMETHOD(pci_enable_busmaster, vga_pci_enable_busmaster), + DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster), + DEVMETHOD(pci_enable_io, vga_pci_enable_io), + DEVMETHOD(pci_disable_io, vga_pci_disable_io), + DEVMETHOD(pci_get_powerstate, vga_pci_get_powerstate), + DEVMETHOD(pci_set_powerstate, vga_pci_set_powerstate), + DEVMETHOD(pci_assign_interrupt, vga_pci_assign_interrupt), + DEVMETHOD(pci_find_extcap, vga_pci_find_extcap), + + { 0, 0 } +}; + +static driver_t vga_pci_driver = { + "vgapci", + vga_pci_methods, + 1, +}; + +static devclass_t vga_devclass; + +DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0); diff --git a/sys/conf/files b/sys/conf/files index 4bccca5029..4391b7922a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1330,13 +1330,17 @@ dev/video/meteor/meteor.c optional meteor pci dev/disk/ncr/ncr.c optional ncr dev/disk/sym/sym_hipd.c optional sym \ dependency "$S/dev/disk/sym/sym_{conf,defs}.h" -bus/pci/pci.c optional pci -bus/pci/pci_compat.c optional pci compat_oldpci -bus/pci/pci_isab.c optional pci isa -bus/pci/pci_pcib.c optional pci -bus/pci/pcisupport.c optional pci -bus/pci/pci_if.m optional pci -bus/pci/pcib_if.m optional pci +bus/pci/eisa_pci.c optional pci eisa +bus/pci/fixup_pci.c optional pci +bus/pci/hostb_pci.c optional pci +bus/pci/ignore_pci.c optional pci +bus/pci/isa_pci.c optional pci isa +bus/pci/pci.c optional pci +bus/pci/pci_if.m optional pci +bus/pci/pci_pci.c optional pci +bus/pci/pci_user.c optional pci +bus/pci/pcib_if.m optional pci +bus/pci/vga_pci.c optional pci dev/powermng/i386/alpm/alpm.c optional alpm kern/kern_posix4_mib.c standard kern/kern_p1003_1b.c standard diff --git a/sys/dev/pccard/cardbus/cardbus.c b/sys/dev/pccard/cardbus/cardbus.c index 89b5454c9c..d6fb46fc63 100644 --- a/sys/dev/pccard/cardbus/cardbus.c +++ b/sys/dev/pccard/cardbus/cardbus.c @@ -443,11 +443,12 @@ cardbus_attach_card(device_t cbdev) device_t brdev = device_get_parent(cbdev); device_t child; int cardattached = 0; - int bus, slot, func; + int bus, slot, func, domain; cardbus_detach_card(cbdev); /* detach existing cards */ POWER_ENABLE_SOCKET(brdev, cbdev); bus = pcib_get_bus(brdev); + domain = pcib_get_domain(brdev); /* For each function, set it up and try to attach a driver to it */ for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) { int cardbusfunchigh = 0; @@ -455,7 +456,7 @@ cardbus_attach_card(device_t cbdev) struct cardbus_devinfo *dinfo; dinfo = (struct cardbus_devinfo *) - pci_read_device(brdev, bus, slot, func, + pci_read_device(brdev, domain, bus, slot, func, sizeof(struct cardbus_devinfo)); if (dinfo == NULL) continue; diff --git a/sys/kern/kern_slaballoc.c b/sys/kern/kern_slaballoc.c index ab1d8d2697..132f282e45 100644 --- a/sys/kern/kern_slaballoc.c +++ b/sys/kern/kern_slaballoc.c @@ -804,6 +804,18 @@ krealloc(void *ptr, unsigned long size, struct malloc_type *type, int flags) return(nptr); } +/* + * reallocf: same as realloc() but free memory on failure. + */ +void * +kreallocf(void *addr, unsigned long size, struct malloc_type *mtp, int flags) +{ + void *mem; + if ((mem = krealloc(addr, size, mtp, flags)) == NULL) + kfree(addr, mtp); + return (mem); +} + /* * Return the kmalloc limit for this type, in bytes. */ diff --git a/sys/platform/pc32/conf/files b/sys/platform/pc32/conf/files index c5df358b3c..452c9c8e1d 100644 --- a/sys/platform/pc32/conf/files +++ b/sys/platform/pc32/conf/files @@ -219,8 +219,10 @@ dev/misc/labpc/labpc.c optional labpc dev/misc/mse/mse.c optional mse platform/pc32/isa/npx.c mandatory npx bus/iicbus/i386/pcf.c optional pcf -bus/pci/i386/pci_cfgreg.c optional pci -bus/pci/i386/pcibus.c optional pci +bus/pci/i386/legacy.c optional pci +bus/pci/i386/pci_bus.c optional pci +bus/pci/i386/pci_cfgreg.c optional pci +bus/pci/i386/pci_pir.c optional pci platform/pc32/isa/pmtimer.c optional pmtimer acpi # XXX drhodus platform/pc32/isa/prof_machdep.c optional profiling-routine diff --git a/sys/platform/pc32/include/legacyvar.h b/sys/platform/pc32/include/legacyvar.h new file mode 100644 index 0000000000..721a5b7869 --- /dev/null +++ b/sys/platform/pc32/include/legacyvar.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2000 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/i386/include/legacyvar.h,v 1.8.8.1 2009/04/15 03:14:26 kensmith Exp $ + */ + +#ifndef _MACHINE_LEGACYVAR_H_ +#define _MACHINE_LEGACYVAR_H_ + +enum legacy_device_ivars { + LEGACY_IVAR_PCIDOMAIN, + LEGACY_IVAR_PCIBUS +}; + +#define LEGACY_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(legacy, var, LEGACY, ivar, type) + +LEGACY_ACCESSOR(pcidomain, PCIDOMAIN, uint32_t) +LEGACY_ACCESSOR(pcibus, PCIBUS, uint32_t) + +#undef LEGACY_ACCESSOR + +int legacy_pcib_maxslots(device_t dev); +uint32_t legacy_pcib_read_config(device_t dev, int bus, int slot, int func, + int reg, int bytes); +int legacy_pcib_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result); +void legacy_pcib_write_config(device_t dev, int bus, int slot, int func, + int reg, u_int32_t data, int bytes); +int legacy_pcib_write_ivar(device_t dev, device_t child, int which, + uintptr_t value); +struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child, + int type, int *rid, u_long start, u_long end, u_long count, u_int flags); + +#endif /* !_MACHINE_LEGACYVAR_H_ */ diff --git a/sys/sys/bus.h b/sys/sys/bus.h index cf86c40432..c74d69dbbb 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -59,6 +59,7 @@ typedef struct kobj_class driver_t; typedef struct devclass *devclass_t; #define device_method_t kobj_method_t +typedef int driver_filter_t(void*); typedef void driver_intr_t(void*); /* @@ -506,6 +507,26 @@ static moduledata_t name##_##busname##_mod = { \ DECLARE_MODULE(name##_##busname, name##_##busname##_mod, \ SI_SUB_DRIVERS, SI_ORDER_MIDDLE) +/** + * Generic ivar accessor generation macros for bus drivers + */ +#define __BUS_ACCESSOR(varp, var, ivarp, ivar, type) \ + \ +static __inline type varp ## _get_ ## var(device_t dev) \ +{ \ + uintptr_t v; \ + BUS_READ_IVAR(device_get_parent(dev), dev, \ + ivarp ## _IVAR_ ## ivar, &v); \ + return ((type) v); \ +} \ + \ +static __inline void varp ## _set_ ## var(device_t dev, type t) \ +{ \ + uintptr_t v = (uintptr_t) t; \ + BUS_WRITE_IVAR(device_get_parent(dev), dev, \ + ivarp ## _IVAR_ ## ivar, v); \ +} + /** * Shorthand macros, taking resource argument */ diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index 12a00d7f4f..8a3c197da8 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -206,6 +206,8 @@ void kmalloc_destroy(struct malloc_type **typep); void *kmalloc (unsigned long size, struct malloc_type *type, int flags); void *krealloc (void *addr, unsigned long size, struct malloc_type *type, int flags); +void *kreallocf (void *addr, unsigned long size, + struct malloc_type *type, int flags); void kfree (void *addr, struct malloc_type *type); char *kstrdup (const char *, struct malloc_type *); long kmalloc_limit (struct malloc_type *type); diff --git a/sys/sys/pciio.h b/sys/sys/pciio.h index 22ce2bf543..d0632e7ec0 100644 --- a/sys/sys/pciio.h +++ b/sys/sys/pciio.h @@ -49,18 +49,20 @@ typedef enum { } pci_getconf_status; typedef enum { - PCI_GETCONF_NO_MATCH = 0x00, - PCI_GETCONF_MATCH_BUS = 0x01, - PCI_GETCONF_MATCH_DEV = 0x02, - PCI_GETCONF_MATCH_FUNC = 0x04, - PCI_GETCONF_MATCH_NAME = 0x08, - PCI_GETCONF_MATCH_UNIT = 0x10, - PCI_GETCONF_MATCH_VENDOR = 0x20, - PCI_GETCONF_MATCH_DEVICE = 0x40, - PCI_GETCONF_MATCH_CLASS = 0x80 + PCI_GETCONF_NO_MATCH = 0x0000, + PCI_GETCONF_MATCH_DOMAIN = 0x0001, + PCI_GETCONF_MATCH_BUS = 0x0002, + PCI_GETCONF_MATCH_DEV = 0x0004, + PCI_GETCONF_MATCH_FUNC = 0x0008, + PCI_GETCONF_MATCH_NAME = 0x0010, + PCI_GETCONF_MATCH_UNIT = 0x0020, + PCI_GETCONF_MATCH_VENDOR = 0x0040, + PCI_GETCONF_MATCH_DEVICE = 0x0080, + PCI_GETCONF_MATCH_CLASS = 0x0100 } pci_getconf_flags; struct pcisel { + u_int32_t pc_domain; /* domain number */ u_int8_t pc_bus; /* bus number */ u_int8_t pc_dev; /* device on this bus */ u_int8_t pc_func; /* function on this device */ @@ -111,11 +113,19 @@ struct pci_io { int pi_width; /* width (in bytes) of read or write */ u_int32_t pi_data; /* data to write or result of read */ }; - -#define PCIOCGETCONF _IOWR('p', 1, struct pci_conf_io) +struct pci_bar_io { + struct pcisel pbi_sel; /* device to operate on */ + int pbi_reg; /* starting address of BAR */ + int pbi_enabled; /* decoding enabled */ + uint64_t pbi_base; /* current value of BAR */ + uint64_t pbi_length; /* length of BAR */ +}; + +#define PCIOCGETCONF _IOWR('p', 5, struct pci_conf_io) #define PCIOCREAD _IOWR('p', 2, struct pci_io) #define PCIOCWRITE _IOWR('p', 3, struct pci_io) #define PCIOCATTACHED _IOWR('p', 4, struct pci_io) +#define PCIOCGETBAR _IOWR('p', 6, struct pci_bar_io) #endif /* !_SYS_PCIIO_H_ */