summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r--sys/dev/pci/pci.c120
1 files changed, 86 insertions, 34 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index ebde142..8b1a283 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -585,12 +585,24 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
case PCIM_HDRTYPE_NORMAL:
cfg->subvendor = REG(PCIR_SUBVEND_0, 2);
cfg->subdevice = REG(PCIR_SUBDEV_0, 2);
+ cfg->mingnt = REG(PCIR_MINGNT, 1);
+ cfg->maxlat = REG(PCIR_MAXLAT, 1);
cfg->nummaps = PCI_MAXMAPS_0;
break;
case PCIM_HDRTYPE_BRIDGE:
+ cfg->bridge.br_seclat = REG(PCIR_SECLAT_1, 1);
+ cfg->bridge.br_subbus = REG(PCIR_SUBBUS_1, 1);
+ cfg->bridge.br_secbus = REG(PCIR_SECBUS_1, 1);
+ cfg->bridge.br_pribus = REG(PCIR_PRIBUS_1, 1);
+ cfg->bridge.br_control = REG(PCIR_BRIDGECTL_1, 2);
cfg->nummaps = PCI_MAXMAPS_1;
break;
case PCIM_HDRTYPE_CARDBUS:
+ cfg->bridge.br_seclat = REG(PCIR_SECLAT_2, 1);
+ cfg->bridge.br_subbus = REG(PCIR_SUBBUS_2, 1);
+ cfg->bridge.br_secbus = REG(PCIR_SECBUS_2, 1);
+ cfg->bridge.br_pribus = REG(PCIR_PRIBUS_2, 1);
+ cfg->bridge.br_control = REG(PCIR_BRIDGECTL_2, 2);
cfg->subvendor = REG(PCIR_SUBVEND_2, 2);
cfg->subdevice = REG(PCIR_SUBDEV_2, 2);
cfg->nummaps = PCI_MAXMAPS_2;
@@ -637,9 +649,6 @@ pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
cfg->intpin = REG(PCIR_INTPIN, 1);
cfg->intline = REG(PCIR_INTLINE, 1);
- cfg->mingnt = REG(PCIR_MINGNT, 1);
- cfg->maxlat = REG(PCIR_MAXLAT, 1);
-
cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
cfg->hdrtype &= ~PCIM_MFDEV;
STAILQ_INIT(&cfg->maps);
@@ -4360,9 +4369,17 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
*result = cfg->cachelnsz;
break;
case PCI_IVAR_MINGNT:
+ if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+ *result = -1;
+ return (EINVAL);
+ }
*result = cfg->mingnt;
break;
case PCI_IVAR_MAXLAT:
+ if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+ *result = -1;
+ return (EINVAL);
+ }
*result = cfg->maxlat;
break;
case PCI_IVAR_LATTIMER:
@@ -4931,16 +4948,6 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
{
/*
- * Only do header type 0 devices. Type 1 devices are bridges,
- * which we know need special treatment. Type 2 devices are
- * cardbus bridges which also require special treatment.
- * Other types are unknown, and we err on the side of safety
- * by ignoring them.
- */
- if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
- return;
-
- /*
* Restore the device to full power mode. We must do this
* before we restore the registers because moving from D3 to
* D0 will cause the chip's BARs and some other registers to
@@ -4950,16 +4957,44 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
*/
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
- pci_restore_bars(dev);
pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
- pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
- pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1);
pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1);
pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
+ switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_NORMAL:
+ pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
+ pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
+ break;
+ case PCIM_HDRTYPE_BRIDGE:
+ pci_write_config(dev, PCIR_SECLAT_1,
+ dinfo->cfg.bridge.br_seclat, 1);
+ pci_write_config(dev, PCIR_SUBBUS_1,
+ dinfo->cfg.bridge.br_subbus, 1);
+ pci_write_config(dev, PCIR_SECBUS_1,
+ dinfo->cfg.bridge.br_secbus, 1);
+ pci_write_config(dev, PCIR_PRIBUS_1,
+ dinfo->cfg.bridge.br_pribus, 1);
+ pci_write_config(dev, PCIR_BRIDGECTL_1,
+ dinfo->cfg.bridge.br_control, 2);
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ pci_write_config(dev, PCIR_SECLAT_2,
+ dinfo->cfg.bridge.br_seclat, 1);
+ pci_write_config(dev, PCIR_SUBBUS_2,
+ dinfo->cfg.bridge.br_subbus, 1);
+ pci_write_config(dev, PCIR_SECBUS_2,
+ dinfo->cfg.bridge.br_secbus, 1);
+ pci_write_config(dev, PCIR_PRIBUS_2,
+ dinfo->cfg.bridge.br_pribus, 1);
+ pci_write_config(dev, PCIR_BRIDGECTL_2,
+ dinfo->cfg.bridge.br_control, 2);
+ break;
+ }
+ pci_restore_bars(dev);
/*
* Restore extended capabilities for PCI-Express and PCI-X
@@ -5028,40 +5063,57 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
int ps;
/*
- * Only do header type 0 devices. Type 1 devices are bridges, which
- * we know need special treatment. Type 2 devices are cardbus bridges
- * which also require special treatment. Other types are unknown, and
- * we err on the side of safety by ignoring them. Powering down
- * bridges should not be undertaken lightly.
- */
- if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
- return;
-
- /*
* Some drivers apparently write to these registers w/o updating our
* cached copy. No harm happens if we update the copy, so do so here
* so we can restore them. The COMMAND register is modified by the
* bus w/o updating the cache. This should represent the normally
- * writable portion of the 'defined' part of type 0 headers. In
- * theory we also need to save/restore the PCI capability structures
- * we know about, but apart from power we don't know any that are
- * writable.
+ * writable portion of the 'defined' part of type 0/1/2 headers.
*/
- dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
- dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
dinfo->cfg.vendor = pci_read_config(dev, PCIR_VENDOR, 2);
dinfo->cfg.device = pci_read_config(dev, PCIR_DEVICE, 2);
dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2);
dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1);
dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1);
- dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
- dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
dinfo->cfg.baseclass = pci_read_config(dev, PCIR_CLASS, 1);
dinfo->cfg.subclass = pci_read_config(dev, PCIR_SUBCLASS, 1);
dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1);
dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1);
+ switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_NORMAL:
+ dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+ dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+ dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
+ dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
+ break;
+ case PCIM_HDRTYPE_BRIDGE:
+ dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+ PCIR_SECLAT_1, 1);
+ dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+ PCIR_SUBBUS_1, 1);
+ dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+ PCIR_SECBUS_1, 1);
+ dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+ PCIR_PRIBUS_1, 1);
+ dinfo->cfg.bridge.br_control = pci_read_config(dev,
+ PCIR_BRIDGECTL_1, 2);
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+ PCIR_SECLAT_2, 1);
+ dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+ PCIR_SUBBUS_2, 1);
+ dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+ PCIR_SECBUS_2, 1);
+ dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+ PCIR_PRIBUS_2, 1);
+ dinfo->cfg.bridge.br_control = pci_read_config(dev,
+ PCIR_BRIDGECTL_2, 2);
+ dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_2, 2);
+ dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_2, 2);
+ break;
+ }
if (dinfo->cfg.pcie.pcie_location != 0)
pci_cfg_save_pcie(dev, dinfo);
OpenPOWER on IntegriCloud