diff --git a/sys/alpha/include/resource.h b/sys/alpha/include/resource.h index c9253c9dc0db..28fcc98ea1be 100644 --- a/sys/alpha/include/resource.h +++ b/sys/alpha/include/resource.h @@ -1,46 +1,44 @@ /* $FreeBSD$ */ /* * 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. */ #ifndef _MACHINE_RESOURCE_H_ #define _MACHINE_RESOURCE_H_ 1 /* * Definitions of resource types for Intel Architecture machines * with support for legacy ISA devices and drivers. */ #define SYS_RES_IRQ 1 /* interrupt lines */ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ -#define SYS_RES_DENSE 5 /* i/o memory in dense space */ -#define SYS_RES_BWX 6 /* i/i memory in bwx space */ #endif /* !_MACHINE_RESOURCE_H_ */ diff --git a/sys/alpha/pci/pcibus.c b/sys/alpha/pci/pcibus.c index d49a57c60d4b..b668c827759f 100644 --- a/sys/alpha/pci/pcibus.c +++ b/sys/alpha/pci/pcibus.c @@ -1,372 +1,363 @@ /* * 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$ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char chipset_type[10]; int chipset_bwx = 0; long chipset_ports = 0; long chipset_memory = 0; long chipset_dense = 0; long chipset_hae_mask = 0; SYSCTL_NODE(_hw, OID_AUTO, chipset, CTLFLAG_RW, 0, "PCI chipset information"); SYSCTL_STRING(_hw_chipset, OID_AUTO, type, CTLFLAG_RD, chipset_type, 0, "PCI chipset type"); SYSCTL_INT(_hw_chipset, OID_AUTO, bwx, CTLFLAG_RD, &chipset_bwx, 0, "PCI chipset supports BWX access"); SYSCTL_LONG(_hw_chipset, OID_AUTO, ports, CTLFLAG_RD, &chipset_ports, "PCI chipset port address"); SYSCTL_LONG(_hw_chipset, OID_AUTO, memory, CTLFLAG_RD, &chipset_memory, "PCI chipset memory address"); SYSCTL_LONG(_hw_chipset, OID_AUTO, dense, CTLFLAG_RD, &chipset_dense, "PCI chipset dense memory address"); SYSCTL_LONG(_hw_chipset, OID_AUTO, hae_mask, CTLFLAG_RD, &chipset_hae_mask, "PCI chipset mask for HAE register"); #ifdef notyet /* return max number of devices on the bus */ int pci_maxdevs(pcicfgregs *cfg) { return chipset.maxdevs(cfg->bus); } #endif /* read configuration space register */ int pci_cfgread(pcicfgregs *cfg, int reg, int bytes) { switch (bytes) { case 1: return chipset.cfgreadb(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg); case 2: return chipset.cfgreadw(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg); case 4: return chipset.cfgreadl(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg); } return ~0; } /* write configuration space register */ void pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) { switch (bytes) { case 1: return chipset.cfgwriteb(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg, data); case 2: return chipset.cfgwritew(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg, data); case 4: return chipset.cfgwritel(cfg->hose, cfg->bus, cfg->slot, cfg->func, reg, data); } } vm_offset_t pci_cvt_to_dense(vm_offset_t sparse) { if(chipset.cvt_to_dense) return ALPHA_PHYS_TO_K0SEG(chipset.cvt_to_dense(sparse)); else return NULL; } vm_offset_t pci_cvt_to_bwx(vm_offset_t sparse) { if(chipset.cvt_to_bwx) return ALPHA_PHYS_TO_K0SEG(chipset.cvt_to_bwx(sparse)); else return NULL; } void alpha_platform_assign_pciintr(pcicfgregs *cfg) { if(platform.pci_intr_map) platform.pci_intr_map((void *)cfg); } int alpha_platform_setup_ide_intr(int chan, driver_intr_t *fn, void *arg) { if (platform.pci_setup_ide_intr) return platform.pci_setup_ide_intr(chan, fn, arg); else { int irqs[2] = { 14, 15 }; void *junk; struct resource *res; res = isa_alloc_intr(0, 0, irqs[chan]); if (res) return isa_setup_intr(0, 0, res, INTR_TYPE_BIO, fn, arg, &junk); else return ENOMEM; } } static struct rman irq_rman, port_rman, mem_rman; void pci_init_resources() { irq_rman.rm_start = 0; irq_rman.rm_end = 64; irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_descr = "PCI Interrupt request lines"; if (rman_init(&irq_rman) || rman_manage_region(&irq_rman, 0, 63)) panic("pci_init_resources irq_rman"); port_rman.rm_start = 0; port_rman.rm_end = ~0u; port_rman.rm_type = RMAN_ARRAY; port_rman.rm_descr = "I/O ports"; if (rman_init(&port_rman) || rman_manage_region(&port_rman, 0x0, (1L << 32))) panic("pci_init_resources port_rman"); mem_rman.rm_start = 0; mem_rman.rm_end = ~0u; mem_rman.rm_type = RMAN_ARRAY; mem_rman.rm_descr = "I/O memory"; if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0x0, (1L << 32))) panic("pci_init_resources mem_rman"); } /* * Allocate a resource on behalf of child. NB: child is usually going to be a * child of one of our descendants, not a direct child of the pci chipset. */ struct resource * pci_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct rman *rm; struct resource *rv; switch (type) { case SYS_RES_IRQ: rm = &irq_rman; break; case SYS_RES_IOPORT: rm = &port_rman; break; - case SYS_RES_DENSE: - case SYS_RES_BWX: case SYS_RES_MEMORY: rm = &mem_rman; break; default: return 0; } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == 0) return 0; switch (type) { case SYS_RES_MEMORY: rman_set_bustag(rv, ALPHA_BUS_SPACE_MEM); rman_set_bushandle(rv, rv->r_start); - rman_set_virtual(rv, (void *) rv->r_start); /* maybe NULL? */ - break; - - case SYS_RES_DENSE: - rman_set_bustag(rv, ALPHA_BUS_SPACE_MEM); - rman_set_bushandle(rv, rv->r_start); - rman_set_virtual(rv, pci_cvt_to_dense(rv->r_start)); - break; - - case SYS_RES_BWX: - rman_set_bustag(rv, ALPHA_BUS_SPACE_MEM); - rman_set_bushandle(rv, rv->r_start); - rman_set_virtual(rv, pci_cvt_to_bwx(rv->r_start)); + if (flags & PCI_RF_DENSE) + rman_set_virtual(rv, pci_cvt_to_dense(rv->r_start)); + else if (flags & PCI_RF_BWX) + rman_set_virtual(rv, pci_cvt_to_bwx(rv->r_start)); + else + rman_set_virtual(rv, (void *) rv->r_start); /* maybe NULL? */ break; case SYS_RES_IOPORT: rman_set_bustag(rv, ALPHA_BUS_SPACE_IO); rman_set_bushandle(rv, rv->r_start); break; } return rv; } int pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_activate_resource(r)); } int pci_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } int pci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_release_resource(r)); } void memcpy_fromio(void *d, u_int32_t s, size_t size) { char *cp = d; while (size--) *cp++ = readb(s++); } void memcpy_toio(u_int32_t d, void *s, size_t size) { char *cp = s; while (size--) writeb(d++, *cp++); } void memcpy_io(u_int32_t d, u_int32_t s, size_t size) { while (size--) writeb(d++, readb(s++)); } void memset_io(u_int32_t d, int val, size_t size) { while (size--) writeb(d++, val); } void memsetw(void *d, int val, size_t size) { u_int16_t *sp = d; while (size--) *sp++ = val; } void memsetw_io(u_int32_t d, int val, size_t size) { while (size--) { writew(d, val); d += sizeof(u_int16_t); } } #include "opt_ddb.h" #ifdef DDB #include DB_COMMAND(in, db_in) { int c; int size; if (!have_addr) return; size = -1; while ((c = *modif++) != '\0') { switch (c) { case 'b': size = 1; break; case 'w': size = 2; break; case 'l': size = 4; break; } } if (size < 0) { db_printf("bad size\n"); return; } if (count <= 0) count = 1; while (--count >= 0) { db_printf("%08lx:\t", addr); switch (size) { case 1: db_printf("%02x\n", inb(addr)); break; case 2: db_printf("%04x\n", inw(addr)); break; case 4: db_printf("%08x\n", inl(addr)); break; } } } #endif diff --git a/sys/amd64/include/resource.h b/sys/amd64/include/resource.h index adcf0ce00f9d..28fcc98ea1be 100644 --- a/sys/amd64/include/resource.h +++ b/sys/amd64/include/resource.h @@ -1,45 +1,44 @@ +/* $FreeBSD$ */ /* * 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. */ #ifndef _MACHINE_RESOURCE_H_ #define _MACHINE_RESOURCE_H_ 1 /* * Definitions of resource types for Intel Architecture machines * with support for legacy ISA devices and drivers. */ #define SYS_RES_IRQ 1 /* interrupt lines */ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ -#define SYS_RES_DENSE SYS_RES_MEMORY -#define SYS_RES_BWX SYS_RES_MEMORY #endif /* !_MACHINE_RESOURCE_H_ */ diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index bfdf9d0452e0..f5da2d81c91c 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,1494 +1,1379 @@ /* * 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$ * */ #include "opt_bus.h" #include "opt_simos.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For the Alpha */ #include #include #include #ifdef APIC_IO #include #endif /* APIC_IO */ +/* map register information */ +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + +struct pci_devinfo { + STAILQ_ENTRY(pci_devinfo) pci_links; + struct resource_list resources; + pcicfgregs cfg; + struct pci_conf conf; +}; + static STAILQ_HEAD(devlist, pci_devinfo) pci_devq; u_int32_t pci_numdevs = 0; static u_int32_t pci_generation = 0; /* return base address of memory or port map */ -static int +static u_int32_t pci_mapbase(unsigned mapreg) { int mask = 0x03; if ((mapreg & 0x01) == 0) mask = 0x0f; return (mapreg & ~mask); } /* return map type of memory or port map */ static int 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]; } /* return log2 of map size decoded for memory or port map */ static int pci_mapsize(unsigned testval) { int ln2size; testval = pci_mapbase(testval); ln2size = 0; if (testval != 0) { while ((testval & 1) == 0) { ln2size++; testval >>= 1; } } return (ln2size); } /* return log2 of address range supported by map register */ static int pci_maprange(unsigned mapreg) { int ln2range = 0; switch (mapreg & 0x07) { case 0x00: case 0x01: case 0x05: ln2range = 32; break; case 0x02: ln2range = 20; break; case 0x04: ln2range = 64; break; } return (ln2range); } -/* extract map parameters into newly allocated array of pcimap structures */ - -static pcimap * -pci_readmaps(pcicfgregs *cfg, int maxmaps) -{ - int i, j = 0; - pcimap *map; - int map64 = 0; - int reg = PCIR_MAPS; - - for (i = 0; i < maxmaps; i++) { - int reg = PCIR_MAPS + i*4; - u_int32_t base; - u_int32_t ln2range; - - base = pci_cfgread(cfg, reg, 4); - ln2range = pci_maprange(base); - - if (base == 0 || ln2range == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - else { - j++; - if (ln2range > 32) { - i++; - j++; - } - } - } - - map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK); - if (map != NULL) { - bzero(map, sizeof(pcimap) * j); - cfg->nummaps = j; - - for (i = 0, j = 0; i < maxmaps; i++, reg += 4) { - u_int32_t base; - u_int32_t testval; - - base = pci_cfgread(cfg, reg, 4); - - if (map64 == 0) { - if (base == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - - pci_cfgwrite(cfg, reg, 0xffffffff, 4); - testval = pci_cfgread(cfg, reg, 4); - pci_cfgwrite(cfg, reg, base, 4); - - map[j].reg = reg; - map[j].base = pci_mapbase(base); - map[j].type = pci_maptype(base); - map[j].ln2size = pci_mapsize(testval); - map[j].ln2range = pci_maprange(testval); - map64 = map[j].ln2range == 64; - } else { - /* only fill in base, other fields are 0 */ - map[j].base = base; - map64 = 0; - } -#ifdef __alpha__ - /* - * XXX: encode hose number in the base addr, - * This will go away once the bus_space functions - * can deal with multiple hoses - */ - - if(cfg->hose){ - if(map[j].base & 0x80000000){ - printf("base addr = 0x%x\n", map[j].base); - printf("hacked addr = 0x%x\n", - map[j].base | (cfg->hose << 31)); - - panic("hose encoding hack would clobber base addr"); - } - if(cfg->hose > 1 ) - panic("only one hose supported!"); - map[j].base |= (cfg->hose << 31); - } -#endif - j++; - } - } - return (map); -} - /* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ static void pci_fixancient(pcicfgregs *cfg) { if (cfg->hdrtype != 0) return; /* PCI to PCI bridges use header type 1 */ if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) cfg->hdrtype = 1; } /* read config data specific to header type 1 device (PCI to PCI bridge) */ static void * pci_readppb(pcicfgregs *cfg) { pcih1cfgregs *p; p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); if (p == NULL) return (NULL); bzero(p, sizeof *p); p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2); p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2); p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1); p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2), pci_cfgread(cfg, PCIR_IOBASEL_1, 1)); p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2), pci_cfgread(cfg, PCIR_IOLIMITL_1, 1)); p->membase = PCI_PPBMEMBASE (0, pci_cfgread(cfg, PCIR_MEMBASE_1, 2)); p->memlimit = PCI_PPBMEMLIMIT (0, pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2)); p->pmembase = PCI_PPBMEMBASE ( (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4), pci_cfgread(cfg, PCIR_PMBASEL_1, 2)); p->pmemlimit = PCI_PPBMEMLIMIT ( (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4), pci_cfgread(cfg, PCIR_PMLIMITL_1, 2)); return (p); } /* read config data specific to header type 2 device (PCI to CardBus bridge) */ static void * pci_readpcb(pcicfgregs *cfg) { pcih2cfgregs *p; p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); if (p == NULL) return (NULL); bzero(p, sizeof *p); p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2); p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2); p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1); p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4); p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4); p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4); p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4); p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4); p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4); p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4); p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4); p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4); return p; } /* extract header type specific config data */ static void pci_hdrtypedata(pcicfgregs *cfg) { switch (cfg->hdrtype) { case 0: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); + cfg->nummaps = PCI_MAXMAPS_0; break; case 1: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); + cfg->nummaps = PCI_MAXMAPS_1; cfg->hdrspec = pci_readppb(cfg); break; case 2: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); + cfg->nummaps = PCI_MAXMAPS_2; cfg->hdrspec = pci_readpcb(cfg); break; } } /* read configuration header into pcicfgrect structure */ static struct pci_devinfo * pci_readcfg(pcicfgregs *probe) { pcicfgregs *cfg = NULL; struct pci_devinfo *devlist_entry; struct devlist *devlist_head; devlist_head = &pci_devq; devlist_entry = NULL; if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) { devlist_entry = malloc(sizeof(struct pci_devinfo), M_DEVBUF, M_WAITOK); if (devlist_entry == NULL) return (NULL); bzero(devlist_entry, sizeof *devlist_entry); cfg = &devlist_entry->cfg; cfg->hose = probe->hose; cfg->bus = probe->bus; cfg->slot = probe->slot; cfg->func = probe->func; cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2); cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2); cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2); cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2); cfg->baseclass = pci_cfgread(cfg, PCIR_CLASS, 1); cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1); cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1); cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1); cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1); cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1); cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1); cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1); cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1); #ifdef __alpha__ alpha_platform_assign_pciintr(cfg); #endif #ifdef APIC_IO 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 = pci_cfgread(cfg, PCIR_MINGNT, 1); cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1); cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; cfg->hdrtype &= ~PCIM_MFDEV; pci_fixancient(cfg); pci_hdrtypedata(cfg); STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links); 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; devlist_entry->conf.pc_hdr = cfg->hdrtype; devlist_entry->conf.pc_subvendor = cfg->subvendor; devlist_entry->conf.pc_subdevice = cfg->subdevice; devlist_entry->conf.pc_vendor = cfg->vendor; devlist_entry->conf.pc_device = cfg->device; devlist_entry->conf.pc_class = cfg->baseclass; devlist_entry->conf.pc_subclass = cfg->subclass; devlist_entry->conf.pc_progif = cfg->progif; devlist_entry->conf.pc_revid = cfg->revid; pci_numdevs++; pci_generation++; } return (devlist_entry); } #if 0 /* free pcicfgregs structure and all depending data structures */ static int pci_freecfg(struct pci_devinfo *dinfo) { struct devlist *devlist_head; devlist_head = &pci_devq; if (dinfo->cfg.hdrspec != NULL) free(dinfo->cfg.hdrspec, M_DEVBUF); if (dinfo->cfg.map != NULL) free(dinfo->cfg.map, M_DEVBUF); /* XXX this hasn't been tested */ STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); free(dinfo, M_DEVBUF); /* increment the generation count */ pci_generation++; /* we're losing one device */ pci_numdevs--; return (0); } #endif /* * This is the user interface to PCI configuration space. */ static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p) { if ((oflags & FWRITE) && securelevel > 0) { return EPERM; } return 0; } static int pci_close(dev_t dev, int flag, int devtype, struct proc *p) { 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(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct pci_io *io; const char *name; int error; if (!(flag & FWRITE)) return EPERM; switch(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 *)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; printf("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); printf("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 ((error = useracc((caddr_t)cio->patterns, cio->pat_buf_len, B_READ)) != 1){ printf("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 = malloc(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; printf("pci_ioctl: invalid GETCONF arguments\n"); error = EINVAL; break; } else pattern_buf = NULL; /* * Make sure we can write to the match buffer. */ if ((error = useracc((caddr_t)cio->matches, cio->match_buf_len, B_WRITE)) != 1) { printf("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) free(pattern_buf, M_TEMP); break; } case PCIOCREAD: io = (struct pci_io *)data; switch(io->pi_width) { pcicfgregs probe; case 4: case 2: case 1: probe.hose = -1; probe.bus = io->pi_sel.pc_bus; probe.slot = io->pi_sel.pc_dev; probe.func = io->pi_sel.pc_func; io->pi_data = pci_cfgread(&probe, io->pi_reg, io->pi_width); error = 0; break; default: error = ENODEV; break; } break; case PCIOCWRITE: io = (struct pci_io *)data; switch(io->pi_width) { pcicfgregs probe; case 4: case 2: case 1: probe.hose = -1; probe.bus = io->pi_sel.pc_bus; probe.slot = io->pi_sel.pc_dev; probe.func = io->pi_sel.pc_func; pci_cfgwrite(&probe, io->pi_reg, io->pi_data, io->pi_width); error = 0; break; default: error = ENODEV; break; } break; default: error = ENOTTY; break; } return (error); } #define PCI_CDEV 78 static struct cdevsw pcicdev = { /* open */ pci_open, /* close */ pci_close, /* read */ noread, /* write */ nowrite, /* ioctl */ pci_ioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "pci", /* maj */ PCI_CDEV, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, /* bmaj */ -1 }; #include "pci_if.h" /* * 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 = device_get_driver(dev)->priv; /* * 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); error = 0; } } 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 = device_get_driver(dev)->priv; unit = device_get_unit(dev); if (unit > *dvp->pd_count) *dvp->pd_count = unit; if (dvp->pd_attach) dvp->pd_attach(cfg, unit); 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 } }; static devclass_t pci_devclass; /* * 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; driver_t *driver; switch (type) { case MOD_LOAD: driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT); if (!driver) return ENOMEM; bzero(driver, sizeof(driver_t)); driver->name = dvp->pd_name; driver->methods = pci_compat_methods; driver->softc = sizeof(struct pci_devinfo *); driver->priv = dvp; devclass_add_driver(pci_devclass, driver); break; case MOD_UNLOAD: printf("%s: module unload not supported!\n", dvp->pd_name); return EOPNOTSUPP; default: break; } 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. */ static void pci_print_verbose(struct pci_devinfo *dinfo) { if (bootverbose) { - int i; pcicfgregs *cfg = &dinfo->cfg; printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", cfg->vendor, cfg->device, cfg->revid); printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", cfg->baseclass, cfg->subclass, cfg->progif, cfg->hdrtype, cfg->mfdev); printf("\tsubordinatebus=%x \tsecondarybus=%x\n", cfg->subordinatebus, cfg->secondarybus); #ifdef PCI_DEBUG printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", cfg->cmdreg, cfg->statreg, cfg->cachelnsz); printf("\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 */ if (cfg->intpin > 0) printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + } +} + +static int +pci_porten(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); +} + +static int +pci_memen(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); +} + +static void +pci_add_resources(device_t dev, pcicfgregs* cfg) +{ + + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct resource_list *rl = &dinfo->resources; + int i; + + for (i = 0; i < cfg->nummaps; i++) { + int reg = PCIR_MAPS + i*4; + u_int32_t map; + u_int64_t base; + u_int8_t ln2size; + u_int8_t ln2range; + u_int32_t testval; + + int type; + + map = pci_cfgread(cfg, reg, 4); + + if (map == 0 || map == 0xffffffff) + continue; /* skip invalid entry */ + + pci_cfgwrite(cfg, reg, 0xffffffff, 4); + testval = pci_cfgread(cfg, reg, 4); + pci_cfgwrite(cfg, reg, map, 4); - for (i = 0; i < cfg->nummaps; i++) { - pcimap *m = &cfg->map[i]; + base = pci_mapbase(map); + if (pci_maptype(map) & PCI_MAPMEM) + type = SYS_RES_MEMORY; + else + type = SYS_RES_IOPORT; + ln2size = pci_mapsize(testval); + ln2range = pci_maprange(testval); + if (ln2range == 64) { + /* Read the other half of a 64bit map register */ + base |= (u_int64_t) pci_cfgread(cfg, reg + 4, 4) << 32; + i++; + } + +#ifdef __alpha__ + /* + * XXX: encode hose number in the base addr, + * This will go away once the bus_space functions + * can deal with multiple hoses + */ + + if(cfg->hose){ + if (base & 0x80000000) { + printf("base addr = 0x%x\n", base); + printf("hacked addr = 0x%x\n", + base | (cfg->hose << 31)); + + panic("hose encoding hack would clobber base addr"); + } + if (cfg->hose > 1) + panic("only one hose supported!"); + base |= (cfg->hose << 31); + } +#endif + if (type == SYS_RES_IOPORT && !pci_porten(cfg)) + continue; + if (type == SYS_RES_IOPORT && !pci_memen(cfg)) + continue; + + resource_list_add(rl, type, reg, + base, base + (1 << ln2size) - 1, + (1 << ln2size)); + + if (bootverbose) { printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n", - i, m->type, m->ln2range, m->base, m->ln2size); + i, pci_maptype(base), ln2range, + (unsigned int) base, ln2size); } } + if (cfg->intline) + resource_list_add(rl, SYS_RES_IRQ, 0, + cfg->intline, cfg->intline, 1); } -static int +static void pci_add_children(device_t dev, int busno) { pcicfgregs probe; - int bushigh = busno; #ifdef SIMOS #undef PCI_SLOTMAX #define PCI_SLOTMAX 0 #endif bzero(&probe, sizeof probe); #ifdef __alpha__ probe.hose = pcib_get_hose(dev); #endif #ifdef __i386__ probe.hose = 0; #endif probe.bus = busno; for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { int pcifunchigh = 0; for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) { struct pci_devinfo *dinfo = pci_readcfg(&probe); if (dinfo != NULL) { if (dinfo->cfg.mfdev) pcifunchigh = 7; pci_print_verbose(dinfo); dinfo->cfg.dev = device_add_child(dev, NULL, -1, dinfo); - - if (bushigh < dinfo->cfg.subordinatebus) - bushigh = dinfo->cfg.subordinatebus; - if (bushigh < dinfo->cfg.secondarybus) - bushigh = dinfo->cfg.secondarybus; + pci_add_resources(dinfo->cfg.dev, &dinfo->cfg); } } } - - return bushigh; } static int pci_new_probe(device_t dev) { static int once; device_set_desc(dev, "PCI bus"); pci_add_children(dev, device_get_unit(dev)); if (!once) { make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644, "pci"); once++; } return 0; } static int pci_print_child(device_t dev, device_t child) { struct pci_devinfo *dinfo; pcicfgregs *cfg; int retval = 0; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; retval += bus_print_child_header(dev, child); if (cfg->intpin > 0 && cfg->intline != 255) retval += printf(" irq %d", cfg->intline); retval += printf(" at device %d.%d", pci_get_slot(child), pci_get_function(child)); retval += bus_print_child_footer(dev, child); return (retval); } static void pci_probe_nomatch(device_t dev, device_t child) { struct pci_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; device_printf(dev, "unknown card (vendor=0x%04x, dev=0x%04x) at %d.%d", cfg->vendor, cfg->device, pci_get_slot(child), pci_get_function(child)); if (cfg->intpin > 0 && cfg->intline != 255) { printf(" irq %d", cfg->intline); } printf("\n"); return; } static int pci_read_ivar(device_t dev, device_t child, int which, u_long *result) { struct pci_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; switch (which) { case PCI_IVAR_SUBVENDOR: *result = cfg->subvendor; break; case PCI_IVAR_SUBDEVICE: *result = cfg->subdevice; break; case PCI_IVAR_VENDOR: *result = cfg->vendor; break; case PCI_IVAR_DEVICE: *result = cfg->device; break; case PCI_IVAR_DEVID: *result = (cfg->device << 16) | cfg->vendor; break; case PCI_IVAR_CLASS: *result = cfg->baseclass; break; case PCI_IVAR_SUBCLASS: *result = cfg->subclass; break; case PCI_IVAR_PROGIF: *result = cfg->progif; break; case PCI_IVAR_REVID: *result = cfg->revid; break; case PCI_IVAR_INTPIN: *result = cfg->intpin; break; case PCI_IVAR_IRQ: *result = cfg->intline; break; case PCI_IVAR_BUS: *result = cfg->bus; break; case PCI_IVAR_SLOT: *result = cfg->slot; break; case PCI_IVAR_FUNCTION: *result = cfg->func; break; case PCI_IVAR_SECONDARYBUS: *result = cfg->secondarybus; break; case PCI_IVAR_SUBORDINATEBUS: *result = cfg->subordinatebus; break; case PCI_IVAR_HOSE: /* * Pass up to parent bridge. */ *result = pcib_get_hose(dev); break; default: return ENOENT; } return 0; } static 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_SUBVENDOR: case PCI_IVAR_SUBDEVICE: case PCI_IVAR_VENDOR: case PCI_IVAR_DEVICE: case PCI_IVAR_DEVID: case PCI_IVAR_CLASS: case PCI_IVAR_SUBCLASS: case PCI_IVAR_PROGIF: case PCI_IVAR_REVID: case PCI_IVAR_INTPIN: case PCI_IVAR_IRQ: case PCI_IVAR_BUS: case PCI_IVAR_SLOT: case PCI_IVAR_FUNCTION: 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 0; } -static int -pci_mapno(pcicfgregs *cfg, int reg) +static 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) { - int i, nummaps; - pcimap *map; - - nummaps = cfg->nummaps; - map = cfg->map; + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; - for (i = 0; i < nummaps; i++) - if (map[i].reg == reg) - return (i); - return (-1); + return resource_list_alloc(rl, dev, child, type, rid, + start, end, count, flags); } static int -pci_porten(pcicfgregs *cfg) +pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) { - return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); -} - -static int -pci_isportmap(pcicfgregs *cfg, int map) + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; -{ - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPPORT) != 0); + return resource_list_release(rl, dev, child, type, rid, r); } static int -pci_memen(pcicfgregs *cfg) +pci_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) { - return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); + printf("pci_set_resource: PCI resources can not be changed\n"); + return EINVAL; } static int -pci_ismemmap(pcicfgregs *cfg, int map) +pci_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPMEM) != 0); -} - -static 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) -{ - int isdefault; struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - struct resource *rv, **rvp = 0; - int map; - - isdefault = (device_get_parent(child) == dev - && start == 0UL && end == ~0UL); - - switch (type) { - case SYS_RES_IRQ: - if (*rid != 0) - return 0; - if (isdefault && cfg->intline != 255) { - start = cfg->intline; - end = cfg->intline; - count = 1; - } - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_memen(cfg) && pci_ismemmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - case SYS_RES_IOPORT: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_porten(cfg) && pci_isportmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - default: - return 0; - } + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; - rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, - type, rid, start, end, count, flags); - if (rvp) - *rvp = rv; + rle = resource_list_find(rl, type, rid); + if (!rle) + return ENOENT; + + *startp = rle->start; + *countp = rle->count; - return rv; + return 0; } -static int -pci_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) +static void +pci_delete_resource(device_t dev, device_t child, int type, int rid) { - int rv; - struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - int map = 0; - int passthrough = (device_get_parent(child) != dev); - - switch (type) { - case SYS_RES_IRQ: - if (rid != 0) - return EINVAL; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - /* - * Only check the map registers if this is a direct - * descendant. - */ - map = passthrough ? -1 : pci_mapno(cfg, rid); - break; - - default: - return (ENOENT); - } - - rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); - - if (rv == 0) { - switch (type) { - case SYS_RES_IRQ: - if (!passthrough) - cfg->irqres = 0; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - if (map != -1) - cfg->map[map].res = 0; - break; - - default: - return ENOENT; - } - } - - return rv; + printf("pci_set_resource: PCI resources can not be deleted\n"); + return EINVAL; } static u_int32_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 pci_cfgread(cfg, reg, width); } static void pci_write_config_method(device_t dev, device_t child, int reg, u_int32_t val, int width) { struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; pci_cfgwrite(cfg, reg, val, width); } static int pci_modevent(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: STAILQ_INIT(&pci_devq); break; case MOD_UNLOAD: break; } return 0; } static device_method_t pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pci_new_probe), DEVMETHOD(device_attach, bus_generic_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, 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, bus_generic_driver_added), 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_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_set_resource, pci_set_resource), + DEVMETHOD(bus_get_resource, pci_get_resource), + DEVMETHOD(bus_delete_resource, pci_delete_resource), /* PCI interface */ DEVMETHOD(pci_read_config, pci_read_config_method), DEVMETHOD(pci_write_config, pci_write_config_method), { 0, 0 } }; static driver_t pci_driver = { "pci", pci_methods, 1, /* no softc */ }; DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index ae4958dbf265..31cea00aa440 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,346 +1,330 @@ /* * 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$ * */ #ifndef _PCIVAR_H_ #define _PCIVAR_H_ #ifndef PCI_COMPAT #define PCI_COMPAT #endif #include /* XXX KDM */ #include /* 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_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 */ #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 -/* map register information */ - -typedef struct { - u_int32_t base; - u_int8_t type; -#define PCI_MAPMEM 0x01 /* memory map */ -#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ -#define PCI_MAPPORT 0x04 /* port map */ - u_int8_t ln2size; - u_int8_t ln2range; - u_int8_t reg; /* offset of map register in config space */ -/* u_int8_t dummy;*/ - struct resource *res; /* handle from resource manager */ -} pcimap; - /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ - pcimap *map; /* pointer to array of PCI maps */ void *hdrspec; /* pointer to header type specific data */ - struct resource *irqres; /* resource descriptor for interrupt mapping */ 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 */ u_int16_t cmdreg; /* disable/enable chip and PCI options */ u_int16_t statreg; /* supported PCI features and error state */ 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 */ 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) */ 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 */ u_int8_t mfdev; /* multi-function device (from hdrtype reg) */ u_int8_t nummaps; /* actual number of PCI maps used */ u_int8_t hose; /* hose which bus is attached to */ u_int8_t bus; /* config space bus address */ u_int8_t slot; /* config space slot address */ u_int8_t func; /* config space function number */ u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ } 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) 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 */ } 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 */ } pcih2cfgregs; /* PCI bus attach definitions (there could be multiple PCI bus *trees* ... */ typedef struct pciattach { int unit; int pcibushigh; struct pciattach *next; } pciattach; -struct pci_devinfo { - STAILQ_ENTRY(pci_devinfo) pci_links; - pcicfgregs cfg; - struct pci_conf conf; -}; - extern u_int32_t pci_numdevs; /* externally visible functions */ const char *ide_pci_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); #ifdef __alpha__ vm_offset_t pci_cvt_to_dense (vm_offset_t); vm_offset_t pci_cvt_to_bwx (vm_offset_t); #endif /* __alpha__ */ /* 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" +/* + * 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 + 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_HOSE, }; /* * Simplified accessors for pci devices */ #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) \ { \ u_long v = (u_long) 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) PCI_ACCESSOR(hose, HOSE, u_int32_t) static __inline u_int32_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_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_HOSE, }; #define PCIB_ACCESSOR(A, B, T) \ \ static __inline T pcib_get_ ## A(device_t dev) \ { \ uintptr_t v; \ BUS_READ_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, &v); \ return (T) v; \ } \ \ static __inline void pcib_set_ ## A(device_t dev, T t) \ { \ u_long v = (u_long) t; \ BUS_WRITE_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, v); \ } PCIB_ACCESSOR(hose, HOSE, u_int32_t) #endif /* for compatibility to FreeBSD-2.2 version of PCI code */ #ifdef PCI_COMPAT typedef pcicfgregs *pcici_t; typedef unsigned pcidi_t; typedef void pci_inthand_t(void *arg); #define pci_max_burst_len (3) /* just copied from old PCI code for now ... */ extern int pci_mechanism; 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); }; #ifdef __i386__ typedef u_short pci_port_t; #else typedef u_int pci_port_t; #endif 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_dense (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); int pci_map_bwx (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, intrmask_t *maskptr); int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr, 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 /* PCI_COMPAT */ #endif /* _PCIVAR_H_ */ diff --git a/sys/i386/include/resource.h b/sys/i386/include/resource.h index adcf0ce00f9d..28fcc98ea1be 100644 --- a/sys/i386/include/resource.h +++ b/sys/i386/include/resource.h @@ -1,45 +1,44 @@ +/* $FreeBSD$ */ /* * 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. */ #ifndef _MACHINE_RESOURCE_H_ #define _MACHINE_RESOURCE_H_ 1 /* * Definitions of resource types for Intel Architecture machines * with support for legacy ISA devices and drivers. */ #define SYS_RES_IRQ 1 /* interrupt lines */ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ -#define SYS_RES_DENSE SYS_RES_MEMORY -#define SYS_RES_BWX SYS_RES_MEMORY #endif /* !_MACHINE_RESOURCE_H_ */ diff --git a/sys/pci/pci.c b/sys/pci/pci.c index bfdf9d0452e0..f5da2d81c91c 100644 --- a/sys/pci/pci.c +++ b/sys/pci/pci.c @@ -1,1494 +1,1379 @@ /* * 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$ * */ #include "opt_bus.h" #include "opt_simos.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For the Alpha */ #include #include #include #ifdef APIC_IO #include #endif /* APIC_IO */ +/* map register information */ +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + +struct pci_devinfo { + STAILQ_ENTRY(pci_devinfo) pci_links; + struct resource_list resources; + pcicfgregs cfg; + struct pci_conf conf; +}; + static STAILQ_HEAD(devlist, pci_devinfo) pci_devq; u_int32_t pci_numdevs = 0; static u_int32_t pci_generation = 0; /* return base address of memory or port map */ -static int +static u_int32_t pci_mapbase(unsigned mapreg) { int mask = 0x03; if ((mapreg & 0x01) == 0) mask = 0x0f; return (mapreg & ~mask); } /* return map type of memory or port map */ static int 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]; } /* return log2 of map size decoded for memory or port map */ static int pci_mapsize(unsigned testval) { int ln2size; testval = pci_mapbase(testval); ln2size = 0; if (testval != 0) { while ((testval & 1) == 0) { ln2size++; testval >>= 1; } } return (ln2size); } /* return log2 of address range supported by map register */ static int pci_maprange(unsigned mapreg) { int ln2range = 0; switch (mapreg & 0x07) { case 0x00: case 0x01: case 0x05: ln2range = 32; break; case 0x02: ln2range = 20; break; case 0x04: ln2range = 64; break; } return (ln2range); } -/* extract map parameters into newly allocated array of pcimap structures */ - -static pcimap * -pci_readmaps(pcicfgregs *cfg, int maxmaps) -{ - int i, j = 0; - pcimap *map; - int map64 = 0; - int reg = PCIR_MAPS; - - for (i = 0; i < maxmaps; i++) { - int reg = PCIR_MAPS + i*4; - u_int32_t base; - u_int32_t ln2range; - - base = pci_cfgread(cfg, reg, 4); - ln2range = pci_maprange(base); - - if (base == 0 || ln2range == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - else { - j++; - if (ln2range > 32) { - i++; - j++; - } - } - } - - map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK); - if (map != NULL) { - bzero(map, sizeof(pcimap) * j); - cfg->nummaps = j; - - for (i = 0, j = 0; i < maxmaps; i++, reg += 4) { - u_int32_t base; - u_int32_t testval; - - base = pci_cfgread(cfg, reg, 4); - - if (map64 == 0) { - if (base == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - - pci_cfgwrite(cfg, reg, 0xffffffff, 4); - testval = pci_cfgread(cfg, reg, 4); - pci_cfgwrite(cfg, reg, base, 4); - - map[j].reg = reg; - map[j].base = pci_mapbase(base); - map[j].type = pci_maptype(base); - map[j].ln2size = pci_mapsize(testval); - map[j].ln2range = pci_maprange(testval); - map64 = map[j].ln2range == 64; - } else { - /* only fill in base, other fields are 0 */ - map[j].base = base; - map64 = 0; - } -#ifdef __alpha__ - /* - * XXX: encode hose number in the base addr, - * This will go away once the bus_space functions - * can deal with multiple hoses - */ - - if(cfg->hose){ - if(map[j].base & 0x80000000){ - printf("base addr = 0x%x\n", map[j].base); - printf("hacked addr = 0x%x\n", - map[j].base | (cfg->hose << 31)); - - panic("hose encoding hack would clobber base addr"); - } - if(cfg->hose > 1 ) - panic("only one hose supported!"); - map[j].base |= (cfg->hose << 31); - } -#endif - j++; - } - } - return (map); -} - /* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ static void pci_fixancient(pcicfgregs *cfg) { if (cfg->hdrtype != 0) return; /* PCI to PCI bridges use header type 1 */ if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) cfg->hdrtype = 1; } /* read config data specific to header type 1 device (PCI to PCI bridge) */ static void * pci_readppb(pcicfgregs *cfg) { pcih1cfgregs *p; p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); if (p == NULL) return (NULL); bzero(p, sizeof *p); p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2); p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2); p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1); p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2), pci_cfgread(cfg, PCIR_IOBASEL_1, 1)); p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2), pci_cfgread(cfg, PCIR_IOLIMITL_1, 1)); p->membase = PCI_PPBMEMBASE (0, pci_cfgread(cfg, PCIR_MEMBASE_1, 2)); p->memlimit = PCI_PPBMEMLIMIT (0, pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2)); p->pmembase = PCI_PPBMEMBASE ( (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4), pci_cfgread(cfg, PCIR_PMBASEL_1, 2)); p->pmemlimit = PCI_PPBMEMLIMIT ( (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4), pci_cfgread(cfg, PCIR_PMLIMITL_1, 2)); return (p); } /* read config data specific to header type 2 device (PCI to CardBus bridge) */ static void * pci_readpcb(pcicfgregs *cfg) { pcih2cfgregs *p; p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); if (p == NULL) return (NULL); bzero(p, sizeof *p); p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2); p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2); p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1); p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4); p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4); p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4); p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4); p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4); p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4); p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4); p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4); p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4); return p; } /* extract header type specific config data */ static void pci_hdrtypedata(pcicfgregs *cfg) { switch (cfg->hdrtype) { case 0: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); + cfg->nummaps = PCI_MAXMAPS_0; break; case 1: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); + cfg->nummaps = PCI_MAXMAPS_1; cfg->hdrspec = pci_readppb(cfg); break; case 2: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); + cfg->nummaps = PCI_MAXMAPS_2; cfg->hdrspec = pci_readpcb(cfg); break; } } /* read configuration header into pcicfgrect structure */ static struct pci_devinfo * pci_readcfg(pcicfgregs *probe) { pcicfgregs *cfg = NULL; struct pci_devinfo *devlist_entry; struct devlist *devlist_head; devlist_head = &pci_devq; devlist_entry = NULL; if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) { devlist_entry = malloc(sizeof(struct pci_devinfo), M_DEVBUF, M_WAITOK); if (devlist_entry == NULL) return (NULL); bzero(devlist_entry, sizeof *devlist_entry); cfg = &devlist_entry->cfg; cfg->hose = probe->hose; cfg->bus = probe->bus; cfg->slot = probe->slot; cfg->func = probe->func; cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2); cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2); cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2); cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2); cfg->baseclass = pci_cfgread(cfg, PCIR_CLASS, 1); cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1); cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1); cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1); cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1); cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1); cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1); cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1); cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1); #ifdef __alpha__ alpha_platform_assign_pciintr(cfg); #endif #ifdef APIC_IO 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 = pci_cfgread(cfg, PCIR_MINGNT, 1); cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1); cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; cfg->hdrtype &= ~PCIM_MFDEV; pci_fixancient(cfg); pci_hdrtypedata(cfg); STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links); 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; devlist_entry->conf.pc_hdr = cfg->hdrtype; devlist_entry->conf.pc_subvendor = cfg->subvendor; devlist_entry->conf.pc_subdevice = cfg->subdevice; devlist_entry->conf.pc_vendor = cfg->vendor; devlist_entry->conf.pc_device = cfg->device; devlist_entry->conf.pc_class = cfg->baseclass; devlist_entry->conf.pc_subclass = cfg->subclass; devlist_entry->conf.pc_progif = cfg->progif; devlist_entry->conf.pc_revid = cfg->revid; pci_numdevs++; pci_generation++; } return (devlist_entry); } #if 0 /* free pcicfgregs structure and all depending data structures */ static int pci_freecfg(struct pci_devinfo *dinfo) { struct devlist *devlist_head; devlist_head = &pci_devq; if (dinfo->cfg.hdrspec != NULL) free(dinfo->cfg.hdrspec, M_DEVBUF); if (dinfo->cfg.map != NULL) free(dinfo->cfg.map, M_DEVBUF); /* XXX this hasn't been tested */ STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); free(dinfo, M_DEVBUF); /* increment the generation count */ pci_generation++; /* we're losing one device */ pci_numdevs--; return (0); } #endif /* * This is the user interface to PCI configuration space. */ static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p) { if ((oflags & FWRITE) && securelevel > 0) { return EPERM; } return 0; } static int pci_close(dev_t dev, int flag, int devtype, struct proc *p) { 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(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct pci_io *io; const char *name; int error; if (!(flag & FWRITE)) return EPERM; switch(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 *)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; printf("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); printf("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 ((error = useracc((caddr_t)cio->patterns, cio->pat_buf_len, B_READ)) != 1){ printf("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 = malloc(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; printf("pci_ioctl: invalid GETCONF arguments\n"); error = EINVAL; break; } else pattern_buf = NULL; /* * Make sure we can write to the match buffer. */ if ((error = useracc((caddr_t)cio->matches, cio->match_buf_len, B_WRITE)) != 1) { printf("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) free(pattern_buf, M_TEMP); break; } case PCIOCREAD: io = (struct pci_io *)data; switch(io->pi_width) { pcicfgregs probe; case 4: case 2: case 1: probe.hose = -1; probe.bus = io->pi_sel.pc_bus; probe.slot = io->pi_sel.pc_dev; probe.func = io->pi_sel.pc_func; io->pi_data = pci_cfgread(&probe, io->pi_reg, io->pi_width); error = 0; break; default: error = ENODEV; break; } break; case PCIOCWRITE: io = (struct pci_io *)data; switch(io->pi_width) { pcicfgregs probe; case 4: case 2: case 1: probe.hose = -1; probe.bus = io->pi_sel.pc_bus; probe.slot = io->pi_sel.pc_dev; probe.func = io->pi_sel.pc_func; pci_cfgwrite(&probe, io->pi_reg, io->pi_data, io->pi_width); error = 0; break; default: error = ENODEV; break; } break; default: error = ENOTTY; break; } return (error); } #define PCI_CDEV 78 static struct cdevsw pcicdev = { /* open */ pci_open, /* close */ pci_close, /* read */ noread, /* write */ nowrite, /* ioctl */ pci_ioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "pci", /* maj */ PCI_CDEV, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, /* bmaj */ -1 }; #include "pci_if.h" /* * 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 = device_get_driver(dev)->priv; /* * 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); error = 0; } } 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 = device_get_driver(dev)->priv; unit = device_get_unit(dev); if (unit > *dvp->pd_count) *dvp->pd_count = unit; if (dvp->pd_attach) dvp->pd_attach(cfg, unit); 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 } }; static devclass_t pci_devclass; /* * 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; driver_t *driver; switch (type) { case MOD_LOAD: driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT); if (!driver) return ENOMEM; bzero(driver, sizeof(driver_t)); driver->name = dvp->pd_name; driver->methods = pci_compat_methods; driver->softc = sizeof(struct pci_devinfo *); driver->priv = dvp; devclass_add_driver(pci_devclass, driver); break; case MOD_UNLOAD: printf("%s: module unload not supported!\n", dvp->pd_name); return EOPNOTSUPP; default: break; } 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. */ static void pci_print_verbose(struct pci_devinfo *dinfo) { if (bootverbose) { - int i; pcicfgregs *cfg = &dinfo->cfg; printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", cfg->vendor, cfg->device, cfg->revid); printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", cfg->baseclass, cfg->subclass, cfg->progif, cfg->hdrtype, cfg->mfdev); printf("\tsubordinatebus=%x \tsecondarybus=%x\n", cfg->subordinatebus, cfg->secondarybus); #ifdef PCI_DEBUG printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", cfg->cmdreg, cfg->statreg, cfg->cachelnsz); printf("\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 */ if (cfg->intpin > 0) printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + } +} + +static int +pci_porten(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); +} + +static int +pci_memen(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); +} + +static void +pci_add_resources(device_t dev, pcicfgregs* cfg) +{ + + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct resource_list *rl = &dinfo->resources; + int i; + + for (i = 0; i < cfg->nummaps; i++) { + int reg = PCIR_MAPS + i*4; + u_int32_t map; + u_int64_t base; + u_int8_t ln2size; + u_int8_t ln2range; + u_int32_t testval; + + int type; + + map = pci_cfgread(cfg, reg, 4); + + if (map == 0 || map == 0xffffffff) + continue; /* skip invalid entry */ + + pci_cfgwrite(cfg, reg, 0xffffffff, 4); + testval = pci_cfgread(cfg, reg, 4); + pci_cfgwrite(cfg, reg, map, 4); - for (i = 0; i < cfg->nummaps; i++) { - pcimap *m = &cfg->map[i]; + base = pci_mapbase(map); + if (pci_maptype(map) & PCI_MAPMEM) + type = SYS_RES_MEMORY; + else + type = SYS_RES_IOPORT; + ln2size = pci_mapsize(testval); + ln2range = pci_maprange(testval); + if (ln2range == 64) { + /* Read the other half of a 64bit map register */ + base |= (u_int64_t) pci_cfgread(cfg, reg + 4, 4) << 32; + i++; + } + +#ifdef __alpha__ + /* + * XXX: encode hose number in the base addr, + * This will go away once the bus_space functions + * can deal with multiple hoses + */ + + if(cfg->hose){ + if (base & 0x80000000) { + printf("base addr = 0x%x\n", base); + printf("hacked addr = 0x%x\n", + base | (cfg->hose << 31)); + + panic("hose encoding hack would clobber base addr"); + } + if (cfg->hose > 1) + panic("only one hose supported!"); + base |= (cfg->hose << 31); + } +#endif + if (type == SYS_RES_IOPORT && !pci_porten(cfg)) + continue; + if (type == SYS_RES_IOPORT && !pci_memen(cfg)) + continue; + + resource_list_add(rl, type, reg, + base, base + (1 << ln2size) - 1, + (1 << ln2size)); + + if (bootverbose) { printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n", - i, m->type, m->ln2range, m->base, m->ln2size); + i, pci_maptype(base), ln2range, + (unsigned int) base, ln2size); } } + if (cfg->intline) + resource_list_add(rl, SYS_RES_IRQ, 0, + cfg->intline, cfg->intline, 1); } -static int +static void pci_add_children(device_t dev, int busno) { pcicfgregs probe; - int bushigh = busno; #ifdef SIMOS #undef PCI_SLOTMAX #define PCI_SLOTMAX 0 #endif bzero(&probe, sizeof probe); #ifdef __alpha__ probe.hose = pcib_get_hose(dev); #endif #ifdef __i386__ probe.hose = 0; #endif probe.bus = busno; for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { int pcifunchigh = 0; for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) { struct pci_devinfo *dinfo = pci_readcfg(&probe); if (dinfo != NULL) { if (dinfo->cfg.mfdev) pcifunchigh = 7; pci_print_verbose(dinfo); dinfo->cfg.dev = device_add_child(dev, NULL, -1, dinfo); - - if (bushigh < dinfo->cfg.subordinatebus) - bushigh = dinfo->cfg.subordinatebus; - if (bushigh < dinfo->cfg.secondarybus) - bushigh = dinfo->cfg.secondarybus; + pci_add_resources(dinfo->cfg.dev, &dinfo->cfg); } } } - - return bushigh; } static int pci_new_probe(device_t dev) { static int once; device_set_desc(dev, "PCI bus"); pci_add_children(dev, device_get_unit(dev)); if (!once) { make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644, "pci"); once++; } return 0; } static int pci_print_child(device_t dev, device_t child) { struct pci_devinfo *dinfo; pcicfgregs *cfg; int retval = 0; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; retval += bus_print_child_header(dev, child); if (cfg->intpin > 0 && cfg->intline != 255) retval += printf(" irq %d", cfg->intline); retval += printf(" at device %d.%d", pci_get_slot(child), pci_get_function(child)); retval += bus_print_child_footer(dev, child); return (retval); } static void pci_probe_nomatch(device_t dev, device_t child) { struct pci_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; device_printf(dev, "unknown card (vendor=0x%04x, dev=0x%04x) at %d.%d", cfg->vendor, cfg->device, pci_get_slot(child), pci_get_function(child)); if (cfg->intpin > 0 && cfg->intline != 255) { printf(" irq %d", cfg->intline); } printf("\n"); return; } static int pci_read_ivar(device_t dev, device_t child, int which, u_long *result) { struct pci_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; switch (which) { case PCI_IVAR_SUBVENDOR: *result = cfg->subvendor; break; case PCI_IVAR_SUBDEVICE: *result = cfg->subdevice; break; case PCI_IVAR_VENDOR: *result = cfg->vendor; break; case PCI_IVAR_DEVICE: *result = cfg->device; break; case PCI_IVAR_DEVID: *result = (cfg->device << 16) | cfg->vendor; break; case PCI_IVAR_CLASS: *result = cfg->baseclass; break; case PCI_IVAR_SUBCLASS: *result = cfg->subclass; break; case PCI_IVAR_PROGIF: *result = cfg->progif; break; case PCI_IVAR_REVID: *result = cfg->revid; break; case PCI_IVAR_INTPIN: *result = cfg->intpin; break; case PCI_IVAR_IRQ: *result = cfg->intline; break; case PCI_IVAR_BUS: *result = cfg->bus; break; case PCI_IVAR_SLOT: *result = cfg->slot; break; case PCI_IVAR_FUNCTION: *result = cfg->func; break; case PCI_IVAR_SECONDARYBUS: *result = cfg->secondarybus; break; case PCI_IVAR_SUBORDINATEBUS: *result = cfg->subordinatebus; break; case PCI_IVAR_HOSE: /* * Pass up to parent bridge. */ *result = pcib_get_hose(dev); break; default: return ENOENT; } return 0; } static 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_SUBVENDOR: case PCI_IVAR_SUBDEVICE: case PCI_IVAR_VENDOR: case PCI_IVAR_DEVICE: case PCI_IVAR_DEVID: case PCI_IVAR_CLASS: case PCI_IVAR_SUBCLASS: case PCI_IVAR_PROGIF: case PCI_IVAR_REVID: case PCI_IVAR_INTPIN: case PCI_IVAR_IRQ: case PCI_IVAR_BUS: case PCI_IVAR_SLOT: case PCI_IVAR_FUNCTION: 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 0; } -static int -pci_mapno(pcicfgregs *cfg, int reg) +static 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) { - int i, nummaps; - pcimap *map; - - nummaps = cfg->nummaps; - map = cfg->map; + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; - for (i = 0; i < nummaps; i++) - if (map[i].reg == reg) - return (i); - return (-1); + return resource_list_alloc(rl, dev, child, type, rid, + start, end, count, flags); } static int -pci_porten(pcicfgregs *cfg) +pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) { - return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); -} - -static int -pci_isportmap(pcicfgregs *cfg, int map) + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; -{ - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPPORT) != 0); + return resource_list_release(rl, dev, child, type, rid, r); } static int -pci_memen(pcicfgregs *cfg) +pci_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) { - return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); + printf("pci_set_resource: PCI resources can not be changed\n"); + return EINVAL; } static int -pci_ismemmap(pcicfgregs *cfg, int map) +pci_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPMEM) != 0); -} - -static 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) -{ - int isdefault; struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - struct resource *rv, **rvp = 0; - int map; - - isdefault = (device_get_parent(child) == dev - && start == 0UL && end == ~0UL); - - switch (type) { - case SYS_RES_IRQ: - if (*rid != 0) - return 0; - if (isdefault && cfg->intline != 255) { - start = cfg->intline; - end = cfg->intline; - count = 1; - } - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_memen(cfg) && pci_ismemmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - case SYS_RES_IOPORT: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_porten(cfg) && pci_isportmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - default: - return 0; - } + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; - rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, - type, rid, start, end, count, flags); - if (rvp) - *rvp = rv; + rle = resource_list_find(rl, type, rid); + if (!rle) + return ENOENT; + + *startp = rle->start; + *countp = rle->count; - return rv; + return 0; } -static int -pci_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) +static void +pci_delete_resource(device_t dev, device_t child, int type, int rid) { - int rv; - struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - int map = 0; - int passthrough = (device_get_parent(child) != dev); - - switch (type) { - case SYS_RES_IRQ: - if (rid != 0) - return EINVAL; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - /* - * Only check the map registers if this is a direct - * descendant. - */ - map = passthrough ? -1 : pci_mapno(cfg, rid); - break; - - default: - return (ENOENT); - } - - rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); - - if (rv == 0) { - switch (type) { - case SYS_RES_IRQ: - if (!passthrough) - cfg->irqres = 0; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - if (map != -1) - cfg->map[map].res = 0; - break; - - default: - return ENOENT; - } - } - - return rv; + printf("pci_set_resource: PCI resources can not be deleted\n"); + return EINVAL; } static u_int32_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 pci_cfgread(cfg, reg, width); } static void pci_write_config_method(device_t dev, device_t child, int reg, u_int32_t val, int width) { struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; pci_cfgwrite(cfg, reg, val, width); } static int pci_modevent(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: STAILQ_INIT(&pci_devq); break; case MOD_UNLOAD: break; } return 0; } static device_method_t pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pci_new_probe), DEVMETHOD(device_attach, bus_generic_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, 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, bus_generic_driver_added), 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_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_set_resource, pci_set_resource), + DEVMETHOD(bus_get_resource, pci_get_resource), + DEVMETHOD(bus_delete_resource, pci_delete_resource), /* PCI interface */ DEVMETHOD(pci_read_config, pci_read_config_method), DEVMETHOD(pci_write_config, pci_write_config_method), { 0, 0 } }; static driver_t pci_driver = { "pci", pci_methods, 1, /* no softc */ }; DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); diff --git a/sys/pci/pci_compat.c b/sys/pci/pci_compat.c index c007dc577063..d8c4139b05aa 100644 --- a/sys/pci/pci_compat.c +++ b/sys/pci/pci_compat.c @@ -1,273 +1,273 @@ /* * 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$ * */ #include "opt_bus.h" /* for compatibility to FreeBSD-2.2 version of PCI code */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef APIC_IO #include #endif #ifdef __i386__ #include #endif #ifdef PCI_COMPAT /* ------------------------------------------------------------------------- */ 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_dense(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_DENSE, &rid, - 0, ~0, 1, RF_ACTIVE); + res = bus_alloc_resource(cfg->dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE|PCI_RF_DENSE); if (res) { *pa = rman_get_start(res); *va = (vm_offset_t) rman_get_virtual(res); return (1); } return (0); } int pci_map_bwx(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_BWX, &rid, - 0, ~0, 1, RF_ACTIVE); + res = bus_alloc_resource(cfg->dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE|PCI_RF_BWX); 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, intrmask_t *maskptr) { return (pci_map_int_right(cfg, handler, arg, maskptr, 0)); } int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr, 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; #ifdef INTR_FAST if (intflags & INTR_FAST) flags |= INTR_FAST; if (intflags & INTR_EXCL) resflags &= ~RF_SHAREABLE; #endif res = bus_alloc_resource(cfg->dev, SYS_RES_IRQ, &rid, irq, irq, 1, resflags); if (!res) { printf("pci_map_int: can't allocate interrupt\n"); return 0; } /* * This is ugly. Translate the mask into an interrupt type. */ if (maskptr == &tty_imask) flags |= INTR_TYPE_TTY; else if (maskptr == &bio_imask) flags |= INTR_TYPE_BIO; else if (maskptr == &net_imask) flags |= INTR_TYPE_NET; else if (maskptr == &cam_imask) flags |= INTR_TYPE_CAM; error = BUS_SETUP_INTR(device_get_parent(cfg->dev), cfg->dev, res, flags, handler, arg, &ih); 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) { printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); return 0; } printf("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) { printf("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); if (error != 0) { printf("pci_map_int: BUS_SETUP_INTR failed\n"); return 0; } printf("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; } #endif /* PCI_COMPAT */ diff --git a/sys/pci/pcisupport.c b/sys/pci/pcisupport.c index 33ea09c41a53..c49daf864ffb 100644 --- a/sys/pci/pcisupport.c +++ b/sys/pci/pcisupport.c @@ -1,1612 +1,1609 @@ /************************************************************************** ** ** $FreeBSD$ ** ** 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 "opt_smp.h" #include #include #include #include #include #include #include #include #include #include /*--------------------------------------------------------- ** ** Intel chipsets for 486 / Pentium processor ** **--------------------------------------------------------- */ static void chipset_attach(device_t dev, int unit); struct condmsg { unsigned char port; unsigned char mask; unsigned char value; char flags; const char *text; }; 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) { printf("Correcting Natoma config for SMP\n"); pmccfg &= ~0x8000; pci_write_config(dev, 0x50, 2, pmccfg); } #else if ((pmccfg & 0x8000) == 0) { printf("Correcting Natoma config for non-SMP\n"); pmccfg |= 0x8000; pci_write_config(dev, 0x50, 2, pmccfg); } #endif } #ifndef PCI_QUIET #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) printf ("%s", text); tbl++; } } #ifdef DUMPCONFIGSPACE static void dumpconfigspace (device_t dev) { int reg; printf ("configuration space registers:"); for (reg = 0; reg < 0x100; reg+=4) { if ((reg & 0x0f) == 0) printf ("\n%02x:\t", reg); printf ("%08x ", pci_read_config(dev, reg, 4)); } printf ("\n"); } #endif /* DUMPCONFIGSPACE */ #endif /* PCI_QUIET */ const char * ide_pci_match(device_t dev) { switch (pci_get_devid(dev)) { case 0x12308086: return ("Intel PIIX IDE controller"); case 0x70108086: return ("Intel PIIX3 IDE controller"); case 0x71118086: return ("Intel PIIX4 IDE controller"); case 0x4d33105a: return ("Promise Ultra/33 IDE controller"); case 0x522910b9: return ("AcerLabs Aladdin IDE controller"); case 0x15711106: case 0x05711106: return ("VIA Apollo IDE controller"); case 0x06401095: return ("CMD 640 IDE controller"); case 0x06461095: return ("CMD 646 IDE controller"); case 0xc6931080: return ("Cypress 82C693 IDE controller"); case 0x01021078: return ("Cyrix 5530 IDE controller"); case 0x55131039: return ("SiS 5591 IDE controller"); default: if (pci_get_class(dev) == PCIC_STORAGE && pci_get_subclass(dev) == PCIS_STORAGE_IDE) return ("Unknown PCI IDE controller"); } return NULL; } 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 * 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: snprintf(tmpbuf, sizeof(tmpbuf), "PCI to 0x%x", pci_get_subclass(dev)); break; } snprintf(tmpbuf+strlen(tmpbuf), sizeof(tmpbuf)-strlen(tmpbuf), " bridge (vendor=%04x device=%04x)", pci_get_vendor(dev), pci_get_device(dev)); descr = malloc (strlen(tmpbuf) +1, M_DEVBUF, M_WAITOK); strcpy(descr, tmpbuf); return descr; } static const char* pcib_match(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 0x124b8086: return ("Intel 82380FB mobile PCI to PCI 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 0x85981106: return ("VIA 82C598MVP (Apollo MVP3) PCI-PCI (AGP) 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 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"); /* Others */ case 0x00221014: return ("IBM 82351 PCI-PCI bridge"); case 0x00011011: return ("DEC 21050 PCI-PCI bridge"); }; if (pci_get_class(dev) == PCIC_BRIDGE && pci_get_subclass(dev) == PCIS_BRIDGE_PCI) return pci_bridge_type(dev); return NULL; } static int pcib_probe(device_t dev) { const char *desc; desc = pcib_match(dev); if (desc) { device_set_desc_copy(dev, desc); return 0; } return ENXIO; } static int pcib_attach(device_t dev) { - struct pci_devinfo *dinfo; - pcicfgregs *cfg; - - dinfo = device_get_ivars(dev); - cfg = &dinfo->cfg; + u_int8_t secondary; chipset_attach(dev, device_get_unit(dev)); - if (cfg->secondarybus) { - device_add_child(dev, "pci", cfg->secondarybus, 0); + secondary = pci_get_secondarybus(dev); + if (secondary) { + device_add_child(dev, "pci", secondary, 0); return bus_generic_attach(dev); } else return 0; } static int pcib_read_ivar(device_t dev, device_t child, int which, u_long *result) { if (which == PCIB_IVAR_HOSE) { /* * Pass up to parent bus. */ *result = pci_get_hose(dev); return(0); } return ENOENT; } 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_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 pcib_driver = { "pcib", pcib_methods, 1, }; static devclass_t pcib_devclass; DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 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"); /* 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"); /* 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"); /* NEC -- vendor 0x1033 */ /* The "C-bus" is 16-bits bus on PC98. */ case 0x00011033: return ("NEC 0001 PCI to PC-98 C-bus bridge"); case 0x002c1033: return ("NEC 002C PCI to PC-98 C-bus bridge"); case 0x003b1033: return ("NEC 003B PCI to PC-98 C-bus 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, 0); if (!devclass_get_device(devclass_find("isa"), 0)) device_add_child(dev, "isa", -1, 0); return 0; } return ENXIO; } static 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, }; static devclass_t isab_devclass; DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); static const char* 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 0x12348086: return ("Intel 82371MX mobile PCI I/O IDE accelerator (MPIIX)"); 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 0x12378086: fixwsc_natoma(dev); return ("Intel 82440FX (Natoma) PCI and memory controller"); case 0x70208086: return ("Intel 82371SB (PIIX3) USB controller"); #ifdef NWH case 0x71128086: return ("Intel 82371AB/EB (PIIX4) USB controller"); #endif case 0x84c58086: return ("Intel 82453KX/GX (Orion) PCI memory controller"); /* SiS -- vendor 0x1039 */ case 0x04961039: return ("SiS 85c496"); 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: return ("VIA 82C586B ACPI interface"); case 0x05711106: return ("VIA 82C586B IDE controller"); case 0x30381106: return ("VIA 83C572 USB controller"); /* NEC -- vendor 0x1033 */ case 0x00021033: return ("NEC 0002 PCI to PC-98 local bus bridge"); case 0x00161033: return ("NEC 0016 PCI to PC-98 local bus 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 0x523710b9: return ("AcerLabs M5237 (Aladdin-V) USB controller"); case 0x710110b9: return ("AcerLabs M15x3 Power Management Unit"); /* OPTi -- vendor 0x1045 */ case 0xc8221045: return ("OPTi 82C822 host to PCI Bridge"); #ifdef NWH case 0xc8611045: return ("OPTi 82C861 (FireLink) USB controller"); #endif /* NEC -- vendor 0x1033 */ /* PCI to C-bus bridge */ /* The following chipsets are PCI to PC98 C-bus bridge. * The C-bus is the 16-bits bus on PC98 and it should be probed as * PCI to ISA bridge. Because class of the C-bus is not defined, * C-bus bridges are recognized as "other bridge." To make C-bus * bridge be recognized as ISA bridge, this function returns NULL. */ case 0x00011033: case 0x002c1033: case 0x003b1033: return NULL; 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_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); 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; } static int chip_probe(device_t dev) { const char *desc; desc = chip_match(dev); if (desc == NULL) desc = ide_pci_match(dev); if (desc) { if (pci_get_class(dev) == PCIC_BRIDGE && pci_get_subclass(dev) == PCIS_BRIDGE_HOST) { /* * Suppress printing this device since the nexus * has already described it. */ device_quiet(dev); } device_set_desc_copy(dev, desc); return -100; /* Low match priority */ } return ENXIO; } static int chip_attach(device_t dev) { chipset_attach(dev, device_get_unit(dev)); return 0; } static device_method_t chip_methods[] = { /* Device interface */ DEVMETHOD(device_probe, chip_probe), DEVMETHOD(device_attach, chip_attach), { 0, 0 } }; static driver_t chip_driver = { "chip", chip_methods, 1, }; static devclass_t chip_devclass; DRIVER_MODULE(chip, pci, chip_driver, chip_devclass, 0, 0); /*--------------------------------------------------------- ** ** Catchall driver for VGA devices ** ** By Garrett Wollman ** ** **--------------------------------------------------------- */ static const char* 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 0x10c8: vendor = "NeoMagic"; switch (id >> 16) { case 0x0004: chip = "NM2160 laptop"; break; } break; case 0x121a: vendor = "3Dfx"; type = "graphics accelerator"; switch (id >> 16) { 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 2064W"; break; case 0x051a: chip = "MGA 1024SG/1064SG/1164SG"; break; case 0x051b: chip = "MGA 2164W"; break; } break; case 0x1002: vendor = "ATI"; type = "graphics accelerator"; switch (id >> 16) { case 0x4158: chip = "Mach32"; break; case 0x4758: chip = "Mach64-GX"; break; case 0x4358: chip = "Mach64-CX"; break; case 0x4354: chip = "Mach64-CT"; break; case 0x4554: chip = "Mach64-ET"; break; case 0x5654: chip = "Mach64-VT"; break; case 0x4754: chip = "Mach64-GT"; break; } break; case 0x1005: vendor = "Avance Logic"; switch (id >> 16) { case 0x2301: chip = "ALG2301"; 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"; 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 0x00a0: chip = "GD5430"; break; case 0x00a4: case 0x00a8: chip = "GD5434"; break; case 0x00ac: chip = "GD5436"; break; case 0x00b8: chip = "GD5446"; break; case 0x00d0: chip = "GD5462"; break; case 0x00d4: chip = "GD5464"; 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"; if ((id >> 16) == 0x00d8) chip = "65545"; break; case 0x1033: vendor = "NEC"; switch (id >> 16) { case 0x0009: type = "PCI to PC-98 Core Graph bridge"; break; } break; case 0x1039: vendor = "SiS"; switch (id >> 16) { case 0x0001: chip = "86c201"; break; case 0x0002: chip = "86c202"; break; case 0x0205: chip = "86c205"; break; } break; case 0x105d: vendor = "Number Nine"; type = "graphics accelerator"; switch (id >> 16) { case 0x2309: case 0x2339: chip = "Imagine 128"; 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 0x1236: vendor = "Sigma Designs"; if ((id >> 16) == 0x6401) chip = "64GX"; break; case 0x5333: vendor = "S3"; type = "graphics accelerator"; switch (id >> 16) { case 0x8811: chip = "Trio"; break; case 0x8812: chip = "Aurora 64"; break; case 0x8814: case 0x8901: chip = "Trio 64"; break; case 0x8902: chip = "Plato"; 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; } 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 0x0020: chip = "Riva TNT"; break; case 0x0028: chip = "Riva TNT2"; break; } break; case 0x12d2: vendor = "NVidia"; type = "graphics accelerator"; switch (id >> 16) { case 0x0018: chip = "Riva128"; 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_NOWAIT); if (buf) sprintf(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) + strlen(type) + 2 + 6 + 4 + 1; MALLOC(buf, char *, len, M_TEMP, M_NOWAIT); if (buf) sprintf(buf, "%s model %04x %s", vendor, id >> 16, type); return buf; } return type; } static int vga_probe(device_t dev) { const char *desc; desc = vga_match(dev); if (desc) { device_set_desc(dev, desc); return -100; /* Low match priority */ } return ENXIO; } static int vga_attach(device_t dev) { /* ** If the assigned addresses are remapped, ** the console driver has to be informed about the new address. */ #if 0 vm_offset_t va; vm_offset_t pa; int reg; for (reg = PCI_MAP_REG_START; reg < PCI_MAP_REG_END; reg += 4) (void) pci_map_mem (tag, reg, &va, &pa); #endif return 0; } static device_method_t vga_methods[] = { /* Device interface */ DEVMETHOD(device_probe, vga_probe), DEVMETHOD(device_attach, vga_attach), { 0, 0 } }; static driver_t vga_driver = { "vga-pci", vga_methods, 1, }; static devclass_t vga_devclass; DRIVER_MODULE(vga, pci, vga_driver, vga_devclass, 0, 0); /*--------------------------------------------------------- ** ** Devices to ignore ** **--------------------------------------------------------- */ static int ign_probe (device_t dev) { switch (pci_get_devid(dev)) { case 0x10001042ul: /* wd */ return 0; /* return ("SMC FDC 37c665");*/ }; 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/pci/pcivar.h b/sys/pci/pcivar.h index ae4958dbf265..31cea00aa440 100644 --- a/sys/pci/pcivar.h +++ b/sys/pci/pcivar.h @@ -1,346 +1,330 @@ /* * 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$ * */ #ifndef _PCIVAR_H_ #define _PCIVAR_H_ #ifndef PCI_COMPAT #define PCI_COMPAT #endif #include /* XXX KDM */ #include /* 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_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 */ #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 -/* map register information */ - -typedef struct { - u_int32_t base; - u_int8_t type; -#define PCI_MAPMEM 0x01 /* memory map */ -#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ -#define PCI_MAPPORT 0x04 /* port map */ - u_int8_t ln2size; - u_int8_t ln2range; - u_int8_t reg; /* offset of map register in config space */ -/* u_int8_t dummy;*/ - struct resource *res; /* handle from resource manager */ -} pcimap; - /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ - pcimap *map; /* pointer to array of PCI maps */ void *hdrspec; /* pointer to header type specific data */ - struct resource *irqres; /* resource descriptor for interrupt mapping */ 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 */ u_int16_t cmdreg; /* disable/enable chip and PCI options */ u_int16_t statreg; /* supported PCI features and error state */ 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 */ 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) */ 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 */ u_int8_t mfdev; /* multi-function device (from hdrtype reg) */ u_int8_t nummaps; /* actual number of PCI maps used */ u_int8_t hose; /* hose which bus is attached to */ u_int8_t bus; /* config space bus address */ u_int8_t slot; /* config space slot address */ u_int8_t func; /* config space function number */ u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ } 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) 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 */ } 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 */ } pcih2cfgregs; /* PCI bus attach definitions (there could be multiple PCI bus *trees* ... */ typedef struct pciattach { int unit; int pcibushigh; struct pciattach *next; } pciattach; -struct pci_devinfo { - STAILQ_ENTRY(pci_devinfo) pci_links; - pcicfgregs cfg; - struct pci_conf conf; -}; - extern u_int32_t pci_numdevs; /* externally visible functions */ const char *ide_pci_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); #ifdef __alpha__ vm_offset_t pci_cvt_to_dense (vm_offset_t); vm_offset_t pci_cvt_to_bwx (vm_offset_t); #endif /* __alpha__ */ /* 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" +/* + * 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 + 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_HOSE, }; /* * Simplified accessors for pci devices */ #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) \ { \ u_long v = (u_long) 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) PCI_ACCESSOR(hose, HOSE, u_int32_t) static __inline u_int32_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_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_HOSE, }; #define PCIB_ACCESSOR(A, B, T) \ \ static __inline T pcib_get_ ## A(device_t dev) \ { \ uintptr_t v; \ BUS_READ_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, &v); \ return (T) v; \ } \ \ static __inline void pcib_set_ ## A(device_t dev, T t) \ { \ u_long v = (u_long) t; \ BUS_WRITE_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, v); \ } PCIB_ACCESSOR(hose, HOSE, u_int32_t) #endif /* for compatibility to FreeBSD-2.2 version of PCI code */ #ifdef PCI_COMPAT typedef pcicfgregs *pcici_t; typedef unsigned pcidi_t; typedef void pci_inthand_t(void *arg); #define pci_max_burst_len (3) /* just copied from old PCI code for now ... */ extern int pci_mechanism; 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); }; #ifdef __i386__ typedef u_short pci_port_t; #else typedef u_int pci_port_t; #endif 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_dense (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); int pci_map_bwx (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, intrmask_t *maskptr); int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr, 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 /* PCI_COMPAT */ #endif /* _PCIVAR_H_ */ diff --git a/sys/powerpc/include/resource.h b/sys/powerpc/include/resource.h index adcf0ce00f9d..28fcc98ea1be 100644 --- a/sys/powerpc/include/resource.h +++ b/sys/powerpc/include/resource.h @@ -1,45 +1,44 @@ +/* $FreeBSD$ */ /* * 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. */ #ifndef _MACHINE_RESOURCE_H_ #define _MACHINE_RESOURCE_H_ 1 /* * Definitions of resource types for Intel Architecture machines * with support for legacy ISA devices and drivers. */ #define SYS_RES_IRQ 1 /* interrupt lines */ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ -#define SYS_RES_DENSE SYS_RES_MEMORY -#define SYS_RES_BWX SYS_RES_MEMORY #endif /* !_MACHINE_RESOURCE_H_ */