Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 {
+0 −37
Original line number Original line Diff line number Diff line
@@ -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",
@@ -331,9 +330,6 @@ static int board_added(struct slot *p_slot)
		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) {
		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
@@ -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)
			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)
		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)


	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 @@ err_exit:
		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)
		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)
		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)


			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)
						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)
						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)


					/* 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)
					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);
+26 −0
Original line number Original line Diff line number Diff line
@@ -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)
	/* 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)
		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);
	}
	}