public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] timer clean up for i2c-keywest.c
@ 2003-07-07  7:03 Paul Mackerras
  2003-07-08 10:15 ` Benjamin Herrenschmidt
  2003-07-08 10:26 ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 5+ messages in thread
From: Paul Mackerras @ 2003-07-07  7:03 UTC (permalink / raw)
  To: greg; +Cc: linux-kernel

This patch changes i2c-keywest.c to use mod_timer instead of a
two-line sequence to compute .expires and call add_timer in 3 places.
Without this patch I get a BUG from time to time in add_timer.

Paul.

diff -urN linux-2.5/drivers/i2c/i2c-keywest.c pmac-2.5/drivers/i2c/i2c-keywest.c
--- linux-2.5/drivers/i2c/i2c-keywest.c	2003-05-07 14:25:43.000000000 +1000
+++ pmac-2.5/drivers/i2c/i2c-keywest.c	2003-06-15 13:26:59.000000000 +1000
@@ -220,10 +220,8 @@
 	spin_lock(&iface->lock);
 	del_timer(&iface->timeout_timer);
 	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-	}
+	if (iface->state != state_idle)
+		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 	spin_unlock(&iface->lock);
 	return IRQ_HANDLED;
 }
@@ -331,8 +329,7 @@
 		write_reg(reg_subaddr, command);
 
 	/* Arm timeout */
-	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-	add_timer(&iface->timeout_timer);
+	mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 
 	/* Start sending address & enable interrupt*/
 	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
@@ -421,8 +418,7 @@
 			((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
 
 		/* Arm timeout */
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
+		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 
 		/* Start sending address & enable interrupt*/
 		write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] timer clean up for i2c-keywest.c
  2003-07-07  7:03 [PATCH] timer clean up for i2c-keywest.c Paul Mackerras
@ 2003-07-08 10:15 ` Benjamin Herrenschmidt
  2003-07-08 10:26 ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 5+ messages in thread
From: Benjamin Herrenschmidt @ 2003-07-08 10:15 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Greg KH, linux-kernel mailing list

On Mon, 2003-07-07 at 09:03, Paul Mackerras wrote:
> This patch changes i2c-keywest.c to use mod_timer instead of a
> two-line sequence to compute .expires and call add_timer in 3 places.
> Without this patch I get a BUG from time to time in add_timer.

Hrm... I did a different fix for this problem in 2.4, patch
against 2.5 coming in a few minutes...

Ben.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] timer clean up for i2c-keywest.c
  2003-07-07  7:03 [PATCH] timer clean up for i2c-keywest.c Paul Mackerras
  2003-07-08 10:15 ` Benjamin Herrenschmidt
@ 2003-07-08 10:26 ` Benjamin Herrenschmidt
  2003-07-09  9:48   ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 5+ messages in thread
From: Benjamin Herrenschmidt @ 2003-07-08 10:26 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Greg KH, linux-kernel mailing list

On Mon, 2003-07-07 at 09:03, Paul Mackerras wrote:
> This patch changes i2c-keywest.c to use mod_timer instead of a
> two-line sequence to compute .expires and call add_timer in 3 places.
> Without this patch I get a BUG from time to time in add_timer.

Ok, here it is. It also remove the never used "polled" mode. The
driver is now in sync with the more up-to-date 2.4 version ;)

Sorry for not sending that earlier, I forgot about it and didn't
notice it was out of sync.

Ben.

===== drivers/i2c/i2c-keywest.c 1.2 vs edited =====
--- 1.2/drivers/i2c/i2c-keywest.c	Wed Apr 23 13:32:32 2003
+++ edited/drivers/i2c/i2c-keywest.c	Tue Jul  8 12:16:51 2003
@@ -66,8 +66,6 @@
 
 #include "i2c-keywest.h"
 
-#undef POLLED_MODE
-
 #define DBG(x...) do {\
 	if (debug > 0) \
 		printk(KERN_DEBUG "KW:" x); \
@@ -85,27 +83,6 @@
 
 static struct keywest_iface *ifaces = NULL;
 
-#ifdef POLLED_MODE
-/* This isn't fast, but will go once I implement interrupt with
- * proper timeout
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
-	int i;
-	u8 isr;
-	
-	for (i = 0; i < POLL_TIMEOUT; i++) {
-		isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-		if (isr != 0)
-			return isr;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1);
-	}
-	return isr;
-}
-#endif /* POLLED_MODE */
-
 
 static void
 do_stop(struct keywest_iface* iface, int result)
