[PATCH] shpchp - cleanup check command status

This patch cleanups codes that check the command status. For this, it
introduces a new semaphore "cmd_sem" for each controller.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index f6d606d..b1e2a77 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -80,6 +80,7 @@
 struct controller {
 	struct list_head ctrl_list;
 	struct mutex crit_sect;		/* critical section mutex */
+	struct mutex cmd_lock;		/* command lock */
 	struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
 	int num_slots;			/* Number of slots on ctlr */
 	int slot_num_inc;		/* 1 or -1 */
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 3a8e733..802c4c4 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -242,21 +242,10 @@
 	int rc = 0;
 
 	dbg("%s: change to speed %d\n", __FUNCTION__, speed);
-	mutex_lock(&ctrl->crit_sect);
 	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
 		err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
-		mutex_unlock(&ctrl->crit_sect);
 		return WRONG_BUS_FREQUENCY;
 	}
-		
-	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",
-			  __FUNCTION__);
-		err("%s: Error code (%d)\n", __FUNCTION__, rc);
-		mutex_unlock(&ctrl->crit_sect);
-		return WRONG_BUS_FREQUENCY;
-	}
-	mutex_unlock(&ctrl->crit_sect);
 	return rc;
 }
 
@@ -330,15 +319,6 @@
 		return -1;
 	}
 	
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
-		return -1;
-	}
-
-	
 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
 		if (slots_not_empty)
 			return WRONG_BUS_FREQUENCY;
@@ -349,25 +329,12 @@
 			return WRONG_BUS_FREQUENCY;
 		}
 		
-		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",
-				  __FUNCTION__);
-			err("%s: Error code (%d)\n", __FUNCTION__, rc);
-			mutex_unlock(&ctrl->crit_sect);
-			return WRONG_BUS_FREQUENCY;
-		}
 		/* turn on board, blink green LED, turn off Amber LED */
 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
 			err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
 			mutex_unlock(&ctrl->crit_sect);
 			return rc;
 		}
-
-		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-			err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-			mutex_unlock(&ctrl->crit_sect);
-			return rc;  
-		}
 	}
  
 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
@@ -481,22 +448,12 @@
 				return rc;
 	}
 
-	mutex_lock(&ctrl->crit_sect);
 	/* turn on board, blink green LED, turn off Amber LED */
 	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
 		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
-		mutex_unlock(&ctrl->crit_sect);
 		return rc;
 	}
 
-	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-		mutex_unlock(&ctrl->crit_sect);
-		return rc;  
-	}
-
-	mutex_unlock(&ctrl->crit_sect);
-
 	/* Wait for ~1 second */
 	wait_for_ctrl_irq (ctrl);
 
@@ -520,40 +477,18 @@
 	p_slot->is_a_board = 0x01;
 	p_slot->pwr_save = 1;
 
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->crit_sect);
-
 	p_slot->hpc_ops->green_led_on(p_slot);
 
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->crit_sect);
-
 	return 0;
 
 err_exit:
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->crit_sect);
-
 	/* turn off slot, turn on Amber LED, turn off Green LED */
 	rc = p_slot->hpc_ops->slot_disable(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
 		return rc;
 	}
 
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
-		return rc;
-	}
-
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->crit_sect);
-
 	return(rc);
 }
 
@@ -580,37 +515,19 @@
 	if (p_slot->is_a_board)
 		p_slot->status = 0x01;
 
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->crit_sect);
-
 	/* turn off slot, turn on Amber LED, turn off Green LED */
 	rc = p_slot->hpc_ops->slot_disable(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
 		return rc;
 	}
-
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
-		return rc;  
-	}
 	
 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
 	if (rc) {
 		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		mutex_unlock(&ctrl->crit_sect);
 		return rc;
 	}
 
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->crit_sect);
-
 	p_slot->pwr_save = 0;
 	p_slot->is_a_board = 0;
 
