]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- atm backport from 2.5 and fixes for kernel 2.4
authorJan Rękorajski <baggins@pld-linux.org>
Thu, 6 Mar 2003 14:27:55 +0000 (14:27 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    atm-00-backport-2.5.patch -> 1.1
    atm-01-Makefile.patch -> 1.1
    atm-04-min-frame-size.patch -> 1.1
    atm-05-multicast-lec.patch -> 1.1
    atm-06-skb_pull.patch -> 1.1
    atm-07-atm_dev_lock-sem.patch -> 1.1
    atm-08-lane-MOD_USE_COUNT.patch -> 1.1
    atm-09-suni-MOD_USE_COUNT.patch -> 1.1
    atm-10-modular-atm.patch -> 1.1
    atm-11-correct-lec-net_device-names.patch -> 1.1
    atm-12-br2684-xmit-return.patch -> 1.1
    atm-13-atm_vcc-cleanup.patch -> 1.1
    atm-20-fore200e-gettimeofday.patch -> 1.1
    atm-21-fore200e-0.3.patch -> 1.1

14 files changed:
atm-00-backport-2.5.patch [new file with mode: 0644]
atm-01-Makefile.patch [new file with mode: 0644]
atm-04-min-frame-size.patch [new file with mode: 0644]
atm-05-multicast-lec.patch [new file with mode: 0644]
atm-06-skb_pull.patch [new file with mode: 0644]
atm-07-atm_dev_lock-sem.patch [new file with mode: 0644]
atm-08-lane-MOD_USE_COUNT.patch [new file with mode: 0644]
atm-09-suni-MOD_USE_COUNT.patch [new file with mode: 0644]
atm-10-modular-atm.patch [new file with mode: 0644]
atm-11-correct-lec-net_device-names.patch [new file with mode: 0644]
atm-12-br2684-xmit-return.patch [new file with mode: 0644]
atm-13-atm_vcc-cleanup.patch [new file with mode: 0644]
atm-20-fore200e-gettimeofday.patch [new file with mode: 0644]
atm-21-fore200e-0.3.patch [new file with mode: 0644]

diff --git a/atm-00-backport-2.5.patch b/atm-00-backport-2.5.patch
new file mode 100644 (file)
index 0000000..3ab16fa
--- /dev/null
@@ -0,0 +1,1159 @@
+diff -uN linux-2.4.20/include/linux/atmdev.h linux-2.5.63/include/linux/atmdev.h
+--- linux-2.4.20/include/linux/atmdev.h        Sat Aug  3 02:39:45 2002
++++ linux-2.5.63/include/linux/atmdev.h        Mon Feb 24 20:05:40 2003
+@@ -33,7 +33,8 @@
+ #define ATM_PDU_OVHD  0       /* number of bytes to charge against buffer
+                                  quota per PDU */
+-#define ATM_SD(s)     ((s)->sk->protinfo.af_atm)
++#define atm_sk(__sk) ((struct atm_vcc *)(__sk)->protinfo.af_atm)
++#define ATM_SD(s)     (atm_sk((s)->sk))
+ #define __AAL_STAT_ITEMS \
+@@ -206,7 +205,7 @@
+ #undef __AAL_STAT_ITEMS
+ #else
+-#include <linux/sched.h> /* wait_queue_head_t */
++#include <linux/wait.h> /* wait_queue_head_t */
+ #include <linux/time.h> /* struct timeval */
+ #include <linux/net.h>
+ #include <linux/skbuff.h> /* struct sk_buff */
+@@ -276,12 +275,8 @@
+ #define ATM_ATMOPT_CLP        1       /* set CLP bit */
+-
+-typedef struct { unsigned long bits; } atm_vcc_flags_t;
+-
+-
+ struct atm_vcc {
+-      atm_vcc_flags_t flags;          /* VCC flags (ATM_VF_*) */
++      unsigned long   flags;          /* VCC flags (ATM_VF_*) */
+       unsigned char   family;         /* address family; 0 if unused */
+       short           vpi;            /* VPI and VCI (types must be equal */
+                                       /* with sockaddr) */
+@@ -302,7 +297,6 @@
+       int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
+       void            *dev_data;      /* per-device data */
+       void            *proto_data;    /* per-protocol data */
+-      struct timeval  timestamp;      /* AAL timestamps */
+       struct sk_buff_head recvq;      /* receive queue */
+       struct k_atm_aal_stats *stats;  /* pointer to AAL stats group */
+       wait_queue_head_t sleep;        /* if socket is busy */
+@@ -331,10 +325,6 @@
+       struct atm_dev_addr *next;      /* next address */
+ };
+-
+-typedef struct { unsigned int bits; } atm_dev_flags_t;
+-
+-
+ struct atm_dev {
+       const struct atmdev_ops *ops;   /* device operations; NULL if unused */
+       const struct atmphy_ops *phy;   /* PHY operations, may be undefined */
+@@ -345,7 +335,7 @@
+       struct atm_vcc  *last;          /* last VCC (or undefined) */
+       void            *dev_data;      /* per-device data */
+       void            *phy_data;      /* private PHY date */
+-      atm_dev_flags_t flags;          /* device flags (ATM_DF_*) */
++      unsigned long   flags;          /* device flags (ATM_DF_*) */
+       struct atm_dev_addr *local;     /* local ATM addresses */
+       unsigned char   esi[ESI_LEN];   /* ESI ("MAC" addr) */
+       struct atm_cirange ci_range;    /* VPI/VCI range */
+@@ -415,7 +405,7 @@
+ #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
+ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
+-    int number,atm_dev_flags_t *flags); /* number == -1: pick first available */
++    int number,unsigned long *flags); /* number == -1: pick first available */
+ struct atm_dev *atm_find_dev(int number);
+ void atm_dev_deregister(struct atm_dev *dev);
+ void shutdown_atm_dev(struct atm_dev *dev);
+diff -urN linux-2.4.20/net/atm/clip.c linux-2.5.63/net/atm/clip.c
+--- linux-2.4.20/net/atm/clip.c        Thu Jun 28 02:10:55 2001
++++ linux-2.5.63/net/atm/clip.c        Mon Feb 24 20:06:01 2003
+@@ -710,7 +711,7 @@
+       999,            /* dummy device number */
+       NULL,NULL,      /* pretend not to have any VCCs */
+       NULL,NULL,      /* no data */
+-      { 0 },          /* no flags */
++      0,              /* no flags */
+       NULL,           /* no local address */
+       { 0 }           /* no ESI, no statistics */
+ };
+diff -urN linux-2.4.20/net/atm/common.c linux-2.5.63/net/atm/common.c
+--- linux-2.4.20/net/atm/common.c      Sat Aug  3 02:39:46 2002
++++ linux-2.5.63/net/atm/common.c      Mon Feb 24 20:06:03 2003
+@@ -112,7 +105,7 @@
+       sock->sk = NULL;
+       if (sock->type == SOCK_STREAM) return -EINVAL;
+       if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
+-      vcc = sk->protinfo.af_atm;
++      vcc = atm_sk(sk);
+       memset(&vcc->flags,0,sizeof(vcc->flags));
+       vcc->dev = NULL;
+       vcc->family = sock->ops->family;
+@@ -128,7 +121,6 @@
+       vcc->push_oam = NULL;
+       vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
+       vcc->atm_options = vcc->aal_options = 0;
+-      vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0;
+       init_waitqueue_head(&vcc->sleep);
+       skb_queue_head_init(&vcc->recvq);
+       skb_queue_head_init(&vcc->listenq);
+@@ -140,10 +132,9 @@
+ void atm_release_vcc_sk(struct sock *sk,int free_sk)
+ {
+-      struct atm_vcc *vcc;
++      struct atm_vcc *vcc = atm_sk(sk);
+       struct sk_buff *skb;
+-      vcc = sk->protinfo.af_atm;
+       clear_bit(ATM_VF_READY,&vcc->flags);
+       if (vcc->dev) {
+               if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
+@@ -295,7 +286,7 @@
+       if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
+               clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+       else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL;
+-      printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
++      DPRINTK("atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
+           "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
+           vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
+           vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
+@@ -387,7 +378,7 @@
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&vcc->sleep,&wait);
+       if (error <= 0) return error;
+-      vcc->timestamp = skb->stamp;
++      sock_recv_timestamp(m, vcc->sk, skb);
+       eff_len = skb->len > size ? size : skb->len;
+       if (skb->len > size) /* Not fit ?  Report it... */
+               m->msg_flags |= MSG_TRUNC;
+@@ -619,13 +610,11 @@
+                       kfree(tmp_buf);
+                       goto done;
+               case SIOCGSTAMP: /* borrowed from IP */
+-                      if (!vcc->timestamp.tv_sec) {
++                      if (!vcc->sk->stamp.tv_sec) {
+                               ret_val = -ENOENT;
+                               goto done;
+                       }
+-                      vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
+-                      vcc->timestamp.tv_usec %= 1000000;
+-                      ret_val = copy_to_user((void *) arg,&vcc->timestamp,
++                      ret_val = copy_to_user((void *) arg, &vcc->sk->stamp,
+                           sizeof(struct timeval)) ? -EFAULT : 0;
+                       goto done;
+               case ATM_SETSC:
+diff -urN linux-2.4.20/net/atm/lec.c linux-2.5.63/net/atm/lec.c
+--- linux-2.4.20/net/atm/lec.c Sun Sep 30 21:26:08 2001
++++ linux-2.5.63/net/atm/lec.c Mon Feb 24 20:05:34 2003
+@@ -20,6 +20,7 @@
+ #include <net/arp.h>
+ #include <net/dst.h>
+ #include <linux/proc_fs.h>
++#include <linux/spinlock.h>
+ /* TokenRing if needed */
+ #ifdef CONFIG_TR
+@@ -35,6 +36,10 @@
+ #include <linux/if_bridge.h>
+ #include "../bridge/br_private.h"
+ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
++
++extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
++       unsigned char *addr);
++extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+ #endif
+ /* Modular too */
+@@ -51,10 +56,7 @@
+ #define DPRINTK(format,args...)
+ #endif
+-extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+-      unsigned char *addr);
+-extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+-
++static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED;
+ #define DUMP_PACKETS 0 /* 0 = None,
+                         * 1 = 30 first bytes
+@@ -196,6 +198,23 @@
+         return 0;
+ }
++static __inline__ void
++lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
++{
++      if (atm_may_send(vcc, skb->len)) {
++              atomic_add(skb->truesize, &vcc->tx_inuse);
++              ATM_SKB(skb)->vcc = vcc;
++              ATM_SKB(skb)->iovcnt = 0;
++              ATM_SKB(skb)->atm_options = vcc->atm_options;
++              priv->stats.tx_packets++;
++              priv->stats.tx_bytes += skb->len;
++              vcc->send(vcc, skb);
++      } else {
++              priv->stats.tx_dropped++;
++              dev_kfree_skb(skb);
++      }
++}
++
+ static int 
+ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
+ {
+@@ -341,34 +360,10 @@
+                 DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+                         lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+                         lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+-                ATM_SKB(skb2)->vcc = send_vcc;
+-                ATM_SKB(skb2)->iovcnt = 0;
+-                ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
+-                DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
+-                        send_vcc->vpi, send_vcc->vci);       
+-                if (atm_may_send(send_vcc, skb2->len)) {
+-                        atomic_add(skb2->truesize, &send_vcc->tx_inuse);
+-                        priv->stats.tx_packets++;
+-                        priv->stats.tx_bytes += skb2->len;
+-                        send_vcc->send(send_vcc, skb2);
+-                } else {
+-                        priv->stats.tx_dropped++;
+-                        dev_kfree_skb(skb2);
+-              }
++              lec_send(send_vcc, skb2, priv);
+         }
+-        ATM_SKB(skb)->vcc = send_vcc;
+-        ATM_SKB(skb)->iovcnt = 0;
+-        ATM_SKB(skb)->atm_options = send_vcc->atm_options;
+-        if (atm_may_send(send_vcc, skb->len)) {
+-                atomic_add(skb->truesize, &send_vcc->tx_inuse);
+-                priv->stats.tx_packets++;
+-                priv->stats.tx_bytes += skb->len;
+-                send_vcc->send(send_vcc, skb);
+-        } else {
+-                priv->stats.tx_dropped++;
+-                dev_kfree_skb(skb);
+-      }
++      lec_send(send_vcc, skb, priv);
+ #if 0
+         /* Should we wait for card's device driver to notify us? */
+@@ -564,7 +559,7 @@
+         999,      /*dummy device number*/
+         NULL,NULL,  /*no VCCs*/
+         NULL,NULL,  /*no data*/
+-        { 0 },            /*no flags*/
++        0,        /*no flags*/
+         NULL,     /* no local address*/
+         { 0 }     /*no ESI or rest of the atm_dev struct things*/
+ };
+@@ -1044,15 +1039,15 @@
+ #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
+ static __inline__ void 
+-lec_arp_lock(struct lec_priv *priv)
++lec_arp_get(struct lec_priv *priv)
+ {
+-        atomic_inc(&priv->lec_arp_lock_var);
++        atomic_inc(&priv->lec_arp_users);
+ }
+ static __inline__ void 
+-lec_arp_unlock(struct lec_priv *priv)
++lec_arp_put(struct lec_priv *priv)
+ {
+-        atomic_dec(&priv->lec_arp_lock_var);
++        atomic_dec(&priv->lec_arp_users);
+ }
+ /*
+@@ -1103,33 +1098,33 @@
+  * LANE2: Add to the end of the list to satisfy 8.1.13
+  */
+ static __inline__ void 
+-lec_arp_put(struct lec_arp_table **lec_arp_tables, 
+-            struct lec_arp_table *to_put)
++lec_arp_add(struct lec_arp_table **lec_arp_tables, 
++            struct lec_arp_table *to_add)
+ {
+-        unsigned short place;
+         unsigned long flags;
++        unsigned short place;
+         struct lec_arp_table *tmp;
+-        save_flags(flags);
+-        cli();
++        spin_lock_irqsave(&lec_arp_spinlock, flags);
+-        place = HASH(to_put->mac_addr[ETH_ALEN-1]);
++        place = HASH(to_add->mac_addr[ETH_ALEN-1]);
+         tmp = lec_arp_tables[place];
+-        to_put->next = NULL;
++        to_add->next = NULL;
+         if (tmp == NULL)
+-                lec_arp_tables[place] = to_put;
++                lec_arp_tables[place] = to_add;
+   
+         else {  /* add to the end */
+                 while (tmp->next)
+                         tmp = tmp->next;
+-                tmp->next = to_put;
++                tmp->next = to_add;
+         }
+-        restore_flags(flags);
++        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
++
+         DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+-                0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1],
+-                0xff&to_put->mac_addr[2], 0xff&to_put->mac_addr[3],
+-                0xff&to_put->mac_addr[4], 0xff&to_put->mac_addr[5]);
++                0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
++                0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
++                0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
+ }
+ /*
+@@ -1139,16 +1134,15 @@
+ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
+                struct lec_arp_table *to_remove)
+ {
++        unsigned long flags;
+         unsigned short place;
+         struct lec_arp_table *tmp;
+-        unsigned long flags;
+         int remove_vcc=1;
+-        save_flags(flags);
+-        cli();
++        spin_lock_irqsave(&lec_arp_spinlock, flags);
+         if (!to_remove) {
+-                restore_flags(flags);
++                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                 return -1;
+         }
+         place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
+@@ -1160,7 +1154,7 @@
+                         tmp = tmp->next;
+                 }
+                 if (!tmp) {/* Entry was not found */
+-                        restore_flags(flags);
++                        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                         return -1;
+                 }
+         }
+@@ -1186,7 +1180,9 @@
+                         lec_arp_clear_vccs(to_remove);
+         }
+         skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
+-        restore_flags(flags);
++
++        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
++
+         DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+                 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
+                 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
+@@ -1371,12 +1367,8 @@
+ lec_arp_destroy(struct lec_priv *priv)
+ {
+         struct lec_arp_table *entry, *next;
+-        unsigned long flags;
+         int i;
+-        save_flags(flags);
+-        cli();
+-
+         del_timer(&priv->lec_arp_timer);
+         
+         /*
+@@ -1419,7 +1411,6 @@
+         priv->mcast_vcc = NULL;
+         memset(priv->lec_arp_tables, 0, 
+                sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE);
+-        restore_flags(flags);
+ }
+@@ -1436,18 +1427,18 @@
+         DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+                 mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff, 
+                 mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         place = HASH(mac_addr[ETH_ALEN-1]);
+   
+         to_return = priv->lec_arp_tables[place];
+         while(to_return) {
+                 if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) {
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return to_return;
+                 }
+                 to_return = to_return->next;
+         }
+-        lec_arp_unlock(priv);
++        lec_arp_put(priv);
+         return NULL;
+ }
+@@ -1574,11 +1565,11 @@
+         del_timer(&priv->lec_arp_timer);
+         DPRINTK("lec_arp_check_expire %p,%d\n",priv,
+-                priv->lec_arp_lock_var.counter);
++                atomic_read(&priv->lec_arp_users));
+         DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
+                 priv->lec_no_forward);
+-        if (!priv->lec_arp_lock_var.counter) {
+-                lec_arp_lock(priv);
++        if (!atomic_read(&priv->lec_arp_users)) {
++                lec_arp_get(priv);
+                 now = jiffies;
+                 for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+                         for(entry = lec_arp_tables[i];entry != NULL;) {
+@@ -1616,6 +1607,10 @@
+                                            &&
+                                            time_after_eq(now, entry->timestamp+
+                                            priv->path_switching_delay)) {
++                                              struct sk_buff *skb;
++
++                                              while ((skb = skb_dequeue(&entry->tx_wait)))
++                                                      lec_send(entry->vcc, skb, entry->priv);
+                                                 entry->last_used = jiffies;
+                                                 entry->status = 
+                                                         ESI_FORWARD_DIRECT;
+@@ -1624,7 +1619,7 @@
+                                 }
+                         }
+                 }
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+         }
+         priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
+         add_timer(&priv->lec_arp_timer);
+@@ -1686,7 +1681,7 @@
+                 if (!entry) {
+                         return priv->mcast_vcc;
+                 }
+-                lec_arp_put(priv->lec_arp_tables, entry);
++                lec_arp_add(priv->lec_arp_tables, entry);
+                 /* We want arp-request(s) to be sent */
+                 entry->packets_flooded =1;
+                 entry->status = ESI_ARP_PENDING;
+@@ -1711,7 +1706,7 @@
+         struct lec_arp_table *entry, *next;
+         int i;
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         DPRINTK("lec_addr_delete\n");
+         for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+                 for(entry=priv->lec_arp_tables[i];entry != NULL; entry=next) {
+@@ -1722,11 +1717,11 @@
+                                 lec_arp_remove(priv->lec_arp_tables, entry);
+                                 kfree(entry);
+                         }
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return 0;
+                 }
+         }
+-        lec_arp_unlock(priv);
++        lec_arp_put(priv);
+         return -1;
+ }
+@@ -1751,7 +1746,7 @@
+                 return;   /* LANE2: ignore targetless LE_ARPs for which
+                            * we have no entry in the cache. 7.1.30
+                            */
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         if (priv->lec_arp_empty_ones) {
+                 entry = priv->lec_arp_empty_ones;
+                 if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
+@@ -1785,13 +1780,13 @@
+                                 entry->status = ESI_FORWARD_DIRECT;
+                                 memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
+                                 entry->last_used = jiffies;
+-                                lec_arp_put(priv->lec_arp_tables, entry);
++                                lec_arp_add(priv->lec_arp_tables, entry);
+                         }
+                         if (remoteflag)
+                                 entry->flags|=LEC_REMOTE_FLAG;
+                         else
+                                 entry->flags&=~LEC_REMOTE_FLAG;
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         DPRINTK("After update\n");
+                         dump_arp_table(priv);
+                         return;
+@@ -1801,11 +1796,11 @@
+         if (!entry) {
+                 entry = make_entry(priv, mac_addr);
+                 if (!entry) {
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return;
+                 }
+                 entry->status = ESI_UNKNOWN;
+-                lec_arp_put(priv->lec_arp_tables, entry);
++                lec_arp_add(priv->lec_arp_tables, entry);
+                 /* Temporary, changes before end of function */
+         }
+         memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
+@@ -1840,7 +1835,7 @@
+         }
+         DPRINTK("After update2\n");
+         dump_arp_table(priv);
+-        lec_arp_unlock(priv);
++        lec_arp_put(priv);
+ }
+ /*
+@@ -1854,7 +1849,7 @@
+         struct lec_arp_table *entry;
+         int i, found_entry=0;
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         if (ioc_data->receive == 2) {
+                 /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
+@@ -1863,7 +1858,7 @@
+                 entry = lec_arp_find(priv, bus_mac);
+                 if (!entry) {
+                         printk("LEC_ARP: Multicast entry not found!\n");
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return;
+                 }
+                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+@@ -1872,7 +1867,7 @@
+ #endif
+                 entry = make_entry(priv, bus_mac);
+                 if (entry == NULL) {
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return;
+                 }
+                 del_timer(&entry->timer);
+@@ -1881,7 +1876,7 @@
+                 entry->old_recv_push = old_push;
+                 entry->next = priv->mcast_fwds;
+                 priv->mcast_fwds = entry;
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+                 return;
+         } else if (ioc_data->receive == 1) {
+                 /* Vcc which we don't want to make default vcc, attach it
+@@ -1899,7 +1894,7 @@
+                         ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
+                 entry = make_entry(priv, bus_mac);
+                 if (entry == NULL) {
+-                        lec_arp_unlock(priv);
++                        lec_arp_put(priv);
+                         return;
+                 }
+                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+@@ -1912,7 +1907,7 @@
+                 add_timer(&entry->timer);
+                 entry->next = priv->lec_no_forward;
+                 priv->lec_no_forward = entry;
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+               dump_arp_table(priv);
+                 return;
+         }
+@@ -1971,7 +1966,7 @@
+                 }
+         }
+         if (found_entry) {
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+                 DPRINTK("After vcc was added\n");
+                 dump_arp_table(priv);
+                 return;
+@@ -1980,7 +1975,7 @@
+            this vcc */
+         entry = make_entry(priv, bus_mac);
+         if (!entry) {
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+                 return;
+         }
+         entry->vcc = vcc;
+@@ -1993,7 +1988,7 @@
+         entry->timer.expires = jiffies + priv->vcc_timeout_period;
+         entry->timer.function = lec_arp_expire_vcc;
+         add_timer(&entry->timer);
+-        lec_arp_unlock(priv);
++        lec_arp_put(priv);
+         DPRINTK("After vcc was added\n");
+       dump_arp_table(priv);
+ }
+@@ -2009,6 +2004,10 @@
+                 for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) {
+                         if (entry->flush_tran_id == tran_id &&
+                             entry->status == ESI_FLUSH_PENDING) {
++                              struct sk_buff *skb;
++
++                              while ((skb = skb_dequeue(&entry->tx_wait)))
++                                      lec_send(entry->vcc, skb, entry->priv);
+                                 entry->status = ESI_FORWARD_DIRECT;
+                                 DPRINTK("LEC_ARP: Flushed\n");
+                         }
+@@ -2039,10 +2038,10 @@
+                 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+         struct lec_arp_table *to_add;
+   
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         to_add = make_entry(priv, mac_addr);
+         if (!to_add) {
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
+                 return -ENOMEM;
+         }
+         memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
+@@ -2052,8 +2051,8 @@
+         to_add->old_push = vcc->push;
+         vcc->push = lec_push;
+         priv->mcast_vcc = vcc;
+-        lec_arp_put(priv->lec_arp_tables, to_add);
+-        lec_arp_unlock(priv);
++        lec_arp_add(priv->lec_arp_tables, to_add);
++        lec_arp_put(priv);
+         return 0;
+ }
+@@ -2065,7 +2064,7 @@
+         DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
+         dump_arp_table(priv);
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+                 for(entry = priv->lec_arp_tables[i];entry; entry=next) {
+                         next = entry->next;
+@@ -2127,7 +2126,7 @@
+                 entry = next;
+         }
+-        lec_arp_unlock(priv);
++        lec_arp_put(priv);
+       dump_arp_table(priv);
+ }
+@@ -2135,9 +2134,9 @@
+ lec_arp_check_empties(struct lec_priv *priv,
+                       struct atm_vcc *vcc, struct sk_buff *skb)
+ {
++        unsigned long flags;
+         struct lec_arp_table *entry, *prev;
+         struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
+-        unsigned long flags;
+         unsigned char *src;
+ #ifdef CONFIG_TR
+         struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
+@@ -2147,26 +2146,26 @@
+ #endif
+         src = hdr->h_source;
+-        lec_arp_lock(priv);
++        lec_arp_get(priv);
+         entry = priv->lec_arp_empty_ones;
+         if (vcc == entry->vcc) {
+-                save_flags(flags);
+-                cli();
++              spin_lock_irqsave(&lec_arp_spinlock, flags);
+                 del_timer(&entry->timer);
+                 memcpy(entry->mac_addr, src, ETH_ALEN);
+                 entry->status = ESI_FORWARD_DIRECT;
+                 entry->last_used = jiffies;
+                 priv->lec_arp_empty_ones = entry->next;
+-                restore_flags(flags);
++                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                 /* We might have got an entry */
+                 if ((prev=lec_arp_find(priv,src))) {
+                         lec_arp_remove(priv->lec_arp_tables, prev);
+                         kfree(prev);
+                 }
+-                lec_arp_put(priv->lec_arp_tables, entry);
+-                lec_arp_unlock(priv);
++                lec_arp_add(priv->lec_arp_tables, entry);
++                lec_arp_put(priv);
+                 return;
+         }
++        spin_lock_irqsave(&lec_arp_spinlock, flags);
+         prev = entry;
+         entry = entry->next;
+         while (entry && entry->vcc != vcc) {
+@@ -2175,22 +2174,21 @@
+         }
+         if (!entry) {
+                 DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
+-                lec_arp_unlock(priv);
++                lec_arp_put(priv);
++                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                 return;
+         }
+-        save_flags(flags);
+-        cli();
+         del_timer(&entry->timer);
+         memcpy(entry->mac_addr, src, ETH_ALEN);
+         entry->status = ESI_FORWARD_DIRECT;
+         entry->last_used = jiffies;
+         prev->next = entry->next;
+-        restore_flags(flags);
++        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+         if ((prev = lec_arp_find(priv, src))) {
+                 lec_arp_remove(priv->lec_arp_tables,prev);
+                 kfree(prev);
+         }
+-        lec_arp_put(priv->lec_arp_tables,entry);
+-        lec_arp_unlock(priv);  
++        lec_arp_add(priv->lec_arp_tables,entry);
++        lec_arp_put(priv);  
+ }
+ MODULE_LICENSE("GPL");
+diff -urN linux-2.4.20/net/atm/lec.h linux-2.5.63/net/atm/lec.h
+--- linux-2.4.20/net/atm/lec.h Fri Feb  9 20:34:13 2001
++++ linux-2.5.63/net/atm/lec.h Mon Feb 24 20:05:15 2003
+@@ -98,7 +98,7 @@
+            establishes multiple Multicast Forward VCCs to us. This list
+            collects all those VCCs. LANEv1 client has only one item in this
+            list. These entries are not aged out. */
+-        atomic_t lec_arp_lock_var;
++        atomic_t lec_arp_users;
+         struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+         struct atm_vcc *lecd;
+         struct timer_list lec_arp_timer;
+diff -urN linux-2.4.20/net/atm/mpc.c linux-2.5.63/net/atm/mpc.c
+--- linux-2.4.20/net/atm/mpc.c Sun Sep 30 21:26:08 2001
++++ linux-2.5.63/net/atm/mpc.c Mon Feb 24 20:05:40 2003
+@@ -13,7 +13,7 @@
+ #include <linux/ip.h>
+ #include <asm/byteorder.h>
+ #include <asm/uaccess.h>
+-#include <asm/checksum.h>   /* for ip_fast_csum() */
++#include <net/checksum.h>   /* for ip_fast_csum() */
+ #include <net/arp.h>
+ #include <net/dst.h>
+ #include <linux/proc_fs.h>
+@@ -741,18 +741,10 @@
+ };
+ static struct atm_dev mpc_dev = {
+-      &mpc_ops,       /* device operations    */
+-      NULL,           /* PHY operations       */
+-      "mpc",          /* device type name     */
+-      42,             /* device index (dummy) */
+-      NULL,           /* VCC table            */
+-      NULL,           /* last VCC             */
+-      NULL,           /* per-device data      */
+-      NULL,           /* private PHY data     */
+-      { 0 },          /* device flags         */
+-      NULL,           /* local ATM address    */
+-      { 0 }           /* no ESI               */
+-      /* rest of the members will be 0 */
++      ops:    &mpc_ops,
++      type:   "mpc",
++      number: 42,
++      /* members not explicitely initialised will be 0 */
+ };
+ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
+@@ -1432,10 +1424,6 @@
+       struct atm_mpoa_qos *qos, *nextqos;
+       struct lec_priv *priv;
+-      if (MOD_IN_USE) {
+-              printk("mpc.c: module in use\n");
+-              return;
+-      }
+ #ifdef CONFIG_PROC_FS
+       mpc_proc_clean();
+ #endif
+diff -urN linux-2.4.20/net/atm/mpoa_proc.c linux-2.5.63/net/atm/mpoa_proc.c
+--- linux-2.4.20/net/atm/mpoa_proc.c   Wed Jul  4 20:50:38 2001
++++ linux-2.5.63/net/atm/mpoa_proc.c   Mon Feb 24 20:05:39 2003
+@@ -111,7 +111,7 @@
+       unsigned char ip_string[16];
+       if(count == 0)
+               return 0;
+-      page = get_free_page(GFP_KERNEL);
++      page = get_zeroed_page(GFP_KERNEL);
+       if(!page)
+               return -ENOMEM;
+       atm_mpoa_disp_qos((char *)page, &length);
+diff -urN linux-2.4.20/net/atm/proc.c linux-2.5.63/net/atm/proc.c
+--- linux-2.4.20/net/atm/proc.c        Fri Nov 29 00:53:15 2002
++++ linux-2.5.63/net/atm/proc.c        Mon Feb 24 20:05:14 2003
+@@ -220,7 +220,7 @@
+               default:
+                       here += sprintf(here,"%3d",vcc->family);
+       }
+-      here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
++      here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7d\n",vcc->flags,
+           vcc->reply,
+           atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
+           atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
+@@ -496,7 +496,7 @@
+       int length;
+       if (count == 0) return 0;
+-      page = get_free_page(GFP_KERNEL);
++      page = get_zeroed_page(GFP_KERNEL);
+       if (!page) return -ENOMEM;
+       dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
+           ->data;
+@@ -521,7 +520,7 @@
+           ->data;
+       if (count == 0) return 0;
+-      page = get_free_page(GFP_KERNEL);
++      page = get_zeroed_page(GFP_KERNEL);
+       if (!page) return -ENOMEM;
+       length = (*info)(*pos,(char *) page);
+       if (length > count) length = -EINVAL;
+@@ -552,7 +550,7 @@
+       for (num = dev->number; num; num /= 10) digits++;
+       if (!digits) digits++;
+-      dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
++      dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_KERNEL);
+       if (!dev->proc_name)
+               goto fail1;
+       sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
+diff -urN linux-2.4.20/net/atm/pvc.c linux-2.5.63/net/atm/pvc.c
+--- linux-2.4.20/net/atm/pvc.c Thu Apr 12 21:11:39 2001
++++ linux-2.5.63/net/atm/pvc.c Mon Feb 24 20:05:14 2003
+@@ -111,11 +111,8 @@
+ static struct net_proto_family pvc_family_ops = {
+-      PF_ATMPVC,
+-      pvc_create,
+-      0,                      /* no authentication */
+-      0,                      /* no encryption */
+-      0                       /* no encrypt_net */
++      family: PF_ATMPVC,
++      create: pvc_create,
+ };
+diff -urN linux-2.4.20/net/atm/resources.c linux-2.5.63/net/atm/resources.c
+--- linux-2.4.20/net/atm/resources.c   Fri Nov 29 00:53:15 2002
++++ linux-2.5.63/net/atm/resources.c   Mon Feb 24 20:05:45 2003
+@@ -2,6 +2,11 @@
+ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
++/* Fixes
++ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
++ * 2002/01 - don't free the whole struct sock on sk->destruct time,
++ *         use the default destruct function initialized by sock_init_data */
++
+ #include <linux/config.h>
+ #include <linux/ctype.h>
+@@ -11,7 +16,6 @@
+ #include <linux/module.h>
+ #include <linux/bitops.h>
+ #include <net/sock.h>  /* for struct sock */
+-#include <asm/segment.h> /* for get_fs_long and put_fs_long */
+ #include "common.h"
+ #include "resources.h"
+@@ -27,14 +31,15 @@
+ struct atm_vcc *nodev_vccs = NULL;
+ extern spinlock_t atm_dev_lock;
+-
+-static struct atm_dev *alloc_atm_dev(const char *type)
++/* Caller must hold atm_dev_lock. */
++static struct atm_dev *__alloc_atm_dev(const char *type)
+ {
+       struct atm_dev *dev;
+       dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+-      if (!dev) return NULL;
+-      memset(dev,0,sizeof(*dev));
++      if (!dev)
++              return NULL;
++      memset(dev, 0, sizeof(*dev));
+       dev->type = type;
+       dev->signal = ATM_PHY_SIG_UNKNOWN;
+       dev->link_rate = ATM_OC3_PCR;
+@@ -42,39 +47,49 @@
+       dev->prev = last_dev;
+-      if (atm_devs) last_dev->next = dev;
+-      else atm_devs = dev;
++      if (atm_devs)
++              last_dev->next = dev;
++      else
++              atm_devs = dev;
+       last_dev = dev;
++
+       return dev;
+ }
+-
+-static void free_atm_dev(struct atm_dev *dev)
++/* Caller must hold atm_dev_lock. */
++static void __free_atm_dev(struct atm_dev *dev)
+ {
+-      if (dev->prev) dev->prev->next = dev->next;
+-      else atm_devs = dev->next;
+-      if (dev->next) dev->next->prev = dev->prev;
+-      else last_dev = dev->prev;
++      if (dev->prev)
++              dev->prev->next = dev->next;
++      else
++              atm_devs = dev->next;
++      if (dev->next)
++              dev->next->prev = dev->prev;
++      else
++              last_dev = dev->prev;
+       kfree(dev);
+ }
++/* Caller must hold atm_dev_lock. */
+ struct atm_dev *atm_find_dev(int number)
+ {
+       struct atm_dev *dev;
+       for (dev = atm_devs; dev; dev = dev->next)
+-              if (dev->ops && dev->number == number) return dev;
++              if (dev->ops && dev->number == number)
++                      return dev;
+       return NULL;
+ }
+-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
+-    int number,atm_dev_flags_t *flags)
++
++struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
++                               int number, unsigned long *flags)
+ {
+-      struct atm_dev *dev = NULL;
++      struct atm_dev *dev;
+       spin_lock(&atm_dev_lock);
+-      dev = alloc_atm_dev(type);
++      dev = __alloc_atm_dev(type);
+       if (!dev) {
+               printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
+                   type);
+@@ -82,31 +97,37 @@
+       }
+       if (number != -1) {
+               if (atm_find_dev(number)) {
+-                      free_atm_dev(dev);
+-                      return NULL;
++                      __free_atm_dev(dev);
++                      dev = NULL;
++                      goto done;
+               }
+               dev->number = number;
+       } else {
+               dev->number = 0;
+-              while (atm_find_dev(dev->number)) dev->number++;
++              while (atm_find_dev(dev->number))
++                      dev->number++;
+       }
+       dev->vccs = dev->last = NULL;
+       dev->dev_data = NULL;
+       barrier();
+       dev->ops = ops;
+-      if (flags) 
++      if (flags)
+               dev->flags = *flags;
+-      else 
+-              memset(&dev->flags,0,sizeof(dev->flags));
+-      memset((void *) &dev->stats,0,sizeof(dev->stats));
++      else
++              memset(&dev->flags, 0, sizeof(dev->flags));
++      memset(&dev->stats, 0, sizeof(dev->stats));
++
+ #ifdef CONFIG_PROC_FS
+-      if (ops->proc_read)
++      if (ops->proc_read) {
+               if (atm_proc_dev_register(dev) < 0) {
+                       printk(KERN_ERR "atm_dev_register: "
+-                          "atm_proc_dev_register failed for dev %s\n",type);
+-                      free_atm_dev(dev);
++                             "atm_proc_dev_register failed for dev %s\n",
++                             type);
++                      __free_atm_dev(dev);
++                      dev = NULL;
+                       goto done;
+               }
++      }
+ #endif
+ done:
+@@ -118,47 +139,50 @@
+ void atm_dev_deregister(struct atm_dev *dev)
+ {
+ #ifdef CONFIG_PROC_FS
+-      if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
++      if (dev->ops->proc_read)
++              atm_proc_dev_deregister(dev);
+ #endif
+       spin_lock(&atm_dev_lock);
+-      free_atm_dev(dev);
++      __free_atm_dev(dev);
+       spin_unlock(&atm_dev_lock);
+ }
+ void shutdown_atm_dev(struct atm_dev *dev)
+ {
+       if (dev->vccs) {
+-              set_bit(ATM_DF_CLOSE,&dev->flags);
++              set_bit(ATM_DF_CLOSE, &dev->flags);
+               return;
+       }
+-      if (dev->ops->dev_close) dev->ops->dev_close(dev);
++      if (dev->ops->dev_close)
++              dev->ops->dev_close(dev);
+       atm_dev_deregister(dev);
+ }
+-
+ /* Handler for sk->destruct, invoked by sk_free() */
+ static void atm_free_sock(struct sock *sk)
+ {
+       kfree(sk->protinfo.af_atm);
+ }
+ struct sock *alloc_atm_vcc_sk(int family)
+ {
+       struct sock *sk;
+       struct atm_vcc *vcc;
+-      sk = sk_alloc(family, GFP_KERNEL, 1);
+-      if (!sk) return NULL;
+-      vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
++      sk = sk_alloc(family, GFP_KERNEL, 1);
++      if (!sk)
++              return NULL;
++      vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
+       if (!vcc) {
+               sk_free(sk);
+               return NULL;
+       }
+-      sock_init_data(NULL,sk);
+       sk->destruct = atm_free_sock;
+-      memset(vcc,0,sizeof(*vcc));
++      sock_init_data(NULL, sk);
++      memset(vcc, 0, sizeof(*vcc));
+       vcc->sk = sk;
+-      if (nodev_vccs) nodev_vccs->prev = vcc;
++      if (nodev_vccs)
++              nodev_vccs->prev = vcc;
+       vcc->prev = NULL;
+       vcc->next = nodev_vccs;
+       nodev_vccs = vcc;
+@@ -168,11 +185,16 @@
+ static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
+ {
+-      if (vcc->prev) vcc->prev->next = vcc->next;
+-      else if (vcc->dev) vcc->dev->vccs = vcc->next;
+-          else nodev_vccs = vcc->next;
+-      if (vcc->next) vcc->next->prev = vcc->prev;
+-      else if (vcc->dev) vcc->dev->last = vcc->prev;
++      if (vcc->prev)
++              vcc->prev->next = vcc->next;
++      else if (vcc->dev)
++              vcc->dev->vccs = vcc->next;
++      else
++              nodev_vccs = vcc->next;
++      if (vcc->next)
++              vcc->next->prev = vcc->prev;
++      else if (vcc->dev)
++              vcc->dev->last = vcc->prev;
+       if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
+           test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
+               shutdown_atm_dev(vcc->dev);
+@@ -181,11 +203,10 @@
+ void free_atm_vcc_sk(struct sock *sk)
+ {
+-      unlink_vcc(sk->protinfo.af_atm,NULL);
++      unlink_vcc(atm_sk(sk), NULL);
+       sk_free(sk);
+ }
+-
+ void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
+ {
+       unlink_vcc(vcc,dev);
+@@ -193,19 +214,20 @@
+       if (dev) {
+               vcc->next = NULL;
+               vcc->prev = dev->last;
+-              if (dev->vccs) dev->last->next = vcc;
+-              else dev->vccs = vcc;
++              if (dev->vccs)
++                      dev->last->next = vcc;
++              else
++                      dev->vccs = vcc;
+               dev->last = vcc;
+-      }
+-      else {
+-              if (nodev_vccs) nodev_vccs->prev = vcc;
++      } else {
++              if (nodev_vccs)
++                      nodev_vccs->prev = vcc;
+               vcc->next = nodev_vccs;
+               vcc->prev = NULL;
+               nodev_vccs = vcc;
+       }
+ }
+-
+ EXPORT_SYMBOL(atm_dev_register);
+ EXPORT_SYMBOL(atm_dev_deregister);
+ EXPORT_SYMBOL(atm_find_dev);
+diff -urN linux-2.4.20/net/atm/signaling.c linux-2.5.63/net/atm/signaling.c
+--- linux-2.4.20/net/atm/signaling.c   Thu Jun 28 02:10:55 2001
++++ linux-2.5.63/net/atm/signaling.c   Mon Feb 24 20:05:39 2003
+@@ -239,7 +239,7 @@
+       999,            /* dummy device number */
+       NULL,NULL,      /* pretend not to have any VCCs */
+       NULL,NULL,      /* no data */
+-      { 0 },          /* no flags */
++      0,              /* no flags */
+       NULL,           /* no local address */
+       { 0 }           /* no ESI, no statistics */
+ };
+diff -urN linux-2.4.20/net/atm/svc.c linux-2.5.63/net/atm/svc.c
+--- linux-2.4.20/net/atm/svc.c Thu Apr 12 21:11:39 2001
++++ linux-2.5.63/net/atm/svc.c Mon Feb 24 20:05:36 2003
+@@ -430,11 +430,8 @@
+ static struct net_proto_family svc_family_ops = {
+-      PF_ATMSVC,
+-      svc_create,
+-      0,                      /* no authentication */
+-      0,                      /* no encryption */
+-      0                       /* no encrypt_net */
++      family: PF_ATMSVC,
++      create: svc_create,
+ };
diff --git a/atm-01-Makefile.patch b/atm-01-Makefile.patch
new file mode 100644 (file)
index 0000000..4e956a8
--- /dev/null
@@ -0,0 +1,40 @@
+--- linux-2.4.20/net/atm/Makefile.orig Sat Aug  3 02:39:46 2002
++++ linux-2.4.20/net/atm/Makefile      Wed Mar  5 23:15:50 2003
+@@ -14,32 +14,18 @@
+ list-multi    := mpoa.o
+ mpoa-objs     := mpc.o mpoa_caches.o mpoa_proc.o
+-obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o
++obj-y := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o ipcommon.o
+-ifeq ($(CONFIG_ATM_CLIP),y)
+-obj-y += clip.o
+-NEED_IPCOM = ipcommon.o
++ifeq ($(CONFIG_ATM),m)
++obj-m += $(O_TARGET)
+ endif
+-ifeq ($(CONFIG_ATM_BR2684),y)
+-  NEED_IPCOM = ipcommon.o
+-else
+-  ifeq ($(CONFIG_ATM_BR2684),m)
+-      NEED_IPCOM = ipcommon.o
+-  endif
+-endif
+-obj-$(CONFIG_ATM_BR2684) += br2684.o
+-
+-ifeq ($(CONFIG_NET_SCH_ATM),y)
+-NEED_IPCOM = ipcommon.o
+-endif
+-
+-obj-y += $(NEED_IPCOM)
+-
+ ifeq ($(CONFIG_PROC_FS),y)
+ obj-y += proc.o
+ endif
++obj-$(CONFIG_ATM_CLIP) += clip.o
++obj-$(CONFIG_ATM_BR2684) += br2684.o
+ obj-$(CONFIG_ATM_LANE) += lec.o
+ obj-$(CONFIG_ATM_MPOA) += mpoa.o
+ obj-$(CONFIG_PPPOATM) += pppoatm.o
diff --git a/atm-04-min-frame-size.patch b/atm-04-min-frame-size.patch
new file mode 100644 (file)
index 0000000..3ebf326
--- /dev/null
@@ -0,0 +1,86 @@
+the minimum frame size for token ring (802.5) pdus is 16 octets.  also,
+count the pdus that failed to copy as dropped.  also, skb_copy_expand()
+now seems to be the right way to do this.
+
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.5
+retrieving revision 1.6
+diff -u -d -b -w -r1.5 -r1.6
+--- linux/net/atm/lec.c        22 Feb 2003 19:23:22 -0000      1.5
++++ linux/net/atm/lec.c        24 Feb 2003 13:24:45 -0000      1.6
+@@ -223,7 +223,8 @@
+         struct lecdatahdr_8023 *lec_h;
+         struct atm_vcc *send_vcc;
+       struct lec_arp_table *entry;
+-        unsigned char *nb, *dst;
++        unsigned char *dst;
++      int min_frame_size;
+ #ifdef CONFIG_TR
+         unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
+ #endif
+@@ -294,26 +295,24 @@
+ #endif /* DUMP_PACKETS > 0 */
+         /* Minimum ethernet-frame size */
+-        if (skb->len <62) {
+-                if (skb->truesize < 62) {
+-                        printk("%s:data packet %d / %d\n",
+-                               dev->name,
+-                               skb->len,skb->truesize);
+-                        nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+-                        if (nb == NULL) {
++#ifdef CONFIG_TR
++        if (priv->is_trdev)
++                min_frame_size = LEC_MINIMUM_8025_SIZE;
++      else
++#endif
++        min_frame_size = LEC_MINIMUM_8023_SIZE;
++        if (skb->len < min_frame_size) {
++                if (skb->truesize < min_frame_size) {
++                        skb2 = skb_copy_expand(skb, 0,
++                            min_frame_size - skb->truesize, GFP_ATOMIC);
+                                 dev_kfree_skb(skb);
++                        if (skb2 == NULL) {
++                                priv->stats.tx_dropped++;
+                                 return 0;
+                         }
+-                        memcpy(nb,skb->data,skb->len);
+-                        kfree(skb->head);
+-                        skb->head = skb->data = nb;
+-                        skb->tail = nb+62;
+-                        skb->end = nb+64;
+-                        skb->len=62;
+-                        skb->truesize = 64;
+-                } else {
+-                        skb->len = 62;
++                        skb = skb2;
+                 }
++              skb_put(skb, min_frame_size - skb->len);
+         }
+         
+         /* Send to right vcc */
+Index: linux/net/atm/lec.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.h,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -u -d -b -w -r1.2 -r1.3
+--- linux/net/atm/lec.h        22 Feb 2003 19:29:27 -0000      1.2
++++ linux/net/atm/lec.h        24 Feb 2003 13:24:46 -0000      1.3
+@@ -38,6 +38,9 @@
+   unsigned char h_source[ETH_ALEN];
+ };
++#define LEC_MINIMUM_8023_SIZE   62
++#define LEC_MINIMUM_8025_SIZE   16
++
+ /*
+  * Operations that LANE2 capable device can do. Two first functions
+  * are used to make the device do things. See spec 3.1.3 and 3.1.4.
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-05-multicast-lec.patch b/atm-05-multicast-lec.patch
new file mode 100644 (file)
index 0000000..8a5b58e
--- /dev/null
@@ -0,0 +1,39 @@
+the ip layer uses the presence of the .set_multicast_list to determine
+if the underlying network device supports multicast.
+
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.7
+diff -u -d -b -w -r1.7 lec.c
+--- linux/net/atm/lec.c        24 Feb 2003 13:34:43 -0000      1.7
++++ linux/net/atm/lec.c        25 Feb 2003 11:49:42 -0000
+@@ -617,6 +617,14 @@
+         return 0;
+ }
++static void lec_set_multicast_list(struct net_device *dev)
++{
++      /* by default, all multicast frames arrive over the bus.
++         * eventually support selective multicast service
++         */
++        return;
++}
++
+ static void 
+ lec_init(struct net_device *dev)
+ {
+@@ -626,7 +634,7 @@
+         dev->hard_start_xmit = lec_send_packet;
+         dev->get_stats = lec_get_stats;
+-        dev->set_multicast_list = NULL;
++        dev->set_multicast_list = lec_set_multicast_list;
+         dev->do_ioctl  = NULL;
+         printk("%s: Initialized!\n",dev->name);
+         return;
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-06-skb_pull.patch b/atm-06-skb_pull.patch
new file mode 100644 (file)
index 0000000..2e14e12
--- /dev/null
@@ -0,0 +1,28 @@
+In message <20030223.214513.120185268.davem@redhat.com>,"David S. Miller" writes:
+>Don't try to modify skb->{data,len} by hands, let the skb_*()
+>interfaces do it.  Use skb_pull() in this case.
+
+missed that function when i went looking for it.  again, the right way:
+
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.1
+retrieving revision 1.7
+diff -u -d -b -w -r1.1 -r1.7
+--- linux/net/atm/lec.c        20 Feb 2003 13:46:30 -0000      1.1
++++ linux/net/atm/lec.c        24 Feb 2003 13:34:43 -0000      1.7
+@@ -711,7 +705,7 @@
+                         lec_arp_check_empties(priv, vcc, skb);
+                 }
+                 skb->dev = dev;
+-                skb->data += 2; /* skip lec_id */
++                skb_pull(skb, 2); /* skip lec_id */
+ #ifdef CONFIG_TR
+                 if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
+                 else
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-07-atm_dev_lock-sem.patch b/atm-07-atm_dev_lock-sem.patch
new file mode 100644 (file)
index 0000000..93013fa
--- /dev/null
@@ -0,0 +1,209 @@
+      [PATCH][2.4] convert atm_dev_lock from spinlock to semaphore
+From: chas williams (chas@locutus.cmf.nrl.navy.mil)
+Date: Tue Feb 18 2003 - 16:31:55 EST
+same as the 2.5 patch just for 2.4 kernels.
+Index: linux/net/atm/addr.c
+===================================================================
+RCS file: /afs/cmf/project/cvsroot/linux/net/atm/addr.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -u -d -b -w -r1.2 -r1.3
+--- linux/net/atm/addr.c 5 Mar 2002 13:41:26 -0000 1.2
++++ linux/net/atm/addr.c 14 Feb 2003 17:02:40 -0000 1.3
+@@ -42,7 +42,6 @@
+  */
+ static DECLARE_MUTEX(local_lock);
+-extern  spinlock_t atm_dev_lock;
+ static void notify_sigd(struct atm_dev *dev)
+ {
+Index: linux/net/atm/common.c
+===================================================================
+RCS file: /afs/cmf/project/cvsroot/linux/net/atm/common.c,v
+retrieving revision 1.5
+retrieving revision 1.6
+diff -u -d -b -w -r1.5 -r1.6
+--- linux/net/atm/common.c 14 Feb 2003 16:59:38 -0000 1.5
++++ linux/net/atm/common.c 14 Feb 2003 17:02:40 -0000 1.6
+@@ -18,6 +18,7 @@
+ #include <linux/capability.h>
+ #include <linux/mm.h>         /* verify_area */
+ #include <linux/sched.h>
++#include <linux/sem.h>
+ #include <linux/time.h>               /* struct timeval */
+ #include <linux/skbuff.h>
+ #include <linux/bitops.h>
+@@ -27,6 +28,7 @@
+ #include <asm/atomic.h>
+ #include <asm/poll.h>
+ #include <asm/ioctls.h>
++#include <asm/semaphore.h>
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ #include <linux/atmlec.h>
+@@ -86,7 +88,7 @@
+ #define DPRINTK(format,args...)
+ #endif
+-spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
++DECLARE_MUTEX(atm_dev_sem);
+ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
+ {
+@@ -154,7 +156,7 @@
+                               vcc->dev->ops->free_rx_skb(vcc,skb);
+                       else kfree_skb(skb);
+               }
+-              spin_lock (&atm_dev_lock);      
++              down(&atm_dev_sem);
+               fops_put (vcc->dev->ops);
+               if (atomic_read(&vcc->rx_inuse))
+                       printk(KERN_WARNING "atm_release_vcc: strange ... "
+@@ -162,11 +164,11 @@
+                           atomic_read(&vcc->rx_inuse));
+               bind_vcc(vcc,NULL);
+       } else
+-              spin_lock (&atm_dev_lock);      
++              down(&atm_dev_sem);
+       if (free_sk) free_atm_vcc_sk(sk);
+-      spin_unlock (&atm_dev_lock);
++      up(&atm_dev_sem);
+ }
+@@ -277,14 +279,14 @@
+       struct atm_dev *dev;
+       int return_val;
+-      spin_lock (&atm_dev_lock);
++      down(&atm_dev_sem);
+       dev = atm_find_dev(itf);
+       if (!dev)
+               return_val =  -ENODEV;
+       else
+               return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+-      spin_unlock (&atm_dev_lock);
++      up(&atm_dev_sem);
+       return return_val;
+ }
+@@ -316,10 +318,10 @@
+       else {
+               struct atm_dev *dev;
+-              spin_lock (&atm_dev_lock);
++              down(&atm_dev_sem);
+               for (dev = atm_devs; dev; dev = dev->next)
+                       if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+-              spin_unlock (&atm_dev_lock);
++              up(&atm_dev_sem);
+               if (!dev) return -ENODEV;
+       }
+       if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
+@@ -561,7 +563,7 @@
+       int error,len,size,number, ret_val;
+       ret_val = 0;
+-      spin_lock (&atm_dev_lock);
++      down(&atm_dev_sem);
+       vcc = ATM_SD(sock);
+       switch (cmd) {
+               case SIOCOUTQ:
+@@ -961,7 +963,7 @@
+               ret_val = 0;
+  done:
+-      spin_unlock (&atm_dev_lock); 
++      up(&atm_dev_sem);
+       return ret_val;
+ }
+Index: linux/net/atm/resources.c
+===================================================================
+RCS file: /afs/cmf/project/cvsroot/linux/net/atm/resources.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -u -d -b -w -r1.2 -r1.3
+--- linux/net/atm/resources.c 2 May 2002 16:56:23 -0000 1.2
++++ linux/net/atm/resources.c 14 Feb 2003 17:02:40 -0000 1.3
+@@ -25,7 +25,7 @@
+ struct atm_dev *atm_devs = NULL;
+ static struct atm_dev *last_dev = NULL;
+ struct atm_vcc *nodev_vccs = NULL;
+-extern spinlock_t atm_dev_lock;
++extern struct semaphore atm_dev_sem;
+ static struct atm_dev *alloc_atm_dev(const char *type)
+@@ -72,7 +72,7 @@
+ {
+       struct atm_dev *dev = NULL;
+-      spin_lock(&atm_dev_lock);
++      down(&atm_dev_sem);
+       dev = alloc_atm_dev(type);
+       if (!dev) {
+@@ -110,7 +110,7 @@
+ #endif
+ done:
+-      spin_unlock(&atm_dev_lock);
++      up(&atm_dev_sem);
+       return dev;
+ }
+@@ -120,9 +120,9 @@
+ #ifdef CONFIG_PROC_FS
+       if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
+ #endif
+-      spin_lock(&atm_dev_lock);
++      down(&atm_dev_sem);
+       __free_atm_dev(dev);
+-      spin_unlock(&atm_dev_lock);
++      up(&atm_dev_sem);
+ }
+ void shutdown_atm_dev(struct atm_dev *dev)
+Index: linux/net/atm/signaling.c
+===================================================================
+RCS file: /afs/cmf/project/cvsroot/linux/net/atm/signaling.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -u -d -b -w -r1.2 -r1.3
+--- linux/net/atm/signaling.c 12 Feb 2003 20:57:47 -0000 1.2
++++ linux/net/atm/signaling.c 14 Feb 2003 17:02:40 -0000 1.3
+@@ -33,7 +33,7 @@
+ struct atm_vcc *sigd = NULL;
+ static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
+-extern spinlock_t atm_dev_lock;
++extern struct semaphore atm_dev_sem;
+ static void sigd_put_skb(struct sk_buff *skb)
+ {
+@@ -220,9 +220,9 @@
+       skb_queue_purge(&vcc->recvq);
+       purge_vccs(nodev_vccs);
+-      spin_lock (&atm_dev_lock);
++      down(&atm_dev_sem);
+       for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+-      spin_unlock (&atm_dev_lock);
++      up(&atm_dev_sem);
+ }
+To unsubscribe from this list: send the line "unsubscribe
+linux-kernel" in
+the body of a message to [8]majordomo@vger.kernel.org
+More majordomo info at [9]http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at [10]http://www.tux.org/lkml/
diff --git a/atm-08-lane-MOD_USE_COUNT.patch b/atm-08-lane-MOD_USE_COUNT.patch
new file mode 100644 (file)
index 0000000..28bf47f
--- /dev/null
@@ -0,0 +1,158 @@
+lets try this again.  for now there are two owner pointers, the original
+in atmdev_ops and another in the struct shared between the common code
+and the lane code.  the shared one pointers to the private owner.
+would that be the 'right' way or should i just ignore the owner field
+in atmdev_ops.
+
+Index: linux/net/atm/lec.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.h,v
+retrieving revision 1.3
+retrieving revision 1.4
+diff -u -r1.3 -r1.4
+--- linux/net/atm/lec.h        24 Feb 2003 13:24:46 -0000      1.3
++++ linux/net/atm/lec.h        26 Feb 2003 15:52:44 -0000      1.4
+@@ -65,6 +65,7 @@
+         int (*mcast_attach)(struct atm_vcc *vcc, int arg);
+         int (*vcc_attach)(struct atm_vcc *vcc, void *arg);
+         struct net_device **(*get_lecs)(void);
++        struct module *owner;
+ };
+ /*
+Index: linux/net/atm/proc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/proc.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -u -r1.1 -r1.2
+--- linux/net/atm/proc.c       20 Feb 2003 13:46:30 -0000      1.1
++++ linux/net/atm/proc.c       26 Feb 2003 15:52:44 -0000      1.2
+@@ -444,8 +444,11 @@
+       }
+       if (atm_lane_ops.get_lecs == NULL)
+               return 0; /* the lane module is not there yet */
+-      else
+-              dev_lec = atm_lane_ops.get_lecs();
++
++      if (!try_module_get(atm_lane_ops.owner))
++              return 0;
++
++      dev_lec = atm_lane_ops.get_lecs();
+       count = pos;
+       for(d=0;d<MAX_LEC_ITF;d++) {
+@@ -458,6 +461,7 @@
+                               e=sprintf(buf,"%s ",
+                                   dev_lec[d]->name);
+                               lec_info(entry,buf+e);
++                              module_put(atm_lane_ops.owner);
+                               return strlen(buf);
+                       }
+               }
+@@ -466,6 +470,7 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
++                      module_put(atm_lane_ops.owner);
+                       return strlen(buf);
+               }
+               for(entry=priv->lec_no_forward; entry;
+@@ -473,6 +478,7 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
++                      module_put(atm_lane_ops.owner);
+                       return strlen(buf);
+               }
+               for(entry=priv->mcast_fwds; entry;
+@@ -480,9 +486,11 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
++                      module_put(atm_lane_ops.owner);
+                       return strlen(buf);
+               }
+       }
++      module_put(atm_lane_ops.owner);
+       return 0;
+ }
+ #endif
+Index: linux/net/atm/common.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/common.c,v
+retrieving revision 1.4
+retrieving revision 1.5
+diff -u -r1.4 -r1.5
+--- linux/net/atm/common.c     25 Feb 2003 20:06:54 -0000      1.4
++++ linux/net/atm/common.c     26 Feb 2003 15:52:44 -0000      1.5
+@@ -685,12 +685,15 @@
+                       }
+                         if (atm_lane_ops.lecd_attach == NULL)
+                               atm_lane_init();
+-                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
++                        if (!try_module_get(atm_lane_ops.owner)) { /* try again */
+                               ret_val = -ENOSYS;
+                               goto done;
+                       }
+                       error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+-                      if (error >= 0) sock->state = SS_CONNECTED;
++                      if (error >= 0)
++                              sock->state = SS_CONNECTED;
++                      else
++                              module_put(atm_lane_ops.owner);
+                       ret_val =  error;
+                       goto done;
+                 case ATMLEC_MCAST:
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.8
+retrieving revision 1.10
+diff -u -r1.8 -r1.10
+--- linux/net/atm/lec.c        25 Feb 2003 11:59:08 -0000      1.8
++++ linux/net/atm/lec.c        26 Feb 2003 15:52:44 -0000      1.10
+@@ -543,12 +543,12 @@
+         }
+   
+       printk("%s: Shut down!\n", dev->name);
+-        MOD_DEC_USE_COUNT;
+ }
+ static struct atmdev_ops lecdev_ops = {
+         close:        lec_atm_close,
+-        send: lec_atm_send
++        send: lec_atm_send,
++        owner:        THIS_MODULE
+ };
+ static struct atm_dev lecatm_dev = {
+@@ -824,7 +824,6 @@
+         if (dev_lec[i]->flags & IFF_UP) {
+                 netif_start_queue(dev_lec[i]);
+         }
+-        MOD_INC_USE_COUNT;
+         return i;
+ }
+@@ -834,6 +833,7 @@
+         ops->mcast_attach = lec_mcast_attach;
+         ops->vcc_attach = lec_vcc_attach;
+         ops->get_lecs = get_dev_lec;
++        ops->owner = lecdev_ops.owner;
+         printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+@@ -859,6 +859,7 @@
+         atm_lane_ops.mcast_attach = NULL;
+         atm_lane_ops.vcc_attach = NULL;
+         atm_lane_ops.get_lecs = NULL;
++        atm_lane_ops.owner = NULL;
+         for (i = 0; i < MAX_LEC_ITF; i++) {
+                 if (dev_lec[i] != NULL) {
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-09-suni-MOD_USE_COUNT.patch b/atm-09-suni-MOD_USE_COUNT.patch
new file mode 100644 (file)
index 0000000..1e677dc
--- /dev/null
@@ -0,0 +1,52 @@
+exporting a symbol declared as __init is bogus.  additonally, suni
+doesnt need to modify its ref counts, to quote:
+
+Q: My code use "MOD_INC_USE_COUNT".  Do I still need to adjust my
+   module count when someone calls one of my functions?
+A: No ...
+           ... It could be another module using one of your
+   EXPORT_SYMBOL'ed functions, in which case you cannot be removed
+   since they would have to be removed first. ...
+
+this is certainly the case for suni which is used by the various
+atm drivers.
+
+Index: linux/drivers/atm/suni.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/drivers/atm/suni.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -u -r1.1 -r1.3
+--- linux/drivers/atm/suni.c   20 Feb 2003 13:45:03 -0000      1.1
++++ linux/drivers/atm/suni.c   26 Feb 2003 15:43:30 -0000      1.3
+@@ -233,8 +233,6 @@
+       if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
+               return -ENOMEM;
+-      MOD_INC_USE_COUNT;
+-
+       PRIV(dev)->dev = dev;
+       spin_lock_irqsave(&sunis_lock,flags);
+       first = !sunis;
+@@ -280,7 +278,6 @@
+       spin_unlock_irqrestore(&sunis_lock,flags);
+       kfree(PRIV(dev));
+-      MOD_DEC_USE_COUNT;
+       return 0;
+ }
+@@ -293,7 +290,7 @@
+ };
+-int __init suni_init(struct atm_dev *dev)
++int suni_init(struct atm_dev *dev)
+ {
+       unsigned char mri;
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-10-modular-atm.patch b/atm-10-modular-atm.patch
new file mode 100644 (file)
index 0000000..9dac9a2
--- /dev/null
@@ -0,0 +1,1126 @@
+the following patch makes atm a module.  this patch also fixes a 
+number of other problems:  MOD_INC/MOD_DEC are gone in lec and mpc
+(however i needed to use module_put() inside lec, mpc and clip due to
+the way the user space 'clients' unregister from the modules), clip
+is a module (i wrote the clip module_exit() function -- its *probably*
+correct), structs are now exported as pointers (if someone has a
+compelling reason it should remain the old way let me know), ipcommon.c
+is included by clip.c and doesnt export symbols -- it should probably
+just be split eventually with only llc_oui residing in the kernel
+(and exported) and skb_migrate moved to clip -- this really depends
+on the status of CONFIG_NET_SCH_ATM.
+
+Index: linux/net/atm/clip.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/clip.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 clip.c
+--- linux/net/atm/clip.c       20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/clip.c       3 Mar 2003 19:33:38 -0000
+@@ -7,6 +7,7 @@
+ #include <linux/string.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h> /* for UINT_MAX */
++#include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/wait.h>
+@@ -48,6 +49,7 @@
+ static struct timer_list idle_timer;
+ static int start_timer = 1;
++#include "ipcommon.c"
+ static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
+ {
+@@ -696,6 +698,7 @@
+                   "pending\n");
+       skb_queue_purge(&vcc->recvq);
+       DPRINTK("(done)\n");
++      MOD_DEC_USE_COUNT;
+ }
+@@ -747,10 +750,50 @@
+       return 0;
+ }
++static struct atm_clip_ops __atm_clip_ops = {
++      clip_create:            clip_create,
++      clip_mkip:              clip_mkip,
++      clip_setentry:          clip_setentry,
++      clip_encap:             clip_encap,
++      clip_push:              clip_push,
++      atm_init_atmarp:        atm_init_atmarp,
++      clip_tbl:               &clip_tbl,
++      owner:                  THIS_MODULE
++};
+-void atm_clip_init(void)
++static int __init atm_clip_init(void)
+ {
++      extern struct atm_clip_ops *atm_clip_ops;
++
+       clip_tbl.lock = RW_LOCK_UNLOCKED;
+       clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id,
+           clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++
++      atm_clip_ops = &__atm_clip_ops;
++
++      return 0;
+ }
++
++static void __exit atm_clip_exit(void)
++{
++      extern struct atm_clip_ops *atm_clip_ops;
++      struct net_device *dev, *next;
++
++      atm_clip_ops = NULL;
++
++      next = clip_devs;
++      while (next) {
++              dev = next;
++              next = PRIV(dev)->next;
++              unregister_netdev(dev);
++              kfree(dev);
++      }
++      if (start_timer == 0) del_timer(&idle_timer);
++
++      kmem_cache_destroy(clip_tbl.kmem_cachep);
++}
++
++module_init(atm_clip_init);
++module_exit(atm_clip_exit);
++
++MODULE_LICENSE("GPL");
+Index: linux/net/atm/common.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/common.c,v
+retrieving revision 1.5
+diff -u -r1.5 common.c
+--- linux/net/atm/common.c     26 Feb 2003 15:52:44 -0000      1.5
++++ linux/net/atm/common.c     3 Mar 2003 19:41:21 -0000
+@@ -33,16 +33,16 @@
+ #include <linux/atmlec.h>
+ #include "lec.h"
+ #include "lec_arpc.h"
+-struct atm_lane_ops atm_lane_ops;
+-#endif
++struct atm_lane_ops *atm_lane_ops = NULL;
+ #ifdef CONFIG_ATM_LANE_MODULE
+ EXPORT_SYMBOL(atm_lane_ops);
+ #endif
++#endif
+ #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
+ #include <linux/atmmpc.h>
+ #include "mpc.h"
+-struct atm_mpoa_ops atm_mpoa_ops;
++struct atm_mpoa_ops *atm_mpoa_ops = NULL;
+ #endif
+ #ifdef CONFIG_ATM_MPOA_MODULE
+ EXPORT_SYMBOL(atm_mpoa_ops);
+@@ -59,6 +59,14 @@
+ #endif
+ #endif
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
++#include <net/atmclip.h>
++struct atm_clip_ops *atm_clip_ops = NULL;
++#ifdef CONFIG_ATM_CLIP_MODULE
++EXPORT_SYMBOL(atm_clip_ops);
++#endif
++#endif
++
+ #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE)
+ int (*pppoatm_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
+ EXPORT_SYMBOL(pppoatm_ioctl_hook);
+@@ -68,9 +76,6 @@
+ #include "common.h"           /* prototypes */
+ #include "protocols.h"                /* atm_init_<transport> */
+ #include "addr.h"             /* address registry */
+-#ifdef CONFIG_ATM_CLIP
+-#include <net/atmclip.h>      /* for clip_create */
+-#endif
+ #include "signaling.h"                /* for WAITING and sigd_attach */
+@@ -642,39 +647,50 @@
+                       if (!error) sock->state = SS_CONNECTED;
+                       ret_val = error;
+                       goto done;
+-#ifdef CONFIG_ATM_CLIP
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+               case SIOCMKCLIP:
+                       if (!capable(CAP_NET_ADMIN))
+                               ret_val = -EPERM;
+                       else 
+-                              ret_val = clip_create(arg);
++                              ret_val = atm_clip_ops->clip_create(arg);
+                       goto done;
+               case ATMARPD_CTRL:
+                       if (!capable(CAP_NET_ADMIN)) {
+                               ret_val = -EPERM;
+                               goto done;
+                       }
+-                      error = atm_init_atmarp(vcc);
+-                      if (!error) sock->state = SS_CONNECTED;
++#if defined(CONFIG_ATM_CLIP_MODULE)
++                      if (atm_clip_ops == NULL)
++                              request_module("clip");
++#endif
++                      if (atm_clip_ops && !try_inc_mod_count(atm_clip_ops->owner)) {
++                              ret_val = -ENOSYS;
++                              goto done;
++                      }
++                      error = atm_clip_ops->atm_init_atmarp(vcc);
++                      if (!error)
++                              sock->state = SS_CONNECTED;
++                      else if (atm_clip_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_clip_ops->owner);
+                       ret_val = error;
+                       goto done;
+               case ATMARP_MKIP:
+                       if (!capable(CAP_NET_ADMIN)) 
+                               ret_val = -EPERM;
+                       else 
+-                              ret_val = clip_mkip(vcc,arg);
++                              ret_val = atm_clip_ops->clip_mkip(vcc,arg);
+                       goto done;
+               case ATMARP_SETENTRY:
+                       if (!capable(CAP_NET_ADMIN)) 
+                               ret_val = -EPERM;
+                       else
+-                              ret_val = clip_setentry(vcc,arg);
++                              ret_val = atm_clip_ops->clip_setentry(vcc,arg);
+                       goto done;
+               case ATMARP_ENCAP:
+                       if (!capable(CAP_NET_ADMIN)) 
+                               ret_val = -EPERM;
+                       else
+-                              ret_val = clip_encap(vcc,arg);
++                              ret_val = atm_clip_ops->clip_encap(vcc,arg);
+                       goto done;
+ #endif
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+@@ -683,30 +699,32 @@
+                               ret_val = -EPERM;
+                               goto done;
+                       }
+-                        if (atm_lane_ops.lecd_attach == NULL)
+-                              atm_lane_init();
+-                        if (!try_module_get(atm_lane_ops.owner)) { /* try again */
++#if defined(CONFIG_ATM_LANE_MODULE)
++                        if (atm_lane_ops == NULL)
++                              request_module("lec");
++#endif
++                        if (atm_lane_ops && !try_inc_mod_count(atm_lane_ops->owner)) {
+                               ret_val = -ENOSYS;
+                               goto done;
+                       }
+-                      error = atm_lane_ops.lecd_attach(vcc, (int)arg);
++                      error = atm_lane_ops->lecd_attach(vcc, (int)arg);
+                       if (error >= 0)
+                               sock->state = SS_CONNECTED;
+-                      else
+-                              module_put(atm_lane_ops.owner);
++                      else if (atm_lane_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+                       ret_val =  error;
+                       goto done;
+                 case ATMLEC_MCAST:
+                       if (!capable(CAP_NET_ADMIN))
+                               ret_val = -EPERM;
+                       else
+-                              ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
++                              ret_val = atm_lane_ops->mcast_attach(vcc, (int)arg);
+                       goto done;
+                 case ATMLEC_DATA:
+                       if (!capable(CAP_NET_ADMIN))
+                               ret_val = -EPERM;
+                       else
+-                              ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
++                              ret_val = atm_lane_ops->vcc_attach(vcc, (void*)arg);
+                       goto done;
+ #endif
+ #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
+@@ -715,21 +733,26 @@
+                               ret_val = -EPERM;
+                               goto done;
+                       }
+-                      if (atm_mpoa_ops.mpoad_attach == NULL)
+-                                atm_mpoa_init();
+-                      if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
++#if defined(CONFIG_ATM_MPOA_MODULE)
++                      if (atm_mpoa_ops == NULL)
++                                request_module("mpoa");
++#endif
++                      if (atm_mpoa_ops && !try_inc_mod_count(atm_mpoa_ops->owner)) {
+                               ret_val = -ENOSYS;
+                               goto done;
+                       }
+-                      error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+-                      if (error >= 0) sock->state = SS_CONNECTED;
++                      error = atm_mpoa_ops->mpoad_attach(vcc, (int)arg);
++                      if (error >= 0)
++                              sock->state = SS_CONNECTED;
++                      else if (atm_mpoa_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_mpoa_ops->owner);
+                       ret_val = error;
+                       goto done;
+               case ATMMPC_DATA:
+                       if (!capable(CAP_NET_ADMIN)) 
+                               ret_val = -EPERM;
+                       else
+-                              ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
++                              ret_val = atm_mpoa_ops->vcc_attach(vcc, arg);
+                       goto done;
+ #endif
+ #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
+@@ -1105,40 +1128,6 @@
+ }
+-/*
+- * lane_mpoa_init.c: A couple of helper functions
+- * to make modular LANE and MPOA client easier to implement
+- */
+-
+-/*
+- * This is how it goes:
+- *
+- * if xxxx is not compiled as module, call atm_xxxx_init_ops()
+- *    from here
+- * else call atm_mpoa_init_ops() from init_module() within
+- *    the kernel when xxxx module is loaded
+- *
+- * In either case function pointers in struct atm_xxxx_ops
+- * are initialized to their correct values. Either they
+- * point to functions in the module or in the kernel
+- */
+- 
+-extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */
+-extern struct atm_lane_ops atm_lane_ops; /* in common.c */
+-
+-#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
+-void atm_mpoa_init(void)
+-{
+-#ifndef CONFIG_ATM_MPOA_MODULE /* not module */
+-        atm_mpoa_init_ops(&atm_mpoa_ops);
+-#else
+-      request_module("mpoa");
+-#endif
+-
+-        return;
+-}
+-#endif
+-
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+@@ -1149,15 +1138,33 @@
+ EXPORT_SYMBOL(br_fdb_put_hook);
+ #endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
+ #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
++#endif /* defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) */
++
+-void atm_lane_init(void)
++static int __init atm_init(void)
+ {
+-#ifndef CONFIG_ATM_LANE_MODULE /* not module */
+-        atm_lane_init_ops(&atm_lane_ops);
+-#else
+-      request_module("lec");
++      int error = 0;
++
++      if (atmpvc_init() < 0)
++              return -1;
++      if (atmsvc_init() < 0)
++              return -1;
++#ifdef CONFIG_PROC_FS
++        error = atm_proc_init();
++        if (error) printk("atm_proc_init fails with %d\n",error);
+ #endif
++      return error;
++}
+-        return;
+-}        
++static void __exit atm_exit(void)
++{
++#ifdef CONFIG_PROC_FS
++      atm_proc_exit();
+ #endif
++      atmsvc_exit();
++      atmpvc_exit();
++}
++
++module_init(atm_init);
++module_exit(atm_exit);
++MODULE_LICENSE("GPL");
+Index: linux/net/atm/common.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/common.h,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 common.h
+--- linux/net/atm/common.h     20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/common.h     27 Feb 2003 16:47:15 -0000
+@@ -28,7 +28,14 @@
+ void atm_release_vcc_sk(struct sock *sk,int free_sk);
+ void atm_shutdown_dev(struct atm_dev *dev);
++int atmsvc_init(void);
++void atmsvc_exit(void);
++
++int atmpvc_init(void);
++void atmpvc_exit(void);
++
+ int atm_proc_init(void);
++void atm_proc_exit(void);
+ /* SVC */
+Index: linux/net/atm/ipcommon.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/ipcommon.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 ipcommon.c
+--- linux/net/atm/ipcommon.c   20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/ipcommon.c   3 Mar 2003 16:51:32 -0000
+@@ -65,6 +65,3 @@
+       from->qlen = 0;
+       spin_unlock_irqrestore(&from->lock,flags);
+ }
+-
+-
+-EXPORT_SYMBOL(skb_migrate);
+Index: linux/net/atm/ipcommon.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/ipcommon.h,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 ipcommon.h
+--- linux/net/atm/ipcommon.h   20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/ipcommon.h   3 Mar 2003 16:52:24 -0000
+@@ -13,8 +13,6 @@
+ #include <linux/atmdev.h>
+-extern struct net_device *clip_devs;
+-
+ /*
+  * Appends all skbs from "from" to "to". The operation is atomic with respect
+  * to all other skb operations on "from" or "to".
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.11
+diff -u -r1.11 lec.c
+--- linux/net/atm/lec.c        3 Mar 2003 21:25:05 -0000       1.11
++++ linux/net/atm/lec.c        3 Mar 2003 21:27:05 -0000
+@@ -790,7 +790,6 @@
+                 dev_lec[i] = init_etherdev(NULL, size);
+                 if (!dev_lec[i])
+                         return -ENOMEM;
+-
+                 priv = dev_lec[i]->priv;
+                 priv->is_trdev = is_trdev;
+                 sprintf(dev_lec[i]->name, "lec%d", i);
+@@ -828,24 +827,20 @@
+         return i;
+ }
+-void atm_lane_init_ops(struct atm_lane_ops *ops)
+-{
+-        ops->lecd_attach = lecd_attach;
+-        ops->mcast_attach = lec_mcast_attach;
+-        ops->vcc_attach = lec_vcc_attach;
+-        ops->get_lecs = get_dev_lec;
+-        ops->owner = lecdev_ops.owner;
+-
+-        printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+-
+-      return;
+-}
++static struct atm_lane_ops __atm_lane_ops = {
++        lecd_attach:  lecd_attach,
++        mcast_attach: lec_mcast_attach,
++        vcc_attach:   lec_vcc_attach,
++        get_lecs:     get_dev_lec,
++        owner:                THIS_MODULE
++};
+ static int __init lane_module_init(void)
+ {
+-        extern struct atm_lane_ops atm_lane_ops;
++        extern struct atm_lane_ops *atm_lane_ops;
+-        atm_lane_init_ops(&atm_lane_ops);
++        atm_lane_ops = &__atm_lane_ops;
++        printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+         return 0;
+ }
+@@ -852,14 +847,10 @@
+ static void __exit lane_module_cleanup(void)
+ {
+         int i;
+-        extern struct atm_lane_ops atm_lane_ops;
++        extern struct atm_lane_ops *atm_lane_ops;
+         struct lec_priv *priv;
+-        atm_lane_ops.lecd_attach = NULL;
+-        atm_lane_ops.mcast_attach = NULL;
+-        atm_lane_ops.vcc_attach = NULL;
+-        atm_lane_ops.get_lecs = NULL;
+-        atm_lane_ops.owner = NULL;
++        atm_lane_ops = NULL;
+         for (i = 0; i < MAX_LEC_ITF; i++) {
+                 if (dev_lec[i] != NULL) {
+@@ -871,7 +863,7 @@
+                         unregister_netdev(dev_lec[i]);
+                         kfree(dev_lec[i]);
+                         dev_lec[i] = NULL;
+-                }
++              }
+         }
+         return;                                    
+@@ -1021,7 +1013,7 @@
+ #include <linux/timer.h>
+ #include <asm/param.h>
+ #include <asm/atomic.h>
+-#include <linux/inetdevice.h>
++#include <linux/netdevice.h>
+ #include <net/route.h>
+Index: linux/net/atm/lec.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.h,v
+retrieving revision 1.5
+diff -u -r1.5 lec.h
+--- linux/net/atm/lec.h        3 Mar 2003 21:25:05 -0000       1.5
++++ linux/net/atm/lec.h        3 Mar 2003 21:25:17 -0000
+@@ -155,7 +156,5 @@
+                  unsigned char *atm_addr, struct sk_buff *data);
+ void lec_push(struct atm_vcc *vcc, struct sk_buff *skb);
+-void atm_lane_init(void);
+-void atm_lane_init_ops(struct atm_lane_ops *ops);
+ #endif /* _LEC_H_ */
+Index: linux/net/atm/mpc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/mpc.c,v
+retrieving revision 1.3
+diff -u -r1.3 mpc.c
+--- linux/net/atm/mpc.c        3 Mar 2003 21:25:05 -0000       1.3
++++ linux/net/atm/mpc.c        3 Mar 2003 21:25:19 -0000
+@@ -799,7 +799,6 @@
+                       send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
+       }
+-      MOD_INC_USE_COUNT;
+       return arg;
+ }
+@@ -1390,11 +1389,17 @@
+       return;
+ }
+-void atm_mpoa_init_ops(struct atm_mpoa_ops *ops)
++struct atm_mpoa_ops __atm_mpoa_ops = {
++        mpoad_attach: atm_mpoa_mpoad_attach,
++        vcc_attach:   atm_mpoa_vcc_attach,
++        owner:                THIS_MODULE
++};
++
++static int __init atm_mpoa_init(void)
+ {
+-      ops->mpoad_attach = atm_mpoa_mpoad_attach;
+-      ops->vcc_attach = atm_mpoa_vcc_attach;
++      extern struct atm_mpoa_ops *atm_mpoa_ops;
++      atm_mpoa_ops = &__atm_mpoa_ops;
+ #ifdef CONFIG_PROC_FS
+       if(mpc_proc_init() != 0)
+               printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
+@@ -1404,22 +1409,12 @@
+       printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
+-      return;
+-}
+-
+-#ifdef MODULE
+-int init_module(void)
+-{
+-      extern struct atm_mpoa_ops atm_mpoa_ops;
+-
+-      atm_mpoa_init_ops(&atm_mpoa_ops);
+-
+       return 0;
+ }
+-void cleanup_module(void)
++static void __exit atm_mpoa_cleanup(void)
+ {
+-      extern struct atm_mpoa_ops atm_mpoa_ops;
++      extern struct atm_mpoa_ops *atm_mpoa_ops;
+       struct mpoa_client *mpc, *tmp;
+       struct atm_mpoa_qos *qos, *nextqos;
+       struct lec_priv *priv;
+@@ -1430,8 +1425,7 @@
+       del_timer(&mpc_timer);
+       unregister_netdevice_notifier(&mpoa_notifier);
+-      atm_mpoa_ops.mpoad_attach = NULL;
+-      atm_mpoa_ops.vcc_attach = NULL;
++      atm_mpoa_ops = NULL;
+       mpc = mpcs;
+       mpcs = NULL;
+@@ -1463,8 +1457,9 @@
+               kfree(qos);
+               qos = nextqos;
+       }
+-
+-      return;
+ }
+-#endif /* MODULE */
++
++module_init(atm_mpoa_init);
++module_exit(atm_mpoa_cleanup);
++
+ MODULE_LICENSE("GPL");
+Index: linux/net/atm/mpc.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/mpc.h,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 mpc.h
+--- linux/net/atm/mpc.h        20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/mpc.h        1 Mar 2003 13:37:05 -0000
+@@ -48,11 +48,8 @@
+ struct atm_mpoa_ops {
+         int (*mpoad_attach)(struct atm_vcc *vcc, int arg);  /* attach mpoa daemon  */
+         int (*vcc_attach)(struct atm_vcc *vcc, long arg);   /* attach shortcut vcc */
++        struct module *owner;
+ };
+-
+-/* Boot/module initialization function */
+-void atm_mpoa_init(void);
+-void atm_mpoa_init_ops(struct atm_mpoa_ops *ops);
+ /* MPOA QoS operations */
+ struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos);
+Index: linux/net/atm/proc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/proc.c,v
+retrieving revision 1.2
+diff -u -r1.2 proc.c
+--- linux/net/atm/proc.c       26 Feb 2003 15:52:44 -0000      1.2
++++ linux/net/atm/proc.c       1 Mar 2003 14:39:12 -0000
+@@ -39,16 +39,15 @@
+ #include "common.h" /* atm_proc_init prototype */
+ #include "signaling.h" /* to get sigd - ugly too */
+-#ifdef CONFIG_ATM_CLIP
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+ #include <net/atmclip.h>
+-#include "ipcommon.h"
+-extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb);
++extern struct atm_clip_ops *atm_clip_ops; /* in common.c */
+ #endif
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ #include "lec.h"
+ #include "lec_arpc.h"
+-extern struct atm_lane_ops atm_lane_ops; /* in common.c */
++extern struct atm_lane_ops *atm_lane_ops; /* in common.c */
+ #endif
+ static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
+@@ -89,7 +88,7 @@
+ }
+-#ifdef CONFIG_ATM_CLIP
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+ static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
+@@ -178,8 +177,8 @@
+           aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
+           class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
+           class_name[vcc->qos.txtp.traffic_class]);
+-#ifdef CONFIG_ATM_CLIP
+-      if (vcc->push == clip_push) {
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
++      if (atm_clip_ops && (vcc->push == atm_clip_ops->clip_push)) {
+               struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
+               struct net_device *dev;
+@@ -393,7 +392,7 @@
+       return 0;
+ }
+-#ifdef CONFIG_ATM_CLIP
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+ static int atm_arp_info(loff_t pos,char *buf)
+ {
+       struct neighbour *n;
+@@ -403,28 +402,30 @@
+               return sprintf(buf,"IPitf TypeEncp Idle IP address      "
+                   "ATM address\n");
+       }
++      if (!atm_clip_ops)
++              return 0;
+       count = pos;
+-      read_lock_bh(&clip_tbl.lock);
++      read_lock_bh(&atm_clip_ops->clip_tbl->lock);
+       for (i = 0; i <= NEIGH_HASHMASK; i++)
+-              for (n = clip_tbl.hash_buckets[i]; n; n = n->next) {
++              for (n = atm_clip_ops->clip_tbl->hash_buckets[i]; n; n = n->next) {
+                       struct atmarp_entry *entry = NEIGH2ENTRY(n);
+                       struct clip_vcc *vcc;
+                       if (!entry->vccs) {
+                               if (--count) continue;
+                               atmarp_info(n->dev,entry,NULL,buf);
+-                              read_unlock_bh(&clip_tbl.lock);
++                              read_unlock_bh(&atm_clip_ops->clip_tbl->lock);
+                               return strlen(buf);
+                       }
+                       for (vcc = entry->vccs; vcc;
+                           vcc = vcc->next) {
+                               if (--count) continue;
+                               atmarp_info(n->dev,entry,vcc,buf);
+-                              read_unlock_bh(&clip_tbl.lock);
++                              read_unlock_bh(&atm_clip_ops->clip_tbl->lock);
+                               return strlen(buf);
+                       }
+               }
+-      read_unlock_bh(&clip_tbl.lock);
++      read_unlock_bh(&atm_clip_ops->clip_tbl->lock);
+       return 0;
+ }
+ #endif
+@@ -442,13 +443,13 @@
+                   "                          Status            Flags "
+                   "VPI/VCI Recv VPI/VCI\n");
+       }
+-      if (atm_lane_ops.get_lecs == NULL)
++      if (!atm_lane_ops)
+               return 0; /* the lane module is not there yet */
+-      if (!try_module_get(atm_lane_ops.owner))
++      if (!try_inc_mod_count(atm_lane_ops->owner))
+               return 0;
+-      dev_lec = atm_lane_ops.get_lecs();
++      dev_lec = atm_lane_ops->get_lecs();
+       count = pos;
+       for(d=0;d<MAX_LEC_ITF;d++) {
+@@ -461,7 +462,8 @@
+                               e=sprintf(buf,"%s ",
+                                   dev_lec[d]->name);
+                               lec_info(entry,buf+e);
+-                              module_put(atm_lane_ops.owner);
++                              if (atm_lane_ops->owner)
++                                      __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+                               return strlen(buf);
+                       }
+               }
+@@ -470,7 +471,8 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
+-                      module_put(atm_lane_ops.owner);
++                      if (atm_lane_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+                       return strlen(buf);
+               }
+               for(entry=priv->lec_no_forward; entry;
+@@ -478,7 +479,8 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
+-                      module_put(atm_lane_ops.owner);
++                      if (atm_lane_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+                       return strlen(buf);
+               }
+               for(entry=priv->mcast_fwds; entry;
+@@ -486,11 +487,13 @@
+                       if (--count) continue;
+                       e=sprintf(buf,"%s ",dev_lec[d]->name);
+                       lec_info(entry, buf+e);
+-                      module_put(atm_lane_ops.owner);
++                      if (atm_lane_ops->owner)
++                              __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+                       return strlen(buf);
+               }
+       }
+-      module_put(atm_lane_ops.owner);
++      if (atm_lane_ops->owner)
++              __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
+       return 0;
+ }
+ #endif
+@@ -591,12 +592,11 @@
+     name->proc_fops = &proc_spec_atm_operations; \
+     name->owner = THIS_MODULE
++struct proc_dir_entry *devices = NULL, *pvc = NULL, *svc = NULL;
++struct proc_dir_entry *arp = NULL, *lec = NULL, *vc = NULL;
+ int __init atm_proc_init(void)
+ {
+-      struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL;
+-      struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL;
+-
+       atm_proc_root = proc_mkdir("net/atm",NULL);
+       if (!atm_proc_root)
+               return -ENOMEM;
+@@ -604,7 +604,7 @@
+       CREATE_ENTRY(pvc);
+       CREATE_ENTRY(svc);
+       CREATE_ENTRY(vc);
+-#ifdef CONFIG_ATM_CLIP
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+       CREATE_ENTRY(arp);
+ #endif
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+@@ -621,4 +621,15 @@
+       if (vc) remove_proc_entry("vc",atm_proc_root);
+       remove_proc_entry("net/atm",NULL);
+       return -ENOMEM;
++}
++
++void __exit atm_proc_exit(void)
++{
++      if (vc) remove_proc_entry("vc",atm_proc_root);
++      if (lec) remove_proc_entry("lec",atm_proc_root);
++      if (arp) remove_proc_entry("arp",atm_proc_root);
++      if (svc) remove_proc_entry("svc",atm_proc_root);
++      if (pvc) remove_proc_entry("pvc",atm_proc_root);
++      if (devices) remove_proc_entry("devices",atm_proc_root);
++      remove_proc_entry("net/atm",NULL);
+ }
+Index: linux/net/atm/pvc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/pvc.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 pvc.c
+--- linux/net/atm/pvc.c        20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/pvc.c        1 Mar 2003 14:11:17 -0000
+@@ -15,9 +15,6 @@
+ #include <linux/skbuff.h>
+ #include <linux/bitops.h>
+ #include <net/sock.h>         /* for sock_no_* */
+-#ifdef CONFIG_ATM_CLIP
+-#include <net/atmclip.h>
+-#endif
+ #include "resources.h"                /* devs and vccs */
+ #include "common.h"           /* common for PVCs and SVCs */
+@@ -121,23 +118,20 @@
+  */
+-static int __init atmpvc_init(void)
++int __init atmpvc_init(void)
+ {
+       int error;
+       error = sock_register(&pvc_family_ops);
+       if (error < 0) {
+-              printk(KERN_ERR "ATMPVC: can't register (%d)",error);
++              printk(KERN_ERR "ATMPVC: can't register (%d)", error);
+               return error;
+       }
+-#ifdef CONFIG_ATM_CLIP
+-      atm_clip_init();
+-#endif
+-#ifdef CONFIG_PROC_FS
+-      error = atm_proc_init();
+-      if (error) printk("atm_proc_init fails with %d\n",error);
+-#endif
+-      return 0;
++
++      return error;
+ }
+-module_init(atmpvc_init);
++void __exit atmpvc_exit(void)
++{
++      sock_unregister(PF_ATMPVC);
++}
+Index: linux/net/atm/svc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/svc.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 svc.c
+--- linux/net/atm/svc.c        20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/svc.c        27 Feb 2003 16:48:54 -0000
+@@ -439,13 +439,19 @@
+  *    Initialize the ATM SVC protocol family
+  */
+-static int __init atmsvc_init(void)
++int __init atmsvc_init(void)
+ {
+-      if (sock_register(&svc_family_ops) < 0) {
+-              printk(KERN_ERR "ATMSVC: can't register");
++      int error;
++
++      error = sock_register(&svc_family_ops);
++      if (error < 0) {
++              printk(KERN_ERR "ATMSVC: can't register (%d)\n", error);
+               return -1;
+       }
+       return 0;
+ }
+-module_init(atmsvc_init);
++void __exit atmsvc_exit(void)
++{
++      sock_unregister(PF_ATMSVC);
++}
+Index: linux/include/net/atmclip.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/include/net/atmclip.h,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 atmclip.h
+--- linux/include/net/atmclip.h        20 Feb 2003 13:45:58 -0000      1.1.1.1
++++ linux/include/net/atmclip.h        1 Mar 2003 13:59:31 -0000
+@@ -62,6 +62,16 @@
+ int clip_mkip(struct atm_vcc *vcc,int timeout);
+ int clip_setentry(struct atm_vcc *vcc,u32 ip);
+ int clip_encap(struct atm_vcc *vcc,int mode);
+-void atm_clip_init(void);
++
++struct atm_clip_ops {
++      int (*clip_create)(int number);
++      int (*clip_mkip)(struct atm_vcc *vcc,int timeout);
++      int (*clip_setentry)(struct atm_vcc *vcc,u32 ip);
++      int (*clip_encap)(struct atm_vcc *vcc,int mode);
++      void (*clip_push)(struct atm_vcc *vcc,struct sk_buff *skb);
++      int (*atm_init_atmarp)(struct atm_vcc *vcc);
++      struct neigh_table *clip_tbl;
++      struct module *owner;
++};
+ #endif
+--- linux-2.4.20/net/atm/clip.c.orig   Wed Mar  5 22:54:57 2003
++++ linux-2.4.20/net/atm/clip.c        Thu Mar  6 00:03:50 2003
+@@ -49,7 +49,13 @@
+ static struct timer_list idle_timer;
+ static int start_timer = 1;
+-#include "ipcommon.c"
++const unsigned char llc_oui[] = {
++      0xaa,   /* DSAP: non-ISO */
++      0xaa,   /* SSAP: non-ISO */
++      0x03,   /* Ctrl: Unnumbered Information Command PDU */
++      0x00,   /* OUI: EtherType */
++      0x00,
++      0x00 };
+ static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
+ {
+--- linux-2.4.20/net/atm/ipcommon.c.orig       Wed Mar  5 22:54:57 2003
++++ linux-2.4.20/net/atm/ipcommon.c    Thu Mar  6 00:03:48 2003
+@@ -22,15 +22,6 @@
+ #endif
+-const unsigned char llc_oui[] = {
+-      0xaa,   /* DSAP: non-ISO */
+-      0xaa,   /* SSAP: non-ISO */
+-      0x03,   /* Ctrl: Unnumbered Information Command PDU */
+-      0x00,   /* OUI: EtherType */
+-      0x00,
+-      0x00 };
+-
+-
+ /*
+  * skb_migrate appends the list at "from" to "to", emptying "from" in the
+  * process. skb_migrate is atomic with respect to all other skb operations on
+@@ -65,3 +56,5 @@
+       from->qlen = 0;
+       spin_unlock_irqrestore(&from->lock,flags);
+ }
++
++EXPORT_SYMBOL(skb_migrate);
+--- linux-2.4.20/net/Config.in.orig    Sat Aug  3 02:39:46 2002
++++ linux-2.4.20/net/Config.in Wed Mar  5 03:16:08 2003
+@@ -31,23 +31,13 @@
+    fi
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   bool 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM
+-   if [ "$CONFIG_ATM" = "y" ]; then
+-      if [ "$CONFIG_INET" = "y" ]; then
+-       bool '  Classical IP over ATM' CONFIG_ATM_CLIP
+-       if [ "$CONFIG_ATM_CLIP" = "y" ]; then
+-          bool '    Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP
+-       fi
+-      fi
+-      tristate '  LAN Emulation (LANE) support' CONFIG_ATM_LANE
+-      if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
+-       tristate '    Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA
+-      fi
+-      tristate '  RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684
+-      if [ "$CONFIG_ATM_BR2684" != "n" ]; then
+-            bool '    Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER
+-      fi
+-   fi
++   tristate 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM
++   dep_tristate '  Classical IP over ATM' CONFIG_ATM_CLIP $CONFIG_ATM $CONFIG_INET
++   dep_mbool '    Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP $CONFIG_ATM_CLIP
++   dep_tristate '  LAN Emulation (LANE) support' CONFIG_ATM_LANE $CONFIG_ATM $CONFIG_INET
++   dep_tristate '    Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA $CONFIG_ATM_LANE
++   dep_tristate '  RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684 $CONFIG_ATM $CONFIG_INET
++   dep_mbool '    Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER $CONFIG_ATM_BR2684
+ fi
+ tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q
+--- linux/arch/alpha/config.in.orig    Wed Mar  5 22:24:02 2003
++++ linux/arch/alpha/config.in Wed Mar  5 22:24:10 2003
+@@ -344,7 +344,7 @@
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+     source drivers/net/Config.in
+-    if [ "$CONFIG_ATM" = "y" ]; then
++    if [ "$CONFIG_ATM" != "n" ]; then
+       source drivers/atm/Config.in
+     fi
+   fi
+--- linux/arch/cris/config.in.orig     Wed Mar  5 22:24:24 2003
++++ linux/arch/cris/config.in  Wed Mar  5 22:24:31 2003
+@@ -198,7 +198,7 @@
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+     source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+          source drivers/atm/Config.in
+       fi
+   fi
+--- linux/arch/i386/config.in.orig     Wed Mar  5 22:24:33 2003
++++ linux/arch/i386/config.in  Wed Mar  5 22:24:39 2003
+@@ -406,7 +406,7 @@
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+          source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/parisc/config.in.orig   Wed Mar  5 22:25:34 2003
++++ linux/arch/parisc/config.in        Wed Mar  5 22:25:40 2003
+@@ -144,7 +144,7 @@
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+          source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/ppc/config.in.orig      Wed Mar  5 22:25:42 2003
++++ linux/arch/ppc/config.in   Wed Mar  5 22:25:48 2003
+@@ -292,7 +292,7 @@
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+     source drivers/net/Config.in
+-    if [ "$CONFIG_ATM" = "y" ]; then
++    if [ "$CONFIG_ATM" != "n" ]; then
+       source drivers/atm/Config.in
+     fi
+   fi
+--- linux/arch/ppc64/config.in.orig    Wed Mar  5 22:25:50 2003
++++ linux/arch/ppc64/config.in Wed Mar  5 22:25:55 2003
+@@ -138,7 +138,7 @@
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+          source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/sh/config.in.orig       Wed Mar  5 22:26:08 2003
++++ linux/arch/sh/config.in    Wed Mar  5 22:26:14 2003
+@@ -264,7 +264,7 @@
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+          source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/sparc/config.in.orig    Wed Mar  5 22:26:16 2003
++++ linux/arch/sparc/config.in Wed Mar  5 22:26:32 2003
+@@ -217,7 +217,7 @@
+         dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
+       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+         dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+-        if [ "$CONFIG_ATM" = "y" ]; then
++        if [ "$CONFIG_ATM" != "n" ]; then
+           dep_tristate '  PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP
+         fi
+       fi
+@@ -243,7 +243,7 @@
+ #      if [ "$CONFIG_FDDI" = "y" ]; then
+ #      fi
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+        source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/sparc64/config.in.orig  Wed Mar  5 22:26:39 2003
++++ linux/arch/sparc64/config.in       Wed Mar  5 22:26:45 2003
+@@ -242,7 +242,7 @@
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+       source drivers/atm/Config.in
+       fi
+    fi
+--- linux/arch/x86_64/config.in.orig   Wed Mar  5 22:26:51 2003
++++ linux/arch/x86_64/config.in        Wed Mar  5 22:27:11 2003
+@@ -173,7 +173,7 @@
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+ # seems to be largely not 64bit safe     
+-#      if [ "$CONFIG_ATM" = "y" ]; then
++#      if [ "$CONFIG_ATM" != "n" ]; then
+ #         source drivers/atm/Config.in
+ #      fi
+    fi
+--- linux/arch/mips/config-shared.in.orig      Wed Mar  5 22:25:13 2003
++++ linux/arch/mips/config-shared.in   Wed Mar  5 22:25:19 2003
+@@ -691,7 +691,7 @@
+    bool 'Network device support' CONFIG_NETDEVICES
+    if [ "$CONFIG_NETDEVICES" = "y" ]; then
+       source drivers/net/Config.in
+-      if [ "$CONFIG_ATM" = "y" ]; then
++      if [ "$CONFIG_ATM" != "n" ]; then
+        source drivers/atm/Config.in
+       fi
+    fi
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-11-correct-lec-net_device-names.patch b/atm-11-correct-lec-net_device-names.patch
new file mode 100644 (file)
index 0000000..3b4d569
--- /dev/null
@@ -0,0 +1,41 @@
+init_etherdev() allocates and registers the network device in one
+step.  it uses eth%d as the template for the device names.  this
+conflicts with already registered ethernet devices, like eth0.  since
+we want a fixed (and different name) this patch uses alloc_etherdev,
+rewrites the device name and then registers our interface.
+
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.12
+diff -u -r1.12 lec.c
+--- linux/net/atm/lec.c        3 Mar 2003 22:23:13 -0000       1.12
++++ linux/net/atm/lec.c        3 Mar 2003 22:29:02 -0000
+@@ -784,15 +784,19 @@
+                 size = sizeof(struct lec_priv);
+ #ifdef CONFIG_TR
+                 if (is_trdev)
+-                        dev_lec[i] = init_trdev(NULL, size);
++                        dev_lec[i] = alloc_trdev(size);
+                 else
+ #endif
+-                dev_lec[i] = init_etherdev(NULL, size);
++                dev_lec[i] = alloc_etherdev(size);
+                 if (!dev_lec[i])
+                         return -ENOMEM;
++                snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
++                if (register_netdev(dev_lec[i])) {
++                        kfree(dev_lec[i]);
++                        return -EINVAL;
++                }
+                 priv = dev_lec[i]->priv;
+                 priv->is_trdev = is_trdev;
+-                sprintf(dev_lec[i]->name, "lec%d", i);
+                 lec_init(dev_lec[i]);
+         } else {
+                 priv = dev_lec[i]->priv;
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-12-br2684-xmit-return.patch b/atm-12-br2684-xmit-return.patch
new file mode 100644 (file)
index 0000000..eac7504
--- /dev/null
@@ -0,0 +1,58 @@
+According to chas williams:
+> >> so wherever clip_start_xmit() calls dev_free_skb() it should return 1
+> >> instead of 0?
+> >> did i follow that correctly...?
+> 
+> i believe that you should only return non zero if you want the ip
+> stack to requeue the skb and try to send it again (perhaps your
+> driver was busy).  in practice this is rarely done.  if you drop 
+> the skb and return 1 this is going to create trouble.  check out
+> Documentation/networking/driver.txt.  it looks like br2684 should
+> simple not return 1 at the end of br2684_xmit_vcc.
+
+But that's br2684, not clip... and I posted the same thing about
+a week ago ;)
+
+--- linux-2.4.21-pre4/net/atm/br2684.c.orig    2002-08-03 02:39:46.000000000 +0200
++++ linux-2.4.21-pre4/net/atm/br2684.c 2003-02-26 15:11:48.000000000 +0100
+@@ -219,17 +219,19 @@
+               /* netif_stop_queue(dev); */
+               dev_kfree_skb(skb);
+               read_unlock(&devs_lock);
+-              return -EUNATCH;
++              /* Pretend we succeeded so the packet is dropped. */
++              return 0;
+       }
+       if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
+               /*
+                * We should probably use netif_*_queue() here, but that
+                * involves added complication.  We need to walk before
+                * we can run
++               *
++               * Note: at this point, skb is no longer valid.
++               * br2684_xmit_vcc() might have realloced or freed it.
++               * We don't need to worry about that.
+                */
+-              /* don't free here! this pointer might be no longer valid!
+-              dev_kfree_skb(skb);
+-              */
+               brdev->stats.tx_errors++;
+               brdev->stats.tx_fifo_errors++;
+       }
+
+
+Mike.
+-- 
+Anyone who is capable of getting themselves made President should
+on no account be allowed to do the job -- Douglas Adams.
+
+
+-------------------------------------------------------
+This SF.net email is sponsored by: Etnus, makers of TotalView, The debugger 
+for complex code. Debugging C/C++ programs can leave you feeling lost and 
+disoriented. TotalView can help you find your way. Available on major UNIX 
+and Linux platforms. Try it free. www.etnus.com
+_______________________________________________
+Linux-atm-general mailing list
+Linux-atm-general@lists.sourceforge.net
+https://lists.sourceforge.net/lists/listinfo/linux-atm-general
diff --git a/atm-13-atm_vcc-cleanup.patch b/atm-13-atm_vcc-cleanup.patch
new file mode 100644 (file)
index 0000000..1fb49b4
--- /dev/null
@@ -0,0 +1,844 @@
+it has been suggested that atm_vcc has redundant members with
+struct sock.
+
+this patch removes family, tx_inuse, rx_inuse, and recvq from 
+atm_vcc in favor of sk->family, sk->wmem_alloc, sk->rmem_alloc,
+and sk->receive_queue (respectively).  listenq and backlog_quota
+should be removed as well but i need to think about them for a 
+bit.  also, atm_dev now uses the list manipulation routines (converting
+the vccs lists is a bit more involved since some the atm drivers know
+too much)
+
+
+Index: linux/include/linux/atmdev.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/include/linux/atmdev.h,v
+retrieving revision 1.2
+diff -u -r1.2 atmdev.h
+--- linux/include/linux/atmdev.h       20 Feb 2003 20:17:59 -0000      1.2
++++ linux/include/linux/atmdev.h       5 Mar 2003 00:05:46 -0000
+@@ -277,7 +277,6 @@
+ struct atm_vcc {
+       unsigned long   flags;          /* VCC flags (ATM_VF_*) */
+-      unsigned char   family;         /* address family; 0 if unused */
+       short           vpi;            /* VPI and VCI (types must be equal */
+                                       /* with sockaddr) */
+       int             vci;
+@@ -286,7 +285,6 @@
+       struct atm_dev  *dev;           /* device back pointer */
+       struct atm_qos  qos;            /* QOS */
+       struct atm_sap  sap;            /* SAP */
+-      atomic_t        tx_inuse,rx_inuse; /* buffer space in use */
+       void (*push)(struct atm_vcc *vcc,struct sk_buff *skb);
+       void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */
+       struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size);
+@@ -297,7 +295,6 @@
+       int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
+       void            *dev_data;      /* per-device data */
+       void            *proto_data;    /* per-protocol data */
+-      struct sk_buff_head recvq;      /* receive queue */
+       struct k_atm_aal_stats *stats;  /* pointer to AAL stats group */
+       wait_queue_head_t sleep;        /* if socket is busy */
+       struct sock     *sk;            /* socket backpointer */
+@@ -346,7 +343,7 @@
+       struct proc_dir_entry *proc_entry; /* proc entry */
+       char *proc_name;                /* proc entry name */
+ #endif
+-      struct atm_dev  *prev,*next;    /* linkage */
++      struct list_head dev_list;      /* linkage */
+ };
+@@ -425,19 +422,19 @@
+ static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize)
+ {
+-      atomic_add(truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
++      atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
+ }
+ static __inline__ void atm_return(struct atm_vcc *vcc,int truesize)
+ {
+-      atomic_sub(truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
++      atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
+ }
+ static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size)
+ {
+-      return size+atomic_read(&vcc->tx_inuse)+ATM_PDU_OVHD < vcc->sk->sndbuf;
++      return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf;
+ }
+Index: linux/net/atm/atm_misc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/atm_misc.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 atm_misc.c
+--- linux/net/atm/atm_misc.c   20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/atm_misc.c   4 Mar 2003 23:29:50 -0000
+@@ -16,7 +16,7 @@
+ int atm_charge(struct atm_vcc *vcc,int truesize)
+ {
+       atm_force_charge(vcc,truesize);
+-      if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1;
++      if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) return 1;
+       atm_return(vcc,truesize);
+       atomic_inc(&vcc->stats->rx_drop);
+       return 0;
+@@ -29,11 +29,11 @@
+       int guess = atm_guess_pdu2truesize(pdu_size);
+       atm_force_charge(vcc,guess);
+-      if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) {
++      if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) {
+               struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
+               if (skb) {
+-                      atomic_add(skb->truesize-guess,&vcc->rx_inuse);
++                      atomic_add(skb->truesize-guess,&vcc->sk->rmem_alloc);
+                       return skb;
+               }
+       }
+Index: linux/net/atm/clip.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/clip.c,v
+retrieving revision 1.3
+diff -u -r1.3 clip.c
+--- linux/net/atm/clip.c       4 Mar 2003 20:48:04 -0000       1.3
++++ linux/net/atm/clip.c       4 Mar 2003 23:45:45 -0000
+@@ -63,7 +63,7 @@
+       ctrl->itf_num = itf;
+       ctrl->ip = ip;
+       atm_force_charge(atmarpd,skb->truesize);
+-      skb_queue_tail(&atmarpd->recvq,skb);
++      skb_queue_tail(&atmarpd->sk->receive_queue,skb);
+       wake_up(&atmarpd->sleep);
+       return 0;
+ }
+@@ -426,7 +426,7 @@
+               memcpy(here,llc_oui,sizeof(llc_oui));
+               ((u16 *) here)[3] = skb->protocol;
+       }
+-      atomic_add(skb->truesize,&vcc->tx_inuse);
++      atomic_add(skb->truesize,&vcc->sk->wmem_alloc);
+       ATM_SKB(skb)->iovcnt = 0;
+       ATM_SKB(skb)->atm_options = vcc->atm_options;
+       entry->vccs->last_use = jiffies;
+@@ -485,7 +485,7 @@
+       vcc->push = clip_push;
+       vcc->pop = clip_pop;
+       skb_queue_head_init(&copy);
+-      skb_migrate(&vcc->recvq,&copy);
++      skb_migrate(&vcc->sk->receive_queue,&copy);
+       /* re-process everything received between connection setup and MKIP */
+       while ((skb = skb_dequeue(&copy)))
+               if (!clip_devs) {
+@@ -691,10 +691,10 @@
+       barrier();
+       unregister_inetaddr_notifier(&clip_inet_notifier);
+       unregister_netdevice_notifier(&clip_dev_notifier);
+-      if (skb_peek(&vcc->recvq))
++      if (skb_peek(&vcc->sk->receive_queue))
+               printk(KERN_ERR "atmarpd_close: closing with requests "
+                   "pending\n");
+-      skb_queue_purge(&vcc->recvq);
++      skb_queue_purge(&vcc->sk->receive_queue);
+       DPRINTK("(done)\n");
+       module_put(THIS_MODULE);
+ }
+Index: linux/net/atm/common.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/common.c,v
+retrieving revision 1.6
+diff -u -r1.6 common.c
+--- linux/net/atm/common.c     3 Mar 2003 22:23:13 -0000       1.6
++++ linux/net/atm/common.c     5 Mar 2003 00:15:53 -0000
+@@ -91,14 +91,14 @@
+ {
+       struct sk_buff *skb;
+-      if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc,size)) {
+-              DPRINTK("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n",
+-                  atomic_read(&vcc->tx_inuse),size,vcc->sk->sndbuf);
++      if (atomic_read(&vcc->sk->wmem_alloc) && !atm_may_send(vcc,size)) {
++              DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
++                  atomic_read(&vcc->sk->wmem_alloc),size,vcc->sk->sndbuf);
+               return NULL;
+       }
+       while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
+-      DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse),skb->truesize);
+-      atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
++      DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize);
++      atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+       return skb;
+ }
+@@ -114,21 +114,19 @@
+       vcc = atm_sk(sk);
+       memset(&vcc->flags,0,sizeof(vcc->flags));
+       vcc->dev = NULL;
+-      vcc->family = sock->ops->family;
+       vcc->alloc_tx = alloc_tx;
+       vcc->callback = NULL;
+       memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
+       memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
+       vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
+-      atomic_set(&vcc->tx_inuse,0);
+-      atomic_set(&vcc->rx_inuse,0);
++      atomic_set(&vcc->sk->wmem_alloc,0);
++      atomic_set(&vcc->sk->rmem_alloc,0);
+       vcc->push = NULL;
+       vcc->pop = NULL;
+       vcc->push_oam = NULL;
+       vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
+       vcc->atm_options = vcc->aal_options = 0;
+       init_waitqueue_head(&vcc->sleep);
+-      skb_queue_head_init(&vcc->recvq);
+       skb_queue_head_init(&vcc->listenq);
+       sk->sleep = &vcc->sleep;
+       sock->sk = sk;
+@@ -145,7 +143,7 @@
+       if (vcc->dev) {
+               if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
+               if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
+-              while ((skb = skb_dequeue(&vcc->recvq))) {
++              while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
+                       atm_return(vcc,skb->truesize);
+                       if (vcc->dev->ops->free_rx_skb)
+                               vcc->dev->ops->free_rx_skb(vcc,skb);
+@@ -153,10 +151,10 @@
+               }
+               down(&atm_dev_sem);     
+               fops_put (vcc->dev->ops);
+-              if (atomic_read(&vcc->rx_inuse))
++              if (atomic_read(&vcc->sk->rmem_alloc))
+                       printk(KERN_WARNING "atm_release_vcc: strange ... "
+-                          "rx_inuse == %d after closing\n",
+-                          atomic_read(&vcc->rx_inuse));
++                          "rmem_alloc == %d after closing\n",
++                          atomic_read(&vcc->sk->rmem_alloc));
+               bind_vcc(vcc,NULL);
+       } else
+               down(&atm_dev_sem);     
+@@ -311,11 +309,15 @@
+               if (error) return error;
+       }
+       else {
+-              struct atm_dev *dev;
++              struct atm_dev *dev = NULL;
++              struct list_head *p;
+               down(&atm_dev_sem);
+-              for (dev = atm_devs; dev; dev = dev->next)
++              list_for_each(p, &atm_devs) {
++                      dev = list_entry(p, struct atm_dev, dev_list);
+                       if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
++                      dev = NULL;
++              }
+               up(&atm_dev_sem);
+               if (!dev) return -ENODEV;
+       }
+@@ -360,7 +362,7 @@
+       add_wait_queue(&vcc->sleep,&wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       error = 1; /* <= 0 is error */
+-      while (!(skb = skb_dequeue(&vcc->recvq))) {
++      while (!(skb = skb_dequeue(&vcc->sk->receive_queue))) {
+               if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+                   test_bit(ATM_VF_CLOSE,&vcc->flags)) {
+                       error = vcc->reply;
+@@ -391,7 +393,7 @@
+       if (vcc->dev->ops->feedback)
+               vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data,
+                   (unsigned long) buff,eff_len);
+-      DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->rx_inuse),skb->truesize);
++      DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize);
+       atm_return(vcc,skb->truesize);
+       if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */
+               /* iovcnt set, use scatter-gather for receive */
+@@ -494,14 +496,14 @@
+       vcc = ATM_SD(sock);
+       poll_wait(file,&vcc->sleep,wait);
+       mask = 0;
+-      if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
++      if (skb_peek(&vcc->sk->receive_queue) || skb_peek(&vcc->listenq))
+               mask |= POLLIN | POLLRDNORM;
+       if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+           test_bit(ATM_VF_CLOSE,&vcc->flags))
+               mask |= POLLHUP;
+       if (sock->state != SS_CONNECTING) {
+               if (vcc->qos.txtp.traffic_class != ATM_NONE &&
+-                  vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+
++                  vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc)+
+                   ATM_PDU_OVHD <= vcc->sk->sndbuf)
+                       mask |= POLLOUT | POLLWRNORM;
+       }
+@@ -552,6 +554,7 @@
+ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       struct atm_vcc *vcc;
+       int *tmp_buf, *tmp_p;
+       void *buf;
+@@ -568,7 +571,7 @@
+                               goto done;
+                       }
+                       ret_val =  put_user(vcc->sk->sndbuf-
+-                          atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
++                          atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD,
+                           (int *) arg) ? -EFAULT : 0;
+                       goto done;
+               case SIOCINQ:
+@@ -579,7 +582,7 @@
+                                       ret_val = -EINVAL;
+                                       goto done;
+                               }
+-                              skb = skb_peek(&vcc->recvq);
++                              skb = skb_peek(&vcc->sk->receive_queue);
+                               ret_val = put_user(skb ? skb->len : 0,(int *) arg)
+                                   ? -EFAULT : 0;
+                               goto done;
+@@ -596,7 +599,7 @@
+                               goto done;
+                       }
+                       size = 0;
+-                      for (dev = atm_devs; dev; dev = dev->next)
++                      list_for_each(p, &atm_devs)
+                               size += sizeof(int);
+                       if (size > len) {
+                               ret_val = -E2BIG;
+@@ -608,8 +611,10 @@
+                               goto done;
+                       }
+                       tmp_p = tmp_buf;
+-                      for (dev = atm_devs; dev; dev = dev->next)
++                      list_for_each(p, &atm_devs) {
++                              dev = list_entry(p, struct atm_dev, dev_list);
+                               *tmp_p++ = dev->number;
++                      }
+                       ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
+                           put_user(size, &((struct atm_iobuf *) arg)->length)
+                           ) ? -EFAULT : 0;
+@@ -990,7 +995,7 @@
+       if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
+       if (error) return error;
+       if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
+-      if (vcc->family == AF_ATMPVC)
++      if (vcc->sk->family == AF_ATMPVC)
+               return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
+       return svc_change_qos(vcc,qos);
+ }
+Index: linux/net/atm/lec.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/lec.c,v
+retrieving revision 1.14
+diff -u -r1.14 lec.c
+--- linux/net/atm/lec.c        4 Mar 2003 20:48:28 -0000       1.14
++++ linux/net/atm/lec.c        4 Mar 2003 23:42:21 -0000
+@@ -125,7 +125,7 @@
+                 priv = (struct lec_priv *)dev->priv;
+                 atm_force_charge(priv->lecd, skb2->truesize);
+-                skb_queue_tail(&priv->lecd->recvq, skb2);
++                skb_queue_tail(&priv->lecd->sk->receive_queue, skb2);
+                 wake_up(&priv->lecd->sleep);
+         }
+@@ -202,7 +202,7 @@
+ lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
+ {
+       if (atm_may_send(vcc, skb->len)) {
+-              atomic_add(skb->truesize, &vcc->tx_inuse);
++              atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
+               ATM_SKB(skb)->vcc = vcc;
+               ATM_SKB(skb)->iovcnt = 0;
+               ATM_SKB(skb)->atm_options = vcc->atm_options;
+@@ -399,7 +399,7 @@
+         int i;
+         char *tmp; /* FIXME */
+-      atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
++      atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
+         mesg = (struct atmlec_msg *)skb->data;
+         tmp = skb->data;
+         tmp += sizeof(struct atmlec_msg);
+@@ -505,7 +505,7 @@
+                         skb2->len = sizeof(struct atmlec_msg);
+                         memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
+                         atm_force_charge(priv->lecd, skb2->truesize);
+-                        skb_queue_tail(&priv->lecd->recvq, skb2);
++                        skb_queue_tail(&priv->lecd->sk->receive_queue, skb2);
+                         wake_up(&priv->lecd->sleep);
+                 }
+                 if (f != NULL) br_fdb_put_hook(f);
+@@ -534,10 +534,10 @@
+         netif_stop_queue(dev);
+         lec_arp_destroy(priv);
+-        if (skb_peek(&vcc->recvq))
++        if (skb_peek(&vcc->sk->receive_queue))
+               printk("%s lec_atm_close: closing with messages pending\n",
+                        dev->name);
+-        while ((skb = skb_dequeue(&vcc->recvq))) {
++        while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
+                 atm_return(vcc, skb->truesize);
+               dev_kfree_skb(skb);
+         }
+@@ -595,13 +595,13 @@
+               memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+         atm_force_charge(priv->lecd, skb->truesize);
+-      skb_queue_tail(&priv->lecd->recvq, skb);
++      skb_queue_tail(&priv->lecd->sk->receive_queue, skb);
+         wake_up(&priv->lecd->sleep);
+         if (data != NULL) {
+                 DPRINTK("lec: about to send %d bytes of data\n", data->len);
+                 atm_force_charge(priv->lecd, data->truesize);
+-                skb_queue_tail(&priv->lecd->recvq, data);
++                skb_queue_tail(&priv->lecd->sk->receive_queue, data);
+                 wake_up(&priv->lecd->sleep);
+         }
+@@ -683,7 +683,7 @@
+ #endif /* DUMP_PACKETS > 0 */
+         if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
+                 DPRINTK("%s: To daemon\n",dev->name);
+-                skb_queue_tail(&vcc->recvq, skb);
++                skb_queue_tail(&vcc->sk->receive_queue, skb);
+                 wake_up(&vcc->sleep);
+         } else { /* Data frame, queue to protocol handlers */
+                 unsigned char *dst;
+Index: linux/net/atm/mpc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/mpc.c,v
+retrieving revision 1.4
+diff -u -r1.4 mpc.c
+--- linux/net/atm/mpc.c        3 Mar 2003 22:23:13 -0000       1.4
++++ linux/net/atm/mpc.c        4 Mar 2003 23:42:27 -0000
+@@ -520,7 +520,7 @@
+               memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
+       }
+-      atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
++      atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc);
+       ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
+       ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
+       entry->shortcut->send(entry->shortcut, skb);
+@@ -665,7 +665,7 @@
+       skb->dev = dev;
+       if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
+               dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
+-              skb_queue_tail(&vcc->recvq, skb);           /* Pass control packets to daemon */
++              skb_queue_tail(&vcc->sk->receive_queue, skb);           /* Pass control packets to daemon */
+               wake_up(&vcc->sleep);
+               return;
+       }
+@@ -840,7 +840,7 @@
+       mpc->in_ops->destroy_cache(mpc);
+       mpc->eg_ops->destroy_cache(mpc);
+-      while ( (skb = skb_dequeue(&vcc->recvq)) ){
++      while ( (skb = skb_dequeue(&vcc->sk->receive_queue)) ){
+               atm_return(vcc, skb->truesize);
+               kfree_skb(skb);
+       }
+@@ -860,7 +860,7 @@
+       
+       struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
+       struct k_message *mesg = (struct k_message*)skb->data;
+-      atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
++      atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
+       
+       if (mpc == NULL) {
+               printk("mpoa: msg_from_mpoad: no mpc found\n");
+@@ -937,7 +937,7 @@
+       skb_put(skb, sizeof(struct k_message));
+       memcpy(skb->data, mesg, sizeof(struct k_message));
+       atm_force_charge(mpc->mpoad_vcc, skb->truesize);
+-      skb_queue_tail(&mpc->mpoad_vcc->recvq, skb);
++      skb_queue_tail(&mpc->mpoad_vcc->sk->receive_queue, skb);
+       wake_up(&mpc->mpoad_vcc->sleep);
+       return 0;
+@@ -1214,7 +1214,7 @@
+               purge_msg->content.eg_info = entry->ctrl_info;
+       atm_force_charge(vcc, skb->truesize);
+-      skb_queue_tail(&vcc->recvq, skb);
++      skb_queue_tail(&vcc->sk->receive_queue, skb);
+       wake_up(&vcc->sleep);
+       dprintk("mpoa: purge_egress_shortcut: exiting:\n");
+Index: linux/net/atm/proc.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/proc.c,v
+retrieving revision 1.3
+diff -u -r1.3 proc.c
+--- linux/net/atm/proc.c       3 Mar 2003 22:23:13 -0000       1.3
++++ linux/net/atm/proc.c       5 Mar 2003 00:19:32 -0000
+@@ -134,7 +134,7 @@
+       unsigned char *ip;
+       int svc,off,ip_len;
+-      svc = !clip_vcc || clip_vcc->vcc->family == AF_ATMSVC;
++      svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC;
+       off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC",
+           !clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
+           (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/
+@@ -209,7 +209,7 @@
+       if (!vcc->dev) here += sprintf(here,"Unassigned    ");
+       else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
+                   vcc->vci);
+-      switch (vcc->family) {
++      switch (vcc->sk->family) {
+               case AF_ATMPVC:
+                       here += sprintf(here,"PVC");
+                       break;
+@@ -217,12 +217,12 @@
+                       here += sprintf(here,"SVC");
+                       break;
+               default:
+-                      here += sprintf(here,"%3d",vcc->family);
++                      here += sprintf(here,"%3d",vcc->sk->family);
+       }
+       here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7d\n",vcc->flags,
+           vcc->reply,
+-          atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
+-          atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
++          atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
++          atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
+ }
+@@ -302,6 +302,7 @@
+ static int atm_devices_info(loff_t pos,char *buf)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       int left;
+       if (!pos) {
+@@ -309,10 +310,14 @@
+                   "AAL(TX,err,RX,err,drop) ...\n");
+       }
+       left = pos-1;
+-      for (dev = atm_devs; dev && left; dev = dev->next) left--;
+-      if (!dev) return 0;
+-      dev_info(dev,buf);
+-      return strlen(buf);
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
++              if (left-- == 0) {
++                      dev_info(dev,buf);
++                      return strlen(buf);
++              }
++      }
++      return 0;
+ }
+ /*
+@@ -323,6 +328,7 @@
+ static int atm_pvc_info(loff_t pos,char *buf)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       struct atm_vcc *vcc;
+       int left;
+@@ -331,13 +337,15 @@
+                   "TX(PCR,Class)\n");
+       }
+       left = pos-1;
+-      for (dev = atm_devs; dev; dev = dev->next)
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
+               for (vcc = dev->vccs; vcc; vcc = vcc->next)
+-                      if (vcc->family == PF_ATMPVC &&
++                      if (vcc->sk->family == PF_ATMPVC &&
+                           vcc->dev && !left--) {
+                               pvc_info(vcc,buf);
+                               return strlen(buf);
+                       }
++      }
+       return 0;
+ }
+@@ -345,6 +353,7 @@
+ static int atm_vc_info(loff_t pos,char *buf)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       struct atm_vcc *vcc;
+       int left;
+@@ -353,12 +362,14 @@
+                   "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
+                   "     Recv buffer\n");
+       left = pos-1;
+-      for (dev = atm_devs; dev; dev = dev->next)
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
+               for (vcc = dev->vccs; vcc; vcc = vcc->next)
+                       if (!left--) {
+                               vc_info(vcc,buf);
+                               return strlen(buf);
+                       }
++      }
+       for (vcc = nodev_vccs; vcc; vcc = vcc->next)
+               if (!left--) {
+                       vc_info(vcc,buf);
+@@ -372,20 +383,23 @@
+ static int atm_svc_info(loff_t pos,char *buf)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       struct atm_vcc *vcc;
+       int left;
+       if (!pos)
+               return sprintf(buf,"Itf VPI VCI           State      Remote\n");
+       left = pos-1;
+-      for (dev = atm_devs; dev; dev = dev->next)
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
+               for (vcc = dev->vccs; vcc; vcc = vcc->next)
+-                      if (vcc->family == PF_ATMSVC && !left--) {
++                      if (vcc->sk->family == PF_ATMSVC && !left--) {
+                               svc_info(vcc,buf);
+                               return strlen(buf);
+                       }
++      }
+       for (vcc = nodev_vccs; vcc; vcc = vcc->next)
+-              if (vcc->family == PF_ATMSVC && !left--) {
++              if (vcc->sk->family == PF_ATMSVC && !left--) {
+                       svc_info(vcc,buf);
+                       return strlen(buf);
+               }
+Index: linux/net/atm/raw.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/raw.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 raw.c
+--- linux/net/atm/raw.c        20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/raw.c        4 Mar 2003 23:42:30 -0000
+@@ -28,7 +28,7 @@
+ void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
+ {
+       if (skb) {
+-              skb_queue_tail(&vcc->recvq,skb);
++              skb_queue_tail(&vcc->sk->receive_queue,skb);
+               wake_up(&vcc->sleep);
+       }
+ }
+@@ -36,8 +36,8 @@
+ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
+ {
+-      DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
+-      atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
++      DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize);
++      atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+       dev_kfree_skb_any(skb);
+       wake_up(&vcc->sleep);
+ }
+Index: linux/net/atm/resources.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/resources.c,v
+retrieving revision 1.2
+diff -u -r1.2 resources.c
+--- linux/net/atm/resources.c  25 Feb 2003 20:03:53 -0000      1.2
++++ linux/net/atm/resources.c  5 Mar 2003 00:10:01 -0000
+@@ -26,8 +26,7 @@
+ #endif
+-struct atm_dev *atm_devs = NULL;
+-static struct atm_dev *last_dev = NULL;
++LIST_HEAD(atm_devs);
+ struct atm_vcc *nodev_vccs = NULL;
+ extern struct semaphore atm_dev_sem;
+@@ -43,15 +42,7 @@
+       dev->type = type;
+       dev->signal = ATM_PHY_SIG_UNKNOWN;
+       dev->link_rate = ATM_OC3_PCR;
+-      dev->next = NULL;
+-
+-      dev->prev = last_dev;
+-
+-      if (atm_devs)
+-              last_dev->next = dev;
+-      else
+-              atm_devs = dev;
+-      last_dev = dev;
++      list_add_tail(&dev->dev_list, &atm_devs);
+       return dev;
+ }
+@@ -59,14 +50,7 @@
+ /* Caller must hold atm_dev_sem. */
+ static void __free_atm_dev(struct atm_dev *dev)
+ {
+-      if (dev->prev)
+-              dev->prev->next = dev->next;
+-      else
+-              atm_devs = dev->next;
+-      if (dev->next)
+-              dev->next->prev = dev->prev;
+-      else
+-              last_dev = dev->prev;
++      list_del(&dev->dev_list);
+       kfree(dev);
+ }
+@@ -74,10 +58,13 @@
+ struct atm_dev *atm_find_dev(int number)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+-      for (dev = atm_devs; dev; dev = dev->next)
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
+               if (dev->ops && dev->number == number)
+                       return dev;
++      }
+       return NULL;
+ }
+Index: linux/net/atm/resources.h
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/resources.h,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 resources.h
+--- linux/net/atm/resources.h  20 Feb 2003 13:46:30 -0000      1.1.1.1
++++ linux/net/atm/resources.h  5 Mar 2003 00:11:51 -0000
+@@ -10,7 +10,7 @@
+ #include <linux/atmdev.h>
+-extern struct atm_dev *atm_devs;
++extern struct list_head atm_devs;
+ extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */
+Index: linux/net/atm/signaling.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/net/atm/signaling.c,v
+retrieving revision 1.2
+diff -u -r1.2 signaling.c
+--- linux/net/atm/signaling.c  25 Feb 2003 20:03:53 -0000      1.2
++++ linux/net/atm/signaling.c  5 Mar 2003 00:21:45 -0000
+@@ -61,7 +61,7 @@
+       }
+ #endif
+       atm_force_charge(sigd,skb->truesize);
+-      skb_queue_tail(&sigd->recvq,skb);
++      skb_queue_tail(&sigd->sk->receive_queue,skb);
+       wake_up(&sigd->sleep);
+ }
+@@ -98,7 +98,7 @@
+       struct atm_vcc *session_vcc;
+       msg = (struct atmsvc_msg *) skb->data;
+-      atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
++      atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+       DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
+         (unsigned long) msg->vcc);
+       vcc = *(struct atm_vcc **) &msg->vcc;
+@@ -198,7 +198,7 @@
+ static void purge_vccs(struct atm_vcc *vcc)
+ {
+       while (vcc) {
+-              if (vcc->family == PF_ATMSVC &&
++              if (vcc->sk->family == PF_ATMSVC &&
+                   !test_bit(ATM_VF_META,&vcc->flags)) {
+                       set_bit(ATM_VF_RELEASED,&vcc->flags);
+                       vcc->reply = -EUNATCH;
+@@ -212,16 +212,20 @@
+ static void sigd_close(struct atm_vcc *vcc)
+ {
+       struct atm_dev *dev;
++      struct list_head *p;
+       DPRINTK("sigd_close\n");
+       sigd = NULL;
+-      if (skb_peek(&vcc->recvq))
++      if (skb_peek(&vcc->sk->receive_queue))
+               printk(KERN_ERR "sigd_close: closing with requests pending\n");
+-      skb_queue_purge(&vcc->recvq);
++      skb_queue_purge(&vcc->sk->receive_queue);
+       purge_vccs(nodev_vccs);
+       down(&atm_dev_sem);
+-      for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
++      list_for_each(p, &atm_devs) {
++              dev = list_entry(p, struct atm_dev, dev_list);
++              purge_vccs(dev->vccs);
++      }
+       up(&atm_dev_sem);
+ }
+--- linux-2.4.20/drivers/atm/idt77252.c.orig   Fri Dec 21 18:41:53 2001
++++ linux-2.4.20/drivers/atm/idt77252.c        Wed Mar  5 20:27:00 2003
+@@ -730,7 +730,7 @@
+               struct atm_vcc *vcc = vc->tx_vcc;
+               vc->estimator->cells += (skb->len + 47) / 48;
+-              if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
++              if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) {
+                       u32 cps = vc->estimator->maxcps;
+                       vc->estimator->cps = cps;
+@@ -2025,7 +2025,7 @@
+               atomic_inc(&vcc->stats->tx_err);
+               return -ENOMEM;
+       }
+-      atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
++      atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
+       ATM_SKB(skb)->iovcnt = 0;
+       memcpy(skb_put(skb, 52), cell, 52);
+--- linux-2.4.20/net/atm/br2684.c.orig Wed Mar  5 22:11:10 2003
++++ linux-2.4.20/net/atm/br2684.c      Wed Mar  5 22:42:20 2003
+@@ -188,7 +188,7 @@
+               dev_kfree_skb(skb);
+               return 0;
+               }
+-      atomic_add(skb->truesize, &atmvcc->tx_inuse);
++      atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc);
+       ATM_SKB(skb)->iovcnt = 0;
+       ATM_SKB(skb)->atm_options = atmvcc->atm_options;
+       brdev->stats.tx_packets++;
+@@ -553,7 +553,7 @@
+       barrier();
+       atmvcc->push = br2684_push;
+       skb_queue_head_init(&copy);
+-      skb_migrate(&atmvcc->recvq, &copy);
++      skb_migrate(&atmvcc->sk->receive_queue, &copy);
+       while ((skb = skb_dequeue(&copy))) {
+               BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
+               BRPRIV(skb->dev)->stats.rx_packets--;
+--- linux-2.4.20/net/atm/pppoatm.c~    Sat Aug  3 02:39:46 2002
++++ linux-2.4.20/net/atm/pppoatm.c     Wed Mar  5 22:43:51 2003
+@@ -231,7 +231,7 @@
+               kfree_skb(skb);
+               return 1;
+       }
+-      atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->tx_inuse);
++      atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc);
+       ATM_SKB(skb)->iovcnt = 0;
+       ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
+       DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-20-fore200e-gettimeofday.patch b/atm-20-fore200e-gettimeofday.patch
new file mode 100644 (file)
index 0000000..d683d8d
--- /dev/null
@@ -0,0 +1,31 @@
+In message <20030225131546.GL7685@fs.tum.de>,Adrian Bunk writes:
+>drivers/atm/fore200e.o drivers/atm/fore200e.c
+>drivers/atm/fore200e.c: In function `fore200e_push_rpd':
+>drivers/atm/fore200e.c:1135: structure has no member named `timestamp'
+>drivers/atm/fore200e.c:1136: structure has no member named `timestamp'
+
+it shouldnt be doing that.  you only need to set the timestamp in the 
+skb.  i see the eni driver does the same thing.  i will see about
+a patch for that shortly.
+
+Index: linux/drivers/atm/fore200e.c
+===================================================================
+RCS file: /home/chas/CVSROOT/linux/drivers/atm/fore200e.c,v
+retrieving revision 1.1.1.1
+diff -u -d -b -w -r1.1.1.1 fore200e.c
+--- linux/drivers/atm/fore200e.c       20 Feb 2003 13:45:03 -0000      1.1.1.1
++++ linux/drivers/atm/fore200e.c       25 Feb 2003 14:42:06 -0000
+@@ -1135,7 +1135,7 @@
+       return;
+     } 
+-    skb->stamp = vcc->timestamp = xtime;
++    do_gettimeofday(&skb->stamp);
+     
+ #ifdef FORE200E_52BYTE_AAL0_SDU
+     if (cell_header) {
+-
+To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
+Please read the FAQ at  http://www.tux.org/lkml/
diff --git a/atm-21-fore200e-0.3.patch b/atm-21-fore200e-0.3.patch
new file mode 100644 (file)
index 0000000..b73f117
--- /dev/null
@@ -0,0 +1,1055 @@
+--- linux-2.4.0-test9-orig/drivers/atm/fore200e.c
++++ linux-2.4.0-test9/drivers/atm/fore200e.c   Fri Dec  1 16:18:31 2000
+@@ -2,7 +2,7 @@
+   $Id$
+   A FORE Systems 200E-series driver for ATM on Linux.
+-  Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000.
++  Christophe Lizzi (lizzi@cnam.fr), October 1999-December 2000.
+   Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de).
+@@ -34,6 +34,8 @@
+ #include <linux/sched.h>
+ #include <linux/interrupt.h>
+ #include <linux/bitops.h>
++#include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/atmdev.h>
+ #include <linux/sonet.h>
+ #include <linux/atm_suni.h>
+@@ -46,7 +48,6 @@
+ #include <asm/byteorder.h>
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
+-#include <linux/pci.h>
+ #ifdef CONFIG_ATM_FORE200E_SBA
+ #include <asm/idprom.h>
+@@ -56,25 +57,31 @@
+ #include <asm/pgtable.h>
+ #endif
+-#include <linux/module.h>
+-#include "fore200e.h"
+-#include "suni.h"
++#if 0 /* defer intr work to a tasklet */
++#define FORE200E_USE_TASKLET
++#endif
++
++#if 0 /* enable the debugging code of the buffer supply queues */
++#define FORE200E_BSQ_DEBUG
++#endif
+ #if 1   /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */
+ #define FORE200E_52BYTE_AAL0_SDU
+ #endif
+-#define FORE200E_VERSION "0.2d"
++#include "fore200e.h"
++#include "suni.h"
++#define FORE200E_VERSION "0.3"
+ #define FORE200E         "fore200e: "
+ #if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
+ #define DPRINTK(level, format, args...)  do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \
+-                                                  printk(FORE200E format, ##args); } while(0)
++                                                  printk(FORE200E format, ##args); } while (0)
+ #else
+-#define DPRINTK(level, format, args...)  while(0)
++#define DPRINTK(level, format, args...)  do {} while (0)
+ #endif
+@@ -503,6 +510,7 @@
+ {
+ #if defined(__sparc_v9__)
+     /* returned chunks are page-aligned */
++    chunk->alloc_size = size * nbr;
+     chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev,
+                                            chunk->alloc_size,
+                                            &chunk->dma_addr);
+@@ -589,7 +597,7 @@
+ {
+     DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name);
+-    /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41),
++    /* XXX iounmap() does nothing on PowerPC (at least in 2.2.x and 2.3.x),
+        this leads to a kernel panic if the module is loaded and unloaded several times */
+     if (fore200e->virt_base != NULL)
+       iounmap(fore200e->virt_base);
+@@ -989,44 +997,89 @@
+ static void
+ fore200e_irq_tx(struct fore200e* fore200e)
+ {
++    struct host_txq*       txq = &fore200e->host_txq;
+     struct host_txq_entry* entry;
+-    int i;
+-    
+-    entry = fore200e->host_txq.host_entry;
+-    for (i = 0; i < QUEUE_SIZE_TX; i++) {
++    for (;;) {
+-      if (*entry->status & STATUS_COMPLETE) {
++      entry = &txq->host_entry[ txq->tail ];
+-          DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb);
++        if (!(*entry->status & STATUS_COMPLETE)) {
++          break;
++      }
+-          /* free copy of misaligned data */
+-          if (entry->data)
+-              kfree(entry->data);
++      DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vcc = %p, skb = %p\n", 
++              entry, txq->tail, entry->vcc, entry->skb);
+-          /* remove DMA mapping */
+-          fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+-                                   FORE200E_DMA_TODEVICE);
++      /* free copy of misaligned data */
++      if (entry->data)
++          kfree(entry->data);
++      
++      /* remove DMA mapping */
++      fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
++                               FORE200E_DMA_TODEVICE);
++      
++      /* notify tx completion */
++      if (entry->vcc->pop)
++          entry->vcc->pop(entry->vcc, entry->skb);
++      else
++          dev_kfree_skb_irq(entry->skb);
++      
++      /* check error condition */
++      if (*entry->status & STATUS_ERROR)
++          atomic_inc(&entry->vcc->stats->tx_err);
++      else
++          atomic_inc(&entry->vcc->stats->tx);
++      
++      *entry->status = STATUS_FREE;
++      
++      fore200e->host_txq.txing--;
+-          /* notify tx completion */
+-          if (entry->vcc->pop)
+-              entry->vcc->pop(entry->vcc, entry->skb);
+-          else
+-              dev_kfree_skb_irq(entry->skb);
++      FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX);
++    }
++}
+-          /* check error condition */
+-          if (*entry->status & STATUS_ERROR)
+-              atomic_inc(&entry->vcc->stats->tx_err);
+-          else
+-              atomic_inc(&entry->vcc->stats->tx);
+-          *entry->status = STATUS_FREE;
+-          
+-          fore200e->host_txq.txing--;
++#ifdef FORE200E_BSQ_DEBUG
++int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn) /* FFF */
++{
++    struct buffer* buffer;
++    int count = 0;
++
++    buffer = bsq->freebuf;
++    while (buffer) {
++
++      if (buffer->supplied) {
++          printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n",
++                 where, scheme, magn, buffer->index);
+       }
+-      entry++;
++
++      if (buffer->magn != magn) {
++          printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n",
++                 where, scheme, magn, buffer->index, buffer->magn);
++      }
++
++      if (buffer->scheme != scheme) {
++          printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n",
++                 where, scheme, magn, buffer->index, buffer->scheme);
++      }
++
++      if (buffer->index < 0 || buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ]) {
++          printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n",
++                 where, scheme, magn, buffer->index);
++      }
++
++      count++;
++      buffer = buffer->next;
++    }
++
++    if (count != bsq->freebuf_count) {
++      printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n",
++             where, scheme, magn, count, bsq->freebuf_count);
+     }
++    return 0;
+ }
++#endif
+ static void
+@@ -1043,28 +1096,44 @@
+           bsq = &fore200e->host_bsq[ scheme ][ magn ];
+-          if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) {
++#ifdef FORE200E_BSQ_DEBUG
++          bsq_audit(1, bsq, scheme, magn);
++#endif
+-              DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n",
+-                      scheme, magn, bsq->count);
++          while (bsq->freebuf_count >= RBD_BLK_SIZE) {
++
++              DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n",
++                      RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count);
+               entry = &bsq->host_entry[ bsq->head ];
+-              
+-              FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
+               for (i = 0; i < RBD_BLK_SIZE; i++) {
+-                  buffer = &bsq->buffer[ bsq->free ];
+-                  
+-                  FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]);
++                  /* take the first buffer in the free buffer list */
++                  buffer = bsq->freebuf;
++                  if (!buffer) {
++                      printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n",
++                             scheme, magn, bsq->freebuf_count);
++                      return;
++                  }
++                  bsq->freebuf = buffer->next;
+                   
++#ifdef FORE200E_BSQ_DEBUG
++                  if (buffer->supplied)
++                      printk(FORE200E "queue %d.%d, buffer %lu already supplied\n",
++                             scheme, magn, buffer->index);
++                  buffer->supplied = 1;
++#endif
++
+                   entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr;
+                   entry->rbd_block->rbd[ i ].handle       = FORE200E_BUF2HDL(buffer);
+               }
+-              /* increase the number of supplied rx buffers */
+-              bsq->count += RBD_BLK_SIZE;
+-              
++              FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
++
++              /* decrease accordingly the number of free rx buffers */
++              bsq->freebuf_count -= RBD_BLK_SIZE;
++
+               *entry->status = STATUS_PENDING;
+               fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr);
+           }
+@@ -1073,7 +1142,6 @@
+ }
+-
+ static struct atm_vcc* 
+ fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
+ {
+@@ -1089,7 +1157,7 @@
+ }
+-static void
++static int
+ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
+ {
+     struct atm_vcc*      vcc;
+@@ -1103,10 +1171,15 @@
+     vcc = fore200e_find_vcc(fore200e, rpd);
+     if (vcc == NULL) {
+-      
+-      printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n",
+-             fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci);
+-      return;
++      DPRINTK(1, "no vcc found for PDU received on %d.%d.%d\n",
++              fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci);
++      return -EINVAL;
++    }
++
++
++    if (!test_bit(ATM_VF_READY, &vcc->flags)) {
++      DPRINTK(1, "vcc %d.%d.%d not ready for rx\n", vcc->itf, vcc->vpi, vcc->vpi);
++      return -EINVAL;
+     }
+     fore200e_vcc = FORE200E_VCC(vcc);
+@@ -1129,10 +1202,9 @@
+     
+     skb = alloc_skb(pdu_len, GFP_ATOMIC);
+     if (skb == NULL) {
+-      
+       printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
+       atomic_inc(&vcc->stats->rx_drop);
+-      return;
++      return -ENOMEM;
+     } 
+     do_gettimeofday(&skb->stamp);
+@@ -1169,11 +1241,13 @@
+               vcc->itf, vcc->vpi, vcc->vci);
+       dev_kfree_skb_irq(skb);
+-      return;
++      return -ENOMEM;
+     }
+     vcc->push(vcc, skb);
+     atomic_inc(&vcc->stats->rx);
++
++    return 0;
+ }
+@@ -1183,13 +1257,31 @@
+     struct buffer* buffer;
+     int            i;
+     
++    struct host_bsq* bsq;
++
++
+     for (i = 0; i < rpd->nseg; i++) {
+       /* rebuild rx buffer address from rsd handle */
+       buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
+-      /* decrease the number of supplied rx buffers */
+-      fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--;
++      bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ];
++
++#ifdef FORE200E_BSQ_DEBUG
++      bsq_audit(2, bsq, buffer->scheme, buffer->magn);
++
++      if (buffer->supplied == 0)
++          printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n",
++                 buffer->scheme, buffer->magn, buffer->index);
++      buffer->supplied = 0;
++#endif
++
++      /* re-insert the buffer into the free buffer list */
++      buffer->next = bsq->freebuf;
++      bsq->freebuf = buffer;
++
++      /* then increment the number of free rx buffers */
++      bsq->freebuf_count++;
+     }
+ }
+@@ -1208,8 +1300,6 @@
+       if ((*entry->status & STATUS_COMPLETE) == 0)
+           break;
+-      FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
+-
+       if ((*entry->status & STATUS_ERROR) == 0) {
+           fore200e_push_rpd(fore200e, entry->rpd);
+@@ -1219,6 +1309,8 @@
+                  fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
+       }
++      FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
++
+       fore200e_collect_rpd(fore200e, entry->rpd);
+       fore200e_supply(fore200e);
+@@ -1230,6 +1322,23 @@
+ }
++static void 
++fore200e_irq(struct fore200e* fore200e)
++{
++    fore200e_irq_rx(fore200e);
++    
++    if (fore200e->host_txq.txing) {
++
++      /* give up if someone else is playing with the tx queue */
++      if (test_bit(0, &fore200e->tx_bit))
++          return;
++
++      fore200e_irq_tx(fore200e);
++    }
++}
++
++
++
+ static void
+ fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
+ {
+@@ -1242,23 +1351,25 @@
+     }
+     DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]);
++#ifdef FORE200E_USE_TASKLET
+     tasklet_schedule(&fore200e->tasklet);
++#else
++    fore200e_irq(fore200e);
++#endif
+     
+     fore200e->bus->irq_ack(fore200e);
+ }
++#ifdef FORE200E_USE_TASKLET
+ static void
+ fore200e_tasklet(unsigned long data)
+ {
+-    struct fore200e* fore200e = (struct fore200e*) data;
++    DPRINTK(3, "tasklet scheduled for device %c\n", fore200e->name[9]);
+-    fore200e_irq_rx(fore200e);
+-    
+-    if (fore200e->host_txq.txing)
+-      fore200e_irq_tx(fore200e);
++    fore200e_irq((struct fore200e*) data);
+ }
+-
++#endif
+ static int
+@@ -1268,7 +1379,7 @@
+ #if 1
+     /* fairly balance VCs over (identical) buffer schemes */
+-    scheme =  vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
++    scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
+ #else
+     /* bit 7 of VPI magically selects the second buffer scheme */
+     if (vcc->vpi & (1<<7)) {
+@@ -1419,7 +1530,7 @@
+       return 0;
+     set_bit(ATM_VF_ADDR, &vcc->flags);
+-    vcc->itf    = vcc->dev->number;
++    vcc->itf = vcc->dev->number;
+     DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
+           "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n",
+@@ -1438,7 +1549,7 @@
+       }
+       /* reserving the pseudo-CBR bandwidth at this point grants us
+          to reduce the length of the critical section protected
+-         by 'rate_sf'. in counterpart, we have to reset the available
++         by 'rate_sf'. in counterpart, we have to restore the available
+          bandwidth if we later encounter an error */
+       fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr;
+@@ -1490,6 +1601,8 @@
+     
+     DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
+     
++    clear_bit(ATM_VF_READY, &vcc->flags);
++
+     fore200e_activate_vcin(fore200e, 0, vcc, 0);
+     
+     kfree(FORE200E_VCC(vcc));
+@@ -1499,8 +1610,6 @@
+       fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
+       up(&fore200e->rate_sf);
+     }
+-
+-    clear_bit(ATM_VF_READY, &vcc->flags);
+ }
+@@ -1518,7 +1627,6 @@
+     struct host_txq_entry* entry;
+     struct tpd*            tpd;
+     struct tpd_haddr       tpd_haddr;
+-    //unsigned long          flags;
+     int                    retry        = CONFIG_ATM_FORE200E_TX_RETRY;
+     int                    tx_copy      = 0;
+     int                    tx_len       = skb->len;
+@@ -1526,6 +1634,11 @@
+     unsigned char*         skb_data;
+     int                    skb_len;
++    if (!test_bit(ATM_VF_READY, &vcc->flags)) {
++      DPRINTK(1, "vcc %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi);
++      return -EINVAL;
++    }
++
+ #ifdef FORE200E_52BYTE_AAL0_SDU
+     if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) {
+       cell_header = (u32*) skb->data;
+@@ -1543,18 +1656,18 @@
+     
+   retry_here:
+     
+-    tasklet_disable(&fore200e->tasklet);
++    set_bit(0, &fore200e->tx_bit);
+     entry = &txq->host_entry[ txq->head ];
+     
+-    if (*entry->status != STATUS_FREE) {
++    if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) {
+       
+       /* try to free completed tx queue entries */
+       fore200e_irq_tx(fore200e);
+       
+       if (*entry->status != STATUS_FREE) {
+           
+-          tasklet_enable(&fore200e->tasklet);
++          clear_bit(0, &fore200e->tx_bit);
+           /* retry once again? */
+           if(--retry > 0)
+@@ -1562,13 +1675,16 @@
+           
+           atomic_inc(&vcc->stats->tx_err);
+           
+-          printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
++          fore200e->tx_sat++;
++          DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
+                  fore200e->name, fore200e->cp_queues->heartbeat);
+           if (vcc->pop)
+               vcc->pop(vcc, skb);
+           else
+               dev_kfree_skb(skb);
+-          return -EIO;
++
++          clear_bit(0, &fore200e->tx_bit);
++          return -ENOBUFS;
+       }
+     }
+@@ -1594,7 +1710,8 @@
+       entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
+       if (entry->data == NULL) {
+           
+-          tasklet_enable(&fore200e->tasklet);
++          clear_bit(0, &fore200e->tx_bit);
++
+           if (vcc->pop)
+               vcc->pop(vcc, skb);
+           else
+@@ -1618,7 +1735,7 @@
+     FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
+     txq->txing++;
+-    tasklet_enable(&fore200e->tasklet);
++    clear_bit(0, &fore200e->tx_bit);
+     /* ensure DMA synchronisation */
+     fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
+@@ -1959,6 +2076,11 @@
+     struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
+     struct fore200e*     fore200e     = FORE200E_DEV(vcc->dev);
++    if (!test_bit(ATM_VF_READY, &vcc->flags)) {
++      DPRINTK(1, "vcc %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi);
++      return -EINVAL;
++    }
++
+     DPRINTK(2, "change_qos %d.%d.%d, "
+           "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
+           "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n"
+@@ -2008,7 +2130,9 @@
+     printk(FORE200E "IRQ %s reserved for device %s\n",
+          fore200e_irq_itoa(fore200e->irq), fore200e->name);
++#ifdef FORE200E_USE_TASKLET
+     tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e);
++#endif
+     fore200e->state = FORE200E_STATE_IRQ;
+     return 0;
+@@ -2070,10 +2194,16 @@
+           if (buffer == NULL)
+               return -ENOMEM;
++          bsq->freebuf = NULL;
++
+           for (i = 0; i < nbr; i++) {
+               buffer[ i ].scheme = scheme;
+               buffer[ i ].magn   = magn;
++#ifdef FORE200E_BSQ_DEBUG
++              buffer[ i ].index  = i;
++              buffer[ i ].supplied = 0;
++#endif
+               /* allocate the receive buffer body */
+               if (fore200e_chunk_alloc(fore200e,
+@@ -2086,9 +2216,17 @@
+                   
+                   return -ENOMEM;
+               }
++
++              /* insert the buffer into the free buffer list */
++              buffer[ i ].next = bsq->freebuf;
++              bsq->freebuf = &buffer[ i ];
+           }
+-          /* set next free buffer index */
+-          bsq->free = 0;
++          /* all the buffers are free, initially */
++          bsq->freebuf_count = nbr;
++
++#ifdef FORE200E_BDQ_DEBUG
++          bsq_audit(3, bsq, scheme, magn);
++#endif
+       }
+     }
+@@ -2145,9 +2283,9 @@
+                                    FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i);
+               bsq->host_entry[ i ].rbd_block_dma =
+                                    FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i);
+-              bsq->host_entry[ i ].cp_entry      = &cp_entry[ i ];
++              bsq->host_entry[ i ].cp_entry = &cp_entry[ i ];
+               
+-              *bsq->host_entry[ i ].status   = STATUS_FREE;
++              *bsq->host_entry[ i ].status = STATUS_FREE;
+               
+               fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), 
+                                    &cp_entry[ i ].status_haddr);
+@@ -2276,8 +2414,9 @@
+          operation to detect that a new pdu has been submitted for tx */
+ }
+-    /* set the head entry of the queue */
++    /* set the head and tail entries of the queue */
+     txq->head = 0;
++    txq->tail = 0;
+     fore200e->state = FORE200E_STATE_INIT_TXQ;
+     return 0;
+@@ -2591,7 +2730,7 @@
+     struct       fore200e*     fore200e;
+     int                        index, link;
+-    printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
++    printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+     /* for each configured bus interface */
+     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
+@@ -2674,14 +2817,15 @@
+     if (!left--)
+       return sprintf(page,
+-                     "   supplied small bufs (1):\t%d\n"
+-                     "   supplied large bufs (1):\t%d\n"
+-                     "   supplied small bufs (2):\t%d\n"
+-                     "   supplied large bufs (2):\t%d\n",
+-                     fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count,
+-                     fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count,
+-                     fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count,
+-                     fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count);
++                     "   free small bufs, scheme 1:\t%d\n"
++                     "   free large bufs, scheme 1:\t%d\n"
++                     "   free small bufs, scheme 2:\t%d\n"
++                     "   free large bufs, scheme 2:\t%d\n",
++                     fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count,
++                     fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count,
++                     fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count,
++                     fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count);
++
+     if (!left--) {
+       u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
+@@ -2867,13 +3011,15 @@
+                      "     large b1:\t\t\t%10u\n"
+                      "     small b2:\t\t\t%10u\n"
+                      "     large b2:\t\t\t%10u\n"
+-                     "     RX PDUs:\t\t\t%10u\n",
++                     "     RX PDUs:\t\t\t%10u\n"
++                     "     TX PDUs:\t\t\t%10lu\n",
+                      fore200e_swap(fore200e->stats->aux.small_b1_failed),
+                      fore200e_swap(fore200e->stats->aux.large_b1_failed),
+                      fore200e_swap(fore200e->stats->aux.small_b2_failed),
+                      fore200e_swap(fore200e->stats->aux.large_b2_failed),
+-                     fore200e_swap(fore200e->stats->aux.rpd_alloc_failed));
+-    
++                     fore200e_swap(fore200e->stats->aux.rpd_alloc_failed),
++                       fore200e->tx_sat);
++
+     if (!left--)
+       return sprintf(page,"\n"
+                      " receive carrier:\t\t\t%s\n",
+--- linux-2.4.0-test9-orig/drivers/atm/fore200e.h
++++ linux-2.4.0-test9/drivers/atm/fore200e.h   Fri Dec  1 16:27:20 2000
+@@ -11,7 +11,7 @@
+ #define LARGE_BUFFER_SIZE    4032    /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */
+-#define RBD_BLK_SIZE       32      /* nbr of supplied rx buffers per rbd */
++#define RBD_BLK_SIZE       16      /* nbr of supplied rx buffers per rbd */
+ #define MAX_PDU_SIZE       65535   /* maximum PDU size supported by AALs */
+@@ -23,17 +23,17 @@
+ #define BUFFER_S2_SIZE       SMALL_BUFFER_SIZE    /* size of small buffers, scheme 2 */
+ #define BUFFER_L2_SIZE       LARGE_BUFFER_SIZE    /* size of large buffers, scheme 2 */
+-#define BUFFER_S1_NBR        (RBD_BLK_SIZE * 2)
+-#define BUFFER_L1_NBR        (RBD_BLK_SIZE * 2)
++#define BUFFER_S1_NBR        (RBD_BLK_SIZE * 6)
++#define BUFFER_L1_NBR        (RBD_BLK_SIZE * 4)
+-#define BUFFER_S2_NBR        (RBD_BLK_SIZE * 2)
+-#define BUFFER_L2_NBR        (RBD_BLK_SIZE * 2)
++#define BUFFER_S2_NBR        (RBD_BLK_SIZE * 6)
++#define BUFFER_L2_NBR        (RBD_BLK_SIZE * 4)
+ #define QUEUE_SIZE_CMD       16            /* command queue capacity       */
+ #define QUEUE_SIZE_RX      64      /* receive queue capacity       */
+ #define QUEUE_SIZE_TX      256     /* transmit queue capacity      */
+-#define QUEUE_SIZE_BS        16            /* buffer supply queue capacity */
++#define QUEUE_SIZE_BS        32            /* buffer supply queue capacity */
+ #define NBR_CONNECT          1024    /* number of ATM connections     */
+@@ -576,6 +576,10 @@
+     enum   buffer_scheme scheme;      /* buffer scheme           */
+     enum   buffer_magn   magn;        /* buffer magnitude        */
+     struct chunk         data;        /* data buffer             */
++#ifdef FORE200E_BSQ_DEBUG
++    unsigned long        index;       /* buffer # in queue       */
++    int                  supplied;    /* 'buffer supplied' flag  */
++#endif
+ } buffer_t;
+@@ -602,6 +606,7 @@
+ typedef struct host_txq {
+     struct host_txq_entry host_entry[ QUEUE_SIZE_TX ];    /* host resident tx queue entries         */
+     int                   head;                           /* head of tx queue                       */
++    int                   tail;                           /* tail of tx queue                       */
+     struct chunk          tpd;                            /* array of tpds                          */
+     struct chunk          status;                         /* arry of completion status              */
+     int                   txing;                          /* number of pending PDUs in tx queue     */
+@@ -626,8 +631,8 @@
+     struct chunk          rbd_block;                      /* array of rbds                             */
+     struct chunk          status;                         /* array of completion status                */
+     struct buffer*        buffer;                         /* array of rx buffers                       */
+-    int                   free;                           /* index of first free rx buffer             */
+-    volatile int          count;                          /* count of supplied rx buffers              */
++    struct buffer*        freebuf;                        /* list of free rx buffers                   */
++    volatile int          freebuf_count;                  /* count of free rx buffers                  */
+ } host_bsq_t;
+@@ -879,8 +884,11 @@
+     struct stats*              stats;                  /* last snapshot of the stats         */
+     
+     struct semaphore           rate_sf;                /* protects rate reservation ops      */
++#ifdef FORE200E_USE_TASKLET
+     struct tasklet_struct      tasklet;                /* performs interrupt work            */
+-
++#endif
++    volatile int               tx_bit;                 /* 'in tx code' flag                  */
++    unsigned long              tx_sat;                 /* tx queue saturation count          */
+ } fore200e_t;
+--- /dev/null  Thu Jan  1 01:00:00 1970
++++ linux-2.4.20/drivers/atm/fore200e.CHANGES  Mon Dec  4 14:34:31 2000
+@@ -0,0 +1,207 @@
++Version 0.3 (December, 1, 2000)
++-------------------------------
++
++   this version should fix some of the bugs introduced
++   in the preceding releases (and thus should introduce new ones :-)
++
++   - fix the bug in the sparc64-specific part of
++     fore200e_pca_dma_chunk_alloc(): chunk->alloc_size was
++     left uninitialized.
++   - rewrite the management of the buffer supply queues:
++     now use per-queue linked-lists of free buffers.
++   - the debugging code that audits the sanity of the free buffers
++     lists can be enabled by the FORE200E_BSQ_DEBUG define.
++   - check that a VCC is ready before playing with it.
++   - fix bugs in the management of the tx queue. note that ENOBUFS is
++     now returned in case of tx queue saturation: this prevent
++     ttcp_atm to give up immediately if this event occurs.
++   - count of tx queue saturation occurrences appended to the
++     auxiliary statistics.
++   - minor cosmetic changes.
++
++
++Version 0.2g (July, 16, 2000)
++-----------------------------
++
++   this release includes some experimental changes to 
++   the tx/interrupt code. It's an attempt to improve
++   the schedulability of the driver and its performances.
++
++   - interrupts are no longer disabled to protect the
++     critical section of the tx code. As a consequence,
++     the rx processing may no longer be delayed by the
++     tx processing.
++   - handling of completed tx entries is improved
++     thanks to a tail queue pointer.
++   - interrupt work can be performed by the intr handler
++     or can be deferred to a tasklet according to the
++     FORE200E_USE_TASKLET define.
++
++
++Version 0.2f (May, 21, 2000)
++----------------------------
++
++   this is just the 'official' release of the preceding version.
++   It also fixes a buglet spotted by Mitchell Blank Jr.
++
++   - the driver no longer mess with vcc->timestamp.
++
++
++Version 0.2e (May, 8, 2000)
++---------------------------
++
++   this is an experimental version, intended as a first attempt
++   to fix the lockup problems encountered by a few users
++   under heavy loads/SMP (probably introduced with the tasklet
++   code).
++
++   - use the spin_lock_bh() machinery to guard the
++     critical section of the tx code.
++   - minor fix to the Makefile test that tells the target
++     endianess from <asm/byteorder.h>.
++
++
++Version 0.2d (Mar, 28, 2000)
++----------------------------
++
++   - fix fatal bug in fore200e_open(): the ATM_VF_READY flag
++     should be set, not cleared!
++   - fix SBUS DMA direction flags.
++   - move interrupt handler work to tasklet.
++   - the compile no longer fails when the driver is compiled
++     without any hardware support (i.e. with both PCA and SBA
++     support disabled) (spotted by Arjan van de Ven). Also display
++     a message to warn the user.
++
++
++Version 0.2c (Mar, 23, 2000)
++----------------------------
++
++   this is a minor interim release. It does not provide significant
++   improvement to the driver code.
++
++   - initiate transition to the new-style PCI driver support.
++   - minor cosmetic changes.
++   - fix typos in Documentation/networking/fore200e.txt.
++
++
++Version 0.2b (Feb, 23, 2000)
++----------------------------
++
++   - update of PCI and SBUS DVMA code to 2.3.47-7 (DVMA functions
++     now have a 'direction' argument).
++
++
++Version 0.2a (Feb, 11, 2000)
++----------------------------
++
++   this release completes the transition of the driver to the new
++   DVMA interface. Many thanks to Marconi Networks (formerly FORE
++   Systems) for having placed their binary firmware images under GPL.
++
++   - switch to the new PCI interface (requires 2.3.42+).
++   - minor code cleanup.
++   - add FORE firmware copyright notice.
++
++
++Version 0.2 (Jan, 22, 2000)
++---------------------------
++
++   as the driver is now shipped with the regular linux-atm 
++   distributions, it is now released as a diff against the latest
++   linux-atm code.
++ 
++   - drop support of 2.2.x and pre-2.3.36 kernels.
++   - switch to the new SBUS interface.
++
++
++Version 0.1f (Jan, 22, 2000)
++----------------------------
++
++  this is an interim release that makes the driver ready for the
++  important 2.3.35+ transition. Significant parts of the driver 
++  have been rewritten to comply to the principles of the new SBUS
++  interface introduced by the latest 2.3 kernels.
++
++  - clean code.
++  - rewrite memory management routines.
++  - rewrite DMA/DVMA management routines.
++  - rewrite I/O management routines (and fix design weakness).
++  - fix a bug in the initialization of the buffer supply queue.
++  - cmd polling now gives up immediately if an error condition
++    is detected.
++
++  note that the driver remains useable with 2.2 and earlier 2.3 kernels,
++  but future releases will drop support of pre-2.3.36 kernels.
++
++
++Version 0.1e (Dec, 23, 1999)
++----------------------------
++
++  - support of S/UNI hardware loopback modes via SUNI_GETLOOP/SUNI_SETLOOP
++    ioctls.
++  - add the related ioctl entries in arch/sparc64/kernel/ioctl32.c.
++  - add a simple 'sunimode' utility to get/set the S/UNI loopback mode
++    (should also work with all the drivers that use suni.c/suni.h).
++  - fix handling of 52-byte AAL0 SDUs used by atmdump-like applications:
++    * if qos.txtp.max_sdu == 52, the following tx SDU format is expected
++      by the driver:
++      <4-byte cell header><48-byte AAL0 payload>[<48-byte AAL0 payload>...]
++      i.e.
++      <--- 52-byte AAL0 SDU used by atmdump --->[<- opt. extra payloads ->]
++      otherwise, the following tx SDU format is assumed:
++      <48-byte AAL0 payload>[<48-byte AAL0 payload>...]
++    * if qos.txtp.max_sdu == 52, the rx SDUs are delivered as follows:
++      <4-byte cell header><48-byte AAL0 payload>
++      i.e.
++      <- 52-byte AAL0 SDU expected by atmdump ->
++      otherwise, the SDUs are delivered as: <48-byte AAL0 payload>
++
++
++Version 0.1d (Dec, 16, 1999)
++----------------------------
++
++  - add a retry mechanism so that the driver does not immediately give up
++    if the tx queue is saturated. Saturation of the transmit queue may occur
++    under extreme conditions, when a fast host continuously submits very
++    small frames or raw AAL0 cells.
++  - add a new config option to tune the retry mecanism.
++  - improve AAL0 support. Attempting to transmit incomplete cell payloads
++    over an AAL0 VC simply used to nuke the PCA board.
++
++
++Version 0.1c (Nov, 22, 1999)
++----------------------------
++
++  - endian-dependent code no longer depends on arch-specific definitions
++    (e.g. __powerpc__ or __sparc_v9__) but on __BIG_ENDIAN/__LITTLE_ENDIAN
++  - the right PCA-200E firmware is no longer selected according to
++    a list of well-known archs in Config.in, but is guessed from
++    <asm/byteorder.h> in Makefile.
++  - rbd/rsd handles now use the FORE200E_BUF2HDL() and FORE200E_HDL2BUF()
++    macros.
++  - minor cosmetic changes.
++  - spend some time playing with AAL0. Seems to work with MTU = 48 bytes.
++
++
++Version 0.1b (Nov, 16, 1999)
++----------------------------
++
++  - improve the configuration process in order to avoid confusion
++    caused by the firmware stuff.
++  - update accordingly the build process and the help file.
++
++    (note that the driver code is unchanged)
++
++
++Version 0.1a (Nov, 2, 1999)
++---------------------------
++
++  - use new mutex initializer in 2.3.1+ kernels.
++  - add CHANGES file.
++
++
++Version 0.1 (Oct, 25, 1999)
++---------------------------
++
++  - first public release
+--- /dev/null  Thu Jan  1 01:00:00 1970
++++ linux-2.4.20/drivers/atm/fore200e.README   Mon Dec  4 14:34:31 2000
+@@ -0,0 +1,79 @@
++
++linux-2.4.0-test9-fore200e-0.3.tar
++----------------------------------
++
++This package updates the support of the FORE Systems 200E-series ATM
++adapters by the Linux operating system. Note that the driver itself is
++now distributed with the regular Linux kernel distribution.
++
++It is based on the earlier PCA-200E driver written by Uwe Dannowski.
++
++This device driver simultaneously supports PCA-200E and SBA-200E adapters on
++i386, alpha (untested), powerpc, sparc and sparc64 hosts.
++
++The intent is to enable the use of different models of FORE adapters at the
++same time, by servers that have several bus interfaces (such as PCI+SBUS,
++PCI+MCA or PCI+EISA).
++Only PCI and SBUS devices are currently supported by the driver, but support
++for other bus interfaces such as EISA should not be too hard to add (this may
++be more tricky for the MCA bus, though, as FORE made some MCA-specific
++modifications to the adapter's AALI interface).
++
++The driver is shipped with firmware data being uploaded to the ATM adapters
++at system boot time or at module loading time. The supplied firmware images
++should work with all adapters.
++
++However, if you encounter problems (the firmware doesn't start or the driver
++is unable to read the PROM data), you may consider trying another firmware
++version. Alternative binary firmware images can be found somewhere on the
++ForeThough CD-ROM supplied with your adapter by FORE Systems.
++
++You can also get the latest firmware images from FORE Systems at
++http://www.fore.com. Register TACTics Online and go to
++the 'software updates' pages. The firmware binaries are part of
++the various ForeThough software distributions.
++
++Notice that different versions of the PCA-200E firmware exist, depending
++on the endianess of the host architecture. The driver is shipped with
++both little and big endian PCA firmware images.
++
++Name and location of the alternative firmware images can be set at kernel
++configuration time. See the INSTALL file for details.
++
++Also note that the firmware binaries are the intellectual property
++of FORE Systems, Inc. Please read the fore200e_firmware_copyright file.
++
++
++
++Driver features summary
++-----------------------
++
++    - simultaneously supports PCA-200E and SBA-200E adapters;
++    - works on i386, powerpc, SBUS-based sparc and 
++      SBUS or PCI-based sparc64 architectures;
++    - now targeted to 2.4.0-test9 kernels;
++    - uses new DVMA PCI and SBUS interfaces;
++    - useable as a removable kernel module;
++    - supports FORE pseudo-CBR rate control;
++    - the reserved CBR rate can be changed after VC setup;
++    - supports AAL0, AAL3/4 and AAL5;
++    - supports S/UNI hardware loopback modes;
++    - internal design focuses on portability and extensibility.
++
++
++Restrictions / Known bugs
++-------------------------
++
++    - only VP=0 is supported;
++    - 'insmod' coredumps when attempting to load the driver on sparc64
++      hosts (at least using the old Ultrapenguin 1.1.9 distribution);
++    - some memory resources cannot be freed on sparc, sparc64 and powerpc,
++      because the required support is still missing in 2.2 and 2.3 kernels.
++      You shouldn't try to unload the module driver on these platforms.
++
++
++Feedback
++--------
++
++Feedback is welcome. Please send success stories/bug reports/
++patches/improvement/comments/flames to <lizzi@cnam.fr>.
This page took 1.306313 seconds and 4 git commands to generate.