@@ -116,16 +93,17 @@
 }
 
 /* Main state machine for standard & standard sub mode */
-static void
+static int
 handle_interrupt(struct keywest_iface *iface, u8 isr)
 {
 	int ack;
+	int rearm_timer = 1;
 	
 	DBG("handle_interrupt(), got: %x, status: %x, state: %d\n",
 		isr, read_reg(reg_status), iface->state);
 	if (isr == 0 && iface->state != state_stop) {
 		do_stop(iface, -1);
-		return;
+		return rearm_timer;
 	}
 	if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
 		iface->result = -1;
@@ -196,20 +174,19 @@
 		if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
 			do_stop(iface, -1);
 		else {
+			rearm_timer = 0;
 			iface->state = state_idle;
 			write_reg(reg_control, 0x00);
 			write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
 			complete(&iface->complete);
-#endif /* POLLED_MODE */			
 		}
 		break;
 	}
 	
 	write_reg(reg_isr, isr);
-}
 
-#ifndef POLLED_MODE
+	return rearm_timer;
+}
 
 /* Interrupt handler */
 static irqreturn_t
@@ -219,8 +196,7 @@
 
 	spin_lock(&iface->lock);
 	del_timer(&iface->timeout_timer);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
+	if (handle_interrupt(iface, read_reg(reg_isr))) {
 		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
 		add_timer(&iface->timeout_timer);
 	}
@@ -235,16 +211,13 @@
 
 	DBG("timeout !\n");
 	spin_lock_irq(&iface->lock);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
+	if (handle_interrupt(iface, read_reg(reg_isr))) {
 		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
 		add_timer(&iface->timeout_timer);
 	}
 	spin_unlock(&iface->lock);
 }
 
-#endif /* POLLED_MODE */
-
 /*
  * SMBUS-type transfer entrypoint
  */
@@ -338,17 +311,7 @@
 	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 	write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-	DBG("using polled mode...\n");
-	/* State machine, to turn into an interrupt handler */
-	while(iface->state != state_idle) {
-		u8 isr = wait_interrupt(iface);
-		handle_interrupt(iface, isr);
-	}
-#else /* POLLED_MODE */
-	DBG("using interrupt mode...\n");
 	wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 	rc = iface->result;	
 	DBG("transfer done, result: %d\n", rc);
@@ -428,17 +391,7 @@
 		write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 		write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-		DBG("using polled mode...\n");
-		/* State machine, to turn into an interrupt handler */
-		while(iface->state != state_idle) {
-			u8 isr = wait_interrupt(iface);
-			handle_interrupt(iface, isr);
-		}
-#else /* POLLED_MODE */
-		DBG("using interrupt mode...\n");
 		wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 		rc = iface->result;
 		if (rc == 0)
@@ -540,8 +493,8 @@
 			*prate);
 	}
 	
-	/* Select standard sub mode */
-	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+	/* Select standard mode by default */
+	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	
 	/* Write mode */
 	write_reg(reg_mode, iface->cur_mode);
@@ -550,7 +503,6 @@
 	write_reg(reg_ier, 0x00);
 	write_reg(reg_isr, KW_I2C_IRQ_MASK);
 
-#ifndef POLLED_MODE
 	/* Request chip interrupt */	
 	rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
 	if (rc) {
@@ -559,7 +511,6 @@
 		kfree(iface);
 		return -ENODEV;
 	}