@@ -654,15 +571,9 @@
 	} else {
 		p_slot->state = POWERON_STATE;
 
-		if (shpchp_enable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			mutex_lock(&p_slot->ctrl->crit_sect);
-
+		if (shpchp_enable_slot(p_slot))
 			p_slot->hpc_ops->green_led_off(p_slot);
 
-			/* Done with exclusive hardware access */
-			mutex_unlock(&p_slot->ctrl->crit_sect);
-		}
 		p_slot->state = STATIC_STATE;
 	}
 
@@ -767,27 +678,12 @@
 
 					switch (p_slot->state) {
 					case BLINKINGOFF_STATE:
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->crit_sect);
-
 						p_slot->hpc_ops->green_led_on(p_slot);
-
 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->crit_sect);
 						break;
 					case BLINKINGON_STATE:
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->crit_sect);
-
 						p_slot->hpc_ops->green_led_off(p_slot);
-
 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->crit_sect);
-
 						break;
 					default:
 						warn("Not a valid state\n");
@@ -812,17 +708,10 @@
 						info(msg_button_on, p_slot->number);
 					}
 
-					/* Wait for exclusive access to hardware */
-					mutex_lock(&ctrl->crit_sect);
-
 					/* blink green LED and turn off amber */
 					p_slot->hpc_ops->green_led_blink(p_slot);
-					
 					p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-					/* Done with exclusive hardware access */
-					mutex_unlock(&ctrl->crit_sect);
-
 					init_timer(&p_slot->task_event);
 					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
 					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -833,15 +722,8 @@
 				} else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
 					/***********POWER FAULT********************/
 					dbg("%s: power fault\n", __FUNCTION__);
-					/* Wait for exclusive access to hardware */
-					mutex_lock(&ctrl->crit_sect);
-
 					p_slot->hpc_ops->set_attention_status(p_slot, 1);
-					
 					p_slot->hpc_ops->green_led_off(p_slot);
-
-					/* Done with exclusive hardware access */
-					mutex_unlock(&ctrl->crit_sect);
 				} else {
 					/* refresh notification */
 					if (p_slot)
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index ae81427..c32a1b1 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -231,6 +231,7 @@
 static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
 
 static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static int hpc_check_cmd_status(struct controller *ctrl);
 
 /* This is the interrupt polling timeout function. */
 static void int_poll_timeout(unsigned long lphp_ctlr)
@@ -303,10 +304,13 @@
 	int i;
 
 	DBG_ENTER_ROUTINE 
-	
+
+	mutex_lock(&slot->ctrl->cmd_lock);
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
+		retval = -EINVAL;
+		goto out;
 	}
 
 	for (i = 0; i < 10; i++) {
@@ -323,7 +327,8 @@
 	if (cmd_status & 0x1) { 
 		/* After 1 sec and and the controller is still busy */
 		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
-		return -1;
+		retval = -EBUSY;
+		goto out;
 	}
 
 	++t_slot;
@@ -340,6 +345,17 @@
 	 * Wait for command completion.
 	 */
 	retval = shpc_wait_cmd(slot->ctrl);
+	if (retval)
+		goto out;
+
+	cmd_status = hpc_check_cmd_status(slot->ctrl);
+	if (cmd_status) {
+		err("%s: Failed to issued command 0x%x (error code = %d)\n",
+		    __FUNCTION__, cmd, cmd_status);
+		retval = -EIO;
+	}
+ out:
+	mutex_unlock(&slot->ctrl->cmd_lock);
 
 	DBG_LEAVE_ROUTINE 
 	return retval;
@@ -1343,7 +1359,6 @@
 	.green_led_blink		= hpc_set_green_led_blink,
 	
 	.release_ctlr			= hpc_release_ctlr,
-	.check_cmd_status		= hpc_check_cmd_status,
 };
 
 inline static int shpc_indirect_creg_read(struct controller *ctrl, int index,
@@ -1455,6 +1470,8 @@
 	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
 
 	mutex_init(&ctrl->crit_sect);
+	mutex_init(&ctrl->cmd_lock);
+
 	/* Setup wait queue */
 	init_waitqueue_head(&ctrl->queue);