local_irq_save(flags);
netif_tx_lock(dev);
if ((netif_queue_stopped(dev) ||
- netif_subqueue_stopped(dev, skb->queue_mapping)) ||
+ netif_subqueue_stopped(dev, skb)) ||
dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
skb_queue_head(&npinfo->txq, skb);
netif_tx_unlock(dev);
* network adapter, forcing superfluous retries and possibly timeouts.
* Thus, we set our budget to greater than 1.
*/
-static void poll_napi(struct netpoll *np)
+static int poll_one_napi(struct netpoll_info *npinfo,
+ struct napi_struct *napi, int budget)
+{
+ int work;
+
+ /* net_rx_action's ->poll() invocations and our's are
+ * synchronized by this test which is only made while
+ * holding the napi->poll_lock.
+ */
+ if (!test_bit(NAPI_STATE_SCHED, &napi->state))
+ return budget;
+
+ npinfo->rx_flags |= NETPOLL_RX_DROP;
+ atomic_inc(&trapped);
+
+ work = napi->poll(napi, budget);
+
+ atomic_dec(&trapped);
+ npinfo->rx_flags &= ~NETPOLL_RX_DROP;
+
+ return budget - work;
+}
+
+static void poll_napi(struct net_device *dev)
{
- struct netpoll_info *npinfo = np->dev->npinfo;
struct napi_struct *napi;
int budget = 16;
- list_for_each_entry(napi, &np->dev->napi_list, dev_list) {
- if (test_bit(NAPI_STATE_SCHED, &napi->state) &&
- napi->poll_owner != smp_processor_id() &&
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (napi->poll_owner != smp_processor_id() &&
spin_trylock(&napi->poll_lock)) {
- npinfo->rx_flags |= NETPOLL_RX_DROP;
- atomic_inc(&trapped);
-
- napi->poll(napi, budget);
-
- atomic_dec(&trapped);
- npinfo->rx_flags &= ~NETPOLL_RX_DROP;
+ budget = poll_one_napi(dev->npinfo, napi, budget);
spin_unlock(&napi->poll_lock);
+
+ if (!budget)
+ break;
}
}
}
static void service_arp_queue(struct netpoll_info *npi)
{
- struct sk_buff *skb;
-
- if (unlikely(!npi))
- return;
+ if (npi) {
+ struct sk_buff *skb;
- skb = skb_dequeue(&npi->arp_tx);
-
- while (skb != NULL) {
- arp_reply(skb);
- skb = skb_dequeue(&npi->arp_tx);
+ while ((skb = skb_dequeue(&npi->arp_tx)))
+ arp_reply(skb);
}
}
void netpoll_poll(struct netpoll *np)
{
- if (!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
+ struct net_device *dev = np->dev;
+
+ if (!dev || !netif_running(dev) || !dev->poll_controller)
return;
/* Process pending work on NIC */
- np->dev->poll_controller(np->dev);
- if (!list_empty(&np->dev->napi_list))
- poll_napi(np);
+ dev->poll_controller(dev);
- service_arp_queue(np->dev->npinfo);
+ poll_napi(dev);
+
+ service_arp_queue(dev->npinfo);
zap_completion_queue();
}
while (clist != NULL) {
struct sk_buff *skb = clist;
clist = clist->next;
- if (skb->destructor)
+ if (skb->destructor) {
+ atomic_inc(&skb->users);
dev_kfree_skb_any(skb); /* put this one back */
- else
+ } else {
__kfree_skb(skb);
+ }
}
}
tries > 0; --tries) {
if (netif_tx_trylock(dev)) {
if (!netif_queue_stopped(dev) &&
- !netif_subqueue_stopped(dev, skb->queue_mapping))
+ !netif_subqueue_stopped(dev, skb))
status = dev->hard_start_xmit(skb, dev);
netif_tx_unlock(dev);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP);
- memcpy(eth->h_source, np->local_mac, 6);
- memcpy(eth->h_dest, np->remote_mac, 6);
+ memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
+ memcpy(eth->h_dest, np->remote_mac, ETH_ALEN);
skb->dev = np->dev;
memcpy(&tip, arp_ptr, 4);
/* Should we ignore arp? */
- if (tip != htonl(np->local_ip) || LOOPBACK(tip) || MULTICAST(tip))
+ if (tip != htonl(np->local_ip) ||
+ ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
return;
size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4);
/* Fill the device header for the ARP frame */
if (dev_hard_header(send_skb, skb->dev, ptype,
- sha, np->local_mac,
+ sha, np->dev->dev_addr,
send_skb->len) < 0) {
kfree_skb(send_skb);
return;
}
}
- if (is_zero_ether_addr(np->local_mac) && ndev->dev_addr)
- memcpy(np->local_mac, ndev->dev_addr, 6);
-
if (!np->local_ip) {
rcu_read_lock();
in_dev = __in_dev_get_rcu(ndev);
cancel_rearming_delayed_work(&npinfo->tx_work);
/* clean after last, unfinished work */
- if (!skb_queue_empty(&npinfo->txq)) {
- struct sk_buff *skb;
- skb = __skb_dequeue(&npinfo->txq);
- kfree_skb(skb);
- }
+ __skb_queue_purge(&npinfo->txq);
kfree(npinfo);
np->dev->npinfo = NULL;
}