-#endif /* POLLED_MODE */
 
 	for (i=0; i<nchan; i++) {
 		struct keywest_chan* chan = &iface->channels[i];
@@ -609,19 +560,16 @@
 
 	/* Make sure we stop all activity */
 	down(&iface->sem);
-#ifndef POLLED_MODE
 	spin_lock_irq(&iface->lock);
 	while (iface->state != state_idle) {
 		spin_unlock_irq(&iface->lock);
-		schedule();
+		set_task_state(current,TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/10);
 		spin_lock_irq(&iface->lock);
 	}
-#endif /* POLLED_MODE */
 	iface->state = state_dead;
-#ifndef POLLED_MODE
 	spin_unlock_irq(&iface->lock);
 	free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
 	up(&iface->sem);
 
 	/* Release all channels */


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] timer clean up for i2c-keywest.c
  2003-07-08 10:26 ` Benjamin Herrenschmidt
@ 2003-07-09  9:48   ` Benjamin Herrenschmidt
  2003-07-10  3:56     ` Greg KH
  0 siblings, 1 reply; 5+ messages in thread
From: Benjamin Herrenschmidt @ 2003-07-09  9:48 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Greg KH, linux-kernel mailing list

On Tue, 2003-07-08 at 12:26, Benjamin Herrenschmidt wrote:
> On Mon, 2003-07-07 at 09:03, Paul Mackerras wrote:
> > This patch changes i2c-keywest.c to use mod_timer instead of a
> > two-line sequence to compute .expires and call add_timer in 3 places.
> > Without this patch I get a BUG from time to time in add_timer.
> 
> Ok, here it is. It also remove the never used "polled" mode. The
> driver is now in sync with the more up-to-date 2.4 version ;)
> 
> Sorry for not sending that earlier, I forgot about it and didn't
> notice it was out of sync.

And just in case you didn't merge it yet... Here's a version changing
the timer->expire ; add_timer() pairs into calls to mod_timer, makes
the code slighly cleaner.

Ben.

===== drivers/i2c/i2c-keywest.c 1.2 vs edited =====
--- 1.2/drivers/i2c/i2c-keywest.c	Wed Apr 23 13:32:32 2003
+++ edited/drivers/i2c/i2c-keywest.c	Wed Jul  9 11:45:34 2003
@@ -66,8 +66,6 @@
 
 #include "i2c-keywest.h"
 
-#undef POLLED_MODE
-
 #define DBG(x...) do {\
 	if (debug > 0) \
 		printk(KERN_DEBUG "KW:" x); \
@@ -85,27 +83,6 @@
 
 static struct keywest_iface *ifaces = NULL;
 
-#ifdef POLLED_MODE
-/* This isn't fast, but will go once I implement interrupt with
- * proper timeout
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
-	int i;
-	u8 isr;
-	
-	for (i = 0; i < POLL_TIMEOUT; i++) {
-		isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-		if (isr != 0)
-			return isr;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1);
-	}
-	return isr;
-}
-#endif /* POLLED_MODE */
-
 
 static void
 do_stop(struct keywest_iface* iface, int result)
@@ -116,16 +93,17 @@
 }
 
 /* Main state machine for standard & standard sub mode */
-static void
+static int
 handle_interrupt(struct keywest_iface *iface, u8 isr)
 {
 	int ack;
+	int rearm_timer = 1;
 	
 	DBG("handle_interrupt(), got: %x, status: %x, state: %d\n",
 		isr, read_reg(reg_status), iface->state);
 	if (isr == 0 && iface->state != state_stop) {
 		do_stop(iface, -1);
-		return;
+		return rearm_timer;
 	}
 	if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
 		iface->result = -1;
@@ -196,20 +174,19 @@
 		if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
 			do_stop(iface, -1);
 		else {
+			rearm_timer = 0;
 			iface->state = state_idle;
 			write_reg(reg_control, 0x00);
 			write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
 			complete(&iface->complete);
-#endif /* POLLED_MODE */			
 		}
 		break;
 	}
 	
 	write_reg(reg_isr, isr);
-}
 
-#ifndef POLLED_MODE
+	return rearm_timer;
+}
 
 /* Interrupt handler */
 static irqreturn_t
@@ -219,11 +196,8 @@
 
 	spin_lock(&iface->lock);
 	del_timer(&iface->timeout_timer);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-	}
+	if (handle_interrupt(iface, read_reg(reg_isr)))
+		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 	spin_unlock(&iface->lock);
 	return IRQ_HANDLED;
 }
@@ -235,16 +209,11 @@
 
 	DBG("timeout !\n");
 	spin_lock_irq(&iface->lock);
-	handle_interrupt(iface, read_reg(reg_isr));
-	if (iface->state != state_idle) {
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
-	}
+	if (handle_interrupt(iface, read_reg(reg_isr)))
+		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 	spin_unlock(&iface->lock);
 }
 
-#endif /* POLLED_MODE */
-
 /*
  * SMBUS-type transfer entrypoint
  */
@@ -331,24 +300,13 @@
 		write_reg(reg_subaddr, command);
 
 	/* Arm timeout */
-	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-	add_timer(&iface->timeout_timer);
+	mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 
 	/* Start sending address & enable interrupt*/
 	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 	write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-	DBG("using polled mode...\n");
-	/* State machine, to turn into an interrupt handler */
-	while(iface->state != state_idle) {
-		u8 isr = wait_interrupt(iface);
-		handle_interrupt(iface, isr);
-	}
-#else /* POLLED_MODE */
-	DBG("using interrupt mode...\n");
 	wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 	rc = iface->result;	
 	DBG("transfer done, result: %d\n", rc);
@@ -421,24 +379,13 @@
 			((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
 
 		/* Arm timeout */
-		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-		add_timer(&iface->timeout_timer);
+		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
 
 		/* Start sending address & enable interrupt*/
 		write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 		write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-#ifdef POLLED_MODE
-		DBG("using polled mode...\n");
-		/* State machine, to turn into an interrupt handler */
-		while(iface->state != state_idle) {
-			u8 isr = wait_interrupt(iface);
-			handle_interrupt(iface, isr);
-		}
-#else /* POLLED_MODE */
-		DBG("using interrupt mode...\n");
 		wait_for_completion(&iface->complete);	
-#endif /* POLLED_MODE */	
 
 		rc = iface->result;
 		if (rc == 0)
@@ -540,8 +487,8 @@
 			*prate);
 	}
 	
-	/* Select standard sub mode */
-	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+	/* Select standard mode by default */
+	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	
 	/* Write mode */
 	write_reg(reg_mode, iface->cur_mode);
@@ -550,7 +497,6 @@
 	write_reg(reg_ier, 0x00);
 	write_reg(reg_isr, KW_I2C_IRQ_MASK);
 
-#ifndef POLLED_MODE
 	/* Request chip interrupt */	
 	rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
 	if (rc) {
@@ -559,7 +505,6 @@
 		kfree(iface);
 		return -ENODEV;
 	}
-#endif /* POLLED_MODE */
 
 	for (i=0; i<nchan; i++) {
 		struct keywest_chan* chan = &iface->channels[i];
@@ -609,19 +554,16 @@
 
 	/* Make sure we stop all activity */
 	down(&iface->sem);
-#ifndef POLLED_MODE
 	spin_lock_irq(&iface->lock);
 	while (iface->state != state_idle) {
 		spin_unlock_irq(&iface->lock);
-		schedule();
+		set_task_state(current,TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/10);
 		spin_lock_irq(&iface->lock);
 	}
-#endif /* POLLED_MODE */
 	iface->state = state_dead;
-#ifndef POLLED_MODE
 	spin_unlock_irq(&iface->lock);
 	free_irq(iface->irq, iface);
-#endif /* POLLED_MODE */
 	up(&iface->sem);
 
 	/* Release all channels */


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] timer clean up for i2c-keywest.c
  2003-07-09  9:48   ` Benjamin Herrenschmidt
