+++ /dev/null
-diff -urN linux-2.4.20/arch/alpha/config.in linux-2.4.20-atm/arch/alpha/config.in
---- linux-2.4.20/arch/alpha/config.in Wed May 28 01:53:41 2003
-+++ linux-2.4.20-atm/arch/alpha/config.in Wed May 28 01:58:41 2003
-@@ -355,7 +355,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
-diff -urN linux-2.4.20/arch/cris/config.in linux-2.4.20-atm/arch/cris/config.in
---- linux-2.4.20/arch/cris/config.in Wed May 28 01:53:41 2003
-+++ linux-2.4.20-atm/arch/cris/config.in Wed May 28 01:58:41 2003
-@@ -199,7 +199,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
-diff -urN linux-2.4.20/arch/i386/config.in linux-2.4.20-atm/arch/i386/config.in
---- linux-2.4.20/arch/i386/config.in Wed May 28 01:53:41 2003
-+++ linux-2.4.20-atm/arch/i386/config.in Wed May 28 01:58:41 2003
-@@ -399,7 +399,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
-diff -urN linux-2.4.20/arch/parisc/config.in linux-2.4.20-atm/arch/parisc/config.in
---- linux-2.4.20/arch/parisc/config.in Fri Nov 29 00:53:10 2002
-+++ linux-2.4.20-atm/arch/parisc/config.in Wed May 28 01:58:41 2003
-@@ -136,7 +136,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
-diff -urN linux-2.4.20/arch/ppc/config.in linux-2.4.20-atm/arch/ppc/config.in
---- linux-2.4.20/arch/ppc/config.in Wed May 28 01:53:43 2003
-+++ linux-2.4.20-atm/arch/ppc/config.in Wed May 28 01:58:41 2003
-@@ -297,7 +297,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
-diff -urN linux-2.4.20/arch/ppc64/config.in linux-2.4.20-atm/arch/ppc64/config.in
---- linux-2.4.20/arch/ppc64/config.in Wed May 28 01:53:44 2003
-+++ linux-2.4.20-atm/arch/ppc64/config.in Wed May 28 01:58:41 2003
-@@ -136,7 +136,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
-diff -urN linux-2.4.20/arch/sh/config.in linux-2.4.20-atm/arch/sh/config.in
---- linux-2.4.20/arch/sh/config.in Wed May 28 01:53:44 2003
-+++ linux-2.4.20-atm/arch/sh/config.in Wed May 28 01:58:41 2003
-@@ -259,7 +259,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
-diff -urN linux-2.4.20/arch/sparc/config.in linux-2.4.20-atm/arch/sparc/config.in
---- linux-2.4.20/arch/sparc/config.in Wed May 28 01:53:44 2003
-+++ linux-2.4.20-atm/arch/sparc/config.in Wed May 28 01:58:41 2003
-@@ -209,7 +209,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
-@@ -235,7 +235,7 @@
- # if [ "$CONFIG_FDDI" = "y" ]; then
- # fi
-
-- if [ "$CONFIG_ATM" = "y" ]; then
-+ if [ "$CONFIG_ATM" != "n" ]; then
- source drivers/atm/Config.in
- fi
- fi
-diff -urN linux-2.4.20/arch/sparc64/config.in linux-2.4.20-atm/arch/sparc64/config.in
---- linux-2.4.20/arch/sparc64/config.in Fri Nov 29 00:53:12 2002
-+++ linux-2.4.20-atm/arch/sparc64/config.in Wed May 28 01:58:41 2003
-@@ -234,7 +234,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
-diff -urN linux-2.4.20/arch/x86_64/config.in linux-2.4.20-atm/arch/x86_64/config.in
---- linux-2.4.20/arch/x86_64/config.in Wed May 28 01:53:44 2003
-+++ linux-2.4.20-atm/arch/x86_64/config.in Wed May 28 01:58:41 2003
-@@ -172,10 +172,9 @@
- bool 'Network device support' CONFIG_NETDEVICES
- if [ "$CONFIG_NETDEVICES" = "y" ]; then
- source drivers/net/Config.in
--# seems to be largely not 64bit safe
--# if [ "$CONFIG_ATM" = "y" ]; then
--# source drivers/atm/Config.in
--# fi
-+ if [ "$CONFIG_ATM" != "n" ]; then
-+ source drivers/atm/Config.in
-+ fi
- fi
- endmenu
- fi
-diff -urN linux-2.4.20/drivers/atm/Config.in linux-2.4.20-atm/drivers/atm/Config.in
---- linux-2.4.20/drivers/atm/Config.in Tue Nov 13 18:19:41 2001
-+++ linux-2.4.20-atm/drivers/atm/Config.in Wed May 28 01:58:41 2003
-@@ -4,11 +4,11 @@
- mainmenu_option next_comment
- comment 'ATM drivers'
- if [ "$CONFIG_INET" = "y" ]; then
-- tristate 'ATM over TCP' CONFIG_ATM_TCP
-+ dep_tristate 'ATM over TCP' CONFIG_ATM_TCP $CONFIG_ATM
- fi
- if [ "$CONFIG_PCI" = "y" ]; then
-- tristate 'Efficient Networks Speedstream 3010' CONFIG_ATM_LANAI
-- tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI
-+ dep_tristate 'Efficient Networks Speedstream 3010' CONFIG_ATM_LANAI $CONFIG_ATM
-+ dep_tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI $CONFIG_ATM
- if [ "$CONFIG_ATM_ENI" != "n" ]; then
- bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG
- bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST
-@@ -23,8 +23,8 @@
- bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W
- fi
- fi
-- tristate 'Fujitsu FireStream (FS50/FS155) ' CONFIG_ATM_FIRESTREAM
-- tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM
-+ dep_tristate 'Fujitsu FireStream (FS50/FS155) ' CONFIG_ATM_FIRESTREAM $CONFIG_ATM
-+ dep_tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM $CONFIG_ATM
- if [ "$CONFIG_ATM_ZATM" != "n" ]; then
- bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG
- if [ "$CONFIG_X86" = "y" ]; then
-@@ -35,32 +35,32 @@
- # if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
- # bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
- # fi
-- tristate 'IDT 77201 (NICStAR) (ForeRunnerLE)' CONFIG_ATM_NICSTAR
-+ dep_tristate 'IDT 77201 (NICStAR) (ForeRunnerLE)' CONFIG_ATM_NICSTAR $CONFIG_ATM
- if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
- bool ' Use suni PHY driver (155Mbps)' CONFIG_ATM_NICSTAR_USE_SUNI
- bool ' Use IDT77015 PHY driver (25Mbps)' CONFIG_ATM_NICSTAR_USE_IDT77105
- fi
-- tristate 'IDT 77252 (NICStAR II)' CONFIG_ATM_IDT77252
-+ dep_tristate 'IDT 77252 (NICStAR II)' CONFIG_ATM_IDT77252 $CONFIG_ATM
- if [ "$CONFIG_ATM_IDT77252" != "n" ]; then
- bool ' Enable debugging messages' CONFIG_ATM_IDT77252_DEBUG
- bool ' Receive ALL cells in raw queue' CONFIG_ATM_IDT77252_RCV_ALL
- define_bool CONFIG_ATM_IDT77252_USE_SUNI y
- fi
-- tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
-+ dep_tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR $CONFIG_ATM
- if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
- bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
- fi
-- tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON
-+ dep_tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON $CONFIG_ATM
- if [ "$CONFIG_ATM_HORIZON" != "n" ]; then
- bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
- fi
-- tristate 'Interphase ATM PCI x575/x525/x531' CONFIG_ATM_IA
-- if [ "$CONFIG_ATM_IA" != "n" ]; then
-- bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG
-- fi
-+ dep_tristate 'Interphase ATM PCI x575/x525/x531' CONFIG_ATM_IA $CONFIG_ATM
-+ if [ "$CONFIG_ATM_IA" != "n" ]; then
-+ bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG
-+ fi
- fi
- if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then
-- tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE
-+ dep_tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE $CONFIG_ATM
- if [ "$CONFIG_ATM_FORE200E_MAYBE" != "n" ]; then
- if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA
-@@ -90,6 +90,10 @@
- else
- define_tristate CONFIG_ATM_FORE200E m
- fi
-+ fi
-+ dep_tristate 'ForeRunnerHE (155/622)' CONFIG_ATM_HE $CONFIG_ATM
-+ if [ "$CONFIG_ATM_HE" != "n" ] ; then
-+ bool ' Use S/UNI PHY driver' CONFIG_ATM_HE_USE_SUNI $CONFIG_ATM_HE
- fi
- fi
- endmenu
-diff -urN linux-2.4.20/drivers/atm/Makefile linux-2.4.20-atm/drivers/atm/Makefile
---- linux-2.4.20/drivers/atm/Makefile Wed Nov 7 23:39:36 2001
-+++ linux-2.4.20-atm/drivers/atm/Makefile Wed May 28 01:58:41 2003
-@@ -32,6 +32,10 @@
- obj-$(CONFIG_ATM_IA) += iphase.o suni.o
- obj-$(CONFIG_ATM_FIRESTREAM) += firestream.o
- obj-$(CONFIG_ATM_LANAI) += lanai.o
-+obj-$(CONFIG_ATM_HE) += he.o
-+ifeq ($(CONFIG_ATM_HE_USE_SUNI),y)
-+ obj-$(CONFIG_ATM_HE) += suni.o
-+endif
-
- ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
- FORE200E_FW_OBJS += fore200e_pca_fw.o
-diff -urN linux-2.4.20/drivers/atm/ambassador.c linux-2.4.20-atm/drivers/atm/ambassador.c
---- linux-2.4.20/drivers/atm/ambassador.c Fri Sep 14 00:21:32 2001
-+++ linux-2.4.20-atm/drivers/atm/ambassador.c Wed May 28 01:58:41 2003
-@@ -1149,14 +1149,6 @@
- }
- #endif
-
-- // deal with possibly wildcarded VCs
-- error = atm_find_ci (atm_vcc, &vpi, &vci);
-- if (error) {
-- PRINTD (DBG_WARN|DBG_VCC, "atm_find_ci failed!");
-- return error;
-- }
-- PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci);
--
- if (!(0 <= vpi && vpi < (1<<NUM_VPI_BITS) &&
- 0 <= vci && vci < (1<<NUM_VCI_BITS))) {
- PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci);
-diff -urN linux-2.4.20/drivers/atm/atmtcp.c linux-2.4.20-atm/drivers/atm/atmtcp.c
---- linux-2.4.20/drivers/atm/atmtcp.c Fri Nov 29 00:53:12 2002
-+++ linux-2.4.20-atm/drivers/atm/atmtcp.c Wed May 28 01:58:41 2003
-@@ -4,6 +4,7 @@
-
-
- #include <linux/module.h>
-+#include <linux/init.h>
- #include <linux/wait.h>
- #include <linux/atmdev.h>
- #include <linux/atm_tcp.h>
-@@ -125,8 +125,6 @@
- msg.addr.sap_addr.vpi = vpi;
- msg.hdr.vci = htons(vci);
- msg.addr.sap_addr.vci = vci;
-- error = atm_find_ci(vcc,&msg.addr.sap_addr.vpi,&msg.addr.sap_addr.vci);
-- if (error) return error;
- if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
- msg.type = ATMTCP_CTRL_OPEN;
- msg.qos = vcc->qos;
-@@ -155,6 +153,7 @@
- {
- struct atm_cirange ci;
- struct atm_vcc *vcc;
-+ struct sock *s;
-
- if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
- if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
-@@ -162,9 +161,17 @@
- if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
- if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
- ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
-- for (vcc = dev->vccs; vcc; vcc = vcc->next)
-+ read_lock(&vcc_sklist_lock);
-+ for (s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
-+ if (vcc->dev != dev) continue;
- if ((vcc->vpi >> ci.vpi_bits) ||
-- (vcc->vci >> ci.vci_bits)) return -EBUSY;
-+ (vcc->vci >> ci.vci_bits)) {
-+ read_unlock(&vcc_sklist_lock);
-+ return -EBUSY;
-+ }
-+ }
-+ read_unlock(&vcc_sklist_lock);
- dev->ci_range = ci;
- return 0;
- }
-@@ -230,6 +237,7 @@
- struct atm_dev *atmtcp_dev;
- struct atmtcp_dev_data *dev_data;
- struct atm_vcc *walk;
-+ struct sock *s;
-
- atmtcp_dev = (struct atm_dev *) vcc->dev_data;
- dev_data = PRIV(atmtcp_dev);
-@@ -239,8 +247,12 @@
- kfree(dev_data);
- shutdown_atm_dev(atmtcp_dev);
- vcc->dev_data = NULL;
-- for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
-- wake_up(&walk->sleep);
-+ read_lock(&vcc_sklist_lock);
-+ for (s = vcc_sklist; s; s = s->next) {
-+ walk = atm_sk(s);
-+ if (walk->dev == atmtcp_dev) wake_up(&walk->sleep);
-+ }
-+ read_unlock(&vcc_sklist_lock);
- }
-
-
-@@ -248,7 +260,8 @@
- {
- struct atm_dev *dev;
- struct atmtcp_hdr *hdr;
-- struct atm_vcc *out_vcc;
-+ struct atm_vcc *out_vcc = NULL;
-+ struct sock *s;
- struct sk_buff *new_skb;
- int result = 0;
-
-@@ -260,11 +273,17 @@
- (struct atmtcp_control *) skb->data);
- goto done;
- }
-- for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
-+ read_lock(&vcc_sklist_lock);
-+ for (s = vcc_sklist; s; s = s->next) {
-+ out_vcc = atm_sk(s);
-+ if (out_vcc->dev != dev) continue;
- if (out_vcc->vpi == ntohs(hdr->vpi) &&
- out_vcc->vci == ntohs(hdr->vci) &&
- out_vcc->qos.rxtp.traffic_class != ATM_NONE)
- break;
-+ out_vcc = NULL;
-+ }
-+ read_unlock(&vcc_sklist_lock);
- if (!out_vcc) {
- atomic_inc(&vcc->stats->tx_err);
- goto done;
-@@ -315,15 +334,10 @@
-
-
- static struct atm_dev atmtcp_control_dev = {
-- &atmtcp_c_dev_ops,
-- NULL, /* no PHY */
-- "atmtcp", /* type */
-- 999, /* dummy device number */
-- NULL,NULL, /* pretend not to have any VCCs */
-- NULL,NULL, /* no data */
-- { 0 }, /* no flags */
-- NULL, /* no local address */
-- { 0 } /* no ESI, no statistics */
-+ .ops = &atmtcp_c_dev_ops,
-+ .type = "atmtcp",
-+ .number = 999,
-+ .lock = SPIN_LOCK_UNLOCKED
- };
-
-
-@@ -356,9 +370,12 @@
- struct atm_dev *dev;
-
- dev = NULL;
-- if (itf != -1) dev = atm_find_dev(itf);
-+ if (itf != -1) dev = atm_dev_lookup(itf);
- if (dev) {
-- if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
-+ if (dev->ops != &atmtcp_v_dev_ops) {
-+ atm_dev_release(dev);
-+ return -EMEDIUMTYPE;
-+ }
- if (PRIV(dev)->vcc) return -EBUSY;
- }
- else {
-@@ -368,7 +385,7 @@
- if (error) return error;
- }
- PRIV(dev)->vcc = vcc;
-- bind_vcc(vcc,&atmtcp_control_dev);
-+ vcc_insert_socket(&atmtcp_control_dev, vcc->sk);
- set_bit(ATM_VF_META,&vcc->flags);
- set_bit(ATM_VF_READY,&vcc->flags);
- vcc->dev_data = dev;
-@@ -389,44 +406,42 @@
- struct atm_dev *dev;
- struct atmtcp_dev_data *dev_data;
-
-- dev = atm_find_dev(itf);
-+ dev = atm_dev_lookup(itf);
- if (!dev) return -ENODEV;
-- if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
-+ if (dev->ops != &atmtcp_v_dev_ops) {
-+ atm_dev_release(dev);
-+ return -EMEDIUMTYPE;
-+ }
- dev_data = PRIV(dev);
- if (!dev_data->persist) return 0;
- dev_data->persist = 0;
- if (PRIV(dev)->vcc) return 0;
- kfree(dev_data);
-+ atm_dev_release(dev);
- shutdown_atm_dev(dev);
- return 0;
- }
-
-
--#ifdef MODULE
-+static struct atm_tcp_ops __atm_tcp_ops = {
-+ atmtcp_attach, /* attach */
-+ atmtcp_create_persistent, /* create_persistent */
-+ atmtcp_remove_persistent /* remove_persistent */
-+};
-+
-
--int init_module(void)
-+static int __init atmtcp_init(void)
- {
-- atm_tcp_ops.attach = atmtcp_attach;
-- atm_tcp_ops.create_persistent = atmtcp_create_persistent;
-- atm_tcp_ops.remove_persistent = atmtcp_remove_persistent;
-+ atm_tcp_ops = &__atm_tcp_ops;
- return 0;
- }
-
--
--void cleanup_module(void)
-+static void __exit atmtcp_cleanup(void)
- {
-- atm_tcp_ops.attach = NULL;
-- atm_tcp_ops.create_persistent = NULL;
-- atm_tcp_ops.remove_persistent = NULL;
-+ atm_tcp_ops = NULL;
- }
-
--MODULE_LICENSE("GPL");
--#else
-+module_init(atmtcp_init);
-+module_exit(atmtcp_cleanup);
-
--struct atm_tcp_ops atm_tcp_ops = {
-- atmtcp_attach, /* attach */
-- atmtcp_create_persistent, /* create_persistent */
-- atmtcp_remove_persistent /* remove_persistent */
--};
--
--#endif
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.20/drivers/atm/eni.c linux-2.4.20-atm/drivers/atm/eni.c
---- linux-2.4.20/drivers/atm/eni.c Fri Dec 21 18:41:53 2001
-+++ linux-2.4.20-atm/drivers/atm/eni.c Wed May 28 01:58:41 2003
-@@ -829,6 +829,7 @@
- if (eni_dev->rx_map[vcc->vci])
- printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already "
- "in use\n",vcc->dev->number,vcc->vci);
-+ vcc_hold(vcc);
- eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */
- writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) <<
- MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE |
-@@ -858,7 +859,11 @@
- /* discard pending cell */
- writel(readl(here) & ~MID_VCI_IN_SERVICE,here);
- /* don't accept any new ones */
-+ tasklet_disable(&eni_dev->task);
- eni_dev->rx_map[vcc->vci] = NULL;
-+ barrier();
-+ tasklet_enable(&eni_dev->task);
-+ vcc_put(vcc);
- /* wait for RX queue to drain */
- DPRINTK("eni_close: waiting for RX ...\n");
- EVENT("RX closing\n",0,0);
-@@ -1101,9 +1106,9 @@
- dma_rd = eni_in(MID_DMA_RD_TX);
- dma_size = 3; /* JK for descriptor and final fill, plus final size
- mis-alignment fix */
--DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
-- if (!ATM_SKB(skb)->iovcnt) dma_size += 5;
-- else dma_size += 5*ATM_SKB(skb)->iovcnt;
-+DPRINTK("nr_frags = %d\n", skb_shinfo(skb)->nr_frags);
-+ if (!skb_shinfo(skb)->nr_frags) dma_size += 5;
-+ else dma_size += 5*skb_shinfo(skb)->nr_frags;
- if (dma_size > TX_DMA_BUF) {
- printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries "
- "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF);
-@@ -1124,15 +1129,15 @@
- MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |
- MID_DT_JK;
- j++;
-- if (!ATM_SKB(skb)->iovcnt)
-+ if (!skb_shinfo(skb)->nr_frags)
- if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len);
- else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4);
- else {
- DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
-- for (i = 0; i < ATM_SKB(skb)->iovcnt; i++)
-+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
-- ((struct iovec *) skb->data)[i].iov_base,
-- ((struct iovec *) skb->data)[i].iov_len);
-+ skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset,
-+ skb_shinfo(skb)->frags[i].size);
- }
- if (skb->len & 3)
- put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));
-@@ -1880,43 +1885,6 @@
- }
-
-
--static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
--{
-- struct atm_vcc *walk;
--
-- if (*vpi == ATM_VPI_ANY) *vpi = 0;
-- if (*vci == ATM_VCI_ANY) {
-- for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
-- if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
-- ENI_DEV(vcc->dev)->rx_map[*vci])
-- continue;
-- if (vcc->qos.txtp.traffic_class != ATM_NONE) {
-- for (walk = vcc->dev->vccs; walk;
-- walk = walk->next)
-- if (test_bit(ATM_VF_ADDR,&walk->flags)
-- && walk->vci == *vci &&
-- walk->qos.txtp.traffic_class !=
-- ATM_NONE)
-- break;
-- if (walk) continue;
-- }
-- break;
-- }
-- return *vci == NR_VCI ? -EADDRINUSE : 0;
-- }
-- if (*vci == ATM_VCI_UNSPEC) return 0;
-- if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
-- ENI_DEV(vcc->dev)->rx_map[*vci])
-- return -EADDRINUSE;
-- if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
-- for (walk = vcc->dev->vccs; walk; walk = walk->next)
-- if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
-- walk->qos.txtp.traffic_class != ATM_NONE)
-- return -EADDRINUSE;
-- return 0;
--}
--
--
- static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
- {
- struct eni_dev *eni_dev;
-@@ -1927,8 +1895,6 @@
- EVENT("eni_open\n",0,0);
- if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL;
- eni_dev = ENI_DEV(vcc->dev);
-- error = get_ci(vcc,&vpi,&vci);
-- if (error) return error;
- vcc->vpi = vpi;
- vcc->vci = vci;
- if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
-@@ -2122,8 +2088,8 @@
- {
- static const char *signal[] = { "LOST","unknown","okay" };
- struct eni_dev *eni_dev = ENI_DEV(dev);
-- struct atm_vcc *vcc;
- int left,i;
-+ struct sock *s;
-
- left = *pos;
- if (!left)
-@@ -2192,10 +2158,13 @@
- return sprintf(page,"%10sbacklog %u packets\n","",
- skb_queue_len(&tx->backlog));
- }
-- for (vcc = dev->vccs; vcc; vcc = vcc->next) {
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ struct atm_vcc *vcc = atm_sk(s);
- struct eni_vcc *eni_vcc = ENI_VCC(vcc);
- int length;
-
-+ if (vcc->dev != dev) continue;
- if (--left) continue;
- length = sprintf(page,"vcc %4d: ",vcc->vci);
- if (eni_vcc->rx) {
-@@ -2210,8 +2179,10 @@
- length += sprintf(page+length,"tx[%d], txing %d bytes",
- eni_vcc->tx->index,eni_vcc->txing);
- page[length] = '\n';
-+ spin_unlock(&dev->lock);
- return length+1;
- }
-+ read_unlock(&vcc_sklist_lock);
- for (i = 0; i < eni_dev->free_len; i++) {
- struct eni_free *fe = eni_dev->free_list+i;
- unsigned long offset;
-diff -urN linux-2.4.20/drivers/atm/firestream.c linux-2.4.20-atm/drivers/atm/firestream.c
---- linux-2.4.20/drivers/atm/firestream.c Fri Nov 29 00:53:12 2002
-+++ linux-2.4.20-atm/drivers/atm/firestream.c Wed May 28 01:58:41 2003
-@@ -874,12 +874,6 @@
- fs_dprintk (FS_DEBUG_OPEN, "fs: open on dev: %p, vcc at %p\n",
- dev, atm_vcc);
-
-- error = atm_find_ci(atm_vcc, &vpi, &vci);
-- if (error) {
-- fs_dprintk (FS_DEBUG_OPEN, "fs: find_ci failed.\n");
-- return error;
-- }
--
- atm_vcc->vpi = vpi;
- atm_vcc->vci = vci;
- if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
-diff -urN linux-2.4.20/drivers/atm/fore200e.c linux-2.4.20-atm/drivers/atm/fore200e.c
---- linux-2.4.20/drivers/atm/fore200e.c Wed May 28 01:53:45 2003
-+++ linux-2.4.20-atm/drivers/atm/fore200e.c Wed May 28 01:58:41 2003
-@@ -65,7 +65,7 @@
- #define FORE200E_52BYTE_AAL0_SDU
- #endif
-
--#define FORE200E_VERSION "0.2d"
-+#define FORE200E_VERSION "0.2f"
-
-
- #define FORE200E "fore200e: "
-@@ -1077,15 +1077,7 @@
- static struct atm_vcc*
- fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
- {
-- struct atm_vcc* vcc;
--
-- for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
--
-- if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
-- break;
-- }
--
-- return vcc;
-+ return vcc_lookup(fore200e->atm_dev, rpd->atm_header.vpi, rpd->atm_header.vci);
- }
-
-
-@@ -1132,6 +1124,7 @@
-
- printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
- atomic_inc(&vcc->stats->rx_drop);
-+ vcc_put(vcc);
- return;
- }
-
-@@ -1166,14 +1159,16 @@
- if (atm_charge(vcc, skb->truesize) == 0) {
-
- DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n",
-- vcc->itf, vcc->vpi, vcc->vci);
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci);
-
- dev_kfree_skb_irq(skb);
-+ vcc_put(vcc);
- return;
- }
-
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
-+ vcc_put(vcc);
- }
-
-
-@@ -1215,8 +1210,8 @@
- fore200e_push_rpd(fore200e, entry->rpd);
- }
- else {
-- printk(FORE200E "damaged PDU on %d.%d.%d\n",
-- fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
-+ DPRINTK(1, "damaged PDU on %d.%d.%d\n",
-+ fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
- }
-
- fore200e_collect_rpd(fore200e, entry->rpd);
-@@ -1281,7 +1276,7 @@
- #endif
-
- DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n",
-- vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second");
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second");
-
- return scheme;
- }
-@@ -1351,39 +1346,6 @@
- }
-
-
--static int
--fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
--{
-- struct atm_vcc* walk;
--
-- /* find a free VPI */
-- if (*vpi == ATM_VPI_ANY) {
--
-- for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
--
-- if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
-- (*vpi)++;
-- walk = vcc->dev->vccs;
-- }
-- }
-- }
--
-- /* find a free VCI */
-- if (*vci == ATM_VCI_ANY) {
--
-- for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
--
-- if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
-- *vci = walk->vci + 1;
-- walk = vcc->dev->vccs;
-- }
-- }
-- }
--
-- return 0;
--}
--
--
- #define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */
-
- static void
-@@ -1408,9 +1370,6 @@
- struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
- struct fore200e_vcc* fore200e_vcc;
-
-- /* find a free VPI/VCI */
-- fore200e_walk_vccs(vcc, &vpi, &vci);
--
- vcc->vpi = vpi;
- vcc->vci = vci;
-
-@@ -1419,11 +1378,11 @@
- return 0;
-
- set_bit(ATM_VF_ADDR, &vcc->flags);
-- vcc->itf = vcc->dev->number;
-+ vcc->sk->bound_dev_if = 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",
-- vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
- fore200e_traffic_class[ vcc->qos.txtp.traffic_class ],
- vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu,
- fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ],
-@@ -1469,7 +1428,7 @@
- fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate);
-
- DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n",
-- vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
- vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr,
- fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells);
- }
-@@ -1488,7 +1447,7 @@
- {
- struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
-
-- DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
-+ DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
-
- fore200e_activate_vcin(fore200e, 0, vcc, 0);
-
-@@ -1543,7 +1502,7 @@
-
- retry_here:
-
-- tasklet_disable(&fore200e->tasklet);
-+ spin_lock_bh(&fore200e->tx_lock);
-
- entry = &txq->host_entry[ txq->head ];
-
-@@ -1553,8 +1512,8 @@
- fore200e_irq_tx(fore200e);
-
- if (*entry->status != STATUS_FREE) {
--
-- tasklet_enable(&fore200e->tasklet);
-+
-+ spin_unlock_bh(&fore200e->tx_lock);
-
- /* retry once again? */
- if(--retry > 0)
-@@ -1593,8 +1552,9 @@
-
- entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
- if (entry->data == NULL) {
--
-- tasklet_enable(&fore200e->tasklet);
-+
-+ spin_unlock_bh(&fore200e->tx_lock);
-+
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
-@@ -1618,13 +1578,13 @@
- FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
- txq->txing++;
-
-- tasklet_enable(&fore200e->tasklet);
-+ spin_unlock_bh(&fore200e->tx_lock);
-
- /* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
-
- DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n",
-- vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
- tpd->tsd[0].length, skb_len);
-
- if (skb_len < fore200e_vcc->tx_min_pdu)
-@@ -1690,14 +1650,14 @@
- dev_kfree_skb(skb);
-
- if (ok == 0) {
-- printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
-+ printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->sk->bound_dev_if, vcc->vpi, vcc->vci);
-
- atomic_inc(&entry->vcc->stats->tx_err);
- return -EIO;
- }
- atomic_inc(&entry->vcc->stats->tx);
-
-- DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
-+ DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->sk->bound_dev_if, vcc->vpi, vcc->vci);
-
- }
- #endif
-@@ -1755,7 +1715,7 @@
- // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
-
- DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
-- vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, level, optname, optval, optlen);
-
- return -EINVAL;
- }
-@@ -1767,7 +1727,7 @@
- // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
-
- DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
-- vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci, level, optname, optval, optlen);
-
- return -EINVAL;
- }
-@@ -1963,7 +1923,7 @@
- "(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"
- "available_cell_rate = %u",
-- vcc->itf, vcc->vpi, vcc->vci,
-+ vcc->sk->bound_dev_if, vcc->vpi, vcc->vci,
- fore200e_traffic_class[ qos->txtp.traffic_class ],
- qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu,
- fore200e_traffic_class[ qos->rxtp.traffic_class ],
-@@ -2355,6 +2315,7 @@
-
- DPRINTK(2, "device %s being initialized\n", fore200e->name);
-
-+ spin_lock_init(&fore200e->tx_lock);
- init_MUTEX(&fore200e->rate_sf);
-
- cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
-@@ -2642,6 +2603,7 @@
- {
- struct fore200e* fore200e = FORE200E_DEV(dev);
- int len, left = *pos;
-+ struct sock *s;
-
- if (!left--) {
-
-@@ -2886,7 +2848,11 @@
- len = sprintf(page,"\n"
- " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
-
-- for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
-+
-+ if (vcc->dev != fore200e->atm_dev) continue;
-
- fore200e_vcc = FORE200E_VCC(vcc);
-
-@@ -2900,6 +2866,7 @@
- fore200e_vcc->rx_max_pdu
- );
- }
-+ read_unlock(&vcc_sklist_lock);
-
- return len;
- }
-diff -urN linux-2.4.20/drivers/atm/fore200e.h linux-2.4.20-atm/drivers/atm/fore200e.h
---- linux-2.4.20/drivers/atm/fore200e.h Mon Dec 11 22:22:12 2000
-+++ linux-2.4.20-atm/drivers/atm/fore200e.h Wed May 28 01:58:41 2003
-@@ -879,6 +879,7 @@
- struct stats* stats; /* last snapshot of the stats */
-
- struct semaphore rate_sf; /* protects rate reservation ops */
-+ spinlock_t tx_lock; /* protects tx ops */
- struct tasklet_struct tasklet; /* performs interrupt work */
-
- } fore200e_t;
-diff -urN linux-2.4.20/drivers/atm/he.c linux-2.4.20-atm/drivers/atm/he.c
---- linux-2.4.20/drivers/atm/he.c Thu Jan 1 01:00:00 1970
-+++ linux-2.4.20-atm/drivers/atm/he.c Wed May 28 01:58:41 2003
-@@ -0,0 +1,3282 @@
-+/* $Id$ */
-+
-+/*
-+
-+ he.c
-+
-+ ForeRunnerHE ATM Adapter driver for ATM on Linux
-+ Copyright (C) 1999-2001 Naval Research Laboratory
-+
-+ This library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2.1 of the License, or (at your option) any later version.
-+
-+ This library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with this library; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+*/
-+
-+/*
-+
-+ he.c
-+
-+ ForeRunnerHE ATM Adapter driver for ATM on Linux
-+ Copyright (C) 1999-2001 Naval Research Laboratory
-+
-+ Permission to use, copy, modify and distribute this software and its
-+ documentation is hereby granted, provided that both the copyright
-+ notice and this permission notice appear in all copies of the software,
-+ derivative works or modified versions, and any portions thereof, and
-+ that both notices appear in supporting documentation.
-+
-+ NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
-+ DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
-+ RESULTING FROM THE USE OF THIS SOFTWARE.
-+
-+ This driver was written using the "Programmer's Reference Manual for
-+ ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98.
-+
-+ AUTHORS:
-+ chas williams <chas@cmf.nrl.navy.mil>
-+ eric kinzie <ekinzie@cmf.nrl.navy.mil>
-+
-+ NOTES:
-+ 4096 supported 'connections'
-+ group 0 is used for all traffic
-+ interrupt queue 0 is used for all interrupts
-+ aal0 support for receive only
-+
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/skbuff.h>
-+#include <linux/pci.h>
-+#include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/string.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <asm/io.h>
-+#include <asm/byteorder.h>
-+#include <asm/uaccess.h>
-+
-+#include <linux/atmdev.h>
-+#include <linux/atm.h>
-+#include <linux/sonet.h>
-+#ifndef ATM_OC12_PCR
-+#define ATM_OC12_PCR (622080000/1080*1040/8/53)
-+#endif
-+
-+#ifdef BUS_INT_WAR
-+void sn_add_polled_interrupt(int irq, int interval);
-+void sn_delete_polled_interrupt(int irq);
-+#endif
-+
-+#define USE_TASKLET
-+#define USE_HE_FIND_VCC
-+#define USE_SCATTERGATHER
-+#undef USE_CHECKSUM_HW /* still confused about this */
-+#define USE_RBPS /* probably broken */
-+#define USE_RBPL_POOL
-+
-+#ifdef CONFIG_ATM_HE_USE_SUNI_MODULE
-+#define CONFIG_ATM_HE_USE_SUNI
-+#endif
-+
-+/* 2.2 kernel support */
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
-+#define dev_kfree_skb_irq(skb) dev_kfree_skb(skb)
-+#define dev_kfree_skb_any(skb) dev_kfree_skb(skb)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
-+#define set_current_state(x) current->state = (x);
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
-+#undef USE_TASKLET
-+#endif
-+
-+#include "he.h"
-+
-+#include "suni.h"
-+
-+#include <linux/atm_he.h>
-+
-+#define hprintk(fmt,args...) printk(DEV_LABEL "%d: " fmt, he_dev->number, args)
-+#define hprintk1(fmt) printk(DEV_LABEL "%d: " fmt, he_dev->number)
-+
-+#undef DEBUG
-+#ifdef DEBUG
-+#define HPRINTK(fmt,args...) hprintk(fmt,args)
-+#define HPRINTK1(fmt) hprintk1(fmt)
-+#else
-+#define HPRINTK(fmt,args...)
-+#define HPRINTK1(fmt,args...)
-+#endif /* DEBUG */
-+
-+
-+/* version definition */
-+
-+static char *version = "$Id$";
-+
-+/* defines */
-+#define ALIGN_ADDRESS(addr, alignment) \
-+ ((((unsigned long) (addr)) + (((unsigned long) (alignment)) - 1)) & ~(((unsigned long) (alignment)) - 1))
-+
-+/* declarations */
-+
-+static int he_open(struct atm_vcc *vcc, short vpi, int vci);
-+static void he_close(struct atm_vcc *vcc);
-+static int he_send(struct atm_vcc *vcc, struct sk_buff *skb);
-+static int he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size);
-+static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg);
-+static void he_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
-+static void he_tasklet(unsigned long data);
-+static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
-+static int he_start(struct atm_dev *dev);
-+static void he_stop(struct he_dev *dev);
-+static void he_phy_put(struct atm_dev *, unsigned char, unsigned long);
-+static unsigned char he_phy_get(struct atm_dev *, unsigned long);
-+
-+static u8 read_prom_byte(struct he_dev *he_dev, int addr);
-+
-+/* globals */
-+
-+struct he_dev *he_devs = NULL;
-+static short disable64 = -1;
-+static short nvpibits = -1;
-+static short nvcibits = -1;
-+static short rx_skb_reserve = 16;
-+static short irq_coalesce = 1;
-+static short sdh = 1;
-+
-+static struct atmdev_ops he_ops =
-+{
-+ open: he_open,
-+ close: he_close,
-+ ioctl: he_ioctl,
-+ send: he_send,
-+ sg_send: he_sg_send,
-+ phy_put: he_phy_put,
-+ phy_get: he_phy_get,
-+ proc_read: he_proc_read,
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1)
-+ owner: THIS_MODULE
-+#endif
-+};
-+
-+/* see the comments in he.h about global_lock */
-+
-+#ifdef CONFIG_SMP
-+#define HE_SPIN_LOCK(dev, flags) spin_lock_irqsave(&(dev)->global_lock, flags)
-+#define HE_SPIN_UNLOCK(dev, flags) spin_unlock_irqrestore(&(dev)->global_lock, flags)
-+#else
-+#define HE_SPIN_LOCK(dev, flags) do { flags = 0; } while(0)
-+#define HE_SPIN_UNLOCK(dev, flags) do { flags = 0; } while(0)
-+#endif
-+
-+
-+#define he_writel(dev, val, reg) writel(val, (dev)->membase + (reg))
-+#define he_readl(dev, reg) readl((dev)->membase + (reg))
-+
-+/* section 2.12 connection memory access */
-+
-+static __inline__ void
-+he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr,
-+ unsigned flags)
-+{
-+ while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
-+ he_writel(he_dev, val, CON_DAT);
-+ he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL);
-+}
-+
-+#define he_writel_rcm(dev, val, reg) \
-+ he_writel_internal(dev, val, reg, CON_CTL_RCM)
-+
-+#define he_writel_tcm(dev, val, reg) \
-+ he_writel_internal(dev, val, reg, CON_CTL_TCM)
-+
-+#define he_writel_mbox(dev, val, reg) \
-+ he_writel_internal(dev, val, reg, CON_CTL_MBOX)
-+
-+static unsigned
-+he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags)
-+{
-+ while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
-+ he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL);
-+ return he_readl(he_dev, CON_DAT);
-+}
-+
-+#define he_readl_rcm(dev, reg) \
-+ he_readl_internal(dev, reg, CON_CTL_RCM)
-+
-+#define he_readl_tcm(dev, reg) \
-+ he_readl_internal(dev, reg, CON_CTL_TCM)
-+
-+#define he_readl_mbox(dev, reg) \
-+ he_readl_internal(dev, reg, CON_CTL_MBOX)
-+
-+
-+/* figure 2.2 connection id */
-+
-+#define he_mkcid(dev, vpi, vci) (((vpi<<(dev)->vcibits) | vci) & 0x1fff)
-+
-+/* 2.5.1 per connection transmit state registers */
-+
-+#define he_writel_tsr0(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 0)
-+#define he_readl_tsr0(dev, cid) \
-+ he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 0)
-+
-+#define he_writel_tsr1(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 1)
-+
-+#define he_writel_tsr2(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 2)
-+
-+#define he_writel_tsr3(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 3)
-+
-+#define he_writel_tsr4(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 4)
-+
-+ /* from page 2-20
-+ *
-+ * NOTE While the transmit connection is active, bits 23 through 0
-+ * of this register must not be written by the host. Byte
-+ * enables should be used during normal operation when writing
-+ * the most significant byte.
-+ */
-+
-+#define he_writel_tsr4_upper(dev, val, cid) \
-+ he_writel_internal(dev, val, CONFIG_TSRA | (cid<<3) | 4, \
-+ CON_CTL_TCM \
-+ | CON_BYTE_DISABLE_2 \
-+ | CON_BYTE_DISABLE_1 \
-+ | CON_BYTE_DISABLE_0)
-+
-+#define he_readl_tsr4(dev, cid) \
-+ he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 4)
-+
-+#define he_writel_tsr5(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 5)
-+
-+#define he_writel_tsr6(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 6)
-+
-+#define he_writel_tsr7(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 7)
-+
-+
-+#define he_writel_tsr8(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<1) | 0)
-+
-+#define he_writel_tsr9(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<1) | 1)
-+
-+
-+#define he_writel_tsr10(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<2) | 0)
-+
-+#define he_writel_tsr11(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<2) | 1)
-+
-+#define he_writel_tsr12(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<2) | 2)
-+
-+#define he_writel_tsr13(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<2) | 3)
-+
-+
-+#define he_writel_tsr14(dev, val, cid) \
-+ he_writel_tcm(dev, val, CONFIG_TSRD | cid)
-+
-+#define he_writel_tsr14_upper(dev, val, cid) \
-+ he_writel_internal(dev, val, CONFIG_TSRD | cid, \
-+ CON_CTL_TCM \
-+ | CON_BYTE_DISABLE_2 \
-+ | CON_BYTE_DISABLE_1 \
-+ | CON_BYTE_DISABLE_0)
-+
-+/* 2.7.1 per connection receive state registers */
-+
-+#define he_writel_rsr0(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 0)
-+#define he_readl_rsr0(dev, cid) \
-+ he_readl_rcm(dev, 0x00000 | (cid<<3) | 0)
-+
-+#define he_writel_rsr1(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 1)
-+
-+#define he_writel_rsr2(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 2)
-+
-+#define he_writel_rsr3(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 3)
-+
-+#define he_writel_rsr4(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 4)
-+
-+#define he_writel_rsr5(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 5)
-+
-+#define he_writel_rsr6(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 6)
-+
-+#define he_writel_rsr7(dev, val, cid) \
-+ he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 7)
-+
-+static __inline__ struct atm_vcc*
-+he_find_vcc(struct he_dev *he_dev, unsigned cid)
-+{
-+ short vpi;
-+ int vci;
-+
-+ vpi = cid >> he_dev->vcibits;
-+ vci = cid & ((1<<he_dev->vcibits)-1);
-+
-+ return __vcc_lookup(he_dev->atm_dev, vpi, vci);
-+}
-+
-+static int __devinit
-+he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
-+{
-+ struct atm_dev *atm_dev;
-+ struct he_dev *he_dev;
-+
-+ printk(KERN_INFO "he: %s\n", version);
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,43)
-+ if (pci_enable_device(pci_dev)) return -EIO;
-+#endif
-+ if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0)
-+ {
-+ printk(KERN_WARNING "he: no suitable dma available\n");
-+ return -EIO;
-+ }
-+
-+ atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, 0);
-+ if (!atm_dev) return -ENODEV;
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,3)
-+ pci_set_drvdata(pci_dev, atm_dev);
-+#else
-+ pci_dev->driver_data = atm_dev;
-+#endif
-+
-+ he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev),
-+ GFP_KERNEL);
-+ if (!he_dev) return -ENOMEM;
-+ memset(he_dev, 0, sizeof(struct he_dev));
-+
-+ he_dev->pci_dev = pci_dev;
-+ he_dev->atm_dev = atm_dev;
-+ he_dev->atm_dev->dev_data = he_dev;
-+ HE_DEV(atm_dev) = he_dev;
-+ he_dev->number = atm_dev->number; /* was devs */
-+ if (he_start(atm_dev)) {
-+ atm_dev_deregister(atm_dev);
-+ he_stop(he_dev);
-+ kfree(he_dev);
-+ return -ENODEV;
-+ }
-+ he_dev->next = NULL;
-+ if (he_devs) he_dev->next = he_devs;
-+ he_devs = he_dev;
-+
-+ return 0;
-+}
-+
-+static void __devexit
-+he_remove_one (struct pci_dev *pci_dev)
-+{
-+ struct atm_dev *atm_dev;
-+ struct he_dev *he_dev;
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,3)
-+ atm_dev = pci_get_drvdata(pci_dev);
-+#else
-+ atm_dev = pci_dev->driver_data;
-+#endif
-+ he_dev = HE_DEV(atm_dev);
-+
-+ /* need to remove from he_devs */
-+
-+ he_stop(he_dev);
-+ atm_dev_deregister(atm_dev);
-+ kfree(he_dev);
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,3)
-+ pci_set_drvdata(pci_dev, NULL);
-+#else
-+ pci_dev->driver_data = NULL;
-+#endif
-+}
-+
-+
-+static unsigned
-+rate_to_atmf(unsigned rate) /* cps to atm forum format */
-+{
-+#define NONZERO (1<<14)
-+
-+ unsigned exp = 0;
-+
-+ if (rate == 0) return(0);
-+
-+ rate <<= 9;
-+ while (rate > 0x3ff)
-+ {
-+ ++exp;
-+ rate >>= 1;
-+ }
-+
-+ return (NONZERO | (exp << 9) | (rate & 0x1ff));
-+}
-+
-+static void __init
-+he_init_rx_lbfp0(struct he_dev *he_dev)
-+{
-+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
-+ unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
-+ unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row;
-+
-+ lbufd_index = 0;
-+ lbm_offset = he_readl(he_dev, RCMLBM_BA);
-+
-+ he_writel(he_dev, lbufd_index, RLBF0_H);
-+
-+ for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i)
-+ {
-+ lbufd_index += 2;
-+ lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
-+
-+ he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
-+ he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
-+
-+ if (++lbuf_count == lbufs_per_row)
-+ {
-+ lbuf_count = 0;
-+ row_offset += he_dev->bytes_per_row;
-+ }
-+ lbm_offset += 4;
-+ }
-+
-+ he_writel(he_dev, lbufd_index - 2, RLBF0_T);
-+ he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
-+}
-+
-+static void __init
-+he_init_rx_lbfp1(struct he_dev *he_dev)
-+{
-+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
-+ unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
-+ unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row;
-+
-+ lbufd_index = 1;
-+ lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
-+
-+ he_writel(he_dev, lbufd_index, RLBF1_H);
-+
-+ for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i)
-+ {
-+ lbufd_index += 2;
-+ lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
-+
-+ he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
-+ he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
-+
-+ if (++lbuf_count == lbufs_per_row)
-+ {
-+ lbuf_count = 0;
-+ row_offset += he_dev->bytes_per_row;
-+ }
-+ lbm_offset += 4;
-+ }
-+
-+ he_writel(he_dev, lbufd_index - 2, RLBF1_T);
-+ he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
-+}
-+
-+static void __init
-+he_init_tx_lbfp(struct he_dev *he_dev)
-+{
-+ unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
-+ unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
-+ unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row;
-+
-+ lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs;
-+ lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
-+
-+ he_writel(he_dev, lbufd_index, TLBF_H);
-+
-+ for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i)
-+ {
-+ lbufd_index += 1;
-+ lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
-+
-+ he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
-+ he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
-+
-+ if (++lbuf_count == lbufs_per_row)
-+ {
-+ lbuf_count = 0;
-+ row_offset += he_dev->bytes_per_row;
-+ }
-+ lbm_offset += 2;
-+ }
-+
-+ he_writel(he_dev, lbufd_index - 1, TLBF_T);
-+}
-+
-+static int __init
-+he_init_tpdrq(struct he_dev *he_dev)
-+{
-+ he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
-+ CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys);
-+ if (he_dev->tpdrq_base == NULL)
-+ {
-+ hprintk1("failed to alloc tpdrq\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->tpdrq_base, 0,
-+ CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq));
-+
-+ he_dev->tpdrq_tail = he_dev->tpdrq_base;
-+ he_dev->tpdrq_head = he_dev->tpdrq_base;
-+
-+ he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H);
-+ he_writel(he_dev, 0, TPDRQ_T);
-+ he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S);
-+
-+ return 0;
-+}
-+
-+static void __init
-+he_init_cs_block(struct he_dev *he_dev)
-+{
-+ unsigned clock, rate, delta;
-+ int reg;
-+
-+ /* 5.1.7 cs block initialization */
-+
-+ for(reg = 0; reg < 0x20; ++reg)
-+ he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg);
-+
-+ /* rate grid timer reload values */
-+
-+ clock = he_is622(he_dev) ? 66667000 : 50000000;
-+ rate = he_dev->atm_dev->link_rate;
-+ delta = rate / 16 / 2;
-+
-+ for(reg = 0; reg < 0x10; ++reg)
-+ {
-+ /* 2.4 internal transmit function
-+ *
-+ * we initialize the first row in the rate grid.
-+ * values are period (in clock cycles) of timer
-+ */
-+ unsigned period = clock / rate;
-+
-+ he_writel_mbox(he_dev, period, CS_TGRLD0 + reg);
-+ rate -= delta;
-+ }
-+
-+ if (he_is622(he_dev))
-+ {
-+ /* table 5.2 (4 cells per lbuf) */
-+ he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0);
-+ he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1);
-+ he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2);
-+ he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3);
-+ he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4);
-+
-+ /* table 5.3, 5.4, 5.5, 5.6, 5.7 */
-+ he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0);
-+ he_writel_mbox(he_dev, 0x1801, CS_ERCTL1);
-+ he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2);
-+ he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
-+ he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1);
-+ he_writel_mbox(he_dev, 0x14585, CS_RTFWR);
-+
-+ he_writel_mbox(he_dev, 0x4680, CS_RTATR);
-+
-+ /* table 5.8 */
-+ he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET);
-+ he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX);
-+ he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN);
-+ he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC);
-+ he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC);
-+ he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL);
-+
-+ /* table 5.9 */
-+ he_writel_mbox(he_dev, 0x5, CS_OTPPER);
-+ he_writel_mbox(he_dev, 0x14, CS_OTWPER);
-+ }
-+ else
-+ {
-+ /* table 5.1 (4 cells per lbuf) */
-+ he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0);
-+ he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1);
-+ he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2);
-+ he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3);
-+ he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4);
-+
-+ /* table 5.3, 5.4, 5.5, 5.6, 5.7 */
-+ he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0);
-+ he_writel_mbox(he_dev, 0x4701, CS_ERCTL1);
-+ he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2);
-+ he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
-+ he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1);
-+ he_writel_mbox(he_dev, 0xf424, CS_RTFWR);
-+
-+ he_writel_mbox(he_dev, 0x4680, CS_RTATR);
-+
-+ /* table 5.8 */
-+ he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET);
-+ he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX);
-+ he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN);
-+ he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC);
-+ he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC);
-+ he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL);
-+
-+ /* table 5.9 */
-+ he_writel_mbox(he_dev, 0x6, CS_OTPPER);
-+ he_writel_mbox(he_dev, 0x1e, CS_OTWPER);
-+
-+ }
-+
-+ he_writel_mbox(he_dev, 0x8, CS_OTTLIM);
-+
-+ for(reg = 0; reg < 0x8; ++reg)
-+ he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg);
-+
-+}
-+
-+static void __init
-+he_init_cs_block_rcm(struct he_dev *he_dev)
-+{
-+ unsigned rategrid[16][16];
-+ unsigned rate, delta;
-+ int i, j, reg;
-+
-+ unsigned rate_atmf, exp, man;
-+ unsigned long long rate_cps;
-+ int mult, buf, buf_limit = 4;
-+
-+ /* initialize rate grid group table */
-+
-+ for (reg = 0x0; reg < 0xff; ++reg)
-+ he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
-+
-+ /* initialize rate controller groups */
-+
-+ for (reg = 0x100; reg < 0x1ff; ++reg)
-+ he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
-+
-+ /* initialize tNrm lookup table */
-+
-+ /* the manual makes reference to a routine in a sample driver
-+ for proper configuration; fortunately, we only need this
-+ in order to support abr connection */
-+
-+ /* initialize rate to group table */
-+
-+ rate = he_dev->atm_dev->link_rate;
-+ delta = rate / 32;
-+
-+ /*
-+ * 2.4 transmit internal functions
-+ *
-+ * we construct a copy of the rate grid used by the scheduler
-+ * in order to construct the rate to group table below
-+ */
-+
-+ for (j = 0; j < 16; j++)
-+ {
-+ rategrid[0][j] = rate;
-+ rate -= delta;
-+ }
-+
-+ for (i = 1; i < 16; i++)
-+ for (j = 0; j < 16; j++)
-+ if (i > 14)
-+ rategrid[i][j] = rategrid[i - 1][j] / 4;
-+ else
-+ rategrid[i][j] = rategrid[i - 1][j] / 2;
-+
-+ /*
-+ * 2.4 transmit internal function
-+ *
-+ * this table maps the upper 5 bits of exponent and mantissa
-+ * of the atm forum representation of the rate into an index
-+ * on rate grid
-+ */
-+
-+ rate_atmf = 0;
-+ while (rate_atmf < 0x400)
-+ {
-+ man = (rate_atmf & 0x1f) << 4;
-+ exp = rate_atmf >> 5;
-+
-+ /*
-+ instead of '/ 512', use '>> 9' to prevent a call
-+ to divdu3 on x86 platforms
-+ */
-+ rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9;
-+
-+ if (rate_cps < 10) rate_cps = 10;
-+ /* 2.2.1 minimum payload rate is 10 cps */
-+
-+ for (i = 255; i > 0; i--)
-+ if (rategrid[i/16][i%16] >= rate_cps) break;
-+ /* pick nearest rate instead? */
-+
-+ /*
-+ * each table entry is 16 bits: (rate grid index (8 bits)
-+ * and a buffer limit (8 bits)
-+ * there are two table entries in each 32-bit register
-+ */
-+
-+#ifdef notdef
-+ buf = rate_cps * he_dev->tx_numbuffs /
-+ (he_dev->atm_dev->link_rate * 2);
-+#else
-+ /* this is pretty, but avoids _divdu3 and is mostly correct */
-+ buf = 0;
-+ mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR;
-+ if (rate_cps > (68 * mult)) buf = 1;
-+ if (rate_cps > (136 * mult)) buf = 2;
-+ if (rate_cps > (204 * mult)) buf = 3;
-+ if (rate_cps > (272 * mult)) buf = 4;
-+#endif
-+ if (buf > buf_limit) buf = buf_limit;
-+ reg = (reg<<16) | ((i<<8) | buf);
-+
-+#define RTGTBL_OFFSET 0x400
-+
-+ if (rate_atmf & 0x1)
-+ he_writel_rcm(he_dev, reg,
-+ CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf>>1));
-+
-+ ++rate_atmf;
-+ }
-+}
-+
-+
-+static int __init
-+he_init_group(struct he_dev *he_dev, int group)
-+{
-+ int i;
-+
-+#ifdef USE_RBPS
-+ /* small buffer pool */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
-+ he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
-+ CONFIG_RBPS_BUFSIZE, 8, 0, SLAB_KERNEL);
-+#else
-+ he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
-+ CONFIG_RBPS_BUFSIZE, 8, 0);
-+#endif
-+ if (he_dev->rbps_pool == NULL)
-+ {
-+ hprintk1("unable to create rbpl pool\n");
-+ return -ENOMEM;
-+ }
-+
-+ he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
-+ CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
-+ if (he_dev->rbps_base == NULL)
-+ {
-+ hprintk1("failed to alloc rbps\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
-+ he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
-+
-+ for (i = 0; i < CONFIG_RBPS_SIZE; ++i)
-+ {
-+ dma_addr_t dma_handle;
-+ void *cpuaddr;
-+
-+ cpuaddr = pci_pool_alloc(he_dev->rbps_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle);
-+ if (cpuaddr == NULL)
-+ return -ENOMEM;
-+
-+ he_dev->rbps_virt[i].virt = cpuaddr;
-+ he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
-+ he_dev->rbps_base[i].phys = dma_handle;
-+
-+ }
-+ he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE-1];
-+
-+ he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32));
-+ he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail),
-+ G0_RBPS_T + (group * 32));
-+ he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4,
-+ G0_RBPS_BS + (group * 32));
-+ he_writel(he_dev,
-+ RBP_THRESH(CONFIG_RBPS_THRESH) |
-+ RBP_QSIZE(CONFIG_RBPS_SIZE-1) |
-+ RBP_INT_ENB,
-+ G0_RBPS_QI + (group * 32));
-+#else /* !USE_RBPS */
-+ he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
-+ he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
-+ G0_RBPS_BS + (group * 32));
-+#endif /* USE_RBPS */
-+
-+ /* large buffer pool */
-+#ifdef USE_RBPL_POOL
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
-+ he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
-+ CONFIG_RBPL_BUFSIZE, 8, 0, SLAB_KERNEL);
-+#else
-+ he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
-+ CONFIG_RBPL_BUFSIZE, 8, 0);
-+#endif
-+ if (he_dev->rbpl_pool == NULL)
-+ {
-+ hprintk1("unable to create rbpl pool\n");
-+ return -ENOMEM;
-+ }
-+#endif
-+
-+ he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
-+ CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys);
-+ if (he_dev->rbpl_base == NULL)
-+ {
-+ hprintk1("failed to alloc rbpl\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
-+ he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
-+
-+ for (i = 0; i < CONFIG_RBPL_SIZE; ++i)
-+ {
-+ dma_addr_t dma_handle;
-+ void *cpuaddr;
-+
-+#ifdef USE_RBPL_POOL
-+ cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle);
-+#else
-+ cpuaddr = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPL_BUFSIZE, &dma_handle);
-+#endif
-+ if (cpuaddr == NULL)
-+ return -ENOMEM;
-+
-+ he_dev->rbpl_virt[i].virt = cpuaddr;
-+ he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
-+ he_dev->rbpl_base[i].phys = dma_handle;
-+
-+ }
-+ he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE-1];
-+
-+ he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32));
-+ he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail),
-+ G0_RBPL_T + (group * 32));
-+ he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4,
-+ G0_RBPL_BS + (group * 32));
-+ he_writel(he_dev,
-+ RBP_THRESH(CONFIG_RBPL_THRESH) |
-+ RBP_QSIZE(CONFIG_RBPL_SIZE-1) |
-+ RBP_INT_ENB,
-+ G0_RBPL_QI + (group * 32));
-+
-+ /* rx buffer ready queue */
-+
-+ he_dev->rbrq_base = pci_alloc_consistent(he_dev->pci_dev,
-+ CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
-+ if (he_dev->rbrq_base == NULL)
-+ {
-+ hprintk1("failed to allocate rbrq\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
-+
-+ he_dev->rbrq_head = he_dev->rbrq_base;
-+ he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16));
-+ he_writel(he_dev, 0, G0_RBRQ_H + (group * 16));
-+ he_writel(he_dev,
-+ RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1),
-+ G0_RBRQ_Q + (group * 16));
-+ if (irq_coalesce)
-+ {
-+ hprintk1("coalescing interrupts\n");
-+ he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7),
-+ G0_RBRQ_I + (group * 16));
-+ }
-+ else
-+ he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1),
-+ G0_RBRQ_I + (group * 16));
-+
-+ /* tx buffer ready queue */
-+
-+ he_dev->tbrq_base = pci_alloc_consistent(he_dev->pci_dev,
-+ CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys);
-+ if (he_dev->tbrq_base == NULL)
-+ {
-+ hprintk1("failed to allocate tbrq\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq));
-+
-+ he_dev->tbrq_head = he_dev->tbrq_base;
-+
-+ he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16));
-+ he_writel(he_dev, 0, G0_TBRQ_H + (group * 16));
-+ he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16));
-+ he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16));
-+
-+ return 0;
-+}
-+
-+static int __init
-+he_init_irq(struct he_dev *he_dev)
-+{
-+ int i;
-+
-+ /* 2.9.3.5 tail offset for each interrupt queue is located after the
-+ end of the interrupt queue */
-+
-+ he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev,
-+ (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys);
-+ if (he_dev->irq_base == NULL)
-+ {
-+ hprintk1("failed to allocate irq\n");
-+ return -ENOMEM;
-+ }
-+ he_dev->irq_tailoffset = (unsigned *)
-+ &he_dev->irq_base[CONFIG_IRQ_SIZE];
-+ *he_dev->irq_tailoffset = 0;
-+ he_dev->irq_head = he_dev->irq_base;
-+ he_dev->irq_tail = he_dev->irq_base;
-+
-+ for(i=0; i < CONFIG_IRQ_SIZE; ++i)
-+ he_dev->irq_base[i].isw = ITYPE_INVALID;
-+
-+ he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE);
-+ he_writel(he_dev,
-+ IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH),
-+ IRQ0_HEAD);
-+ he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL);
-+ he_writel(he_dev, 0x0, IRQ0_DATA);
-+
-+ he_writel(he_dev, 0x0, IRQ1_BASE);
-+ he_writel(he_dev, 0x0, IRQ1_HEAD);
-+ he_writel(he_dev, 0x0, IRQ1_CNTL);
-+ he_writel(he_dev, 0x0, IRQ1_DATA);
-+
-+ he_writel(he_dev, 0x0, IRQ2_BASE);
-+ he_writel(he_dev, 0x0, IRQ2_HEAD);
-+ he_writel(he_dev, 0x0, IRQ2_CNTL);
-+ he_writel(he_dev, 0x0, IRQ2_DATA);
-+
-+ he_writel(he_dev, 0x0, IRQ3_BASE);
-+ he_writel(he_dev, 0x0, IRQ3_HEAD);
-+ he_writel(he_dev, 0x0, IRQ3_CNTL);
-+ he_writel(he_dev, 0x0, IRQ3_DATA);
-+
-+ /* 2.9.3.2 interrupt queue mapping registers */
-+
-+ he_writel(he_dev, 0x0, GRP_10_MAP);
-+ he_writel(he_dev, 0x0, GRP_32_MAP);
-+ he_writel(he_dev, 0x0, GRP_54_MAP);
-+ he_writel(he_dev, 0x0, GRP_76_MAP);
-+
-+ if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev))
-+ {
-+ hprintk("irq %d already in use\n", he_dev->pci_dev->irq);
-+ return -EINVAL;
-+ }
-+
-+ he_dev->irq = he_dev->pci_dev->irq;
-+
-+#ifdef BUS_INT_WAR
-+ HPRINTK("sn_add_polled_interrupt(irq %d, 1)\n", he_dev->irq);
-+ sn_add_polled_interrupt(he_dev->irq, 1);
-+#endif
-+
-+ return 0;
-+}
-+
-+static int __init
-+he_start(struct atm_dev *dev)
-+{
-+ struct he_dev *he_dev;
-+ struct pci_dev *pci_dev;
-+
-+ u16 command;
-+ u32 gen_cntl_0, host_cntl, lb_swap;
-+ u8 cache_size, timer;
-+
-+ unsigned err;
-+ unsigned int status, reg;
-+ int i, group;
-+
-+ he_dev = HE_DEV(dev);
-+ pci_dev = he_dev->pci_dev;
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,3)
-+ he_dev->membase = pci_dev->resource[0].start;
-+#else
-+ he_dev->membase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
-+#endif
-+ HPRINTK("membase = 0x%x irq = %d.\n", he_dev->membase, pci_dev->irq);
-+
-+ /*
-+ * pci bus controller initialization
-+ */
-+
-+ /* 4.3 pci bus controller-specific initialization */
-+ if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0)
-+ {
-+ hprintk1("can't read GEN_CNTL_0\n");
-+ return -EINVAL;
-+ }
-+ gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT);
-+ if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0)
-+ {
-+ hprintk1("can't write GEN_CNTL_0.\n");
-+ return -EINVAL;
-+ }
-+
-+ if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0)
-+ {
-+ hprintk1("can't read PCI_COMMAND.\n");
-+ return -EINVAL;
-+ }
-+
-+ command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
-+ if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0)
-+ {
-+ hprintk1("can't enable memory.\n");
-+ return -EINVAL;
-+ }
-+
-+ if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size))
-+ {
-+ hprintk1("can't read cache line size?\n");
-+ return -EINVAL;
-+ }
-+
-+ if (cache_size < 16)
-+ {
-+ cache_size = 16;
-+ if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size))
-+ hprintk("can't set cache line size to %d\n", cache_size);
-+ }
-+
-+ if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer))
-+ {
-+ hprintk1("can't read latency timer?\n");
-+ return -EINVAL;
-+ }
-+
-+ /* from table 3.9
-+ *
-+ * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE
-+ *
-+ * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles]
-+ * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles]
-+ *
-+ */
-+#define LAT_TIMER 209
-+ if (timer < LAT_TIMER)
-+ {
-+ HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER);
-+ timer = LAT_TIMER;
-+ if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer))
-+ hprintk("can't set latency timer to %d\n", timer);
-+ }
-+
-+ if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) {
-+ hprintk1("can't set up page mapping\n");
-+ return -EINVAL;
-+ }
-+
-+ /* 4.4 card reset */
-+ he_writel(he_dev, 0x0, RESET_CNTL);
-+ he_writel(he_dev, 0xff, RESET_CNTL);
-+
-+ udelay(16*1000); /* 16 ms */
-+ status = he_readl(he_dev, RESET_CNTL);
-+ if ((status & BOARD_RST_STATUS) == 0)
-+ {
-+ hprintk1("reset failed\n");
-+ return -EINVAL;
-+ }
-+
-+ /* 4.5 set bus width */
-+ host_cntl = he_readl(he_dev, HOST_CNTL);
-+ if (host_cntl & PCI_BUS_SIZE64)
-+ gen_cntl_0 |= ENBL_64;
-+ else
-+ gen_cntl_0 &= ~ENBL_64;
-+
-+ if (disable64 == 1)
-+ {
-+ hprintk1("disabling 64-bit pci bus transfers\n");
-+ gen_cntl_0 &= ~ENBL_64;
-+ }
-+
-+ if (gen_cntl_0 & ENBL_64) hprintk1("64-bit transfers enabled\n");
-+
-+ pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
-+
-+ /* 4.7 read prom contents */
-+ for(i=0; i<PROD_ID_LEN; ++i)
-+ he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i);
-+
-+ he_dev->media = read_prom_byte(he_dev, MEDIA);
-+
-+ for(i=0; i<6; ++i)
-+ dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i);
-+
-+ hprintk("%s%s, %x:%x:%x:%x:%x:%x\n",
-+ he_dev->prod_id,
-+ he_dev->media & 0x40 ? "SM" : "MM",
-+ dev->esi[0],
-+ dev->esi[1],
-+ dev->esi[2],
-+ dev->esi[3],
-+ dev->esi[4],
-+ dev->esi[5]);
-+ he_dev->atm_dev->link_rate = he_is622(he_dev) ?
-+ ATM_OC12_PCR : ATM_OC3_PCR;
-+
-+ /* 4.6 set host endianess */
-+ lb_swap = he_readl(he_dev, LB_SWAP);
-+ if (he_is622(he_dev))
-+ lb_swap &= ~XFER_SIZE; /* 4 cells */
-+ else
-+ lb_swap |= XFER_SIZE; /* 8 cells */
-+#ifdef __BIG_ENDIAN
-+ lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST;
-+#else
-+ lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST |
-+ DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP);
-+#endif /* __BIG_ENDIAN */
-+ he_writel(he_dev, lb_swap, LB_SWAP);
-+
-+ /* 4.8 sdram controller initialization */
-+ he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL);
-+
-+ /* 4.9 initialize rnum value */
-+ lb_swap |= SWAP_RNUM_MAX(0xf);
-+ he_writel(he_dev, lb_swap, LB_SWAP);
-+
-+ /* 4.10 initialize the interrupt queues */
-+ if ((err = he_init_irq(he_dev)) != 0) return err;
-+
-+#ifdef USE_TASKLET
-+ tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev);
-+#endif
-+ spin_lock_init(&he_dev->global_lock);
-+ spin_lock_init(&he_dev->tpdrq_lock);
-+
-+ /* 4.11 enable pci bus controller state machines */
-+ host_cntl |= (OUTFF_ENB | CMDFF_ENB |
-+ QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB);
-+ he_writel(he_dev, host_cntl, HOST_CNTL);
-+
-+ gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB;
-+ pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
-+
-+ /*
-+ * atm network controller initialization
-+ */
-+
-+ /* 5.1.1 generic configuration state */
-+
-+ /*
-+ * local (cell) buffer memory map
-+ *
-+ * HE155 HE622
-+ *
-+ * 0 ____________1023 bytes 0 _______________________2047 bytes
-+ * | | | | |
-+ * | utility | | rx0 | |
-+ * 5|____________| 255|___________________| u |
-+ * 6| | 256| | t |
-+ * | | | | i |
-+ * | rx0 | row | tx | l |
-+ * | | | | i |
-+ * | | 767|___________________| t |
-+ * 517|____________| 768| | y |
-+ * row 518| | | rx1 | |
-+ * | | 1023|___________________|___|
-+ * | |
-+ * | tx |
-+ * | |
-+ * | |
-+ * 1535|____________|
-+ * 1536| |
-+ * | rx1 |
-+ * 2047|____________|
-+ *
-+ */
-+
-+ /* total 4096 connections */
-+ he_dev->vcibits = CONFIG_DEFAULT_VCIBITS;
-+ he_dev->vpibits = CONFIG_DEFAULT_VPIBITS;
-+
-+ if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS)
-+ {
-+ hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS);
-+ return -ENODEV;
-+ }
-+
-+ if (nvpibits != -1)
-+ {
-+ he_dev->vpibits = nvpibits;
-+ he_dev->vcibits = HE_MAXCIDBITS - nvpibits;
-+ }
-+
-+ if (nvcibits != -1)
-+ {
-+ he_dev->vcibits = nvcibits;
-+ he_dev->vpibits = HE_MAXCIDBITS - nvcibits;
-+ }
-+
-+
-+ if (he_is622(he_dev))
-+ {
-+ he_dev->cells_per_row = 40;
-+ he_dev->bytes_per_row = 2048;
-+ he_dev->r0_numrows = 256;
-+ he_dev->tx_numrows = 512;
-+ he_dev->r1_numrows = 256;
-+ he_dev->r0_startrow = 0;
-+ he_dev->tx_startrow = 256;
-+ he_dev->r1_startrow = 768;
-+ }
-+ else
-+ {
-+ he_dev->cells_per_row = 20;
-+ he_dev->bytes_per_row = 1024;
-+ he_dev->r0_numrows = 512;
-+ he_dev->tx_numrows = 1018;
-+ he_dev->r1_numrows = 512;
-+ he_dev->r0_startrow = 6;
-+ he_dev->tx_startrow = 518;
-+ he_dev->r1_startrow = 1536;
-+ }
-+
-+ he_dev->cells_per_lbuf = 4;
-+ he_dev->buffer_limit = 4;
-+ he_dev->r0_numbuffs = he_dev->r0_numrows *
-+ he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ if (he_dev->r0_numbuffs > 2560) he_dev->r0_numbuffs = 2560;
-+
-+ he_dev->r1_numbuffs = he_dev->r1_numrows *
-+ he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ if (he_dev->r1_numbuffs > 2560) he_dev->r1_numbuffs = 2560;
-+
-+ he_dev->tx_numbuffs = he_dev->tx_numrows *
-+ he_dev->cells_per_row / he_dev->cells_per_lbuf;
-+ if (he_dev->tx_numbuffs > 5120) he_dev->tx_numbuffs = 5120;
-+
-+ /* 5.1.2 configure hardware dependent registers */
-+
-+ he_writel(he_dev,
-+ SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) |
-+ RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) |
-+ (he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) |
-+ (he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)),
-+ LBARB);
-+
-+ he_writel(he_dev, BANK_ON |
-+ (he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)),
-+ SDRAMCON);
-+
-+ he_writel(he_dev,
-+ (he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) |
-+ RM_RW_WAIT(1), RCMCONFIG);
-+ he_writel(he_dev,
-+ (he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) |
-+ TM_RW_WAIT(1), TCMCONFIG);
-+
-+ he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG);
-+
-+ he_writel(he_dev,
-+ (he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) |
-+ (he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) |
-+ RX_VALVP(he_dev->vpibits) |
-+ RX_VALVC(he_dev->vcibits), RC_CONFIG);
-+
-+ he_writel(he_dev, DRF_THRESH(0x20) |
-+ (he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) |
-+ TX_VCI_MASK(he_dev->vcibits) |
-+ LBFREE_CNT(he_dev->tx_numbuffs), TX_CONFIG);
-+
-+ he_writel(he_dev, 0x0, TXAAL5_PROTO);
-+
-+ he_writel(he_dev, PHY_INT_ENB |
-+ (he_is622(he_dev) ? PTMR_PRE(67-1) : PTMR_PRE(50-1)),
-+ RH_CONFIG);
-+
-+ /* 5.1.3 initialize connection memory */
-+
-+ for(i=0; i < TCM_MEM_SIZE; ++i)
-+ he_writel_tcm(he_dev, 0, i);
-+
-+ for(i=0; i < RCM_MEM_SIZE; ++i)
-+ he_writel_rcm(he_dev, 0, i);
-+
-+ /*
-+ * transmit connection memory map
-+ *
-+ * tx memory
-+ * 0x0 ___________________
-+ * | |
-+ * | |
-+ * | TSRa |
-+ * | |
-+ * | |
-+ * 0x8000|___________________|
-+ * | |
-+ * | TSRb |
-+ * 0xc000|___________________|
-+ * | |
-+ * | TSRc |
-+ * 0xe000|___________________|
-+ * | TSRd |
-+ * 0xf000|___________________|
-+ * | tmABR |
-+ * 0x10000|___________________|
-+ * | |
-+ * | tmTPD |
-+ * |___________________|
-+ * | |
-+ * ....
-+ * 0x1ffff|___________________|
-+ *
-+ *
-+ */
-+
-+ he_writel(he_dev, CONFIG_TSRB, TSRB_BA);
-+ he_writel(he_dev, CONFIG_TSRC, TSRC_BA);
-+ he_writel(he_dev, CONFIG_TSRD, TSRD_BA);
-+ he_writel(he_dev, CONFIG_TMABR, TMABR_BA);
-+ he_writel(he_dev, CONFIG_TPDBA, TPD_BA);
-+
-+
-+ /*
-+ * receive connection memory map
-+ *
-+ * 0x0 ___________________
-+ * | |
-+ * | |
-+ * | RSRa |
-+ * | |
-+ * | |
-+ * 0x8000|___________________|
-+ * | |
-+ * | rx0/1 |
-+ * | LBM | link lists of local
-+ * | tx | buffer memory
-+ * | |
-+ * 0xd000|___________________|
-+ * | |
-+ * | rmABR |
-+ * 0xe000|___________________|
-+ * | |
-+ * | RSRb |
-+ * |___________________|
-+ * | |
-+ * ....
-+ * 0xffff|___________________|
-+ */
-+
-+ he_writel(he_dev, 0x08000, RCMLBM_BA);
-+ he_writel(he_dev, 0x0e000, RCMRSRB_BA);
-+ he_writel(he_dev, 0x0d800, RCMABR_BA);
-+
-+ /* 5.1.4 initialize local buffer free pools linked lists */
-+
-+ he_init_rx_lbfp0(he_dev);
-+ he_init_rx_lbfp1(he_dev);
-+
-+ he_writel(he_dev, 0x0, RLBC_H);
-+ he_writel(he_dev, 0x0, RLBC_T);
-+ he_writel(he_dev, 0x0, RLBC_H2);
-+
-+ he_writel(he_dev, 512, RXTHRSH); /* 10% of r0+r1 buffers */
-+ he_writel(he_dev, 256, LITHRSH); /* 5% of r0+r1 buffers */
-+
-+ he_init_tx_lbfp(he_dev);
-+
-+ he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA);
-+
-+ /* 5.1.5 initialize intermediate receive queues */
-+
-+ if (he_is622(he_dev))
-+ {
-+ he_writel(he_dev, 0x000f, G0_INMQ_S);
-+ he_writel(he_dev, 0x200f, G0_INMQ_L);
-+
-+ he_writel(he_dev, 0x001f, G1_INMQ_S);
-+ he_writel(he_dev, 0x201f, G1_INMQ_L);
-+
-+ he_writel(he_dev, 0x002f, G2_INMQ_S);
-+ he_writel(he_dev, 0x202f, G2_INMQ_L);
-+
-+ he_writel(he_dev, 0x003f, G3_INMQ_S);
-+ he_writel(he_dev, 0x203f, G3_INMQ_L);
-+
-+ he_writel(he_dev, 0x004f, G4_INMQ_S);
-+ he_writel(he_dev, 0x204f, G4_INMQ_L);
-+
-+ he_writel(he_dev, 0x005f, G5_INMQ_S);
-+ he_writel(he_dev, 0x205f, G5_INMQ_L);
-+
-+ he_writel(he_dev, 0x006f, G6_INMQ_S);
-+ he_writel(he_dev, 0x206f, G6_INMQ_L);
-+
-+ he_writel(he_dev, 0x007f, G7_INMQ_S);
-+ he_writel(he_dev, 0x207f, G7_INMQ_L);
-+ }
-+ else
-+ {
-+ he_writel(he_dev, 0x0000, G0_INMQ_S);
-+ he_writel(he_dev, 0x0008, G0_INMQ_L);
-+
-+ he_writel(he_dev, 0x0001, G1_INMQ_S);
-+ he_writel(he_dev, 0x0009, G1_INMQ_L);
-+
-+ he_writel(he_dev, 0x0002, G2_INMQ_S);
-+ he_writel(he_dev, 0x000a, G2_INMQ_L);
-+
-+ he_writel(he_dev, 0x0003, G3_INMQ_S);
-+ he_writel(he_dev, 0x000b, G3_INMQ_L);
-+
-+ he_writel(he_dev, 0x0004, G4_INMQ_S);
-+ he_writel(he_dev, 0x000c, G4_INMQ_L);
-+
-+ he_writel(he_dev, 0x0005, G5_INMQ_S);
-+ he_writel(he_dev, 0x000d, G5_INMQ_L);
-+
-+ he_writel(he_dev, 0x0006, G6_INMQ_S);
-+ he_writel(he_dev, 0x000e, G6_INMQ_L);
-+
-+ he_writel(he_dev, 0x0007, G7_INMQ_S);
-+ he_writel(he_dev, 0x000f, G7_INMQ_L);
-+ }
-+
-+ /* 5.1.6 application tunable parameters */
-+
-+ he_writel(he_dev, 0x0, MCC);
-+ he_writel(he_dev, 0x0, OEC);
-+ he_writel(he_dev, 0x0, DCC);
-+ he_writel(he_dev, 0x0, CEC);
-+
-+ /* 5.1.7 cs block initialization */
-+
-+ he_init_cs_block(he_dev);
-+
-+ /* 5.1.8 cs block connection memory initialization */
-+
-+ he_init_cs_block_rcm(he_dev);
-+
-+ /* 5.1.10 initialize host structures */
-+
-+ he_init_tpdrq(he_dev);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
-+ he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev,
-+ sizeof(struct he_tpd), TPD_ALIGNMENT, 0, SLAB_KERNEL);
-+#else
-+ he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev,
-+ sizeof(struct he_tpd), TPD_ALIGNMENT, 0);
-+#endif
-+ if (he_dev->tpd_pool == NULL)
-+ {
-+ hprintk1("unable to create tpd pci_pool\n");
-+ return -ENOMEM;
-+ }
-+ INIT_LIST_HEAD(&he_dev->outstanding_tpds);
-+
-+ if (he_init_group(he_dev, 0) != 0)
-+ return -ENOMEM;
-+
-+ for (group = 1; group < HE_NUM_GROUPS; ++group)
-+ {
-+ he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
-+ he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
-+ G0_RBPS_BS + (group * 32));
-+
-+ he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32));
-+ he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
-+ G0_RBPL_QI + (group * 32));
-+ he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32));
-+
-+ he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16));
-+ he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16));
-+ he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0),
-+ G0_RBRQ_Q + (group * 16));
-+ he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16));
-+
-+ he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16));
-+ he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16));
-+ he_writel(he_dev, TBRQ_THRESH(0x1),
-+ G0_TBRQ_THRESH + (group * 16));
-+ he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16));
-+ }
-+
-+ /* host status page */
-+
-+ he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev,
-+ sizeof(struct he_hsp), &he_dev->hsp_phys);
-+ if (he_dev->hsp == NULL)
-+ {
-+ hprintk1("failed to allocate host status page\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->hsp, 0, sizeof(struct he_hsp));
-+ he_writel(he_dev, he_dev->hsp_phys, HSP_BA);
-+
-+ /* initialize framer */
-+
-+#ifdef CONFIG_ATM_HE_USE_SUNI
-+ suni_init(he_dev->atm_dev);
-+ if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start)
-+ he_dev->atm_dev->phy->start(he_dev->atm_dev);
-+#endif /* CONFIG_ATM_HE_USE_SUNI */
-+
-+ if (sdh)
-+ {
-+ /* this really should be in suni.c but for now... */
-+
-+ int val;
-+
-+ val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM);
-+ val = (val & ~SUNI_TPOP_APM_S) | ( 0x2 << SUNI_TPOP_APM_S_SHIFT);
-+ he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM);
-+ }
-+
-+ /* 5.1.12 enable transmit and receive */
-+
-+ reg = he_readl_mbox(he_dev, CS_ERCTL0);
-+ reg |= TX_ENABLE|ER_ENABLE;
-+ he_writel_mbox(he_dev, reg, CS_ERCTL0);
-+
-+ reg = he_readl(he_dev, RC_CONFIG);
-+ reg |= RX_ENABLE;
-+ he_writel(he_dev, reg, RC_CONFIG);
-+
-+#ifndef USE_HE_FIND_VCC
-+ he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) *
-+ (1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
-+ if (he_dev->he_vcc_table == NULL)
-+ {
-+ hprintk1("failed to alloc he_vcc_table\n");
-+ return -ENOMEM;
-+ }
-+ memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
-+ (1 << (he_dev->vcibits + he_dev->vpibits)));
-+#endif
-+
-+ for (i = 0; i < HE_NUM_CS_STPER; ++i)
-+ {
-+ he_dev->cs_stper[i].inuse = 0;
-+ he_dev->cs_stper[i].pcr = -1;
-+ }
-+ he_dev->total_bw = 0;
-+
-+
-+ /* atm linux initialization */
-+
-+ he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits;
-+ he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits;
-+
-+ he_dev->irq_peak = 0;
-+ he_dev->rbrq_peak = 0;
-+ he_dev->rbpl_peak = 0;
-+ he_dev->tbrq_peak = 0;
-+
-+ hprintk1("hell bent for leather!\n");
-+
-+ return 0;
-+}
-+
-+static void
-+he_stop(struct he_dev *he_dev)
-+{
-+ u16 command;
-+ u32 gen_cntl_0, reg;
-+ struct pci_dev *pci_dev;
-+ int i;
-+
-+ pci_dev = he_dev->pci_dev;
-+
-+ /* disable interrupts */
-+
-+ if (he_dev->membase)
-+ {
-+ pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0);
-+ gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB);
-+ pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
-+
-+#ifdef USE_TASKLET
-+ tasklet_disable(&he_dev->tasklet);
-+#endif
-+
-+ /* disable recv and transmit */
-+
-+ reg = he_readl_mbox(he_dev, CS_ERCTL0);
-+ reg &= ~(TX_ENABLE|ER_ENABLE);
-+ he_writel_mbox(he_dev, reg, CS_ERCTL0);
-+
-+ reg = he_readl(he_dev, RC_CONFIG);
-+ reg &= ~(RX_ENABLE);
-+ he_writel(he_dev, reg, RC_CONFIG);
-+ }
-+
-+#ifdef CONFIG_ATM_HE_USE_SUNI
-+ if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop)
-+ he_dev->atm_dev->phy->stop(he_dev->atm_dev);
-+#endif /* CONFIG_ATM_HE_USE_SUNI */
-+
-+ if (he_dev->irq)
-+ {
-+#ifdef BUS_INT_WAR
-+ sn_delete_polled_interrupt(he_dev->irq);
-+#endif
-+ free_irq(he_dev->irq, he_dev);
-+ }
-+
-+ if (he_dev->irq_base)
-+ pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1)
-+ * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys);
-+
-+ if (he_dev->hsp)
-+ pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp),
-+ he_dev->hsp, he_dev->hsp_phys);
-+
-+ if (he_dev->rbpl_base)
-+ {
-+ for (i=0; i<CONFIG_RBPL_SIZE; ++i)
-+ {
-+ void *cpuaddr = he_dev->rbpl_virt[i].virt;
-+ dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
-+
-+#ifdef USE_RBPL_POOL
-+ pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle);
-+#else
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_BUFSIZE, cpuaddr, dma_handle);
-+#endif
-+ }
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
-+ * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
-+ }
-+
-+#ifdef USE_RBPL_POOL
-+ if (he_dev->rbpl_pool)
-+ pci_pool_destroy(he_dev->rbpl_pool);
-+#endif
-+
-+#ifdef USE_RBPS
-+ if (he_dev->rbps_base)
-+ {
-+ for (i=0; i<CONFIG_RBPS_SIZE; ++i)
-+ {
-+ void *cpuaddr = he_dev->rbps_virt[i].virt;
-+ dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
-+
-+ pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle);
-+ }
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
-+ * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys);
-+ }
-+#endif /* USE_RBPS */
-+
-+ if (he_dev->rbrq_base)
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
-+ he_dev->rbrq_base, he_dev->rbrq_phys);
-+
-+ if (he_dev->tbrq_base)
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
-+ he_dev->tbrq_base, he_dev->tbrq_phys);
-+
-+ if (he_dev->tpdrq_base)
-+ pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
-+ he_dev->tpdrq_base, he_dev->tpdrq_phys);
-+
-+ if (he_dev->tpd_pool)
-+ pci_pool_destroy(he_dev->tpd_pool);
-+
-+#ifndef USE_HE_FIND_VCC
-+ if (he_dev->he_vcc_table)
-+ kfree(he_dev->he_vcc_table);
-+#endif
-+
-+ if (he_dev->pci_dev)
-+ {
-+ pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
-+ command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-+ pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command);
-+ }
-+
-+ if (he_dev->membase) iounmap((void *) he_dev->membase);
-+}
-+
-+static __inline__ struct he_tpd *
-+he_alloc_tpd(struct he_dev *he_dev)
-+{
-+ struct he_tpd *tpd;
-+ dma_addr_t dma_handle;
-+
-+ tpd = pci_pool_alloc(he_dev->tpd_pool, SLAB_ATOMIC|SLAB_DMA, &dma_handle);
-+ if (tpd == NULL)
-+ return NULL;
-+
-+ tpd->status = TPD_ADDR(dma_handle);
-+ tpd->reserved = 0;
-+ tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0;
-+ tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0;
-+ tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0;
-+
-+ return tpd;
-+}
-+
-+
-+#define AAL5_LEN(buf,len) \
-+ ((((unsigned char *)(buf))[(len)-6]<<8) | \
-+ (((unsigned char *)(buf))[(len)-5]))
-+
-+/* 2.10.1.2 receive
-+ *
-+ * aal5 packets can optionally return the tcp checksum in the lower
-+ * 16 bits of the crc (RSR0_TCP_CKSUM)
-+ */
-+
-+#define TCP_CKSUM(buf,len) \
-+ ((((unsigned char *)(buf))[(len)-2]<<8) | \
-+ (((unsigned char *)(buf))[(len-1)]))
-+
-+static int
-+he_service_rbrq(struct he_dev *he_dev, int group)
-+{
-+ struct he_rbrq *rbrq_tail = (struct he_rbrq *)
-+ ((unsigned long)he_dev->rbrq_base |
-+ he_dev->hsp->group[group].rbrq_tail);
-+ struct he_rbp *rbp = NULL;
-+ unsigned cid, lastcid = -1;
-+ unsigned buf_len = 0;
-+ struct sk_buff *skb;
-+ struct atm_vcc *vcc = NULL;
-+ struct he_vcc *he_vcc;
-+ struct iovec *iov;
-+ int pdus_assembled = 0;
-+ int updated = 0;
-+
-+ read_lock(&vcc_sklist_lock);
-+ while (he_dev->rbrq_head != rbrq_tail)
-+ {
-+ ++updated;
-+
-+ HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n",
-+ he_dev->rbrq_head, group,
-+ RBRQ_ADDR(he_dev->rbrq_head),
-+ RBRQ_BUFLEN(he_dev->rbrq_head),
-+ RBRQ_CID(he_dev->rbrq_head),
-+ RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "",
-+ RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "",
-+ RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "",
-+ RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "",
-+ RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "",
-+ RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : "");
-+
-+#ifdef USE_RBPS
-+ if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF)
-+ rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-+ else
-+#endif
-+ rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-+
-+ buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
-+ cid = RBRQ_CID(he_dev->rbrq_head);
-+
-+#ifdef USE_HE_FIND_VCC
-+ if (cid != lastcid)
-+ vcc = he_find_vcc(he_dev, cid);
-+ lastcid = cid;
-+#else
-+ vcc = HE_LOOKUP_VCC(he_dev, cid);
-+#endif
-+ if (vcc == NULL)
-+ {
-+ hprintk("vcc == NULL (cid 0x%x)\n", cid);
-+ if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
-+ rbp->status &= ~RBP_LOANED;
-+
-+ goto next_rbrq_entry;
-+ }
-+
-+ he_vcc = HE_VCC(vcc);
-+ if (he_vcc == NULL)
-+ {
-+ hprintk("he_vcc == NULL (cid 0x%x)\n", cid);
-+ if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
-+ rbp->status &= ~RBP_LOANED;
-+ goto next_rbrq_entry;
-+ }
-+
-+ if (RBRQ_HBUF_ERR(he_dev->rbrq_head))
-+ {
-+ hprintk("HBUF_ERR! (cid 0x%x)\n", cid);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->rx_drop;
-+#else
-+ atomic_inc(&vcc->stats->rx_drop);
-+#endif
-+ goto return_host_buffers;
-+ }
-+
-+ he_vcc->iov_tail->iov_base = (void *) RBRQ_ADDR(he_dev->rbrq_head);
-+ he_vcc->iov_tail->iov_len = buf_len;
-+ he_vcc->pdu_len += buf_len;
-+ ++he_vcc->iov_tail;
-+
-+ if (RBRQ_CON_CLOSED(he_dev->rbrq_head))
-+ {
-+ lastcid = -1;
-+ HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid);
-+ wake_up(&he_vcc->rx_waitq);
-+ goto return_host_buffers;
-+ }
-+
-+#ifdef notdef
-+ if (he_vcc->iov_tail - he_vcc->iov_head > 32)
-+ {
-+ hprintk("iovec full! cid 0x%x\n", cid);
-+ goto return_host_buffers;
-+ }
-+#endif
-+ if (!RBRQ_END_PDU(he_dev->rbrq_head)) goto next_rbrq_entry;
-+
-+ if (RBRQ_LEN_ERR(he_dev->rbrq_head)
-+ || RBRQ_CRC_ERR(he_dev->rbrq_head))
-+ {
-+ HPRINTK("%s%s (%d.%d)\n",
-+ RBRQ_CRC_ERR(he_dev->rbrq_head)
-+ ? "CRC_ERR " : "",
-+ RBRQ_LEN_ERR(he_dev->rbrq_head)
-+ ? "LEN_ERR" : "",
-+ vcc->vpi, vcc->vci);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->rx_err;
-+#else
-+ atomic_inc(&vcc->stats->rx_err);
-+#endif
-+ goto return_host_buffers;
-+ }
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,15)
-+ skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve,
-+ GFP_ATOMIC);
-+#else
-+ if (!atm_charge(vcc, atm_pdu2truesize(he_vcc->pdu_len + rx_skb_reserve)))
-+ skb = NULL;
-+ else
-+ {
-+ skb = alloc_skb(he_vcc->pdu_len + rx_skb_reserve, GFP_ATOMIC);
-+ if (!skb) atm_return(vcc,
-+ atm_pdu2truesize(he_vcc->pdu_len + rx_skb_reserve));
-+ }
-+#endif
-+ if (!skb)
-+ {
-+ HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci);
-+ goto return_host_buffers;
-+ }
-+
-+ if (rx_skb_reserve > 0) skb_reserve(skb, rx_skb_reserve);
-+
-+ do_gettimeofday(&skb->stamp);
-+
-+ for(iov = he_vcc->iov_head;
-+ iov < he_vcc->iov_tail; ++iov)
-+ {
-+#ifdef USE_RBPS
-+ if ((u32)iov->iov_base & RBP_SMALLBUF)
-+ memcpy(skb_put(skb, iov->iov_len),
-+ he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
-+ else
-+#endif
-+ memcpy(skb_put(skb, iov->iov_len),
-+ he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
-+ }
-+
-+ switch(vcc->qos.aal)
-+ {
-+ case ATM_AAL0:
-+ /* 2.10.1.5 raw cell receive */
-+ skb->len = ATM_AAL0_SDU;
-+ skb->tail = skb->data + skb->len;
-+ break;
-+ case ATM_AAL5:
-+ /* 2.10.1.2 aal5 receive */
-+
-+ skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len);
-+ skb->tail = skb->data + skb->len;
-+#ifdef USE_CHECKSUM_HW
-+ if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI)
-+ {
-+ skb->ip_summed = CHECKSUM_HW;
-+ skb->csum = TCP_CKSUM(skb->data,
-+ he_vcc->pdu_len);
-+ }
-+#endif
-+ break;
-+ }
-+
-+#ifdef should_never_happen
-+ if (skb->len > vcc->qos.rxtp.max_sdu)
-+ hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)! cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid);
-+#endif
-+
-+#ifdef notdef
-+ ATM_SKB(skb)->vcc = vcc;
-+#endif
-+ vcc->push(vcc, skb);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->rx;
-+#else
-+ atomic_inc(&vcc->stats->rx);
-+#endif
-+
-+return_host_buffers:
-+ ++pdus_assembled;
-+
-+ for(iov = he_vcc->iov_head;
-+ iov < he_vcc->iov_tail; ++iov)
-+ {
-+#ifdef USE_RBPS
-+ if ((u32)iov->iov_base & RBP_SMALLBUF)
-+ rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)];
-+ else
-+#endif
-+ rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)];
-+
-+ rbp->status &= ~RBP_LOANED;
-+ }
-+
-+ he_vcc->iov_tail = he_vcc->iov_head;
-+ he_vcc->pdu_len = 0;
-+
-+next_rbrq_entry:
-+ he_dev->rbrq_head = (struct he_rbrq *)
-+ ((unsigned long) he_dev->rbrq_base |
-+ RBRQ_MASK(++he_dev->rbrq_head));
-+
-+ }
-+ read_unlock(&vcc_sklist_lock);
-+
-+ if (updated)
-+ {
-+ if (updated > he_dev->rbrq_peak) he_dev->rbrq_peak = updated;
-+
-+ he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head),
-+ G0_RBRQ_H + (group * 16));
-+ }
-+
-+ return pdus_assembled;
-+}
-+
-+static void
-+he_service_tbrq(struct he_dev *he_dev, int group)
-+{
-+ struct he_tbrq *tbrq_tail = (struct he_tbrq *)
-+ ((unsigned long)he_dev->tbrq_base |
-+ he_dev->hsp->group[group].tbrq_tail);
-+ struct he_tpd *tpd;
-+ int slot, updated = 0;
-+ struct list_head *list;
-+
-+ /* 2.1.6 transmit buffer return queue */
-+
-+ while (he_dev->tbrq_head != tbrq_tail)
-+ {
-+ ++updated;
-+
-+ HPRINTK("tbrq%d 0x%x%s%s\n",
-+ group,
-+ TBRQ_TPD(he_dev->tbrq_head),
-+ TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "",
-+ TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : "");
-+
-+ tpd = NULL;
-+ list = &he_dev->outstanding_tpds;
-+ while ((list = list->next) != &he_dev->outstanding_tpds)
-+ {
-+ struct he_tpd *_tpd = list_entry(list, struct he_tpd, entry);
-+ if (TPD_ADDR(_tpd->status) == TBRQ_TPD(he_dev->tbrq_head))
-+ {
-+ tpd = _tpd;
-+ list_del(&_tpd->entry);
-+ break;
-+ }
-+ }
-+
-+ if (tpd == NULL)
-+ {
-+ hprintk("unable to locate tpd for dma buffer %x\n",
-+ TBRQ_TPD(he_dev->tbrq_head));
-+ goto next_tbrq_entry;
-+ }
-+
-+ if (TBRQ_EOS(he_dev->tbrq_head))
-+ {
-+ HPRINTK("wake_up(tx_waitq) cid 0x%x\n",
-+ he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci));
-+ if (tpd->vcc)
-+ wake_up(&HE_VCC(tpd->vcc)->tx_waitq);
-+
-+ goto next_tbrq_entry;
-+ }
-+
-+ for(slot = 0; slot < TPD_MAXIOV; ++slot)
-+ {
-+ if (tpd->iovec[slot].addr)
-+ pci_unmap_single(he_dev->pci_dev,
-+ tpd->iovec[slot].addr,
-+ tpd->iovec[slot].len & TPD_LEN_MASK,
-+ PCI_DMA_TODEVICE);
-+ if (tpd->iovec[slot].len & TPD_LST) break;
-+
-+ }
-+
-+ if (tpd->skb) /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */
-+ {
-+ if (tpd->vcc && tpd->vcc->pop)
-+ tpd->vcc->pop(tpd->vcc, tpd->skb);
-+ else
-+ dev_kfree_skb_any(tpd->skb);
-+ }
-+
-+
-+next_tbrq_entry:
-+ pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
-+
-+ he_dev->tbrq_head = (struct he_tbrq *)
-+ ((unsigned long) he_dev->tbrq_base |
-+ TBRQ_MASK(++he_dev->tbrq_head));
-+ }
-+
-+ if (updated)
-+ {
-+ if (updated > he_dev->tbrq_peak) he_dev->tbrq_peak = updated;
-+
-+ he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head),
-+ G0_TBRQ_H + (group * 16));
-+ }
-+}
-+
-+
-+static void
-+he_service_rbpl(struct he_dev *he_dev, int group)
-+{
-+ struct he_rbp *newtail;
-+ struct he_rbp *rbpl_head;
-+ int moved = 0;
-+
-+ rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
-+ RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
-+
-+ for(;;)
-+ {
-+ newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
-+ RBPL_MASK(he_dev->rbpl_tail+1));
-+
-+ /* table 3.42 -- rbpl_tail should never be set to rbpl_head */
-+ if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED))
-+ break;
-+
-+ newtail->status |= RBP_LOANED;
-+ he_dev->rbpl_tail = newtail;
-+ ++moved;
-+
-+ }
-+
-+ if (moved)
-+ he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
-+}
-+
-+#ifdef USE_RBPS
-+static void
-+he_service_rbps(struct he_dev *he_dev, int group)
-+{
-+ struct he_rbp *newtail;
-+ struct he_rbp *rbps_head;
-+ int moved = 0;
-+
-+ rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
-+ RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
-+
-+ for(;;)
-+ {
-+ newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
-+ RBPS_MASK(he_dev->rbps_tail+1));
-+
-+ /* table 3.42 -- rbps_tail should never be set to rbps_head */
-+ if ((newtail == rbps_head) || (newtail->status & RBP_LOANED))
-+ break;
-+
-+ newtail->status |= RBP_LOANED;
-+ he_dev->rbps_tail = newtail;
-+ ++moved;
-+
-+ }
-+
-+ if (moved)
-+ he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T);
-+}
-+#endif /* USE_RBPS */
-+
-+static void
-+he_tasklet(unsigned long data)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = (struct he_dev *) data;
-+ int group, type;
-+ int updated = 0;
-+
-+ HPRINTK("tasklet (0x%lx)\n", data);
-+#ifdef USE_TASKLET
-+ HE_SPIN_LOCK(he_dev, flags);
-+#endif
-+
-+ while(he_dev->irq_head != he_dev->irq_tail)
-+ {
-+ ++updated;
-+
-+ type = ITYPE_TYPE(he_dev->irq_head->isw);
-+ group = ITYPE_GROUP(he_dev->irq_head->isw);
-+
-+ switch (type)
-+ {
-+ case ITYPE_RBRQ_THRESH:
-+ hprintk("rbrq%d threshold\n", group);
-+ case ITYPE_RBRQ_TIMER:
-+ if (he_service_rbrq(he_dev, group))
-+ {
-+ he_service_rbpl(he_dev, group);
-+#ifdef USE_RBPS
-+ he_service_rbps(he_dev, group);
-+#endif /* USE_RBPS */
-+ }
-+ break;
-+ case ITYPE_TBRQ_THRESH:
-+ hprintk("tbrq%d threshold\n", group);
-+ case ITYPE_TPD_COMPLETE:
-+ he_service_tbrq(he_dev, group);
-+ break;
-+ case ITYPE_RBPL_THRESH:
-+ he_service_rbpl(he_dev, group);
-+ break;
-+ case ITYPE_RBPS_THRESH:
-+#ifdef USE_RBPS
-+ he_service_rbps(he_dev, group);
-+#endif /* USE_RBPS */
-+ break;
-+ case ITYPE_PHY:
-+#ifdef CONFIG_ATM_HE_USE_SUNI
-+ if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt)
-+ he_dev->atm_dev->phy->interrupt(he_dev->atm_dev);
-+#endif
-+ HPRINTK1("phy interrupt\n");
-+ break;
-+ case ITYPE_OTHER:
-+ switch (type|group)
-+ {
-+ case ITYPE_PARITY:
-+ hprintk1("parity error\n");
-+ break;
-+ case ITYPE_ABORT:
-+ hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR));
-+ break;
-+ }
-+ break;
-+ default:
-+ if (he_dev->irq_head->isw == ITYPE_INVALID)
-+ {
-+ /* see 8.1.1 -- check all queues */
-+
-+ HPRINTK("isw not updated 0x%x\n",
-+ he_dev->irq_head->isw);
-+
-+ he_service_rbrq(he_dev, 0);
-+ he_service_rbpl(he_dev, 0);
-+#ifdef USE_RBPS
-+ he_service_rbps(he_dev, 0);
-+#endif /* USE_RBPS */
-+ he_service_tbrq(he_dev, 0);
-+ }
-+ else
-+ hprintk("bad isw = 0x%x?\n",
-+ he_dev->irq_head->isw);
-+ }
-+
-+ he_dev->irq_head->isw = ITYPE_INVALID;
-+
-+ he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK);
-+ }
-+
-+ if (updated)
-+ {
-+ if (updated > he_dev->irq_peak) he_dev->irq_peak = updated;
-+
-+ he_writel(he_dev,
-+ IRQ_SIZE(CONFIG_IRQ_SIZE) |
-+ IRQ_THRESH(CONFIG_IRQ_THRESH) |
-+ IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD);
-+ (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */
-+ }
-+#ifdef USE_TASKLET
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+#endif
-+}
-+
-+static void
-+he_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = (struct he_dev * )dev_id;
-+
-+ if (he_dev == NULL) return;
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+
-+ he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) |
-+ (*he_dev->irq_tailoffset << 2));
-+
-+ if (he_dev->irq_tail == he_dev->irq_head)
-+ {
-+ HPRINTK1("tailoffset not updated?\n");
-+ he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base |
-+ ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2));
-+ (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */
-+ }
-+
-+#ifdef notdef
-+ if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */)
-+ hprintk1("spurious interrupt?\n");
-+#endif
-+
-+ if (he_dev->irq_head != he_dev->irq_tail)
-+ {
-+#ifdef USE_TASKLET
-+ tasklet_schedule(&he_dev->tasklet);
-+#else
-+ he_tasklet((unsigned long) he_dev);
-+#endif
-+ he_writel(he_dev, INT_CLEAR_A, INT_FIFO);
-+ /* clear interrupt */
-+ }
-+
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+}
-+
-+static __inline__ void
-+he_enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
-+{
-+ struct he_tpdrq *new_tail;
-+ unsigned flags;
-+
-+ spin_lock_irqsave(&he_dev->tpdrq_lock, flags);
-+
-+ HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n",
-+ tpd, cid, he_dev->tpdrq_tail);
-+
-+ new_tail = he_dev->tpdrq_tail;
-+ new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base |
-+ TPDRQ_MASK(++new_tail));
-+
-+ /*
-+ * check to see if we are about to set the tail == head
-+ * if true, update the head pointer from the adapter
-+ * to see if this is really the case (reading the queue
-+ * head for every enqueue would be unnecessarily slow)
-+ */
-+
-+ if (new_tail == he_dev->tpdrq_head)
-+ {
-+ he_dev->tpdrq_head = (struct he_tpdrq *)
-+ (((unsigned long)he_dev->tpdrq_base) |
-+ TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H)));
-+
-+ if (new_tail == he_dev->tpdrq_head)
-+ {
-+ hprintk("tpdrq full (cid 0x%x)\n", cid);
-+ /*
-+ * FIXME
-+ * push tpd onto a transmit backlog queue
-+ * after service_tbrq, service the backlog
-+ * for now, we just drop the pdu
-+ */
-+ if (tpd->skb)
-+ {
-+ if (tpd->vcc->pop)
-+ tpd->vcc->pop(tpd->vcc, tpd->skb);
-+ else
-+ dev_kfree_skb_any(tpd->skb);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++tpd->vcc->stats->tx_err;
-+#else
-+ atomic_inc(&tpd->vcc->stats->tx_err);
-+#endif
-+ }
-+ pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
-+ spin_unlock_irqrestore(&he_dev->tpdrq_lock, flags);
-+ return;
-+ }
-+ }
-+
-+ /* 2.1.5 transmit packet descriptor ready queue */
-+ he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status);
-+ he_dev->tpdrq_tail->cid = cid;
-+ mb();
-+ list_add_tail(&tpd->entry, &he_dev->outstanding_tpds);
-+
-+ he_dev->tpdrq_tail = new_tail;
-+
-+ he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T);
-+ spin_unlock_irqrestore(&he_dev->tpdrq_lock, flags);
-+}
-+
-+static int
-+he_open(struct atm_vcc *vcc, short vpi, int vci)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = HE_DEV(vcc->dev);
-+ struct he_vcc *he_vcc;
-+ int err = 0;
-+ unsigned cid, rsr0, rsr1, rsr4, tsr0, period, reg, clock;
-+ int first_open = 0;
-+
-+ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0;
-+ vcc->vpi = vpi;
-+ vcc->vci = vci;
-+
-+ HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ vcc->flags |= ATM_VF_ADDR;
-+#else
-+ set_bit(ATM_VF_ADDR, &vcc->flags);
-+#endif
-+
-+ cid = he_mkcid(he_dev, vpi, vci);
-+
-+ he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_KERNEL);
-+ if (he_vcc == NULL)
-+ {
-+ hprintk1("unable to allocate he_vcc during open\n");
-+ return -ENOMEM;
-+ }
-+
-+ he_vcc->iov_tail = he_vcc->iov_head;
-+ he_vcc->pdu_len = 0;
-+ he_vcc->rc_index = -1;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ init_waitqueue(&he_vcc->rx_waitq);
-+ init_waitqueue(&he_vcc->tx_waitq);
-+#else
-+ init_waitqueue_head(&he_vcc->rx_waitq);
-+ init_waitqueue_head(&he_vcc->tx_waitq);
-+#endif
-+
-+ HE_VCC(vcc) = he_vcc;
-+
-+ if (vcc->qos.txtp.traffic_class != ATM_NONE)
-+ {
-+ int pcr_goal;
-+
-+ pcr_goal = atm_pcr_goal(&vcc->qos.txtp);
-+ if (pcr_goal == 0)
-+ pcr_goal = he_dev->atm_dev->link_rate;
-+ if (pcr_goal < 0) /* means round down, technically */
-+ pcr_goal = -pcr_goal;
-+
-+ HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal);
-+
-+ /* no transmit support for AAL0 -- FIXME */
-+
-+ if (vcc->qos.aal != ATM_AAL5)
-+ {
-+ err = -EINVAL;
-+ goto open_failed;
-+ }
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+ tsr0 = he_readl_tsr0(he_dev, cid);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+ if (tsr0 == 0 && vcc->qos.aal == ATM_AAL5) first_open = 1;
-+
-+ if (TSR0_CONN_STATE(tsr0) != 0)
-+ {
-+ hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0);
-+#ifdef notdef
-+ err = -EBUSY;
-+ goto open_failed;
-+#endif
-+ }
-+
-+ switch(vcc->qos.txtp.traffic_class)
-+ {
-+ case ATM_UBR:
-+ /* 2.3.3.1 open connection ubr */
-+
-+ tsr0 = TSR0_UBR | TSR0_GROUP(0) | TSR0_AAL5 |
-+ TSR0_USE_WMIN | TSR0_UPDATE_GER;
-+ break;
-+
-+ case ATM_CBR:
-+ /* 2.3.3.2 open connection cbr */
-+
-+ clock = he_is622(he_dev) ? 66667000 : 50000000;
-+ period = clock / pcr_goal;
-+
-+ /* find an unused cs_stper register */
-+
-+ for(reg = 0; reg < HE_NUM_CS_STPER; ++reg)
-+ if (he_dev->cs_stper[reg].inuse == 0 ||
-+ he_dev->cs_stper[reg].pcr == pcr_goal)
-+ break;
-+
-+ if (reg == HE_NUM_CS_STPER)
-+ {
-+ err = -EBUSY;
-+ goto open_failed;
-+ }
-+
-+ /* 8.2.3 cbr scheduler wrap problem */
-+ if ((he_dev->total_bw + pcr_goal)
-+ > (he_dev->atm_dev->link_rate * 10 / 9))
-+ {
-+ err = -EBUSY;
-+ goto open_failed;
-+ }
-+ he_dev->total_bw += pcr_goal;
-+
-+ he_vcc->rc_index = reg;
-+ ++he_dev->cs_stper[reg].inuse;
-+ he_dev->cs_stper[reg].pcr = pcr_goal;
-+
-+ HPRINTK("rc_index = %d period = %d\n",
-+ reg, period);
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+ he_writel_mbox(he_dev, rate_to_atmf(period/2),
-+ CS_STPER0 + reg);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+ tsr0 = TSR0_CBR | TSR0_GROUP(0) | TSR0_AAL5 |
-+ TSR0_RC_INDEX(reg);
-+
-+ break;
-+ default:
-+ err = -EINVAL;
-+ goto open_failed;
-+ }
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+
-+ he_writel_tsr0(he_dev, tsr0, cid);
-+ he_writel_tsr4(he_dev, TSR4_AAL5 | 1, cid);
-+ he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) |
-+ TSR1_PCR(rate_to_atmf(pcr_goal)), cid);
-+ he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid);
-+ he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid);
-+
-+ he_writel_tsr3(he_dev, 0x0, cid);
-+ he_writel_tsr5(he_dev, 0x0, cid);
-+ he_writel_tsr6(he_dev, 0x0, cid);
-+ he_writel_tsr7(he_dev, 0x0, cid);
-+ he_writel_tsr8(he_dev, 0x0, cid);
-+ he_writel_tsr10(he_dev, 0x0, cid);
-+ he_writel_tsr11(he_dev, 0x0, cid);
-+ he_writel_tsr12(he_dev, 0x0, cid);
-+ he_writel_tsr13(he_dev, 0x0, cid);
-+ he_writel_tsr14(he_dev, 0x0, cid);
-+
-+ /* work around:
-+ *
-+ * the first aal5 pdu sent always seems to have a bad
-+ * crc. no idea why. probably initializing the card
-+ * wrong? if tsr0 == 0 this is the first open after
-+ * a reset.
-+ */
-+
-+ if (first_open)
-+ {
-+#define BADCRCMESG "BAD CRC WORKAROUND"
-+ static char *badcrc = NULL;
-+ struct he_tpd *tpd;
-+
-+ tpd = he_alloc_tpd(he_dev);
-+
-+ if (!badcrc)
-+ {
-+ badcrc = kmalloc(strlen(BADCRCMESG), GFP_DMA);
-+ memcpy(badcrc, BADCRCMESG, strlen(BADCRCMESG));
-+ }
-+
-+ HPRINTK("bad crc workaround cid = 0x%x\n", cid);
-+
-+ tpd->address0 = pci_map_single(he_dev->pci_dev,
-+ badcrc, strlen(BADCRCMESG), PCI_DMA_TODEVICE);
-+ tpd->length0 = strlen(BADCRCMESG) | TPD_LST;
-+ tpd->status |= TPD_USERCELL | TPD_INT;
-+ mb();
-+ tpd->skb = NULL;
-+ tpd->vcc = vcc;
-+
-+ he_enqueue_tpd(he_dev, tpd, cid);
-+ }
-+
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ }
-+
-+ if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-+ {
-+ unsigned aal;
-+
-+ HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid,
-+ &HE_VCC(vcc)->rx_waitq);
-+
-+ switch (vcc->qos.aal)
-+ {
-+ case ATM_AAL5:
-+ aal = RSR0_AAL5;
-+ break;
-+ case ATM_AAL0:
-+ aal = RSR0_RAWCELL;
-+ break;
-+ default:
-+ err = -EINVAL;
-+ goto open_failed;
-+ }
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+
-+ rsr0 = he_readl_rsr0(he_dev, cid);
-+ if (rsr0 & RSR0_OPEN_CONN)
-+ {
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+ hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0);
-+ err = -EBUSY;
-+ goto open_failed;
-+ }
-+
-+#ifdef USE_RBPS
-+ rsr1 = RSR1_GROUP(0);
-+ rsr4 = RSR4_GROUP(0);
-+#else /* !USE_RBPS */
-+ rsr1 = RSR1_GROUP(0)|RSR1_RBPL_ONLY;
-+ rsr4 = RSR4_GROUP(0)|RSR4_RBPL_ONLY;
-+#endif /* USE_RBPS */
-+ rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ?
-+ (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
-+
-+#ifdef USE_CHECKSUM_HW
-+ if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) rsr0 |= RSR0_TCP_CKSUM;
-+#endif
-+
-+ he_writel_rsr4(he_dev, rsr4, cid);
-+ he_writel_rsr1(he_dev, rsr1, cid);
-+ /* 5.1.11 last parameter initialized should be
-+ the open/closed indication in rsr0 */
-+ he_writel_rsr0(he_dev,
-+ rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid);
-+
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+#ifndef USE_HE_FIND_VCC
-+ HE_LOOKUP_VCC(he_dev, cid) = vcc;
-+#endif
-+ }
-+
-+open_failed:
-+
-+ if (err)
-+ {
-+ if (he_vcc) kfree(he_vcc);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ vcc->flags &= ~ATM_VF_ADDR;
-+#else
-+ clear_bit(ATM_VF_ADDR, &vcc->flags);
-+#endif
-+ }
-+ else
-+ {
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ vcc->flags |= ATM_VF_READY;
-+#else
-+ set_bit(ATM_VF_READY, &vcc->flags);
-+#endif
-+ }
-+
-+ return err;
-+}
-+
-+static void
-+he_close(struct atm_vcc *vcc)
-+{
-+ unsigned long flags;
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,1)
-+ DECLARE_WAITQUEUE(wait, current);
-+#else
-+ struct wait_queue wait = { current, NULL };
-+#endif
-+ struct he_dev *he_dev = HE_DEV(vcc->dev);
-+ struct he_tpd *tpd;
-+ unsigned cid;
-+ struct he_vcc *he_vcc = HE_VCC(vcc);
-+#define MAX_RETRY 30
-+ int retry = 0, sleep = 1, tx_inuse;
-+
-+ HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ vcc->flags &= ~ATM_VF_READY;
-+#else
-+ clear_bit(ATM_VF_READY, &vcc->flags);
-+#endif
-+ cid = he_mkcid(he_dev, vcc->vpi, vcc->vci);
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+
-+ if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-+ {
-+ int timeout;
-+
-+ HPRINTK("close rx cid 0x%x\n", cid);
-+
-+ /* 2.7.2.2 close receive operation */
-+
-+ /* wait for previous close (if any) to finish */
-+
-+ while(he_readl(he_dev, RCC_STAT) & RCC_BUSY)
-+ {
-+ HPRINTK("close cid 0x%x RCC_BUSY\n", cid);
-+ udelay(250);
-+ }
-+
-+ add_wait_queue(&he_vcc->rx_waitq, &wait);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+
-+ he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid);
-+ he_writel_mbox(he_dev, cid, RXCON_CLOSE);
-+
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ timeout = schedule_timeout(30*HZ);
-+ HE_SPIN_LOCK(he_dev, flags);
-+ remove_wait_queue(&he_vcc->rx_waitq, &wait);
-+ set_current_state(TASK_RUNNING);
-+
-+ if (timeout == 0)
-+ hprintk("close rx timeout cid 0x%x\n", cid);
-+
-+#ifndef USE_HE_FIND_VCC
-+ HE_LOOKUP_VCC(he_dev, cid) = NULL;
-+#endif
-+ HPRINTK("close rx cid 0x%x complete\n", cid);
-+
-+ }
-+
-+ if (vcc->qos.txtp.traffic_class != ATM_NONE)
-+ {
-+ volatile unsigned tsr4, tsr0;
-+ int timeout;
-+
-+ HPRINTK("close tx cid 0x%x\n", cid);
-+
-+ /* 2.1.2
-+ *
-+ * ... the host must first stop queueing packets to the TPDRQ
-+ * on the connection to be closed, then wait for all outstanding
-+ * packets to be transmitted and their buffers returned to the
-+ * TBRQ. When the last packet on the connection arrives in the
-+ * TBRQ, the host issues the close command to the adapter.
-+ */
-+
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ while (((tx_inuse = atomic_read(&vcc->sk->wmem_alloc)) > 0)
-+ && (retry < MAX_RETRY))
-+ {
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ (void) schedule_timeout(sleep);
-+ set_current_state(TASK_RUNNING);
-+ if (sleep < HZ) sleep = sleep * 2;
-+
-+ ++retry;
-+ }
-+
-+ if (tx_inuse) hprintk("close tx cid 0x%x tx_inuse = %d\n",
-+ cid, tx_inuse);
-+ HE_SPIN_LOCK(he_dev, flags);
-+
-+ /* 2.3.1.1 generic close operations with flush */
-+
-+ he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid);
-+ /* also clears TSR4_SESSION_ENDED */
-+
-+ switch(vcc->qos.txtp.traffic_class)
-+ {
-+ case ATM_UBR:
-+ he_writel_tsr1(he_dev,
-+ TSR1_MCR(rate_to_atmf(200000))
-+ | TSR1_PCR(0), cid);
-+ break;
-+ case ATM_CBR:
-+ he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid);
-+ break;
-+ }
-+
-+
-+ tpd = he_alloc_tpd(he_dev);
-+ if (tpd == NULL)
-+ {
-+ hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid);
-+ goto close_tx_incomplete;
-+ }
-+ tpd->status |= TPD_EOS | TPD_INT;
-+ tpd->skb = NULL;
-+ tpd->vcc = vcc;
-+ mb();
-+
-+ add_wait_queue(&he_vcc->tx_waitq, &wait);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ he_enqueue_tpd(he_dev, tpd, cid);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ timeout = schedule_timeout(30*HZ);
-+ HE_SPIN_LOCK(he_dev, flags);
-+ remove_wait_queue(&he_vcc->tx_waitq, &wait);
-+ set_current_state(TASK_RUNNING);
-+
-+ if (timeout == 0)
-+ {
-+ hprintk("close tx timeout cid 0x%x\n", cid);
-+ goto close_tx_incomplete;
-+ }
-+
-+ while (!((tsr4 = he_readl_tsr4(he_dev, cid))
-+ & TSR4_SESSION_ENDED))
-+ {
-+ HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4);
-+ udelay(250);
-+ }
-+
-+ while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0)
-+ {
-+ HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0);
-+ udelay(250);
-+ }
-+
-+close_tx_incomplete:
-+
-+ if (vcc->qos.txtp.traffic_class == ATM_CBR)
-+ {
-+ int reg = he_vcc->rc_index;
-+
-+ HPRINTK("cs_stper reg = %d\n", reg);
-+
-+ if (he_dev->cs_stper[reg].inuse == 0)
-+ hprintk("cs_stper[%d].inuse = 0!\n", reg);
-+ else
-+ --he_dev->cs_stper[reg].inuse;
-+
-+ he_dev->total_bw -= he_dev->cs_stper[reg].pcr;
-+ }
-+
-+ HPRINTK("close tx cid 0x%x complete\n", cid);
-+ }
-+
-+ kfree(he_vcc);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ vcc->flags &= ~ATM_VF_ADDR;
-+#else
-+ clear_bit(ATM_VF_ADDR, &vcc->flags);
-+#endif
-+}
-+
-+static int
-+he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size)
-+{
-+#ifdef USE_SCATTERGATHER
-+ return 1;
-+#else
-+ return 0;
-+#endif
-+}
-+
-+static int
-+he_send(struct atm_vcc *vcc, struct sk_buff *skb)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = HE_DEV(vcc->dev);
-+ unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci);
-+ struct he_tpd *tpd;
-+#ifdef USE_SCATTERGATHER
-+ int i, slot = 0;
-+#endif
-+
-+#define HE_TPD_BUFSIZE 0xffff
-+
-+ HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci);
-+
-+ if (skb->len > HE_TPD_BUFSIZE )
-+ {
-+ hprintk("buffer too large (%d bytes)\n", skb->len );
-+ if (vcc->pop)
-+ vcc->pop(vcc, skb);
-+ else
-+ dev_kfree_skb_any(skb);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->tx_err;
-+#else
-+ atomic_inc(&vcc->stats->tx_err);
-+#endif
-+ return -EINVAL;
-+ }
-+
-+#ifndef USE_SCATTERGATHER
-+ if (skb_shinfo(skb)->nr_frags)
-+ {
-+ hprintk1("no scatter/gather support\n");
-+ if (vcc->pop)
-+ vcc->pop(vcc, skb);
-+ else
-+ dev_kfree_skb_any(skb);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->tx_err;
-+#else
-+ atomic_inc(&vcc->stats->tx_err);
-+#endif
-+ return -EINVAL;
-+ }
-+#endif
-+
-+ tpd = he_alloc_tpd(he_dev);
-+ if (tpd == NULL)
-+ {
-+ if (vcc->pop)
-+ vcc->pop(vcc, skb);
-+ else
-+ dev_kfree_skb_any(skb);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->tx_err;
-+#else
-+ atomic_inc(&vcc->stats->tx_err);
-+#endif
-+ return -ENOMEM;
-+ }
-+ tpd->status |= TPD_USERCELL;
-+
-+#ifdef USE_SCATTERGATHER
-+ tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data,
-+ skb->len - skb->data_len, PCI_DMA_TODEVICE);
-+ tpd->iovec[slot].len = skb->len - skb->data_len;
-+ ++slot;
-+
-+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-+ {
-+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-+
-+ if (slot == TPD_MAXIOV) /* send tpd; start new tpd */
-+ {
-+ tpd->vcc = vcc;
-+ tpd->skb = NULL; /* not the last fragment
-+ so dont ->push() yet */
-+ mb();
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+ he_enqueue_tpd(he_dev, tpd, cid);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ tpd = he_alloc_tpd(he_dev);
-+ if (tpd == NULL)
-+ {
-+ if (vcc->pop)
-+ vcc->pop(vcc, skb);
-+ else
-+ dev_kfree_skb_any(skb);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->tx_err;
-+#else
-+ atomic_inc(&vcc->stats->tx_err);
-+#endif
-+ return -ENOMEM;
-+ }
-+ tpd->status |= TPD_USERCELL;
-+ slot = 0;
-+ }
-+
-+ tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev,
-+ (void *) page_address(frag->page) + frag->page_offset,
-+ frag->size, PCI_DMA_TODEVICE);
-+ tpd->iovec[slot].len = frag->size;
-+ ++slot;
-+
-+ }
-+
-+ tpd->iovec[slot-1].len |= TPD_LST;
-+#else
-+ tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
-+ tpd->length0 = skb->len | TPD_LST;
-+#endif
-+ tpd->status |= TPD_INT;
-+
-+ tpd->vcc = vcc;
-+ tpd->skb = skb;
-+ mb();
-+ ATM_SKB(skb)->vcc = vcc;
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+ he_enqueue_tpd(he_dev, tpd, cid);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)
-+ ++vcc->stats->tx;
-+#else
-+ atomic_inc(&vcc->stats->tx);
-+#endif
-+
-+ return 0;
-+}
-+
-+static int
-+he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = HE_DEV(atm_dev);
-+ struct he_ioctl_reg reg;
-+ int err = 0;
-+
-+ switch (cmd)
-+ {
-+ case HE_GET_REG:
-+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
-+
-+ copy_from_user(®, (struct he_ioctl_reg *) arg,
-+ sizeof(struct he_ioctl_reg));
-+ HE_SPIN_LOCK(he_dev, flags);
-+ switch (reg.type)
-+ {
-+ case HE_REGTYPE_PCI:
-+ reg.val = he_readl(he_dev, reg.addr);
-+ break;
-+ case HE_REGTYPE_RCM:
-+ reg.val =
-+ he_readl_rcm(he_dev, reg.addr);
-+ break;
-+ case HE_REGTYPE_TCM:
-+ reg.val =
-+ he_readl_tcm(he_dev, reg.addr);
-+ break;
-+ case HE_REGTYPE_MBOX:
-+ reg.val =
-+ he_readl_mbox(he_dev, reg.addr);
-+ break;
-+ default:
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ return -EINVAL;
-+ }
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+ copy_to_user((struct he_ioctl_reg *) arg, ®,
-+ sizeof(struct he_ioctl_reg));
-+ break;
-+ default:
-+#ifdef CONFIG_ATM_HE_USE_SUNI
-+ HE_SPIN_LOCK(he_dev, flags);
-+ if (atm_dev->phy && atm_dev->phy->ioctl)
-+ err = atm_dev->phy->ioctl(atm_dev, cmd, arg);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+#else /* CONFIG_ATM_HE_USE_SUNI */
-+ return -EINVAL;
-+#endif /* CONFIG_ATM_HE_USE_SUNI */
-+ break;
-+ }
-+
-+ return err;
-+}
-+
-+static void
-+he_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr)
-+{
-+ struct he_dev *he_dev = HE_DEV(atm_dev);
-+
-+ HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr);
-+
-+ he_writel(he_dev, val, FRAMER + (addr*4));
-+}
-+
-+
-+static unsigned char
-+he_phy_get(struct atm_dev *atm_dev, unsigned long addr)
-+{
-+ struct he_dev *he_dev = HE_DEV(atm_dev);
-+ unsigned reg;
-+
-+ reg = he_readl(he_dev, FRAMER + (addr*4));
-+
-+ HPRINTK("phy_get(addr 0x%lx) =0x%lx\n", addr, reg);
-+ return reg;
-+}
-+
-+static int
-+he_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
-+{
-+ unsigned long flags;
-+ struct he_dev *he_dev = HE_DEV(dev);
-+ int left, i;
-+#ifdef notdef
-+ struct he_rbrq *rbrq_tail;
-+ struct he_tpdrq *tpdrq_head;
-+ int rbpl_head, rbpl_tail;
-+#endif
-+ static long mcc = 0, oec = 0, dcc = 0, cec = 0;
-+
-+
-+ left = *pos;
-+ if (!left--)
-+ return sprintf(page, "%s\n", version);
-+
-+ if (!left--)
-+ return sprintf(page, "%s%s\n\n",
-+ he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM");
-+
-+ if (!left--)
-+ return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n");
-+
-+ HE_SPIN_LOCK(he_dev, flags);
-+ mcc += he_readl(he_dev, MCC);
-+ oec += he_readl(he_dev, OEC);
-+ dcc += he_readl(he_dev, DCC);
-+ cec += he_readl(he_dev, CEC);
-+ HE_SPIN_UNLOCK(he_dev, flags);
-+
-+ if (!left--)
-+ return sprintf(page, "%16ld %16ld %13ld %17ld\n\n",
-+ mcc, oec, dcc, cec);
-+
-+ if (!left--)
-+ return sprintf(page, "irq_size = %d inuse = ? peak = %d\n",
-+ CONFIG_IRQ_SIZE, he_dev->irq_peak);
-+
-+ if (!left--)
-+ return sprintf(page, "tpdrq_size = %d inuse = ?\n",
-+ CONFIG_TPDRQ_SIZE);
-+
-+ if (!left--)
-+ return sprintf(page, "rbrq_size = %d inuse = ? peak = %d\n",
-+ CONFIG_RBRQ_SIZE, he_dev->rbrq_peak);
-+
-+ if (!left--)
-+ return sprintf(page, "tbrq_size = %d peak = %d\n",
-+ CONFIG_TBRQ_SIZE, he_dev->tbrq_peak);
-+
-+
-+#ifdef notdef
-+ rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S));
-+ rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T));
-+
-+ inuse = rbpl_head - rbpl_tail;
-+ if (inuse < 0) inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp);
-+ inuse /= sizeof(struct he_rbp);
-+
-+ if (!left--)
-+ return sprintf(page, "rbpl_size = %d inuse = %d\n\n",
-+ CONFIG_RBPL_SIZE, inuse);
-+#endif
-+
-+ if (!left--)
-+ return sprintf(page, "rate controller periods (cbr)\n pcr #vc\n");
-+
-+ for (i = 0; i < HE_NUM_CS_STPER; ++i)
-+ if (!left--)
-+ return sprintf(page, "cs_stper%-2d %8ld %3d\n", i,
-+ he_dev->cs_stper[i].pcr,
-+ he_dev->cs_stper[i].inuse);
-+
-+ if (!left--)
-+ return sprintf(page, "total bw (cbr): %d (limit %d)\n",
-+ he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9);
-+
-+ return 0;
-+}
-+
-+/* eeprom routines -- see 4.7 */
-+
-+u8
-+read_prom_byte(struct he_dev *he_dev, int addr)
-+{
-+ u32 val = 0, tmp_read = 0;
-+ int i, j = 0;
-+ u8 byte_read = 0;
-+
-+ val = readl(he_dev->membase + HOST_CNTL);
-+ val &= 0xFFFFE0FF;
-+
-+ /* Turn on write enable */
-+ val |= 0x800;
-+ writel(val, he_dev->membase + HOST_CNTL);
-+
-+ /* Send READ instruction */
-+ for (i=0; i<sizeof(readtab)/sizeof(readtab[0]); i++) {
-+ writel(val | readtab[i], he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+ }
-+
-+ /* Next, we need to send the byte address to read from */
-+ for (i=7; i>=0; i--) {
-+ writel(val | clocktab[j++] | (((addr >> i) & 1) << 9),
-+ he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+ writel(val | clocktab[j++] | (((addr >> i) & 1) << 9),
-+ he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+ }
-+
-+ j=0;
-+
-+ val &= 0xFFFFF7FF; /* Turn off write enable */
-+ writel(val, he_dev->membase + HOST_CNTL);
-+
-+ /* Now, we can read data from the EEPROM by clocking it in */
-+ for (i=7; i>=0; i--) {
-+ writel(val | clocktab[j++], he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+ tmp_read = readl(he_dev->membase + HOST_CNTL);
-+ byte_read |= (unsigned char)
-+ ((tmp_read & ID_DOUT)
-+ >> ID_DOFFSET << i);
-+ writel(val | clocktab[j++],
-+ he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+ }
-+
-+ writel(val | clocktab[j++], he_dev->membase + HOST_CNTL);
-+ udelay(EEPROM_DELAY);
-+
-+ return (byte_read);
-+}
-+
-+MODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>");
-+MODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver");
-+MODULE_PARM(disable64, "h");
-+MODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers");
-+MODULE_PARM(nvpibits, "i");
-+MODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)");
-+MODULE_PARM(nvcibits, "i");
-+MODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)");
-+MODULE_PARM(rx_skb_reserve, "i");
-+MODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)");
-+MODULE_PARM(irq_coalesce, "i");
-+MODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)");
-+MODULE_PARM(sdh, "i");
-+MODULE_PARM_DESC(sdh, "use SDH framing (default 0)");
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,1)
-+static struct pci_device_id he_pci_tbl[] __devinitdata = {
-+ { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID,
-+ 0, 0, 0 },
-+ { 0, }
-+};
-+
-+static struct pci_driver he_driver = {
-+ .name = "he",
-+ .probe = he_init_one,
-+ .remove = __devexit_p(he_remove_one),
-+ .id_table = he_pci_tbl,
-+};
-+
-+static int __init he_init(void)
-+{
-+ return pci_module_init(&he_driver);
-+}
-+
-+static void __exit he_cleanup(void)
-+{
-+ pci_unregister_driver(&he_driver);
-+}
-+
-+module_init(he_init);
-+module_exit(he_cleanup);
-+#else
-+static int __init
-+he_init()
-+{
-+ if (!pci_present())
-+ return -EIO;
-+
-+#ifdef CONFIG_ATM_HE_USE_SUNI_MODULE
-+ /* request_module("suni"); */
-+#endif
-+
-+ pci_dev = NULL;
-+ while ((pci_dev = pci_find_device(PCI_VENDOR_ID_FORE,
-+ PCI_DEVICE_ID_FORE_HE, pci_dev)) != NULL)
-+ if (he_init_one(pci_dev, NULL) == 0)
-+ ++ndevs;
-+
-+ return (ndevs ? 0 : -ENODEV);
-+}
-+
-+static void __devexit
-+he_cleanup(void)
-+{
-+ while (he_devs)
-+ {
-+ struct he_dev *next = he_devs->next;
-+ he_stop(he_devs);
-+ atm_dev_deregister(he_devs->atm_dev);
-+ kfree(he_devs);
-+
-+ he_devs = next;
-+ }
-+
-+}
-+
-+int init_module(void)
-+{
-+ return he_init();
-+}
-+
-+void cleanup_module(void)
-+{
-+ he_cleanup();
-+}
-+#endif
-+
-+MODULE_LICENSE("GPL");
-diff -urN linux-2.4.20/drivers/atm/he.h linux-2.4.20-atm/drivers/atm/he.h
---- linux-2.4.20/drivers/atm/he.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.20-atm/drivers/atm/he.h Wed May 28 01:58:41 2003
-@@ -0,0 +1,910 @@
-+/* $Id$ */
-+
-+/*
-+
-+ he.h
-+
-+ ForeRunnerHE ATM Adapter driver for ATM on Linux
-+ Copyright (C) 1999-2001 Naval Research Laboratory
-+
-+ This library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2.1 of the License, or (at your option) any later version.
-+
-+ This library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with this library; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+*/
-+
-+/*
-+
-+ he.h
-+
-+ ForeRunnerHE ATM Adapter driver for ATM on Linux
-+ Copyright (C) 1999-2000 Naval Research Laboratory
-+
-+ Permission to use, copy, modify and distribute this software and its
-+ documentation is hereby granted, provided that both the copyright
-+ notice and this permission notice appear in all copies of the software,
-+ derivative works or modified versions, and any portions thereof, and
-+ that both notices appear in supporting documentation.
-+
-+ NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
-+ DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
-+ RESULTING FROM THE USE OF THIS SOFTWARE.
-+
-+ */
-+
-+#ifndef _HE_H_
-+#define _HE_H_
-+
-+#define DEV_LABEL "he"
-+
-+#define CONFIG_DEFAULT_VCIBITS 12
-+#define CONFIG_DEFAULT_VPIBITS 0
-+
-+#define CONFIG_IRQ_SIZE 128
-+#define CONFIG_IRQ_THRESH (CONFIG_IRQ_SIZE/2)
-+
-+#define CONFIG_TPDRQ_SIZE 512
-+#define TPDRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TPDRQ_SIZE<<3)-1))
-+
-+#define CONFIG_RBRQ_SIZE 512
-+#define CONFIG_RBRQ_THRESH 400
-+#define RBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_RBRQ_SIZE<<3)-1))
-+
-+#define CONFIG_TBRQ_SIZE 512
-+#define CONFIG_TBRQ_THRESH 400
-+#define TBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TBRQ_SIZE<<2)-1))
-+
-+#define CONFIG_RBPL_SIZE 512
-+#define CONFIG_RBPL_THRESH 64
-+#define CONFIG_RBPL_BUFSIZE 4096
-+#define RBPL_MASK(x) (((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1))
-+
-+#define CONFIG_RBPS_SIZE 1024
-+#define CONFIG_RBPS_THRESH 64
-+#define CONFIG_RBPS_BUFSIZE 128
-+#define RBPS_MASK(x) (((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1))
-+
-+/* 5.1.3 initialize connection memory */
-+
-+#define CONFIG_RSRA 0x00000
-+#define CONFIG_RCMLBM 0x08000
-+#define CONFIG_RCMABR 0x0d800
-+#define CONFIG_RSRB 0x0e000
-+
-+#define CONFIG_TSRA 0x00000
-+#define CONFIG_TSRB 0x08000
-+#define CONFIG_TSRC 0x0c000
-+#define CONFIG_TSRD 0x0e000
-+#define CONFIG_TMABR 0x0f000
-+#define CONFIG_TPDBA 0x10000
-+
-+#define HE_MAXCIDBITS 12
-+
-+/* 2.9.3.3 interrupt encodings */
-+
-+struct he_irq {
-+ volatile u32 isw;
-+};
-+
-+#define IRQ_ALIGNMENT 0x1000
-+
-+#define NEXT_ENTRY(base, tail, mask) \
-+ (((unsigned long)base)|(((unsigned long)(tail+1))&mask))
-+
-+#define ITYPE_INVALID 0xffffffff
-+#define ITYPE_TBRQ_THRESH (0<<3)
-+#define ITYPE_TPD_COMPLETE (1<<3)
-+#define ITYPE_RBPS_THRESH (2<<3)
-+#define ITYPE_RBPL_THRESH (3<<3)
-+#define ITYPE_RBRQ_THRESH (4<<3)
-+#define ITYPE_RBRQ_TIMER (5<<3)
-+#define ITYPE_PHY (6<<3)
-+#define ITYPE_OTHER 0x80
-+#define ITYPE_PARITY 0x81
-+#define ITYPE_ABORT 0x82
-+
-+#define ITYPE_GROUP(x) (x & 0x7)
-+#define ITYPE_TYPE(x) (x & 0xf8)
-+
-+#define HE_NUM_GROUPS 8
-+
-+/* 2.1.4 transmit packet descriptor */
-+
-+struct he_tpd {
-+
-+ /* read by the adapter */
-+
-+ volatile u32 status;
-+ volatile u32 reserved;
-+
-+#define TPD_MAXIOV 3
-+ struct {
-+ u32 addr, len;
-+ } iovec[TPD_MAXIOV];
-+
-+
-+#define address0 iovec[0].addr
-+#define length0 iovec[0].len
-+
-+ /* linux-atm extensions */
-+
-+ struct sk_buff *skb;
-+ struct atm_vcc *vcc;
-+
-+ struct list_head entry;
-+};
-+
-+#define TPD_ALIGNMENT 64
-+#define TPD_LEN_MASK 0xffff
-+
-+#define TPD_ADDR(x) ((x) & 0xffffffc0)
-+
-+
-+/* table 2.3 transmit buffer return elements */
-+
-+struct he_tbrq {
-+ volatile u32 tbre;
-+};
-+
-+#define TBRQ_ALIGNMENT CONFIG_TBRQ_SIZE
-+
-+#define TBRQ_TPD(tbrq) ((tbrq)->tbre & 0xffffffc0)
-+#define TBRQ_EOS(tbrq) ((tbrq)->tbre & (1<<3))
-+#define TBRQ_MULTIPLE(tbrq) ((tbrq)->tbre & (1))
-+
-+/* table 2.21 receive buffer return queue element field organization */
-+
-+struct he_rbrq {
-+ volatile u32 addr;
-+ volatile u32 cidlen;
-+};
-+
-+#define RBRQ_ALIGNMENT CONFIG_RBRQ_SIZE
-+
-+#define RBRQ_ADDR(rbrq) ((rbrq)->addr & 0xffffffc0)
-+#define RBRQ_CRC_ERR(rbrq) ((rbrq)->addr & (1<<5))
-+#define RBRQ_LEN_ERR(rbrq) ((rbrq)->addr & (1<<4))
-+#define RBRQ_END_PDU(rbrq) ((rbrq)->addr & (1<<3))
-+#define RBRQ_AAL5_PROT(rbrq) ((rbrq)->addr & (1<<2))
-+#define RBRQ_CON_CLOSED(rbrq) ((rbrq)->addr & (1<<1))
-+#define RBRQ_HBUF_ERR(rbrq) ((rbrq)->addr & 1)
-+#define RBRQ_CID(rbrq) (((rbrq)->cidlen >> 16) & 0x1fff)
-+#define RBRQ_BUFLEN(rbrq) ((rbrq)->cidlen & 0xffff)
-+
-+/* figure 2.3 transmit packet descriptor ready queue */
-+
-+struct he_tpdrq {
-+ volatile u32 tpd;
-+ volatile u32 cid;
-+};
-+
-+#define TPDRQ_ALIGNMENT CONFIG_TPDRQ_SIZE
-+
-+/* table 2.30 host status page detail */
-+
-+#define HSP_ALIGNMENT 0x400 /* must align on 1k boundary */
-+
-+struct he_hsp {
-+ struct he_hsp_entry {
-+ volatile u32 tbrq_tail;
-+ volatile u32 reserved1[15];
-+ volatile u32 rbrq_tail;
-+ volatile u32 reserved2[15];
-+ } group[HE_NUM_GROUPS];
-+};
-+
-+/* figure 2.9 receive buffer pools */
-+
-+struct he_rbp {
-+ volatile u32 phys;
-+ volatile u32 status;
-+};
-+
-+/* NOTE: it is suggested that virt be the virtual address of the host
-+ buffer. on a 64-bit machine, this would not work. Instead, we
-+ store the real virtual address in another list, and store an index
-+ (and buffer status) in the virt member.
-+*/
-+
-+#define RBP_INDEX_OFF 6
-+#define RBP_INDEX(x) (((long)(x) >> RBP_INDEX_OFF) & 0xffff)
-+#define RBP_LOANED 0x80000000
-+#define RBP_SMALLBUF 0x40000000
-+
-+struct he_virt {
-+ void *virt;
-+};
-+
-+#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE
-+#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE
-+
-+#ifdef notyet
-+struct he_group {
-+ u32 rpbs_size, rpbs_qsize;
-+ struct he_rbp rbps_ba;
-+
-+ u32 rpbl_size, rpbl_qsize;
-+ struct he_rpb_entry *rbpl_ba;
-+};
-+#endif
-+
-+#define HE_LOOKUP_VCC(dev, cid) ((dev)->he_vcc_table[(cid)].vcc)
-+
-+struct he_vcc_table
-+{
-+ struct atm_vcc *vcc;
-+};
-+
-+struct he_cs_stper
-+{
-+ long pcr;
-+ int inuse;
-+};
-+
-+#define HE_NUM_CS_STPER 16
-+
-+struct he_dev {
-+ unsigned int number;
-+ unsigned int irq;
-+ unsigned long membase;
-+
-+ char prod_id[30];
-+ char mac_addr[6];
-+ int media; /*
-+ * 0x26 = HE155 MM
-+ * 0x27 = HE622 MM
-+ * 0x46 = HE155 SM
-+ * 0x47 = HE622 SM
-+ */
-+
-+
-+ unsigned int vcibits, vpibits;
-+ unsigned int cells_per_row;
-+ unsigned int bytes_per_row;
-+ unsigned int cells_per_lbuf;
-+ unsigned int r0_numrows, r0_startrow, r0_numbuffs;
-+ unsigned int r1_numrows, r1_startrow, r1_numbuffs;
-+ unsigned int tx_numrows, tx_startrow, tx_numbuffs;
-+ unsigned int buffer_limit;
-+
-+ struct he_vcc_table *he_vcc_table;
-+
-+#ifdef notyet
-+ struct he_group group[HE_NUM_GROUPS];
-+#endif
-+ struct he_cs_stper cs_stper[HE_NUM_CS_STPER];
-+ unsigned total_bw;
-+
-+ dma_addr_t irq_phys;
-+ struct he_irq *irq_base, *irq_head, *irq_tail;
-+ volatile unsigned *irq_tailoffset;
-+ int irq_peak;
-+
-+#ifdef USE_TASKLET
-+ struct tasklet_struct tasklet;
-+#endif
-+
-+ struct pci_pool *tpd_pool;
-+ struct list_head outstanding_tpds;
-+ dma_addr_t tpdrq_phys;
-+ struct he_tpdrq *tpdrq_base, *tpdrq_tail, *tpdrq_head;
-+ spinlock_t tpdrq_lock; /* serialize access to tpdrq */
-+
-+ spinlock_t global_lock; /* 8.1.5 pci transaction ordering
-+ error problem */
-+ dma_addr_t rbrq_phys;
-+ struct he_rbrq *rbrq_base, *rbrq_head;
-+ int rbrq_peak;
-+
-+ struct pci_pool *rbpl_pool;
-+ dma_addr_t rbpl_phys;
-+ struct he_rbp *rbpl_base, *rbpl_tail;
-+ struct he_virt *rbpl_virt;
-+ int rbpl_peak;
-+
-+ struct pci_pool *rbps_pool;
-+ dma_addr_t rbps_phys;
-+ struct he_rbp *rbps_base, *rbps_tail;
-+ struct he_virt *rbps_virt;
-+ int rbps_peak;
-+
-+ dma_addr_t tbrq_phys;
-+ struct he_tbrq *tbrq_base, *tbrq_head;
-+ int tbrq_peak;
-+
-+ dma_addr_t hsp_phys;
-+ struct he_hsp *hsp;
-+
-+ struct pci_dev *pci_dev;
-+ struct atm_dev *atm_dev;
-+ struct he_dev *next;
-+};
-+
-+struct he_vcc
-+{
-+ struct iovec iov_head[32];
-+ struct iovec *iov_tail;
-+ int pdu_len;
-+
-+ int rc_index;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-+ struct wait_queue *rx_waitq;
-+ atruct wait_queue *tx_waitq;
-+#else
-+ wait_queue_head_t rx_waitq;
-+ wait_queue_head_t tx_waitq;
-+#endif
-+};
-+
-+#define HE_VCC(vcc) ((struct he_vcc *)(vcc->dev_data))
-+
-+#define PCI_VENDOR_ID_FORE 0x1127
-+#define PCI_DEVICE_ID_FORE_HE 0x400
-+
-+#define HE_DMA_MASK 0xffffffff
-+
-+#define GEN_CNTL_0 0x40
-+#define INT_PROC_ENBL (1<<25)
-+#define SLAVE_ENDIAN_MODE (1<<16)
-+#define MRL_ENB (1<<5)
-+#define MRM_ENB (1<<4)
-+#define INIT_ENB (1<<2)
-+#define IGNORE_TIMEOUT (1<<1)
-+#define ENBL_64 (1<<0)
-+
-+#define MIN_PCI_LATENCY 32 /* errata 8.1.3 */
-+
-+#define HE_DEV(dev) ((struct he_dev *) (dev)->dev_data)
-+
-+#define he_is622(dev) ((dev)->media & 0x1)
-+
-+#define HE_REGMAP_SIZE 0x100000
-+
-+#define RESET_CNTL 0x80000
-+#define BOARD_RST_STATUS (1<<6)
-+
-+#define HOST_CNTL 0x80004
-+#define PCI_BUS_SIZE64 (1<<27)
-+#define DESC_RD_STATIC_64 (1<<26)
-+#define DATA_RD_STATIC_64 (1<<25)
-+#define DATA_WR_STATIC_64 (1<<24)
-+#define ID_CS (1<<12)
-+#define ID_WREN (1<<11)
-+#define ID_DOUT (1<<10)
-+#define ID_DOFFSET 10
-+#define ID_DIN (1<<9)
-+#define ID_CLOCK (1<<8)
-+#define QUICK_RD_RETRY (1<<7)
-+#define QUICK_WR_RETRY (1<<6)
-+#define OUTFF_ENB (1<<5)
-+#define CMDFF_ENB (1<<4)
-+#define PERR_INT_ENB (1<<2)
-+#define IGNORE_INTR (1<<0)
-+
-+#define LB_SWAP 0x80008
-+#define SWAP_RNUM_MAX(x) (x<<27)
-+#define DATA_WR_SWAP (1<<20)
-+#define DESC_RD_SWAP (1<<19)
-+#define DATA_RD_SWAP (1<<18)
-+#define INTR_SWAP (1<<17)
-+#define DESC_WR_SWAP (1<<16)
-+#define SDRAM_INIT (1<<15)
-+#define BIG_ENDIAN_HOST (1<<14)
-+#define XFER_SIZE (1<<7)
-+
-+#define LB_MEM_ADDR 0x8000c
-+#define LB_MEM_DATA 0x80010
-+
-+#define LB_MEM_ACCESS 0x80014
-+#define LB_MEM_HNDSHK (1<<30)
-+#define LM_MEM_WRITE (0x7)
-+#define LM_MEM_READ (0x3)
-+
-+#define SDRAM_CTL 0x80018
-+#define LB_64_ENB (1<<3)
-+#define LB_TWR (1<<2)
-+#define LB_TRP (1<<1)
-+#define LB_TRAS (1<<0)
-+
-+#define INT_FIFO 0x8001c
-+#define INT_MASK_D (1<<15)
-+#define INT_MASK_C (1<<14)
-+#define INT_MASK_B (1<<13)
-+#define INT_MASK_A (1<<12)
-+#define INT_CLEAR_D (1<<11)
-+#define INT_CLEAR_C (1<<10)
-+#define INT_CLEAR_B (1<<9)
-+#define INT_CLEAR_A (1<<8)
-+
-+#define ABORT_ADDR 0x80020
-+
-+#define IRQ0_BASE 0x80080
-+#define IRQ_BASE(x) (x<<12)
-+#define IRQ_MASK ((CONFIG_IRQ_SIZE<<2)-1) /* was 0x3ff */
-+#define IRQ_TAIL(x) (((unsigned long)(x)) & IRQ_MASK)
-+#define IRQ0_HEAD 0x80084
-+#define IRQ_SIZE(x) (x<<22)
-+#define IRQ_THRESH(x) (x<<12)
-+#define IRQ_HEAD(x) (x<<2)
-+/* #define IRQ_PENDING (1) conflict with linux/irq.h */
-+#define IRQ0_CNTL 0x80088
-+#define IRQ_ADDRSEL(x) (x<<2)
-+#define IRQ_INT_A (0<<2)
-+#define IRQ_INT_B (1<<2)
-+#define IRQ_INT_C (2<<2)
-+#define IRQ_INT_D (3<<2)
-+#define IRQ_TYPE_ADDR 0x1
-+#define IRQ_TYPE_LINE 0x0
-+#define IRQ0_DATA 0x8008c
-+
-+#define IRQ1_BASE 0x80090
-+#define IRQ1_HEAD 0x80094
-+#define IRQ1_CNTL 0x80098
-+#define IRQ1_DATA 0x8009c
-+
-+#define IRQ2_BASE 0x800a0
-+#define IRQ2_HEAD 0x800a4
-+#define IRQ2_CNTL 0x800a8
-+#define IRQ2_DATA 0x800ac
-+
-+#define IRQ3_BASE 0x800b0
-+#define IRQ3_HEAD 0x800b4
-+#define IRQ3_CNTL 0x800b8
-+#define IRQ3_DATA 0x800bc
-+
-+#define GRP_10_MAP 0x800c0
-+#define GRP_32_MAP 0x800c4
-+#define GRP_54_MAP 0x800c8
-+#define GRP_76_MAP 0x800cc
-+
-+#define G0_RBPS_S 0x80400
-+#define G0_RBPS_T 0x80404
-+#define RBP_TAIL(x) ((x)<<3)
-+#define RBP_MASK(x) ((x)|0x1fff)
-+#define G0_RBPS_QI 0x80408
-+#define RBP_QSIZE(x) ((x)<<14)
-+#define RBP_INT_ENB (1<<13)
-+#define RBP_THRESH(x) (x)
-+#define G0_RBPS_BS 0x8040c
-+#define G0_RBPL_S 0x80410
-+#define G0_RBPL_T 0x80414
-+#define G0_RBPL_QI 0x80418
-+#define G0_RBPL_BS 0x8041c
-+
-+#define G1_RBPS_S 0x80420
-+#define G1_RBPS_T 0x80424
-+#define G1_RBPS_QI 0x80428
-+#define G1_RBPS_BS 0x8042c
-+#define G1_RBPL_S 0x80430
-+#define G1_RBPL_T 0x80434
-+#define G1_RBPL_QI 0x80438
-+#define G1_RBPL_BS 0x8043c
-+
-+#define G2_RBPS_S 0x80440
-+#define G2_RBPS_T 0x80444
-+#define G2_RBPS_QI 0x80448
-+#define G2_RBPS_BS 0x8044c
-+#define G2_RBPL_S 0x80450
-+#define G2_RBPL_T 0x80454
-+#define G2_RBPL_QI 0x80458
-+#define G2_RBPL_BS 0x8045c
-+
-+#define G3_RBPS_S 0x80460
-+#define G3_RBPS_T 0x80464
-+#define G3_RBPS_QI 0x80468
-+#define G3_RBPS_BS 0x8046c
-+#define G3_RBPL_S 0x80470
-+#define G3_RBPL_T 0x80474
-+#define G3_RBPL_QI 0x80478
-+#define G3_RBPL_BS 0x8047c
-+
-+#define G4_RBPS_S 0x80480
-+#define G4_RBPS_T 0x80484
-+#define G4_RBPS_QI 0x80488
-+#define G4_RBPS_BS 0x8048c
-+#define G4_RBPL_S 0x80490
-+#define G4_RBPL_T 0x80494
-+#define G4_RBPL_QI 0x80498
-+#define G4_RBPL_BS 0x8049c
-+
-+#define G5_RBPS_S 0x804a0
-+#define G5_RBPS_T 0x804a4
-+#define G5_RBPS_QI 0x804a8
-+#define G5_RBPS_BS 0x804ac
-+#define G5_RBPL_S 0x804b0
-+#define G5_RBPL_T 0x804b4
-+#define G5_RBPL_QI 0x804b8
-+#define G5_RBPL_BS 0x804bc
-+
-+#define G6_RBPS_S 0x804c0
-+#define G6_RBPS_T 0x804c4
-+#define G6_RBPS_QI 0x804c8
-+#define G6_RBPS_BS 0x804cc
-+#define G6_RBPL_S 0x804d0
-+#define G6_RBPL_T 0x804d4
-+#define G6_RBPL_QI 0x804d8
-+#define G6_RBPL_BS 0x804dc
-+
-+#define G7_RBPS_S 0x804e0
-+#define G7_RBPS_T 0x804e4
-+#define G7_RBPS_QI 0x804e8
-+#define G7_RBPS_BS 0x804ec
-+
-+#define G7_RBPL_S 0x804f0
-+#define G7_RBPL_T 0x804f4
-+#define G7_RBPL_QI 0x804f8
-+#define G7_RBPL_BS 0x804fc
-+
-+#define G0_RBRQ_ST 0x80500
-+#define G0_RBRQ_H 0x80504
-+#define G0_RBRQ_Q 0x80508
-+#define RBRQ_THRESH(x) ((x)<<13)
-+#define RBRQ_SIZE(x) (x)
-+#define G0_RBRQ_I 0x8050c
-+#define RBRQ_TIME(x) ((x)<<8)
-+#define RBRQ_COUNT(x) (x)
-+
-+/* fill in 1 ... 7 later */
-+
-+#define G0_TBRQ_B_T 0x80600
-+#define G0_TBRQ_H 0x80604
-+#define G0_TBRQ_S 0x80608
-+#define G0_TBRQ_THRESH 0x8060c
-+#define TBRQ_THRESH(x) (x)
-+
-+/* fill in 1 ... 7 later */
-+
-+#define RH_CONFIG 0x805c0
-+#define PHY_INT_ENB (1<<10)
-+#define OAM_GID(x) (x<<7)
-+#define PTMR_PRE(x) (x)
-+
-+#define G0_INMQ_S 0x80580
-+#define G0_INMQ_L 0x80584
-+#define G1_INMQ_S 0x80588
-+#define G1_INMQ_L 0x8058c
-+#define G2_INMQ_S 0x80590
-+#define G2_INMQ_L 0x80594
-+#define G3_INMQ_S 0x80598
-+#define G3_INMQ_L 0x8059c
-+#define G4_INMQ_S 0x805a0
-+#define G4_INMQ_L 0x805a4
-+#define G5_INMQ_S 0x805a8
-+#define G5_INMQ_L 0x805ac
-+#define G6_INMQ_S 0x805b0
-+#define G6_INMQ_L 0x805b4
-+#define G7_INMQ_S 0x805b8
-+#define G7_INMQ_L 0x805bc
-+
-+#define TPDRQ_B_H 0x80680
-+#define TPDRQ_T 0x80684
-+#define TPDRQ_S 0x80688
-+
-+#define UBUFF_BA 0x8068c
-+
-+#define RLBF0_H 0x806c0
-+#define RLBF0_T 0x806c4
-+#define RLBF1_H 0x806c8
-+#define RLBF1_T 0x806cc
-+#define RLBC_H 0x806d0
-+#define RLBC_T 0x806d4
-+#define RLBC_H2 0x806d8
-+#define TLBF_H 0x806e0
-+#define TLBF_T 0x806e4
-+#define RLBF0_C 0x806e8
-+#define RLBF1_C 0x806ec
-+#define RXTHRSH 0x806f0
-+#define LITHRSH 0x806f4
-+
-+#define LBARB 0x80700
-+#define SLICE_X(x) (x<<28)
-+#define ARB_RNUM_MAX(x) (x<<23)
-+#define TH_PRTY(x) (x<<21)
-+#define RH_PRTY(x) (x<<19)
-+#define TL_PRTY(x) (x<<17)
-+#define RL_PRTY(x) (x<<15)
-+#define BUS_MULTI(x) (x<<8)
-+#define NET_PREF(x) (x)
-+
-+#define SDRAMCON 0x80704
-+#define BANK_ON (1<<14)
-+#define WIDE_DATA (1<<13)
-+#define TWR_WAIT (1<<12)
-+#define TRP_WAIT (1<<11)
-+#define TRAS_WAIT (1<<10)
-+#define REF_RATE(x) (x)
-+
-+#define LBSTAT 0x80708
-+
-+#define RCC_STAT 0x8070c
-+#define RCC_BUSY (1)
-+
-+#define TCMCONFIG 0x80740
-+#define TM_DESL2 (1<<10)
-+#define TM_BANK_WAIT(x) (x<<6)
-+#define TM_ADD_BANK4(x) (x<<4)
-+#define TM_PAR_CHECK(x) (x<<3)
-+#define TM_RW_WAIT(x) (x<<2)
-+#define TM_SRAM_TYPE(x) (x)
-+
-+#define TSRB_BA 0x80744
-+#define TSRC_BA 0x80748
-+#define TMABR_BA 0x8074c
-+#define TPD_BA 0x80750
-+#define TSRD_BA 0x80758
-+
-+#define TX_CONFIG 0x80760
-+#define DRF_THRESH(x) (x<<22)
-+#define TX_UT_MODE(x) (x<<21)
-+#define TX_VCI_MASK(x) (x<<17)
-+#define LBFREE_CNT(x) (x)
-+
-+#define TXAAL5_PROTO 0x80764
-+#define CPCS_UU(x) (x<<8)
-+#define CPI(x) (x)
-+
-+#define RCMCONFIG 0x80780
-+#define RM_DESL2(x) (x<<10)
-+#define RM_BANK_WAIT(x) (x<<6)
-+#define RM_ADD_BANK(x) (x<<4)
-+#define RM_PAR_CHECK(x) (x<<3)
-+#define RM_RW_WAIT(x) (x<<2)
-+#define RM_SRAM_TYPE(x) (x)
-+
-+#define RCMRSRB_BA 0x80784
-+#define RCMLBM_BA 0x80788
-+#define RCMABR_BA 0x8078c
-+
-+#define RC_CONFIG 0x807c0
-+#define UT_RD_DELAY(x) (x<<11)
-+#define WRAP_MODE(x) (x<<10)
-+#define RC_UT_MODE(x) (x<<9)
-+#define RX_ENABLE (1<<8)
-+#define RX_VALVP(x) (x<<4)
-+#define RX_VALVC(x) (x)
-+
-+#define MCC 0x807c4
-+#define OEC 0x807c8
-+#define DCC 0x807cc
-+#define CEC 0x807d0
-+
-+#define HSP_BA 0x807f0
-+
-+#define LB_CONFIG 0x807f4
-+#define LB_SIZE(x) (x)
-+
-+#define CON_DAT 0x807f8
-+#define CON_CTL 0x807fc
-+#define CON_CTL_MBOX (2<<30)
-+#define CON_CTL_TCM (1<<30)
-+#define CON_CTL_RCM (0<<30)
-+#define CON_CTL_WRITE (1<<29)
-+#define CON_CTL_READ (0<<29)
-+#define CON_CTL_BUSY (1<<28)
-+#define CON_BYTE_DISABLE_3 (1<<22) /* 24..31 */
-+#define CON_BYTE_DISABLE_2 (1<<21) /* 16..23 */
-+#define CON_BYTE_DISABLE_1 (1<<20) /* 8..15 */
-+#define CON_BYTE_DISABLE_0 (1<<19) /* 0..7 */
-+#define CON_CTL_ADDR(x) (x)
-+
-+#define FRAMER 0x80800 /* to 0x80bfc */
-+
-+/* 3.3 network controller (internal) mailbox registers */
-+
-+#define CS_STPER0 0x0
-+ /* ... */
-+#define CS_STPER31 0x01f
-+
-+#define CS_STTIM0 0x020
-+ /* ... */
-+#define CS_STTIM31 0x03f
-+
-+#define CS_TGRLD0 0x040
-+ /* ... */
-+#define CS_TGRLD15 0x04f
-+
-+#define CS_ERTHR0 0x050
-+#define CS_ERTHR1 0x051
-+#define CS_ERTHR2 0x052
-+#define CS_ERTHR3 0x053
-+#define CS_ERTHR4 0x054
-+#define CS_ERCTL0 0x055
-+#define TX_ENABLE (1<<28)
-+#define ER_ENABLE (1<<27)
-+#define CS_ERCTL1 0x056
-+#define CS_ERCTL2 0x057
-+#define CS_ERSTAT0 0x058
-+#define CS_ERSTAT1 0x059
-+
-+#define CS_RTCCT 0x060
-+#define CS_RTFWC 0x061
-+#define CS_RTFWR 0x062
-+#define CS_RTFTC 0x063
-+#define CS_RTATR 0x064
-+
-+#define CS_TFBSET 0x070
-+#define CS_TFBADD 0x071
-+#define CS_TFBSUB 0x072
-+#define CS_WCRMAX 0x073
-+#define CS_WCRMIN 0x074
-+#define CS_WCRINC 0x075
-+#define CS_WCRDEC 0x076
-+#define CS_WCRCEIL 0x077
-+#define CS_BWDCNT 0x078
-+
-+#define CS_OTPPER 0x080
-+#define CS_OTWPER 0x081
-+#define CS_OTTLIM 0x082
-+#define CS_OTTCNT 0x083
-+
-+#define CS_HGRRT0 0x090
-+ /* ... */
-+#define CS_HGRRT7 0x097
-+
-+#define CS_ORPTRS 0x0a0
-+
-+#define RXCON_CLOSE 0x100
-+
-+
-+#define RCM_MEM_SIZE 0x10000 /* 1M of 32-bit registers */
-+#define TCM_MEM_SIZE 0x20000 /* 2M of 32-bit registers */
-+
-+/* 2.5 transmit connection memory registers */
-+
-+#define TSR0_CONN_STATE(x) ((x>>28) & 0x7)
-+#define TSR0_USE_WMIN (1<<23)
-+#define TSR0_GROUP(x) ((x & 0x7)<<18)
-+#define TSR0_ABR (2<<16)
-+#define TSR0_UBR (1<<16)
-+#define TSR0_CBR (0<<16)
-+#define TSR0_PROT (1<<15)
-+#define TSR0_AAL0_SDU (2<<12)
-+#define TSR0_AAL0 (1<<12)
-+#define TSR0_AAL5 (0<<12)
-+#define TSR0_HALT_ER (1<<11)
-+#define TSR0_MARK_CI (1<<10)
-+#define TSR0_MARK_ER (1<<9)
-+#define TSR0_UPDATE_GER (1<<8)
-+#define TSR0_RC_INDEX(x) (x & 0x1F)
-+
-+#define TSR1_PCR(x) ((x & 0x7FFF)<<16)
-+#define TSR1_MCR(x) (x & 0x7FFF)
-+
-+#define TSR2_ACR(x) ((x & 0x7FFF)<<16)
-+
-+#define TSR3_NRM_CNT(x) ((x & 0xFF)<<24)
-+#define TSR3_CRM_CNT(x) (x & 0xFFFF)
-+
-+#define TSR4_FLUSH_CONN (1<<31)
-+#define TSR4_SESSION_ENDED (1<<30)
-+#define TSR4_CRC10 (1<<28)
-+#define TSR4_NULL_CRC10 (1<<27)
-+#define TSR4_PROT (1<<26)
-+#define TSR4_AAL0_SDU (2<<23)
-+#define TSR4_AAL0 (1<<23)
-+#define TSR4_AAL5 (0<<23)
-+
-+#define TSR9_OPEN_CONN (1<<20)
-+
-+#define TSR11_ICR(x) ((x & 0x7FFF)<<16)
-+#define TSR11_TRM(x) ((x & 0x7)<<13)
-+#define TSR11_NRM(x) ((x & 0x7)<<10)
-+#define TSR11_ADTF(x) (x & 0x3FF)
-+
-+#define TSR13_RDF(x) ((x & 0xF)<<23)
-+#define TSR13_RIF(x) ((x & 0xF)<<19)
-+#define TSR13_CDF(x) ((x & 0x7)<<16)
-+#define TSR13_CRM(x) (x & 0xFFFF)
-+
-+#define TSR14_DELETE (1<<31)
-+#define TSR14_ABR_CLOSE (1<<16)
-+
-+/* 2.7.1 per connection receieve state registers */
-+
-+#define RSR0_START_PDU (1<<10)
-+#define RSR0_OPEN_CONN (1<<6)
-+#define RSR0_CLOSE_CONN (0<<6)
-+#define RSR0_PPD_ENABLE (1<<5)
-+#define RSR0_EPD_ENABLE (1<<4)
-+#define RSR0_TCP_CKSUM (1<<3)
-+#define RSR0_AAL5 (0)
-+#define RSR0_AAL0 (1)
-+#define RSR0_AAL0_SDU (2)
-+#define RSR0_RAWCELL (3)
-+#define RSR0_RAWCELL_CRC10 (4)
-+
-+#define RSR1_AQI_ENABLE (1<<20)
-+#define RSR1_RBPL_ONLY (1<<19)
-+#define RSR1_GROUP(x) ((x)<<16)
-+
-+#define RSR4_AQI_ENABLE (1<<30)
-+#define RSR4_GROUP(x) ((x)<<27)
-+#define RSR4_RBPL_ONLY (1<<26)
-+
-+/* 2.1.4 transmit packet descriptor */
-+
-+#define TPD_USERCELL 0x0
-+#define TPD_SEGMENT_OAMF5 0x4
-+#define TPD_END2END_OAMF5 0x5
-+#define TPD_RMCELL 0x6
-+#define TPD_CELLTYPE(x) (x<<3)
-+#define TPD_EOS (1<<2)
-+#define TPD_CLP (1<<1)
-+#define TPD_INT (1)
-+#define TPD_LST (1<<31)
-+
-+/* table 4.3 serial eeprom information */
-+
-+#define PROD_ID 0x08 /* char[] */
-+#define PROD_ID_LEN 30
-+#define HW_REV 0x26 /* char[] */
-+#define M_SN 0x3a /* integer */
-+#define MEDIA 0x3e /* integer */
-+#define HE155MM 0x26
-+#define HE155SM 0x27
-+#define HE622MM 0x46
-+#define HE622SM 0x47
-+#define MAC_ADDR 0x42 /* char[] */
-+
-+#define CS_LOW 0x0
-+#define CS_HIGH ID_CS /* HOST_CNTL_ID_PROM_SEL */
-+#define CLK_LOW 0x0
-+#define CLK_HIGH ID_CLOCK /* HOST_CNTL_ID_PROM_CLOCK */
-+#define SI_HIGH ID_DIN /* HOST_CNTL_ID_PROM_DATA_IN */
-+#define EEPROM_DELAY 400 /* microseconds */
-+
-+/* Read from EEPROM = 0000 0011b */
-+unsigned int readtab[] = {
-+ CS_HIGH | CLK_HIGH,
-+ CS_LOW | CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW,
-+ CLK_HIGH, /* 0 */
-+ CLK_LOW | SI_HIGH,
-+ CLK_HIGH | SI_HIGH, /* 1 */
-+ CLK_LOW | SI_HIGH,
-+ CLK_HIGH | SI_HIGH /* 1 */
-+};
-+
-+/* Clock to read from/write to the EEPROM */
-+unsigned int clocktab[] = {
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW,
-+ CLK_HIGH,
-+ CLK_LOW
-+};
-+
-+
-+#endif /* _HE_H_ */
-diff -urN linux-2.4.20/drivers/atm/horizon.c linux-2.4.20-atm/drivers/atm/horizon.c
---- linux-2.4.20/drivers/atm/horizon.c Sat Aug 3 02:39:43 2002
-+++ linux-2.4.20-atm/drivers/atm/horizon.c Wed May 28 01:58:41 2003
-@@ -1765,13 +1765,13 @@
-
- {
- unsigned int tx_len = skb->len;
-- unsigned int tx_iovcnt = ATM_SKB(skb)->iovcnt;
-+ unsigned int tx_nr_frags = skb_shinfo(skb)->nr_frags;
- // remember this so we can free it later
- dev->tx_skb = skb;
-
-- if (tx_iovcnt) {
-+ if (tx_nr_frags) {
- // scatter gather transfer
-- dev->tx_regions = tx_iovcnt;
-+ dev->tx_regions = tx_nr_frags;
- dev->tx_iovec = (struct iovec *) skb->data;
- dev->tx_bytes = 0;
- PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)",
-@@ -2189,14 +2189,6 @@
- }
- #endif
-
-- // deal with possibly wildcarded VCs
-- error = atm_find_ci (atm_vcc, &vpi, &vci);
-- if (error) {
-- PRINTD (DBG_WARN|DBG_VCC, "atm_find_ci failed!");
-- return error;
-- }
-- PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci);
--
- error = vpivci_to_channel (&channel, vpi, vci);
- if (error) {
- PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci);
-diff -urN linux-2.4.20/drivers/atm/idt77252.c linux-2.4.20-atm/drivers/atm/idt77252.c
---- linux-2.4.20/drivers/atm/idt77252.c Wed May 28 01:53:45 2003
-+++ linux-2.4.20-atm/drivers/atm/idt77252.c Wed May 28 01:58:41 2003
-@@ -1054,15 +1054,17 @@
- return;
- }
-
-+ read_lock(&vcc_sklist_lock);
- vc = card->vcs[VPCI2VC(card, vpi, vci)];
-- if (!vc || !test_bit(VCF_RX, &vc->flags)) {
-+ if (!vc || !test_bit(VCF_RX, &vc->flags) || !(vcc = vc->rx_vcc)) {
-+ read_unlock(&vcc_sklist_lock);
- printk("%s: SDU received on non RX vc %u.%u\n",
- card->name, vpi, vci);
- recycle_rx_skb(card, skb);
- return;
- }
--
-- vcc = vc->rx_vcc;
-+ vcc_hold(vcc);
-+ read_unlock(&vcc_sklist_lock);
-
- pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->end - skb->data, PCI_DMA_FROMDEVICE);
-@@ -1106,6 +1108,7 @@
- cell += ATM_CELL_PAYLOAD;
- }
-
-+ vcc_put(vcc);
- recycle_rx_skb(card, skb);
- return;
- }
-@@ -1113,6 +1116,7 @@
- printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n",
- card->name, vcc->qos.aal);
- recycle_rx_skb(card, skb);
-+ vcc_put(vcc);
- return;
- }
- skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD;
-@@ -1142,12 +1146,14 @@
- card->name, len, rpp->len, readl(SAR_REG_CDC));
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
-+ vcc_put(vcc);
- return;
- }
- if (stat & SAR_RSQE_CRC) {
- RXPRINTK("%s: AAL5 CRC error.\n", card->name);
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
-+ vcc_put(vcc);
- return;
- }
- if (rpp->count > 1) {
-@@ -1159,9 +1165,11 @@
- card->name);
- recycle_rx_pool_skb(card, rpp);
- atomic_inc(&vcc->stats->rx_err);
-+ vcc_put(vcc);
- return;
- }
- if (!atm_charge(vcc, skb->truesize)) {
-+ vcc_put(vcc);
- recycle_rx_pool_skb(card, rpp);
- dev_kfree_skb(skb);
- return;
-@@ -1181,6 +1189,7 @@
-
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
-+ vcc_put(vcc);
-
- return;
- }
-@@ -1189,6 +1198,7 @@
- flush_rx_pool(card, rpp);
-
- if (!atm_charge(vcc, skb->truesize)) {
-+ vcc_put(vcc);
- recycle_rx_skb(card, skb);
- return;
- }
-@@ -1212,8 +1222,10 @@
- add_rx_skb(card, 1, SAR_FB_SIZE_1, 1);
- else
- add_rx_skb(card, 0, SAR_FB_SIZE_0, 1);
-+ vcc_put(vcc);
- return;
- }
-+ vcc_put(vcc);
- }
-
- static void
-@@ -1988,7 +2000,7 @@
- return -EINVAL;
- }
-
-- if (ATM_SKB(skb)->iovcnt != 0) {
-+ if (skb_shinfo(skb)->nr_frags != 0) {
- printk("%s: No scatter-gather yet.\n", card->name);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb(skb);
-@@ -2025,8 +2037,7 @@
- atomic_inc(&vcc->stats->tx_err);
- return -ENOMEM;
- }
-- atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
-- ATM_SKB(skb)->iovcnt = 0;
-+ atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
-
- memcpy(skb_put(skb, 52), cell, 52);
-
-@@ -2349,6 +2360,7 @@
- if (test_bit(VCF_RX, &vc->flags))
- return -EBUSY;
-
-+ vcc_hold(vcc);
- vc->rx_vcc = vcc;
- set_bit(VCF_RX, &vc->flags);
-
-@@ -2403,40 +2415,6 @@
- }
-
- static int
--idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
--{
-- struct atm_vcc *walk;
--
-- if (*vpi == ATM_VPI_ANY) {
-- *vpi = 0;
-- walk = vcc->dev->vccs;
-- while (walk) {
-- if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
-- (*vpi)++;
-- walk = vcc->dev->vccs;
-- continue;
-- }
-- walk = walk->next;
-- }
-- }
--
-- if (*vci == ATM_VCI_ANY) {
-- *vci = ATM_NOT_RSV_VCI;
-- walk = vcc->dev->vccs;
-- while (walk) {
-- if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
-- (*vci)++;
-- walk = vcc->dev->vccs;
-- continue;
-- }
-- walk = walk->next;
-- }
-- }
--
-- return 0;
--}
--
--static int
- idt77252_open(struct atm_vcc *vcc, short vpi, int vci)
- {
- struct atm_dev *dev = vcc->dev;
-@@ -2446,8 +2424,6 @@
- unsigned int inuse;
- int error;
-
-- idt77252_find_vcc(vcc, &vpi, &vci);
--
- if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
- return 0;
-
-@@ -2565,6 +2541,8 @@
- spin_lock_irqsave(&vc->lock, flags);
- clear_bit(VCF_RX, &vc->flags);
- vc->rx_vcc = NULL;
-+ barrier();
-+ vcc_put(vcc);
- spin_unlock_irqrestore(&vc->lock, flags);
-
- if ((vcc->vci == 3) || (vcc->vci == 4))
-diff -urN linux-2.4.20/drivers/atm/iphase.c linux-2.4.20-atm/drivers/atm/iphase.c
---- linux-2.4.20/drivers/atm/iphase.c Wed May 28 01:53:45 2003
-+++ linux-2.4.20-atm/drivers/atm/iphase.c Wed May 28 01:58:41 2003
-@@ -1122,13 +1122,17 @@
- IF_ERR(printk("IA: bad descriptor desc = %d \n", desc);)
- return -1;
- }
-+ read_lock(&vcc_sklist_lock);
- vcc = iadev->rx_open[buf_desc_ptr->vc_index & 0xffff];
- if (!vcc)
- {
-+ read_unlock(&vcc_sklist_lock);
- free_desc(dev, desc);
- printk("IA: null vcc, drop PDU\n");
- return -1;
- }
-+ vcc_hold(vcc);
-+ read_unlock(&vcc_sklist_lock);
-
-
- /* might want to check the status bits for errors */
-@@ -1185,8 +1189,6 @@
- }
- skb_put(skb,len);
- // pwang_test
-- ATM_SKB(skb)->vcc = vcc;
-- ATM_SKB(skb)->iovcnt = 0;
- ATM_DESC(skb) = desc;
- skb_queue_tail(&iadev->rx_dma_q, skb);
-
-@@ -1205,7 +1207,8 @@
- udelay(1);
- /* Increment transaction counter */
- writel(1, iadev->dma+IPHASE5575_RX_COUNTER);
--out: return 0;
-+out: vcc_put(vcc);
-+ return 0;
- out_free_desc:
- free_desc(dev, desc);
- goto out;
-@@ -1283,6 +1286,7 @@
- struct dle *dle, *cur_dle;
- u_int dle_lp;
- int len;
-+ struct rx_buf_desc *buf_desc_ptr;
- iadev = INPH_IA_DEV(dev);
-
- /* free all the dles done, that is just update our own dle read pointer
-@@ -1293,6 +1297,7 @@
- dle = iadev->rx_dle_q.read;
- dle_lp = readl(iadev->dma+IPHASE5575_RX_LIST_ADDR) & (sizeof(struct dle)*DLE_ENTRIES - 1);
- cur_dle = (struct dle*)(iadev->rx_dle_q.start + (dle_lp >> 4));
-+ read_lock(&vcc_sklist_lock);
- while(dle != cur_dle)
- {
- /* free the DMAed skb */
-@@ -1300,6 +1305,9 @@
- if (!skb)
- goto INCR_DLE;
- desc = ATM_DESC(skb);
-+ buf_desc_ptr = (struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR;
-+ buf_desc_ptr += desc;
-+ vcc = iadev->rx_open[buf_desc_ptr->vc_index & 0xffff];
- free_desc(dev, desc);
-
- if (!(len = skb->len))
-@@ -1316,7 +1324,6 @@
- pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr,
- len, PCI_DMA_FROMDEVICE);
- /* no VCC related housekeeping done as yet. lets see */
-- vcc = ATM_SKB(skb)->vcc;
- if (!vcc) {
- printk("IA: null vcc\n");
- dev_kfree_skb_any(skb);
-@@ -1360,6 +1367,7 @@
- printk("\n");)
-
- IF_RX(printk("rx_dle_intr: skb push");)
-+ ATM_SKB(skb)->vcc = vcc;
- vcc->push(vcc,skb);
- atomic_inc(&vcc->stats->rx);
- iadev->rx_pkt_cnt++;
-@@ -1368,6 +1376,7 @@
- if (++dle == iadev->rx_dle_q.end)
- dle = iadev->rx_dle_q.start;
- }
-+ read_unlock(&vcc_sklist_lock);
- iadev->rx_dle_q.read = dle;
-
- /* if the interrupts are masked because there were no free desc available,
-@@ -1425,6 +1434,7 @@
- if (iadev->rx_open[vcc->vci])
- printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d already open\n",
- vcc->dev->number, vcc->vci);
-+ vcc_hold(vcc);
- iadev->rx_open[vcc->vci] = vcc;
- return 0;
- }
-@@ -1725,15 +1735,14 @@
- printk("tx_dle_intr: vcc is null\n");
- spin_unlock_irqrestore(&iadev->tx_lock, flags);
- dev_kfree_skb_any(skb);
--
-- return;
-+ goto cont_loop;
- }
- iavcc = INPH_IA_VCC(vcc);
- if (!iavcc) {
- printk("tx_dle_intr: iavcc is null\n");
- spin_unlock_irqrestore(&iadev->tx_lock, flags);
- dev_kfree_skb_any(skb);
-- return;
-+ goto cont_loop;
- }
- if (vcc->qos.txtp.pcr >= iadev->rate_limit) {
- if ((vcc->pop) && (skb->len != 0))
-@@ -1749,6 +1758,7 @@
- skb_queue_tail(&iavcc->txing_skb, skb);
- }
- IF_EVENT(printk("tx_dle_intr: enque skb = 0x%x \n", (u32)skb);)
-+cont_loop:
- if (++dle == iadev->tx_dle_q.end)
- dle = iadev->tx_dle_q.start;
- }
-@@ -2705,6 +2715,8 @@
- // Drain the packets
- rx_dle_intr(vcc->dev);
- iadev->rx_open[vcc->vci] = 0;
-+ barrier();
-+ vcc_put(vcc);
- }
- kfree(INPH_IA_VCC(vcc));
- ia_vcc = NULL;
-@@ -2724,12 +2736,6 @@
- INPH_IA_VCC(vcc) = NULL;
- }
- iadev = INPH_IA_DEV(vcc->dev);
-- error = atm_find_ci(vcc, &vpi, &vci);
-- if (error)
-- {
-- printk("iadev: atm_find_ci returned error %d\n", error);
-- return error;
-- }
- vcc->vpi = vpi;
- vcc->vci = vci;
- if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
-diff -urN linux-2.4.20/drivers/atm/lanai.c linux-2.4.20-atm/drivers/atm/lanai.c
---- linux-2.4.20/drivers/atm/lanai.c Fri Nov 29 00:53:12 2002
-+++ linux-2.4.20-atm/drivers/atm/lanai.c Wed May 28 01:58:41 2003
-@@ -1820,10 +1820,10 @@
- {
- vci_t vci = SERVICE_GET_VCI(s);
- struct lanai_vcc *lvcc;
-- vcclist_read_lock();
-+ read_lock(&vcc_sklist_lock);
- lvcc = lanai->vccs[vci];
- if (lvcc == NULL) {
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- DPRINTK("(itf %d) got service entry 0x%X for nonexistent "
- "vcc %d\n", lanai->number, s, vci);
- if (s & SERVICE_TX)
-@@ -1834,7 +1834,7 @@
- }
- if (s & SERVICE_TX) { /* segmentation interrupt */
- if (lvcc->tx.atmvcc == NULL) {
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- DPRINTK("(itf %d) got service entry 0x%X for non-TX "
- "vcc %d\n", lanai->number, s, vci);
- lanai->stats.service_notx++;
-@@ -1842,18 +1842,18 @@
- }
- vci_bitfield_set(&lanai->transmit_ready, vci);
- lvcc->tx.endptr = SERVICE_GET_END(s);
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- return 1;
- }
- if (lvcc->rx.atmvcc == NULL) {
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- DPRINTK("(itf %d) got service entry 0x%X for non-RX "
- "vcc %d\n", lanai->number, s, vci);
- lanai->stats.service_norx++;
- return 0;
- }
- if (lvcc->rx.atmvcc->qos.aal != ATM_AAL5) {
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 "
- "vcc %d\n", lanai->number, s, vci);
- lanai->stats.service_rxnotaal5++;
-@@ -1862,12 +1862,12 @@
- }
- if ((s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)) == 0) {
- vcc_rx_aal5(lvcc, SERVICE_GET_END(s));
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- return 0;
- }
- if (s & SERVICE_TRASH) {
- int bytes;
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- DPRINTK("got trashed rx pdu on vci %d\n", vci);
- atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
- lvcc->stats.x.aal5.service_trash++;
-@@ -1880,7 +1880,7 @@
- return 0;
- }
- if (s & SERVICE_STREAM) {
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
- lvcc->stats.x.aal5.service_stream++;
- printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream "
-@@ -1893,7 +1893,7 @@
- lvcc->stats.x.aal5.service_rxcrc++;
- lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4];
- cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr);
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- return 0;
- }
-
-@@ -1924,11 +1924,11 @@
- reg_write(lanai, wreg, ServRead_Reg);
- if (ntx != 0) {
- spin_lock(&lanai->txlock);
-- vcclist_read_lock();
-+ read_lock(&vcc_sklist_lock);
- vci_bitfield_iterate(lanai, &lanai->transmit_ready,
- iter_transmit);
- vci_bitfield_init(&lanai->transmit_ready);
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- spin_unlock(&lanai->txlock);
- }
- }
-@@ -2785,7 +2785,7 @@
- return sprintf(page, "resets: dma=%d, card=%d\n",
- lanai->stats.dma_reenable, lanai->stats.card_reset);
- /* At this point, "left" should be the VCI we're looking for */
-- vcclist_read_lock();
-+ read_lock(&vcc_sklist_lock);
- for (; ; left++) {
- if (left >= NUM_VCI) {
- left = 0;
-@@ -2821,7 +2821,7 @@
- page[left++] = '\n';
- page[left] = '\0';
- out:
-- vcclist_read_unlock();
-+ read_unlock(&vcc_sklist_lock);
- return left;
- }
- #endif /* CONFIG_PROC_FS */
-@@ -2842,7 +2842,6 @@
- phy_get: NULL,
- feedback: NULL,
- change_qos: lanai_change_qos,
-- free_rx_skb: NULL,
- proc_read: lanai_proc_read
- };
-
-diff -urN linux-2.4.20/drivers/atm/nicstar.c linux-2.4.20-atm/drivers/atm/nicstar.c
---- linux-2.4.20/drivers/atm/nicstar.c Wed May 28 01:53:45 2003
-+++ linux-2.4.20-atm/drivers/atm/nicstar.c Wed May 28 01:58:41 2003
-@@ -941,9 +941,15 @@
- return error;
- }
-
-- if (ns_parse_mac(mac[i], card->atmdev->esi))
-+ if (ns_parse_mac(mac[i], card->atmdev->esi)) {
- nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
- card->atmdev->esi, 6);
-+ if (!memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6)) {
-+ nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
-+ card->atmdev->esi, 6);
-+ }
-+ }
-+
-
- printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i,
- card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2],
-@@ -1433,7 +1439,6 @@
- {
- ns_dev *card;
- vc_map *vc;
-- int error;
- unsigned long tmpl, modl;
- int tcr, tcra; /* target cell rate, and absolute value */
- int n = 0; /* Number of entries in the TST. Initialized to remove
-@@ -1453,11 +1458,6 @@
- return -EINVAL;
- }
-
-- if ((error = atm_find_ci(vcc, &vpi, &vci)))
-- {
-- PRINTK("nicstar%d: error in atm_find_ci().\n", card->index);
-- return error;
-- }
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
- vcc->vpi = vpi;
- vcc->vci = vci;
-@@ -1597,6 +1597,7 @@
- u32 status;
-
- vc->rx = 1;
-+ vcc_hold(vcc);
- vc->rx_vcc = vcc;
- vc->rx_iov = NULL;
-
-@@ -1646,6 +1647,9 @@
- spin_unlock_irqrestore(&card->res_lock, flags);
-
- vc->rx = 0;
-+ vc->rx_vcc = NULL;
-+ barrier();
-+ vcc_put(vcc);
- if (vc->rx_iov != NULL)
- {
- struct sk_buff *iovb;
-@@ -1659,9 +1663,9 @@
- card->index);
- iovb = vc->rx_iov;
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-- ATM_SKB(iovb)->iovcnt);
-- ATM_SKB(iovb)->iovcnt = 0;
-- ATM_SKB(iovb)->vcc = NULL;
-+ NS_SKB(iovb)->iovcnt);
-+ NS_SKB(iovb)->iovcnt = 0;
-+ NS_SKB(iovb)->vcc = NULL;
- ns_grab_int_lock(card, flags);
- recycle_iov_buf(card, iovb);
- spin_unlock_irqrestore(&card->int_lock, flags);
-@@ -1859,7 +1863,7 @@
- return -EINVAL;
- }
-
-- if (ATM_SKB(skb)->iovcnt != 0)
-+ if (skb_shinfo(skb)->nr_frags != 0)
- {
- printk("nicstar%d: No scatter-gather yet.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
-@@ -2203,16 +2207,18 @@
- return;
- }
-
-+ read_lock(&vcc_sklist_lock);
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
-- if (!vc->rx)
-+ if (!vc->rx || !(vcc = vc->rx_vcc))
- {
-+ read_unlock(&vcc_sklist_lock);
- RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
- card->index, vpi, vci);
- recycle_rx_buf(card, skb);
- return;
- }
--
-- vcc = vc->rx_vcc;
-+ vcc_hold(vcc);
-+ read_unlock(&vcc_sklist_lock);
-
- if (vcc->qos.aal == ATM_AAL0)
- {
-@@ -2252,7 +2258,7 @@
- atomic_inc(&vcc->stats->rx);
- cell += ATM_CELL_PAYLOAD;
- }
--
-+ vcc_put(vcc);
- recycle_rx_buf(card, skb);
- return;
- }
-@@ -2269,6 +2275,7 @@
- {
- printk("nicstar%d: Out of iovec buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
-+ vcc_put(vcc);
- recycle_rx_buf(card, skb);
- return;
- }
-@@ -2284,30 +2291,30 @@
- }
- }
- vc->rx_iov = iovb;
-- ATM_SKB(iovb)->iovcnt = 0;
-+ NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->tail = iovb->data = iovb->head;
-- ATM_SKB(iovb)->vcc = vcc;
-+ NS_SKB(iovb)->vcc = vcc;
- /* IMPORTANT: a pointer to the sk_buff containing the small or large
- buffer is stored as iovec base, NOT a pointer to the
- small or large buffer itself. */
- }
-- else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
-+ else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
- {
- printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
-- ATM_SKB(iovb)->iovcnt = 0;
-+ NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->tail = iovb->data = iovb->head;
-- ATM_SKB(iovb)->vcc = vcc;
-+ NS_SKB(iovb)->vcc = vcc;
- }
-- iov = &((struct iovec *) iovb->data)[ATM_SKB(iovb)->iovcnt++];
-+ iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
- iov->iov_base = (void *) skb;
- iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
- iovb->len += iov->iov_len;
-
-- if (ATM_SKB(iovb)->iovcnt == 1)
-+ if (NS_SKB(iovb)->iovcnt == 1)
- {
- if (skb->list != &card->sbpool.queue)
- {
-@@ -2317,11 +2324,12 @@
- atomic_inc(&vcc->stats->rx_err);
- recycle_rx_buf(card, skb);
- vc->rx_iov = NULL;
-+ vcc_put(vcc);
- recycle_iov_buf(card, iovb);
- return;
- }
- }
-- else /* ATM_SKB(iovb)->iovcnt >= 2 */
-+ else /* NS_SKB(iovb)->iovcnt >= 2 */
- {
- if (skb->list != &card->lbpool.queue)
- {
-@@ -2330,8 +2338,9 @@
- which_list(card, skb);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-- ATM_SKB(iovb)->iovcnt);
-+ NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
-+ vcc_put(vcc);
- recycle_iov_buf(card, iovb);
- return;
- }
-@@ -2354,15 +2363,16 @@
- printk(".\n");
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-- ATM_SKB(iovb)->iovcnt);
-+ NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
-+ vcc_put(vcc);
- recycle_iov_buf(card, iovb);
- return;
- }
-
- /* By this point we (hopefully) have a complete SDU without errors. */
-
-- if (ATM_SKB(iovb)->iovcnt == 1) /* Just a small buffer */
-+ if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */
- {
- /* skb points to a small buffer */
- if (!atm_charge(vcc, skb->truesize))
-@@ -2384,7 +2394,7 @@
- atomic_inc(&vcc->stats->rx);
- }
- }
-- else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
-+ else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
- {
- struct sk_buff *sb;
-
-@@ -2461,8 +2471,9 @@
- printk("nicstar%d: Out of huge buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-- ATM_SKB(iovb)->iovcnt);
-+ NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
-+ vcc_put(vcc);
- recycle_iov_buf(card, iovb);
- return;
- }
-@@ -2499,7 +2510,7 @@
-
- if (!atm_charge(vcc, hb->truesize))
- {
-- recycle_iovec_rx_bufs(card, iov, ATM_SKB(iovb)->iovcnt);
-+ recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt);
- if (card->hbpool.count < card->hbnr.max)
- {
- skb_queue_tail(&card->hbpool.queue, hb);
-@@ -2522,7 +2533,7 @@
- 0, 0);
-
- /* Copy all large buffers to the huge buffer and free them */
-- for (j = 1; j < ATM_SKB(iovb)->iovcnt; j++)
-+ for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
- {
- lb = (struct sk_buff *) iov->iov_base;
- tocopy = MIN(remaining, iov->iov_len);
-@@ -2550,7 +2561,7 @@
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- }
--
-+ vcc_put(vcc);
- }
-
-
-diff -urN linux-2.4.20/drivers/atm/nicstar.h linux-2.4.20-atm/drivers/atm/nicstar.h
---- linux-2.4.20/drivers/atm/nicstar.h Thu Oct 25 22:53:46 2001
-+++ linux-2.4.20-atm/drivers/atm/nicstar.h Wed May 28 01:58:41 2003
-@@ -96,6 +96,7 @@
- /* ESI stuff ******************************************************************/
-
- #define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C
-+#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6
-
-
- /* #defines *******************************************************************/
-@@ -748,6 +749,14 @@
- int tbd_count;
- } vc_map;
-
-+
-+struct ns_skb_data
-+{
-+ struct atm_vcc *vcc;
-+ int iovcnt;
-+};
-+
-+#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb))
-
- typedef struct ns_dev
- {
-diff -urN linux-2.4.20/drivers/atm/zatm.c linux-2.4.20-atm/drivers/atm/zatm.c
---- linux-2.4.20/drivers/atm/zatm.c Fri Sep 14 23:40:00 2001
-+++ linux-2.4.20-atm/drivers/atm/zatm.c Wed May 28 01:58:41 2003
-@@ -827,10 +827,10 @@
- vcc = ATM_SKB(skb)->vcc;
- zatm_dev = ZATM_DEV(vcc->dev);
- zatm_vcc = ZATM_VCC(vcc);
-- EVENT("iovcnt=%d\n",ATM_SKB(skb)->iovcnt,0);
-+ EVENT("nr_frags=%d\n",skb_shinfo(skb)->nr_frags,0);
- save_flags(flags);
- cli();
-- if (!ATM_SKB(skb)->iovcnt) {
-+ if (!skb_shinfo(skb)->nr_frags) {
- if (zatm_vcc->txing == RING_ENTRIES-1) {
- restore_flags(flags);
- return RING_BUSY;
-@@ -1579,8 +1579,6 @@
- DPRINTK(">zatm_open\n");
- zatm_dev = ZATM_DEV(vcc->dev);
- if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL;
-- error = atm_find_ci(vcc,&vpi,&vci);
-- if (error) return error;
- vcc->vpi = vpi;
- vcc->vci = vci;
- if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
-diff -urN linux-2.4.20/include/linux/atm_he.h linux-2.4.20-atm/include/linux/atm_he.h
---- linux-2.4.20/include/linux/atm_he.h Thu Jan 1 01:00:00 1970
-+++ linux-2.4.20-atm/include/linux/atm_he.h Wed May 28 01:58:41 2003
-@@ -0,0 +1,20 @@
-+/* atm_he.h */
-+
-+#ifndef LINUX_ATM_HE_H
-+#define LINUX_ATM_HE_H
-+
-+#include <linux/atmioc.h>
-+
-+#define HE_GET_REG _IOW('a', ATMIOC_SARPRV, struct atmif_sioc)
-+
-+#define HE_REGTYPE_PCI 1
-+#define HE_REGTYPE_RCM 2
-+#define HE_REGTYPE_TCM 3
-+#define HE_REGTYPE_MBOX 4
-+
-+struct he_ioctl_reg {
-+ unsigned addr, val;
-+ char type;
-+};
-+
-+#endif /* LINUX_ATM_HE_H */
-diff -urN linux-2.4.20/include/linux/atm_tcp.h linux-2.4.20-atm/include/linux/atm_tcp.h
---- linux-2.4.20/include/linux/atm_tcp.h Fri Dec 29 23:35:47 2000
-+++ linux-2.4.20-atm/include/linux/atm_tcp.h Wed May 28 01:58:41 2003
-@@ -68,7 +68,7 @@
- struct module *owner;
- };
-
--extern struct atm_tcp_ops atm_tcp_ops;
-+extern struct atm_tcp_ops *atm_tcp_ops;
-
- #endif
-
-diff -urN linux-2.4.20/include/linux/atmdev.h linux-2.4.20-atm/include/linux/atmdev.h
---- linux-2.4.20/include/linux/atmdev.h Wed May 28 01:54:12 2003
-+++ linux-2.4.20-atm/include/linux/atmdev.h Wed May 28 01:58:41 2003
-@@ -30,10 +30,9 @@
- #define ATM_DS3_PCR (8000*12)
- /* DS3: 12 cells in a 125 usec time slot */
-
--#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 \
-@@ -292,10 +291,6 @@
- struct atm_sap sap; /* SAP */
- 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);
-- /* TX allocation routine - can be */
-- /* modified by protocol or by driver.*/
-- /* NOTE: this interface will change */
- int (*push_oam)(struct atm_vcc *vcc,void *cell);
- int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
- void *dev_data; /* per-device data */
-@@ -303,15 +298,10 @@
- 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 */
-- struct atm_vcc *prev,*next;
- /* SVC part --- may move later ------------------------------------- */
-- short itf; /* interface number */
- struct sockaddr_atmsvc local;
- struct sockaddr_atmsvc remote;
- void (*callback)(struct atm_vcc *vcc);
-- struct sk_buff_head listenq;
-- int backlog_quota; /* number of connection requests we */
-- /* can still accept */
- int reply; /* also used by ATMTCP */
- /* Multipoint part ------------------------------------------------- */
- struct atm_vcc *session; /* session VCC descriptor */
-@@ -337,8 +327,6 @@
- /* (NULL) */
- const char *type; /* device type name */
- int number; /* device index */
-- struct atm_vcc *vccs; /* VCC table (or NULL) */
-- 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_*) */
-@@ -348,6 +336,8 @@
- struct k_atm_dev_stats stats; /* statistics */
- char signal; /* signal status (ATM_PHY_SIG_*) */
- int link_rate; /* link rate (default: OC3) */
-+ atomic_t refcnt; /* reference count */
-+ spinlock_t lock; /* protect internal members */
- #ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc_entry; /* proc entry */
- char *proc_name; /* proc entry name */
-@@ -388,8 +378,6 @@
- void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb,
- unsigned long start,unsigned long dest,int len);
- int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags);
-- void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
-- /* @@@ temporary hack */
- int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
- struct module *owner;
- };
-@@ -404,53 +392,94 @@
-
- struct atm_skb_data {
- struct atm_vcc *vcc; /* ATM VCC */
-- int iovcnt; /* 0 for "normal" operation */
- unsigned long atm_options; /* ATM layer options */
- };
-
-+extern struct sock *vcc_sklist;
-+extern rwlock_t vcc_sklist_lock;
-+
- #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 */
--struct atm_dev *atm_find_dev(int number);
- void atm_dev_deregister(struct atm_dev *dev);
-+struct atm_dev *atm_dev_lookup(int number);
-+void atm_dev_hold(struct atm_dev *dev);
-+void atm_dev_release(struct atm_dev *dev);
- void shutdown_atm_dev(struct atm_dev *dev);
--void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
-+void vcc_insert_socket(struct atm_dev *dev, struct sock *sk);
-+void vcc_remove_socket(struct atm_dev *dev, struct sock *sk);
-
-
--/*
-- * This is approximately the algorithm used by alloc_skb.
-- *
-- */
-+static inline int atm_guess_pdu2truesize(int pdu_size)
-+{
-+ /* must match allocation in alloc_skb */
-+ return SKB_DATA_ALIGN(pdu_size) + sizeof(struct sk_buff);
-+}
-+
-
--static __inline__ int atm_guess_pdu2truesize(int pdu_size)
-+static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
- {
-- return ((pdu_size+15) & ~15) + sizeof(struct sk_buff);
-+ atomic_add(truesize, &vcc->sk->rmem_alloc);
- }
-
-
--static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize)
-+static inline void atm_return(struct atm_vcc *vcc,int truesize)
- {
-- atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
-+ atomic_sub(truesize, &vcc->sk->rmem_alloc);
-+}
-+
-+
-+static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
-+{
-+ return (size+atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf;
-+}
-+
-+
-+static inline struct atm_vcc *__vcc_lookup(struct atm_dev *dev, short vpi, int vci)
-+{
-+ struct atm_vcc *vcc;
-+ struct sock *s;
-+
-+ for(s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
-+ if (vcc->vci == vci && vcc->vpi == vpi && vcc->dev == dev) return vcc;
-+ }
-+
-+ return NULL;
-+}
-+
-+
-+static inline struct atm_vcc *vcc_lookup(struct atm_dev *dev, short vpi, int vci)
-+{
-+ struct atm_vcc *vcc;
-+
-+ read_lock(&vcc_sklist_lock);
-+ if ((vcc = __vcc_lookup(dev, vpi, vci))) {
-+ sock_hold(vcc->sk);
-+ read_unlock(&vcc_sklist_lock);
-+ return vcc;
-+ }
-+ read_unlock(&vcc_sklist_lock);
-+ return NULL;
- }
-
-
--static __inline__ void atm_return(struct atm_vcc *vcc,int truesize)
-+static inline void vcc_hold(struct atm_vcc *vcc)
- {
-- atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
-+ sock_hold(vcc->sk);
- }
-
-
--static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size)
-+static inline void vcc_put(struct atm_vcc *vcc)
- {
-- return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf;
-+ sock_put(vcc->sk);
- }
-
-
- int atm_charge(struct atm_vcc *vcc,int truesize);
- struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
- int gfp_flags);
--int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci);
- int atm_pcr_goal(struct atm_trafprm *tp);
-
- void atm_async_release_vcc(struct atm_vcc *vcc,int reply);
-diff -urN linux-2.4.20/include/linux/net.h linux-2.4.20-atm/include/linux/net.h
---- linux-2.4.20/include/linux/net.h Thu Nov 22 20:46:19 2001
-+++ linux-2.4.20-atm/include/linux/net.h Wed May 28 01:58:41 2003
-@@ -139,6 +139,7 @@
- extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags);
- extern int sock_readv_writev(int type, struct inode * inode, struct file * file,
- const struct iovec * iov, long count, long size);
-+extern struct socket *sockfd_lookup(int fd, int *err);
-
- extern int net_ratelimit(void);
- extern unsigned long net_random(void);
-diff -urN linux-2.4.20/include/net/atmclip.h linux-2.4.20-atm/include/net/atmclip.h
---- linux-2.4.20/include/net/atmclip.h Thu Nov 22 20:49:31 2001
-+++ linux-2.4.20-atm/include/net/atmclip.h Wed May 28 01:58:41 2003
-@@ -55,13 +55,27 @@
- };
-
-
--extern struct atm_vcc *atmarpd; /* ugly */
- extern struct neigh_table clip_tbl;
-+extern struct atm_vcc *atmarpd; /* ugly */
-
- 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 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 module *owner;
-+};
-+
-+#ifdef __KERNEL__
-+extern struct neigh_table *clip_tbl_hook;
-+extern struct atm_clip_ops *atm_clip_ops;
-+#endif
-
- #endif
-diff -urN linux-2.4.20/net/Config.in linux-2.4.20-atm/net/Config.in
---- linux-2.4.20/net/Config.in Sat Aug 3 02:39:46 2002
-+++ linux-2.4.20-atm/net/Config.in Wed May 28 01:58:41 2003
-@@ -31,19 +31,19 @@
- fi
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-- bool 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM
-- if [ "$CONFIG_ATM" = "y" ]; then
-+ tristate 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM
-+ if [ "$CONFIG_ATM" != "n" ]; then
- if [ "$CONFIG_INET" = "y" ]; then
-- bool ' Classical IP over ATM' CONFIG_ATM_CLIP
-+ dep_tristate ' Classical IP over ATM' CONFIG_ATM_CLIP $CONFIG_ATM
- 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
-+ dep_tristate ' LAN Emulation (LANE) support' CONFIG_ATM_LANE $CONFIG_ATM
- if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
-- tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA
-+ dep_tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA $CONFIG_ATM
- fi
-- tristate ' RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684
-+ dep_tristate ' RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684 $CONFIG_ATM
- if [ "$CONFIG_ATM_BR2684" != "n" ]; then
- bool ' Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER
- fi
-diff -urN linux-2.4.20/net/atm/Makefile linux-2.4.20-atm/net/atm/Makefile
---- linux-2.4.20/net/atm/Makefile Sat Aug 3 02:39:46 2002
-+++ linux-2.4.20-atm/net/atm/Makefile Wed May 28 01:58:41 2003
-@@ -14,32 +14,24 @@
- 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
-+obj-m := $(O_TARGET)
-
--ifeq ($(CONFIG_ATM_CLIP),y)
--obj-y += clip.o
--NEED_IPCOM = ipcommon.o
--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_CLIP) += clip.o
- obj-$(CONFIG_ATM_BR2684) += br2684.o
-
--ifeq ($(CONFIG_NET_SCH_ATM),y)
--NEED_IPCOM = ipcommon.o
-+ifneq ($(CONFIG_ATM_CLIP),n)
-+ ip-common-obj-y = ipcommon.o
- endif
--
--obj-y += $(NEED_IPCOM)
--
--ifeq ($(CONFIG_PROC_FS),y)
--obj-y += proc.o
-+ifneq ($(CONFIG_ATM_BR2684),n)
-+ ip-common-obj-y = ipcommon.o
-+endif
-+ifneq ($(CONFIG_NET_SCH_ATM),n)
-+ ip-common-obj-y = ipcommon.o
- endif
-+obj-y += $(ip-common-obj-y)
-
-+obj-$(CONFIG_PROC_FS) += proc.o
- obj-$(CONFIG_ATM_LANE) += lec.o
- obj-$(CONFIG_ATM_MPOA) += mpoa.o
- obj-$(CONFIG_PPPOATM) += pppoatm.o
-diff -urN linux-2.4.20/net/atm/addr.c linux-2.4.20-atm/net/atm/addr.c
---- linux-2.4.20/net/atm/addr.c Fri Apr 6 19:51:19 2001
-+++ linux-2.4.20-atm/net/atm/addr.c Wed May 28 01:58:41 2003
-@@ -36,14 +36,6 @@
- }
-
-
--/*
-- * Avoid modification of any list of local interfaces while reading it
-- * (which may involve page faults and therefore rescheduling)
-- */
--
--static DECLARE_MUTEX(local_lock);
--extern spinlock_t atm_dev_lock;
--
- static void notify_sigd(struct atm_dev *dev)
- {
- struct sockaddr_atmpvc pvc;
-@@ -60,13 +52,13 @@
- {
- struct atm_dev_addr *this;
-
-- down(&local_lock);
-+ spin_lock(&dev->lock);
- while (dev->local) {
- this = dev->local;
- dev->local = this->next;
- kfree(this);
- }
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- notify_sigd(dev);
- }
-
-@@ -78,20 +70,20 @@
-
- error = check_addr(addr);
- if (error) return error;
-- down(&local_lock);
-+ spin_lock(&dev->lock);
- for (walk = &dev->local; *walk; walk = &(*walk)->next)
- if (identical(&(*walk)->addr,addr)) {
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return -EEXIST;
- }
-- *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
-+ *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_ATOMIC);
- if (!*walk) {
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return -ENOMEM;
- }
- (*walk)->addr = *addr;
- (*walk)->next = NULL;
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- notify_sigd(dev);
- return 0;
- }
-@@ -104,17 +96,17 @@
-
- error = check_addr(addr);
- if (error) return error;
-- down(&local_lock);
-+ spin_lock(&dev->lock);
- for (walk = &dev->local; *walk; walk = &(*walk)->next)
- if (identical(&(*walk)->addr,addr)) break;
- if (!*walk) {
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return -ENOENT;
- }
- this = *walk;
- *walk = this->next;
-+ spin_unlock(&dev->lock);
- kfree(this);
-- up(&local_lock);
- notify_sigd(dev);
- return 0;
- }
-@@ -125,21 +117,21 @@
- struct atm_dev_addr *walk;
- int total;
-
-- down(&local_lock);
-+ spin_lock(&dev->lock);
- total = 0;
- for (walk = dev->local; walk; walk = walk->next) {
- total += sizeof(struct sockaddr_atmsvc);
- if (total > size) {
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return -E2BIG;
- }
- if (copy_to_user(u_buf,&walk->addr,
- sizeof(struct sockaddr_atmsvc))) {
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return -EFAULT;
- }
- u_buf++;
- }
-- up(&local_lock);
-+ spin_unlock(&dev->lock);
- return total;
- }
-diff -urN linux-2.4.20/net/atm/atm_misc.c linux-2.4.20-atm/net/atm/atm_misc.c
---- linux-2.4.20/net/atm/atm_misc.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/atm_misc.c Wed May 28 01:58:41 2003
-@@ -43,63 +43,6 @@
- }
-
-
--static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
--{
-- struct atm_vcc *walk;
--
-- for (walk = vcc->dev->vccs; walk; walk = walk->next)
-- if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
-- walk->vci == vci && ((walk->qos.txtp.traffic_class !=
-- ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
-- (walk->qos.rxtp.traffic_class != ATM_NONE &&
-- vcc->qos.rxtp.traffic_class != ATM_NONE)))
-- return -EADDRINUSE;
-- /* allow VCCs with same VPI/VCI iff they don't collide on
-- TX/RX (but we may refuse such sharing for other reasons,
-- e.g. if protocol requires to have both channels) */
-- return 0;
--}
--
--
--int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
--{
-- static short p = 0; /* poor man's per-device cache */
-- static int c = 0;
-- short old_p;
-- int old_c;
--
-- if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY)
-- return check_ci(vcc,*vpi,*vci);
-- /* last scan may have left values out of bounds for current device */
-- if (*vpi != ATM_VPI_ANY) p = *vpi;
-- else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
-- if (*vci != ATM_VCI_ANY) c = *vci;
-- else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
-- c = ATM_NOT_RSV_VCI;
-- old_p = p;
-- old_c = c;
-- do {
-- if (!check_ci(vcc,p,c)) {
-- *vpi = p;
-- *vci = c;
-- return 0;
-- }
-- if (*vci == ATM_VCI_ANY) {
-- c++;
-- if (c >= 1 << vcc->dev->ci_range.vci_bits)
-- c = ATM_NOT_RSV_VCI;
-- }
-- if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
-- *vpi == ATM_VPI_ANY) {
-- p++;
-- if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
-- }
-- }
-- while (old_p != p || old_c != c);
-- return -EADDRINUSE;
--}
--
--
- /*
- * atm_pcr_goal returns the positive PCR if it should be rounded up, the
- * negative PCR if it should be rounded down, and zero if the maximum available
-@@ -155,7 +98,6 @@
-
- EXPORT_SYMBOL(atm_charge);
- EXPORT_SYMBOL(atm_alloc_charge);
--EXPORT_SYMBOL(atm_find_ci);
- EXPORT_SYMBOL(atm_pcr_goal);
- EXPORT_SYMBOL(sonet_copy_stats);
- EXPORT_SYMBOL(sonet_subtract_stats);
-diff -urN linux-2.4.20/net/atm/br2684.c linux-2.4.20-atm/net/atm/br2684.c
---- linux-2.4.20/net/atm/br2684.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/br2684.c Wed May 28 01:58:41 2003
-@@ -189,7 +189,6 @@
- return 0;
- }
- 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++;
- brdev->stats.tx_bytes += skb->len;
-diff -urN linux-2.4.20/net/atm/clip.c linux-2.4.20-atm/net/atm/clip.c
---- linux-2.4.20/net/atm/clip.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/clip.c Wed May 28 01:58:41 2003
-@@ -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,7 +49,6 @@
- static struct timer_list idle_timer;
- static int start_timer = 1;
-
--
- static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
- {
- struct atmarp_ctrl *ctrl;
-@@ -127,6 +127,8 @@
- struct atmarp_entry *entry = NEIGH2ENTRY(n);
- struct clip_vcc *clip_vcc;
-
-+ write_lock(&n->lock);
-+
- for (clip_vcc = entry->vccs; clip_vcc;
- clip_vcc = clip_vcc->next)
- if (clip_vcc->idle_timeout &&
-@@ -140,6 +142,7 @@
- }
- if (entry->vccs ||
- time_before(jiffies, entry->expires)) {
-+ write_unlock(&n->lock);
- np = &n->next;
- continue;
- }
-@@ -151,12 +154,14 @@
- while ((skb = skb_dequeue(&n->arp_queue)) !=
- NULL)
- dev_kfree_skb(skb);
-+ write_unlock(&n->lock);
- np = &n->next;
- continue;
- }
- *np = n->next;
- DPRINTK("expired neigh %p\n",n);
- n->dead = 1;
-+ write_unlock(&n->lock);
- neigh_release(n);
- }
- }
-@@ -218,6 +223,7 @@
- clip_vcc->last_use = jiffies;
- PRIV(skb->dev)->stats.rx_packets++;
- PRIV(skb->dev)->stats.rx_bytes += skb->len;
-+ memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(skb);
- }
-
-@@ -427,7 +433,6 @@
- ((u16 *) here)[3] = skb->protocol;
- }
- 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;
- DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
-@@ -694,25 +699,21 @@
- printk(KERN_ERR "atmarpd_close: closing with requests "
- "pending\n");
- skb_queue_purge(&vcc->sk->receive_queue);
-+ MOD_DEC_USE_COUNT;
- DPRINTK("(done)\n");
- }
-
-
- static struct atmdev_ops atmarpd_dev_ops = {
-- close: atmarpd_close,
-+ .close = atmarpd_close,
- };
-
-
- static struct atm_dev atmarpd_dev = {
-- &atmarpd_dev_ops,
-- NULL, /* no PHY */
-- "arpd", /* type */
-- 999, /* dummy device number */
-- NULL,NULL, /* pretend not to have any VCCs */
-- NULL,NULL, /* no data */
-- { 0 }, /* no flags */
-- NULL, /* no local address */
-- { 0 } /* no ESI, no statistics */
-+ .ops = &atmarpd_dev_ops,
-+ .type = "arpd",
-+ .number = 999,
-+ .lock = SPIN_LOCK_UNLOCKED
- };
-
-
-@@ -732,7 +733,7 @@
- set_bit(ATM_VF_META,&vcc->flags);
- set_bit(ATM_VF_READY,&vcc->flags);
- /* allow replies and avoid getting closed if signaling dies */
-- bind_vcc(vcc,&atmarpd_dev);
-+ vcc_insert_socket(&atmarpd_dev, vcc->sk);
- vcc->push = NULL;
- vcc->pop = NULL; /* crash */
- vcc->push_oam = NULL; /* crash */
-@@ -746,10 +747,59 @@
- 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,
-+ .owner = THIS_MODULE
-+};
-
--void atm_clip_init(void)
-+static int __init atm_clip_init(void)
- {
-+ /* we should use neigh_table_init() */
- 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);
-+
-+
-+ /* so neigh_ifdown() doesn't complain */
-+ clip_tbl.proxy_timer.data = 0;
-+ clip_tbl.proxy_timer.function = 0;
-+ init_timer(&clip_tbl.proxy_timer);
-+ skb_queue_head_init(&clip_tbl.proxy_queue);
-+
-+
-+ atm_clip_ops = &__atm_clip_ops;
-+
-+ clip_tbl_hook = &clip_tbl;
-+
-+ return 0;
- }
-+
-+static void __exit atm_clip_exit(void)
-+{
-+ struct net_device *dev, *next;
-+
-+ atm_clip_ops = NULL;
-+ clip_tbl_hook = NULL;
-+
-+ neigh_ifdown(&clip_tbl, NULL);
-+ dev = clip_devs;
-+ while (dev) {
-+ next = PRIV(dev)->next;
-+ unregister_netdev(dev);
-+ kfree(dev);
-+ dev = next;
-+ }
-+ 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");
-diff -urN linux-2.4.20/net/atm/common.c linux-2.4.20-atm/net/atm/common.c
---- linux-2.4.20/net/atm/common.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/common.c Wed May 28 02:03:31 2003
-@@ -5,6 +5,7 @@
-
- #include <linux/config.h>
- #include <linux/module.h>
-+#include <linux/init.h>
- #include <linux/kmod.h>
- #include <linux/net.h> /* struct socket, struct net_proto, struct
- proto_ops */
-@@ -27,21 +27,22 @@
- #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>
- #include "lec.h"
- #include "lec_arpc.h"
--struct atm_lane_ops atm_lane_ops;
--#endif
-+struct atm_lane_ops *atm_lane_ops;
- #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;
- #endif
- #ifdef CONFIG_ATM_MPOA_MODULE
- EXPORT_SYMBOL(atm_mpoa_ops);
-@@ -52,12 +53,20 @@
-
- #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
- #include <linux/atm_tcp.h>
-+struct atm_tcp_ops *atm_tcp_ops;
- #ifdef CONFIG_ATM_TCP_MODULE
--struct atm_tcp_ops atm_tcp_ops;
- EXPORT_SYMBOL(atm_tcp_ops);
- #endif
- #endif
-
-+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-+#include <net/atmclip.h>
-+struct atm_clip_ops *atm_clip_ops;
-+#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);
-@@ -74,9 +83,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 */
-
-
-@@ -86,8 +92,6 @@
- #define DPRINTK(format,args...)
- #endif
-
--spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
--
- static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
- {
- struct sk_buff *skb;
-@@ -99,78 +103,94 @@
- }
- while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
- DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize);
-- atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
-+ atomic_add(skb->truesize,&vcc->sk->wmem_alloc);
- return skb;
- }
-
-
--int atm_create(struct socket *sock,int protocol,int family)
-+static void vcc_destruct(struct sock *sk)
-+{
-+ if (atomic_read(&sk->rmem_alloc))
-+ printk(KERN_WARNING "rmem leakage (%d bytes) detected.\n", atomic_read(&sk->rmem_alloc));
-+
-+ if (atomic_read(&sk->wmem_alloc))
-+ printk(KERN_WARNING "wmem leakage (%d bytes) detected.\n", atomic_read(&sk->wmem_alloc));
-+
-+ kfree(sk->protinfo.af_atm);
-+}
-+
-+
-+int vcc_create(struct socket *sock,int protocol,int family)
- {
- struct sock *sk;
- struct atm_vcc *vcc;
-
- sock->sk = NULL;
- if (sock->type == SOCK_STREAM) return -EINVAL;
-- if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
-- vcc = sk->protinfo.af_atm;
-+ sk = sk_alloc(family, GFP_KERNEL, 1);
-+ if (!sk)
-+ return -ENOMEM;
-+ sock_init_data(NULL, sk);
-+
-+ vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
-+ if (!vcc) {
-+ sk_free(sk);
-+ return -ENOMEM;
-+ }
-+ memset(vcc, 0, sizeof(*vcc));
-+
-+ vcc->sk = sk;
- memset(&vcc->flags,0,sizeof(vcc->flags));
- vcc->dev = NULL;
-- 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->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->listenq);
- sk->sleep = &vcc->sleep;
-+
-+ sk->destruct = vcc_destruct;
- sock->sk = sk;
- return 0;
- }
-
-
--void atm_release_vcc_sk(struct sock *sk,int free_sk)
-+void vcc_destroy_socket(struct sock *sk)
- {
-- struct atm_vcc *vcc;
-+ struct atm_vcc *vcc = atm_sk(sk);
-+ struct atm_dev *dev = vcc->dev;
- 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);
-+ if (dev) {
-+ if (dev->ops->close) dev->ops->close(vcc);
- if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
-+
-+ vcc_remove_socket(dev, sk); /* no more receive */
-+
- 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);
-- else kfree_skb(skb);
-+ kfree_skb(skb);
- }
-- spin_lock (&atm_dev_lock);
-- fops_put (vcc->dev->ops);
-- if (atomic_read(&vcc->sk->rmem_alloc))
-- printk(KERN_WARNING "atm_release_vcc: strange ... "
-- "rmem_alloc == %d after closing\n",
-- atomic_read(&vcc->sk->rmem_alloc));
-- bind_vcc(vcc,NULL);
-- } else
-- spin_lock (&atm_dev_lock);
-
-- if (free_sk) free_atm_vcc_sk(sk);
-+ fops_put (dev->ops);
-+ atm_dev_release(dev);
-+ }
-
-- spin_unlock (&atm_dev_lock);
-+ sock_put(sk);
- }
-
--
--int atm_release(struct socket *sock)
-+int vcc_release(struct socket *sock)
- {
-- if (sock->sk)
-- atm_release_vcc_sk(sock->sk,1);
-+ struct sock *sk = sock->sk;
-+ if (sk) {
-+ vcc_destroy_socket(sk);
-+ }
- return 0;
- }
-
-@@ -212,7 +232,105 @@
- }
-
-
--static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
-+static int check_ci(struct atm_dev *dev, struct atm_vcc *vcc, short vpi, int vci)
-+{
-+ struct atm_vcc *walk;
-+ struct sock *s;
-+
-+ for(s = vcc_sklist; s; s = s->next) {
-+ walk = atm_sk(s);
-+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->dev == dev && walk->vpi == vpi &&
-+ walk->vci == vci && ((walk->qos.txtp.traffic_class !=
-+ ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
-+ (walk->qos.rxtp.traffic_class != ATM_NONE &&
-+ vcc->qos.rxtp.traffic_class != ATM_NONE))) {
-+ return -EADDRINUSE;
-+ }
-+ /* allow VCCs with same VPI/VCI iff they don't collide on
-+ TX/RX (but we may refuse such sharing for other reasons,
-+ e.g. if protocol requires to have both channels) */
-+ }
-+ return 0;
-+}
-+
-+
-+static int claim_ci(struct atm_dev *dev, struct atm_vcc *vcc, short *vpi, int *vci)
-+{
-+ static short p = 0; /* poor man's per-device cache */
-+ static int c = 0;
-+ short old_p;
-+ int old_c;
-+ int error;
-+
-+ if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
-+ error = check_ci(dev, vcc, *vpi, *vci);
-+ return error;
-+ }
-+ /* last scan may have left values out of bounds for current device */
-+ if (*vpi != ATM_VPI_ANY) p = *vpi;
-+ else if (p >= 1 << dev->ci_range.vpi_bits) p = 0;
-+ if (*vci != ATM_VCI_ANY) c = *vci;
-+ else if (c < ATM_NOT_RSV_VCI || c >= 1 << dev->ci_range.vci_bits)
-+ c = ATM_NOT_RSV_VCI;
-+ old_p = p;
-+ old_c = c;
-+ do {
-+ if (!check_ci(dev, vcc, p, c)) {
-+ *vpi = p;
-+ *vci = c;
-+ return 0;
-+ }
-+ if (*vci == ATM_VCI_ANY) {
-+ c++;
-+ if (c >= 1 << dev->ci_range.vci_bits)
-+ c = ATM_NOT_RSV_VCI;
-+ }
-+ if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
-+ *vpi == ATM_VPI_ANY) {
-+ p++;
-+ if (p >= 1 << dev->ci_range.vpi_bits) p = 0;
-+ }
-+ }
-+ while (old_p != p || old_c != c);
-+ return -EADDRINUSE;
-+}
-+
-+
-+static void __vcc_insert_socket(struct atm_dev *dev, struct sock *sk)
-+{
-+ atm_sk(sk)->dev = dev;
-+ sk->next = vcc_sklist;
-+ if (sk->next)
-+ vcc_sklist->pprev = &sk->next;
-+ vcc_sklist = sk;
-+ sk->pprev = &vcc_sklist;
-+}
-+
-+
-+void vcc_insert_socket(struct atm_dev *dev, struct sock *sk)
-+{
-+ write_lock_irq(&vcc_sklist_lock);
-+ __vcc_insert_socket(dev, sk);
-+ write_unlock_irq(&vcc_sklist_lock);
-+}
-+EXPORT_SYMBOL(vcc_insert_socket);
-+
-+
-+void vcc_remove_socket(struct atm_dev *dev, struct sock *sk)
-+{
-+ write_lock_irq(&vcc_sklist_lock);
-+ if (sk->pprev) {
-+ if (sk->next)
-+ sk->next->pprev = sk->pprev;
-+ *sk->pprev = sk->next;
-+ sk->pprev = NULL;
-+ }
-+ write_unlock_irq(&vcc_sklist_lock);
-+}
-+EXPORT_SYMBOL(vcc_remove_socket);
-+
-+
-+static int atm_connect_dev(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
- int vci)
- {
- int error;
-@@ -223,8 +341,16 @@
- return -EINVAL;
- if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
- return -EPERM;
-- error = 0;
-- bind_vcc(vcc,dev);
-+ write_lock_irq(&vcc_sklist_lock);
-+ error = claim_ci(dev, vcc, &vpi, &vci);
-+ if (error) {
-+ write_unlock_irq(&vcc_sklist_lock);
-+ return error;
-+ }
-+ vcc->vpi = vpi;
-+ vcc->vci = vci;
-+ __vcc_insert_socket(dev, vcc->sk);
-+ write_unlock_irq(&vcc_sklist_lock);
- switch (vcc->qos.aal) {
- case ATM_AAL0:
- error = atm_init_aal0(vcc);
-@@ -248,7 +374,7 @@
- if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
- if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
- if (error) {
-- bind_vcc(vcc,NULL);
-+ vcc_remove_socket(dev, vcc->sk);
- return error;
- }
- DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
-@@ -256,43 +382,24 @@
- vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
- DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
- vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
-- fops_get (dev->ops);
-+ if (dev->ops->owner) try_inc_mod_count(dev->ops->owner);
- if (dev->ops->open) {
- error = dev->ops->open(vcc,vpi,vci);
- if (error) {
-- fops_put (dev->ops);
-- bind_vcc(vcc,NULL);
-+ if (dev->ops->owner) __MOD_DEC_USE_COUNT(dev->ops->owner);
-+ vcc_remove_socket(dev, vcc->sk);
- return error;
- }
- }
- return 0;
- }
-
--
--static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
--{
-- struct atm_dev *dev;
-- int return_val;
--
-- spin_lock (&atm_dev_lock);
-- 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);
--
-- return return_val;
--}
--
--
- int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
- {
- 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,
-@@ -306,21 +413,28 @@
- return -EINVAL;
- if (itf != ATM_ITF_ANY) {
- int error;
-+ struct atm_dev *dev;
-
-- error = atm_do_connect(vcc,itf,vpi,vci);
-- if (error) return error;
-- }
-- else {
-+ dev = atm_dev_lookup(itf);
-+ if (!dev) return -ENODEV;
-+
-+ error = atm_connect_dev(vcc,dev,vpi,vci);
-+ if (error) {
-+ atm_dev_release(dev);
-+ return error;
-+ }
-+ } else {
- struct atm_dev *dev = NULL;
-- struct list_head *p;
-+ struct list_head *p, *next;
-
-- spin_lock (&atm_dev_lock);
-- list_for_each(p, &atm_devs) {
-+ list_for_each_safe(p, next, &atm_devs) {
- dev = list_entry(p, struct atm_dev, dev_list);
-- if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
-+ /* i suppose it could race in here CHAS */
-+ atm_dev_hold(dev);
-+ if (!atm_connect_dev(vcc,dev,vpi,vci)) break;
-+ atm_dev_release(dev);
- dev = NULL;
- }
-- spin_unlock (&atm_dev_lock);
- if (!dev) return -ENODEV;
- }
- if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
-@@ -397,31 +511,8 @@
- (unsigned long) buff,eff_len);
- 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 */
-- int el, cnt;
-- struct iovec *iov = (struct iovec *)skb->data;
-- unsigned char *p = (unsigned char *)buff;
--
-- el = eff_len;
-- error = 0;
-- for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) {
--/*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/
-- error = copy_to_user(p,iov->iov_base,
-- (iov->iov_len > el) ? el : iov->iov_len) ?
-- -EFAULT : 0;
-- if (error) break;
-- p += iov->iov_len;
-- el -= (iov->iov_len > el)?el:iov->iov_len;
-- iov++;
-- }
-- if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
-- else vcc->dev->ops->free_rx_skb(vcc, skb);
-- return error ? error : eff_len;
-- }
- error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0;
-- if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
-- else vcc->dev->ops->free_rx_skb(vcc, skb);
-+ kfree_skb(skb);
- return error ? error : eff_len;
- }
-
-@@ -453,7 +544,7 @@
- add_wait_queue(&vcc->sleep,&wait);
- set_current_state(TASK_INTERRUPTIBLE);
- error = 0;
-- while (!(skb = vcc->alloc_tx(vcc,eff))) {
-+ while (!(skb = alloc_tx(vcc,eff))) {
- if (m->msg_flags & MSG_DONTWAIT) {
- error = -EAGAIN;
- break;
-@@ -478,7 +569,6 @@
- remove_wait_queue(&vcc->sleep,&wait);
- if (error) return error;
- skb->dev = NULL; /* for paths shared with net_device interfaces */
-- ATM_SKB(skb)->iovcnt = 0;
- ATM_SKB(skb)->atm_options = vcc->atm_options;
- if (copy_from_user(skb_put(skb,size),buff,size)) {
- kfree_skb(skb);
-@@ -498,15 +588,14 @@
- vcc = ATM_SD(sock);
- poll_wait(file,&vcc->sleep,wait);
- mask = 0;
-- if (skb_peek(&vcc->sk->receive_queue) || skb_peek(&vcc->listenq))
-+ if (skb_peek(&vcc->sk->receive_queue))
- 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->sk->wmem_alloc)+
-- ATM_PDU_OVHD <= vcc->sk->sndbuf)
-+ vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc) <= vcc->sk->sndbuf)
- mask |= POLLOUT | POLLWRNORM;
- }
- else if (vcc->reply != WAITING) {
-@@ -555,7 +644,7 @@
-
- int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
- {
-- struct atm_dev *dev;
-+ struct atm_dev *dev = NULL;
- struct list_head *p;
- struct atm_vcc *vcc;
- int *tmp_buf, *tmp_p;
-@@ -563,7 +652,6 @@
- int error,len,size,number, ret_val;
-
- ret_val = 0;
-- spin_lock (&atm_dev_lock);
- vcc = ATM_SD(sock);
- switch (cmd) {
- case SIOCOUTQ:
-@@ -581,7 +661,7 @@
- goto done;
- }
- ret_val = put_user(vcc->sk->sndbuf-
-- atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD,
-+ atomic_read(&vcc->sk->wmem_alloc),
- (int *) arg) ? -EFAULT : 0;
- goto done;
- case SIOCINQ:
-@@ -601,13 +689,14 @@
- goto done;
- }
- size = 0;
-+ read_lock(&atm_dev_lock);
- list_for_each(p, &atm_devs)
- size += sizeof(int);
- if (size > len) {
- ret_val = -E2BIG;
- goto done;
- }
-- tmp_buf = kmalloc(size,GFP_KERNEL);
-+ tmp_buf = kmalloc(size, GFP_ATOMIC);
- if (!tmp_buf) {
- ret_val = -ENOMEM;
- goto done;
-@@ -617,6 +706,8 @@
- dev = list_entry(p, struct atm_dev, dev_list);
- *tmp_p++ = dev->number;
- }
-+ read_unlock(&atm_dev_lock);
-+ dev = NULL;
- ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
- put_user(size, &((struct atm_iobuf *) arg)->length)
- ) ? -EFAULT : 0;
-@@ -654,39 +745,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
-+ __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)
-@@ -695,27 +797,32 @@
- ret_val = -EPERM;
- goto done;
- }
-- if (atm_lane_ops.lecd_attach == NULL)
-- atm_lane_init();
-- if (atm_lane_ops.lecd_attach == NULL) { /* 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);
-- if (error >= 0) sock->state = SS_CONNECTED;
-+ error = atm_lane_ops->lecd_attach(vcc, (int)arg);
-+ if (error >= 0)
-+ sock->state = SS_CONNECTED;
-+ else
-+ __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)
-@@ -724,21 +831,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
-+ __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)
-@@ -747,14 +859,14 @@
- ret_val = -EPERM;
- goto done;
- }
-- if (!atm_tcp_ops.attach) {
-+ if (!atm_tcp_ops) {
- ret_val = -ENOPKG;
- goto done;
- }
-- fops_get (&atm_tcp_ops);
-- error = atm_tcp_ops.attach(vcc,(int) arg);
-+ fops_get(atm_tcp_ops);
-+ error = atm_tcp_ops->attach(vcc,(int) arg);
- if (error >= 0) sock->state = SS_CONNECTED;
-- else fops_put (&atm_tcp_ops);
-+ else fops_put(atm_tcp_ops);
- ret_val = error;
- goto done;
- case ATMTCP_CREATE:
-@@ -762,12 +874,12 @@
- ret_val = -EPERM;
- goto done;
- }
-- if (!atm_tcp_ops.create_persistent) {
-+ if (!atm_tcp_ops) {
- ret_val = -ENOPKG;
- goto done;
- }
-- error = atm_tcp_ops.create_persistent((int) arg);
-- if (error < 0) fops_put (&atm_tcp_ops);
-+ error = atm_tcp_ops->create_persistent((int) arg);
-+ if (error < 0) fops_put(atm_tcp_ops);
- ret_val = error;
- goto done;
- case ATMTCP_REMOVE:
-@@ -775,12 +887,12 @@
- ret_val = -EPERM;
- goto done;
- }
-- if (!atm_tcp_ops.remove_persistent) {
-+ if (!atm_tcp_ops) {
- ret_val = -ENOPKG;
- goto done;
- }
-- error = atm_tcp_ops.remove_persistent((int) arg);
-- fops_put (&atm_tcp_ops);
-+ error = atm_tcp_ops->remove_persistent((int) arg);
-+ fops_put(atm_tcp_ops);
- ret_val = error;
- goto done;
- #endif
-@@ -814,7 +926,7 @@
- ret_val = -EFAULT;
- goto done;
- }
-- if (!(dev = atm_find_dev(number))) {
-+ if (!(dev = atm_dev_lookup(number))) {
- ret_val = -ENODEV;
- goto done;
- }
-@@ -963,7 +1075,7 @@
- ret_val = 0;
-
- done:
-- spin_unlock (&atm_dev_lock);
-+ if (dev) atm_dev_release(dev);
- return ret_val;
- }
-
-@@ -1034,17 +1146,21 @@
- switch (optname) {
- case SO_ATMQOS:
- {
-- struct atm_qos qos;
-+ struct atm_qos *qos;
-
-- if (copy_from_user(&qos,optval,sizeof(qos)))
-+ qos = kmalloc(sizeof(*qos), GFP_KERNEL);
-+ if (!qos)
-+ return -ENOMEM;
-+ if (copy_from_user(qos,optval,sizeof(*qos)))
- return -EFAULT;
-- error = check_qos(&qos);
-+ error = check_qos(qos);
- if (error) return error;
- if (sock->state == SS_CONNECTED)
-- return atm_change_qos(vcc,&qos);
-+ return atm_change_qos(vcc,qos);
- if (sock->state != SS_UNCONNECTED)
- return -EBADFD;
-- vcc->qos = qos;
-+ vcc->qos = *qos;
-+ kfree(qos);
- set_bit(ATM_VF_HASQOS,&vcc->flags);
- return 0;
- }
-@@ -1122,40 +1238,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,
-@@ -1166,15 +1248,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");
-diff -urN linux-2.4.20/net/atm/common.h linux-2.4.20-atm/net/atm/common.h
---- linux-2.4.20/net/atm/common.h Mon Dec 11 22:33:43 2000
-+++ linux-2.4.20-atm/net/atm/common.h Wed May 28 01:58:41 2003
-@@ -10,8 +10,8 @@
- #include <linux/poll.h> /* for poll_table */
-
-
--int atm_create(struct socket *sock,int protocol,int family);
--int atm_release(struct socket *sock);
-+int vcc_create(struct socket *sock,int protocol,int family);
-+int vcc_release(struct socket *sock);
- int atm_connect(struct socket *sock,int itf,short vpi,int vci);
- int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
- int flags,struct scm_cookie *scm);
-@@ -25,10 +25,17 @@
- int *optlen);
-
- int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci);
--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 */
-
-diff -urN linux-2.4.20/net/atm/ipcommon.c linux-2.4.20-atm/net/atm/ipcommon.c
---- linux-2.4.20/net/atm/ipcommon.c Fri Jul 7 06:37:24 2000
-+++ linux-2.4.20-atm/net/atm/ipcommon.c Wed May 28 01:58:41 2003
-@@ -66,5 +66,5 @@
- spin_unlock_irqrestore(&from->lock,flags);
- }
-
--
-+EXPORT_SYMBOL(llc_oui);
- EXPORT_SYMBOL(skb_migrate);
-diff -urN linux-2.4.20/net/atm/ipcommon.h linux-2.4.20-atm/net/atm/ipcommon.h
---- linux-2.4.20/net/atm/ipcommon.h Mon Dec 11 22:33:46 2000
-+++ linux-2.4.20-atm/net/atm/ipcommon.h Wed May 28 01:58:41 2003
-@@ -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".
-diff -urN linux-2.4.20/net/atm/lec.c linux-2.4.20-atm/net/atm/lec.c
---- linux-2.4.20/net/atm/lec.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/lec.c Wed May 28 02:12:42 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 */
-@@ -43,7 +48,7 @@
-
- #include "lec.h"
- #include "lec_arpc.h"
--#include "resources.h" /* for bind_vcc() */
-+#include "resources.h"
-
- #if 0
- #define DPRINTK printk
-@@ -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,22 @@
- 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->sk->wmem_alloc);
-+ ATM_SKB(skb)->vcc = vcc;
-+ 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)
- {
-@@ -340,34 +358,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->sk->wmem_alloc);
-- 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->sk->wmem_alloc);
-- 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? */
-@@ -404,7 +398,7 @@
- int i;
- char *tmp; /* FIXME */
-
-- atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
-+ atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
- mesg = (struct atmlec_msg *)skb->data;
- tmp = skb->data;
- tmp += sizeof(struct atmlec_msg);
-@@ -548,24 +542,19 @@
- }
-
- printk("%s: Shut down!\n", dev->name);
-- MOD_DEC_USE_COUNT;
-+ __MOD_DEC_USE_COUNT(THIS_MODULE);
- }
-
- static struct atmdev_ops lecdev_ops = {
-- close: lec_atm_close,
-- send: lec_atm_send
-+ .close = lec_atm_close,
-+ .send = lec_atm_send
- };
-
- static struct atm_dev lecatm_dev = {
-- &lecdev_ops,
-- NULL, /*PHY*/
-- "lec", /*type*/
-- 999, /*dummy device number*/
-- NULL,NULL, /*no VCCs*/
-- NULL,NULL, /*no data*/
-- { 0 }, /*no flags*/
-- NULL, /* no local address*/
-- { 0 } /*no ESI or rest of the atm_dev struct things*/
-+ .ops = &lecdev_ops,
-+ .type = "lec",
-+ .number = 999,
-+ .lock = SPIN_LOCK_UNLOCKED,
- };
-
- /*
-@@ -726,6 +723,7 @@
- skb->protocol = eth_type_trans(skb, dev);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
-+ memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(skb);
- }
- }
-@@ -812,7 +810,7 @@
- lec_arp_init(priv);
- priv->itfnum = i; /* LANE2 addition */
- priv->lecd = vcc;
-- bind_vcc(vcc, &lecatm_dev);
-+ vcc_insert_socket(&lecatm_dev, vcc->sk);
-
- vcc->proto_data = dev_lec[i];
- set_bit(ATM_VF_META,&vcc->flags);
-@@ -833,27 +831,23 @@
- if (dev_lec[i]->flags & IFF_UP) {
- netif_start_queue(dev_lec[i]);
- }
-- MOD_INC_USE_COUNT;
- 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;
--
-- 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;
- }
-@@ -861,13 +855,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 = NULL;
-
- for (i = 0; i < MAX_LEC_ITF; i++) {
- if (dev_lec[i] != NULL) {
-@@ -880,7 +871,7 @@
- unregister_netdev(dev_lec[i]);
- kfree(dev_lec[i]);
- dev_lec[i] = NULL;
-- }
-+ }
- }
-
- return;
-@@ -1030,7 +1021,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>
-
-
-@@ -1055,15 +1046,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);
- }
-
- /*
-@@ -1114,33 +1105,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]);
- }
-
- /*
-@@ -1150,16 +1141,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]);
-@@ -1171,7 +1161,7 @@
- tmp = tmp->next;
- }
- if (!tmp) {/* Entry was not found */
-- restore_flags(flags);
-+ spin_unlock_irqrestore(&lec_arp_spinlock, flags);
- return -1;
- }
- }
-@@ -1197,7 +1187,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],
-@@ -1382,12 +1374,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);
-
- /*
-@@ -1430,7 +1418,6 @@
- priv->mcast_vcc = NULL;
- memset(priv->lec_arp_tables, 0,
- sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE);
-- restore_flags(flags);
- }
-
-
-@@ -1447,18 +1434,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;
- }
-
-@@ -1585,11 +1572,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;) {
-@@ -1627,6 +1614,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;
-@@ -1635,7 +1626,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);
-@@ -1697,7 +1688,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;
-@@ -1722,7 +1713,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) {
-@@ -1733,11 +1724,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;
- }
-
-@@ -1762,7 +1753,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)) {
-@@ -1796,13 +1787,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;
-@@ -1812,11 +1803,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);
-@@ -1851,7 +1842,7 @@
- }
- DPRINTK("After update2\n");
- dump_arp_table(priv);
-- lec_arp_unlock(priv);
-+ lec_arp_put(priv);
- }
-
- /*
-@@ -1865,7 +1856,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 */
-
-@@ -1874,7 +1865,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);
-@@ -1883,7 +1874,7 @@
- #endif
- entry = make_entry(priv, bus_mac);
- if (entry == NULL) {
-- lec_arp_unlock(priv);
-+ lec_arp_put(priv);
- return;
- }
- del_timer(&entry->timer);
-@@ -1892,7 +1883,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
-@@ -1910,7 +1901,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);
-@@ -1923,7 +1914,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;
- }
-@@ -1982,7 +1973,7 @@
- }
- }
- if (found_entry) {
-- lec_arp_unlock(priv);
-+ lec_arp_put(priv);
- DPRINTK("After vcc was added\n");
- dump_arp_table(priv);
- return;
-@@ -1991,7 +1982,7 @@
- this vcc */
- entry = make_entry(priv, bus_mac);
- if (!entry) {
-- lec_arp_unlock(priv);
-+ lec_arp_put(priv);
- return;
- }
- entry->vcc = vcc;
-@@ -2004,7 +1995,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);
- }
-@@ -2020,6 +2011,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");
- }
-@@ -2050,10 +2045,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);
-@@ -2063,8 +2058,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;
- }
-
-@@ -2076,7 +2071,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;
-@@ -2138,7 +2133,7 @@
- entry = next;
- }
-
-- lec_arp_unlock(priv);
-+ lec_arp_put(priv);
- dump_arp_table(priv);
- }
-
-@@ -2146,9 +2141,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;
-@@ -2158,50 +2153,49 @@
- #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) {
-- prev= entry;
-+ prev = entry;
- entry = entry->next;
- }
- 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.4.20-atm/net/atm/lec.h
---- linux-2.4.20/net/atm/lec.h Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/lec.h Wed May 28 01:58:41 2003
-@@ -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;
- };
-
- /*
-@@ -101,7 +102,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;
-@@ -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_ */
-
-diff -urN linux-2.4.20/net/atm/mpc.c linux-2.4.20-atm/net/atm/mpc.c
---- linux-2.4.20/net/atm/mpc.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/mpc.c Wed May 28 02:14:40 2003
-@@ -28,7 +28,7 @@
-
- #include "lec.h"
- #include "mpc.h"
--#include "resources.h" /* for bind_vcc() */
-+#include "resources.h"
-
- /*
- * mpc.c: Implementation of MPOA client kernel part
-@@ -521,7 +521,6 @@
- }
-
- 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);
- entry->packets_fwded++;
-@@ -730,6 +729,7 @@
- eg->packets_rcvd++;
- mpc->eg_ops->put(eg);
-
-+ memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(new_skb);
-
- return;
-@@ -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,
-+ .lock = SPIN_LOCK_UNLOCKED
- };
-
- int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
-@@ -791,7 +783,7 @@
- }
-
- mpc->mpoad_vcc = vcc;
-- bind_vcc(vcc, &mpc_dev);
-+ vcc_insert_socket(&mpc_dev, vcc->sk);
- set_bit(ATM_VF_META,&vcc->flags);
- set_bit(ATM_VF_READY,&vcc->flags);
-
-@@ -807,7 +799,6 @@
- send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
- }
-
-- MOD_INC_USE_COUNT;
- return arg;
- }
-
-@@ -856,7 +847,7 @@
-
- printk("mpoa: (%s) going down\n",
- (mpc->dev) ? mpc->dev->name : "<unknown>");
-- MOD_DEC_USE_COUNT;
-+ __MOD_DEC_USE_COUNT(THIS_MODULE);
-
- return;
- }
-@@ -869,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->sk->wmem_alloc);
-+ atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
-
- if (mpc == NULL) {
- printk("mpoa: msg_from_mpoad: no mpc found\n");
-@@ -1398,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");
-@@ -1412,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;
-@@ -1442,8 +1429,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;
-@@ -1475,8 +1461,9 @@
- kfree(qos);
- qos = nextqos;
- }
--
-- return;
- }
--#endif /* MODULE */
-+
-+module_init(atm_mpoa_init);
-+module_exit(atm_mpoa_cleanup);
-+
- MODULE_LICENSE("GPL");
-diff -urN linux-2.4.20/net/atm/mpc.h linux-2.4.20-atm/net/atm/mpc.h
---- linux-2.4.20/net/atm/mpc.h Mon Dec 11 22:33:43 2000
-+++ linux-2.4.20-atm/net/atm/mpc.h Wed May 28 01:58:41 2003
-@@ -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);
-diff -urN linux-2.4.20/net/atm/pppoatm.c linux-2.4.20-atm/net/atm/pppoatm.c
---- linux-2.4.20/net/atm/pppoatm.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/pppoatm.c Wed May 28 02:15:02 2003
-@@ -232,7 +232,6 @@
- return 1;
- }
- 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",
- pvcc->chan.unit, skb, ATM_SKB(skb)->vcc,
-diff -urN linux-2.4.20/net/atm/proc.c linux-2.4.20-atm/net/atm/proc.c
---- linux-2.4.20/net/atm/proc.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/proc.c Wed May 28 02:46:02 2003
-@@ -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,
-@@ -85,11 +84,12 @@
- add_stats(buf,"0",&dev->stats.aal0);
- strcat(buf," ");
- add_stats(buf,"5",&dev->stats.aal5);
-+ sprintf(strchr(buf,0), " %d", atomic_read(&dev->refcnt));
- strcat(buf,"\n");
- }
-
-
--#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 +178,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;
-
-@@ -220,10 +220,11 @@
- default:
- here += sprintf(here,"%3d",vcc->sk->family);
- }
-- here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
-+ here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d %d\n",vcc->flags.bits,
- vcc->reply,
- atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
-- atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
-+ atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf,
-+ atomic_read(&vcc->sk->refcnt));
- }
-
-
-@@ -311,26 +312,24 @@
- "AAL(TX,err,RX,err,drop) ...\n");
- }
- left = pos-1;
-+ read_lock(&atm_dev_lock);
- list_for_each(p, &atm_devs) {
- dev = list_entry(p, struct atm_dev, dev_list);
- if (left-- == 0) {
- dev_info(dev,buf);
-+ read_unlock(&atm_dev_lock);
- return strlen(buf);
- }
- }
-+ read_unlock(&atm_dev_lock);
- return 0;
- }
-
--/*
-- * FIXME: it isn't safe to walk the VCC list without turning off interrupts.
-- * What is really needed is some lock on the devices. Ditto for ATMARP.
-- */
-
- static int atm_pvc_info(loff_t pos,char *buf)
- {
-- struct atm_dev *dev;
-- struct list_head *p;
- struct atm_vcc *vcc;
-+ struct sock *s;
- int left;
-
- if (!pos) {
-@@ -338,24 +337,25 @@
- "TX(PCR,Class)\n");
- }
- left = pos-1;
-- 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->sk->family == PF_ATMPVC &&
-- vcc->dev && !left--) {
-- pvc_info(vcc,buf);
-- return strlen(buf);
-- }
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
-+ if (vcc->sk->family == PF_ATMPVC &&
-+ vcc->dev && !left--) {
-+ pvc_info(vcc,buf);
-+ read_unlock(&vcc_sklist_lock);
-+ return strlen(buf);
-+ }
- }
-+ read_unlock(&vcc_sklist_lock);
- return 0;
- }
-
-
- static int atm_vc_info(loff_t pos,char *buf)
- {
-- struct atm_dev *dev;
-- struct list_head *p;
- struct atm_vcc *vcc;
-+ struct sock *s;
- int left;
-
- if (!pos)
-@@ -363,19 +363,16 @@
- "Address"," Itf VPI VCI Fam Flags Reply Send buffer"
- " Recv buffer\n");
- left = pos-1;
-- 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)
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
- if (!left--) {
- vc_info(vcc,buf);
-+ read_unlock(&vcc_sklist_lock);
- return strlen(buf);
- }
-+ }
-+ read_unlock(&vcc_sklist_lock);
-
- return 0;
- }
-@@ -383,31 +380,28 @@
-
- static int atm_svc_info(loff_t pos,char *buf)
- {
-- struct atm_dev *dev;
-- struct list_head *p;
- struct atm_vcc *vcc;
-+ struct sock *s;
- int left;
-
- if (!pos)
- return sprintf(buf,"Itf VPI VCI State Remote\n");
- left = pos-1;
-- 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->sk->family == PF_ATMSVC && !left--) {
-- svc_info(vcc,buf);
-- return strlen(buf);
-- }
-- }
-- for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ vcc = atm_sk(s);
- if (vcc->sk->family == PF_ATMSVC && !left--) {
- svc_info(vcc,buf);
-+ read_unlock(&vcc_sklist_lock);
- return strlen(buf);
- }
-+ }
-+ read_unlock(&vcc_sklist_lock);
-+
- 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;
-@@ -417,28 +411,30 @@
- return sprintf(buf,"IPitf TypeEncp Idle IP address "
- "ATM address\n");
- }
-+ if (!clip_tbl_hook)
-+ return 0;
- count = pos;
-- read_lock_bh(&clip_tbl.lock);
-+ read_lock_bh(&clip_tbl_hook->lock);
- for (i = 0; i <= NEIGH_HASHMASK; i++)
-- for (n = clip_tbl.hash_buckets[i]; n; n = n->next) {
-+ for (n = clip_tbl_hook->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(&clip_tbl_hook->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(&clip_tbl_hook->lock);
- return strlen(buf);
- }
- }
-- read_unlock_bh(&clip_tbl.lock);
-+ read_unlock_bh(&clip_tbl_hook->lock);
- return 0;
- }
- #endif
-@@ -456,10 +452,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 */
-- else
-- dev_lec = atm_lane_ops.get_lecs();
-+
-+ if (!try_inc_mod_count(atm_lane_ops->owner))
-+ return 0;
-+
-+ dev_lec = atm_lane_ops->get_lecs();
-
- count = pos;
- for(d=0;d<MAX_LEC_ITF;d++) {
-@@ -472,6 +471,7 @@
- e=sprintf(buf,"%s ",
- dev_lec[d]->name);
- lec_info(entry,buf+e);
-+ __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
- return strlen(buf);
- }
- }
-@@ -480,6 +480,7 @@
- if (--count) continue;
- e=sprintf(buf,"%s ",dev_lec[d]->name);
- lec_info(entry, buf+e);
-+ __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
- return strlen(buf);
- }
- for(entry=priv->lec_no_forward; entry;
-@@ -487,6 +488,7 @@
- if (--count) continue;
- e=sprintf(buf,"%s ",dev_lec[d]->name);
- lec_info(entry, buf+e);
-+ __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
- return strlen(buf);
- }
- for(entry=priv->mcast_fwds; entry;
-@@ -494,9 +496,11 @@
- if (--count) continue;
- e=sprintf(buf,"%s ",dev_lec[d]->name);
- lec_info(entry, buf+e);
-+ __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
- return strlen(buf);
- }
- }
-+ __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
- return 0;
- }
- #endif
-@@ -566,7 +570,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);
-@@ -599,12 +603,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;
-@@ -612,7 +615,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)
-@@ -629,4 +632,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);
- }
-diff -urN linux-2.4.20/net/atm/pvc.c linux-2.4.20-atm/net/atm/pvc.c
---- linux-2.4.20/net/atm/pvc.c Thu Apr 12 21:11:39 2001
-+++ linux-2.4.20-atm/net/atm/pvc.c Wed May 28 01:58:41 2003
-@@ -15,17 +15,10 @@
- #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 */
-
--#ifndef NULL
--#define NULL 0
--#endif
--
-
- static int pvc_shutdown(struct socket *sock,int how)
- {
-@@ -77,45 +70,38 @@
- }
-
-
--static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = {
-- family: PF_ATMPVC,
-+static struct proto_ops pvc_proto_ops = {
-+ .family = PF_ATMPVC,
-
-- release: atm_release,
-- bind: pvc_bind,
-- connect: pvc_connect,
-- socketpair: sock_no_socketpair,
-- accept: sock_no_accept,
-- getname: pvc_getname,
-- poll: atm_poll,
-- ioctl: atm_ioctl,
-- listen: sock_no_listen,
-- shutdown: pvc_shutdown,
-- setsockopt: atm_setsockopt,
-- getsockopt: atm_getsockopt,
-- sendmsg: atm_sendmsg,
-- recvmsg: atm_recvmsg,
-- mmap: sock_no_mmap,
-- sendpage: sock_no_sendpage,
-+ .release = vcc_release,
-+ .bind = pvc_bind,
-+ .connect = pvc_connect,
-+ .socketpair = sock_no_socketpair,
-+ .accept = sock_no_accept,
-+ .getname = pvc_getname,
-+ .poll = atm_poll,
-+ .ioctl = atm_ioctl,
-+ .listen = sock_no_listen,
-+ .shutdown = pvc_shutdown,
-+ .setsockopt = atm_setsockopt,
-+ .getsockopt = atm_getsockopt,
-+ .sendmsg = atm_sendmsg,
-+ .recvmsg = atm_recvmsg,
-+ .mmap = sock_no_mmap,
-+ .sendpage = sock_no_sendpage,
- };
-
-
--#include <linux/smp_lock.h>
--SOCKOPS_WRAP(pvc_proto, PF_ATMPVC);
--
--
- static int pvc_create(struct socket *sock,int protocol)
- {
- sock->ops = &pvc_proto_ops;
-- return atm_create(sock,protocol,PF_ATMPVC);
-+ return vcc_create(sock,protocol,PF_ATMPVC);
- }
-
-
- 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,
- };
-
-
-@@ -124,23 +110,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);
-+}
-diff -urN linux-2.4.20/net/atm/raw.c linux-2.4.20-atm/net/atm/raw.c
---- linux-2.4.20/net/atm/raw.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/raw.c Wed May 28 01:58:41 2003
-@@ -37,7 +37,7 @@
- static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
- {
- 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);
-+ atomic_sub(skb->truesize,&vcc->sk->wmem_alloc);
- dev_kfree_skb_any(skb);
- wake_up(&vcc->sleep);
- }
-diff -urN linux-2.4.20/net/atm/resources.c linux-2.4.20-atm/net/atm/resources.c
---- linux-2.4.20/net/atm/resources.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/resources.c Wed May 28 02:38:44 2003
-@@ -2,7 +2,6 @@
-
- /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
-
--
- #include <linux/config.h>
- #include <linux/ctype.h>
- #include <linux/string.h>
-@@ -11,198 +10,185 @@
- #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"
-
--
--#ifndef NULL
--#define NULL 0
--#endif
--
-+struct sock *vcc_sklist = NULL;
-+rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
-
- LIST_HEAD(atm_devs);
--struct atm_vcc *nodev_vccs = NULL;
--extern spinlock_t atm_dev_lock;
-+rwlock_t atm_dev_lock = RW_LOCK_UNLOCKED;
-
-
--static struct atm_dev *alloc_atm_dev(const char *type)
-+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;
-- list_add_tail(&dev->dev_list, &atm_devs);
-+ dev->dev_data = NULL;
-+ memset(&dev->stats, 0, sizeof(dev->stats));
-+ atomic_set(&dev->refcnt, 0);
-+ spin_lock_init(&dev->lock);
-
- return dev;
- }
-
-
--static void free_atm_dev(struct atm_dev *dev)
-+static void __free_atm_dev(struct atm_dev *dev)
- {
-- list_del(&dev->dev_list);
- kfree(dev);
- }
-
--struct atm_dev *atm_find_dev(int number)
-+static struct atm_dev *__atm_dev_lookup(int number)
- {
- struct atm_dev *dev;
- struct list_head *p;
-
- list_for_each(p, &atm_devs) {
- dev = list_entry(p, struct atm_dev, dev_list);
-- if (dev->ops && dev->number == number)
-+ if (dev->ops && dev->number == number) {
-+ atm_dev_hold(dev);
- 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_lookup(int number)
- {
-- struct atm_dev *dev = NULL;
-+ struct atm_dev *dev;
-+
-+ read_lock(&atm_dev_lock);
-+ dev = __atm_dev_lookup(number);
-+ read_unlock(&atm_dev_lock);
-+ return dev;
-+}
-
-- spin_lock(&atm_dev_lock);
-+void atm_dev_hold(struct atm_dev *dev)
-+{
-+ atomic_inc(&dev->refcnt);
-+}
-
-- dev = alloc_atm_dev(type);
-+void atm_dev_release(struct atm_dev *dev)
-+{
-+ atomic_dec(&dev->refcnt);
-+
-+ if ((atomic_read(&dev->refcnt) == 1) &&
-+ test_bit(ATM_DF_CLOSE,&dev->flags))
-+ shutdown_atm_dev(dev);
-+}
-+
-+
-+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
-+ int number, atm_dev_flags_t *flags)
-+{
-+ struct atm_dev *dev, *inuse;
-+
-+ dev = __alloc_atm_dev(type);
- if (!dev) {
- printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
- type);
-- goto done;
-+ return NULL;
- }
-+ write_lock(&atm_dev_lock);
- if (number != -1) {
-- if (atm_find_dev(number)) {
-- free_atm_dev(dev);
-+ if ((inuse = __atm_dev_lookup(number))) {
-+ atm_dev_release(inuse);
-+ __free_atm_dev(dev);
-+ write_unlock(&atm_dev_lock);
- return NULL;
- }
- dev->number = number;
- } else {
- dev->number = 0;
-- while (atm_find_dev(dev->number)) dev->number++;
-+ while ((inuse = __atm_dev_lookup(dev->number))) {
-+ atm_dev_release(inuse);
-+ 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));
-+ atomic_inc(&dev->refcnt);
-+ list_add_tail(&dev->dev_list, &atm_devs);
-+ write_unlock(&atm_dev_lock);
-+ barrier();
-+
- #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);
-- goto done;
-+ "atm_proc_dev_register failed for dev %s\n",
-+ type);
-+ write_lock(&atm_dev_lock);
-+ list_del(&dev->dev_list);
-+ write_unlock(&atm_dev_lock);
-+ __free_atm_dev(dev);
-+ return NULL;
- }
-+ }
- #endif
-
--done:
-- spin_unlock(&atm_dev_lock);
- return dev;
- }
-
-
- void atm_dev_deregister(struct atm_dev *dev)
- {
-+ unsigned long warning_time;
-+
- #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);
-- spin_unlock(&atm_dev_lock);
--}
--
--void shutdown_atm_dev(struct atm_dev *dev)
--{
-- if (dev->vccs) {
-- set_bit(ATM_DF_CLOSE,&dev->flags);
-- return;
-- }
-- 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);
-- if (!vcc) {
-- sk_free(sk);
-- return NULL;
-- }
-- sock_init_data(NULL,sk);
-- sk->destruct = atm_free_sock;
-- memset(vcc,0,sizeof(*vcc));
-- vcc->sk = sk;
-- if (nodev_vccs) nodev_vccs->prev = vcc;
-- vcc->prev = NULL;
-- vcc->next = nodev_vccs;
-- nodev_vccs = vcc;
-- return sk;
--}
--
--
--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->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
-- test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
-- shutdown_atm_dev(vcc->dev);
--}
-+ write_lock(&atm_dev_lock);
-+ list_del(&dev->dev_list);
-+ write_unlock(&atm_dev_lock);
-
-+ warning_time = jiffies;
-+ while (atomic_read(&dev->refcnt) != 1) {
-+ current->state = TASK_INTERRUPTIBLE;
-+ schedule_timeout(HZ / 4);
-+ current->state = TASK_RUNNING;
-+ if ((jiffies - warning_time) > 10 * HZ) {
-+ printk(KERN_EMERG "atm_dev_deregister: waiting for "
-+ "dev %d to become free. Usage count = %d\n",
-+ dev->number, atomic_read(&dev->refcnt));
-+ warning_time = jiffies;
-+ }
-+ }
-
--void free_atm_vcc_sk(struct sock *sk)
--{
-- unlink_vcc(sk->protinfo.af_atm,NULL);
-- sk_free(sk);
-+ __free_atm_dev(dev);
- }
-
-
--void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
-+void shutdown_atm_dev(struct atm_dev *dev)
- {
-- unlink_vcc(vcc,dev);
-- vcc->dev = dev;
-- if (dev) {
-- vcc->next = NULL;
-- vcc->prev = dev->last;
-- if (dev->vccs) dev->last->next = vcc;
-- else dev->vccs = vcc;
-- dev->last = vcc;
-- }
-- else {
-- if (nodev_vccs) nodev_vccs->prev = vcc;
-- vcc->next = nodev_vccs;
-- vcc->prev = NULL;
-- nodev_vccs = vcc;
-+ if (atomic_read(&dev->refcnt) > 1) {
-+ set_bit(ATM_DF_CLOSE, &dev->flags);
-+ return;
- }
-+ if (dev->ops->dev_close)
-+ dev->ops->dev_close(dev);
-+ atm_dev_deregister(dev);
- }
-
-
- EXPORT_SYMBOL(atm_dev_register);
- EXPORT_SYMBOL(atm_dev_deregister);
--EXPORT_SYMBOL(atm_find_dev);
-+EXPORT_SYMBOL(atm_dev_lookup);
-+EXPORT_SYMBOL(atm_dev_hold);
-+EXPORT_SYMBOL(atm_dev_release);
- EXPORT_SYMBOL(shutdown_atm_dev);
--EXPORT_SYMBOL(bind_vcc);
-+EXPORT_SYMBOL(vcc_sklist);
-+EXPORT_SYMBOL(vcc_sklist_lock);
-diff -urN linux-2.4.20/net/atm/resources.h linux-2.4.20-atm/net/atm/resources.h
---- linux-2.4.20/net/atm/resources.h Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/resources.h Wed May 28 02:23:53 2003
-@@ -11,11 +11,7 @@
-
-
- extern struct list_head atm_devs;
--extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */
--
--
--struct sock *alloc_atm_vcc_sk(int family);
--void free_atm_vcc_sk(struct sock *sk);
-+extern rwlock_t atm_dev_lock;
-
-
- #ifdef CONFIG_PROC_FS
-diff -urN linux-2.4.20/net/atm/signaling.c linux-2.4.20-atm/net/atm/signaling.c
---- linux-2.4.20/net/atm/signaling.c Wed May 28 01:54:25 2003
-+++ linux-2.4.20-atm/net/atm/signaling.c Wed May 28 02:28:19 2003
-@@ -33,7 +33,6 @@
- struct atm_vcc *sigd = NULL;
- static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
-
--extern spinlock_t atm_dev_lock;
-
- static void sigd_put_skb(struct sk_buff *skb)
- {
-@@ -98,7 +97,7 @@
- struct atm_vcc *session_vcc;
-
- msg = (struct atmsvc_msg *) skb->data;
-- atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
-+ atomic_sub(skb->truesize,&vcc->sk->wmem_alloc);
- DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
- (unsigned long) msg->vcc);
- vcc = *(struct atm_vcc **) &msg->vcc;
-@@ -115,7 +114,7 @@
- }
- session_vcc = vcc->session ? vcc->session : vcc;
- if (session_vcc->vpi || session_vcc->vci) break;
-- session_vcc->itf = msg->pvc.sap_addr.itf;
-+ session_vcc->sk->bound_dev_if = msg->pvc.sap_addr.itf;
- session_vcc->vpi = msg->pvc.sap_addr.vpi;
- session_vcc->vci = msg->pvc.sap_addr.vci;
- if (session_vcc->vpi || session_vcc->vci)
-@@ -129,12 +128,12 @@
- case as_indicate:
- vcc = *(struct atm_vcc **) &msg->listen_vcc;
- DPRINTK("as_indicate!!!\n");
-- if (!vcc->backlog_quota) {
-+ if (vcc->sk->ack_backlog == vcc->sk->max_ack_backlog) {
- sigd_enq(0,as_reject,vcc,NULL,NULL);
- return 0;
- }
-- vcc->backlog_quota--;
-- skb_queue_tail(&vcc->listenq,skb);
-+ vcc->sk->ack_backlog++;
-+ skb_queue_tail(&vcc->sk->receive_queue,skb);
- if (vcc->callback) {
- DPRINTK("waking vcc->sleep 0x%p\n",
- &vcc->sleep);
-@@ -195,16 +194,13 @@
- }
-
-
--static void purge_vccs(struct atm_vcc *vcc)
-+static void purge_vcc(struct atm_vcc *vcc)
- {
-- while (vcc) {
-- if (vcc->sk->family == PF_ATMSVC &&
-- !test_bit(ATM_VF_META,&vcc->flags)) {
-- set_bit(ATM_VF_RELEASED,&vcc->flags);
-- vcc->reply = -EUNATCH;
-- wake_up(&vcc->sleep);
-- }
-- vcc = vcc->next;
-+ if (vcc->sk->family == PF_ATMSVC &&
-+ !test_bit(ATM_VF_META,&vcc->flags)) {
-+ set_bit(ATM_VF_RELEASED,&vcc->flags);
-+ vcc->reply = -EUNATCH;
-+ wake_up(&vcc->sleep);
- }
- }
-
-@@ -213,39 +209,42 @@
- {
- struct atm_dev *dev;
- struct list_head *p;
-+ struct sock *s;
-
- DPRINTK("sigd_close\n");
- sigd = NULL;
- if (skb_peek(&vcc->sk->receive_queue))
- printk(KERN_ERR "sigd_close: closing with requests pending\n");
- skb_queue_purge(&vcc->sk->receive_queue);
-- purge_vccs(nodev_vccs);
-
-- spin_lock (&atm_dev_lock);
-+ read_lock(&atm_dev_lock);
- list_for_each(p, &atm_devs) {
- dev = list_entry(p, struct atm_dev, dev_list);
-- purge_vccs(dev->vccs);
-+
-+ read_lock(&vcc_sklist_lock);
-+ for(s = vcc_sklist; s; s = s->next) {
-+ struct atm_vcc *vcc = atm_sk(s);
-+
-+ if (vcc->dev == dev) purge_vcc(vcc);
-+ }
-+ read_unlock(&vcc_sklist_lock);
- }
-- spin_unlock (&atm_dev_lock);
-+ read_unlock(&atm_dev_lock);
- }
-
-
- static struct atmdev_ops sigd_dev_ops = {
-- close: sigd_close,
-- send: sigd_send
-+ .close = sigd_close,
-+ .send = sigd_send
- };
-
-
- static struct atm_dev sigd_dev = {
-- &sigd_dev_ops,
-- NULL, /* no PHY */
-- "sig", /* type */
-- 999, /* dummy device number */
-- NULL,NULL, /* pretend not to have any VCCs */
-- NULL,NULL, /* no data */
-- { 0 }, /* no flags */
-- NULL, /* no local address */
-- { 0 } /* no ESI, no statistics */
-+ .ops = &sigd_dev_ops,
-+ .phy = NULL,
-+ .type = "sig",
-+ .number = 999,
-+ .lock = SPIN_LOCK_UNLOCKED
- };
-
-
-@@ -254,7 +253,7 @@
- if (sigd) return -EADDRINUSE;
- DPRINTK("sigd_attach\n");
- sigd = vcc;
-- bind_vcc(vcc,&sigd_dev);
-+ vcc_insert_socket(&sigd_dev, vcc->sk);
- set_bit(ATM_VF_META,&vcc->flags);
- set_bit(ATM_VF_READY,&vcc->flags);
- wake_up(&sigd_sleep);
-diff -urN linux-2.4.20/net/atm/svc.c linux-2.4.20-atm/net/atm/svc.c
---- linux-2.4.20/net/atm/svc.c Thu Apr 12 21:11:39 2001
-+++ linux-2.4.20-atm/net/atm/svc.c Wed May 28 01:58:41 2003
-@@ -65,8 +65,8 @@
-
- DPRINTK("svc_disconnect %p\n",vcc);
- if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
-- sigd_enq(vcc,as_close,NULL,NULL,NULL);
- add_wait_queue(&vcc->sleep,&wait);
-+ sigd_enq(vcc,as_close,NULL,NULL,NULL);
- while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
-@@ -75,7 +75,7 @@
- }
- /* beware - socket is still in use by atmsigd until the last
- as_indicate has been answered */
-- while ((skb = skb_dequeue(&vcc->listenq))) {
-+ while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
- DPRINTK("LISTEN REL\n");
- sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
- dev_kfree_skb(skb);
-@@ -90,17 +90,19 @@
- static int svc_release(struct socket *sock)
- {
- struct atm_vcc *vcc;
-+ struct sock *sk = sock->sk;
-
-- if (!sock->sk) return 0;
-- vcc = ATM_SD(sock);
-- DPRINTK("svc_release %p\n",vcc);
-- clear_bit(ATM_VF_READY,&vcc->flags);
-- atm_release_vcc_sk(sock->sk,0);
-- svc_disconnect(vcc);
-- /* VCC pointer is used as a reference, so we must not free it
-- (thereby subjecting it to re-use) before all pending connections
-- are closed */
-- free_atm_vcc_sk(sock->sk);
-+ if (sk) {
-+ vcc = atm_sk(sk);
-+ DPRINTK("svc_release %p\n",vcc);
-+ sock_hold(sk);
-+ vcc_release(sock);
-+ svc_disconnect(vcc);
-+ /* VCC pointer is used as a reference, so we must not free it
-+ (thereby subjecting it to re-use) before all pending
-+ connections are closed */
-+ sock_put(sk);
-+ }
- return 0;
- }
-
-@@ -125,8 +127,8 @@
- if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
- vcc->local = *addr;
- vcc->reply = WAITING;
-- sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
- add_wait_queue(&vcc->sleep,&wait);
-+ sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
- while (vcc->reply == WAITING && sigd) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
-@@ -169,13 +171,14 @@
- if (!vcc->qos.txtp.traffic_class &&
- !vcc->qos.rxtp.traffic_class) return -EINVAL;
- vcc->remote = *addr;
-+ add_wait_queue(&vcc->sleep,&wait);
- vcc->reply = WAITING;
- sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
- if (flags & O_NONBLOCK) {
-+ remove_wait_queue(&vcc->sleep,&wait);
- sock->state = SS_CONNECTING;
- return -EINPROGRESS;
- }
-- add_wait_queue(&vcc->sleep,&wait);
- error = 0;
- while (vcc->reply == WAITING && sigd) {
- set_current_state(TASK_INTERRUPTIBLE);
-@@ -228,7 +231,7 @@
- /*
- * #endif
- */
-- if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci)))
-+ if (!(error = atm_connect(sock,vcc->sk->bound_dev_if,vcc->vpi,vcc->vci)))
- sock->state = SS_CONNECTED;
- else (void) svc_disconnect(vcc);
- return error;
-@@ -243,9 +246,9 @@
- DPRINTK("svc_listen %p\n",vcc);
- /* let server handle listen on unbound sockets */
- if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
-+ add_wait_queue(&vcc->sleep,&wait);
- vcc->reply = WAITING;
- sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
-- add_wait_queue(&vcc->sleep,&wait);
- while (vcc->reply == WAITING && sigd) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
-@@ -253,7 +256,7 @@
- remove_wait_queue(&vcc->sleep,&wait);
- if (!sigd) return -EUNATCH;
- set_bit(ATM_VF_LISTEN,&vcc->flags);
-- vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
-+ vcc->sk->max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
- return vcc->reply;
- }
-
-@@ -277,7 +280,7 @@
- DECLARE_WAITQUEUE(wait,current);
-
- add_wait_queue(&old_vcc->sleep,&wait);
-- while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) {
-+ while (!(skb = skb_dequeue(&old_vcc->sk->receive_queue)) && sigd) {
- if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
- if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
- error = old_vcc->reply;
-@@ -306,16 +309,16 @@
- error = atm_connect(newsock,msg->pvc.sap_addr.itf,
- msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci);
- dev_kfree_skb(skb);
-- old_vcc->backlog_quota++;
-+ old_vcc->sk->ack_backlog--;
- if (error) {
- sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
- &old_vcc->qos,error);
- return error == -EAGAIN ? -EBUSY : error;
- }
- /* wait should be short, so we ignore the non-blocking flag */
-+ add_wait_queue(&new_vcc->sleep,&wait);
- new_vcc->reply = WAITING;
- sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
-- add_wait_queue(&new_vcc->sleep,&wait);
- while (new_vcc->reply == WAITING && sigd) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
-@@ -347,9 +350,9 @@
- {
- DECLARE_WAITQUEUE(wait,current);
-
-+ add_wait_queue(&vcc->sleep,&wait);
- vcc->reply = WAITING;
- sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
-- add_wait_queue(&vcc->sleep,&wait);
- while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
- && sigd) {
- set_current_state(TASK_UNINTERRUPTIBLE);
-@@ -390,37 +393,34 @@
- }
-
-
--static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = {
-- family: PF_ATMSVC,
-+static struct proto_ops svc_proto_ops = {
-+ .family = PF_ATMSVC,
-
-- release: svc_release,
-- bind: svc_bind,
-- connect: svc_connect,
-- socketpair: sock_no_socketpair,
-- accept: svc_accept,
-- getname: svc_getname,
-- poll: atm_poll,
-- ioctl: atm_ioctl,
-- listen: svc_listen,
-- shutdown: svc_shutdown,
-- setsockopt: svc_setsockopt,
-- getsockopt: svc_getsockopt,
-- sendmsg: atm_sendmsg,
-- recvmsg: atm_recvmsg,
-- mmap: sock_no_mmap,
-- sendpage: sock_no_sendpage,
-+ .release = svc_release,
-+ .bind = svc_bind,
-+ .connect = svc_connect,
-+ .socketpair = sock_no_socketpair,
-+ .accept = svc_accept,
-+ .getname = svc_getname,
-+ .poll = atm_poll,
-+ .ioctl = atm_ioctl,
-+ .listen = svc_listen,
-+ .shutdown = svc_shutdown,
-+ .setsockopt = svc_setsockopt,
-+ .getsockopt = svc_getsockopt,
-+ .sendmsg = atm_sendmsg,
-+ .recvmsg = atm_recvmsg,
-+ .mmap = sock_no_mmap,
-+ .sendpage = sock_no_sendpage,
- };
-
-
--#include <linux/smp_lock.h>
--SOCKOPS_WRAP(svc_proto, PF_ATMSVC);
--
- static int svc_create(struct socket *sock,int protocol)
- {
- int error;
-
- sock->ops = &svc_proto_ops;
-- error = atm_create(sock,protocol,AF_ATMSVC);
-+ error = vcc_create(sock,protocol,AF_ATMSVC);
- if (error) return error;
- ATM_SD(sock)->callback = svc_callback;
- ATM_SD(sock)->local.sas_family = AF_ATMSVC;
-@@ -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,
- };
-
-
-@@ -442,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);
-+}
-diff -urN linux-2.4.20/net/ipv4/arp.c linux-2.4.20-atm/net/ipv4/arp.c
---- linux-2.4.20/net/ipv4/arp.c Fri Nov 29 00:53:15 2002
-+++ linux-2.4.20-atm/net/ipv4/arp.c Wed May 28 01:58:41 2003
-@@ -105,8 +105,9 @@
- #include <net/netrom.h>
- #endif
- #endif
--#ifdef CONFIG_ATM_CLIP
-+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
- #include <net/atmclip.h>
-+struct neigh_table *clip_tbl_hook = NULL;
- #endif
-
- #include <asm/system.h>
-@@ -438,8 +439,8 @@
- if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
- nexthop = 0;
- n = __neigh_lookup_errno(
--#ifdef CONFIG_ATM_CLIP
-- dev->type == ARPHRD_ATM ? &clip_tbl :
-+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-+ dev->type == ARPHRD_ATM ? clip_tbl_hook :
- #endif
- &arp_tbl, &nexthop, dev);
- if (IS_ERR(n))
-diff -urN linux-2.4.20/net/netsyms.c linux-2.4.20-atm/net/netsyms.c
---- linux-2.4.20/net/netsyms.c Wed May 28 01:54:31 2003
-+++ linux-2.4.20-atm/net/netsyms.c Wed May 28 01:58:41 2003
-@@ -45,6 +45,9 @@
- #include <linux/ip.h>
- #include <net/protocol.h>
- #include <net/arp.h>
-+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-+#include <net/atmclip.h>
-+#endif
- #include <net/ip.h>
- #include <net/udp.h>
- #include <net/tcp.h>
-@@ -160,6 +163,7 @@
- EXPORT_SYMBOL(put_cmsg);
- EXPORT_SYMBOL(sock_kmalloc);
- EXPORT_SYMBOL(sock_kfree_s);
-+EXPORT_SYMBOL(sockfd_lookup);
-
- #ifdef CONFIG_FILTER
- EXPORT_SYMBOL(sk_run_filter);
-@@ -461,6 +465,9 @@
- EXPORT_SYMBOL(ip_rcv);
- EXPORT_SYMBOL(arp_rcv);
- EXPORT_SYMBOL(arp_tbl);
-+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-+EXPORT_SYMBOL(clip_tbl_hook);
-+#endif
- EXPORT_SYMBOL(arp_find);
-
- #endif /* CONFIG_INET */
-diff -urN linux-2.4.20/net/sched/Config.in linux-2.4.20-atm/net/sched/Config.in
---- linux-2.4.20/net/sched/Config.in Fri Nov 29 00:53:16 2002
-+++ linux-2.4.20-atm/net/sched/Config.in Wed May 28 01:58:41 2003
-@@ -6,8 +6,8 @@
- tristate ' CSZ packet scheduler' CONFIG_NET_SCH_CSZ
- #tristate ' H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
- #tristate ' H-FSC packet scheduler' CONFIG_NET_SCH_HFCS
--if [ "$CONFIG_ATM" = "y" ]; then
-- bool ' ATM pseudo-scheduler' CONFIG_NET_SCH_ATM
-+if [ "$CONFIG_ATM" != "n" ]; then
-+ dep_tristate ' ATM pseudo-scheduler' CONFIG_NET_SCH_ATM $CONFIG_ATM
- fi
- tristate ' The simplest PRIO pseudoscheduler' CONFIG_NET_SCH_PRIO
- tristate ' RED queue' CONFIG_NET_SCH_RED
-diff -urN linux-2.4.20/net/sched/sch_atm.c linux-2.4.20-atm/net/sched/sch_atm.c
---- linux-2.4.20/net/sched/sch_atm.c Wed May 28 01:54:31 2003
-+++ linux-2.4.20-atm/net/sched/sch_atm.c Wed May 28 01:59:30 2003
-@@ -512,7 +512,6 @@
- memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
- flow->hdr_len);
- atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc);
-- ATM_SKB(skb)->iovcnt = 0;
- /* atm.atm_options are already set by atm_tc_enqueue */
- (void) flow->vcc->send(flow->vcc,skb);
- }