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>

authored by Kenji Kaneshige and committed by Greg Kroah-Hartman f1050a35 8bb7c7af

+45
+45
drivers/pci/hotplug/pciehp_hpc.c
··· 636 636 return retval; 637 637 } 638 638 639 + static 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 + 656 + static 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 + 639 672 static int hpc_power_off_slot(struct slot * slot) 640 673 { 641 674 struct controller *ctrl = slot->ctrl; 642 675 u16 slot_cmd; 643 676 u16 cmd_mask; 644 677 int retval = 0; 678 + int changed; 645 679 646 680 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); 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); 647 689 648 690 slot_cmd = POWER_OFF; 649 691 cmd_mask = PWR_CTRL; ··· 722 680 * removed from the slot/adapter. 723 681 */ 724 682 msleep(1000); 683 + 684 + if (changed) 685 + pcie_unmask_bad_dllp(ctrl); 725 686 726 687 return retval; 727 688 }