void (*old_write_space)(struct sock *);
struct net_device *dev;
-
- struct sk_buff_head tx_queue;
- struct work_struct tx_work;
- spinlock_t tx_lock;
- unsigned tx_max;
};
static __be16 gprs_type_trans(struct sk_buff *skb)
return htons(0);
}
+static void gprs_writeable(struct gprs_dev *gp)
+{
+ struct net_device *dev = gp->dev;
+
+ if (pep_writeable(gp->sk))
+ netif_wake_queue(dev);
+}
+
/*
* Socket callbacks
*/
rskb->truesize += rskb->len;
/* Avoid nested fragments */
- for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+ skb_walk_frags(skb, fs)
flen += fs->len;
skb->next = skb_shinfo(skb)->frag_list;
- skb_shinfo(skb)->frag_list = NULL;
+ skb_frag_list_init(skb);
skb->len -= flen;
skb->data_len -= flen;
skb->truesize -= flen;
static void gprs_write_space(struct sock *sk)
{
struct gprs_dev *gp = sk->sk_user_data;
- struct net_device *dev = gp->dev;
- unsigned credits = pep_writeable(sk);
- spin_lock_bh(&gp->tx_lock);
- gp->tx_max = credits;
- if (credits > skb_queue_len(&gp->tx_queue) && netif_running(dev))
- netif_wake_queue(dev);
- spin_unlock_bh(&gp->tx_lock);
+ if (netif_running(gp->dev))
+ gprs_writeable(gp);
}
/*
{
struct gprs_dev *gp = netdev_priv(dev);
- gprs_write_space(gp->sk);
+ gprs_writeable(gp);
return 0;
}
static int gprs_close(struct net_device *dev)
{
- struct gprs_dev *gp = netdev_priv(dev);
-
netif_stop_queue(dev);
- flush_work(&gp->tx_work);
return 0;
}
static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gprs_dev *gp = netdev_priv(dev);
+ struct sock *sk = gp->sk;
+ int len, err;
switch (skb->protocol) {
case htons(ETH_P_IP):
return 0;
}
- spin_lock(&gp->tx_lock);
- if (likely(skb_queue_len(&gp->tx_queue) < gp->tx_max)) {
- skb_queue_tail(&gp->tx_queue, skb);
- skb = NULL;
- }
- if (skb_queue_len(&gp->tx_queue) >= gp->tx_max)
- netif_stop_queue(dev);
- spin_unlock(&gp->tx_lock);
-
- schedule_work(&gp->tx_work);
- if (unlikely(skb))
- dev_kfree_skb(skb);
- return 0;
-}
-
-static void gprs_tx(struct work_struct *work)
-{
- struct gprs_dev *gp = container_of(work, struct gprs_dev, tx_work);
- struct net_device *dev = gp->dev;
- struct sock *sk = gp->sk;
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&gp->tx_queue)) != NULL) {
- int err;
-
- dev->stats.tx_bytes += skb->len;
+ skb_orphan(skb);
+ skb_set_owner_w(skb, sk);
+ len = skb->len;
+ err = pep_write(sk, skb);
+ if (err) {
+ LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
+ dev->name, err);
+ dev->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ } else {
dev->stats.tx_packets++;
-
- skb_orphan(skb);
- skb_set_owner_w(skb, sk);
-
- lock_sock(sk);
- err = pep_write(sk, skb);
- if (err) {
- LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
- dev->name, err);
- dev->stats.tx_aborted_errors++;
- dev->stats.tx_errors++;
- }
- release_sock(sk);
+ dev->stats.tx_bytes += len;
}
- lock_sock(sk);
- gprs_write_space(sk);
- release_sock(sk);
+ netif_stop_queue(dev);
+ if (pep_writeable(sk))
+ netif_wake_queue(dev);
+ return 0;
}
static int gprs_set_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static const struct net_device_ops gprs_netdev_ops = {
+ .ndo_open = gprs_open,
+ .ndo_stop = gprs_close,
+ .ndo_start_xmit = gprs_xmit,
+ .ndo_change_mtu = gprs_set_mtu,
+};
+
static void gprs_setup(struct net_device *dev)
{
dev->features = NETIF_F_FRAGLIST;
dev->addr_len = 0;
dev->tx_queue_len = 10;
+ dev->netdev_ops = &gprs_netdev_ops;
dev->destructor = free_netdev;
- dev->open = gprs_open;
- dev->stop = gprs_close;
- dev->hard_start_xmit = gprs_xmit; /* mandatory */
- dev->change_mtu = gprs_set_mtu;
}
/*
if (!dev)
return -ENOMEM;
gp = netdev_priv(dev);
+ gp->sk = sk;
gp->dev = dev;
- gp->tx_max = 0;
- spin_lock_init(&gp->tx_lock);
- skb_queue_head_init(&gp->tx_queue);
- INIT_WORK(&gp->tx_work, gprs_tx);
netif_stop_queue(dev);
err = register_netdev(dev);
sk->sk_data_ready = gprs_data_ready;
sk->sk_write_space = gprs_write_space;
release_sock(sk);
-
sock_hold(sk);
- gp->sk = sk;
printk(KERN_DEBUG"%s: attached\n", dev->name);
return dev->ifindex;