qtnfmac: support 64-bit network interface stats
On 32-bit platforms packet counters are stored in a net_device_stats struct as unsigned long integers. As a result, after some time of network activity an overflow takes place in network packet counters. This patch makes use of new structs for holding interface statistics. Signed-off-by: Vasily Ulyanov <vulyanov@quantenna.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
87affddef9
commit
04b01affb8
|
@ -119,9 +119,38 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||||
|
|
||||||
/* Netdev handler for getting stats.
|
/* Netdev handler for getting stats.
|
||||||
*/
|
*/
|
||||||
static struct net_device_stats *qtnf_netdev_get_stats(struct net_device *dev)
|
static void qtnf_netdev_get_stats64(struct net_device *ndev,
|
||||||
|
struct rtnl_link_stats64 *stats)
|
||||||
{
|
{
|
||||||
return &dev->stats;
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||||
|
unsigned int start;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
netdev_stats_to_stats64(stats, &ndev->stats);
|
||||||
|
|
||||||
|
if (!vif->stats64)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
struct pcpu_sw_netstats *stats64;
|
||||||
|
u64 rx_packets, rx_bytes;
|
||||||
|
u64 tx_packets, tx_bytes;
|
||||||
|
|
||||||
|
stats64 = per_cpu_ptr(vif->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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Netdev handler for transmission timeout.
|
/* Netdev handler for transmission timeout.
|
||||||
|
@ -156,7 +185,7 @@ const struct net_device_ops qtnf_netdev_ops = {
|
||||||
.ndo_stop = qtnf_netdev_close,
|
.ndo_stop = qtnf_netdev_close,
|
||||||
.ndo_start_xmit = qtnf_netdev_hard_start_xmit,
|
.ndo_start_xmit = qtnf_netdev_hard_start_xmit,
|
||||||
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
|
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
|
||||||
.ndo_get_stats = qtnf_netdev_get_stats,
|
.ndo_get_stats64 = qtnf_netdev_get_stats64,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
|
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
|
||||||
|
@ -289,6 +318,11 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
||||||
qtnf_sta_list_init(&mac->iflist[i].sta_list);
|
qtnf_sta_list_init(&mac->iflist[i].sta_list);
|
||||||
mutex_init(&mac->mac_lock);
|
mutex_init(&mac->mac_lock);
|
||||||
timer_setup(&mac->scan_timeout, NULL, 0);
|
timer_setup(&mac->scan_timeout, NULL, 0);
|
||||||
|
mac->iflist[i].stats64 =
|
||||||
|
netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||||
|
if (!mac->iflist[i].stats64)
|
||||||
|
pr_warn("VIF%u.%u: per cpu stats allocation failed\n",
|
||||||
|
macid, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
qtnf_mac_init_primary_intf(mac);
|
qtnf_mac_init_primary_intf(mac);
|
||||||
|
@ -364,6 +398,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
qtnf_sta_list_free(&vif->sta_list);
|
qtnf_sta_list_free(&vif->sta_list);
|
||||||
|
free_percpu(vif->stats64);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mac->wiphy_registered)
|
if (mac->wiphy_registered)
|
||||||
|
@ -643,6 +678,46 @@ void qtnf_wake_all_queues(struct net_device *ndev)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qtnf_wake_all_queues);
|
EXPORT_SYMBOL_GPL(qtnf_wake_all_queues);
|
||||||
|
|
||||||
|
void qtnf_update_rx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||||
|
struct pcpu_sw_netstats *stats64;
|
||||||
|
|
||||||
|
if (unlikely(!vif || !vif->stats64)) {
|
||||||
|
ndev->stats.rx_packets++;
|
||||||
|
ndev->stats.rx_bytes += skb->len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stats64 = this_cpu_ptr(vif->stats64);
|
||||||
|
|
||||||
|
u64_stats_update_begin(&stats64->syncp);
|
||||||
|
stats64->rx_packets++;
|
||||||
|
stats64->rx_bytes += skb->len;
|
||||||
|
u64_stats_update_end(&stats64->syncp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qtnf_update_rx_stats);
|
||||||
|
|
||||||
|
void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||||
|
struct pcpu_sw_netstats *stats64;
|
||||||
|
|
||||||
|
if (unlikely(!vif || !vif->stats64)) {
|
||||||
|
ndev->stats.tx_packets++;
|
||||||
|
ndev->stats.tx_bytes += skb->len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stats64 = this_cpu_ptr(vif->stats64);
|
||||||
|
|
||||||
|
u64_stats_update_begin(&stats64->syncp);
|
||||||
|
stats64->tx_packets++;
|
||||||
|
stats64->tx_bytes += skb->len;
|
||||||
|
u64_stats_update_end(&stats64->syncp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qtnf_update_tx_stats);
|
||||||
|
|
||||||
MODULE_AUTHOR("Quantenna Communications");
|
MODULE_AUTHOR("Quantenna Communications");
|
||||||
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
|
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -89,6 +89,8 @@ struct qtnf_vif {
|
||||||
struct qtnf_sta_list sta_list;
|
struct qtnf_sta_list sta_list;
|
||||||
unsigned long cons_tx_timeout_cnt;
|
unsigned long cons_tx_timeout_cnt;
|
||||||
int generation;
|
int generation;
|
||||||
|
|
||||||
|
struct pcpu_sw_netstats __percpu *stats64;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qtnf_mac_info {
|
struct qtnf_mac_info {
|
||||||
|
@ -157,6 +159,9 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac);
|
||||||
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid);
|
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid);
|
||||||
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb);
|
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb);
|
||||||
void qtnf_wake_all_queues(struct net_device *ndev);
|
void qtnf_wake_all_queues(struct net_device *ndev);
|
||||||
|
void qtnf_update_rx_stats(struct net_device *ndev, const struct sk_buff *skb);
|
||||||
|
void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb);
|
||||||
|
|
||||||
void qtnf_virtual_intf_cleanup(struct net_device *ndev);
|
void qtnf_virtual_intf_cleanup(struct net_device *ndev);
|
||||||
|
|
||||||
void qtnf_netdev_updown(struct net_device *ndev, bool up);
|
void qtnf_netdev_updown(struct net_device *ndev, bool up);
|
||||||
|
|
|
@ -615,8 +615,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv)
|
||||||
PCI_DMA_TODEVICE);
|
PCI_DMA_TODEVICE);
|
||||||
|
|
||||||
if (skb->dev) {
|
if (skb->dev) {
|
||||||
skb->dev->stats.tx_packets++;
|
qtnf_update_tx_stats(skb->dev, skb);
|
||||||
skb->dev->stats.tx_bytes += skb->len;
|
|
||||||
if (unlikely(priv->tx_stopped)) {
|
if (unlikely(priv->tx_stopped)) {
|
||||||
qtnf_wake_all_queues(skb->dev);
|
qtnf_wake_all_queues(skb->dev);
|
||||||
priv->tx_stopped = 0;
|
priv->tx_stopped = 0;
|
||||||
|
@ -855,9 +854,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget)
|
||||||
skb_put(skb, psize);
|
skb_put(skb, psize);
|
||||||
ndev = qtnf_classify_skb(bus, skb);
|
ndev = qtnf_classify_skb(bus, skb);
|
||||||
if (likely(ndev)) {
|
if (likely(ndev)) {
|
||||||
ndev->stats.rx_packets++;
|
qtnf_update_rx_stats(ndev, skb);
|
||||||
ndev->stats.rx_bytes += skb->len;
|
|
||||||
|
|
||||||
skb->protocol = eth_type_trans(skb, ndev);
|
skb->protocol = eth_type_trans(skb, ndev);
|
||||||
napi_gro_receive(napi, skb);
|
napi_gro_receive(napi, skb);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue