Browse Source

[PATCH] s390: ctc driver fixes

Jeff,
sorry if I have flooded your inbox, I had some problems with the
mail server here yesterday, but it seems to be fixed ...
Ok patch 3-4 have no dependencies on patch 2 since only qeth driver is
affected.Thus I have made a new patch 2 for ctc driver.
Thank you .

[patch 2/4] s390: ctc driver fixes

From: Peter Tiedemann <ptiedem@de.ibm.com>
	- race condition fixed
	- minor cleanup

Signed-off-by: Peter Tiedemann <ptiedem@de.ibm.com>
Signed-off-by: Frank Pavlic <pavlic@de.ibm.com>

diffstat:
 ctcmain.c |   41 ++++++++++++++++++++++-------------------
 1 files changed, 22 insertions(+), 19 deletions(-)
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Frank Pavlic 19 years ago
parent
commit
e172577da0
1 changed files with 22 additions and 19 deletions
  1. 22 19
      drivers/s390/net/ctcmain.c

+ 22 - 19
drivers/s390/net/ctcmain.c

@@ -1,5 +1,5 @@
 /*
 /*
- * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $
+ * $Id: ctcmain.c,v 1.78 2005/09/07 12:18:02 pavlic Exp $
  *
  *
  * CTC / ESCON network driver
  * CTC / ESCON network driver
  *
  *
@@ -37,10 +37,9 @@
  * along with this program; if not, write to the Free Software
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.78 $
  *
  *
  */
  */
-
 #undef DEBUG
 #undef DEBUG
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
@@ -135,7 +134,7 @@ static const char *dev_event_names[] = {
 	"TX down",
 	"TX down",
 	"Restart",
 	"Restart",
 };
 };
-
+
 /**
 /**
  * Events of the channel statemachine
  * Events of the channel statemachine
  */
  */
@@ -249,7 +248,7 @@ static void
 print_banner(void)
 print_banner(void)
 {
 {
 	static int printed = 0;
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.74 $";
+	char vbuf[] = "$Revision: 1.78 $";
 	char *version = vbuf;
 	char *version = vbuf;
 
 
 	if (printed)
 	if (printed)
@@ -334,7 +333,7 @@ static const char *ch_state_names[] = {
 	"Restarting",
 	"Restarting",
 	"Not operational",
 	"Not operational",
 };
 };
-
+
 #ifdef DEBUG
 #ifdef DEBUG
 /**
 /**
  * Dump header and first 16 bytes of an sk_buff for debugging purposes.
  * Dump header and first 16 bytes of an sk_buff for debugging purposes.
@@ -671,7 +670,7 @@ static void
 fsm_action_nop(fsm_instance * fi, int event, void *arg)
 fsm_action_nop(fsm_instance * fi, int event, void *arg)
 {
 {
 }
 }
-
+
 /**
 /**
  * Actions for channel - statemachines.
  * Actions for channel - statemachines.
  *****************************************************************************/
  *****************************************************************************/
@@ -1514,7 +1513,6 @@ ch_action_reinit(fsm_instance *fi, int event, void *arg)
  	fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev);
  	fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev);
 }
 }
 
 
-
 /**
 /**
  * The statemachine for a channel.
  * The statemachine for a channel.
  */
  */
@@ -1625,7 +1623,7 @@ static const fsm_node ch_fsm[] = {
 };
 };
 
 
 static const int CH_FSM_LEN = sizeof (ch_fsm) / sizeof (fsm_node);
 static const int CH_FSM_LEN = sizeof (ch_fsm) / sizeof (fsm_node);
-
+
 /**
 /**
  * Functions related to setup and device detection.
  * Functions related to setup and device detection.
  *****************************************************************************/
  *****************************************************************************/
@@ -1976,7 +1974,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 		fsm_event(ch->fsm, CH_EVENT_IRQ, ch);
 		fsm_event(ch->fsm, CH_EVENT_IRQ, ch);
 
 
 }
 }
-
+
 /**
 /**
  * Actions for interface - statemachine.
  * Actions for interface - statemachine.
  *****************************************************************************/
  *****************************************************************************/
