Re: [PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Bjørn Mork


On March 31, 2017 3:27:59 PM CEST, Greg Ungerer  wrote:
>On 31/03/17 18:48, Bjørn Mork wrote:
>
>>> +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, >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(>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(>syncp, start));
>>> +
>>> +   stats->rx_packets += rx_packets;
>>> +   stats->rx_bytes += rx_bytes;
>>> +   stats->tx_packets += tx_packets;
>>> +   stats->tx_bytes += tx_bytes;
>>> +   }
>>> +}
>>
>> So we only count packets and bytes.  No errors.  Why?
>
>All stats are counted. That call to netdev_stats_to_stats64() transfers
>all other stats struct fields (errors, etc) to the stats64 struct.
>No error counts are lost (though they are only stored as 32bits values
>on 32bit machines).


Ah, right. Thanks for explaining and sorry for being so slow. Then I have no 
objection to the patch as it is.


Bjørn



Re: [PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Greg Ungerer

Hi Oliver,

On 31/03/17 19:39, Oliver Neukum wrote:

Am Freitag, den 31.03.2017, 10:48 +0200 schrieb Bjørn Mork:

You get *all* the "0" line drivers for free, not only "qmi_wwan".  No
code changes needed, except for adding the single .ndo line to drivers
overriding the usbnet default net_device_ops. And even that only applies
to a few of them.  Most will be OK if you just change the usbnet
default.

I don't think the size of a complete series will be terrifying to
anyone.


It would really be nice to do that.
However, if you really don't want to do it, well you wrote
a patch. But I am afraid dropping the error count is not acceptable.


Of course dropping error counts would be, but that doesn't happen.

I will generate a patch that converts all usbnet users in one go.

Regards
Greg







Re: [PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Greg Ungerer

Hi Bjorn,

On 31/03/17 18:48, Bjørn Mork wrote:

Greg Ungerer  writes:

Add support for the net stats64 counters to the usbnet core and then to
the qmi_wwan driver.

This is a strait forward addition of 64bit counters for RX and TX packets
and byte counts. It is done in the same style as for the other net drivers
that support stats64.

The bulk of the change is to the usbnet core. Then it is trivial to use
that in the qmi_wwan.c driver. It would be very simple to extend this
support to other usbnet based drivers.


Sorry, but I am starting to have my doubts about this partial conversion
of the usbnet stats.  I don't have any problem with doing incremental
changes.  But in this case it means running duplicate code. And I see no
reasons to justify doing this incrementally.  As you say: It is very
simple to extend it to all usbnet drivers when the basic infrastructure
is in place.

You alreay do most of that work. So why not just update the other
drivers too, allowing us to drop the legacy counters?  Deleting code is
always good :)


Ok.



+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, >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(>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(>syncp, start));
+
+   stats->rx_packets += rx_packets;
+   stats->rx_bytes += rx_bytes;
+   stats->tx_packets += tx_packets;
+   stats->tx_bytes += tx_bytes;
+   }
+}


So we only count packets and bytes.  No errors.  Why?


All stats are counted. That call to netdev_stats_to_stats64() transfers
all other stats struct fields (errors, etc) to the stats64 struct.
No error counts are lost (though they are only stored as 32bits values
on 32bit machines).



@@ -1212,8 +1249,15 @@ static void tx_complete (struct urb *urb)
struct usbnet   *dev = entry->dev;

if (urb->status == 0) {
+   struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
+
dev->net->stats.tx_packets += entry->packets;
dev->net->stats.tx_bytes += entry->length;
+
+   u64_stats_update_begin(>syncp);
+   stats64->tx_packets += entry->packets;
+   stats64->tx_bytes += entry->length;
+   u64_stats_update_end(>syncp);
} else {
dev->net->stats.tx_errors++;




This is one place where the old stats counted errors too.  But there are more:

bjorn@miraculix:/usr/local/src/git/linux$ git grep -E -- '->stats.*\+' 
drivers/net/usb/usbnet.c|grep -Ev '(bytes|packet)'
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_length_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_over_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.tx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.tx_dropped++;


Personally, I'd rather have incorrect byte counters than losing these


Luckily we can have all values correct :-)



error counters. They are valuable debugging aids. I don't see why they
cannot be converted to 64bit stats right away.  Except that it makes the
amount of double accounting much more obvious...

