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