Commit 6592e02a authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Jesse Barnes

pciehp: poll cmd completion if hotplug interrupt is disabled

Fix improper long wait for command completion in pciehp probing.

As described in PCI Express specification, software notification is
not generated if the command that occurs as a result of a write to the
Slot Control register that disables software notification of command
completed events. Since pciehp driver doesn't take it into account,
such command is issued in pciehp probing, and it causes improper long
wait for command completion.

This patch changes the pciehp driver to take such command into
account.
Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarKristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 5808639b
...@@ -247,13 +247,37 @@ static inline void pciehp_free_irq(struct controller *ctrl) ...@@ -247,13 +247,37 @@ static inline void pciehp_free_irq(struct controller *ctrl)
free_irq(ctrl->pci_dev->irq, ctrl); free_irq(ctrl->pci_dev->irq, ctrl);
} }
static inline int pcie_wait_cmd(struct controller *ctrl) static inline int pcie_poll_cmd(struct controller *ctrl)
{
u16 slot_status;
int timeout = 1000;
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
if (slot_status & CMD_COMPLETED)
goto completed;
for (timeout = 1000; timeout > 0; timeout -= 100) {
msleep(100);
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
if (slot_status & CMD_COMPLETED)
goto completed;
}
return 0; /* timeout */
completed:
pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
return timeout;
}
static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
{ {
int retval = 0; int retval = 0;
unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
unsigned long timeout = msecs_to_jiffies(msecs); unsigned long timeout = msecs_to_jiffies(msecs);
int rc; int rc;
if (poll)
rc = pcie_poll_cmd(ctrl);
else
rc = wait_event_interruptible_timeout(ctrl->queue, rc = wait_event_interruptible_timeout(ctrl->queue,
!ctrl->cmd_busy, timeout); !ctrl->cmd_busy, timeout);
if (!rc) if (!rc)
...@@ -331,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -331,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
/* /*
* Wait for command completion. * Wait for command completion.
*/ */
if (!retval && !ctrl->no_cmd_complete) if (!retval && !ctrl->no_cmd_complete) {
retval = pcie_wait_cmd(ctrl); int poll = 0;
/*
* if hotplug interrupt is not enabled or command
* completed interrupt is not enabled, we need to poll
* command completed event.
*/
if (!(slot_ctrl & HP_INTR_ENABLE) ||
!(slot_ctrl & CMD_CMPL_INTR_ENABLE))
poll = 1;
retval = pcie_wait_cmd(ctrl, poll);
}
out: out:
mutex_unlock(&ctrl->ctrl_lock); mutex_unlock(&ctrl->ctrl_lock);
return retval; return retval;
......
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