aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_hpc.c
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2007-12-20 05:45:09 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 18:04:28 -0500
commitf1050a35cd99d6cfded7ce1273757dca84e92f9b (patch)
treecff53ccb259acaae0fe25f3caf396cc5df6426a7 /drivers/pci/hotplug/pciehp_hpc.c
parent8bb7c7af1ff2a9e9e0936dbdd15901c80329c7af (diff)
pciehp: workaround against Bad DLLP during power off
Set Bad DLLP Mask bit in Correctable Error Mask Register during turning power off the slot. This is the workaround against Bad DLLP error that sometimes happen during turning power off on the slot which conforms to PCI Express 1.0a spec. The cause of this error seems that PCI Express 1.0a spec doesn't have the following consideration that was added to PCI Express 1.1 spec. "If the port is associated with a hot-pluggable slot (Hot-Plug Capable bit in the Slot Capabilities register set to 1b), and Power Controller Control bit in Slot Control register is 1b(Off), then any transition to DL Inactive must not be considered an error." Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-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