Which is why I have landed on on a request to convert all the usbnet
drivers in one go.  There aren't that many of them, and even fewer
touching the stats outside of usbnet.c.  Among those few, none have more
than 6 lines currently touching "stats":

bjorn@miraculix:/usr/local/src/git/linux$ for f in `git grep -l -- 'usbnet_probe' 
drivers/net/usb/`; do grep -Hc -- '->stats' $f; done
drivers/net/usb/asix_devices.c:0
drivers/net/usb/ax88179_178a.c:0
drivers/net/usb/cdc_eem.c:1
drivers/net/usb/cdc_ether.c:0
drivers/net/usb/cdc_mbim.c:0
drivers/net/usb/cdc_ncm.c:4
drivers/net/usb/cdc_subset.c:0
drivers/net/usb/ch9200.c:0
drivers/net/usb/cx82310_eth.c:0
drivers/net/usb/dm9601.c:5
drivers/net/usb/gl620a.c:0
drivers/net/usb/huawei_cdc_ncm.c:0
drivers/net/usb/int51x1.c:0
drivers/net/usb/kalmia.c:0

Re: [PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Oliver Neukum
Am Freitag, den 31.03.2017, 10:48 +0200 schrieb Bjørn Mork:
> You get *all* the "0" line drivers for free, not only "qmi_wwan".  No
> code changes needed, except for adding the single .ndo line to drivers
> overriding the usbnet default net_device_ops. And even that only applies
> to a few of them.  Most will be OK if you just change the usbnet
> default.
> 
> I don't think the size of a complete series will be terrifying to
> anyone.

It would really be nice to do that.
However, if you really don't want to do it, well you wrote
a patch. But I am afraid dropping the error count is not acceptable.

Regards
Oliver



Re: [PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Bjørn Mork
Greg Ungerer  writes:

> Add support for the net stats64 counters to the usbnet core and then to
> the qmi_wwan driver.
>
> This is a strait forward addition of 64bit counters for RX and TX packets
> and byte counts. It is done in the same style as for the other net drivers
> that support stats64.
>
> The bulk of the change is to the usbnet core. Then it is trivial to use
> that in the qmi_wwan.c driver. It would be very simple to extend this
> support to other usbnet based drivers.

Sorry, but I am starting to have my doubts about this partial conversion
of the usbnet stats.  I don't have any problem with doing incremental
changes.  But in this case it means running duplicate code. And I see no
reasons to justify doing this incrementally.  As you say: It is very
simple to extend it to all usbnet drivers when the basic infrastructure
is in place.

You alreay do most of that work. So why not just update the other
drivers too, allowing us to drop the legacy counters?  Deleting code is
always good :)


> +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, >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(>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(>syncp, start));
> +
> + stats->rx_packets += rx_packets;
> + stats->rx_bytes += rx_bytes;
> + stats->tx_packets += tx_packets;
> + stats->tx_bytes += tx_bytes;
> + }
> +}

So we only count packets and bytes.  No errors.  Why?

