Index: head/sys/dev/pci/pci_pci.c =================================================================== --- head/sys/dev/pci/pci_pci.c +++ head/sys/dev/pci/pci_pci.c @@ -918,6 +918,7 @@ pcib_probe_hotplug(struct pcib_softc *sc) { device_t dev; + uint16_t link_sta, slot_sta; if (!pci_enable_pcie_hp) return; @@ -932,15 +933,29 @@ sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4); sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_CAP, 4); + if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) == 0) + return; + /* - * XXX: Handling of slots with a power controller needs to be - * reexamined. Ignore hotplug on such slots for now. + * Some devices report that they have an MRL when they actually + * do not. Since they always report that the MRL is open, child + * devices would be ignored. Try to detect these devices and + * ignore their claim of HotPlug support. + * + * If there is an open MRL but the Data Link Layer is active, + * the MRL is not real. */ - if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP) - return; - - if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) - sc->flags |= PCIB_HOTPLUG; + if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP) != 0 && + (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) != 0) { + link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); + slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); + if ((slot_sta & PCIEM_SLOT_STA_MRLSS) != 0 && + (link_sta & PCIEM_LINK_STA_DL_ACTIVE) != 0) { + return; + } + } + + sc->flags |= PCIB_HOTPLUG; } /* @@ -966,6 +981,8 @@ new = (ctl & ~mask) | val; if (new == ctl) return; + if (bootverbose) + device_printf(dev, "HotPlug command: %04x -> %04x\n", ctl, new); pcie_write_config(dev, PCIER_SLOT_CTL, new, 2); if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) && (ctl & new) & PCIEM_SLOT_CTL_CCIE) { @@ -1028,9 +1045,6 @@ static int pcib_hotplug_present(struct pcib_softc *sc) { - device_t dev; - - dev = sc->dev; /* Card must be inserted. */ if (!pcib_hotplug_inserted(sc)) @@ -1059,7 +1073,7 @@ { bool card_inserted, ei_engaged; - /* Clear DETACHING if Present Detect has cleared. */ + /* Clear DETACHING if Presence Detect has cleared. */ if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) == PCIEM_SLOT_STA_PDC) sc->flags &= ~PCIB_DETACHING; @@ -1101,14 +1115,15 @@ /* * Start a timer to see if the Data Link Layer times out. - * Note that we only start the timer if Presence Detect + * Note that we only start the timer if Presence Detect or MRL Sensor * changed on this interrupt. Stop any scheduled timer if * the Data Link Layer is active. */ if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) { if (card_inserted && !(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) && - sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) { + sc->pcie_slot_sta & + (PCIEM_SLOT_STA_MRLSC | PCIEM_SLOT_STA_PDC)) { if (cold) device_printf(sc->dev, "Data Link Layer inactive\n"); @@ -1144,6 +1159,10 @@ /* Clear the events just reported. */ pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2); + if (bootverbose) + device_printf(dev, "HotPlug interrupt: %#x\n", + sc->pcie_slot_sta); + if (sc->pcie_slot_sta & PCIEM_SLOT_STA_ABP) { if (sc->flags & PCIB_DETACH_PENDING) { device_printf(dev, @@ -1165,7 +1184,7 @@ sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" : "closed"); if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) - device_printf(dev, "Present Detect Changed to %s\n", + device_printf(dev, "Presence Detect Changed to %s\n", sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" : "empty"); if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC) @@ -1234,7 +1253,7 @@ sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); if (!(sta & PCIEM_SLOT_STA_CC)) { device_printf(dev, - "Hotplug Command Timed Out - forcing detach\n"); + "HotPlug Command Timed Out - forcing detach\n"); sc->flags &= ~(PCIB_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING); sc->flags |= PCIB_DETACHING; pcib_pcie_hotplug_update(sc, 0, 0, true);