summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c653
-rw-r--r--sys/dev/pci/pci_if.m44
-rw-r--r--sys/dev/pci/pcireg.h4
-rw-r--r--sys/dev/pci/pcivar.h79
4 files changed, 665 insertions, 115 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index e449fc25e50f..889550c9bc95 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -23,10 +23,12 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: pci.c,v 1.93 1999/01/19 23:29:18 se Exp $
+ * $Id: pci.c,v 1.94 1999/04/11 02:47:31 eivind Exp $
*
*/
+#include "opt_bus.h"
+
#include "pci.h"
#if NPCI > 0
@@ -50,6 +52,11 @@
#include <vm/pmap.h>
#include <vm/vm_extern.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#include <pci/pci_ioctl.h>
@@ -338,11 +345,10 @@ pci_readcfg(pcicfgregs *probe)
M_DEVBUF, M_WAITOK);
if (devlist_entry == NULL)
return (NULL);
+ bzero(devlist_entry, sizeof *devlist_entry);
cfg = &devlist_entry->cfg;
- bzero(cfg, sizeof *cfg);
-
cfg->bus = probe->bus;
cfg->slot = probe->slot;
cfg->func = probe->func;
@@ -450,113 +456,6 @@ pci_freecfg(struct pci_devinfo *dinfo)
}
#endif
-static void
-pci_addcfg(struct pci_devinfo *dinfo)
-{
- if (bootverbose) {
- int i;
- pcicfgregs *cfg = &dinfo->cfg;
-
- printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n",
- cfg->vendor, cfg->device, cfg->revid);
- printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n",
- cfg->baseclass, cfg->subclass, cfg->progif,
- cfg->hdrtype, cfg->mfdev);
- printf("\tsubordinatebus=%x \tsecondarybus=%x\n",
- cfg->subordinatebus, cfg->secondarybus);
-#ifdef PCI_DEBUG
- printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n",
- cfg->cmdreg, cfg->statreg, cfg->cachelnsz);
- printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n",
- cfg->lattimer, cfg->lattimer * 30,
- cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250);
-#endif /* PCI_DEBUG */
- if (cfg->intpin > 0)
- printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline);
-
- for (i = 0; i < cfg->nummaps; i++) {
- pcimap *m = &cfg->map[i];
- printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n",
- i, m->type, m->ln2range, m->base, m->ln2size);
- }
- }
- pci_drvattach(dinfo); /* XXX currently defined in pci_compat.c */
-}
-
-/* scan one PCI bus for devices */
-
-static int
-pci_probebus(int bus)
-{
- pcicfgregs probe;
- int bushigh = bus;
-
-#ifdef SIMOS
-#undef PCI_SLOTMAX
-#define PCI_SLOTMAX 0
-#endif
-
- bzero(&probe, sizeof probe);
- /* XXX KDM */
- /* probe.parent = pci_bridgeto(bus); */
- probe.bus = bus;
- for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
- int pcifunchigh = 0;
- for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) {
- struct pci_devinfo *dinfo = pci_readcfg(&probe);
- if (dinfo != NULL) {
- if (dinfo->cfg.mfdev)
- pcifunchigh = 7;
- /*
- * XXX: Temporarily move pci_addcfg() up before
- * the use of cfg->subordinatebus. This is
- * necessary, since pci_addcfg() calls the
- * device's probe(), which may read the bus#
- * from some device dependent register of
- * some host to PCI bridges. The probe will
- * eventually be moved to pci_readcfg(), and
- * pci_addcfg() will then be moved back down
- * below the conditional statement ...
- */
- pci_addcfg(dinfo);
-
- if (bushigh < dinfo->cfg.subordinatebus)
- bushigh = dinfo->cfg.subordinatebus;
- if (bushigh < dinfo->cfg.secondarybus)
- bushigh = dinfo->cfg.secondarybus;
-
- /* XXX KDM */
- /* cfg = NULL; we don't own this anymore ... */
- }
- }
- }
- return (bushigh);
-}
-
-/* scan a PCI bus tree reached through one PCI attachment point */
-
-int
-pci_probe(pciattach *parent)
-{
- int bushigh;
- int bus = 0;
-
- STAILQ_INIT(&pci_devq);
-
- bushigh = pci_bushigh();
- while (bus <= bushigh) {
- int newbushigh;
-
- printf("Probing for devices on PCI bus %d:\n", bus);
- newbushigh = pci_probebus(bus);
-
- if (bushigh < newbushigh)
- bushigh = newbushigh;
- bus++;
- }
- return (bushigh);
-}
-
/*
* This is the user interface to PCI configuration space.
*/
@@ -750,8 +649,8 @@ pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
"pci_match_conf) (%d)\npci_ioctl: "
"pat_buf_len should be = %d\n",
cio->pat_buf_len, cio->num_patterns,
- sizeof(struct pci_match_conf),
- sizeof(struct pci_match_conf) *
+ (int)sizeof(struct pci_match_conf),
+ (int)sizeof(struct pci_match_conf) *
cio->num_patterns);
printf("pci_ioctl: do your headers match your "
"kernel?\n");
@@ -945,4 +844,534 @@ pci_cdevinit(void *dummy)
SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL);
+#include "pci_if.h"
+
+/*
+ * A simple driver to wrap the old pci driver mechanism for back-compat.
+ */
+
+static int
+pci_compat_probe(device_t dev)
+{
+ struct pci_device *dvp;
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+ const char *name;
+ int error;
+
+ dinfo = device_get_ivars(dev);
+ cfg = &dinfo->cfg;
+ dvp = device_get_driver(dev)->priv;
+
+ /*
+ * Do the wrapped probe.
+ */
+ error = ENXIO;
+ if (dvp && dvp->pd_probe) {
+ name = dvp->pd_probe(cfg, (cfg->device << 16) + cfg->vendor);
+ if (name) {
+ device_set_desc_copy(dev, name);
+ error = 0;
+ }
+ }
+
+ return error;
+}
+
+static int
+pci_compat_attach(device_t dev)
+{
+ struct pci_device *dvp;
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+ int unit;
+
+ dinfo = device_get_ivars(dev);
+ cfg = &dinfo->cfg;
+ dvp = device_get_driver(dev)->priv;
+
+ unit = device_get_unit(dev);
+ if (unit > *dvp->pd_count)
+ *dvp->pd_count = unit;
+ if (dvp->pd_attach)
+ dvp->pd_attach(cfg, unit);
+
+ /*
+ * XXX KDM for some devices, dvp->pd_name winds up NULL.
+ * I haven't investigated enough to figure out why this
+ * would happen.
+ */
+ if (dvp->pd_name != NULL)
+ strncpy(dinfo->conf.pd_name, dvp->pd_name,
+ sizeof(dinfo->conf.pd_name));
+ else
+ strncpy(dinfo->conf.pd_name, "????",
+ sizeof(dinfo->conf.pd_name));
+ dinfo->conf.pd_name[sizeof(dinfo->conf.pd_name) - 1] = 0;
+ dinfo->conf.pd_unit = unit;
+
+ return 0;
+}
+
+static device_method_t pci_compat_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pci_compat_probe),
+ DEVMETHOD(device_attach, pci_compat_attach),
+
+ { 0, 0 }
+};
+
+static devclass_t pci_devclass;
+
+/*
+ * Create a new style driver around each old pci driver.
+ */
+static void
+pci_wrap_old_drivers(void)
+{
+ struct pci_device **dvpp, *dvp;
+
+ dvpp = (struct pci_device **)pcidevice_set.ls_items;
+ while ((dvp = *dvpp++) != NULL) {
+ driver_t *driver;
+ driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT);
+ if (!driver)
+ continue;
+ bzero(driver, sizeof(driver_t));
+ driver->name = dvp->pd_name;
+ driver->methods = pci_compat_methods;
+ driver->type = 0; /* XXX fixup in pci_map_int() */
+ driver->softc = sizeof(struct pci_devinfo *);
+ driver->priv = dvp;
+ devclass_add_driver(pci_devclass, driver);
+ }
+}
+
+/*
+ * New style pci driver. Parent device is either a pci-host-bridge or a
+ * pci-pci-bridge. Both kinds are represented by instances of pcib.
+ */
+
+static void
+pci_print_verbose(struct pci_devinfo *dinfo)
+{
+ if (bootverbose) {
+ int i;
+ pcicfgregs *cfg = &dinfo->cfg;
+
+ printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n",
+ cfg->vendor, cfg->device, cfg->revid);
+ printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n",
+ cfg->baseclass, cfg->subclass, cfg->progif,
+ cfg->hdrtype, cfg->mfdev);
+ printf("\tsubordinatebus=%x \tsecondarybus=%x\n",
+ cfg->subordinatebus, cfg->secondarybus);
+#ifdef PCI_DEBUG
+ printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n",
+ cfg->cmdreg, cfg->statreg, cfg->cachelnsz);
+ printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n",
+ cfg->lattimer, cfg->lattimer * 30,
+ cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250);
+#endif /* PCI_DEBUG */
+ if (cfg->intpin > 0)
+ printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline);
+
+ for (i = 0; i < cfg->nummaps; i++) {
+ pcimap *m = &cfg->map[i];
+ printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n",
+ i, m->type, m->ln2range, m->base, m->ln2size);
+ }
+ }
+}
+
+static int
+pci_add_children(device_t dev, int busno)
+{
+ pcicfgregs probe;
+ int bushigh = busno;
+
+#ifdef SIMOS
+#undef PCI_SLOTMAX
+#define PCI_SLOTMAX 0
+#endif
+
+ bzero(&probe, sizeof probe);
+ /* XXX KDM */
+ /* probe.parent = pci_bridgeto(bus); */
+ probe.bus = busno;
+ for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
+ int pcifunchigh = 0;
+ for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) {
+ struct pci_devinfo *dinfo = pci_readcfg(&probe);
+ if (dinfo != NULL) {
+ if (dinfo->cfg.mfdev)
+ pcifunchigh = 7;
+
+ pci_print_verbose(dinfo);
+ dinfo->cfg.dev =
+ device_add_child(dev, NULL, -1, dinfo);
+
+ if (bushigh < dinfo->cfg.subordinatebus)
+ bushigh = dinfo->cfg.subordinatebus;
+ if (bushigh < dinfo->cfg.secondarybus)
+ bushigh = dinfo->cfg.secondarybus;
+ }
+ }
+ }
+
+ return bushigh;
+}
+
+static int
+pci_new_probe(device_t dev)
+{
+ STAILQ_INIT(&pci_devq);
+ device_set_desc(dev, "PCI bus");
+
+ pci_add_children(dev, device_get_unit(dev));
+
+ return 0;
+}
+
+static void
+pci_print_child(device_t dev, device_t child)
+{
+ printf(" at device %d.%d", pci_get_slot(child), pci_get_function(child));
+ printf(" on %s%d", device_get_name(dev), device_get_unit(dev));
+}
+
+static int
+pci_read_ivar(device_t dev, device_t child, int which, u_long *result)
+{
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+
+ dinfo = device_get_ivars(child);
+ cfg = &dinfo->cfg;
+
+ switch (which) {
+ case PCI_IVAR_SUBVENDOR:
+ *result = cfg->subvendor;
+ break;
+ case PCI_IVAR_SUBDEVICE:
+ *result = cfg->subdevice;
+ break;
+ case PCI_IVAR_VENDOR:
+ *result = cfg->vendor;
+ break;
+ case PCI_IVAR_DEVICE:
+ *result = cfg->device;
+ break;
+ case PCI_IVAR_DEVID:
+ *result = (cfg->device << 16) | cfg->vendor;
+ break;
+ case PCI_IVAR_CLASS:
+ *result = cfg->baseclass;
+ break;
+ case PCI_IVAR_SUBCLASS:
+ *result = cfg->subclass;
+ break;
+ case PCI_IVAR_PROGIF:
+ *result = cfg->progif;
+ break;
+ case PCI_IVAR_REVID:
+ *result = cfg->revid;
+ break;
+ case PCI_IVAR_INTPIN:
+ *result = cfg->intpin;
+ break;
+ case PCI_IVAR_IRQ:
+ *result = cfg->intline;
+ break;
+ case PCI_IVAR_BUS:
+ *result = cfg->bus;
+ break;
+ case PCI_IVAR_SLOT:
+ *result = cfg->slot;
+ break;
+ case PCI_IVAR_FUNCTION:
+ *result = cfg->func;
+ break;
+ case PCI_IVAR_SECONDARYBUS:
+ *result = cfg->secondarybus;
+ break;
+ case PCI_IVAR_SUBORDINATEBUS:
+ *result = cfg->subordinatebus;
+ break;
+ default:
+ return ENOENT;
+ }
+ return 0;
+}
+
+static int
+pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+
+ dinfo = device_get_ivars(child);
+ cfg = &dinfo->cfg;
+
+ switch (which) {
+ case PCI_IVAR_SUBVENDOR:
+ case PCI_IVAR_SUBDEVICE:
+ case PCI_IVAR_VENDOR:
+ case PCI_IVAR_DEVICE:
+ case PCI_IVAR_DEVID:
+ case PCI_IVAR_CLASS:
+ case PCI_IVAR_SUBCLASS:
+ case PCI_IVAR_PROGIF:
+ case PCI_IVAR_REVID:
+ case PCI_IVAR_INTPIN:
+ case PCI_IVAR_IRQ:
+ case PCI_IVAR_BUS:
+ case PCI_IVAR_SLOT:
+ case PCI_IVAR_FUNCTION:
+ return EINVAL; /* disallow for now */
+
+ case PCI_IVAR_SECONDARYBUS:
+ cfg->secondarybus = value;
+ break;
+ case PCI_IVAR_SUBORDINATEBUS:
+ cfg->subordinatebus = value;
+ break;
+ default:
+ return ENOENT;
+ }
+ return 0;
+}
+
+static int
+pci_mapno(pcicfgregs *cfg, int reg)
+{
+ int i, nummaps;
+ pcimap *map;
+
+ nummaps = cfg->nummaps;
+ map = cfg->map;
+
+ for (i = 0; i < nummaps; i++)
+ if (map[i].reg == reg)
+ return (i);
+ return (-1);
+}
+
+static int
+pci_porten(pcicfgregs *cfg)
+{
+ return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0);
+}
+
+static int
+pci_isportmap(pcicfgregs *cfg, int map)
+
+{
+ return ((unsigned)map < cfg->nummaps
+ && (cfg->map[map].type & PCI_MAPPORT) != 0);
+}
+
+static int
+pci_memen(pcicfgregs *cfg)
+{
+ return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0);
+}
+
+static int
+pci_ismemmap(pcicfgregs *cfg, int map)
+{
+ return ((unsigned)map < cfg->nummaps
+ && (cfg->map[map].type & PCI_MAPMEM) != 0);
+}
+
+static struct resource *
+pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ int isdefault;
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->cfg;
+ struct resource *rv, **rvp = 0;
+ int map;
+
+ isdefault = (device_get_parent(child) == dev
+ && start == 0UL && end == ~0UL && count == 1);
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ if (*rid != 0)
+ return 0;
+ if (isdefault && cfg->intline != 255) {
+ start = cfg->intline;
+ end = cfg->intline;
+ count = 1;
+ }
+ break;
+
+ case SYS_RES_DRQ: /* passthru for child isa */
+ break;
+
+ case SYS_RES_MEMORY:
+ if (isdefault) {
+ map = pci_mapno(cfg, *rid);
+ if (pci_memen(cfg) && pci_ismemmap(cfg, map)) {
+ start = cfg->map[map].base;
+ count = 1 << cfg->map[map].ln2size;
+ end = start + count;
+ rvp = &cfg->map[map].res;
+ } else
+ return 0;
+ }
+ break;
+
+ case SYS_RES_IOPORT:
+ if (isdefault) {
+ map = pci_mapno(cfg, *rid);
+ if (pci_porten(cfg) && pci_isportmap(cfg, map)) {
+ start = cfg->map[map].base;
+ count = 1 << cfg->map[map].ln2size;
+ end = start + count;
+ rvp = &cfg->map[map].res;
+ } else
+ return 0;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ type, rid, start, end, count, flags);
+ if (rvp)
+ *rvp = rv;
+
+ return rv;
+}
+
+static int
+pci_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ int rv;
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->cfg;
+ int map = 0;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ if (rid != 0)
+ return EINVAL;
+ break;
+
+ case SYS_RES_DRQ: /* passthru for child isa */
+ break;
+
+ case SYS_RES_MEMORY:
+ case SYS_RES_IOPORT:
+ /*
+ * Only check the map registers if this is a direct
+ * descendant.
+ */
+ if (device_get_parent(child) == dev)
+ map = pci_mapno(cfg, rid);
+ else
+ map = -1;
+ break;
+
+ default:
+ return (ENOENT);
+ }
+
+ rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
+
+ if (rv == 0) {
+ switch (type) {
+ case SYS_RES_IRQ:
+ cfg->irqres = 0;
+ break;
+
+ case SYS_RES_DRQ: /* passthru for child isa */
+ break;
+
+ case SYS_RES_MEMORY:
+ case SYS_RES_IOPORT:
+ if (map != -1)
+ cfg->map[map].res = 0;
+ break;
+
+ default:
+ return ENOENT;
+ }
+ }
+
+ return rv;
+}
+
+static u_int32_t
+pci_read_config_method(device_t dev, device_t child, int reg, int width)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->cfg;
+ return pci_cfgread(cfg, reg, width);
+}
+
+static void
+pci_write_config_method(device_t dev, device_t child, int reg,
+ u_int32_t val, int width)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->cfg;
+ pci_cfgwrite(cfg, reg, val, width);
+}
+
+static int
+pci_modevent(module_t mod, int what, void *arg)
+{
+ switch (what) {
+ case MOD_LOAD:
+ pci_wrap_old_drivers();
+ break;
+
+ case MOD_UNLOAD:
+ break;
+ }
+
+ return 0;
+}
+
+static device_method_t pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pci_new_probe),
+ DEVMETHOD(device_attach, bus_generic_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, pci_print_child),
+ DEVMETHOD(bus_read_ivar, pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, pci_write_ivar),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, pci_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ /* PCI interface */
+ DEVMETHOD(pci_read_config, pci_read_config_method),
+ DEVMETHOD(pci_write_config, pci_write_config_method),
+
+ { 0, 0 }
+};
+
+static driver_t pci_driver = {
+ "pci",
+ pci_methods,
+ DRIVER_TYPE_MISC,
+ 1, /* no softc */
+};
+
+DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
+
#endif /* NPCI > 0 */
diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m
new file mode 100644
index 000000000000..b2fa6758fef6
--- /dev/null
+++ b/sys/dev/pci/pci_if.m
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 1998 Doug Rabson
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $Id$
+#
+
+INTERFACE pci;
+
+METHOD u_int32_t read_config {
+ device_t dev;
+ device_t child;
+ int reg;
+ int width;
+};
+
+METHOD void write_config {
+ device_t dev;
+ device_t child;
+ int reg;
+ u_int32_t val;
+ int width;
+};
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index 0adb5404021e..9c0dba09331d 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -26,7 +26,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: pcireg.h,v 1.19 1997/09/20 07:41:58 dyson Exp $
+ * $Id: pcireg.h,v 1.20 1998/10/07 03:40:51 gibbs Exp $
*
*/
@@ -173,7 +173,7 @@
#define PCIS_MEMORY_OTHER 0x80
#define PCIC_BRIDGE 0x06
-#define PCIS_BRDIGE_HOST 0x00
+#define PCIS_BRIDGE_HOST 0x00
#define PCIS_BRIDGE_ISA 0x01
#define PCIS_BRIDGE_EISA 0x02
#define PCIS_BRIDGE_MCA 0x03
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 7843e3a6d656..55f72a16b875 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: pcivar.h,v 1.24 1999/01/13 04:59:19 bde Exp $
+ * $Id: pcivar.h,v 1.25 1999/01/19 23:29:20 se Exp $
*
*/
@@ -67,13 +67,17 @@ typedef struct {
u_int8_t ln2size;
u_int8_t ln2range;
u_int8_t reg; /* offset of map register in config space */
+/* u_int8_t dummy;*/
+ struct resource *res; /* handle from resource manager */
} pcimap;
/* config header information common to all header types */
typedef struct pcicfg {
+ struct device *dev; /* device which owns this */
pcimap *map; /* pointer to array of PCI maps */
void *hdrspec; /* pointer to header type specific data */
+ struct resource *irqres; /* resource descriptor for interrupt mapping */
u_int16_t subvendor; /* card vendor ID */
u_int16_t subdevice; /* card device ID, assigned by card vendor */
@@ -182,6 +186,79 @@ void pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes);
vm_offset_t pci_cvt_to_dense (vm_offset_t);
vm_offset_t pci_cvt_to_bwx (vm_offset_t);
#endif /* __alpha__ */
+
+#ifdef _SYS_BUS_H_
+
+#include "pci_if.h"
+
+enum pci_device_ivars {
+ PCI_IVAR_SUBVENDOR,
+ PCI_IVAR_SUBDEVICE,
+ PCI_IVAR_VENDOR,
+ PCI_IVAR_DEVICE,
+ PCI_IVAR_DEVID,
+ PCI_IVAR_CLASS,
+ PCI_IVAR_SUBCLASS,
+ PCI_IVAR_PROGIF,
+ PCI_IVAR_REVID,
+ PCI_IVAR_INTPIN,
+ PCI_IVAR_IRQ,
+ PCI_IVAR_BUS,
+ PCI_IVAR_SLOT,
+ PCI_IVAR_FUNCTION,
+ PCI_IVAR_SECONDARYBUS,
+ PCI_IVAR_SUBORDINATEBUS,
+};
+
+/*
+ * Simplified accessors for pci devices
+ */
+#define PCI_ACCESSOR(A, B, T) \
+ \
+static __inline T pci_get_ ## A(device_t dev) \
+{ \
+ uintptr_t v; \
+ BUS_READ_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, &v); \
+ return (T) v; \
+} \
+ \
+static __inline void pci_set_ ## A(device_t dev, T t) \
+{ \
+ u_long v = (u_long) t; \
+ BUS_WRITE_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, v); \
+}
+
+PCI_ACCESSOR(subvendor, SUBVENDOR, u_int16_t)
+PCI_ACCESSOR(subdevice, SUBDEVICE, u_int16_t)
+PCI_ACCESSOR(vendor, VENDOR, u_int16_t)
+PCI_ACCESSOR(device, DEVICE, u_int16_t)
+PCI_ACCESSOR(devid, DEVID, u_int32_t)
+PCI_ACCESSOR(class, CLASS, u_int8_t)
+PCI_ACCESSOR(subclass, SUBCLASS, u_int8_t)
+PCI_ACCESSOR(progif, PROGIF, u_int8_t)
+PCI_ACCESSOR(revid, REVID, u_int8_t)
+PCI_ACCESSOR(intpin, INTPIN, u_int8_t)
+PCI_ACCESSOR(irq, IRQ, u_int8_t)
+PCI_ACCESSOR(bus, BUS, u_int8_t)
+PCI_ACCESSOR(slot, SLOT, u_int8_t)
+PCI_ACCESSOR(function, FUNCTION, u_int8_t)
+PCI_ACCESSOR(secondarybus, SECONDARYBUS, u_int8_t)
+PCI_ACCESSOR(subordinatebus, SUBORDINATEBUS, u_int8_t)
+
+static __inline u_int32_t
+pci_read_config(device_t dev, int reg, int width)
+{
+ return PCI_READ_CONFIG(device_get_parent(dev), dev, reg, width);
+}
+
+static __inline void
+pci_write_config(device_t dev, int reg, u_int32_t val, int width)
+{
+ PCI_WRITE_CONFIG(device_get_parent(dev), dev, reg, val, width);
+}
+
+#endif
+
/* for compatibility to FreeBSD-2.2 version of PCI code */
#ifdef PCI_COMPAT