summaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
commit8624512aa908741ba2795200133eae0d7f4557ea (patch)
treed5d3036fccf2604f4c98dedc11e8adb929d6b52e /net/atm
parent7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff)
Merge with 2.3.48.
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/clip.c67
-rw-r--r--net/atm/lec.c255
-rw-r--r--net/atm/mpoa_proc.c9
-rw-r--r--net/atm/proc.c13
-rw-r--r--net/atm/raw.c4
5 files changed, 175 insertions, 173 deletions
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 43cf3d9a2..98d51c094 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -73,6 +73,7 @@ static void link_vcc(struct clip_vcc *clip_vcc,struct atmarp_entry *entry)
DPRINTK("link_vcc %p to entry %p (neigh %p)\n",clip_vcc,entry,
entry->neigh);
clip_vcc->entry = entry;
+ clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */
clip_vcc->next = entry->vccs;
entry->vccs = clip_vcc;
entry->neigh->used = jiffies;
@@ -95,6 +96,8 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
*walk = clip_vcc->next; /* atomic */
clip_vcc->entry = NULL;
+ if (clip_vcc->xoff)
+ netif_wake_queue(entry->neigh->dev);
if (entry->vccs) return;
entry->expires = jiffies-1;
/* force resolution or expiration */
@@ -218,13 +221,27 @@ void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
}
+/*
+ * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that
+ * clip_pop is atomic with respect to the critical section in clip_start_xmit.
+ */
+
+
static void clip_pop(struct atm_vcc *vcc,struct sk_buff *skb)
{
+ struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
+ int old;
+
DPRINTK("clip_pop(vcc %p)\n",vcc);
- CLIP_VCC(vcc)->old_pop(vcc,skb);
+ clip_vcc->old_pop(vcc,skb);
/* skb->dev == NULL in outbound ARP packets */
- if (atm_may_send(vcc,0) && skb->dev)
- netif_wake_queue(skb->dev);
+ if (!skb->dev) return;
+ spin_lock(&PRIV(skb->dev)->xoff_lock);
+ if (atm_may_send(vcc,0)) {
+ old = xchg(&clip_vcc->xoff,0);
+ if (old) netif_wake_queue(skb->dev);
+ }
+ spin_unlock(&PRIV(skb->dev)->xoff_lock);
}
@@ -354,8 +371,10 @@ int clip_encap(struct atm_vcc *vcc,int mode)
static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
{
+ struct clip_priv *clip_priv = PRIV(dev);
struct atmarp_entry *entry;
struct atm_vcc *vcc;
+ int old;
DPRINTK("clip_start_xmit (skb %p)\n",skb);
if (!skb->dst) {
@@ -368,7 +387,7 @@ static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
skb->dst->neighbour = clip_find_neighbour(skb->dst,1);
if (!skb->dst->neighbour) {
dev_kfree_skb(skb); /* lost that one */
- PRIV(dev)->stats.tx_dropped++;
+ clip_priv->stats.tx_dropped++;
return 0;
}
#endif
@@ -386,7 +405,7 @@ return 0;
skb_queue_tail(&entry->neigh->arp_queue,skb);
else {
dev_kfree_skb(skb);
- PRIV(dev)->stats.tx_dropped++;
+ clip_priv->stats.tx_dropped++;
}
return 0;
}
@@ -401,15 +420,33 @@ return 0;
((u16 *) here)[3] = skb->protocol;
}
atomic_add(skb->truesize,&vcc->tx_inuse);
- if (!atm_may_send(vcc,0))
- netif_stop_queue(dev);
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);
- PRIV(dev)->stats.tx_packets++;
- PRIV(dev)->stats.tx_bytes += skb->len;
+ old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */
+ if (old) {
+ printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
+ return 0;
+ }
+ clip_priv->stats.tx_packets++;
+ clip_priv->stats.tx_bytes += skb->len;
(void) vcc->dev->ops->send(vcc,skb);
+ if (atm_may_send(vcc,0)) {
+ entry->vccs->xoff = 0;
+ return 0;
+ }
+ if (old) return 0;
+ spin_lock(&clip_priv->xoff_lock);
+ netif_stop_queue(dev); /* XOFF -> throttle immediately */
+ barrier();
+ if (!entry->vccs->xoff)
+ netif_start_queue(dev);
+ /* Oh, we just raced with clip_pop. netif_start_queue should be
+ good enough, because nothing should really be asleep because
+ of the brief netif_stop_queue. If this isn't true or if it
+ changes, use netif_wake_queue instead. */
+ spin_unlock(&clip_priv->xoff_lock);
return 0;
}
@@ -434,6 +471,7 @@ int clip_mkip(struct atm_vcc *vcc,int timeout)
clip_vcc->vcc = vcc;
vcc->user_back = clip_vcc;
clip_vcc->entry = NULL;
+ clip_vcc->xoff = 0;
clip_vcc->encap = 1;
clip_vcc->last_use = jiffies;
clip_vcc->idle_timeout = timeout*HZ;
@@ -523,7 +561,7 @@ static int clip_init(struct net_device *dev)
dev->hard_header_len = RFC1483LLC_LEN;
dev->mtu = RFC1626_MTU;
dev->addr_len = 0;
- dev->tx_queue_len = 100; /* "normal" queue */
+ dev->tx_queue_len = 100; /* "normal" queue (packets) */
/* When using a "real" qdisc, the qdisc determines the queue */
/* length. tx_queue_len is only used for the default case, */
/* without any more elaborate queuing. 100 is a reasonable */
@@ -538,6 +576,7 @@ static int clip_init(struct net_device *dev)
int clip_create(int number)
{
struct net_device *dev;
+ struct clip_priv *clip_priv;
int error;
if (number != -1) {
@@ -554,16 +593,18 @@ int clip_create(int number)
GFP_KERNEL);
if (!dev) return -ENOMEM;
memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv));
- dev->name = PRIV(dev)->name;
+ clip_priv = PRIV(dev);
+ dev->name = clip_priv->name;
sprintf(dev->name,"atm%d",number);
dev->init = clip_init;
- PRIV(dev)->number = number;
+ spin_lock_init(&clip_priv->xoff_lock);
+ clip_priv->number = number;
error = register_netdev(dev);
if (error) {
kfree(dev);
return error;
}
- PRIV(dev)->next = clip_devs;
+ clip_priv->next = clip_devs;
clip_devs = dev;
DPRINTK("registered (net:%s)\n",dev->name);
return number;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 5b0e9138f..8c6d8d4af 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -184,9 +184,7 @@ lec_open(struct net_device *dev)
{
struct lec_priv *priv = (struct lec_priv *)dev->priv;
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = 1;
+ netif_start_queue(dev);
memset(&priv->stats,0,sizeof(struct net_device_stats));
return 0;
@@ -214,165 +212,148 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
if (!priv->lecd) {
printk("%s:No lecd attached\n",dev->name);
priv->stats.tx_errors++;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
return -EUNATCH;
}
- if (dev->tbusy) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- printk("%s: transmit timed out\n", dev->name);
- dev->tbusy = 0;
- }
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
-
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n",
- dev->name);
- } else {
- DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
- (long)skb->head, (long)skb->data, (long)skb->tail,
- (long)skb->end);
+ DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
+ (long)skb->head, (long)skb->data, (long)skb->tail,
+ (long)skb->end);
#ifdef CONFIG_BRIDGE
- if (skb->pkt_bridged == IS_BRIDGED)
- handle_bridge(skb, dev);
+ if (skb->pkt_bridged == IS_BRIDGED)
+ handle_bridge(skb, dev);
#endif /* CONFIG_BRIDGE */
- /* Make sure we have room for lec_id */
- if (skb_headroom(skb) < 2) {
+ /* Make sure we have room for lec_id */
+ if (skb_headroom(skb) < 2) {
- DPRINTK("lec_send_packet: reallocating skb\n");
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
- skb_push(skb, 2);
+ DPRINTK("lec_send_packet: reallocating skb\n");
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL) return 0;
+ skb = skb2;
+ }
+ skb_push(skb, 2);
- /* Put le header to place, works for TokenRing too */
- lec_h = (struct lecdatahdr_8023*)skb->data;
- lec_h->le_header = htons(priv->lecid);
+ /* Put le header to place, works for TokenRing too */
+ lec_h = (struct lecdatahdr_8023*)skb->data;
+ lec_h->le_header = htons(priv->lecid);
#ifdef CONFIG_TR
- /* Ugly. Use this to realign Token Ring packets for
- * e.g. PCA-200E driver. */
- if (priv->is_trdev) {
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
+ /* Ugly. Use this to realign Token Ring packets for
+ * e.g. PCA-200E driver. */
+ if (priv->is_trdev) {
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL) return 0;
+ skb = skb2;
+ }
#endif
#if DUMP_PACKETS > 0
- printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
- skb->len, priv->lecid);
+ printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
+ skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
- for(i=0;i<skb->len && i <99;i++) {
- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
- }
+ for(i=0;i<skb->len && i <99;i++) {
+ sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
+ }
#elif DUMP_PACKETS >= 1
- for(i=0;i<skb->len && i < 30;i++) {
- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
- }
+ for(i=0;i<skb->len && i < 30;i++) {
+ sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
+ }
#endif /* DUMP_PACKETS >= 1 */
- if (i==skb->len)
- printk("%s\n",buf);
- else
- printk("%s...\n",buf);
+ if (i==skb->len)
+ printk("%s\n",buf);
+ else
+ printk("%s...\n",buf);
#endif /* DUMP_PACKETS > 0 */
- /* Minimum ethernet-frame size */
- if (skb->len <62) {
- if (skb->truesize < 62) {
- printk("%s:data packet %d / %d\n",
- dev->name,
- skb->len,skb->truesize);
- nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
- memcpy(nb,skb->data,skb->len);
- kfree(skb->head);
- skb->head = skb->data = nb;
- skb->tail = nb+62;
- skb->end = nb+64;
- skb->len=62;
- skb->truesize = 64;
- } else {
- skb->len = 62;
- }
+ /* Minimum ethernet-frame size */
+ if (skb->len <62) {
+ if (skb->truesize < 62) {
+ printk("%s:data packet %d / %d\n",
+ dev->name,
+ skb->len,skb->truesize);
+ nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+ memcpy(nb,skb->data,skb->len);
+ kfree(skb->head);
+ skb->head = skb->data = nb;
+ skb->tail = nb+62;
+ skb->end = nb+64;
+ skb->len=62;
+ skb->truesize = 64;
+ } else {
+ skb->len = 62;
}
-
- /* Send to right vcc */
- is_rdesc = 0;
- dst = lec_h->h_dest;
+ }
+
+ /* Send to right vcc */
+ is_rdesc = 0;
+ dst = lec_h->h_dest;
#ifdef CONFIG_TR
- if (priv->is_trdev) {
- dst = get_tr_dst(skb->data+2, rdesc);
- if (dst == NULL) {
- dst = rdesc;
- is_rdesc = 1;
- }
+ if (priv->is_trdev) {
+ dst = get_tr_dst(skb->data+2, rdesc);
+ if (dst == NULL) {
+ dst = rdesc;
+ is_rdesc = 1;
}
+ }
#endif
- entry = NULL;
- send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
- DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
- send_vcc, send_vcc?send_vcc->flags:0, entry);
- if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
- if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
- DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
- 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]);
- skb_queue_tail(&entry->tx_wait, skb);
- } else {
- DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name);
- 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]);
- priv->stats.tx_dropped++;
- dev_kfree_skb(skb);
- }
- dev->tbusy=0;
- return 0;
+ entry = NULL;
+ send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
+ DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
+ send_vcc, send_vcc?send_vcc->flags:0, entry);
+ if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
+ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
+ DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
+ 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]);
+ skb_queue_tail(&entry->tx_wait, skb);
+ } else {
+ DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name);
+ 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]);
+ priv->stats.tx_dropped++;
+ dev_kfree_skb(skb);
}
+ return 0;
+ }
#if DUMP_PACKETS > 0
- printk("%s:sending to vpi:%d vci:%d\n", dev->name,
- send_vcc->vpi, send_vcc->vci);
+ printk("%s:sending to vpi:%d vci:%d\n", dev->name,
+ send_vcc->vpi, send_vcc->vci);
#endif /* DUMP_PACKETS > 0 */
- while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
- DPRINTK("lec.c: emptying tx queue, ");
- 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;
- atomic_add(skb2->truesize, &send_vcc->tx_inuse);
- 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);
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb2->len;
- send_vcc->dev->ops->send(send_vcc, skb2);
- }
-
- ATM_SKB(skb)->vcc = send_vcc;
- atomic_add(skb->truesize, &send_vcc->tx_inuse);
- ATM_SKB(skb)->iovcnt = 0;
- ATM_SKB(skb)->atm_options = send_vcc->atm_options;
+ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
+ DPRINTK("lec.c: emptying tx queue, ");
+ 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;
+ atomic_add(skb2->truesize, &send_vcc->tx_inuse);
+ 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);
priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
- send_vcc->dev->ops->send(send_vcc, skb);
+ priv->stats.tx_bytes += skb2->len;
+ send_vcc->dev->ops->send(send_vcc, skb2);
}
+
+ ATM_SKB(skb)->vcc = send_vcc;
+ atomic_add(skb->truesize, &send_vcc->tx_inuse);
+ ATM_SKB(skb)->iovcnt = 0;
+ ATM_SKB(skb)->atm_options = send_vcc->atm_options;
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ send_vcc->dev->ops->send(send_vcc, skb);
+
+#if 0
/* Should we wait for card's device driver to notify us? */
dev->tbusy=0;
-
+#endif
return 0;
}
@@ -380,8 +361,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
static int
lec_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
return 0;
}
@@ -530,9 +510,7 @@ lec_atm_close(struct atm_vcc *vcc)
priv->lecd = NULL;
/* Do something needful? */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
lec_arp_destroy(priv);
if (skb_peek(&vcc->recvq))
@@ -698,7 +676,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */
!priv->is_proxy && /* Proxy wants all the packets */
- memcmp(dst, dev->dev_addr, sizeof(dev->dev_addr))) {
+ memcmp(dst, dev->dev_addr, dev->addr_len)) {
dev_kfree_skb(skb);
return;
}
@@ -814,8 +792,7 @@ lecd_attach(struct atm_vcc *vcc, int arg)
priv->path_switching_delay = (6*HZ);
if (dev_lec[i]->flags & IFF_UP) {
- dev_lec[i]->tbusy = 0;
- dev_lec[i]->start = 1;
+ netif_start_queue(dev_lec[i]);
}
MOD_INC_USE_COUNT;
return i;
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index c779b18eb..bb6eddfe6 100644
--- a/net/atm/mpoa_proc.c
+++ b/net/atm/mpoa_proc.c
@@ -45,13 +45,6 @@ static struct file_operations mpc_file_operations = {
write: proc_mpc_write,
};
-/*
- * Define allowed INODE OPERATIONS
- */
-static struct inode_operations mpc_inode_operations = {
- &mpc_file_operations,
-};
-
static int print_header(char *buff,struct mpoa_client *mpc){
if(mpc != NULL){
return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);
@@ -330,7 +323,7 @@ int mpc_proc_init(void)
printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
return -ENOMEM;
}
- p->ops = &mpc_inode_operations;
+ p->proc_fops = &mpc_file_operations;
return 0;
}
diff --git a/net/atm/proc.c b/net/atm/proc.c
index b67ae428a..904dc43ba 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -63,15 +63,6 @@ static struct file_operations proc_spec_atm_operations = {
read: proc_spec_atm_read,
};
-static struct inode_operations proc_dev_atm_inode_operations = {
- &proc_dev_atm_operations, /* default ATM directory file-ops */
-};
-
-static struct inode_operations proc_spec_atm_inode_operations = {
- &proc_spec_atm_operations, /* default ATM directory file-ops */
-};
-
-
static void add_stats(char *buf,const char *aal,
const struct atm_aal_stats *stats)
{
@@ -563,7 +554,7 @@ int atm_proc_dev_register(struct atm_dev *dev)
if (!dev->proc_entry)
goto fail0;
dev->proc_entry->data = dev;
- dev->proc_entry->ops = &proc_dev_atm_inode_operations;
+ dev->proc_entry->proc_fops = &proc_dev_atm_operations;
return 0;
kfree(dev->proc_entry);
fail0:
@@ -584,7 +575,7 @@ void atm_proc_dev_deregister(struct atm_dev *dev)
name = create_proc_entry(#name,0,atm_proc_root); \
if (!name) goto cleanup; \
name->data = atm_##name##_info; \
- name->ops = &proc_spec_atm_inode_operations
+ name->proc_fops = &proc_spec_atm_operations
int __init atm_proc_init(void)
diff --git a/net/atm/raw.c b/net/atm/raw.c
index 0db4aabb6..355382502 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -1,6 +1,6 @@
/* net/atm/raw.c - Raw AAL0 and AAL5 transports */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/module.h>
@@ -38,7 +38,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
{
DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
wake_up(&vcc->wsleep);
}