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
- Lines: 185
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/s390/net/ctctty.c
- Orig date:
2002-08-02 17:39:44.000000000 -0700
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)