summaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/usbnet.c
diff options
context:
space:
mode:
authorGreg Ungerer <gerg@linux-m68k.org>2017-04-03 07:50:03 +0200
committerDavid S. Miller <davem@davemloft.net>2017-04-04 04:09:40 +0200
commitc8b5d129ee293bcf972e7279ac996bb8a138505c (patch)
tree540780055f735ffe4eb500f0f429a6e5d2cb5bb9 /drivers/net/usb/usbnet.c
parentsoreuseport: use "unsigned int" in __reuseport_alloc() (diff)
downloadlinux-c8b5d129ee293bcf972e7279ac996bb8a138505c.tar.xz
linux-c8b5d129ee293bcf972e7279ac996bb8a138505c.zip
net: usbnet: support 64bit stats
Add support for the net stats64 counters to the usbnet core. With that in place put the hooks into every usbnet driver to use it. This is a strait forward addition of 64bit counters for RX and TX packet and byte counts. It is done in the same style as for the other net drivers that support stats64. Note that the other stats fields remain as 32bit sized values (error counts, etc). The motivation to add this is that it is not particularly difficult to get the RX and TX byte counts to wrap on 32bit platforms. Signed-off-by: Greg Ungerer <gerg@linux-m68k.org> Acked-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r--drivers/net/usb/usbnet.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 13d4ec5f6f34..9890656af735 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -316,6 +316,7 @@ static void __usbnet_status_stop_force(struct usbnet *dev)
*/
void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
{
+ struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
int status;
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
@@ -327,8 +328,10 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
if (skb->protocol == 0)
skb->protocol = eth_type_trans (skb, dev->net);
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb->len;
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->rx_packets++;
+ stats64->rx_bytes += skb->len;
+ u64_stats_update_end(&stats64->syncp);
netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
skb->len + sizeof (struct ethhdr), skb->protocol);
@@ -981,6 +984,37 @@ int usbnet_set_link_ksettings(struct net_device *net,
}
EXPORT_SYMBOL_GPL(usbnet_set_link_ksettings);
+void usbnet_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats)
+{
+ struct usbnet *dev = netdev_priv(net);
+ unsigned int start;
+ int cpu;
+
+ netdev_stats_to_stats64(stats, &net->stats);
+
+ for_each_possible_cpu(cpu) {
+ struct pcpu_sw_netstats *stats64;
+ u64 rx_packets, rx_bytes;
+ u64 tx_packets, tx_bytes;
+
+ stats64 = per_cpu_ptr(dev->stats64, cpu);
+
+ do {
+ start = u64_stats_fetch_begin_irq(&stats64->syncp);
+ rx_packets = stats64->rx_packets;
+ rx_bytes = stats64->rx_bytes;
+ tx_packets = stats64->tx_packets;
+ tx_bytes = stats64->tx_bytes;
+ } while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ stats->tx_packets += tx_packets;
+ stats->tx_bytes += tx_bytes;
+ }
+}
+EXPORT_SYMBOL_GPL(usbnet_get_stats64);
+
u32 usbnet_get_link (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
@@ -1212,8 +1246,12 @@ static void tx_complete (struct urb *urb)
struct usbnet *dev = entry->dev;
if (urb->status == 0) {
- dev->net->stats.tx_packets += entry->packets;
- dev->net->stats.tx_bytes += entry->length;
+ struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
+
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->tx_packets += entry->packets;
+ stats64->tx_bytes += entry->length;
+ u64_stats_update_end(&stats64->syncp);
} else {
dev->net->stats.tx_errors++;
@@ -1570,6 +1608,7 @@ void usbnet_disconnect (struct usb_interface *intf)
usb_free_urb(dev->interrupt);
kfree(dev->padding_pkt);
+ free_percpu(dev->stats64);
free_netdev(net);
}
EXPORT_SYMBOL_GPL(usbnet_disconnect);
@@ -1581,6 +1620,7 @@ static const struct net_device_ops usbnet_netdev_ops = {
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_set_rx_mode = usbnet_set_rx_mode,
.ndo_change_mtu = usbnet_change_mtu,
+ .ndo_get_stats64 = usbnet_get_stats64,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -1642,6 +1682,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;
+
+ dev->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!dev->stats64)
+ goto out0;
+
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
init_waitqueue_head(&dev->wait);
@@ -1781,6 +1826,8 @@ out1:
*/
cancel_work_sync(&dev->kevent);
del_timer_sync(&dev->delay);
+ free_percpu(dev->stats64);
+out0:
free_netdev(net);
out:
return status;