patch-2.2.15 linux/drivers/net/ppp.c
Next file: linux/drivers/net/rcpci45.c
Previous file: linux/drivers/net/plip.c
Back to the patch index
Back to the overall index
- Lines: 319
- Date:
Fri Apr 21 12:46:19 2000
- Orig file:
v2.2.14/drivers/net/ppp.c
- Orig date:
Wed Oct 20 01:12:39 1999
diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/net/ppp.c linux/drivers/net/ppp.c
@@ -4,7 +4,7 @@
* Al Longyear <longyear@netcom.com>
* Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
*
- * ==FILEVERSION 990510==
+ * ==FILEVERSION 20000223==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
@@ -175,6 +175,27 @@
EXPORT_SYMBOL(ppp_register_compressor);
EXPORT_SYMBOL(ppp_unregister_compressor);
+/* Bits in ppp->state */
+#define PUSHING 0 /* currently executing in ppp_tty_push */
+#define WAKEUP 1 /* someone else wants to also */
+#define XMITFULL 2 /* someone owns ppp->tpkt */
+#define FLUSHING 3 /* discard output */
+
+/* Non-blocking locking. */
+static inline int xmit_trylock(struct ppp *ppp)
+{
+ wmb();
+ if (test_and_set_bit(PUSHING, &ppp->state))
+ return 0;
+ return 1;
+}
+
+static inline void xmit_unlock(struct ppp *ppp)
+{
+ wmb();
+ clear_bit(PUSHING, &ppp->state);
+}
+
/*************************************************************
* LINE DISCIPLINE SUPPORT
* The following code implements the PPP line discipline
@@ -323,7 +344,7 @@
{
ppp->escape = 0;
ppp->toss = 0xE0;
- ppp->tty_pushing = 0;
+ ppp->state = 0;
memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
ppp->xmit_async_map[0] = 0xffffffff;
@@ -838,7 +859,7 @@
CHECK_PPP(0);
- if (ppp->tpkt != NULL)
+ if (test_and_set_bit(XMITFULL, &ppp->state))
return -1;
ppp->tpkt = skb;
@@ -886,67 +907,52 @@
static int
ppp_tty_sync_push(struct ppp *ppp)
{
- int sent;
- struct tty_struct *tty = ppp2tty(ppp);
- unsigned long flags;
+ int sent, done = 0;
+ struct tty_struct *tty;
CHECK_PPP(0);
- if (ppp->tpkt == NULL)
- return 0;
-
- /* prevent reentrancy with tty_pushing flag */
- save_flags(flags);
- cli();
- if (ppp->tty_pushing) {
- /* record wakeup attempt so we don't lose */
- /* a wakeup call while doing push processing */
- ppp->woke_up=1;
- restore_flags(flags);
+ set_bit(WAKEUP, &ppp->state);
+ if (!xmit_trylock(ppp))
return 0;
- }
- ppp->tty_pushing = 1;
- restore_flags(flags);
-
- if (tty == NULL || tty->disc_data != (void *) ppp)
- goto flush;
-
- for(;;){
- ppp->woke_up=0;
-
+
+ again:
+ clear_bit(WAKEUP, &ppp->state);
+
+ if (ppp->tpkt != 0) {
/* Note: Sync driver accepts complete frame or nothing */
- tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len);
- if (sent < 0) {
+ tty = ppp2tty(ppp);
+ sent = -1;
+ if (test_bit(FLUSHING, &ppp->state))
+ sent = ppp->tpkt->len;
+ else if (tty != NULL && tty->disc_data == (void *) ppp) {
+ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+ sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len);
+ }
+ if (sent < 0)
/* write error (possible loss of CD) */
/* record error and discard current packet */
ppp->stats.ppp_oerrors++;
- break;
- }
- ppp->stats.ppp_obytes += sent;
- if (sent < ppp->tpkt->len) {
- /* driver unable to accept frame just yet */
- save_flags(flags);
- cli();
- if (ppp->woke_up) {
- /* wake up called while processing */
- /* try to send the frame again */
- restore_flags(flags);
- continue;
- }
- /* wait for wakeup callback to try send again */
- ppp->tty_pushing = 0;
- restore_flags(flags);
- return 0;
- }
- break;
- }
-flush:
- /* done with current packet (sent or discarded) */
- kfree_skb(ppp->tpkt);
- ppp->tpkt = 0;
- ppp->tty_pushing = 0;
- return 1;
+ else
+ ppp->stats.ppp_obytes += sent;
+ if (sent < 0 || sent >= ppp->tpkt->len) {
+ /* driver accepted the frame or we got an error */
+ kfree_skb(ppp->tpkt);
+ ppp->tpkt = 0;
+ wmb();
+ clear_bit(XMITFULL, &ppp->state);
+ done = 1;
+ }
+ }
+ if (ppp->tpkt == 0)
+ clear_bit(FLUSHING, &ppp->state);
+
+ xmit_unlock(ppp);
+ if (test_and_clear_bit(WAKEUP, &ppp->state))
+ if (xmit_trylock(ppp))
+ goto again;
+
+ return done;
}
/*
@@ -964,10 +970,11 @@
ppp_tty_push(ppp);
- if (ppp->tpkt != NULL)
+ if (test_and_set_bit(XMITFULL, &ppp->state))
return -1;
- ppp->tpkt = skb;
ppp->tpkt_pos = 0;
+ wmb();
+ ppp->tpkt = skb;
return ppp_tty_push(ppp);
}
@@ -980,58 +987,62 @@
ppp_tty_push(struct ppp *ppp)
{
int avail, sent, done = 0;
- struct tty_struct *tty = ppp2tty(ppp);
-
+ struct tty_struct *tty;
+
if (ppp->flags & SC_SYNC)
return ppp_tty_sync_push(ppp);
CHECK_PPP(0);
- if (ppp->tty_pushing) {
- ppp->woke_up = 1;
+
+ set_bit(WAKEUP, &ppp->state);
+ if (!xmit_trylock(ppp))
return 0;
- }
- if (tty == NULL || tty->disc_data != (void *) ppp)
- goto flush;
- while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
- ppp->tty_pushing = 1;
- mb();
- ppp->woke_up = 0;
- avail = ppp->olim - ppp->optr;
- if (avail > 0) {
+
+ again:
+ clear_bit(WAKEUP, &ppp->state);
+
+ avail = ppp->olim - ppp->optr;
+ if (avail > 0) {
+ tty = ppp2tty(ppp);
+ sent = -1;
+ if (test_bit(FLUSHING, &ppp->state)) {
+ sent = avail;
+ } else if (tty != NULL && tty->disc_data == (void *) ppp) {
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
sent = tty->driver.write(tty, 0, ppp->optr, avail);
- if (sent < 0)
- goto flush; /* error, e.g. loss of CD */
- ppp->stats.ppp_obytes += sent;
- ppp->optr += sent;
- if (sent < avail) {
+ }
+ if (sent < 0) {
+ /* error, e.g. loss of CD */
+ ppp->stats.ppp_oerrors++;
+ ppp->optr = ppp->olim;
+ if (ppp->tpkt != 0) {
+ kfree_skb(ppp->tpkt);
+ ppp->tpkt = 0;
wmb();
- ppp->tty_pushing = 0;
- mb();
- if (ppp->woke_up)
- continue;
- return done;
+ clear_bit(XMITFULL, &ppp->state);
+ done = 1;
}
+ } else {
+ ppp->stats.ppp_obytes += sent;
+ ppp->optr += sent;
}
- if (ppp->tpkt != 0)
- done = ppp_async_encode(ppp);
- wmb();
- ppp->tty_pushing = 0;
}
- return done;
-flush:
- ppp->tty_pushing = 1;
- mb();
- ppp->stats.ppp_oerrors++;
- if (ppp->tpkt != 0) {
- kfree_skb(ppp->tpkt);
- ppp->tpkt = 0;
- done = 1;
+ if (ppp->optr == ppp->olim) {
+ if (ppp->tpkt != 0) {
+ done |= ppp_async_encode(ppp);
+ goto again;
+ } else {
+ /* buffers are empty */
+ clear_bit(FLUSHING, &ppp->state);
+ }
}
- ppp->optr = ppp->olim;
- wmb();
- ppp->tty_pushing = 0;
+
+ xmit_unlock(ppp);
+ if (test_and_clear_bit(WAKEUP, &ppp->state))
+ if (xmit_trylock(ppp))
+ goto again;
+
return done;
}
@@ -1132,6 +1143,8 @@
kfree_skb(ppp->tpkt);
ppp->tpkt = 0;
+ wmb();
+ clear_bit(XMITFULL, &ppp->state);
return 1;
}
@@ -1152,22 +1165,10 @@
ppp_tty_flush_output(struct ppp *ppp)
{
struct sk_buff *skb;
- int done = 0;
+ set_bit(FLUSHING, &ppp->state);
while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
kfree_skb(skb);
- ppp->tty_pushing = 1;
- mb();
- ppp->optr = ppp->olim;
- if (ppp->tpkt != NULL) {
- kfree_skb(ppp->tpkt);
- ppp->tpkt = 0;
- done = 1;
- }
- wmb();
- ppp->tty_pushing = 0;
- if (done)
- ppp_output_wakeup(ppp);
}
/*
@@ -2711,7 +2712,7 @@
}
/*
- * The dev->tbusy field acts as a lock to allow only
+ * The ppp->xmit_busy field acts as a lock to allow only
* one packet to be processed at a time. If we can't
* get the lock, try again later.
* We deliberately queue as little as possible inside
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)