aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b2cde04ede1a..6eba9b2cfb90 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot)
636 return retval; 636 return retval;
637} 637}
638 638
639static inline int pcie_mask_bad_dllp(struct controller *ctrl)
640{
641 struct pci_dev *dev = ctrl->pci_dev;
642 int pos;
643 u32 reg;
644
645 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
646 if (!pos)
647 return 0;
648 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
649 if (reg & PCI_ERR_COR_BAD_DLLP)
650 return 0;
651 reg |= PCI_ERR_COR_BAD_DLLP;
652 pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
653 return 1;
654}
655
656static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
657{
658 struct pci_dev *dev = ctrl->pci_dev;
659 u32 reg;
660 int pos;
661
662 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
663 if (!pos)
664 return;
665 pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
666 if (!(reg & PCI_ERR_COR_BAD_DLLP))
667 return;
668 reg &= ~PCI_ERR_COR_BAD_DLLP;
669 pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
670}
671
639static int hpc_power_off_slot(struct slot * slot) 672static int hpc_power_off_slot(struct slot * slot)
640{ 673{
641 struct controller *ctrl = slot->ctrl; 674 struct controller *ctrl = slot->ctrl;
642 u16 slot_cmd; 675 u16 slot_cmd;
643 u16 cmd_mask; 676 u16 cmd_mask;
644 int retval = 0; 677 int retval = 0;
678 int changed;
645 679
646 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); 680 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
647 681
682 /*
683 * Set Bad DLLP Mask bit in Correctable Error Mask
684 * Register. This is the workaround against Bad DLLP error
685 * that sometimes happens during turning power off the slot
686 * which conforms to PCI Express 1.0a spec.
687 */
688 changed = pcie_mask_bad_dllp(ctrl);
689
648 slot_cmd = POWER_OFF; 690 slot_cmd = POWER_OFF;
649 cmd_mask = PWR_CTRL; 691 cmd_mask = PWR_CTRL;
650 /* 692 /*
@@ -681,6 +723,9 @@ static int hpc_power_off_slot(struct slot * slot)
681 */ 723 */
682 msleep(1000); 724 msleep(1000);
683 725
726 if (changed)
727 pcie_unmask_bad_dllp(ctrl);
728
684 return retval; 729 return retval;
685} 730}
686 731