[PATCH] shpchp: event handling rework

The event handler of SHPCHP driver is unnecessarily very complex. In
addition, current event handler can only a fixed number of events at
the same time, and some of events would be lost if several number of
events happened at the same time.

This patch simplify the event handler by using 'work queue', and it
also fix the above-mentioned issue.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 8b21fc2..5de659d 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -32,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/workqueue.h>
 #include "shpchp.h"
 
 /* Global variables */
@@ -39,6 +40,7 @@
 int shpchp_poll_mode;
 int shpchp_poll_time;
 LIST_HEAD(shpchp_ctrl_list);
+struct workqueue_struct *shpchp_wq;
 
 #define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -57,7 +59,6 @@
 
 #define SHPC_MODULE_NAME "shpchp"
 
-static int shpc_start_thread (void);
 static int set_attention_status (struct hotplug_slot *slot, u8 value);
 static int enable_slot		(struct hotplug_slot *slot);
 static int disable_slot		(struct hotplug_slot *slot);
@@ -141,6 +142,7 @@
 			goto error_info;
 
 		slot->number = sun;
+		INIT_WORK(&slot->work, shpchp_pushbutton_thread, slot);
 
 		/* register this slot with the hotplug pci core */
 		hotplug_slot->private = slot;
@@ -176,7 +178,7 @@
 	return retval;
 }
 
-static void cleanup_slots(struct controller *ctrl)
+void cleanup_slots(struct controller *ctrl)
 {
 	struct list_head *tmp;
 	struct list_head *next;
@@ -185,6 +187,8 @@
 	list_for_each_safe(tmp, next, &ctrl->slot_list) {
 		slot = list_entry(tmp, struct slot, slot_list);
 		list_del(&slot->slot_list);
+		cancel_delayed_work(&slot->work);
+		flush_workqueue(shpchp_wq);
 		pci_hp_deregister(slot->hotplug_slot);
 	}
 }
@@ -400,7 +404,7 @@
 	rc = get_ctlr_slot_config(ctrl);
 	if (rc) {
 		err(msg_initialization_err, rc);
-		goto err_out_unmap_mmio_region;
+		goto err_out_release_ctlr;
 	}
 	first_device_num = ctrl->slot_device_offset;
 	num_ctlr_slots = ctrl->num_slots;
@@ -411,7 +415,7 @@
 	rc = init_slots(ctrl);
 	if (rc) {
 		err(msg_initialization_err, 6);
-		goto err_out_free_ctrl_slot;
+		goto err_out_release_ctlr;
 	}
 
 	/* Now hpc_functions (slot->hpc_ops->functions) are ready  */
@@ -427,18 +431,13 @@
 		ctrl->speed = PCI_SPEED_33MHz;
 	}
 
-	/* Finish setting up the hot plug ctrl device */
-	ctrl->next_event = 0;
-
 	list_add(&ctrl->ctrl_list, &shpchp_ctrl_list);
 
 	shpchp_create_ctrl_files(ctrl);
 
 	return 0;
 
-err_out_free_ctrl_slot:
-	cleanup_slots(ctrl);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
 	ctrl->hpc_ops->release_ctlr(ctrl);
 err_out_free_ctrl:
 	kfree(ctrl);
@@ -446,21 +445,6 @@
 	return -ENODEV;
 }
 
-static int shpc_start_thread(void)
-{
-	int retval = 0;
-
-	dbg("Initialize + Start the notification/polling mechanism \n");
-
-	retval = shpchp_event_start_thread();
-	if (retval) {
-		dbg("shpchp_event_start_thread() failed\n");
-		return retval;
-	}
-
-	return retval;
-}
-
 static void __exit unload_shpchpd(void)
 {
 	struct list_head *tmp;
@@ -470,14 +454,11 @@
 	list_for_each_safe(tmp, next, &shpchp_ctrl_list) {
 		ctrl = list_entry(tmp, struct controller, ctrl_list);
 		shpchp_remove_ctrl_files(ctrl);
-		cleanup_slots(ctrl);
 		ctrl->hpc_ops->release_ctlr(ctrl);
 		kfree(ctrl);
 	}
 
-	/* Stop the notification mechanism */
-	shpchp_event_stop_thread();
-
+	destroy_workqueue(shpchp_wq);
 }
 
 static struct pci_device_id shpcd_pci_tbl[] = {
@@ -501,17 +482,15 @@
 	shpchp_poll_mode = 1;
 #endif
 
-	retval = shpc_start_thread();
-	if (retval)
-		goto error_hpc_init;
+	shpchp_wq = create_singlethread_workqueue("shpchpd");
+	if (!shpchp_wq)
+		return -ENOMEM;
 
 	retval = pci_register_driver(&shpc_driver);
 	dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
 	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
-error_hpc_init:
 	if (retval) {
-		shpchp_event_stop_thread();
+		destroy_workqueue(shpchp_wq);
 	}
 	return retval;
 }