patch-2.4.22 linux-2.4.22/drivers/s390/net/ctctty.c

Next file: linux-2.4.22/drivers/s390/net/fsm.h
Previous file: linux-2.4.22/drivers/s390/net/ctcmain.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/s390/net/ctctty.c linux-2.4.22/drivers/s390/net/ctctty.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $
+ * $Id: ctctty.c,v 1.11 2003/05/14 15:27:54 felfert Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -88,6 +88,7 @@
   struct semaphore      write_sem;
   struct tq_struct      tq;
   struct timer_list     stoptimer;
+  struct timer_list	flowtimer;
 } ctc_tty_info;
 
 /* Description of one CTC-tty */
@@ -114,7 +115,7 @@
 static char *ctc_ttyname = CTC_TTY_NAME;
 #endif
 
-char *ctc_tty_revision = "$Revision: 1.8 $";
+char *ctc_tty_revision = "$Revision: 1.11 $";
 
 static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
 static int ctc_tty_shuttingdown = 0;
@@ -163,35 +164,44 @@
 static int
 ctc_tty_readmodem(ctc_tty_info *info)
 {
-	int ret = 1;
+	int c;
 	struct tty_struct *tty;
+	struct sk_buff *skb;
 
-	if ((tty = info->tty)) {
-		if (info->mcr & UART_MCR_RTS) {
-			int c = TTY_FLIPBUF_SIZE - tty->flip.count;
-			struct sk_buff *skb;
-			
-			if ((c > 0) && (skb = skb_dequeue(&info->rx_queue))) {
-				int len = skb->len;
-				if (len > c)
-					len = c;
-				memcpy(tty->flip.char_buf_ptr, skb->data, len);
-				skb_pull(skb, len);
-				memset(tty->flip.flag_buf_ptr, 0, len);
-				tty->flip.count += len;
-				tty->flip.char_buf_ptr += len;
-				tty->flip.flag_buf_ptr += len;
-				tty_flip_buffer_push(tty);
-				if (skb->len > 0)
-					skb_queue_head(&info->rx_queue, skb);
-				else {
-					kfree_skb(skb);
-					ret = skb_queue_len(&info->rx_queue);
-				}
-			}
+	if (!(tty = info->tty)) 
+		return 0;
+
+	/* If the upper layer is flow blocked or just
+   	 * has no room for data we schedule a timer to 
+	 * try again later - wilder
+	 */
+	c = TTY_FLIPBUF_SIZE - tty->flip.count;
+	if ( !(info->mcr & UART_MCR_RTS) || (c <= 0) ) {
+		/* can't do any work now, wake up later */
+		mod_timer(&info->flowtimer, jiffies+(HZ/100) );
+		return 0;
+	}
+
+	if ((skb = skb_dequeue(&info->rx_queue))) {
+		int len = skb->len;
+		if (len > c)
+			len = c;
+		memcpy(tty->flip.char_buf_ptr, skb->data, len);
+		skb_pull(skb, len);
+		memset(tty->flip.flag_buf_ptr, 0, len);
+		tty->flip.count += len;
+		tty->flip.char_buf_ptr += len;
+		tty->flip.flag_buf_ptr += len;
+		tty_flip_buffer_push(tty);
+
+		if (skb->len > 0){
+			skb_queue_head(&info->rx_queue, skb);
+		}else {
+			kfree_skb(skb);
 		}
 	}
-	return ret;
+
+	return  skb_queue_len(&info->rx_queue);
 }
 
 void
@@ -234,6 +244,11 @@
 		dev_kfree_skb(skb);
 		return;
 	}
+	if ( !(info->tty) ) {
+		dev_kfree_skb(skb);
+		return;
+        }
+
 	if (skb->len < 6) {
 		dev_kfree_skb(skb);
 		return;
@@ -244,7 +259,7 @@
 	}
 	skb_pull(skb, sizeof(__u32));
 
-	i = *((int *)skb->data);
+	i = *((__u32 *)skb->data);
 	skb_pull(skb, sizeof(info->mcr));
 	if (i & UART_MCR_RTS) {
 		info->msr |= UART_MSR_CTS;
@@ -270,7 +285,12 @@
 	/* Direct deliver failed or queue wasn't empty.
 	 * Queue up for later dequeueing via timer-irq.
 	 */
-	skb_queue_tail(&info->rx_queue, skb);
+	if (skb_queue_len(&info->rx_queue) < 50)
+		skb_queue_tail(&info->rx_queue, skb);
+	else {
+		kfree_skb(skb);
+		printk(KERN_DEBUG "ctctty: RX overrun\n");
+	}
 	/* Schedule dequeuing */
 	queue_task(&info->tq, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
@@ -330,6 +350,13 @@
 			skb_queue_head(&info->tx_queue, skb);
 		else
 			kfree_skb(skb);
+
+	/* The connection is not up yet, try again in one second. - wilder */
+		if ( rc == -EBUSY ){ 
+			mod_timer(&info->flowtimer, jiffies+(HZ) );
+			return 0;
+		}
+
 	} else {
 		struct tty_struct *tty = info->tty;
 
@@ -484,6 +511,18 @@
 	info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
 }
 
+/* Run from the timer queue when we are flow blocked
+ * to kick start the bottom half - wilder */
+static void
+ctc_tty_startupbh(unsigned long data)
+{
+	ctc_tty_info *info = (ctc_tty_info *)data;
+	if (( !ctc_tty_shuttingdown) && info) {
+		queue_task(&info->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
@@ -577,6 +616,12 @@
 
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write_room"))
 		return 0;
+
+/* wilder */
+	if (skb_queue_len(&info->tx_queue) > 10 ) {
+		return 0;
+	}
+
 	return CTC_TTY_XMIT_SIZE;
 }
 
@@ -1262,6 +1307,9 @@
 		init_timer(&info->stoptimer);
 		info->stoptimer.function = ctc_tty_stopdev;
 		info->stoptimer.data = (unsigned long)info;
+		init_timer(&info->flowtimer);
+                info->flowtimer.function = ctc_tty_startupbh;
+                info->flowtimer.data = (unsigned long)info;
 		info->mcr = UART_MCR_RTS;
 	}
 	return 0;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)