# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.465   -> 1.466  
#	drivers/hotplug/ibmphp_hpc.c	1.2     -> 1.3    
#	drivers/hotplug/ibmphp_core.c	1.5     -> 1.6    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/07	greg@kroah.com	1.466
# IBM PCI Hotplug driver:  polling thread locking cleanup
# 
# removed a lot of bizzare polling locking logic, causing the driver to not sleep
# for 2 seconds with some locks held.  This improves userspace interaction by
# a few orders of magnitude :)
# --------------------------------------------
#
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Fri Jun  7 13:35:38 2002
+++ b/drivers/hotplug/ibmphp_core.c	Fri Jun  7 13:35:38 2002
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.2"
+#define DRIVER_VERSION	"0.3"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c
--- a/drivers/hotplug/ibmphp_hpc.c	Fri Jun  7 13:35:38 2002
+++ b/drivers/hotplug/ibmphp_hpc.c	Fri Jun  7 13:35:38 2002
@@ -3,7 +3,7 @@
  *
  * Written By: Jyoti Shah, IBM Corporation
  *
- * Copyright (c) 2001,2001 IBM Corp.
+ * Copyright (c) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -27,7 +27,6 @@
  *
  */
 
-//#include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/module.h>
@@ -35,9 +34,6 @@
 #include <linux/smp_lock.h>
 #include "ibmphp.h"
 
-#define POLL_NO		0x01
-#define POLL_YES	0x00
-
 static int to_debug = FALSE;
 #define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
 
@@ -98,19 +94,15 @@
 // if bits 20,22,25,26,27,29,30 are OFF return TRUE
 #define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
 
-// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
-#define INCREMENT_POLLCNT(i)	((i < POLL_LATCH_CNT) ? i++ : (i=0))
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
 static int ibmphp_shutdown;
 static int tid_poll;
-static int stop_polling;		// 2 values: poll, don't poll
 static struct semaphore sem_hpcaccess;	// lock access to HPC
 static struct semaphore semOperations;	// lock all operations and
 					// access to data structures
 static struct semaphore sem_exit;	// make sure polling thread goes away
-static struct semaphore sem_poll;	// make sure poll is idle 
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
@@ -141,8 +133,6 @@
 	init_MUTEX (&sem_hpcaccess);
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
-	init_MUTEX_LOCKED (&sem_poll);
-	stop_polling = POLL_YES;
 	to_debug = FALSE;
 	ibmphp_shutdown = FALSE;
 	tid_poll = 0;
@@ -710,11 +700,6 @@
 void ibmphp_lock_operations (void)
 {
 	down (&semOperations);
-	stop_polling = POLL_NO;
-	to_debug = TRUE;
-
-	/* waiting for polling to actually stop */
-	down (&sem_poll);
 }
 
 /*----------------------------------------------------------------------
@@ -723,8 +708,6 @@
 void ibmphp_unlock_operations (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
-	stop_polling = POLL_YES;
-	to_debug = FALSE;
 	up (&semOperations);
 	debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -732,34 +715,30 @@
 /*----------------------------------------------------------------------
 * Name:    poll_hpc()
 *---------------------------------------------------------------------*/
+#define POLL_LATCH_REGISTER	0
+#define POLL_SLOTS		1
+#define POLL_SLEEP		2
 static void poll_hpc (void)
 {
-	struct slot myslot, *pslot = NULL;
+	struct slot myslot;
+	struct slot *pslot = NULL;
 	struct list_head *pslotlist;
 	int rc;
+	int poll_state = POLL_LATCH_REGISTER;
 	u8 oldlatchlow = 0x00;
 	u8 curlatchlow = 0x00;
-	int pollcnt = 0;
+	int poll_count = 0;
 	u8 ctrl_count = 0x00;
 
-	debug ("poll_hpc - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	while (!ibmphp_shutdown) {
-		if (stop_polling) {
-			debug ("poll_hpc - stop_polling\n");
-			up (&sem_poll); 
-			/* to prevent deadlock */
-			if (ibmphp_shutdown)
-				break;
-			/* to make the thread sleep */
-			down (&semOperations);
-			up (&semOperations);
-			debug ("poll_hpc - after stop_polling sleep\n");
-		} else {
-			if (pollcnt) {
-				// only poll the latch register
-				oldlatchlow = curlatchlow;
+		/* try to get the lock to do some kind of harware access */
+		down (&semOperations);
 
+		switch (poll_state) {
+			case POLL_LATCH_REGISTER:
+				oldlatchlow = curlatchlow;
 				ctrl_count = 0x00;
 				list_for_each (pslotlist, &ibmphp_slot_head) {
 					if (ctrl_count >= ibmphp_get_total_controllers())
@@ -773,14 +752,16 @@
 										  &curlatchlow);
 							if (oldlatchlow != curlatchlow)
 								process_changeinlatch (oldlatchlow,
-											curlatchlow, pslot->ctrl);
+										       curlatchlow,
+										       pslot->ctrl);
 						}
 					}
 				}
-			} else {
+				poll_state = POLL_SLOTS;
+				break;
+
+			case POLL_SLOTS:
 				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (stop_polling)
-						break;
 					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
 					// make a copy of the old status
 					memcpy ((void *) &myslot, (void *) pslot,
@@ -791,31 +772,45 @@
 						process_changeinstatus (pslot, &myslot);
 				}
 
-				if (!stop_polling) {
-					ctrl_count = 0x00;
-					list_for_each (pslotlist, &ibmphp_slot_head) {
-						if (ctrl_count >= ibmphp_get_total_controllers())
-							break;
-						pslot =
-						    list_entry (pslotlist, struct slot,
-								ibm_slot_list);
-						if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-							ctrl_count++;
-							if (READ_SLOT_LATCH (pslot->ctrl))
-								rc = ibmphp_hpc_readslot (pslot,
-											  READ_SLOTLATCHLOWREG,
-											  &curlatchlow);
-						}
+				ctrl_count = 0x00;
+				list_for_each (pslotlist, &ibmphp_slot_head) {
+					if (ctrl_count >= ibmphp_get_total_controllers())
+						break;
+					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+						ctrl_count++;
+						if (READ_SLOT_LATCH (pslot->ctrl))
+							rc = ibmphp_hpc_readslot (pslot,
+										  READ_SLOTLATCHLOWREG,
+										  &curlatchlow);
 					}
 				}
-			}
-			INCREMENT_POLLCNT (pollcnt);
-			long_delay (POLL_INTERVAL_SEC * HZ);	// snooze
+				++poll_count;
+				if (poll_count >= POLL_LATCH_CNT) {
+					poll_count = 0;
+					poll_state = POLL_SLEEP;
+				}
+				break;
+
+			case POLL_SLEEP:
+				/* don't sleep with a lock on the hardware */
+				up (&semOperations);
+				long_delay (POLL_INTERVAL_SEC * HZ);
+				down (&semOperations);
+				poll_state = POLL_LATCH_REGISTER;
+				break;
 		}
+
+		/* give up the harware semaphore */
+		up (&semOperations);
+
+		/* sleep for a short time just for good measure */
+		set_current_state (TASK_INTERRUPTIBLE);
+		schedule_timeout (HZ/10);
 	}
-	up (&sem_poll);
+
 	up (&sem_exit);
-	debug ("poll_hpc - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 
@@ -1083,7 +1078,6 @@
 	// cleanup
 	free_hpc_access ();
 	ibmphp_unlock_operations ();
-	up (&sem_poll);
 	up (&sem_exit);
 
 	debug ("ibmphp_hpc_stop_poll_thread - Exit\n");
