Skip to content

Commit

Permalink
pciehp: workaround against Bad DLLP during power off
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kenji Kaneshige authored and Greg Kroah-Hartman committed Feb 1, 2008
1 parent 8bb7c7a commit f1050a3
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions drivers/pci/hotplug/pciehp_hpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot)
return retval;
}

static inline int pcie_mask_bad_dllp(struct controller *ctrl)
{
struct pci_dev *dev = ctrl->pci_dev;
int pos;
u32 reg;

pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return 0;
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
if (reg & PCI_ERR_COR_BAD_DLLP)
return 0;
reg |= PCI_ERR_COR_BAD_DLLP;
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
return 1;
}

static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
{
struct pci_dev *dev = ctrl->pci_dev;
u32 reg;
int pos;

pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return;
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
if (!(reg & PCI_ERR_COR_BAD_DLLP))
return;
reg &= ~PCI_ERR_COR_BAD_DLLP;
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
}

static int hpc_power_off_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
int retval = 0;
int changed;

dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);

/*
* Set Bad DLLP Mask bit in Correctable Error Mask
* Register. This is the workaround against Bad DLLP error
* that sometimes happens during turning power off the slot
* which conforms to PCI Express 1.0a spec.
*/
changed = pcie_mask_bad_dllp(ctrl);

slot_cmd = POWER_OFF;
cmd_mask = PWR_CTRL;
/*
Expand Down Expand Up @@ -681,6 +723,9 @@ static int hpc_power_off_slot(struct slot * slot)
*/
msleep(1000);

if (changed)
pcie_unmask_bad_dllp(ctrl);

return retval;
}

Expand Down

0 comments on commit f1050a3

Please sign in to comment.