struct net_device *device;
/* keep old push, pop functions for chaining */
void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
- /* void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); */
+ void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
enum br2684_encaps encaps;
struct list_head brvccs;
#ifdef CONFIG_ATM_BR2684_IPFILTER
return NULL;
}
+/* chained vcc->pop function. Check if we should wake the netif_queue */
+static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+ struct br2684_vcc *brvcc = BR2684_VCC(vcc);
+ struct net_device *net_dev = skb->dev;
+
+ pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev);
+ brvcc->old_pop(vcc, skb);
+
+ if (!net_dev)
+ return;
+
+ if (atm_may_send(vcc, 0))
+ netif_wake_queue(net_dev);
+
+}
/*
* Send a packet out a particular vcc. Not to useful right now, but paves
* the way for multiple vcc's per itf. Returns true if we can send,
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
- if (!atm_may_send(atmvcc, skb->truesize)) {
- /*
- * We free this here for now, because we cannot know in a higher
- * layer whether the skb pointer it supplied wasn't freed yet.
- * Now, it always is.
- */
- dev_kfree_skb(skb);
- return 0;
- }
atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = atmvcc->atm_options;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
atmvcc->send(atmvcc, skb);
+
+ if (!atm_may_send(atmvcc, 0)) {
+ netif_stop_queue(brvcc->device);
+ /*check for race with br2684_pop*/
+ if (atm_may_send(atmvcc, 0))
+ netif_start_queue(brvcc->device);
+ }
+
return 1;
}
return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */
}
-static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct br2684_dev *brdev = BRPRIV(dev);
struct br2684_vcc *brvcc;
- pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst);
+ pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb));
read_lock(&devs_lock);
brvcc = pick_outgoing_vcc(skb, brdev);
if (brvcc == NULL) {
/* netif_stop_queue(dev); */
dev_kfree_skb(skb);
read_unlock(&devs_lock);
- return 0;
+ return NETDEV_TX_OK;
}
if (!br2684_xmit_vcc(skb, dev, brvcc)) {
/*
dev->stats.tx_fifo_errors++;
}
read_unlock(&devs_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
*/
static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
{
+ struct sk_buff_head queue;
int err;
struct br2684_vcc *brvcc;
- struct sk_buff *skb;
+ struct sk_buff *skb, *tmp;
struct sk_buff_head *rq;
struct br2684_dev *brdev;
struct net_device *net_dev;
atmvcc->user_back = brvcc;
brvcc->encaps = (enum br2684_encaps)be.encaps;
brvcc->old_push = atmvcc->push;
+ brvcc->old_pop = atmvcc->pop;
barrier();
atmvcc->push = br2684_push;
+ atmvcc->pop = br2684_pop;
+ __skb_queue_head_init(&queue);
rq = &sk_atm(atmvcc)->sk_receive_queue;
spin_lock_irqsave(&rq->lock, flags);
- if (skb_queue_empty(rq)) {
- skb = NULL;
- } else {
- /* NULL terminate the list. */
- rq->prev->next = NULL;
- skb = rq->next;
- }
- rq->prev = rq->next = (struct sk_buff *)rq;
- rq->qlen = 0;
+ skb_queue_splice_init(rq, &queue);
spin_unlock_irqrestore(&rq->lock, flags);
- while (skb) {
- struct sk_buff *next = skb->next;
+ skb_queue_walk_safe(&queue, skb, tmp) {
+ struct net_device *dev = skb->dev;
- skb->next = skb->prev = NULL;
- br2684_push(atmvcc, skb);
- skb->dev->stats.rx_bytes -= skb->len;
- skb->dev->stats.rx_packets--;
+ dev->stats.rx_bytes -= skb->len;
+ dev->stats.rx_packets--;
- skb = next;
+ br2684_push(atmvcc, skb);
}
__module_get(THIS_MODULE);
return 0;
struct br2684_dev *brdev = BRPRIV(netdev);
ether_setup(netdev);
+ brdev->net_dev = netdev;
netdev->netdev_ops = &br2684_netdev_ops;