|
@@ -389,13 +389,27 @@ void pciehp_get_latch_status(struct slot *slot, u8 *status)
|
|
|
*status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
|
|
|
}
|
|
|
|
|
|
-void pciehp_get_adapter_status(struct slot *slot, u8 *status)
|
|
|
+bool pciehp_card_present(struct controller *ctrl)
|
|
|
{
|
|
|
- struct pci_dev *pdev = ctrl_dev(slot->ctrl);
|
|
|
+ struct pci_dev *pdev = ctrl_dev(ctrl);
|
|
|
u16 slot_status;
|
|
|
|
|
|
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
|
|
|
- *status = !!(slot_status & PCI_EXP_SLTSTA_PDS);
|
|
|
+ return slot_status & PCI_EXP_SLTSTA_PDS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pciehp_card_present_or_link_active() - whether given slot is occupied
|
|
|
+ * @ctrl: PCIe hotplug controller
|
|
|
+ *
|
|
|
+ * Unlike pciehp_card_present(), which determines presence solely from the
|
|
|
+ * Presence Detect State bit, this helper also returns true if the Link Active
|
|
|
+ * bit is set. This is a concession to broken hotplug ports which hardwire
|
|
|
+ * Presence Detect State to zero, such as Wilocity's [1ae9:0200].
|
|
|
+ */
|
|
|
+bool pciehp_card_present_or_link_active(struct controller *ctrl)
|
|
|
+{
|
|
|
+ return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl);
|
|
|
}
|
|
|
|
|
|
int pciehp_query_power_fault(struct slot *slot)
|
|
@@ -858,7 +872,7 @@ struct controller *pcie_init(struct pcie_device *dev)
|
|
|
{
|
|
|
struct controller *ctrl;
|
|
|
u32 slot_cap, link_cap;
|
|
|
- u8 occupied, poweron;
|
|
|
+ u8 poweron;
|
|
|
struct pci_dev *pdev = dev->port;
|
|
|
|
|
|
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
|
|
@@ -918,9 +932,8 @@ struct controller *pcie_init(struct pcie_device *dev)
|
|
|
* requested yet, so avoid triggering a notification with this command.
|
|
|
*/
|
|
|
if (POWER_CTRL(ctrl)) {
|
|
|
- pciehp_get_adapter_status(ctrl->slot, &occupied);
|
|
|
pciehp_get_power_status(ctrl->slot, &poweron);
|
|
|
- if (!occupied && poweron) {
|
|
|
+ if (!pciehp_card_present_or_link_active(ctrl) && poweron) {
|
|
|
pcie_disable_notification(ctrl);
|
|
|
pciehp_power_off_slot(ctrl->slot);
|
|
|
}
|