> @@ -1212,8 +1249,15 @@ static void tx_complete (struct urb *urb)
>   struct usbnet   *dev = entry->dev;
>  
>   if (urb->status == 0) {
> + struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
> +
>   dev->net->stats.tx_packets += entry->packets;
>   dev->net->stats.tx_bytes += entry->length;
> +
> + u64_stats_update_begin(>syncp);
> + stats64->tx_packets += entry->packets;
> + stats64->tx_bytes += entry->length;
> + u64_stats_update_end(>syncp);
>   } else {
>   dev->net->stats.tx_errors++;
>  


This is one place where the old stats counted errors too.  But there are more:

bjorn@miraculix:/usr/local/src/git/linux$ git grep -E -- '->stats.*\+' 
drivers/net/usb/usbnet.c|grep -Ev '(bytes|packet)'
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_length_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_over_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.rx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.tx_errors++;
drivers/net/usb/usbnet.c:   dev->net->stats.tx_dropped++;


Personally, I'd rather have incorrect byte counters than losing these
error counters. They are valuable debugging aids. I don't see why they
cannot be converted to 64bit stats right away.  Except that it makes the
amount of double accounting much more obvious...

Which is why I have landed on on a request to convert all the usbnet
drivers in one go.  There aren't that many of them, and even fewer
touching the stats outside of usbnet.c.  Among those few, none have more
than 6 lines currently touching "stats":

bjorn@miraculix:/usr/local/src/git/linux$ for f in `git grep -l -- 
'usbnet_probe' drivers/net/usb/`; do grep -Hc -- '->stats' $f; done
drivers/net/usb/asix_devices.c:0
drivers/net/usb/ax88179_178a.c:0
drivers/net/usb/cdc_eem.c:1
drivers/net/usb/cdc_ether.c:0
drivers/net/usb/cdc_mbim.c:0
drivers/net/usb/cdc_ncm.c:4
drivers/net/usb/cdc_subset.c:0
drivers/net/usb/ch9200.c:0
drivers/net/usb/cx82310_eth.c:0
drivers/net/usb/dm9601.c:5
drivers/net/usb/gl620a.c:0
drivers/net/usb/huawei_cdc_ncm.c:0
drivers/net/usb/int51x1.c:0
drivers/net/usb/kalmia.c:0
drivers/net/usb/lg-vl600.c:4
drivers/net/usb/mcs7830.c:4
drivers/net/usb/net1080.c:6
drivers/net/usb/plusb.c:0
drivers/net/usb/qmi_wwan.c:0
drivers/net/usb/rndis_host.c:1
drivers/net/usb/sierra_net.c:6
drivers/net/usb/smsc75xx.c:4
drivers/net/usb/smsc95xx.c:5
drivers/net/usb/sr9700.c:0

[PATCHv3] net: usbnet: support 64bit stats in qmi_wwan driver

2017-03-31 Thread Greg Ungerer
Add support for the net stats64 counters to the usbnet core and then to
the qmi_wwan driver.

This is a strait forward addition of 64bit counters for RX and TX packets
and byte counts. It is done in the same style as for the other net drivers
that support stats64.

The bulk of the change is to the usbnet core. Then it is trivial to use
that in the qmi_wwan.c driver. It would be very simple to extend this
support to other usbnet based drivers.

Note that the old 32bit stats counters are still incremented as well -
to cater for other driver users of the usbnet core. When all users are
upgraded to use 64bit stats we can remove the code to increment those.

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 
---
 drivers/net/usb/qmi_wwan.c |  1 +
 drivers/net/usb/usbnet.c   | 52 ++
 include/linux/usb/usbnet.h |  4 
 3 files changed, 57 insertions(+)

v2: EXPORT usbnet_get_stats64()
rebase on top of net-next

v3: use percpu vars for stats64 counters

diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 629fe64..dd2b65e 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -544,6 +544,7 @@ static int qmi_wwan_mac_addr(struct net_device *dev, void 
*p)
.ndo_change_mtu = usbnet_change_mtu,
.ndo_set_mac_address= qmi_wwan_mac_addr,
.ndo_validate_addr  = eth_validate_addr,
+   .ndo_get_stats64= usbnet_get_stats64,
 };
 
 /* using a counter to merge subdriver requests with our own into a
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 13d4ec5..6618a67 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, >flags)) {
@@ -330,6 +331,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff 
*skb)
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
 
+   u64_stats_update_begin(>syncp);
+   stats64->rx_packets++;
+   stats64->rx_bytes += skb->len;
+   u64_stats_update_end(>syncp);
+
netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
  skb->len + sizeof (struct ethhdr), skb->protocol);
memset (skb->cb, 0, sizeof (struct skb_data));
@@ -981,6 +987,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, >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(>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(>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 +1249,15 @@ static void tx_complete (struct urb *urb)
struct usbnet   *dev = entry->dev;
 
if (urb->status == 0) {
+   struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
+
dev->net->stats.tx_packets += entry->packets;
dev->net->stats.tx_bytes += entry->length;
+
+   u64_stats_update_begin(>syncp);
+   stats64->tx_packets += entry->packets;
+   stats64->tx_bytes += entry->length;
+   u64_stats_update_end(>syncp);
} else {
dev->net->stats.tx_errors++;
 
@@ -1570,6 +1614,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);
@@ -1642,6 +1687,11 @@ void usbnet_disconnect (struct usb_interface *intf)
dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;