PCI: pciehp: Disable link notification across slot reset
authorRajat Jain <rajatxjain@gmail.com>
Wed, 5 Feb 2014 02:30:40 +0000 (18:30 -0800)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 11 Feb 2014 23:13:01 +0000 (16:13 -0700)
Disable the link notification (in addition to presence detect
notifications) across the slot reset since the reset could flap the link,
and we don't want to treat it as hot unplug followed by a hotplug.

Signed-off-by: Rajat Jain <rajatxjain@gmail.com>
Signed-off-by: Rajat Jain <rajatjain@juniper.net>
Signed-off-by: Guenter Roeck <groeck@juniper.net>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/hotplug/pciehp_hpc.c

index 15ca3a1cad8d4015720809ea8eb6bcf71727ce61..6433e73aa2df3eaf66c86a816cb2529cdb21c957 100644 (file)
@@ -619,33 +619,37 @@ static void pcie_disable_notification(struct controller *ctrl)
 
 /*
  * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
- * bus reset of the bridge, but if the slot supports surprise removal we need
- * to disable presence detection around the bus reset and clear any spurious
+ * bus reset of the bridge, but if the slot supports surprise removal (or
+ * link state change based hotplug), we need to disable presence detection
+ * (or link state notifications) around the bus reset and clear any spurious
  * events after.
  */
 int pciehp_reset_slot(struct slot *slot, int probe)
 {
        struct controller *ctrl = slot->ctrl;
        struct pci_dev *pdev = ctrl_dev(ctrl);
+       u16 stat_mask = 0, ctrl_mask = 0;
 
        if (probe)
                return 0;
 
-       if (HP_SUPR_RM(ctrl)) {
-               pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
-               if (pciehp_poll_mode)
-                       del_timer_sync(&ctrl->poll_timer);
+       if (HP_SUPR_RM(ctrl) && !ATTN_BUTTN(ctrl)) {
+               ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
+               stat_mask |= PCI_EXP_SLTSTA_PDC;
        }
+       ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
+       stat_mask |= PCI_EXP_SLTSTA_DLLSC;
+
+       pcie_write_cmd(ctrl, 0, ctrl_mask);
+       if (pciehp_poll_mode)
+               del_timer_sync(&ctrl->poll_timer);
 
        pci_reset_bridge_secondary_bus(ctrl->pcie->port);
 
-       if (HP_SUPR_RM(ctrl)) {
-               pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
-                                          PCI_EXP_SLTSTA_PDC);
-               pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
-               if (pciehp_poll_mode)
-                       int_poll_timeout(ctrl->poll_timer.data);
-       }
+       pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
+       pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
+       if (pciehp_poll_mode)
+               int_poll_timeout(ctrl->poll_timer.data);
 
        return 0;
 }