pci.c revision 49129
129088Smarkm/* 229088Smarkm * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 329088Smarkm * All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice unmodified, this list of conditions, and the following 1029088Smarkm * disclaimer. 1129088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1229088Smarkm * notice, this list of conditions and the following disclaimer in the 1329088Smarkm * documentation and/or other materials provided with the distribution. 1429088Smarkm * 1529088Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1629088Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1729088Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1829088Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1929088Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2029088Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2129088Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2229088Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2329088Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2429088Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2529088Smarkm * 2629088Smarkm * $Id: pci.c,v 1.110 1999/07/03 20:17:07 peter Exp $ 2729088Smarkm * 2829088Smarkm */ 2929088Smarkm 3029088Smarkm#include "opt_bus.h" 3129088Smarkm 3256668Sshin#include "opt_devfs.h" 3356668Sshin#include "opt_simos.h" 3429088Smarkm 3529088Smarkm#include <sys/param.h> 3629088Smarkm#include <sys/systm.h> 3729181Smarkm#include <sys/malloc.h> 3829088Smarkm#include <sys/module.h> 3929088Smarkm#include <sys/fcntl.h> 4029088Smarkm#include <sys/conf.h> 4129088Smarkm#include <sys/kernel.h> 4229088Smarkm#include <sys/queue.h> 4329088Smarkm#include <sys/types.h> 4429088Smarkm#include <sys/buf.h> 4529088Smarkm#ifdef DEVFS 4629088Smarkm#include <sys/devfsext.h> 4729088Smarkm#endif /* DEVFS */ 4829088Smarkm 4929088Smarkm#include <vm/vm.h> 5029088Smarkm#include <vm/pmap.h> 5129088Smarkm#include <vm/vm_extern.h> 5229088Smarkm 5329088Smarkm#include <sys/bus.h> 5429088Smarkm#include <machine/bus.h> 5529088Smarkm#include <sys/rman.h> 5629088Smarkm#include <machine/resource.h> 5729088Smarkm#include <machine/md_var.h> /* For the Alpha */ 5829088Smarkm 5929088Smarkm#include <pci/pcireg.h> 6029088Smarkm#include <pci/pcivar.h> 6129181Smarkm#include <pci/pci_ioctl.h> 6229181Smarkm 6329088Smarkm#ifdef APIC_IO 6429088Smarkm#include <machine/smp.h> 6529088Smarkm#endif /* APIC_IO */ 6629088Smarkm 6729088Smarkmstatic STAILQ_HEAD(devlist, pci_devinfo) pci_devq; 6829088Smarkmu_int32_t pci_numdevs = 0; 6929088Smarkmstatic u_int32_t pci_generation = 0; 7029088Smarkm 7129088Smarkm#define PCI_MFCTR_CHAR0(ID) (char)(((ID>>10) & 0x1F) | '@') /* Bits 10-14 */ 7229088Smarkm#define PCI_MFCTR_CHAR1(ID) (char)(((ID>>5 ) & 0x1F) | '@') /* Bits 5-9 */ 7329088Smarkm#define PCI_MFCTR_CHAR2(ID) (char)(( ID & 0x1F) | '@') /* Bits 0-4 */ 7429181Smarkm 7529181Smarkm/* return base address of memory or port map */ 7629181Smarkm 7729181Smarkmstatic int 7829181Smarkmpci_mapbase(unsigned mapreg) 7929181Smarkm{ 8029181Smarkm int mask = 0x03; 8129088Smarkm if ((mapreg & 0x01) == 0) 8229088Smarkm mask = 0x0f; 8329088Smarkm return (mapreg & ~mask); 8429088Smarkm} 8529088Smarkm 8629088Smarkm/* return map type of memory or port map */ 8729088Smarkm 8856668Sshinstatic int 8929088Smarkmpci_maptype(unsigned mapreg) 9029088Smarkm{ 9129088Smarkm static u_int8_t maptype[0x10] = { 9229088Smarkm PCI_MAPMEM, PCI_MAPPORT, 9329088Smarkm PCI_MAPMEM, 0, 9429088Smarkm PCI_MAPMEM, PCI_MAPPORT, 9529088Smarkm 0, 0, 9629088Smarkm PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, 9729088Smarkm PCI_MAPMEM|PCI_MAPMEMP, 0, 9829088Smarkm PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, 9929088Smarkm 0, 0, 10029088Smarkm }; 10129088Smarkm 10229088Smarkm return maptype[mapreg & 0x0f]; 10329088Smarkm} 10429088Smarkm 10529088Smarkm/* return log2 of map size decoded for memory or port map */ 10629088Smarkm 10729088Smarkmstatic int 10829181Smarkmpci_mapsize(unsigned testval) 10929181Smarkm{ 11029181Smarkm int ln2size; 11157125Sshin 11229088Smarkm testval = pci_mapbase(testval); 11329181Smarkm ln2size = 0; 11429181Smarkm if (testval != 0) { 11529088Smarkm while ((testval & 1) == 0) 11629088Smarkm { 11729088Smarkm ln2size++; 11829088Smarkm testval >>= 1; 11929088Smarkm } 12029088Smarkm } 12129088Smarkm return (ln2size); 12229088Smarkm} 12329088Smarkm 12429088Smarkm/* return log2 of address range supported by map register */ 12529088Smarkm 12629088Smarkmstatic int 12729181Smarkmpci_maprange(unsigned mapreg) 12829181Smarkm{ 12929181Smarkm int ln2range = 0; 13029181Smarkm switch (mapreg & 0x07) { 13129181Smarkm case 0x00: 13229181Smarkm case 0x01: 13329181Smarkm case 0x05: 13429181Smarkm ln2range = 32; 13529181Smarkm break; 13629181Smarkm case 0x02: 13729181Smarkm ln2range = 20; 13829181Smarkm break; 13929181Smarkm case 0x04: 14029181Smarkm ln2range = 64; 14129181Smarkm break; 14229181Smarkm } 14329181Smarkm return (ln2range); 14429181Smarkm} 14529181Smarkm 14629181Smarkm/* extract map parameters into newly allocated array of pcimap structures */ 14729181Smarkm 14829181Smarkmstatic pcimap * 14929181Smarkmpci_readmaps(pcicfgregs *cfg, int maxmaps) 15029181Smarkm{ 15129181Smarkm int i, j = 0; 15229181Smarkm pcimap *map; 15329181Smarkm int map64 = 0; 15429181Smarkm int reg = PCIR_MAPS; 15529181Smarkm 15629181Smarkm for (i = 0; i < maxmaps; i++) { 15729181Smarkm int reg = PCIR_MAPS + i*4; 15829088Smarkm u_int32_t base; 15929088Smarkm u_int32_t ln2range; 16029088Smarkm 16129088Smarkm base = pci_cfgread(cfg, reg, 4); 16229088Smarkm ln2range = pci_maprange(base); 16329088Smarkm 16429088Smarkm if (base == 0 || ln2range == 0 || base == 0xffffffff) 16529088Smarkm continue; /* skip invalid entry */ 16629088Smarkm else { 16729088Smarkm j++; 16829088Smarkm if (ln2range > 32) { 16929088Smarkm i++; 17029088Smarkm j++; 17129088Smarkm } 17229181Smarkm } 17329088Smarkm } 17429088Smarkm 17529088Smarkm map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK); 17629088Smarkm if (map != NULL) { 17729088Smarkm bzero(map, sizeof(pcimap) * j); 17829088Smarkm cfg->nummaps = j; 17929088Smarkm 18029088Smarkm for (i = 0, j = 0; i < maxmaps; i++, reg += 4) { 18129088Smarkm u_int32_t base; 18229088Smarkm u_int32_t testval; 18329088Smarkm 18429088Smarkm base = pci_cfgread(cfg, reg, 4); 18529088Smarkm 18629088Smarkm if (map64 == 0) { 18729088Smarkm if (base == 0 || base == 0xffffffff) 18829088Smarkm continue; /* skip invalid entry */ 18929088Smarkm pci_cfgwrite(cfg, reg, 0xffffffff, 4); 19029088Smarkm testval = pci_cfgread(cfg, reg, 4); 19129088Smarkm pci_cfgwrite(cfg, reg, base, 4); 19229088Smarkm 19329088Smarkm map[j].reg = reg; 19429088Smarkm map[j].base = pci_mapbase(base); 19529088Smarkm map[j].type = pci_maptype(base); 19629088Smarkm map[j].ln2size = pci_mapsize(testval); 19729088Smarkm map[j].ln2range = pci_maprange(testval); 19829088Smarkm map64 = map[j].ln2range == 64; 19929088Smarkm } else { 20029088Smarkm /* only fill in base, other fields are 0 */ 20129088Smarkm map[j].base = base; 20229088Smarkm map64 = 0; 20329088Smarkm } 20429088Smarkm#ifdef __alpha__ 20529088Smarkm /* 20629088Smarkm * XXX: encode hose number in the base addr, 20729088Smarkm * This will go away once the bus_space functions 20829088Smarkm * can deal with multiple hoses 20929088Smarkm */ 21029088Smarkm 21129088Smarkm if(cfg->hose){ 21229088Smarkm if(map[j].base & 0x80000000){ 21329088Smarkm printf("base addr = 0x%x\n", map[j].base); 21429088Smarkm printf("hacked addr = 0x%x\n", 21529181Smarkm map[j].base | (cfg->hose << 31)); 21629088Smarkm 21729088Smarkm panic("hose encoding hack would clobber base addr"); 21829088Smarkm } 21929088Smarkm if(cfg->hose > 1 ) 22029088Smarkm panic("only one hose supported!"); 22129088Smarkm map[j].base |= (cfg->hose << 31); 22229088Smarkm } 22329088Smarkm#endif 22429088Smarkm j++; 22529088Smarkm } 22629088Smarkm } 22729088Smarkm return (map); 22829088Smarkm} 22929088Smarkm 23029088Smarkm/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ 23129088Smarkm 23229088Smarkmstatic void 23329088Smarkmpci_fixancient(pcicfgregs *cfg) 23429088Smarkm{ 23529088Smarkm if (cfg->hdrtype != 0) 23629088Smarkm return; 23729088Smarkm 23829088Smarkm /* PCI to PCI bridges use header type 1 */ 23929088Smarkm if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) 24029088Smarkm cfg->hdrtype = 1; 24129088Smarkm} 24229088Smarkm 24329088Smarkm/* read config data specific to header type 1 device (PCI to PCI bridge) */ 24429088Smarkm 24529088Smarkmstatic void * 24629088Smarkmpci_readppb(pcicfgregs *cfg) 24729088Smarkm{ 24829088Smarkm pcih1cfgregs *p; 24929088Smarkm 25029088Smarkm p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); 25129088Smarkm if (p == NULL) 25229088Smarkm return (NULL); 25329088Smarkm 25429088Smarkm bzero(p, sizeof *p); 25529088Smarkm 25629088Smarkm p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2); 25729088Smarkm p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2); 25829088Smarkm 25929088Smarkm p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1); 26029088Smarkm 26129088Smarkm p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2), 26229088Smarkm pci_cfgread(cfg, PCIR_IOBASEL_1, 1)); 26329088Smarkm p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2), 26429088Smarkm pci_cfgread(cfg, PCIR_IOLIMITL_1, 1)); 26529088Smarkm 26629088Smarkm p->membase = PCI_PPBMEMBASE (0, 26729088Smarkm pci_cfgread(cfg, PCIR_MEMBASE_1, 2)); 26829088Smarkm p->memlimit = PCI_PPBMEMLIMIT (0, 26929088Smarkm pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2)); 27029088Smarkm 27129088Smarkm p->pmembase = PCI_PPBMEMBASE ( 27229088Smarkm (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4), 27329088Smarkm pci_cfgread(cfg, PCIR_PMBASEL_1, 2)); 27429088Smarkm 27529088Smarkm p->pmemlimit = PCI_PPBMEMLIMIT ( 27629088Smarkm (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4), 27729088Smarkm pci_cfgread(cfg, PCIR_PMLIMITL_1, 2)); 27829088Smarkm return (p); 27929088Smarkm} 28029088Smarkm 28129088Smarkm/* read config data specific to header type 2 device (PCI to CardBus bridge) */ 28229088Smarkm 28329088Smarkmstatic void * 28429088Smarkmpci_readpcb(pcicfgregs *cfg) 28529088Smarkm{ 28629088Smarkm pcih2cfgregs *p; 28729088Smarkm 28829088Smarkm p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); 28929088Smarkm if (p == NULL) 29029088Smarkm return (NULL); 29129088Smarkm 29229088Smarkm bzero(p, sizeof *p); 29329088Smarkm 29429088Smarkm p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2); 29529088Smarkm p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2); 29629088Smarkm 29729088Smarkm p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1); 29829088Smarkm 29929088Smarkm p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4); 30029088Smarkm p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4); 30129088Smarkm p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4); 30229088Smarkm p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4); 30329088Smarkm 30429088Smarkm p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4); 30529088Smarkm p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4); 30629088Smarkm p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4); 30729088Smarkm p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4); 30829088Smarkm 30929088Smarkm p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4); 31029088Smarkm return p; 31129088Smarkm} 31229088Smarkm 31329088Smarkm/* extract header type specific config data */ 31429088Smarkm 31529088Smarkmstatic void 31629088Smarkmpci_hdrtypedata(pcicfgregs *cfg) 31729088Smarkm{ 31829088Smarkm switch (cfg->hdrtype) { 31929088Smarkm case 0: 32029088Smarkm cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); 32129088Smarkm cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); 32229088Smarkm cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); 32329088Smarkm break; 32429088Smarkm case 1: 32529088Smarkm cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); 32629088Smarkm cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); 32729088Smarkm cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); 32829088Smarkm cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); 32929088Smarkm cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); 33029088Smarkm cfg->hdrspec = pci_readppb(cfg); 33129088Smarkm break; 33229088Smarkm case 2: 33329088Smarkm cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2); 33429088Smarkm cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); 33529088Smarkm cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); 33629088Smarkm cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); 33729088Smarkm cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); 33829088Smarkm cfg->hdrspec = pci_readpcb(cfg); 33929088Smarkm break; 34029088Smarkm } 34129088Smarkm} 34229088Smarkm 34329088Smarkm/* read configuration header into pcicfgrect structure */ 34429088Smarkm 34529088Smarkmstatic struct pci_devinfo * 34629088Smarkmpci_readcfg(pcicfgregs *probe) 34729088Smarkm{ 34829088Smarkm pcicfgregs *cfg = NULL; 34929088Smarkm struct pci_devinfo *devlist_entry; 35029088Smarkm struct devlist *devlist_head; 35129088Smarkm 35229088Smarkm devlist_head = &pci_devq; 35329088Smarkm 35429088Smarkm devlist_entry = NULL; 35529088Smarkm 35629088Smarkm if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) { 35729088Smarkm devlist_entry = malloc(sizeof(struct pci_devinfo), 35829088Smarkm M_DEVBUF, M_WAITOK); 35929088Smarkm if (devlist_entry == NULL) 36029088Smarkm return (NULL); 36129088Smarkm bzero(devlist_entry, sizeof *devlist_entry); 36229088Smarkm 36329088Smarkm cfg = &devlist_entry->cfg; 36429088Smarkm 36529088Smarkm cfg->hose = probe->hose; 36629088Smarkm cfg->bus = probe->bus; 36729088Smarkm cfg->slot = probe->slot; 36829088Smarkm cfg->func = probe->func; 36929088Smarkm cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2); 37029088Smarkm cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2); 37129088Smarkm cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2); 37229088Smarkm cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2); 37329088Smarkm cfg->baseclass = pci_cfgread(cfg, PCIR_CLASS, 1); 37429088Smarkm cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1); 37529088Smarkm cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1); 37629088Smarkm cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1); 37729088Smarkm cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1); 37829088Smarkm cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1); 37929088Smarkm cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1); 38029088Smarkm cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1); 38129088Smarkm cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1); 38229088Smarkm#ifdef __alpha__ 38329088Smarkm alpha_platform_assign_pciintr(cfg); 38429088Smarkm#endif 38529088Smarkm 38629088Smarkm#ifdef APIC_IO 38729088Smarkm if (cfg->intpin != 0) { 38829088Smarkm int airq; 38929088Smarkm 39029088Smarkm airq = pci_apic_irq(cfg->bus, cfg->slot, cfg->intpin); 39129088Smarkm if (airq >= 0) { 39229088Smarkm /* PCI specific entry found in MP table */ 39329088Smarkm if (airq != cfg->intline) { 39429088Smarkm undirect_pci_irq(cfg->intline); 39529088Smarkm cfg->intline = airq; 39629088Smarkm } 39729088Smarkm } else { 39829088Smarkm /* 39929088Smarkm * PCI interrupts might be redirected to the 40029088Smarkm * ISA bus according to some MP tables. Use the 40129088Smarkm * same methods as used by the ISA devices 40229088Smarkm * devices to find the proper IOAPIC int pin. 40329088Smarkm */ 40429088Smarkm airq = isa_apic_irq(cfg->intline); 40529088Smarkm if ((airq >= 0) && (airq != cfg->intline)) { 40629088Smarkm /* XXX: undirect_pci_irq() ? */ 40729088Smarkm undirect_isa_irq(cfg->intline); 40829088Smarkm cfg->intline = airq; 40929088Smarkm } 41029088Smarkm } 41129088Smarkm } 41229088Smarkm#endif /* APIC_IO */ 41329088Smarkm 41429088Smarkm cfg->mingnt = pci_cfgread(cfg, PCIR_MINGNT, 1); 41529088Smarkm cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1); 41629088Smarkm 41729088Smarkm cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; 41829088Smarkm cfg->hdrtype &= ~PCIM_MFDEV; 41929088Smarkm 42029088Smarkm pci_fixancient(cfg); 42129088Smarkm pci_hdrtypedata(cfg); 42229088Smarkm 42329088Smarkm STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links); 42429088Smarkm 42529088Smarkm devlist_entry->conf.pc_sel.pc_bus = cfg->bus; 42629088Smarkm devlist_entry->conf.pc_sel.pc_dev = cfg->slot; 42729088Smarkm devlist_entry->conf.pc_sel.pc_func = cfg->func; 42829088Smarkm devlist_entry->conf.pc_hdr = cfg->hdrtype; 42929088Smarkm 43029088Smarkm devlist_entry->conf.pc_subvendor = cfg->subvendor; 43129088Smarkm devlist_entry->conf.pc_subdevice = cfg->subdevice; 43229088Smarkm devlist_entry->conf.pc_vendor = cfg->vendor; 43329088Smarkm devlist_entry->conf.pc_device = cfg->device; 43429088Smarkm 43529088Smarkm devlist_entry->conf.pc_class = cfg->baseclass; 43629088Smarkm devlist_entry->conf.pc_subclass = cfg->subclass; 43729088Smarkm devlist_entry->conf.pc_progif = cfg->progif; 43829088Smarkm devlist_entry->conf.pc_revid = cfg->revid; 43929088Smarkm 44029088Smarkm pci_numdevs++; 44129088Smarkm pci_generation++; 44229088Smarkm } 44329088Smarkm return (devlist_entry); 44429088Smarkm} 44529088Smarkm 44629088Smarkm#if 0 44729088Smarkm/* free pcicfgregs structure and all depending data structures */ 44829088Smarkm 44929088Smarkmstatic int 45029088Smarkmpci_freecfg(struct pci_devinfo *dinfo) 45129088Smarkm{ 45229088Smarkm struct devlist *devlist_head; 45329088Smarkm 45429088Smarkm devlist_head = &pci_devq; 45529088Smarkm 45629088Smarkm if (dinfo->cfg.hdrspec != NULL) 45729088Smarkm free(dinfo->cfg.hdrspec, M_DEVBUF); 45829088Smarkm if (dinfo->cfg.map != NULL) 45929088Smarkm free(dinfo->cfg.map, M_DEVBUF); 46029088Smarkm /* XXX this hasn't been tested */ 46129088Smarkm STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); 46229088Smarkm free(dinfo, M_DEVBUF); 46329088Smarkm 46429088Smarkm /* increment the generation count */ 46529088Smarkm pci_generation++; 46629088Smarkm 46729088Smarkm /* we're losing one device */ 46829088Smarkm pci_numdevs--; 46929088Smarkm return (0); 47029088Smarkm} 47129088Smarkm#endif 47229088Smarkm 47329088Smarkm 47429088Smarkm/* 47529088Smarkm * This is the user interface to PCI configuration space. 47629088Smarkm */ 47729088Smarkm 47829088Smarkmstatic int 47929088Smarkmpci_open(dev_t dev, int oflags, int devtype, struct proc *p) 48029088Smarkm{ 48129088Smarkm if ((oflags & FWRITE) && securelevel > 0) { 48229088Smarkm return EPERM; 48329088Smarkm } 48429088Smarkm return 0; 48529088Smarkm} 48629088Smarkm 48729088Smarkmstatic int 48829088Smarkmpci_close(dev_t dev, int flag, int devtype, struct proc *p) 48929088Smarkm{ 49029088Smarkm return 0; 49129088Smarkm} 49229088Smarkm 49329088Smarkm/* 49429088Smarkm * Match a single pci_conf structure against an array of pci_match_conf 49529088Smarkm * structures. The first argument, 'matches', is an array of num_matches 49629088Smarkm * pci_match_conf structures. match_buf is a pointer to the pci_conf 49729088Smarkm * structure that will be compared to every entry in the matches array. 49829088Smarkm * This function returns 1 on failure, 0 on success. 49929088Smarkm */ 50029088Smarkmstatic int 50129088Smarkmpci_conf_match(struct pci_match_conf *matches, int num_matches, 50229088Smarkm struct pci_conf *match_buf) 50329088Smarkm{ 50429088Smarkm int i; 50529088Smarkm 50629088Smarkm if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 50729088Smarkm return(1); 50829088Smarkm 50929088Smarkm for (i = 0; i < num_matches; i++) { 51029088Smarkm /* 51129088Smarkm * I'm not sure why someone would do this...but... 51229088Smarkm */ 51329088Smarkm if (matches[i].flags == PCI_GETCONF_NO_MATCH) 51429088Smarkm continue; 51529088Smarkm 51629088Smarkm /* 51729088Smarkm * Look at each of the match flags. If it's set, do the 51829088Smarkm * comparison. If the comparison fails, we don't have a 51929088Smarkm * match, go on to the next item if there is one. 52029088Smarkm */ 52129088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 52229088Smarkm && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 52329088Smarkm continue; 52429088Smarkm 52529088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 52629088Smarkm && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 52729088Smarkm continue; 52829088Smarkm 52929088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 53029088Smarkm && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 53129088Smarkm continue; 53229088Smarkm 53329088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 53429088Smarkm && (match_buf->pc_vendor != matches[i].pc_vendor)) 53529088Smarkm continue; 53629088Smarkm 53729088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 53829088Smarkm && (match_buf->pc_device != matches[i].pc_device)) 53929088Smarkm continue; 54029088Smarkm 54129088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 54229088Smarkm && (match_buf->pc_class != matches[i].pc_class)) 54329088Smarkm continue; 54429088Smarkm 54529088Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 54629088Smarkm && (match_buf->pd_unit != matches[i].pd_unit)) 54729088Smarkm continue; 54829088Smarkm 54929181Smarkm if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 55029088Smarkm && (strncmp(matches[i].pd_name, match_buf->pd_name, 55129088Smarkm sizeof(match_buf->pd_name)) != 0)) 55229088Smarkm continue; 55329088Smarkm 55429088Smarkm return(0); 55529088Smarkm } 55629088Smarkm 55729088Smarkm return(1); 55829088Smarkm} 55929088Smarkm 56029088Smarkm/* 56129088Smarkm * Locate the parent of a PCI device by scanning the PCI devlist 56229088Smarkm * and return the entry for the parent. 56329088Smarkm * For devices on PCI Bus 0 (the host bus), this is the PCI Host. 56429088Smarkm * For devices on secondary PCI busses, this is that bus' PCI-PCI Bridge. 56529088Smarkm */ 56629088Smarkm 56729088Smarkmpcicfgregs * 56829088Smarkmpci_devlist_get_parent(pcicfgregs *cfg) 56929088Smarkm{ 57029088Smarkm struct devlist *devlist_head; 57129088Smarkm struct pci_devinfo *dinfo; 57229088Smarkm pcicfgregs *bridge_cfg; 57329088Smarkm int i; 57429088Smarkm 57529088Smarkm dinfo = STAILQ_FIRST(devlist_head = &pci_devq); 57629088Smarkm 57729088Smarkm /* If the device is on PCI bus 0, look for the host */ 57829088Smarkm if (cfg->bus == 0) { 57929088Smarkm for (i = 0; (dinfo != NULL) && (i < pci_numdevs); 58029088Smarkm dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 58129088Smarkm bridge_cfg = &dinfo->cfg; 58229088Smarkm if (bridge_cfg->baseclass == PCIC_BRIDGE 58329088Smarkm && bridge_cfg->subclass == PCIS_BRIDGE_HOST 58429088Smarkm && bridge_cfg->bus == cfg->bus) { 58529088Smarkm return bridge_cfg; 58629088Smarkm } 58729088Smarkm } 58829088Smarkm } 58929088Smarkm 59029088Smarkm /* If the device is not on PCI bus 0, look for the PCI-PCI bridge */ 59129088Smarkm if (cfg->bus > 0) { 59229088Smarkm for (i = 0; (dinfo != NULL) && (i < pci_numdevs); 59329088Smarkm dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 59429088Smarkm bridge_cfg = &dinfo->cfg; 59529088Smarkm if (bridge_cfg->baseclass == PCIC_BRIDGE 59629088Smarkm && bridge_cfg->subclass == PCIS_BRIDGE_PCI 59729088Smarkm && bridge_cfg->secondarybus == cfg->bus) { 59829088Smarkm return bridge_cfg; 59929088Smarkm } 60029088Smarkm } 60129088Smarkm } 60229088Smarkm 60329088Smarkm return NULL; 60429088Smarkm} 60529088Smarkm 60629088Smarkmstatic int 60729088Smarkmpci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 60829088Smarkm{ 60929088Smarkm struct pci_io *io; 61029088Smarkm const char *name; 61129088Smarkm int error; 61229088Smarkm 61329088Smarkm if (!(flag & FWRITE)) 61429088Smarkm return EPERM; 61529088Smarkm 61629088Smarkm 61729088Smarkm switch(cmd) { 61829088Smarkm case PCIOCGETCONF: 61929088Smarkm { 62029088Smarkm struct pci_devinfo *dinfo; 62129088Smarkm struct pci_conf_io *cio; 62229088Smarkm struct devlist *devlist_head; 62329088Smarkm struct pci_match_conf *pattern_buf; 62429088Smarkm int num_patterns; 62529088Smarkm size_t iolen; 62629088Smarkm int ionum, i; 62729088Smarkm 62829088Smarkm cio = (struct pci_conf_io *)data; 62929088Smarkm 63029088Smarkm num_patterns = 0; 63129088Smarkm dinfo = NULL; 63229088Smarkm 63329088Smarkm /* 63429088Smarkm * Hopefully the user won't pass in a null pointer, but it 63529088Smarkm * can't hurt to check. 63629088Smarkm */ 63729088Smarkm if (cio == NULL) { 63829088Smarkm error = EINVAL; 63929088Smarkm break; 64029088Smarkm } 64129088Smarkm 64229088Smarkm /* 64329088Smarkm * If the user specified an offset into the device list, 64429088Smarkm * but the list has changed since they last called this 64529088Smarkm * ioctl, tell them that the list has changed. They will 64629088Smarkm * have to get the list from the beginning. 64729088Smarkm */ 64829088Smarkm if ((cio->offset != 0) 64929088Smarkm && (cio->generation != pci_generation)){ 65029088Smarkm cio->num_matches = 0; 65129088Smarkm cio->status = PCI_GETCONF_LIST_CHANGED; 65229088Smarkm error = 0; 65329088Smarkm break; 65429088Smarkm } 65529088Smarkm 65629088Smarkm /* 65729088Smarkm * Check to see whether the user has asked for an offset 65829088Smarkm * past the end of our list. 65929088Smarkm */ 66029088Smarkm if (cio->offset >= pci_numdevs) { 66129088Smarkm cio->num_matches = 0; 66229088Smarkm cio->status = PCI_GETCONF_LAST_DEVICE; 66329088Smarkm error = 0; 66429088Smarkm break; 66529088Smarkm } 66629088Smarkm 66729088Smarkm /* get the head of the device queue */ 66829088Smarkm devlist_head = &pci_devq; 66929088Smarkm 67029088Smarkm /* 67129088Smarkm * Determine how much room we have for pci_conf structures. 67229088Smarkm * Round the user's buffer size down to the nearest 67329088Smarkm * multiple of sizeof(struct pci_conf) in case the user 67429088Smarkm * didn't specify a multiple of that size. 67529088Smarkm */ 67629088Smarkm iolen = min(cio->match_buf_len - 67729088Smarkm (cio->match_buf_len % sizeof(struct pci_conf)), 67829088Smarkm pci_numdevs * sizeof(struct pci_conf)); 67929088Smarkm 68029088Smarkm /* 68129088Smarkm * Since we know that iolen is a multiple of the size of 68229088Smarkm * the pciconf union, it's okay to do this. 68329088Smarkm */ 68429088Smarkm ionum = iolen / sizeof(struct pci_conf); 68529088Smarkm 68629088Smarkm /* 68729088Smarkm * If this test is true, the user wants the pci_conf 68829088Smarkm * structures returned to match the supplied entries. 68929088Smarkm */ 69029088Smarkm if ((cio->num_patterns > 0) 69129088Smarkm && (cio->pat_buf_len > 0)) { 69229088Smarkm /* 69329088Smarkm * pat_buf_len needs to be: 69429088Smarkm * num_patterns * sizeof(struct pci_match_conf) 69529088Smarkm * While it is certainly possible the user just 69629088Smarkm * allocated a large buffer, but set the number of 69729088Smarkm * matches correctly, it is far more likely that 69829088Smarkm * their kernel doesn't match the userland utility 69929088Smarkm * they're using. It's also possible that the user 70029088Smarkm * forgot to initialize some variables. Yes, this 70129088Smarkm * may be overly picky, but I hazard to guess that 70229088Smarkm * it's far more likely to just catch folks that 70329088Smarkm * updated their kernel but not their userland. 70429088Smarkm */ 70529088Smarkm if ((cio->num_patterns * 70629088Smarkm sizeof(struct pci_match_conf)) != cio->pat_buf_len){ 70729088Smarkm /* The user made a mistake, return an error*/ 70829088Smarkm cio->status = PCI_GETCONF_ERROR; 70929088Smarkm printf("pci_ioctl: pat_buf_len %d != " 71029088Smarkm "num_patterns (%d) * sizeof(struct " 71129088Smarkm "pci_match_conf) (%d)\npci_ioctl: " 71229088Smarkm "pat_buf_len should be = %d\n", 71329088Smarkm cio->pat_buf_len, cio->num_patterns, 71429088Smarkm (int)sizeof(struct pci_match_conf), 71529088Smarkm (int)sizeof(struct pci_match_conf) * 71629088Smarkm cio->num_patterns); 71729088Smarkm printf("pci_ioctl: do your headers match your " 71829088Smarkm "kernel?\n"); 71929088Smarkm cio->num_matches = 0; 72029088Smarkm error = EINVAL; 72129088Smarkm break; 72229088Smarkm } 72329088Smarkm 72429088Smarkm /* 72529088Smarkm * Check the user's buffer to make sure it's readable. 72629088Smarkm */ 72729088Smarkm if ((error = useracc((caddr_t)cio->patterns, 72829088Smarkm cio->pat_buf_len, B_READ)) != 1){ 72929088Smarkm printf("pci_ioctl: pattern buffer %p, " 73029088Smarkm "length %u isn't user accessible for" 73129088Smarkm " READ\n", cio->patterns, 73229088Smarkm cio->pat_buf_len); 73329088Smarkm error = EACCES; 73429088Smarkm break; 73529088Smarkm } 73629088Smarkm /* 73729088Smarkm * Allocate a buffer to hold the patterns. 73829088Smarkm */ 73929088Smarkm pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 74029088Smarkm M_WAITOK); 74129088Smarkm error = copyin(cio->patterns, pattern_buf, 74229088Smarkm cio->pat_buf_len); 74329088Smarkm if (error != 0) 74429088Smarkm break; 74529088Smarkm num_patterns = cio->num_patterns; 74629088Smarkm 74729088Smarkm } else if ((cio->num_patterns > 0) 74829088Smarkm || (cio->pat_buf_len > 0)) { 74929088Smarkm /* 75029088Smarkm * The user made a mistake, spit out an error. 75129088Smarkm */ 75229088Smarkm cio->status = PCI_GETCONF_ERROR; 75329088Smarkm cio->num_matches = 0; 75429088Smarkm printf("pci_ioctl: invalid GETCONF arguments\n"); 75529088Smarkm error = EINVAL; 75629088Smarkm break; 75729088Smarkm } else 75829088Smarkm pattern_buf = NULL; 75929088Smarkm 76029088Smarkm /* 76129088Smarkm * Make sure we can write to the match buffer. 76229088Smarkm */ 76329088Smarkm if ((error = useracc((caddr_t)cio->matches, cio->match_buf_len, 76429088Smarkm B_WRITE)) != 1) { 76529088Smarkm printf("pci_ioctl: match buffer %p, length %u " 76629088Smarkm "isn't user accessible for WRITE\n", 76729088Smarkm cio->matches, cio->match_buf_len); 76829088Smarkm error = EACCES; 76929088Smarkm break; 77029088Smarkm } 77129088Smarkm 77229088Smarkm /* 77329088Smarkm * Go through the list of devices and copy out the devices 77429088Smarkm * that match the user's criteria. 77529088Smarkm */ 77629088Smarkm for (cio->num_matches = 0, error = 0, i = 0, 77729088Smarkm dinfo = STAILQ_FIRST(devlist_head); 77829088Smarkm (dinfo != NULL) && (cio->num_matches < ionum) 77929088Smarkm && (error == 0) && (i < pci_numdevs); 78029088Smarkm dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 78129088Smarkm 78229088Smarkm if (i < cio->offset) 78329088Smarkm continue; 78429088Smarkm 78529088Smarkm /* Populate pd_name and pd_unit */ 78629088Smarkm name = NULL; 78729088Smarkm if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0') 78829088Smarkm name = device_get_name(dinfo->cfg.dev); 78929088Smarkm if (name) { 79029088Smarkm strncpy(dinfo->conf.pd_name, name, 79129088Smarkm sizeof(dinfo->conf.pd_name)); 79229088Smarkm dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 79329088Smarkm dinfo->conf.pd_unit = 79429088Smarkm device_get_unit(dinfo->cfg.dev); 79529088Smarkm } 79629088Smarkm 79729088Smarkm if ((pattern_buf == NULL) || 79829088Smarkm (pci_conf_match(pattern_buf, num_patterns, 79929088Smarkm &dinfo->conf) == 0)) { 80029088Smarkm 80129088Smarkm /* 80229088Smarkm * If we've filled up the user's buffer, 80329088Smarkm * break out at this point. Since we've 80429088Smarkm * got a match here, we'll pick right back 80529088Smarkm * up at the matching entry. We can also 80629088Smarkm * tell the user that there are more matches 80729088Smarkm * left. 80829088Smarkm */ 80929088Smarkm if (cio->num_matches >= ionum) 81029088Smarkm break; 81129088Smarkm 81229088Smarkm error = copyout(&dinfo->conf, 81329088Smarkm &cio->matches[cio->num_matches], 81429088Smarkm sizeof(struct pci_conf)); 81529088Smarkm cio->num_matches++; 81629088Smarkm } 81729088Smarkm } 81829088Smarkm 81929088Smarkm /* 82029088Smarkm * Set the pointer into the list, so if the user is getting 82129088Smarkm * n records at a time, where n < pci_numdevs, 82229088Smarkm */ 82329088Smarkm cio->offset = i; 82429088Smarkm 82529088Smarkm /* 82629088Smarkm * Set the generation, the user will need this if they make 82729088Smarkm * another ioctl call with offset != 0. 82829088Smarkm */ 82929088Smarkm cio->generation = pci_generation; 83029088Smarkm 83129088Smarkm /* 83229088Smarkm * If this is the last device, inform the user so he won't 83329088Smarkm * bother asking for more devices. If dinfo isn't NULL, we 83429088Smarkm * know that there are more matches in the list because of 83529088Smarkm * the way the traversal is done. 83629088Smarkm */ 83729088Smarkm if (dinfo == NULL) 83829088Smarkm cio->status = PCI_GETCONF_LAST_DEVICE; 83929088Smarkm else 84029088Smarkm cio->status = PCI_GETCONF_MORE_DEVS; 84129088Smarkm 84229088Smarkm if (pattern_buf != NULL) 84329088Smarkm free(pattern_buf, M_TEMP); 84429088Smarkm 84529088Smarkm break; 84629088Smarkm } 84729088Smarkm case PCIOCREAD: 84829088Smarkm io = (struct pci_io *)data; 84929088Smarkm switch(io->pi_width) { 85029088Smarkm pcicfgregs probe; 85129088Smarkm case 4: 85229088Smarkm case 2: 85329088Smarkm case 1: 85429088Smarkm probe.bus = io->pi_sel.pc_bus; 85529088Smarkm probe.slot = io->pi_sel.pc_dev; 85629088Smarkm probe.func = io->pi_sel.pc_func; 85729088Smarkm io->pi_data = pci_cfgread(&probe, 85829088Smarkm io->pi_reg, io->pi_width); 85929088Smarkm error = 0; 86029088Smarkm break; 86129088Smarkm default: 86229088Smarkm error = ENODEV; 86329088Smarkm break; 86429088Smarkm } 86529088Smarkm break; 86629088Smarkm 86729088Smarkm case PCIOCWRITE: 86829088Smarkm io = (struct pci_io *)data; 86929088Smarkm switch(io->pi_width) { 87029088Smarkm pcicfgregs probe; 87129088Smarkm case 4: 87229088Smarkm case 2: 87329088Smarkm case 1: 87429088Smarkm probe.bus = io->pi_sel.pc_bus; 87529088Smarkm probe.slot = io->pi_sel.pc_dev; 87629088Smarkm probe.func = io->pi_sel.pc_func; 87729088Smarkm pci_cfgwrite(&probe, 87829088Smarkm io->pi_reg, io->pi_data, io->pi_width); 87929088Smarkm error = 0; 88029088Smarkm break; 88129088Smarkm default: 88229088Smarkm error = ENODEV; 88329088Smarkm break; 88429088Smarkm } 88529088Smarkm break; 88629088Smarkm 88729088Smarkm default: 88829088Smarkm error = ENOTTY; 88929088Smarkm break; 89029088Smarkm } 89129088Smarkm 89229088Smarkm return (error); 89329088Smarkm} 89429088Smarkm 89529088Smarkm#define PCI_CDEV 78 89629088Smarkm 89729088Smarkmstatic struct cdevsw pcicdev = { 89829088Smarkm /* open */ pci_open, 89929088Smarkm /* close */ pci_close, 90029088Smarkm /* read */ noread, 90129088Smarkm /* write */ nowrite, 90229088Smarkm /* ioctl */ pci_ioctl, 90329088Smarkm /* stop */ nostop, 90429088Smarkm /* reset */ noreset, 90529088Smarkm /* devtotty */ nodevtotty, 90629088Smarkm /* poll */ nopoll, 90729088Smarkm /* mmap */ nommap, 90829088Smarkm /* strategy */ nostrategy, 90929088Smarkm /* name */ "pci", 91029088Smarkm /* parms */ noparms, 91129088Smarkm /* maj */ PCI_CDEV, 91229088Smarkm /* dump */ nodump, 91329088Smarkm /* psize */ nopsize, 91429088Smarkm /* flags */ 0, 91529088Smarkm /* maxio */ 0, 91629088Smarkm /* bmaj */ -1 91729088Smarkm}; 91829088Smarkm 91929088Smarkm#ifdef DEVFS 92029088Smarkmstatic void *pci_devfs_token; 92129088Smarkm#endif 92229088Smarkm 92329088Smarkmstatic void 92429088Smarkmpci_cdevinit(void *dummy) 92529088Smarkm{ 92629088Smarkm cdevsw_add(&pcicdev); 92729088Smarkm#ifdef DEVFS 92829088Smarkm pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR, 92929088Smarkm UID_ROOT, GID_WHEEL, 0644, "pci"); 93029088Smarkm#endif 93129088Smarkm} 93229088Smarkm 93329088SmarkmSYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL); 93429088Smarkm 93529088Smarkm#include "pci_if.h" 93629088Smarkm 93729088Smarkm/* 93829088Smarkm * A simple driver to wrap the old pci driver mechanism for back-compat. 93929088Smarkm */ 94029088Smarkm 94129088Smarkmstatic int 94229088Smarkmpci_compat_probe(device_t dev) 94329088Smarkm{ 94429088Smarkm struct pci_device *dvp; 94529088Smarkm struct pci_devinfo *dinfo; 94629088Smarkm pcicfgregs *cfg; 94729088Smarkm const char *name; 94829088Smarkm int error; 94929088Smarkm 95029088Smarkm dinfo = device_get_ivars(dev); 95129088Smarkm cfg = &dinfo->cfg; 95229088Smarkm dvp = device_get_driver(dev)->priv; 95329088Smarkm 95429088Smarkm /* 95529088Smarkm * Do the wrapped probe. 95629088Smarkm */ 95729088Smarkm error = ENXIO; 95829088Smarkm if (dvp && dvp->pd_probe) { 95929088Smarkm name = dvp->pd_probe(cfg, (cfg->device << 16) + cfg->vendor); 96029088Smarkm if (name) { 96129088Smarkm device_set_desc_copy(dev, name); 96229088Smarkm error = 0; 96329088Smarkm } 96429088Smarkm } 96529088Smarkm 96629088Smarkm return error; 96729088Smarkm} 96829088Smarkm 96929088Smarkmstatic int 97029088Smarkmpci_compat_attach(device_t dev) 97129088Smarkm{ 97229088Smarkm struct pci_device *dvp; 97329088Smarkm struct pci_devinfo *dinfo; 97429088Smarkm pcicfgregs *cfg; 97529088Smarkm int unit; 97629088Smarkm 97729088Smarkm dinfo = device_get_ivars(dev); 97829088Smarkm cfg = &dinfo->cfg; 97929088Smarkm dvp = device_get_driver(dev)->priv; 98029088Smarkm 98129088Smarkm unit = device_get_unit(dev); 98229088Smarkm if (unit > *dvp->pd_count) 98329088Smarkm *dvp->pd_count = unit; 98429088Smarkm if (dvp->pd_attach) 98529088Smarkm dvp->pd_attach(cfg, unit); 98629088Smarkm return 0; 98729088Smarkm} 98829088Smarkm 98929088Smarkmstatic device_method_t pci_compat_methods[] = { 99029088Smarkm /* Device interface */ 99129088Smarkm DEVMETHOD(device_probe, pci_compat_probe), 99229088Smarkm DEVMETHOD(device_attach, pci_compat_attach), 99329088Smarkm 99429088Smarkm { 0, 0 } 99529088Smarkm}; 99629088Smarkm 99729088Smarkmstatic devclass_t pci_devclass; 99829088Smarkm 99929088Smarkm/* 100029088Smarkm * Create a new style driver around each old pci driver. 100129088Smarkm */ 100229088Smarkmint 100329088Smarkmcompat_pci_handler(module_t mod, int type, void *data) 100429088Smarkm{ 100529088Smarkm struct pci_device *dvp = (struct pci_device *)data; 100629088Smarkm driver_t *driver; 100729088Smarkm 100829088Smarkm switch (type) { 100929088Smarkm case MOD_LOAD: 101029088Smarkm driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT); 101129088Smarkm if (!driver) 101229088Smarkm return ENOMEM; 101329088Smarkm bzero(driver, sizeof(driver_t)); 101429088Smarkm driver->name = dvp->pd_name; 101529088Smarkm driver->methods = pci_compat_methods; 101629088Smarkm driver->softc = sizeof(struct pci_devinfo *); 101729088Smarkm driver->priv = dvp; 101829088Smarkm devclass_add_driver(pci_devclass, driver); 101929088Smarkm break; 102029088Smarkm case MOD_UNLOAD: 102129088Smarkm printf("%s: module unload not supported!\n", dvp->pd_name); 102229088Smarkm return EOPNOTSUPP; 102329088Smarkm default: 102429088Smarkm break; 102529088Smarkm } 102629088Smarkm return 0; 102729088Smarkm} 102829088Smarkm 102929088Smarkm/* 103029088Smarkm * New style pci driver. Parent device is either a pci-host-bridge or a 103129088Smarkm * pci-pci-bridge. Both kinds are represented by instances of pcib. 103229088Smarkm */ 103329088Smarkm 103429088Smarkmstatic void 103529088Smarkmpci_print_verbose(struct pci_devinfo *dinfo) 103629088Smarkm{ 103729088Smarkm if (bootverbose) { 103829088Smarkm int i; 103929088Smarkm pcicfgregs *cfg = &dinfo->cfg; 104029088Smarkm 104129088Smarkm printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", 104229088Smarkm cfg->vendor, cfg->device, cfg->revid); 104329088Smarkm printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", 104429088Smarkm cfg->baseclass, cfg->subclass, cfg->progif, 104529088Smarkm cfg->hdrtype, cfg->mfdev); 104629088Smarkm printf("\tsubordinatebus=%x \tsecondarybus=%x\n", 104729088Smarkm cfg->subordinatebus, cfg->secondarybus); 104829088Smarkm#ifdef PCI_DEBUG 104929088Smarkm printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", 105029088Smarkm cfg->cmdreg, cfg->statreg, cfg->cachelnsz); 105129088Smarkm printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", 105229088Smarkm cfg->lattimer, cfg->lattimer * 30, 105329088Smarkm cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); 105429088Smarkm#endif /* PCI_DEBUG */ 105529088Smarkm if (cfg->intpin > 0) 105629088Smarkm printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); 105729088Smarkm 105829088Smarkm for (i = 0; i < cfg->nummaps; i++) { 105929088Smarkm pcimap *m = &cfg->map[i]; 106029088Smarkm printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n", 106129088Smarkm i, m->type, m->ln2range, m->base, m->ln2size); 106229088Smarkm } 106329088Smarkm } 106429088Smarkm} 106529088Smarkm 106629088Smarkmstatic int 106729088Smarkmpci_add_children(device_t dev, int busno) 106829088Smarkm{ 106929088Smarkm pcicfgregs probe; 107029088Smarkm int bushigh = busno; 107129088Smarkm 107229088Smarkm#ifdef SIMOS 107329088Smarkm#undef PCI_SLOTMAX 107429088Smarkm#define PCI_SLOTMAX 0 107529088Smarkm#endif 107629088Smarkm 107729088Smarkm bzero(&probe, sizeof probe); 107829088Smarkm#ifdef __alpha__ 107929088Smarkm probe.hose = pcib_get_hose(dev); 108029088Smarkm#endif 108129088Smarkm#ifdef __i386__ 108229088Smarkm probe.hose = 0; 108329088Smarkm#endif 108429088Smarkm probe.bus = busno; 108529088Smarkm 108629088Smarkm for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { 108729088Smarkm int pcifunchigh = 0; 108829088Smarkm for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) { 108929088Smarkm struct pci_devinfo *dinfo = pci_readcfg(&probe); 109029088Smarkm if (dinfo != NULL) { 109129088Smarkm if (dinfo->cfg.mfdev) 109229088Smarkm pcifunchigh = 7; 109329088Smarkm 109429088Smarkm pci_print_verbose(dinfo); 109529088Smarkm dinfo->cfg.dev = 109629088Smarkm device_add_child(dev, NULL, -1, dinfo); 109729088Smarkm 109829088Smarkm if (bushigh < dinfo->cfg.subordinatebus) 109929088Smarkm bushigh = dinfo->cfg.subordinatebus; 110029088Smarkm if (bushigh < dinfo->cfg.secondarybus) 110129088Smarkm bushigh = dinfo->cfg.secondarybus; 110229088Smarkm } 110329088Smarkm } 110429088Smarkm } 110529088Smarkm 110629088Smarkm return bushigh; 110729088Smarkm} 110829088Smarkm 110929088Smarkmstatic int 111029088Smarkmpci_new_probe(device_t dev) 111129088Smarkm{ 111229088Smarkm device_set_desc(dev, "PCI bus"); 111329088Smarkm 111429088Smarkm pci_add_children(dev, device_get_unit(dev)); 111529088Smarkm 111629088Smarkm return 0; 111729088Smarkm} 111829088Smarkm 111929088Smarkmstatic void 112029088Smarkmpci_print_child(device_t dev, device_t child) 112129088Smarkm{ 112229088Smarkm struct pci_devinfo *dinfo; 112329088Smarkm pcicfgregs *cfg; 112429088Smarkm 112529088Smarkm dinfo = device_get_ivars(child); 112629088Smarkm cfg = &dinfo->cfg; 112729088Smarkm if (cfg->intpin > 0 && cfg->intline != 255) 112829088Smarkm printf(" irq %d", cfg->intline); 112929088Smarkm printf(" at device %d.%d", pci_get_slot(child), pci_get_function(child)); 113029088Smarkm printf(" on %s%d", device_get_name(dev), device_get_unit(dev)); 113129088Smarkm} 113247973Sru 113329088Smarkmstatic void 113429088Smarkmpci_probe_nomatch(device_t dev, device_t child) 113529088Smarkm{ 113629088Smarkm struct pci_devinfo *dinfo; 113729088Smarkm pcicfgregs *cfg; 113829088Smarkm 113949861Snsayer dinfo = device_get_ivars(child); 114029088Smarkm cfg = &dinfo->cfg; 114129088Smarkm 114229088Smarkm device_printf(dev, "unknown card %c%c%c%04x (vendor=0x%04x, dev=0x%04x) at %d.$d", 114329088Smarkm PCI_MFCTR_CHAR0(cfg->vendor), 114429088Smarkm PCI_MFCTR_CHAR1(cfg->vendor), 114529088Smarkm PCI_MFCTR_CHAR2(cfg->vendor), 114629088Smarkm cfg->device, 114729088Smarkm cfg->vendor, 114829088Smarkm cfg->device, 114929088Smarkm pci_get_slot(child), 115029088Smarkm pci_get_function(child)); 115129088Smarkm if (cfg->intpin > 0 && cfg->intline != 255) { 115229088Smarkm printf(" irq %d", cfg->intline); 115329088Smarkm } 115429088Smarkm printf("\n"); 115529088Smarkm 115629088Smarkm return; 115729088Smarkm} 115829088Smarkm 115929088Smarkmstatic int 116029088Smarkmpci_read_ivar(device_t dev, device_t child, int which, u_long *result) 116129088Smarkm{ 116229088Smarkm struct pci_devinfo *dinfo; 116329088Smarkm pcicfgregs *cfg; 116429088Smarkm 116529088Smarkm dinfo = device_get_ivars(child); 116629088Smarkm cfg = &dinfo->cfg; 116729088Smarkm 116829088Smarkm switch (which) { 116929088Smarkm case PCI_IVAR_SUBVENDOR: 117029088Smarkm *result = cfg->subvendor; 117129088Smarkm break; 117229088Smarkm case PCI_IVAR_SUBDEVICE: 117329088Smarkm *result = cfg->subdevice; 117429088Smarkm break; 117529088Smarkm case PCI_IVAR_VENDOR: 117629088Smarkm *result = cfg->vendor; 117729088Smarkm break; 117829088Smarkm case PCI_IVAR_DEVICE: 117929088Smarkm *result = cfg->device; 118029088Smarkm break; 118129088Smarkm case PCI_IVAR_DEVID: 118229088Smarkm *result = (cfg->device << 16) | cfg->vendor; 118329088Smarkm break; 118429088Smarkm case PCI_IVAR_CLASS: 118529088Smarkm *result = cfg->baseclass; 118629088Smarkm break; 118729088Smarkm case PCI_IVAR_SUBCLASS: 118829088Smarkm *result = cfg->subclass; 118929088Smarkm break; 119029181Smarkm case PCI_IVAR_PROGIF: 119129088Smarkm *result = cfg->progif; 119229088Smarkm break; 119329088Smarkm case PCI_IVAR_REVID: 119429088Smarkm *result = cfg->revid; 119529088Smarkm break; 119629088Smarkm case PCI_IVAR_INTPIN: 119729088Smarkm *result = cfg->intpin; 119829088Smarkm break; 119929088Smarkm case PCI_IVAR_IRQ: 120029088Smarkm *result = cfg->intline; 120129088Smarkm break; 120229088Smarkm case PCI_IVAR_BUS: 120329088Smarkm *result = cfg->bus; 120429088Smarkm break; 120529088Smarkm case PCI_IVAR_SLOT: 120629088Smarkm *result = cfg->slot; 120729088Smarkm break; 120829088Smarkm case PCI_IVAR_FUNCTION: 120929088Smarkm *result = cfg->func; 121029088Smarkm break; 121129088Smarkm case PCI_IVAR_SECONDARYBUS: 121229088Smarkm *result = cfg->secondarybus; 121329088Smarkm break; 121429088Smarkm case PCI_IVAR_SUBORDINATEBUS: 121529088Smarkm *result = cfg->subordinatebus; 121629088Smarkm break; 121729088Smarkm case PCI_IVAR_HOSE: 121829088Smarkm /* 121929088Smarkm * Pass up to parent bridge. 122029088Smarkm */ 122129088Smarkm *result = pcib_get_hose(dev); 122229181Smarkm break; 122329181Smarkm default: 122429088Smarkm return ENOENT; 122529181Smarkm } 122629181Smarkm return 0; 122729088Smarkm} 122829181Smarkm 122929181Smarkmstatic int 123029088Smarkmpci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 123129181Smarkm{ 123229181Smarkm struct pci_devinfo *dinfo; 123329088Smarkm pcicfgregs *cfg; 123429088Smarkm 123529088Smarkm dinfo = device_get_ivars(child); 123629088Smarkm cfg = &dinfo->cfg; 123729088Smarkm 123829088Smarkm switch (which) { 123929088Smarkm case PCI_IVAR_SUBVENDOR: 124029088Smarkm case PCI_IVAR_SUBDEVICE: 124129088Smarkm case PCI_IVAR_VENDOR: 124229088Smarkm case PCI_IVAR_DEVICE: 124329088Smarkm case PCI_IVAR_DEVID: 124429088Smarkm case PCI_IVAR_CLASS: 124529088Smarkm case PCI_IVAR_SUBCLASS: 124629088Smarkm case PCI_IVAR_PROGIF: 124729088Smarkm case PCI_IVAR_REVID: 124829088Smarkm case PCI_IVAR_INTPIN: 124929088Smarkm case PCI_IVAR_IRQ: 125029088Smarkm case PCI_IVAR_BUS: 125129088Smarkm case PCI_IVAR_SLOT: 125229088Smarkm case PCI_IVAR_FUNCTION: 125329088Smarkm return EINVAL; /* disallow for now */ 125429088Smarkm 125529088Smarkm case PCI_IVAR_SECONDARYBUS: 125629088Smarkm cfg->secondarybus = value; 125729088Smarkm break; 125829088Smarkm case PCI_IVAR_SUBORDINATEBUS: 125929088Smarkm cfg->subordinatebus = value; 126029088Smarkm break; 126129088Smarkm default: 126229088Smarkm return ENOENT; 126329088Smarkm } 126429088Smarkm return 0; 126529088Smarkm} 126629088Smarkm 126729088Smarkmstatic int 126829088Smarkmpci_mapno(pcicfgregs *cfg, int reg) 126929088Smarkm{ 127029088Smarkm int i, nummaps; 127129088Smarkm pcimap *map; 127229088Smarkm 127329088Smarkm nummaps = cfg->nummaps; 127429088Smarkm map = cfg->map; 127529088Smarkm 127629088Smarkm for (i = 0; i < nummaps; i++) 127729088Smarkm if (map[i].reg == reg) 127829088Smarkm return (i); 127929088Smarkm return (-1); 128029088Smarkm} 128129088Smarkm 128229088Smarkmstatic int 128329088Smarkmpci_porten(pcicfgregs *cfg) 128429088Smarkm{ 128529088Smarkm return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); 128629088Smarkm} 128729088Smarkm 128829088Smarkmstatic int 128929088Smarkmpci_isportmap(pcicfgregs *cfg, int map) 129029088Smarkm 129129088Smarkm{ 129229088Smarkm return ((unsigned)map < cfg->nummaps 129329088Smarkm && (cfg->map[map].type & PCI_MAPPORT) != 0); 129429088Smarkm} 129529088Smarkm 129629088Smarkmstatic int 129729088Smarkmpci_memen(pcicfgregs *cfg) 129829088Smarkm{ 129929088Smarkm return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); 130029088Smarkm} 130129088Smarkm 130229088Smarkmstatic int 130329088Smarkmpci_ismemmap(pcicfgregs *cfg, int map) 130429088Smarkm{ 130529088Smarkm return ((unsigned)map < cfg->nummaps 130629088Smarkm && (cfg->map[map].type & PCI_MAPMEM) != 0); 130729088Smarkm} 130829088Smarkm 130929088Smarkmstatic struct resource * 131029088Smarkmpci_alloc_resource(device_t dev, device_t child, int type, int *rid, 131129088Smarkm u_long start, u_long end, u_long count, u_int flags) 131229088Smarkm{ 131329088Smarkm int isdefault; 131429088Smarkm struct pci_devinfo *dinfo = device_get_ivars(child); 131529088Smarkm pcicfgregs *cfg = &dinfo->cfg; 131629088Smarkm struct resource *rv, **rvp = 0; 131729088Smarkm int map; 131829088Smarkm 131929088Smarkm isdefault = (device_get_parent(child) == dev 132029088Smarkm && start == 0UL && end == ~0UL); 132129088Smarkm 132229088Smarkm switch (type) { 132329088Smarkm case SYS_RES_IRQ: 132429088Smarkm if (*rid != 0) 132529088Smarkm return 0; 132629088Smarkm if (isdefault && cfg->intline != 255) { 132729088Smarkm start = cfg->intline; 132829088Smarkm end = cfg->intline; 132929088Smarkm count = 1; 133029088Smarkm } 133129088Smarkm break; 133229088Smarkm 133329088Smarkm case SYS_RES_DRQ: /* passthru for child isa */ 133429088Smarkm break; 133529088Smarkm 133629088Smarkm case SYS_RES_MEMORY: 133729088Smarkm if (isdefault) { 133829088Smarkm map = pci_mapno(cfg, *rid); 133929088Smarkm if (pci_memen(cfg) && pci_ismemmap(cfg, map)) { 134029088Smarkm start = cfg->map[map].base; 134129088Smarkm count = 1 << cfg->map[map].ln2size; 134229088Smarkm end = start + count; 134329088Smarkm rvp = &cfg->map[map].res; 134429088Smarkm } else 134529088Smarkm return 0; 134629088Smarkm } 134729088Smarkm break; 134829088Smarkm 134929088Smarkm case SYS_RES_IOPORT: 135029088Smarkm if (isdefault) { 135129088Smarkm map = pci_mapno(cfg, *rid); 135229088Smarkm if (pci_porten(cfg) && pci_isportmap(cfg, map)) { 135329088Smarkm start = cfg->map[map].base; 135429088Smarkm count = 1 << cfg->map[map].ln2size; 135529088Smarkm end = start + count; 135629088Smarkm rvp = &cfg->map[map].res; 135729088Smarkm } else 135829088Smarkm return 0; 135929088Smarkm } 136029088Smarkm break; 136129088Smarkm 136229088Smarkm default: 136329088Smarkm return 0; 136429088Smarkm } 136529088Smarkm 136629088Smarkm rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 136729088Smarkm type, rid, start, end, count, flags); 136829088Smarkm if (rvp) 136929088Smarkm *rvp = rv; 137029088Smarkm 137129088Smarkm return rv; 137229088Smarkm} 137329088Smarkm 137429088Smarkmstatic int 137529088Smarkmpci_release_resource(device_t dev, device_t child, int type, int rid, 137629088Smarkm struct resource *r) 137729088Smarkm{ 137829088Smarkm int rv; 137929088Smarkm struct pci_devinfo *dinfo = device_get_ivars(child); 138029088Smarkm pcicfgregs *cfg = &dinfo->cfg; 138129088Smarkm int map = 0; 138229088Smarkm 138329088Smarkm switch (type) { 138429088Smarkm case SYS_RES_IRQ: 138529088Smarkm if (rid != 0) 138629088Smarkm return EINVAL; 138729088Smarkm break; 138829088Smarkm 138929088Smarkm case SYS_RES_DRQ: /* passthru for child isa */ 139029088Smarkm break; 139129088Smarkm 139229088Smarkm case SYS_RES_MEMORY: 139329088Smarkm case SYS_RES_IOPORT: 139429088Smarkm /* 139529088Smarkm * Only check the map registers if this is a direct 139629088Smarkm * descendant. 139729088Smarkm */ 139829088Smarkm if (device_get_parent(child) == dev) 139929088Smarkm map = pci_mapno(cfg, rid); 140029088Smarkm else 140129088Smarkm map = -1; 140229088Smarkm break; 140329088Smarkm 140429088Smarkm default: 140529088Smarkm return (ENOENT); 140629088Smarkm } 140729088Smarkm 140829088Smarkm rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); 140929088Smarkm 141029088Smarkm if (rv == 0) { 141129088Smarkm switch (type) { 141229088Smarkm case SYS_RES_IRQ: 141329088Smarkm cfg->irqres = 0; 141429088Smarkm break; 141529088Smarkm 141629088Smarkm case SYS_RES_DRQ: /* passthru for child isa */ 141729088Smarkm break; 141829088Smarkm 141929088Smarkm case SYS_RES_MEMORY: 142029088Smarkm case SYS_RES_IOPORT: 142129088Smarkm if (map != -1) 142229088Smarkm cfg->map[map].res = 0; 142329088Smarkm break; 142429088Smarkm 142529088Smarkm default: 142629088Smarkm return ENOENT; 142729088Smarkm } 142829088Smarkm } 142929088Smarkm 143029088Smarkm return rv; 143129088Smarkm} 143229088Smarkm 143329088Smarkmstatic u_int32_t 143429088Smarkmpci_read_config_method(device_t dev, device_t child, int reg, int width) 143529088Smarkm{ 143629088Smarkm struct pci_devinfo *dinfo = device_get_ivars(child); 143729088Smarkm pcicfgregs *cfg = &dinfo->cfg; 143829088Smarkm return pci_cfgread(cfg, reg, width); 143929088Smarkm} 144029088Smarkm 144129088Smarkmstatic void 144229088Smarkmpci_write_config_method(device_t dev, device_t child, int reg, 144329088Smarkm u_int32_t val, int width) 144429088Smarkm{ 144529088Smarkm struct pci_devinfo *dinfo = device_get_ivars(child); 144629088Smarkm pcicfgregs *cfg = &dinfo->cfg; 144729088Smarkm pci_cfgwrite(cfg, reg, val, width); 144829088Smarkm} 144929088Smarkm 145029088Smarkmstatic int 145129088Smarkmpci_modevent(module_t mod, int what, void *arg) 145229088Smarkm{ 145329088Smarkm switch (what) { 145429088Smarkm case MOD_LOAD: 145529088Smarkm STAILQ_INIT(&pci_devq); 145629088Smarkm break; 145729088Smarkm 145829088Smarkm case MOD_UNLOAD: 145929088Smarkm break; 146029088Smarkm } 146129088Smarkm 146229088Smarkm return 0; 146329088Smarkm} 146429088Smarkm 146529088Smarkmstatic device_method_t pci_methods[] = { 146629088Smarkm /* Device interface */ 146729088Smarkm DEVMETHOD(device_probe, pci_new_probe), 146829088Smarkm DEVMETHOD(device_attach, bus_generic_attach), 146929088Smarkm DEVMETHOD(device_shutdown, bus_generic_shutdown), 147029088Smarkm DEVMETHOD(device_suspend, bus_generic_suspend), 147129088Smarkm DEVMETHOD(device_resume, bus_generic_resume), 147229088Smarkm 147329088Smarkm /* Bus interface */ 147429088Smarkm DEVMETHOD(bus_print_child, pci_print_child), 147529088Smarkm DEvMETHOD(bus_probe_nomatch, pci_probe_nomatch), 147629088Smarkm DEVMETHOD(bus_read_ivar, pci_read_ivar), 147729088Smarkm DEVMETHOD(bus_write_ivar, pci_write_ivar), 147829088Smarkm DEVMETHOD(bus_driver_added, bus_generic_driver_added), 147929088Smarkm DEVMETHOD(bus_alloc_resource, pci_alloc_resource), 148029088Smarkm DEVMETHOD(bus_release_resource, pci_release_resource), 148129088Smarkm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 148229088Smarkm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 148329088Smarkm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 148429088Smarkm DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 148529088Smarkm 148629181Smarkm /* PCI interface */ 148729088Smarkm DEVMETHOD(pci_read_config, pci_read_config_method), 148829088Smarkm DEVMETHOD(pci_write_config, pci_write_config_method), 148929088Smarkm 149029088Smarkm { 0, 0 } 149129088Smarkm}; 149229088Smarkm 149329088Smarkmstatic driver_t pci_driver = { 149429088Smarkm "pci", 149529088Smarkm pci_methods, 149629088Smarkm 1, /* no softc */ 149729088Smarkm}; 149829088Smarkm 149929088SmarkmDRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); 150029088Smarkm