Commit 3461a068 authored by Bjorn Helgaas's avatar Bjorn Helgaas

PCI: pciehp: Wait for hotplug command completion lazily

Previously we issued a hotplug command and waited for it to complete.  But
there's no need to wait until we're ready to issue the *next* command.  The
next command will probably be much later, so the first one may have already
completed and we may not have to actually wait at all.

Because of hardware errata, some controllers generate command completion
events for some commands but not others.  In the case of Intel CF118 (see
spec update reference), the controller indicates command completion only
for Slot Control writes that change the value of the following bits:

  Power Controller Control
  Power Indicator Control
  Attention Indicator Control
  Electromechanical Interlock Control

Changes to other bits, e.g., the interrupt enable bits, do not cause the
Command Completed bit to be set.  Controllers from AMD and Nvidia are
reported to have similar errata.

These errata cause timeouts when pcie_enable_notification() enables
interrupts.  Previously that timeout occurred at boot-time.  With this
change, the timeout occurs later, when we change the state of the slot
power, indicators, or interlock.  This speeds up boot but causes a timeout
at the first hotplug event on the slot.  Subsequent events don't timeout
because only the first (boot-time) hotplug command updates Slot Control
without touching the power/indicator/interlock controls.

Link: http://www.intel.com/content/www/us/en/processors/xeon/xeon-e7-v2-spec-update.html
Tested-by: Rajat Jain <rajatxjain@gmail.com>	(IDT 807a controller)
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarYinghai Lu <yinghai@kernel.org>
parent 4283c70e
...@@ -168,6 +168,9 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -168,6 +168,9 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
mutex_lock(&ctrl->ctrl_lock); mutex_lock(&ctrl->ctrl_lock);
/* Wait for any previous command that might still be in progress */
pcie_wait_cmd(ctrl);
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (slot_status & PCI_EXP_SLTSTA_CC) { if (slot_status & PCI_EXP_SLTSTA_CC) {
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
...@@ -200,10 +203,6 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -200,10 +203,6 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl);
ctrl->slot_ctrl = slot_ctrl; ctrl->slot_ctrl = slot_ctrl;
/*
* Wait for command completion.
*/
pcie_wait_cmd(ctrl);
mutex_unlock(&ctrl->ctrl_lock); mutex_unlock(&ctrl->ctrl_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment