diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
commit | 8624512aa908741ba2795200133eae0d7f4557ea (patch) | |
tree | d5d3036fccf2604f4c98dedc11e8adb929d6b52e /net/atm | |
parent | 7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff) |
Merge with 2.3.48.
Diffstat (limited to 'net/atm')
-rw-r--r-- | net/atm/clip.c | 67 | ||||
-rw-r--r-- | net/atm/lec.c | 255 | ||||
-rw-r--r-- | net/atm/mpoa_proc.c | 9 | ||||
-rw-r--r-- | net/atm/proc.c | 13 | ||||
-rw-r--r-- | net/atm/raw.c | 4 |
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); } |