@@ -2209,13 +2207,18 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
 	int rc = 0;
 	int rc = 0;
 
 
 	DBF_TEXT(trace, 5, __FUNCTION__);
 	DBF_TEXT(trace, 5, __FUNCTION__);
+	/* we need to acquire the lock for testing the state
+	 * otherwise we can have an IRQ changing the state to 
+	 * TXIDLE after the test but before acquiring the lock.
+	 */
+	spin_lock_irqsave(&ch->collect_lock, saveflags);
 	if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
 	if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
 		int l = skb->len + LL_HEADER_LENGTH;
 		int l = skb->len + LL_HEADER_LENGTH;
 
 
-		spin_lock_irqsave(&ch->collect_lock, saveflags);
-		if (ch->collect_len + l > ch->max_bufsize - 2)
-			rc = -EBUSY;
-		else {
+		if (ch->collect_len + l > ch->max_bufsize - 2) {
+			spin_unlock_irqrestore(&ch->collect_lock, saveflags);
+			return -EBUSY;
+		} else {
 			atomic_inc(&skb->users);
 			atomic_inc(&skb->users);
 			header.length = l;
 			header.length = l;
 			header.type = skb->protocol;
 			header.type = skb->protocol;
@@ -2231,7 +2234,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
 		int ccw_idx;
 		int ccw_idx;
 		struct sk_buff *nskb;
 		struct sk_buff *nskb;
 		unsigned long hi;
 		unsigned long hi;
-
+		spin_unlock_irqrestore(&ch->collect_lock, saveflags);
 		/**
 		/**
 		 * Protect skb against beeing free'd by upper
 		 * Protect skb against beeing free'd by upper
 		 * layers.
 		 * layers.
@@ -2256,6 +2259,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
 			if (!nskb) {
 			if (!nskb) {
 				atomic_dec(&skb->users);
 				atomic_dec(&skb->users);
 				skb_pull(skb, LL_HEADER_LENGTH + 2);
 				skb_pull(skb, LL_HEADER_LENGTH + 2);
+				ctc_clear_busy(ch->netdev);
 				return -ENOMEM;
 				return -ENOMEM;
 			} else {
 			} else {
 				memcpy(skb_put(nskb, skb->len),
 				memcpy(skb_put(nskb, skb->len),
@@ -2281,6 +2285,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
 				 */
 				 */
 				atomic_dec(&skb->users);
 				atomic_dec(&skb->users);
 				skb_pull(skb, LL_HEADER_LENGTH + 2);
 				skb_pull(skb, LL_HEADER_LENGTH + 2);
+				ctc_clear_busy(ch->netdev);
 				return -EBUSY;
 				return -EBUSY;
 			}
 			}
 
 
@@ -2327,9 +2332,10 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
 		}
 		}
 	}
 	}
 
 
+	ctc_clear_busy(ch->netdev);
 	return rc;
 	return rc;
 }
 }
-
+
 /**
 /**
  * Interface API for upper network layers
  * Interface API for upper network layers
  *****************************************************************************/
  *****************************************************************************/
@@ -2421,7 +2427,6 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
 	dev->trans_start = jiffies;
 	dev->trans_start = jiffies;
 	if (transmit_skb(privptr->channel[WRITE], skb) != 0)
 	if (transmit_skb(privptr->channel[WRITE], skb) != 0)
 		rc = 1;
 		rc = 1;
-	ctc_clear_busy(dev);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -2610,7 +2615,6 @@ stats_write(struct device *dev, struct device_attribute *attr, const char *buf,
 	return count;
 	return count;
 }
 }
 
 
-
 static void
 static void
 ctc_netdev_unregister(struct net_device * dev)
 ctc_netdev_unregister(struct net_device * dev)
 {
 {
@@ -2685,7 +2689,6 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b
 	return count;
 	return count;
 }
 }
 
 
-
 static ssize_t
 static ssize_t
 ctc_type_show(struct device *dev, struct device_attribute *attr, char *buf)
 ctc_type_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {