Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/pci/pci_pci.c
Show First 20 Lines • Show All 912 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_hw_pci, OID_AUTO, enable_pcie_hp, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_pci, OID_AUTO, enable_pcie_hp, CTLFLAG_RDTUN, | ||||
&pci_enable_pcie_hp, 0, | &pci_enable_pcie_hp, 0, | ||||
"Enable support for native PCI-express HotPlug."); | "Enable support for native PCI-express HotPlug."); | ||||
static void | static void | ||||
pcib_probe_hotplug(struct pcib_softc *sc) | pcib_probe_hotplug(struct pcib_softc *sc) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
uint16_t link_sta, slot_sta; | |||||
if (!pci_enable_pcie_hp) | if (!pci_enable_pcie_hp) | ||||
return; | return; | ||||
dev = sc->dev; | dev = sc->dev; | ||||
if (pci_find_cap(dev, PCIY_EXPRESS, NULL) != 0) | if (pci_find_cap(dev, PCIY_EXPRESS, NULL) != 0) | ||||
return; | return; | ||||
if (!(pcie_read_config(dev, PCIER_FLAGS, 2) & PCIEM_FLAGS_SLOT)) | if (!(pcie_read_config(dev, PCIER_FLAGS, 2) & PCIEM_FLAGS_SLOT)) | ||||
return; | return; | ||||
sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4); | sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4); | ||||
sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_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 | * Some devices report that they have an MRL when they actually | ||||
* reexamined. Ignore hotplug on such slots for now. | * 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) | 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; | return; | ||||
} | |||||
} | |||||
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) | |||||
sc->flags |= PCIB_HOTPLUG; | sc->flags |= PCIB_HOTPLUG; | ||||
} | } | ||||
/* | /* | ||||
* Send a HotPlug command to the slot control register. If this slot | * Send a HotPlug command to the slot control register. If this slot | ||||
* uses command completion interrupts and a previous command is still | * uses command completion interrupts and a previous command is still | ||||
* in progress, then the command is dropped. Once the previous | * in progress, then the command is dropped. Once the previous | ||||
* command completes or times out, pcib_pcie_hotplug_update() will be | * 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 | * invoked to post a new command based on the slot's state at that | ||||
Show All 9 Lines | pcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask) | ||||
if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) | if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) | ||||
return; | return; | ||||
ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2); | ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2); | ||||
new = (ctl & ~mask) | val; | new = (ctl & ~mask) | val; | ||||
if (new == ctl) | if (new == ctl) | ||||
return; | return; | ||||
if (bootverbose) | |||||
device_printf(dev, "HotPlug command: %04x -> %04x\n", ctl, new); | |||||
pcie_write_config(dev, PCIER_SLOT_CTL, new, 2); | pcie_write_config(dev, PCIER_SLOT_CTL, new, 2); | ||||
if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) && | if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) && | ||||
(ctl & new) & PCIEM_SLOT_CTL_CCIE) { | (ctl & new) & PCIEM_SLOT_CTL_CCIE) { | ||||
sc->flags |= PCIB_HOTPLUG_CMD_PENDING; | sc->flags |= PCIB_HOTPLUG_CMD_PENDING; | ||||
if (!cold) | if (!cold) | ||||
callout_reset(&sc->pcie_cc_timer, hz, | callout_reset(&sc->pcie_cc_timer, hz, | ||||
pcib_pcie_cc_timeout, sc); | pcib_pcie_cc_timeout, sc); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Returns -1 if the card is fully inserted, powered, and ready for | * Returns -1 if the card is fully inserted, powered, and ready for | ||||
* access. Otherwise, returns 0. | * access. Otherwise, returns 0. | ||||
*/ | */ | ||||
static int | static int | ||||
pcib_hotplug_present(struct pcib_softc *sc) | pcib_hotplug_present(struct pcib_softc *sc) | ||||
{ | { | ||||
device_t dev; | |||||
dev = sc->dev; | |||||
/* Card must be inserted. */ | /* Card must be inserted. */ | ||||
if (!pcib_hotplug_inserted(sc)) | if (!pcib_hotplug_inserted(sc)) | ||||
return (0); | return (0); | ||||
/* | /* | ||||
* Require the Electromechanical Interlock to be engaged if | * Require the Electromechanical Interlock to be engaged if | ||||
* present. | * present. | ||||
*/ | */ | ||||
Show All 11 Lines | |||||
} | } | ||||
static void | static void | ||||
pcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask, | pcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask, | ||||
bool schedule_task) | bool schedule_task) | ||||
{ | { | ||||
bool card_inserted, ei_engaged; | 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)) == | if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) == | ||||
PCIEM_SLOT_STA_PDC) | PCIEM_SLOT_STA_PDC) | ||||
sc->flags &= ~PCIB_DETACHING; | sc->flags &= ~PCIB_DETACHING; | ||||
card_inserted = pcib_hotplug_inserted(sc); | card_inserted = pcib_hotplug_inserted(sc); | ||||
/* Turn the power indicator on if a card is inserted. */ | /* Turn the power indicator on if a card is inserted. */ | ||||
if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PIP) { | if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PIP) { | ||||
Show All 25 Lines | if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP) { | ||||
mask |= PCIEM_SLOT_CTL_EIC; | mask |= PCIEM_SLOT_CTL_EIC; | ||||
ei_engaged = (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) != 0; | ei_engaged = (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) != 0; | ||||
if (card_inserted != ei_engaged) | if (card_inserted != ei_engaged) | ||||
val |= PCIEM_SLOT_CTL_EIC; | val |= PCIEM_SLOT_CTL_EIC; | ||||
} | } | ||||
/* | /* | ||||
* Start a timer to see if the Data Link Layer times out. | * 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 | * changed on this interrupt. Stop any scheduled timer if | ||||
* the Data Link Layer is active. | * the Data Link Layer is active. | ||||
*/ | */ | ||||
if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) { | if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) { | ||||
if (card_inserted && | if (card_inserted && | ||||
!(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) && | !(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) | if (cold) | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"Data Link Layer inactive\n"); | "Data Link Layer inactive\n"); | ||||
else | else | ||||
callout_reset(&sc->pcie_dll_timer, hz, | callout_reset(&sc->pcie_dll_timer, hz, | ||||
pcib_pcie_dll_timeout, sc); | pcib_pcie_dll_timeout, sc); | ||||
} else if (sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) | } else if (sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) | ||||
callout_stop(&sc->pcie_dll_timer); | callout_stop(&sc->pcie_dll_timer); | ||||
Show All 19 Lines | pcib_pcie_intr(void *arg) | ||||
sc = arg; | sc = arg; | ||||
dev = sc->dev; | dev = sc->dev; | ||||
sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); | sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); | ||||
/* Clear the events just reported. */ | /* Clear the events just reported. */ | ||||
pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2); | 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->pcie_slot_sta & PCIEM_SLOT_STA_ABP) { | ||||
if (sc->flags & PCIB_DETACH_PENDING) { | if (sc->flags & PCIB_DETACH_PENDING) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Attention Button Pressed: Detach Cancelled\n"); | "Attention Button Pressed: Detach Cancelled\n"); | ||||
sc->flags &= ~PCIB_DETACH_PENDING; | sc->flags &= ~PCIB_DETACH_PENDING; | ||||
callout_stop(&sc->pcie_ab_timer); | callout_stop(&sc->pcie_ab_timer); | ||||
} else { | } else { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Attention Button Pressed: Detaching in 5 seconds\n"); | "Attention Button Pressed: Detaching in 5 seconds\n"); | ||||
sc->flags |= PCIB_DETACH_PENDING; | sc->flags |= PCIB_DETACH_PENDING; | ||||
callout_reset(&sc->pcie_ab_timer, 5 * hz, | callout_reset(&sc->pcie_ab_timer, 5 * hz, | ||||
pcib_pcie_ab_timeout, sc); | pcib_pcie_ab_timeout, sc); | ||||
} | } | ||||
} | } | ||||
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD) | if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD) | ||||
device_printf(dev, "Power Fault Detected\n"); | device_printf(dev, "Power Fault Detected\n"); | ||||
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSC) | if (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSC) | ||||
device_printf(dev, "MRL Sensor Changed to %s\n", | device_printf(dev, "MRL Sensor Changed to %s\n", | ||||
sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" : | sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" : | ||||
"closed"); | "closed"); | ||||
if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) | 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" : | sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" : | ||||
"empty"); | "empty"); | ||||
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC) | if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC) | ||||
pcib_pcie_hotplug_command_completed(sc); | pcib_pcie_hotplug_command_completed(sc); | ||||
if (sc->pcie_slot_sta & PCIEM_SLOT_STA_DLLSC) { | if (sc->pcie_slot_sta & PCIEM_SLOT_STA_DLLSC) { | ||||
sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); | sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, | device_printf(dev, | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | pcib_pcie_cc_timeout(void *arg) | ||||
uint16_t sta; | uint16_t sta; | ||||
sc = arg; | sc = arg; | ||||
dev = sc->dev; | dev = sc->dev; | ||||
mtx_assert(&Giant, MA_OWNED); | mtx_assert(&Giant, MA_OWNED); | ||||
sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); | sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); | ||||
if (!(sta & PCIEM_SLOT_STA_CC)) { | if (!(sta & PCIEM_SLOT_STA_CC)) { | ||||
device_printf(dev, | 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_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING); | ||||
sc->flags |= PCIB_DETACHING; | sc->flags |= PCIB_DETACHING; | ||||
pcib_pcie_hotplug_update(sc, 0, 0, true); | pcib_pcie_hotplug_update(sc, 0, 0, true); | ||||
} else { | } else { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Missed HotPlug interrupt waiting for Command Completion\n"); | "Missed HotPlug interrupt waiting for Command Completion\n"); | ||||
pcib_pcie_intr(sc); | pcib_pcie_intr(sc); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,571 Lines • Show Last 20 Lines |