libata-sff: separate out BMDMA qc_issue
[safe/jmp/linux-2.6] / drivers / net / loopback.c
index 91d0858..72b7949 100644 (file)
 struct pcpu_lstats {
        unsigned long packets;
        unsigned long bytes;
+       unsigned long drops;
 };
 
 /*
  * The higher levels take care of making this non-reentrant (it's
  * called with bh's disabled).
  */
-static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t loopback_xmit(struct sk_buff *skb,
+                                struct net_device *dev)
 {
-       struct pcpu_lstats *pcpu_lstats, *lb_stats;
+       struct pcpu_lstats __percpu *pcpu_lstats;
+       struct pcpu_lstats *lb_stats;
+       int len;
 
        skb_orphan(skb);
 
-       skb->protocol = eth_type_trans(skb,dev);
+       skb->protocol = eth_type_trans(skb, dev);
 
        /* it's OK to use per_cpu_ptr() because BHs are off */
-       pcpu_lstats = dev->ml_priv;
-       lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
-       lb_stats->bytes += skb->len;
-       lb_stats->packets++;
+       pcpu_lstats = (void __percpu __force *)dev->ml_priv;
+       lb_stats = this_cpu_ptr(pcpu_lstats);
 
-       netif_rx(skb);
+       len = skb->len;
+       if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
+               lb_stats->bytes += len;
+               lb_stats->packets++;
+       } else
+               lb_stats->drops++;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *get_stats(struct net_device *dev)
+static struct net_device_stats *loopback_get_stats(struct net_device *dev)
 {
-       const struct pcpu_lstats *pcpu_lstats;
+       const struct pcpu_lstats __percpu *pcpu_lstats;
        struct net_device_stats *stats = &dev->stats;
        unsigned long bytes = 0;
        unsigned long packets = 0;
+       unsigned long drops = 0;
        int i;
 
-       pcpu_lstats = dev->ml_priv;
+       pcpu_lstats = (void __percpu __force *)dev->ml_priv;
        for_each_possible_cpu(i) {
                const struct pcpu_lstats *lb_stats;
 
                lb_stats = per_cpu_ptr(pcpu_lstats, i);
                bytes   += lb_stats->bytes;
                packets += lb_stats->packets;
+               drops   += lb_stats->drops;
        }
        stats->rx_packets = packets;
        stats->tx_packets = packets;
-       stats->rx_bytes = bytes;
-       stats->tx_bytes = bytes;
+       stats->rx_dropped = drops;
+       stats->rx_errors  = drops;
+       stats->rx_bytes   = bytes;
+       stats->tx_bytes   = bytes;
        return stats;
 }
 
@@ -125,38 +136,44 @@ static const struct ethtool_ops loopback_ethtool_ops = {
 
 static int loopback_dev_init(struct net_device *dev)
 {
-       struct pcpu_lstats *lstats;
+       struct pcpu_lstats __percpu *lstats;
 
        lstats = alloc_percpu(struct pcpu_lstats);
        if (!lstats)
                return -ENOMEM;
 
-       dev->ml_priv = lstats;
+       dev->ml_priv = (void __force *)lstats;
        return 0;
 }
 
 static void loopback_dev_free(struct net_device *dev)
 {
-       struct pcpu_lstats *lstats = dev->ml_priv;
+       struct pcpu_lstats __percpu *lstats =
+               (void __percpu __force *)dev->ml_priv;
 
        free_percpu(lstats);
        free_netdev(dev);
 }
 
+static const struct net_device_ops loopback_ops = {
+       .ndo_init      = loopback_dev_init,
+       .ndo_start_xmit= loopback_xmit,
+       .ndo_get_stats = loopback_get_stats,
+};
+
 /*
  * The loopback device is special. There is only one instance
  * per network namespace.
  */
 static void loopback_setup(struct net_device *dev)
 {
-       dev->get_stats          = &get_stats;
        dev->mtu                = (16 * 1024) + 20 + 20 + 12;
-       dev->hard_start_xmit    = loopback_xmit;
        dev->hard_header_len    = ETH_HLEN;     /* 14   */
        dev->addr_len           = ETH_ALEN;     /* 6    */
        dev->tx_queue_len       = 0;
        dev->type               = ARPHRD_LOOPBACK;      /* 0x0001*/
        dev->flags              = IFF_LOOPBACK;
+       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST
                | NETIF_F_TSO
                | NETIF_F_NO_CSUM
@@ -165,8 +182,8 @@ static void loopback_setup(struct net_device *dev)
                | NETIF_F_NETNS_LOCAL;
        dev->ethtool_ops        = &loopback_ethtool_ops;
        dev->header_ops         = &eth_header_ops;
-       dev->init = loopback_dev_init;
-       dev->destructor = loopback_dev_free;
+       dev->netdev_ops         = &loopback_ops;
+       dev->destructor         = loopback_dev_free;
 }
 
 /* Setup and register the loopback device. */
@@ -192,29 +209,12 @@ static __net_init int loopback_net_init(struct net *net)
 out_free_netdev:
        free_netdev(dev);
 out:
-       if (net == &init_net)
+       if (net_eq(net, &init_net))
                panic("loopback: Failed to register netdevice: %d\n", err);
        return err;
 }
 
-static __net_exit void loopback_net_exit(struct net *net)
-{
-       struct net_device *dev = net->loopback_dev;
-
-       unregister_netdev(dev);
-}
-
-static struct pernet_operations __net_initdata loopback_net_ops = {
+/* Registered in net/core/dev.c */
+struct pernet_operations __net_initdata loopback_net_ops = {
        .init = loopback_net_init,
-       .exit = loopback_net_exit,
 };
-
-static int __init loopback_init(void)
-{
-       return register_pernet_device(&loopback_net_ops);
-}
-
-/* Loopback is special. It should be initialized before any other network
- * device and network subsystem.
- */
-fs_initcall(loopback_init);