diff -ur --new-file old/linux/drivers/atm/atmtcp.c new/linux/drivers/atm/atmtcp.c --- old/linux/drivers/atm/atmtcp.c Thu Apr 10 13:28:36 1997 +++ new/linux/drivers/atm/atmtcp.c Thu Apr 10 13:29:02 1997 @@ -226,8 +226,7 @@ if (walk->vpi == ntohs(hdr.vpi) && walk->vci == ntohs(hdr.vci)) break; if (walk) { - skb_queue_tail(&walk->recvq,skb); - wake_up(&walk->sleep); + vcc->push(vcc,skb); nonblock = 1; vcc->stats->rx++; } diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c --- old/linux/drivers/atm/eni.c Thu Apr 10 13:28:36 1997 +++ new/linux/drivers/atm/eni.c Thu Apr 10 13:29:02 1997 @@ -67,7 +67,6 @@ #define DPRINTK(format,args...) #endif - #ifndef CONFIG_ATM_ENI_DEBUG @@ -926,7 +925,7 @@ DPRINTK(">do_tx\n"); NULLCHECK(skb); - EVENT("do_tx: skb=0x%p, %d bytes\n",skb,skb->len); + EVENT("do_tx: skb=0x%p, %d bytes\n",(unsigned long) skb,skb->len); vcc = skb->atm.vcc; NULLCHECK(vcc); eni_dev = ENI_DEV(vcc->dev); @@ -1212,10 +1211,16 @@ save_flags(flags); cli(); while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) { - printk("%d TX left\n",eni_vcc->txing); DPRINTK("%d TX left\n",eni_vcc->txing); sleep_on(&eni_dev->tx_wait); } + /* + * Looping a few times in here is probably far cheaper than keeping + * track of TX completions all the time, so let's poll a bit ... + */ + while (eni_dev->reg[MID_TX_RDPTR(eni_vcc->tx->index)] != + eni_dev->reg[MID_TX_DESCRSTART(eni_vcc->tx->index)]) + schedule(); restore_flags(flags); #if 0 if (skb_peek(&eni_vcc->tx->backlog)) diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c --- old/linux/net/atm/arequipa.c Thu Apr 10 13:28:36 1997 +++ new/linux/net/atm/arequipa.c Thu Apr 10 13:29:03 1997 @@ -196,6 +196,8 @@ static void make_aq_vcc(struct socket *lower,int incoming) { struct atm_vcc *vcc; + struct sk_buff_head copy; + struct sk_buff *skb; unsigned long flags; save_flags(flags); @@ -214,8 +216,13 @@ aq_list = vcc; } vcc->generation = aq_generation++; + skb_migrate(&vcc->recvq,©); + vcc->rx_inuse = 0; restore_flags(flags); lower->file->f_count++; + /* re-process everything received between connection setup and + AREQUIPA_INCOMING*/ + while ((skb = skb_dequeue(©))) atm_push_arequipa(vcc,skb); } diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c --- old/linux/net/atm/atmarp.c Thu Apr 10 13:28:36 1997 +++ new/linux/net/atm/atmarp.c Thu Apr 10 13:29:03 1997 @@ -246,10 +246,21 @@ static void attach_entry(struct atm_vcc *vcc,struct atmarp_entry *entry) { + struct sk_buff_head copy; + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); AE(vcc) = entry; entry->old_push = vcc->push; vcc->push = atm_push_ip; entry->vcc = vcc; + skb_migrate(&vcc->recvq,©); + vcc->rx_inuse = 0; + restore_flags(flags); + /* re-process everything received between connection setup and MKIP */ + while ((skb = skb_dequeue(©))) atm_push_ip(vcc,skb); } diff -ur --new-file old/linux/net/atm/ipcommon.c new/linux/net/atm/ipcommon.c --- old/linux/net/atm/ipcommon.c Thu Apr 10 13:28:36 1997 +++ new/linux/net/atm/ipcommon.c Thu Apr 10 13:29:03 1997 @@ -211,3 +211,22 @@ } return number; } + + +/* + * skb_migrate moves the list at FROM to TO, emptying FROM in the process. + * This function should live in skbuff.c or skbuff.h. Note that skb_migrate + * is not atomic, so turn off interrupts when using it. + */ + + +void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) +{ + struct sk_buff *prev; + + prev = from->prev; + from->next->prev = (struct sk_buff *) to; + prev->next = (struct sk_buff *) to; + *to = *from; + skb_queue_head_init(from); +} diff -ur --new-file old/linux/net/atm/ipcommon.h new/linux/net/atm/ipcommon.h --- old/linux/net/atm/ipcommon.h Thu Apr 10 13:28:36 1997 +++ new/linux/net/atm/ipcommon.h Thu Apr 10 13:29:03 1997 @@ -1,6 +1,6 @@ /* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ -/* Written 1996 by Werner Almesberger, EPFL LRC */ +/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ #ifndef NET_ATM_IPCOMMON_H @@ -69,5 +69,6 @@ int (*hard_start_xmit)(struct sk_buff *skb,struct device *dev), unsigned short extra_flags); int ipcom_pick_number(int number); +void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); #endif .