summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2016-05-17 19:48:28 +0000
committerjhb <jhb@FreeBSD.org>2016-05-17 19:48:28 +0000
commite877de95911b642940a838c49ce449fa2308e65b (patch)
tree76cf30d1c266060adc6caccd543367273b713125
parenteab5a1b232d7b52c3f39a7491ef8ed57acd7ac84 (diff)
downloadFreeBSD-src-e877de95911b642940a838c49ce449fa2308e65b.zip
FreeBSD-src-e877de95911b642940a838c49ce449fa2308e65b.tar.gz
Rework managing hotplug commands with command completions.
Previously the command completion interrupt would post any pending command immediately before pcib_pcie_hotplug_update() had been run to inspect the current status. Now, the command completion interrupt merely clears the flag and stops the timer assuming that the caller is always going to call pcib_pcie_hotplug_update() to generate the next hotplug command if one is needed. While here, fix a bug for systems with command completion where the old (existing) value was written to the slot control register instead of the new value. This fixes the complaint about a missing hotplug interrupt on my T400. Differential Revision: https://reviews.freebsd.org/D6363
-rw-r--r--sys/dev/pci/pci_pci.c64
-rw-r--r--sys/dev/pci/pcib_private.h2
2 files changed, 21 insertions, 45 deletions
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 5e14e95..afc0a08 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -874,8 +874,11 @@ pcib_probe_hotplug(struct pcib_softc *sc)
/*
* Send a HotPlug command to the slot control register. If this slot
- * uses command completion interrupts, these updates will be buffered
- * while a previous command is completing.
+ * uses command completion interrupts and a previous command is still
+ * in progress, then the command is dropped. Once the previous
+ * command completes or times out, pcib_pcie_hotplug_update() will be
+ * invoked to post a new command based on the slot's state at that
+ * time.
*/
static void
pcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask)
@@ -884,28 +887,20 @@ pcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask)
uint16_t ctl, new;
dev = sc->dev;
- if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) {
- ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
- new = (ctl & ~mask) | val;
- if (new != ctl)
- pcie_write_config(dev, PCIER_SLOT_CTL, new, 2);
+
+ if (sc->flags & PCIB_HOTPLUG_CMD_PENDING)
return;
- }
- if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) {
- sc->pcie_pending_link_ctl_val &= ~mask;
- sc->pcie_pending_link_ctl_val |= val;
- sc->pcie_pending_link_ctl_mask |= mask;
- } else {
- ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
- new = (ctl & ~mask) | val;
- if (new != ctl) {
- pcie_write_config(dev, PCIER_SLOT_CTL, ctl, 2);
- sc->flags |= PCIB_HOTPLUG_CMD_PENDING;
- if (!cold)
- callout_reset(&sc->pcie_cc_timer, hz,
- pcib_pcie_cc_timeout, sc);
- }
+ ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
+ new = (ctl & ~mask) | val;
+ if (new == ctl)
+ return;
+ pcie_write_config(dev, PCIER_SLOT_CTL, new, 2);
+ if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS)) {
+ sc->flags |= PCIB_HOTPLUG_CMD_PENDING;
+ if (!cold)
+ callout_reset(&sc->pcie_cc_timer, hz,
+ pcib_pcie_cc_timeout, sc);
}
}
@@ -913,7 +908,6 @@ static void
pcib_pcie_hotplug_command_completed(struct pcib_softc *sc)
{
device_t dev;
- uint16_t ctl, new;
dev = sc->dev;
@@ -921,23 +915,8 @@ pcib_pcie_hotplug_command_completed(struct pcib_softc *sc)
device_printf(dev, "Command Completed\n");
if (!(sc->flags & PCIB_HOTPLUG_CMD_PENDING))
return;
- if (sc->pcie_pending_link_ctl_mask != 0) {
- ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
- new = ctl & ~sc->pcie_pending_link_ctl_mask;
- new |= sc->pcie_pending_link_ctl_val;
- if (new != ctl) {
- pcie_write_config(dev, PCIER_SLOT_CTL, ctl, 2);
- if (!cold)
- callout_reset(&sc->pcie_cc_timer, hz,
- pcib_pcie_cc_timeout, sc);
- } else
- sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
- sc->pcie_pending_link_ctl_mask = 0;
- sc->pcie_pending_link_ctl_val = 0;
- } else {
- callout_stop(&sc->pcie_cc_timer);
- sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
- }
+ callout_stop(&sc->pcie_cc_timer);
+ sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
}
/*
@@ -1041,11 +1020,10 @@ pcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask,
* Interlock.
*/
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP) {
+ mask |= PCIEM_SLOT_CTL_EIC;
if (card_inserted !=
- !(sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS)) {
- mask |= PCIEM_SLOT_CTL_EIC;
+ !(sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS))
val |= PCIEM_SLOT_CTL_EIC;
- }
}
/*
diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h
index 7d43e60..2d805a9 100644
--- a/sys/dev/pci/pcib_private.h
+++ b/sys/dev/pci/pcib_private.h
@@ -134,8 +134,6 @@ struct pcib_softc
uint16_t pcie_slot_sta;
uint32_t pcie_link_cap;
uint32_t pcie_slot_cap;
- uint16_t pcie_pending_link_ctl_mask;
- uint16_t pcie_pending_link_ctl_val;
struct resource *pcie_irq;
void *pcie_ihand;
struct task pcie_hp_task;
OpenPOWER on IntegriCloud