Commit bd62e271 authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Greg Kroah-Hartman

[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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent f467f618
...@@ -101,6 +101,7 @@ struct controller { ...@@ -101,6 +101,7 @@ struct controller {
u32 cap_offset; u32 cap_offset;
unsigned long mmio_base; unsigned long mmio_base;
unsigned long mmio_size; unsigned long mmio_size;
volatile int cmd_busy;
}; };
struct hotplug_params { struct hotplug_params {
......
...@@ -248,7 +248,6 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, ...@@ -248,7 +248,6 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(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", 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) ...@@ -330,9 +329,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return -1; return -1;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
...@@ -352,7 +348,6 @@ static int board_added(struct slot *p_slot) ...@@ -352,7 +348,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(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", 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) ...@@ -367,7 +362,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
...@@ -494,7 +488,6 @@ static int board_added(struct slot *p_slot) ...@@ -494,7 +488,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
...@@ -532,9 +525,6 @@ static int board_added(struct slot *p_slot) ...@@ -532,9 +525,6 @@ static int board_added(struct slot *p_slot)
p_slot->hpc_ops->green_led_on(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 */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
...@@ -552,8 +542,6 @@ static int board_added(struct slot *p_slot) ...@@ -552,8 +542,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
...@@ -603,8 +591,6 @@ static int remove_board(struct slot *p_slot) ...@@ -603,8 +591,6 @@ static int remove_board(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
...@@ -621,8 +607,6 @@ static int remove_board(struct slot *p_slot) ...@@ -621,8 +607,6 @@ static int remove_board(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
...@@ -676,9 +660,6 @@ static void shpchp_pushbutton_thread (unsigned long slot) ...@@ -676,9 +660,6 @@ static void shpchp_pushbutton_thread (unsigned long slot)
p_slot->hpc_ops->green_led_off(p_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 */ /* Done with exclusive hardware access */
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
} }
...@@ -790,14 +771,9 @@ static void interrupt_event_handler(struct controller *ctrl) ...@@ -790,14 +771,9 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->green_led_on(p_slot); 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); 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 */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
break; break;
...@@ -806,12 +782,8 @@ static void interrupt_event_handler(struct controller *ctrl) ...@@ -806,12 +782,8 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->green_led_off(p_slot); 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); 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 */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
...@@ -845,14 +817,9 @@ static void interrupt_event_handler(struct controller *ctrl) ...@@ -845,14 +817,9 @@ static void interrupt_event_handler(struct controller *ctrl)
/* blink green LED and turn off amber */ /* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot); 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); 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 */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
...@@ -870,12 +837,8 @@ static void interrupt_event_handler(struct controller *ctrl) ...@@ -870,12 +837,8 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->set_attention_status(p_slot, 1); 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); 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 */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
......
...@@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) ...@@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
return; 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) 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; 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) ...@@ -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 /* To make sure the Controller Busy bit is 0 before we send out the
* command. * command.
*/ */
slot->ctrl->cmd_busy = 1;
writew(temp_word, php_ctlr->creg + CMD); writew(temp_word, php_ctlr->creg + CMD);
/*
* Wait for command completion.
*/
retval = shpc_wait_cmd(slot->ctrl);
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return retval;
} }
...@@ -1064,6 +1089,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) ...@@ -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 = readl(php_ctlr->creg + SERR_INTR_ENABLE);
temp_dword &= 0xfffdffff; temp_dword &= 0xfffdffff;
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue); wake_up_interruptible(&ctrl->queue);
} }
......
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