summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files3
-rw-r--r--sys/conf/options1
-rw-r--r--sys/dev/pci/eisa_pci.c19
-rw-r--r--sys/dev/pci/pci.c807
-rw-r--r--sys/dev/pci/pci_pci.c49
-rw-r--r--sys/dev/pci/pci_user.c487
-rw-r--r--sys/dev/pci/pcireg.h97
-rw-r--r--sys/dev/pci/pcivar.h165
-rw-r--r--sys/pci/pci_compat.c336
9 files changed, 931 insertions, 1033 deletions
diff --git a/sys/conf/files b/sys/conf/files
index b43b353..9ff4e4d 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -375,6 +375,7 @@ dev/pci/isa_pci.c optional pci
dev/pci/pci.c count pci
dev/pci/pci_if.m optional pci
dev/pci/pci_pci.c optional pci
+dev/pci/pci_user.c optional pci
dev/pci/pcib_if.m optional pci
dev/pci/vga_pci.c optional pci
dev/pcic/i82365.c optional pcic pccard
@@ -1098,8 +1099,6 @@ pci/meteor.c count meteor pci
pci/ncr.c optional ncr
pci/ohci_pci.c optional ohci
dev/pccbb/pccbb.c optional pccbb
-pci/pci_compat.c optional pci compat_oldpci \
- warning "Old PCI driver compatability shims present."
pci/pcic_p.c optional pcic pci card
pci/simos.c optional simos
pci/uhci_pci.c optional uhci
diff --git a/sys/conf/options b/sys/conf/options
index eb53814..098289e 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -381,7 +381,6 @@ MSGBUF_SIZE opt_msgbuf.h
# PCI related options
PCI_QUIET opt_pci.h
-COMPAT_OLDPCI
# NFS options
NFS_MINATTRTIMO opt_nfs.h
diff --git a/sys/dev/pci/eisa_pci.c b/sys/dev/pci/eisa_pci.c
index b44f572..6572801 100644
--- a/sys/dev/pci/eisa_pci.c
+++ b/sys/dev/pci/eisa_pci.c
@@ -90,7 +90,7 @@ eisab_probe(device_t dev)
* Some bridges don't correctly report their class.
*/
switch (pci_get_devid(dev)) {
- case 0x04828086: /* reports PCI-HOST class (!) */
+ case 0x04828086: /* may show up as PCI-HOST or 0:0 */
matched = 1;
break;
default:
@@ -107,21 +107,20 @@ eisab_probe(device_t dev)
static int
eisab_attach(device_t dev)
{
- device_t child;
-
/*
* Attach an EISA bus. Note that we can only have one EISA bus.
*/
- child = device_add_child(dev, "eisa", 0);
- if (child != NULL)
- bus_generic_attach(dev);
+ if (!devclass_get_device(devclass_find("eisa"), 0))
+ device_add_child(dev, "eisa", -1);
/*
- * Attach an ISA bus as well (should this be a child of EISA?)
+ * Attach an ISA bus as well, since the EISA bus may have ISA
+ * cards installed, and we may have no EISA support in the system.
*/
- child = device_add_child(dev, "isa", 0);
- if (child != NULL)
- bus_generic_attach(dev);
+ if (!devclass_get_device(devclass_find("isa"), 0))
+ device_add_child(dev, "isa", -1);
+
+ bus_generic_attach(dev);
return(0);
}
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index a609e66..49eed85 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,5 +1,7 @@
/*
* Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000, BSDi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,12 +56,98 @@
#include <pci/pcivar.h>
#include "pcib_if.h"
+#include "pci_if.h"
+
+static u_int32_t pci_mapbase(unsigned mapreg);
+static int pci_maptype(unsigned mapreg);
+static int pci_mapsize(unsigned testval);
+static int pci_maprange(unsigned mapreg);
+static void pci_fixancient(pcicfgregs *cfg);
+static void *pci_readpcb(device_t pcib, int b, int s, int f);
+static void pci_hdrtypedata(device_t pcib, int b, int s, int f,
+ pcicfgregs *cfg);
+static struct pci_devinfo *pci_read_device(device_t pcib, int b, int s, int f);
+static void pci_read_extcap(device_t pcib, pcicfgregs *cfg);
+
+static void pci_print_verbose(struct pci_devinfo *dinfo);
+static int pci_porten(device_t pcib, int b, int s, int f);
+static int pci_memen(device_t pcib, int b, int s, int f);
+static int pci_add_map(device_t pcib, int b, int s, int f, int reg,
+ struct resource_list *rl);
+static void pci_add_resources(device_t pcib, int b, int s, int f,
+ device_t dev);
+static void pci_add_children(device_t dev, int busno);
+static int pci_probe(device_t dev);
+static int pci_print_resources(struct resource_list *rl,
+ const char *name, int type,
+ const char *format);
+static int pci_print_child(device_t dev, device_t child);
+static void pci_probe_nomatch(device_t dev, device_t child);
+static int pci_describe_parse_line(char **ptr, int *vendor,
+ int *device, char **desc);
+static char *pci_describe_device(device_t dev);
+static int pci_read_ivar(device_t dev, device_t child, int which,
+ uintptr_t *result);
+static int pci_write_ivar(device_t dev, device_t child, int which,
+ uintptr_t value);
+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);
+static void pci_delete_resource(device_t dev, device_t child,
+ int type, int rid);
+static struct resource_list *pci_get_resource_list (device_t dev, device_t child);
+static u_int32_t pci_read_config_method(device_t dev, device_t child,
+ int reg, int width);
+static void pci_write_config_method(device_t dev, device_t child,
+ int reg, u_int32_t val, int width);
+static int pci_modevent(module_t mod, int what, void *arg);
+
+static device_method_t pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pci_probe),
+ DEVMETHOD(device_attach, bus_generic_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, pci_print_child),
+ DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch),
+ DEVMETHOD(bus_read_ivar, pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, pci_write_ivar),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_delete_resource, pci_delete_resource),
+ DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+ /* 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,
+ 0, /* no softc */
+};
+
+static devclass_t pci_devclass;
+DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
+DRIVER_MODULE(pci, acpi_pcib, pci_driver, pci_devclass, pci_modevent, 0);
static char *pci_vendordata;
static size_t pci_vendordata_size;
-static char *pci_describe_device(device_t dev);
-static devclass_t pci_devclass;
struct pci_quirk {
u_int32_t devid; /* Vendor/device of the card */
@@ -83,9 +171,7 @@ struct pci_quirk pci_quirks[] = {
#define PCI_MAPMEMP 0x02 /* prefetchable memory map */
#define PCI_MAPPORT 0x04 /* port map */
-static STAILQ_HEAD(devlist, pci_devinfo) pci_devq;
u_int32_t pci_numdevs = 0;
-static u_int32_t pci_generation = 0;
/* return base address of memory or port map */
@@ -171,36 +257,6 @@ pci_fixancient(pcicfgregs *cfg)
cfg->hdrtype = 1;
}
-/* read config data specific to header type 2 device (PCI to CardBus bridge) */
-
-static void *
-pci_readpcb(device_t pcib, int b, int s, int f)
-{
- pcih2cfgregs *p;
-
- p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK | M_ZERO);
- if (p == NULL)
- return (NULL);
-
- p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_2, 2);
- p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_2, 2);
-
- p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_2, 1);
-
- p->membase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE0_2, 4);
- p->memlimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT0_2, 4);
- p->membase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE1_2, 4);
- p->memlimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT1_2, 4);
-
- p->iobase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE0_2, 4);
- p->iolimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT0_2, 4);
- p->iobase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE1_2, 4);
- p->iolimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT1_2, 4);
-
- p->pccardif = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PCCARDIF_2, 4);
- return p;
-}
-
/* extract header type specific config data */
static void
@@ -221,16 +277,13 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
case 2:
cfg->subvendor = REG(PCIR_SUBVEND_2, 2);
cfg->subdevice = REG(PCIR_SUBDEV_2, 2);
- cfg->secondarybus = REG(PCIR_SECBUS_2, 1);
- cfg->subordinatebus = REG(PCIR_SUBBUS_2, 1);
cfg->nummaps = PCI_MAXMAPS_2;
- cfg->hdrspec = pci_readpcb(pcib, b, s, f);
break;
}
#undef REG
}
-/* read configuration header into pcicfgrect structure */
+/* read configuration header into pcicfgregs structure */
static struct pci_devinfo *
pci_read_device(device_t pcib, int b, int s, int f)
@@ -278,6 +331,9 @@ pci_read_device(device_t pcib, int b, int s, int f)
pci_fixancient(cfg);
pci_hdrtypedata(pcib, b, s, f, cfg);
+ if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
+ pci_read_extcap(pcib, cfg);
+
STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);
devlist_entry->conf.pc_sel.pc_bus = cfg->bus;
@@ -302,6 +358,50 @@ pci_read_device(device_t pcib, int b, int s, int f)
#undef REG
}
+static void
+pci_read_extcap(device_t pcib, pcicfgregs *cfg)
+{
+#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
+ int ptr, nextptr, ptrptr;
+
+ switch (cfg->hdrtype) {
+ case 0:
+ ptrptr = 0x34;
+ break;
+ case 2:
+ ptrptr = 0x14;
+ break;
+ default:
+ return; /* no extended capabilities support */
+ }
+ nextptr = REG(ptrptr, 1); /* sanity check? */
+
+ /*
+ * Read capability entries.
+ */
+ while (nextptr != 0) {
+ /* Find the next entry */
+ ptr = nextptr;
+ nextptr = REG(ptr + 1, 1);
+
+ /* Process this entry */
+ switch (REG(ptr, 1)) {
+ case 0x01: /* PCI power management */
+ if (cfg->pp_cap == 0) {
+ cfg->pp_cap = REG(ptr + PCIR_POWER_CAP, 2);
+ cfg->pp_status = ptr + PCIR_POWER_STATUS;
+ cfg->pp_pmcsr = ptr + PCIR_POWER_PMCSR;
+ if ((nextptr - ptr) > PCIR_POWER_DATA)
+ cfg->pp_data = ptr + PCIR_POWER_DATA;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#undef REG
+}
+
#if 0
/* free pcicfgregs structure and all depending data structures */
@@ -329,477 +429,147 @@ pci_freecfg(struct pci_devinfo *dinfo)
}
#endif
-
/*
- * This is the user interface to PCI configuration space.
+ * PCI power manangement
*/
-
-static int
-pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
+int
+pci_set_powerstate(device_t dev, int state)
{
- if ((oflags & FWRITE) && securelevel > 0) {
- return EPERM;
- }
- return 0;
-}
-
-static int
-pci_close(dev_t dev, int flag, int devtype, struct proc *p)
-{
- return 0;
-}
-
-/*
- * Match a single pci_conf structure against an array of pci_match_conf
- * structures. The first argument, 'matches', is an array of num_matches
- * pci_match_conf structures. match_buf is a pointer to the pci_conf
- * structure that will be compared to every entry in the matches array.
- * This function returns 1 on failure, 0 on success.
- */
-static int
-pci_conf_match(struct pci_match_conf *matches, int num_matches,
- struct pci_conf *match_buf)
-{
- int i;
-
- if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
- return(1);
-
- for (i = 0; i < num_matches; i++) {
- /*
- * I'm not sure why someone would do this...but...
- */
- if (matches[i].flags == PCI_GETCONF_NO_MATCH)
- continue;
-
- /*
- * Look at each of the match flags. If it's set, do the
- * comparison. If the comparison fails, we don't have a
- * match, go on to the next item if there is one.
- */
- if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
- && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
- && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
- && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
- && (match_buf->pc_vendor != matches[i].pc_vendor))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
- && (match_buf->pc_device != matches[i].pc_device))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
- && (match_buf->pc_class != matches[i].pc_class))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
- && (match_buf->pd_unit != matches[i].pd_unit))
- continue;
-
- if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
- && (strncmp(matches[i].pd_name, match_buf->pd_name,
- sizeof(match_buf->pd_name)) != 0))
- continue;
-
- return(0);
- }
-
- return(1);
-}
-
-/*
- * Locate the parent of a PCI device by scanning the PCI devlist
- * and return the entry for the parent.
- * For devices on PCI Bus 0 (the host bus), this is the PCI Host.
- * For devices on secondary PCI busses, this is that bus' PCI-PCI Bridge.
- */
-
-pcicfgregs *
-pci_devlist_get_parent(pcicfgregs *cfg)
-{
- struct devlist *devlist_head;
- struct pci_devinfo *dinfo;
- pcicfgregs *bridge_cfg;
- int i;
-
- dinfo = STAILQ_FIRST(devlist_head = &pci_devq);
-
- /* If the device is on PCI bus 0, look for the host */
- if (cfg->bus == 0) {
- for (i = 0; (dinfo != NULL) && (i < pci_numdevs);
- dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
- bridge_cfg = &dinfo->cfg;
- if (bridge_cfg->baseclass == PCIC_BRIDGE
- && bridge_cfg->subclass == PCIS_BRIDGE_HOST
- && bridge_cfg->bus == cfg->bus) {
- return bridge_cfg;
+ struct pci_devinfo *dinfo = device_get_ivars(dev);
+ pcicfgregs *cfg = &dinfo->cfg;
+ u_int16_t status;
+ int result;
+
+ if (cfg->pp_cap != 0) {
+ status = pci_read_config(dev, cfg->pp_status, 2) & ~PCIM_PSTAT_DMASK;
+ result = 0;
+ switch (state) {
+ case PCI_POWERSTATE_D0:
+ status |= PCIM_PSTAT_D0;
+ break;
+ case PCI_POWERSTATE_D1:
+ if (cfg->pp_cap & PCIM_PCAP_D1SUPP) {
+ status |= PCIM_PSTAT_D1;
+ } else {
+ result = EOPNOTSUPP;
}
- }
- }
-
- /* If the device is not on PCI bus 0, look for the PCI-PCI bridge */
- if (cfg->bus > 0) {
- for (i = 0; (dinfo != NULL) && (i < pci_numdevs);
- dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
- bridge_cfg = &dinfo->cfg;
- if (bridge_cfg->baseclass == PCIC_BRIDGE
- && bridge_cfg->subclass == PCIS_BRIDGE_PCI
- && bridge_cfg->secondarybus == cfg->bus) {
- return bridge_cfg;
+ break;
+ case PCI_POWERSTATE_D2:
+ if (cfg->pp_cap & PCIM_PCAP_D2SUPP) {
+ status |= PCIM_PSTAT_D2;
+ } else {
+ result = EOPNOTSUPP;
}
+ break;
+ case PCI_POWERSTATE_D3:
+ status |= PCIM_PSTAT_D3;
+ break;
+ default:
+ result = EINVAL;
}
+ if (result == 0)
+ pci_write_config(dev, cfg->pp_status, status, 2);
+ } else {
+ result = ENXIO;
}
-
- return NULL;
+ return(result);
}
-static int
-pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+int
+pci_get_powerstate(device_t dev)
{
- device_t pci, pcib;
- struct pci_io *io;
- const char *name;
- int error;
-
- if (!(flag & FWRITE))
- return EPERM;
-
-
- switch(cmd) {
- case PCIOCGETCONF:
- {
- struct pci_devinfo *dinfo;
- struct pci_conf_io *cio;
- struct devlist *devlist_head;
- struct pci_match_conf *pattern_buf;
- int num_patterns;
- size_t iolen;
- int ionum, i;
-
- cio = (struct pci_conf_io *)data;
-
- num_patterns = 0;
- dinfo = NULL;
-
- /*
- * Hopefully the user won't pass in a null pointer, but it
- * can't hurt to check.
- */
- if (cio == NULL) {
- error = EINVAL;
+ struct pci_devinfo *dinfo = device_get_ivars(dev);
+ pcicfgregs *cfg = &dinfo->cfg;
+ u_int16_t status;
+ int result;
+
+ if (cfg->pp_cap != 0) {
+ status = pci_read_config(dev, cfg->pp_status, 2);
+ switch (status & PCIM_PSTAT_DMASK) {
+ case PCIM_PSTAT_D0:
+ result = PCI_POWERSTATE_D0;
break;
- }
-
- /*
- * If the user specified an offset into the device list,
- * but the list has changed since they last called this
- * ioctl, tell them that the list has changed. They will
- * have to get the list from the beginning.
- */
- if ((cio->offset != 0)
- && (cio->generation != pci_generation)){
- cio->num_matches = 0;
- cio->status = PCI_GETCONF_LIST_CHANGED;
- error = 0;
+ case PCIM_PSTAT_D1:
+ result = PCI_POWERSTATE_D1;
break;
- }
-
- /*
- * Check to see whether the user has asked for an offset
- * past the end of our list.
- */
- if (cio->offset >= pci_numdevs) {
- cio->num_matches = 0;
- cio->status = PCI_GETCONF_LAST_DEVICE;
- error = 0;
+ case PCIM_PSTAT_D2:
+ result = PCI_POWERSTATE_D2;
break;
- }
-
- /* get the head of the device queue */
- devlist_head = &pci_devq;
-
- /*
- * Determine how much room we have for pci_conf structures.
- * Round the user's buffer size down to the nearest
- * multiple of sizeof(struct pci_conf) in case the user
- * didn't specify a multiple of that size.
- */
- iolen = min(cio->match_buf_len -
- (cio->match_buf_len % sizeof(struct pci_conf)),
- pci_numdevs * sizeof(struct pci_conf));
-
- /*
- * Since we know that iolen is a multiple of the size of
- * the pciconf union, it's okay to do this.
- */
- ionum = iolen / sizeof(struct pci_conf);
-
- /*
- * If this test is true, the user wants the pci_conf
- * structures returned to match the supplied entries.
- */
- if ((cio->num_patterns > 0)
- && (cio->pat_buf_len > 0)) {
- /*
- * pat_buf_len needs to be:
- * num_patterns * sizeof(struct pci_match_conf)
- * While it is certainly possible the user just
- * allocated a large buffer, but set the number of
- * matches correctly, it is far more likely that
- * their kernel doesn't match the userland utility
- * they're using. It's also possible that the user
- * forgot to initialize some variables. Yes, this
- * may be overly picky, but I hazard to guess that
- * it's far more likely to just catch folks that
- * updated their kernel but not their userland.
- */
- if ((cio->num_patterns *
- sizeof(struct pci_match_conf)) != cio->pat_buf_len){
- /* The user made a mistake, return an error*/
- cio->status = PCI_GETCONF_ERROR;
- printf("pci_ioctl: pat_buf_len %d != "
- "num_patterns (%d) * sizeof(struct "
- "pci_match_conf) (%d)\npci_ioctl: "
- "pat_buf_len should be = %d\n",
- cio->pat_buf_len, cio->num_patterns,
- (int)sizeof(struct pci_match_conf),
- (int)sizeof(struct pci_match_conf) *
- cio->num_patterns);
- printf("pci_ioctl: do your headers match your "
- "kernel?\n");
- cio->num_matches = 0;
- error = EINVAL;
- break;
- }
-
- /*
- * Check the user's buffer to make sure it's readable.
- */
- if (!useracc((caddr_t)cio->patterns,
- cio->pat_buf_len, VM_PROT_READ)) {
- printf("pci_ioctl: pattern buffer %p, "
- "length %u isn't user accessible for"
- " READ\n", cio->patterns,
- cio->pat_buf_len);
- error = EACCES;
- break;
- }
- /*
- * Allocate a buffer to hold the patterns.
- */
- pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
- M_WAITOK);
- error = copyin(cio->patterns, pattern_buf,
- cio->pat_buf_len);
- if (error != 0)
- break;
- num_patterns = cio->num_patterns;
-
- } else if ((cio->num_patterns > 0)
- || (cio->pat_buf_len > 0)) {
- /*
- * The user made a mistake, spit out an error.
- */
- cio->status = PCI_GETCONF_ERROR;
- cio->num_matches = 0;
- printf("pci_ioctl: invalid GETCONF arguments\n");
- error = EINVAL;
+ case PCIM_PSTAT_D3:
+ result = PCI_POWERSTATE_D3;
break;
- } else
- pattern_buf = NULL;
-
- /*
- * Make sure we can write to the match buffer.
- */
- if (!useracc((caddr_t)cio->matches,
- cio->match_buf_len, VM_PROT_WRITE)) {
- printf("pci_ioctl: match buffer %p, length %u "
- "isn't user accessible for WRITE\n",
- cio->matches, cio->match_buf_len);
- error = EACCES;
+ default:
+ result = PCI_POWERSTATE_UNKNOWN;
break;
}
+ } else {
+ /* No support, device is always at D0 */
+ result = PCI_POWERSTATE_D0;
+ }
+ return(result);
+}
- /*
- * Go through the list of devices and copy out the devices
- * that match the user's criteria.
- */
- for (cio->num_matches = 0, error = 0, i = 0,
- dinfo = STAILQ_FIRST(devlist_head);
- (dinfo != NULL) && (cio->num_matches < ionum)
- && (error == 0) && (i < pci_numdevs);
- dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
-
- if (i < cio->offset)
- continue;
-
- /* Populate pd_name and pd_unit */
- name = NULL;
- if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0')
- name = device_get_name(dinfo->cfg.dev);
- if (name) {
- strncpy(dinfo->conf.pd_name, name,
- sizeof(dinfo->conf.pd_name));
- dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
- dinfo->conf.pd_unit =
- device_get_unit(dinfo->cfg.dev);
- }
-
- if ((pattern_buf == NULL) ||
- (pci_conf_match(pattern_buf, num_patterns,
- &dinfo->conf) == 0)) {
-
- /*
- * If we've filled up the user's buffer,
- * break out at this point. Since we've
- * got a match here, we'll pick right back
- * up at the matching entry. We can also
- * tell the user that there are more matches
- * left.
- */
- if (cio->num_matches >= ionum)
- break;
-
- error = copyout(&dinfo->conf,
- &cio->matches[cio->num_matches],
- sizeof(struct pci_conf));
- cio->num_matches++;
- }
- }
-
- /*
- * Set the pointer into the list, so if the user is getting
- * n records at a time, where n < pci_numdevs,
- */
- cio->offset = i;
+/*
+ * Some convenience functions for PCI device drivers.
+ */
- /*
- * Set the generation, the user will need this if they make
- * another ioctl call with offset != 0.
- */
- cio->generation = pci_generation;
-
- /*
- * If this is the last device, inform the user so he won't
- * bother asking for more devices. If dinfo isn't NULL, we
- * know that there are more matches in the list because of
- * the way the traversal is done.
- */
- if (dinfo == NULL)
- cio->status = PCI_GETCONF_LAST_DEVICE;
- else
- cio->status = PCI_GETCONF_MORE_DEVS;
+static __inline void
+pci_set_command_bit(device_t dev, u_int16_t bit)
+{
+ u_int16_t command;
- if (pattern_buf != NULL)
- free(pattern_buf, M_TEMP);
+ command = pci_read_config(dev, PCIR_COMMAND, 2);
+ command |= bit;
+ pci_write_config(dev, PCIR_COMMAND, command, 2);
+}
- break;
- }
- case PCIOCREAD:
- io = (struct pci_io *)data;
- switch(io->pi_width) {
- case 4:
- case 2:
- case 1:
- /*
- * Assume that the user-level bus number is
- * actually the pciN instance number. We map
- * from that to the real pcib+bus combination.
- */
- pci = devclass_get_device(pci_devclass,
- io->pi_sel.pc_bus);
- if (pci) {
- int b = pcib_get_bus(pci);
- pcib = device_get_parent(pci);
- io->pi_data =
- PCIB_READ_CONFIG(pcib,
- b,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
- io->pi_reg,
- io->pi_width);
- error = 0;
- } else {
- error = ENODEV;
- }
- break;
- default:
- error = ENODEV;
- break;
- }
- break;
+static __inline void
+pci_clear_command_bit(device_t dev, u_int16_t bit)
+{
+ u_int16_t command;
- case PCIOCWRITE:
- io = (struct pci_io *)data;
- switch(io->pi_width) {
- case 4:
- case 2:
- case 1:
- /*
- * Assume that the user-level bus number is
- * actually the pciN instance number. We map
- * from that to the real pcib+bus combination.
- */
- pci = devclass_get_device(pci_devclass,
- io->pi_sel.pc_bus);
- if (pci) {
- int b = pcib_get_bus(pci);
- pcib = device_get_parent(pci);
- PCIB_WRITE_CONFIG(pcib,
- b,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
- io->pi_reg,
- io->pi_data,
- io->pi_width);
- error = 0;
- } else {
- error = ENODEV;
- }
- break;
- default:
- error = ENODEV;
- break;
- }
- break;
+ command = pci_read_config(dev, PCIR_COMMAND, 2);
+ command &= ~bit;
+ pci_write_config(dev, PCIR_COMMAND, command, 2);
+}
- default:
- error = ENOTTY;
- break;
- }
+void
+pci_enable_busmaster(device_t dev)
+{
+ pci_set_command_bit(dev, PCIM_CMD_BUSMASTEREN);
+}
- return (error);
+void
+pci_disable_busmaster(device_t dev)
+{
+ pci_clear_command_bit(dev, PCIM_CMD_BUSMASTEREN);
}
-#define PCI_CDEV 78
-
-static struct cdevsw pcicdev = {
- /* open */ pci_open,
- /* close */ pci_close,
- /* read */ noread,
- /* write */ nowrite,
- /* ioctl */ pci_ioctl,
- /* poll */ nopoll,
- /* mmap */ nommap,
- /* strategy */ nostrategy,
- /* name */ "pci",
- /* maj */ PCI_CDEV,
- /* dump */ nodump,
- /* psize */ nopsize,
- /* flags */ 0,
- /* bmaj */ -1
-};
+void
+pci_enable_io(device_t dev, int space)
+{
+ switch(space) {
+ case SYS_RES_IOPORT:
+ pci_set_command_bit(dev, PCIM_CMD_PORTEN);
+ break;
+ case SYS_RES_MEMORY:
+ pci_set_command_bit(dev, PCIM_CMD_MEMEN);
+ break;
+ }
+}
-#include "pci_if.h"
+void
+pci_disable_io(device_t dev, int space)
+{
+ switch(space) {
+ case SYS_RES_IOPORT:
+ pci_clear_command_bit(dev, PCIM_CMD_PORTEN);
+ break;
+ case SYS_RES_MEMORY:
+ pci_clear_command_bit(dev, PCIM_CMD_MEMEN);
+ break;
+ }
+}
/*
* New style pci driver. Parent device is either a pci-host-bridge or a
@@ -819,8 +589,6 @@ pci_print_verbose(struct pci_devinfo *dinfo)
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);
@@ -830,6 +598,16 @@ pci_print_verbose(struct pci_devinfo *dinfo)
#endif /* PCI_DEBUG */
if (cfg->intpin > 0)
printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline);
+ if (cfg->pp_cap) {
+ u_int16_t status;
+
+ status = pci_read_config(cfg->dev, cfg->pp_status, 2);
+ printf("\tpowerspec %d supports D0%s%s D3 current D%d\n",
+ cfg->pp_cap & PCIM_PCAP_SPEC,
+ cfg->pp_cap & PCIM_PCAP_D1SUPP ? " D1" : "",
+ cfg->pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "",
+ status & PCIM_PSTAT_DMASK);
+ }
}
}
@@ -970,13 +748,13 @@ pci_add_children(device_t dev, int busno)
pci_read_device(pcib, busno, s, f);
if (dinfo != NULL) {
if (dinfo->cfg.mfdev)
- pcifunchigh = 7;
+ pcifunchigh = PCI_FUNCMAX;
- pci_print_verbose(dinfo);
dinfo->cfg.dev = device_add_child(dev, NULL, -1);
device_set_ivars(dinfo->cfg.dev, dinfo);
pci_add_resources(pcib, busno, s, f,
dinfo->cfg.dev);
+ pci_print_verbose(dinfo);
}
}
}
@@ -1301,7 +1079,6 @@ pci_describe_device(device_t dev)
return(desc);
}
-
static int
pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
@@ -1354,12 +1131,6 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
case PCI_IVAR_FUNCTION:
*result = cfg->func;
break;
- case PCI_IVAR_SECONDARYBUS:
- *result = cfg->secondarybus;
- break;
- case PCI_IVAR_SUBORDINATEBUS:
- *result = cfg->subordinatebus;
- break;
default:
return ENOENT;
}
@@ -1392,12 +1163,6 @@ pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
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;
}
@@ -1484,6 +1249,7 @@ pci_modevent(module_t mod, int what, void *arg)
switch (what) {
case MOD_LOAD:
STAILQ_INIT(&pci_devq);
+ pci_generation = 0;
break;
case MOD_UNLOAD:
@@ -1492,44 +1258,3 @@ pci_modevent(module_t mod, int what, void *arg)
return 0;
}
-
-static device_method_t pci_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, pci_probe),
- DEVMETHOD(device_attach, bus_generic_attach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
-
- /* Bus interface */
- DEVMETHOD(bus_print_child, pci_print_child),
- DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch),
- DEVMETHOD(bus_read_ivar, pci_read_ivar),
- DEVMETHOD(bus_write_ivar, pci_write_ivar),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
- DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
- DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
-
- DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
- DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
- DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
- DEVMETHOD(bus_delete_resource, pci_delete_resource),
- DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
- DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
- DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
- DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
-
- /* 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,
- 0, /* no softc */
-};
-DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
-DRIVER_MODULE(pci, acpi_pcib, pci_driver, pci_devclass, pci_modevent, 0);
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 6bcb15a..3980158 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -52,12 +52,13 @@
struct pcib_softc
{
device_t dev;
+ u_int16_t command; /* command register */
u_int8_t secbus; /* secondary bus number */
u_int8_t subbus; /* subordinate bus number */
pci_addr_t pmembase; /* base address of prefetchable memory */
pci_addr_t pmemlimit; /* topmost address of prefetchable memory */
- u_int32_t membase; /* base address of memory window */
- u_int32_t memlimit; /* topmost address of memory window */
+ pci_addr_t membase; /* base address of memory window */
+ pci_addr_t memlimit; /* topmost address of memory window */
u_int32_t iobase; /* base address of port window */
u_int32_t iolimit; /* topmost address of port window */
u_int16_t secstat; /* secondary bus status register */
@@ -141,6 +142,7 @@ pcib_attach(device_t dev)
/*
* Get current bridge configuration.
*/
+ sc->command = pci_read_config(dev, PCIR_COMMAND, 1);
sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
@@ -150,31 +152,35 @@ pcib_attach(device_t dev)
/*
* Determine current I/O decode.
*/
- iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1);
- if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
- sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2),
- pci_read_config(dev, PCIR_IOBASEL_1, 1));
- } else {
- sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1));
- }
+ if (sc->command & PCIM_CMD_PORTEN) {
+ iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1);
+ if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
+ sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2),
+ pci_read_config(dev, PCIR_IOBASEL_1, 1));
+ } else {
+ sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1));
+ }
- iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1);
- if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
- sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2),
- pci_read_config(dev, PCIR_IOLIMITL_1, 1));
- } else {
- sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1));
+ iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1);
+ if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
+ sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2),
+ pci_read_config(dev, PCIR_IOLIMITL_1, 1));
+ } else {
+ sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1));
+ }
}
/*
* Determine current memory decode.
*/
- sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2));
- sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
- sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4),
- pci_read_config(dev, PCIR_PMBASEL_1, 2));
- sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4),
- pci_read_config(dev, PCIR_PMLIMITL_1, 2));
+ if (sc->command & PCIM_CMD_MEMEN) {
+ sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2));
+ sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
+ sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4),
+ pci_read_config(dev, PCIR_PMBASEL_1, 2));
+ sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4),
+ pci_read_config(dev, PCIR_PMLIMITL_1, 2));
+ }
/*
* Quirk handling.
@@ -193,7 +199,6 @@ pcib_attach(device_t dev)
break;
}
-
if (bootverbose) {
device_printf(dev, " secondary bus %d\n", sc->secbus);
device_printf(dev, " subordinate bus %d\n", sc->subbus);
diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c
new file mode 100644
index 0000000..1699029
--- /dev/null
+++ b/sys/dev/pci/pci_user.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include "opt_bus.h" /* XXX trim includes */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <vm/vm.h>
+#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 <sys/pciio.h>
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include "pcib_if.h"
+#include "pci_if.h"
+
+/*
+ * This is the user interface to PCI configuration space.
+ */
+
+static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p);
+static int pci_close(dev_t dev, int flag, int devtype, struct proc *p);
+static int pci_conf_match(struct pci_match_conf *matches, int num_matches,
+ struct pci_conf *match_buf);
+static int pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
+
+#define PCI_CDEV 78
+
+struct cdevsw pcicdev = {
+ /* open */ pci_open,
+ /* close */ pci_close,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ pci_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "pci",
+ /* maj */ PCI_CDEV,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+ /* bmaj */ -1
+};
+
+static int
+pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
+{
+ if ((oflags & FWRITE) && securelevel > 0) {
+ return EPERM;
+ }
+ return 0;
+}
+
+static int
+pci_close(dev_t dev, int flag, int devtype, struct proc *p)
+{
+ return 0;
+}
+
+/*
+ * Match a single pci_conf structure against an array of pci_match_conf
+ * structures. The first argument, 'matches', is an array of num_matches
+ * pci_match_conf structures. match_buf is a pointer to the pci_conf
+ * structure that will be compared to every entry in the matches array.
+ * This function returns 1 on failure, 0 on success.
+ */
+static int
+pci_conf_match(struct pci_match_conf *matches, int num_matches,
+ struct pci_conf *match_buf)
+{
+ int i;
+
+ if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
+ return(1);
+
+ for (i = 0; i < num_matches; i++) {
+ /*
+ * I'm not sure why someone would do this...but...
+ */
+ if (matches[i].flags == PCI_GETCONF_NO_MATCH)
+ continue;
+
+ /*
+ * Look at each of the match flags. If it's set, do the
+ * comparison. If the comparison fails, we don't have a
+ * match, go on to the next item if there is one.
+ */
+ if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
+ && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
+ && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
+ && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
+ && (match_buf->pc_vendor != matches[i].pc_vendor))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
+ && (match_buf->pc_device != matches[i].pc_device))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
+ && (match_buf->pc_class != matches[i].pc_class))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
+ && (match_buf->pd_unit != matches[i].pd_unit))
+ continue;
+
+ if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
+ && (strncmp(matches[i].pd_name, match_buf->pd_name,
+ sizeof(match_buf->pd_name)) != 0))
+ continue;
+
+ return(0);
+ }
+
+ return(1);
+}
+
+static int
+pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ device_t pci, pcib;
+ struct pci_io *io;
+ const char *name;
+ int error;
+
+ if (!(flag & FWRITE))
+ return EPERM;
+
+
+ switch(cmd) {
+ case PCIOCGETCONF:
+ {
+ struct pci_devinfo *dinfo;
+ struct pci_conf_io *cio;
+ struct devlist *devlist_head;
+ struct pci_match_conf *pattern_buf;
+ int num_patterns;
+ size_t iolen;
+ int ionum, i;
+
+ cio = (struct pci_conf_io *)data;
+
+ num_patterns = 0;
+ dinfo = NULL;
+
+ /*
+ * Hopefully the user won't pass in a null pointer, but it
+ * can't hurt to check.
+ */
+ if (cio == NULL) {
+ error = EINVAL;
+ break;
+ }
+
+ /*
+ * If the user specified an offset into the device list,
+ * but the list has changed since they last called this
+ * ioctl, tell them that the list has changed. They will
+ * have to get the list from the beginning.
+ */
+ if ((cio->offset != 0)
+ && (cio->generation != pci_generation)){
+ cio->num_matches = 0;
+ cio->status = PCI_GETCONF_LIST_CHANGED;
+ error = 0;
+ break;
+ }
+
+ /*
+ * Check to see whether the user has asked for an offset
+ * past the end of our list.
+ */
+ if (cio->offset >= pci_numdevs) {
+ cio->num_matches = 0;
+ cio->status = PCI_GETCONF_LAST_DEVICE;
+ error = 0;
+ break;
+ }
+
+ /* get the head of the device queue */
+ devlist_head = &pci_devq;
+
+ /*
+ * Determine how much room we have for pci_conf structures.
+ * Round the user's buffer size down to the nearest
+ * multiple of sizeof(struct pci_conf) in case the user
+ * didn't specify a multiple of that size.
+ */
+ iolen = min(cio->match_buf_len -
+ (cio->match_buf_len % sizeof(struct pci_conf)),
+ pci_numdevs * sizeof(struct pci_conf));
+
+ /*
+ * Since we know that iolen is a multiple of the size of
+ * the pciconf union, it's okay to do this.
+ */
+ ionum = iolen / sizeof(struct pci_conf);
+
+ /*
+ * If this test is true, the user wants the pci_conf
+ * structures returned to match the supplied entries.
+ */
+ if ((cio->num_patterns > 0)
+ && (cio->pat_buf_len > 0)) {
+ /*
+ * pat_buf_len needs to be:
+ * num_patterns * sizeof(struct pci_match_conf)
+ * While it is certainly possible the user just
+ * allocated a large buffer, but set the number of
+ * matches correctly, it is far more likely that
+ * their kernel doesn't match the userland utility
+ * they're using. It's also possible that the user
+ * forgot to initialize some variables. Yes, this
+ * may be overly picky, but I hazard to guess that
+ * it's far more likely to just catch folks that
+ * updated their kernel but not their userland.
+ */
+ if ((cio->num_patterns *
+ sizeof(struct pci_match_conf)) != cio->pat_buf_len){
+ /* The user made a mistake, return an error*/
+ cio->status = PCI_GETCONF_ERROR;
+ printf("pci_ioctl: pat_buf_len %d != "
+ "num_patterns (%d) * sizeof(struct "
+ "pci_match_conf) (%d)\npci_ioctl: "
+ "pat_buf_len should be = %d\n",
+ cio->pat_buf_len, cio->num_patterns,
+ (int)sizeof(struct pci_match_conf),
+ (int)sizeof(struct pci_match_conf) *
+ cio->num_patterns);
+ printf("pci_ioctl: do your headers match your "
+ "kernel?\n");
+ cio->num_matches = 0;
+ error = EINVAL;
+ break;
+ }
+
+ /*
+ * Check the user's buffer to make sure it's readable.
+ */
+ if (!useracc((caddr_t)cio->patterns,
+ cio->pat_buf_len, VM_PROT_READ)) {
+ printf("pci_ioctl: pattern buffer %p, "
+ "length %u isn't user accessible for"
+ " READ\n", cio->patterns,
+ cio->pat_buf_len);
+ error = EACCES;
+ break;
+ }
+ /*
+ * Allocate a buffer to hold the patterns.
+ */
+ pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
+ M_WAITOK);
+ error = copyin(cio->patterns, pattern_buf,
+ cio->pat_buf_len);
+ if (error != 0)
+ break;
+ num_patterns = cio->num_patterns;
+
+ } else if ((cio->num_patterns > 0)
+ || (cio->pat_buf_len > 0)) {
+ /*
+ * The user made a mistake, spit out an error.
+ */
+ cio->status = PCI_GETCONF_ERROR;
+ cio->num_matches = 0;
+ printf("pci_ioctl: invalid GETCONF arguments\n");
+ error = EINVAL;
+ break;
+ } else
+ pattern_buf = NULL;
+
+ /*
+ * Make sure we can write to the match buffer.
+ */
+ if (!useracc((caddr_t)cio->matches,
+ cio->match_buf_len, VM_PROT_WRITE)) {
+ printf("pci_ioctl: match buffer %p, length %u "
+ "isn't user accessible for WRITE\n",
+ cio->matches, cio->match_buf_len);
+ error = EACCES;
+ break;
+ }
+
+ /*
+ * Go through the list of devices and copy out the devices
+ * that match the user's criteria.
+ */
+ for (cio->num_matches = 0, error = 0, i = 0,
+ dinfo = STAILQ_FIRST(devlist_head);
+ (dinfo != NULL) && (cio->num_matches < ionum)
+ && (error == 0) && (i < pci_numdevs);
+ dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
+
+ if (i < cio->offset)
+ continue;
+
+ /* Populate pd_name and pd_unit */
+ name = NULL;
+ if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0')
+ name = device_get_name(dinfo->cfg.dev);
+ if (name) {
+ strncpy(dinfo->conf.pd_name, name,
+ sizeof(dinfo->conf.pd_name));
+ dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
+ dinfo->conf.pd_unit =
+ device_get_unit(dinfo->cfg.dev);
+ }
+
+ if ((pattern_buf == NULL) ||
+ (pci_conf_match(pattern_buf, num_patterns,
+ &dinfo->conf) == 0)) {
+
+ /*
+ * If we've filled up the user's buffer,
+ * break out at this point. Since we've
+ * got a match here, we'll pick right back
+ * up at the matching entry. We can also
+ * tell the user that there are more matches
+ * left.
+ */
+ if (cio->num_matches >= ionum)
+ break;
+
+ error = copyout(&dinfo->conf,
+ &cio->matches[cio->num_matches],
+ sizeof(struct pci_conf));
+ cio->num_matches++;
+ }
+ }
+
+ /*
+ * Set the pointer into the list, so if the user is getting
+ * n records at a time, where n < pci_numdevs,
+ */
+ cio->offset = i;
+
+ /*
+ * Set the generation, the user will need this if they make
+ * another ioctl call with offset != 0.
+ */
+ cio->generation = pci_generation;
+
+ /*
+ * If this is the last device, inform the user so he won't
+ * bother asking for more devices. If dinfo isn't NULL, we
+ * know that there are more matches in the list because of
+ * the way the traversal is done.
+ */
+ if (dinfo == NULL)
+ cio->status = PCI_GETCONF_LAST_DEVICE;
+ else
+ cio->status = PCI_GETCONF_MORE_DEVS;
+
+ if (pattern_buf != NULL)
+ free(pattern_buf, M_TEMP);
+
+ break;
+ }
+ case PCIOCREAD:
+ io = (struct pci_io *)data;
+ switch(io->pi_width) {
+ case 4:
+ case 2:
+ case 1:
+ /*
+ * Assume that the user-level bus number is
+ * actually the pciN instance number. We map
+ * from that to the real pcib+bus combination.
+ */
+ pci = devclass_get_device(devclass_find("pci"),
+ io->pi_sel.pc_bus);
+ if (pci) {
+ int b = pcib_get_bus(pci);
+ pcib = device_get_parent(pci);
+ io->pi_data =
+ PCIB_READ_CONFIG(pcib,
+ b,
+ io->pi_sel.pc_dev,
+ io->pi_sel.pc_func,
+ io->pi_reg,
+ io->pi_width);
+ error = 0;
+ } else {
+ error = ENODEV;
+ }
+ break;
+ default:
+ error = ENODEV;
+ break;
+ }
+ break;
+
+ case PCIOCWRITE:
+ io = (struct pci_io *)data;
+ switch(io->pi_width) {
+ case 4:
+ case 2:
+ case 1:
+ /*
+ * Assume that the user-level bus number is
+ * actually the pciN instance number. We map
+ * from that to the real pcib+bus combination.
+ */
+ pci = devclass_get_device(devclass_find("pci"),
+ io->pi_sel.pc_bus);
+ if (pci) {
+ int b = pcib_get_bus(pci);
+ pcib = device_get_parent(pci);
+ PCIB_WRITE_CONFIG(pcib,
+ b,
+ io->pi_sel.pc_dev,
+ io->pi_sel.pc_func,
+ io->pi_reg,
+ io->pi_data,
+ io->pi_width);
+ error = 0;
+ } else {
+ error = ENODEV;
+ }
+ break;
+ default:
+ error = ENODEV;
+ break;
+ }
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ return (error);
+}
+
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index 35297e4..1e98f72 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -52,10 +52,26 @@
#define PCIR_COMMAND 0x04
#define PCIM_CMD_PORTEN 0x0001
#define PCIM_CMD_MEMEN 0x0002
-#define PCIM_CMD_MWRICEN 0x0010
#define PCIM_CMD_BUSMASTEREN 0x0004
+#define PCIM_CMD_SPECIALEN 0x0008
+#define PCIM_CMD_MWRICEN 0x0010
#define PCIM_CMD_PERRESPEN 0x0040
+#define PCIM_CMD_SERREN 0x0100
+#define PCIM_CMD_BACKTOBACK 0x0200
#define PCIR_STATUS 0x06
+#define PCIM_STATUS_CAPPRESENT 0x0010
+#define PCIM_STATUS_66CAPABLE 0x0020
+#define PCIM_STATUS_BACKTOBACK 0x0080
+#define PCIM_STATUS_PERRREPORT 0x0100
+#define PCIM_STATUS_SEL_FAST 0x0000
+#define PCIM_STATUS_SEL_MEDIMUM 0x0200
+#define PCIM_STATUS_SEL_SLOW 0x0400
+#define PCIM_STATUS_SEL_MASK 0x0600
+#define PCIM_STATUS_STABORT 0x0800
+#define PCIM_STATUS_RTABORT 0x1000
+#define PCIM_STATUS_RMABORT 0x2000
+#define PCIM_STATUS_SERR 0x4000
+#define PCIM_STATUS_PERR 0x8000
#define PCIR_REVID 0x08
#define PCIR_PROGIF 0x09
#define PCIR_SUBCLASS 0x0a
@@ -81,7 +97,7 @@
/* config registers for header type 1 devices */
-#define PCIR_SECSTAT_1 0 /**/
+#define PCIR_SECSTAT_1 0x1e
#define PCIR_PRIBUS_1 0x18
#define PCIR_SECBUS_1 0x19
@@ -227,38 +243,59 @@
#define PCIC_OTHER 0xff
+/* PCI power manangement */
+
+#define PCIR_POWER_CAP 0x2
+#define PCIM_PCAP_SPEC 0x0007
+#define PCIM_PCAP_PMEREQCLK 0x0008
+#define PCIM_PCAP_PMEREQPWR 0x0010
+#define PCIM_PCAP_DEVSPECINIT 0x0020
+#define PCIM_PCAP_DYNCLOCK 0x0040
+#define PCIM_PCAP_SECCLOCK 0x00c0
+#define PCIM_PCAP_CLOCKMASK 0x00c0
+#define PCIM_PCAP_REQFULLCLOCK 0x0100
+#define PCIM_PCAP_D1SUPP 0x0200
+#define PCIM_PCAP_D2SUPP 0x0400
+#define PCIM_PCAP_D0PME 0x1000
+#define PCIM_PCAP_D1PME 0x2000
+#define PCIM_PCAP_D2PME 0x4000
+
+#define PCIR_POWER_STATUS 0x4
+#define PCIM_PSTAT_D0 0x0000
+#define PCIM_PSTAT_D1 0x0001
+#define PCIM_PSTAT_D2 0x0002
+#define PCIM_PSTAT_D3 0x0003
+#define PCIM_PSTAT_DMASK 0x0003
+#define PCIM_PSTAT_REPENABLE 0x0010
+#define PCIM_PSTAT_PMEENABLE 0x0100
+#define PCIM_PSTAT_D0POWER 0x0000
+#define PCIM_PSTAT_D1POWER 0x0200
+#define PCIM_PSTAT_D2POWER 0x0400
+#define PCIM_PSTAT_D3POWER 0x0600
+#define PCIM_PSTAT_D0HEAT 0x0800
+#define PCIM_PSTAT_D1HEAT 0x1000
+#define PCIM_PSTAT_D2HEAT 0x1200
+#define PCIM_PSTAT_D3HEAT 0x1400
+#define PCIM_PSTAT_DATAUNKN 0x0000
+#define PCIM_PSTAT_DATADIV10 0x2000
+#define PCIM_PSTAT_DATADIV100 0x4000
+#define PCIM_PSTAT_DATADIV1000 0x6000
+#define PCIM_PSTAT_DATADIVMASK 0x6000
+#define PCIM_PSTAT_PME 0x8000
+
+#define PCIR_POWER_PMCSR 0x6
+#define PCIM_PMCSR_DCLOCK 0x10
+#define PCIM_PMCSR_B2SUPP 0x20
+#define PCIM_BMCSR_B3SUPP 0x40
+#define PCIM_BMCSR_BPCE 0x80
+
+#define PCIR_POWER_DATA 0x7
+
+#if 0
/* some PCI vendor definitions (only used to identify ancient devices !!! */
#define PCIV_INTEL 0x8086
#define PCID_INTEL_SATURN 0x0483
#define PCID_INTEL_ORION 0x84c4
-
-/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */
-
-#if defined(_KERNEL) && !defined(KLD_MODULE)
-#include "opt_compat_oldpci.h"
#endif
-
-#ifdef COMPAT_OLDPCI
-
-#define PCI_ID_REG 0x00
-#define PCI_COMMAND_STATUS_REG 0x04
-#define PCI_COMMAND_IO_ENABLE 0x00000001
-#define PCI_COMMAND_MEM_ENABLE 0x00000002
-#define PCI_CLASS_REG 0x08
-#define PCI_CLASS_MASK 0xff000000
-#define PCI_SUBCLASS_MASK 0x00ff0000
-#define PCI_REVISION_MASK 0x000000ff
-#define PCI_CLASS_PREHISTORIC 0x00000000
-#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000
-#define PCI_CLASS_MASS_STORAGE 0x01000000
-#define PCI_CLASS_DISPLAY 0x03000000
-#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000
-#define PCI_CLASS_BRIDGE 0x06000000
-#define PCI_MAP_REG_START 0x10
-#define PCI_MAP_REG_END 0x28
-#define PCI_MAP_IO 0x00000001
-#define PCI_INTERRUPT_REG 0x3c
-
-#endif /* COMPAT_OLDPCI */
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 4ac4dd1..5ab5d13 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -55,7 +55,6 @@ typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */
typedef struct pcicfg {
struct device *dev; /* device which owns this */
- void *hdrspec; /* pointer to header type specific data */
u_int16_t subvendor; /* card vendor ID */
u_int16_t subdevice; /* card device ID, assigned by card vendor */
@@ -86,8 +85,11 @@ typedef struct pcicfg {
u_int8_t slot; /* config space slot address */
u_int8_t func; /* config space function number */
- u_int8_t secondarybus; /* bus on secondary side of bridge, if any */
- u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */
+ u_int16_t pp_cap; /* PCI power management capabilities */
+ u_int8_t pp_status; /* config space address of PCI power status reg */
+ u_int8_t pp_pmcsr; /* config space address of PMCSR reg */
+ u_int8_t pp_data; /* config space address of PCI power data reg */
+
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */
@@ -144,19 +146,11 @@ struct pci_devinfo {
};
#endif
-/* low level PCI config register functions provided by pcibus.c */
-
-int pci_cfgread (pcicfgregs *cfg, int reg, int bytes);
-void pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes);
-
#ifdef __alpha__
vm_offset_t pci_cvt_to_dense (vm_offset_t);
vm_offset_t pci_cvt_to_bwx (vm_offset_t);
#endif /* __alpha__ */
-/* low level devlist operations for the 2.2 compatibility code in pci.c */
-pcicfgregs * pci_devlist_get_parent(pcicfgregs *cfg);
-
#ifdef _SYS_BUS_H_
#include "pci_if.h"
@@ -169,22 +163,20 @@ pcicfgregs * pci_devlist_get_parent(pcicfgregs *cfg);
#define PCI_RF_BWX 0x20000
enum pci_device_ivars {
- PCI_IVAR_SUBVENDOR,
- PCI_IVAR_SUBDEVICE,
- PCI_IVAR_VENDOR,
- PCI_IVAR_DEVICE,
- PCI_IVAR_DEVID,
- PCI_IVAR_CLASS,
- PCI_IVAR_SUBCLASS,
- PCI_IVAR_PROGIF,
- PCI_IVAR_REVID,
- PCI_IVAR_INTPIN,
- PCI_IVAR_IRQ,
- PCI_IVAR_BUS,
- PCI_IVAR_SLOT,
- PCI_IVAR_FUNCTION,
- PCI_IVAR_SECONDARYBUS,
- PCI_IVAR_SUBORDINATEBUS,
+ PCI_IVAR_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,
};
/*
@@ -194,15 +186,15 @@ enum pci_device_ivars {
\
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; \
+ uintptr_t v; \
+ BUS_READ_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, &v); \
+ return (T) v; \
} \
\
static __inline void pci_set_ ## A(device_t dev, T t) \
{ \
- uintptr_t v = (uintptr_t) t; \
- BUS_WRITE_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, v); \
+ uintptr_t v = (uintptr_t) t; \
+ BUS_WRITE_IVAR(device_get_parent(dev), dev, PCI_IVAR_ ## B, v); \
}
PCI_ACCESSOR(subvendor, SUBVENDOR, u_int16_t)
@@ -219,11 +211,12 @@ 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)
#undef PCI_ACCESSOR
+/*
+ * Operations on configuration space.
+ */
static __inline u_int32_t
pci_read_config(device_t dev, int reg, int width)
{
@@ -249,77 +242,67 @@ enum pcib_device_ivars {
\
static __inline T pcib_get_ ## A(device_t dev) \
{ \
- uintptr_t v; \
- BUS_READ_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, &v); \
- return (T) v; \
+ uintptr_t v; \
+ BUS_READ_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, &v); \
+ return (T) v; \
} \
\
static __inline void pcib_set_ ## A(device_t dev, T t) \
{ \
- uintptr_t v = (uintptr_t) t; \
- BUS_WRITE_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, v); \
+ uintptr_t v = (uintptr_t) t; \
+ BUS_WRITE_IVAR(device_get_parent(dev), dev, PCIB_IVAR_ ## B, v); \
}
PCIB_ACCESSOR(bus, BUS, u_int32_t)
#undef PCIB_ACCESSOR
-#endif
-
-/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */
-
-#if defined(_KERNEL) && !defined(KLD_MODULE)
-#include "opt_compat_oldpci.h"
-#endif
-
-#ifdef COMPAT_OLDPCI
-
-/* all this is going some day */
-
-typedef pcicfgregs *pcici_t;
-typedef unsigned pcidi_t;
-typedef void pci_inthand_t(void *arg);
+/*
+ * Convenience functions.
+ *
+ * These should be used in preference to manually manipulating
+ * configuration space.
+ */
+extern void pci_enable_busmaster(device_t dev);
+extern void pci_disable_busmaster(device_t dev);
+extern void pci_enable_io(device_t dev, int space);
+extern void pci_disable_io(device_t dev, int space);
-#define pci_max_burst_len (3)
+/*
+ * PCI power states are as defined by ACPI:
+ *
+ * D0 State in which device is on and running. It is receiving full
+ * power from the system and delivering full functionality to the user.
+ * D1 Class-specific low-power state in which device context may or may not
+ * be lost. Buses in D1 cannot do anything to the bus that would force
+ * devices on that bus to loose context.
+ * D2 Class-specific low-power state in which device context may or may
+ * not be lost. Attains greater power savings than D1. Buses in D2
+ * can cause devices on that bus to loose some context. Devices in D2
+ * must be prepared for the bus to be in D2 or higher.
+ * D3 State in which the device is off and not running. Device context is
+ * lost. Power can be removed from the device.
+ */
+#define PCI_POWERSTATE_D0 0
+#define PCI_POWERSTATE_D1 1
+#define PCI_POWERSTATE_D2 2
+#define PCI_POWERSTATE_D3 3
+#define PCI_POWERSTATE_UNKNOWN -1
-/* just copied from old PCI code for now ... */
+extern int pci_set_powerstate(device_t dev, int state);
+extern int pci_get_powerstate(device_t dev);
-struct pci_device {
- char* pd_name;
- const char* (*pd_probe ) (pcici_t tag, pcidi_t type);
- void (*pd_attach) (pcici_t tag, int unit);
- u_long *pd_count;
- int (*pd_shutdown) (int, int);
-};
+#endif /* _SYS_BUS_H_ */
-#ifdef __i386__
-typedef u_short pci_port_t;
-#else
-typedef u_int pci_port_t;
-#endif
+/*
+ * cdev switch for control device, initialised in generic PCI code
+ */
+extern struct cdevsw pcicdev;
-u_long pci_conf_read (pcici_t tag, u_long reg);
-void pci_conf_write (pcici_t tag, u_long reg, u_long data);
-int pci_map_port (pcici_t tag, u_long reg, pci_port_t* pa);
-int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa);
-int pci_map_int (pcici_t tag, pci_inthand_t *handler, void *arg,
- intrmask_t *maskptr);
-int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg,
- intrmask_t *maskptr, u_int flags);
-int pci_unmap_int (pcici_t tag);
-
-pcici_t pci_get_parent_from_tag(pcici_t tag);
-int pci_get_bus_from_tag(pcici_t tag);
-
-struct module;
-int compat_pci_handler (struct module *, int, void *);
-#define COMPAT_PCI_DRIVER(name, pcidata) \
-static moduledata_t name##_mod = { \
- #name, \
- compat_pci_handler, \
- &pcidata \
-}; \
-DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_ANY)
-#endif /* COMPAT_OLDPCI */
+/*
+ * List of all PCI devices, generation count for the list.
+ */
+STAILQ_HEAD(devlist, pci_devinfo) pci_devq;
+u_int32_t pci_generation;
#endif /* _PCIVAR_H_ */
diff --git a/sys/pci/pci_compat.c b/sys/pci/pci_compat.c
deleted file mode 100644
index 401680d..0000000
--- a/sys/pci/pci_compat.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice unmodified, this list of conditions, and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- *
- */
-
-#include "opt_bus.h"
-
-/* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
-#include <sys/bus.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <machine/resource.h>
-#include <sys/interrupt.h>
-
-#include <sys/pciio.h>
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#ifdef APIC_IO
-#include <machine/smp.h>
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-u_long
-pci_conf_read(pcici_t cfg, u_long reg)
-{
- return (pci_read_config(cfg->dev, reg, 4));
-}
-
-void
-pci_conf_write(pcici_t cfg, u_long reg, u_long data)
-{
- pci_write_config(cfg->dev, reg, data, 4);
-}
-
-int
-pci_cfgread (pcicfgregs *cfg, int reg, int bytes)
-{
- return (pci_read_config(cfg->dev, reg, bytes));
-}
-
-void
-pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes)
-{
- pci_write_config(cfg->dev, reg, data, bytes);
-}
-
-int
-pci_map_port(pcici_t cfg, u_long reg, pci_port_t* pa)
-{
- int rid;
- struct resource *res;
-
- rid = reg;
- res = bus_alloc_resource(cfg->dev, SYS_RES_IOPORT, &rid,
- 0, ~0, 1, RF_ACTIVE);
- if (res) {
- *pa = rman_get_start(res);
- return (1);
- }
- return (0);
-}
-
-int
-pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
-{
- int rid;
- struct resource *res;
-
- rid = reg;
- res = bus_alloc_resource(cfg->dev, SYS_RES_MEMORY, &rid,
- 0, ~0, 1, RF_ACTIVE);
- if (res) {
- *pa = rman_get_start(res);
- *va = (vm_offset_t) rman_get_virtual(res);
- return (1);
- }
- return (0);
-}
-
-int
-pci_map_int(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr)
-{
- return (pci_map_int_right(cfg, handler, arg, maskptr, 0));
-}
-
-int
-pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg,
- intrmask_t *maskptr, u_int intflags)
-{
- int error;
-#ifdef APIC_IO
- int nextpin, muxcnt;
-#endif
- if (cfg->intpin != 0) {
- int irq = cfg->intline;
- int rid = 0;
- struct resource *res;
- int flags = 0;
- int resflags = RF_SHAREABLE|RF_ACTIVE;
- void *ih;
-
-#ifdef INTR_FAST
- if (intflags & INTR_FAST)
- flags |= INTR_FAST;
- if (intflags & INTR_EXCL)
- resflags &= ~RF_SHAREABLE;
-#endif
-
- res = bus_alloc_resource(cfg->dev, SYS_RES_IRQ, &rid,
- irq, irq, 1, resflags);
- if (!res) {
- printf("pci_map_int: can't allocate interrupt\n");
- return 0;
- }
-
- /*
- * This is ugly. Translate the mask into an interrupt type.
- */
- if (maskptr == &tty_imask)
- flags |= INTR_TYPE_TTY;
- else if (maskptr == &bio_imask)
- flags |= INTR_TYPE_BIO;
- else if (maskptr == &net_imask)
- flags |= INTR_TYPE_NET;
- else if (maskptr == &cam_imask)
- flags |= INTR_TYPE_CAM;
-
- error = BUS_SETUP_INTR(device_get_parent(cfg->dev), cfg->dev,
- res, flags, handler, arg, &ih);
- if (error != 0)
- return 0;
-
-#ifdef NEW_BUS_PCI
- /*
- * XXX this apic stuff looks totally busted. It should
- * move to the nexus code which actually registers the
- * interrupt.
- */
-#endif
-
-#ifdef APIC_IO
- nextpin = next_apic_irq(irq);
-
- if (nextpin < 0)
- return 1;
-
- /*
- * Attempt handling of some broken mp tables.
- *
- * It's OK to yell (since the mp tables are broken).
- *
- * Hanging in the boot is not OK
- */
-
- muxcnt = 2;
- nextpin = next_apic_irq(nextpin);
- while (muxcnt < 5 && nextpin >= 0) {
- muxcnt++;
- nextpin = next_apic_irq(nextpin);
- }
- if (muxcnt >= 5) {
- printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
- return 0;
- }
-
- printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
-
- nextpin = next_apic_irq(irq);
- while (nextpin >= 0) {
- rid = 0;
- res = bus_alloc_resource(cfg->dev, SYS_RES_IRQ, &rid,
- nextpin, nextpin, 1,
- resflags);
- if (!res) {
- printf("pci_map_int: can't allocate extra interrupt\n");
- return 0;
- }
- error = BUS_SETUP_INTR(device_get_parent(cfg->dev),
- cfg->dev, res, flags,
- handler, arg, &ih);
- if (error != 0) {
- printf("pci_map_int: BUS_SETUP_INTR failed\n");
- return 0;
- }
- printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
- nextpin = next_apic_irq(nextpin);
- }
-#endif
- }
- return (1);
-}
-
-int
-pci_unmap_int(pcici_t cfg)
-{
- return (0); /* not supported, yet, since cfg doesn't know about idesc */
-}
-
-pcici_t
-pci_get_parent_from_tag(pcici_t tag)
-{
- return (pcici_t)pci_devlist_get_parent(tag);
-}
-
-int
-pci_get_bus_from_tag(pcici_t tag)
-{
- return tag->bus;
-}
-
-/*
- * 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);
- /* Allow newbus drivers to match "better" */
- error = -200;
- }
- }
-
- return error;
-}
-
-static int
-pci_compat_attach(device_t dev)
-{
- struct pci_device *dvp;
- struct pci_devinfo *dinfo;
- pcicfgregs *cfg;
- int unit;
-
- dinfo = device_get_ivars(dev);
- cfg = &dinfo->cfg;
- dvp = 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);
- device_printf(dev, "driver is using old-style compatability shims\n");
- return 0;
-}
-
-static device_method_t pci_compat_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, pci_compat_probe),
- DEVMETHOD(device_attach, pci_compat_attach),
-
- { 0, 0 }
-};
-
-/*
- * Create a new style driver around each old pci driver.
- */
-int
-compat_pci_handler(module_t mod, int type, void *data)
-{
- struct pci_device *dvp = (struct pci_device *)data;
- driver_t *driver;
- devclass_t pci_devclass = devclass_find("pci");
-
- switch (type) {
- case MOD_LOAD:
- driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (!driver)
- return ENOMEM;
- driver->name = dvp->pd_name;
- driver->methods = pci_compat_methods;
- driver->size = sizeof(struct pci_devinfo *);
- driver->priv = dvp;
- devclass_add_driver(pci_devclass, driver);
- break;
- case MOD_UNLOAD:
- printf("%s: module unload not supported!\n", dvp->pd_name);
- return EOPNOTSUPP;
- default:
- break;
- }
- return 0;
-}
OpenPOWER on IntegriCloud