@ 2003-07-10  3:56     ` Greg KH
  0 siblings, 0 replies; 5+ messages in thread
From: Greg KH @ 2003-07-10  3:56 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Paul Mackerras, linux-kernel mailing list

On Wed, Jul 09, 2003 at 11:48:08AM +0200, Benjamin Herrenschmidt wrote:
> On Tue, 2003-07-08 at 12:26, Benjamin Herrenschmidt wrote:
> > On Mon, 2003-07-07 at 09:03, Paul Mackerras wrote:
> > > This patch changes i2c-keywest.c to use mod_timer instead of a
> > > two-line sequence to compute .expires and call add_timer in 3 places.
> > > Without this patch I get a BUG from time to time in add_timer.
> > 
> > Ok, here it is. It also remove the never used "polled" mode. The
> > driver is now in sync with the more up-to-date 2.4 version ;)
> > 
> > Sorry for not sending that earlier, I forgot about it and didn't
> > notice it was out of sync.
> 
> And just in case you didn't merge it yet... Here's a version changing
> the timer->expire ; add_timer() pairs into calls to mod_timer, makes
> the code slighly cleaner.

Thanks, I've applied this one.

greg k-h

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-07-10  3:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-07-07  7:03 [PATCH] timer clean up for i2c-keywest.c Paul Mackerras
2003-07-08 10:15 ` Benjamin Herrenschmidt
2003-07-08 10:26 ` Benjamin Herrenschmidt
2003-07-09  9:48   ` Benjamin Herrenschmidt
2003-07-10  3:56     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox