diff options
author | Kenji Kaneshige | 2005-11-25 12:28:53 +0900 |
---|---|---|
committer | Greg Kroah-Hartman | 2006-01-09 12:13:17 -0800 |
commit | bd62e271401c5ebf33a0dd24d89baf706f213251 (patch) | |
tree | 77b8e2cd249df83b0d256f8126047a037a1fc542 /drivers/pci | |
parent | f467f6187fc60c954a9509b3a3e17ef89a4f6f22 (diff) |
[PATCH] shpchp: fix improper wait for command completion
Current SHPCHP driver uses msleep_interruptible() function to wait for
a command completion event. But I think this would cause an unnecessary
long wait until timeout, if command completion interrupt came before
task state was changed to TASK_INTERRUPTIBLE. This patch fixes this
issue. With this patch, command completion becomes faster as follows:
o Without this patch
# time echo 1 > power
real 0m4.708s
user 0m0.000s
sys 0m0.524s
o With this patch
# time echo 1 > power
real 0m2.221s
user 0m0.000s
sys 0m0.532s
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 37 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 26 |
3 files changed, 27 insertions, 37 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 55b0cd15f348..ce0e9b6ce833 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -101,6 +101,7 @@ struct controller { u32 cap_offset; unsigned long mmio_base; unsigned long mmio_size; + volatile int cmd_busy; }; struct hotplug_params { diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 58619359ad08..25ccb0e47593 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -248,7 +248,6 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, up(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } - wait_for_ctrl_irq (ctrl); if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", @@ -330,9 +329,6 @@ static int board_added(struct slot *p_slot) up(&ctrl->crit_sect); return -1; } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl); if (rc) { @@ -352,7 +348,6 @@ static int board_added(struct slot *p_slot) up(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } - wait_for_ctrl_irq (ctrl); if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", @@ -367,7 +362,6 @@ static int board_added(struct slot *p_slot) up(&ctrl->crit_sect); return rc; } - wait_for_ctrl_irq (ctrl); if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); @@ -494,7 +488,6 @@ static int board_added(struct slot *p_slot) up(&ctrl->crit_sect); return rc; } - wait_for_ctrl_irq (ctrl); if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); @@ -532,9 +525,6 @@ static int board_added(struct slot *p_slot) p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -552,8 +542,6 @@ err_exit: up(&ctrl->crit_sect); return rc; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl); if (rc) { @@ -603,8 +591,6 @@ static int remove_board(struct slot *p_slot) up(&ctrl->crit_sect); return rc; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl); if (rc) { @@ -621,8 +607,6 @@ static int remove_board(struct slot *p_slot) up(&ctrl->crit_sect); return rc; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -676,9 +660,6 @@ static void shpchp_pushbutton_thread (unsigned long slot) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - /* Done with exclusive hardware access */ up(&p_slot->ctrl->crit_sect); } @@ -790,14 +771,9 @@ static void interrupt_event_handler(struct controller *ctrl) down(&ctrl->crit_sect); p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - /* Done with exclusive hardware access */ up(&ctrl->crit_sect); break; @@ -806,12 +782,8 @@ static void interrupt_event_handler(struct controller *ctrl) down(&ctrl->crit_sect); p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -845,14 +817,9 @@ static void interrupt_event_handler(struct controller *ctrl) /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -870,12 +837,8 @@ static void interrupt_event_handler(struct controller *ctrl) down(&ctrl->crit_sect); p_slot->hpc_ops->set_attention_status(p_slot, 1); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index f25e11645071..b4226ff3a854 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) return; } +static inline int shpc_wait_cmd(struct controller *ctrl) +{ + int retval = 0; + unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; + unsigned long timeout = msecs_to_jiffies(timeout_msec); + int rc = wait_event_interruptible_timeout(ctrl->queue, + !ctrl->cmd_busy, timeout); + if (!rc) { + retval = -EIO; + err("Command not completed in %d msec\n", timeout_msec); + } else if (rc < 0) { + retval = -EINTR; + info("Command was interrupted by a signal\n"); + } + ctrl->cmd_busy = 0; + + return retval; +} + static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; @@ -314,8 +333,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) /* To make sure the Controller Busy bit is 0 before we send out the * command. */ + slot->ctrl->cmd_busy = 1; writew(temp_word, php_ctlr->creg + CMD); + /* + * Wait for command completion. + */ + retval = shpc_wait_cmd(slot->ctrl); + DBG_LEAVE_ROUTINE return retval; } @@ -1064,6 +1089,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); temp_dword &= 0xfffdffff; writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } |