mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
Merge branch 'fix-race-conditions-in-ndo_get_stats64'
Shinas Rasheed says: ==================== Fix race conditions in ndo_get_stats64 Fix race conditions in ndo_get_stats64 by storing tx/rx stats locally and not availing per queue resources which could be torn down during interface stop. Also remove stats fetch from firmware which is currently unnecessary ==================== Link: https://patch.msgid.link/20250117094653.2588578-1-srasheed@marvell.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
ec81a13d88
|
|
@ -150,17 +150,14 @@ octep_get_ethtool_stats(struct net_device *netdev,
|
|||
iface_rx_stats,
|
||||
iface_tx_stats);
|
||||
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_iq *iq = oct->iq[q];
|
||||
struct octep_oq *oq = oct->oq[q];
|
||||
for (q = 0; q < OCTEP_MAX_QUEUES; q++) {
|
||||
tx_packets += oct->stats_iq[q].instr_completed;
|
||||
tx_bytes += oct->stats_iq[q].bytes_sent;
|
||||
tx_busy_errors += oct->stats_iq[q].tx_busy;
|
||||
|
||||
tx_packets += iq->stats.instr_completed;
|
||||
tx_bytes += iq->stats.bytes_sent;
|
||||
tx_busy_errors += iq->stats.tx_busy;
|
||||
|
||||
rx_packets += oq->stats.packets;
|
||||
rx_bytes += oq->stats.bytes;
|
||||
rx_alloc_errors += oq->stats.alloc_failures;
|
||||
rx_packets += oct->stats_oq[q].packets;
|
||||
rx_bytes += oct->stats_oq[q].bytes;
|
||||
rx_alloc_errors += oct->stats_oq[q].alloc_failures;
|
||||
}
|
||||
i = 0;
|
||||
data[i++] = rx_packets;
|
||||
|
|
@ -198,22 +195,18 @@ octep_get_ethtool_stats(struct net_device *netdev,
|
|||
data[i++] = iface_rx_stats->err_pkts;
|
||||
|
||||
/* Per Tx Queue stats */
|
||||
for (q = 0; q < oct->num_iqs; q++) {
|
||||
struct octep_iq *iq = oct->iq[q];
|
||||
|
||||
data[i++] = iq->stats.instr_posted;
|
||||
data[i++] = iq->stats.instr_completed;
|
||||
data[i++] = iq->stats.bytes_sent;
|
||||
data[i++] = iq->stats.tx_busy;
|
||||
for (q = 0; q < OCTEP_MAX_QUEUES; q++) {
|
||||
data[i++] = oct->stats_iq[q].instr_posted;
|
||||
data[i++] = oct->stats_iq[q].instr_completed;
|
||||
data[i++] = oct->stats_iq[q].bytes_sent;
|
||||
data[i++] = oct->stats_iq[q].tx_busy;
|
||||
}
|
||||
|
||||
/* Per Rx Queue stats */
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_oq *oq = oct->oq[q];
|
||||
|
||||
data[i++] = oq->stats.packets;
|
||||
data[i++] = oq->stats.bytes;
|
||||
data[i++] = oq->stats.alloc_failures;
|
||||
for (q = 0; q < OCTEP_MAX_QUEUES; q++) {
|
||||
data[i++] = oct->stats_oq[q].packets;
|
||||
data[i++] = oct->stats_oq[q].bytes;
|
||||
data[i++] = oct->stats_oq[q].alloc_failures;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -822,7 +822,7 @@ static inline int octep_iq_full_check(struct octep_iq *iq)
|
|||
if (unlikely(IQ_INSTR_SPACE(iq) >
|
||||
OCTEP_WAKE_QUEUE_THRESHOLD)) {
|
||||
netif_start_subqueue(iq->netdev, iq->q_no);
|
||||
iq->stats.restart_cnt++;
|
||||
iq->stats->restart_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -960,7 +960,7 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
|
|||
wmb();
|
||||
/* Ring Doorbell to notify the NIC of new packets */
|
||||
writel(iq->fill_cnt, iq->doorbell_reg);
|
||||
iq->stats.instr_posted += iq->fill_cnt;
|
||||
iq->stats->instr_posted += iq->fill_cnt;
|
||||
iq->fill_cnt = 0;
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
|
|
@ -991,37 +991,24 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
|
|||
static void octep_get_stats64(struct net_device *netdev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
|
||||
struct octep_device *oct = netdev_priv(netdev);
|
||||
u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
|
||||
int q;
|
||||
|
||||
if (netif_running(netdev))
|
||||
octep_ctrl_net_get_if_stats(oct,
|
||||
OCTEP_CTRL_NET_INVALID_VFID,
|
||||
&oct->iface_rx_stats,
|
||||
&oct->iface_tx_stats);
|
||||
|
||||
tx_packets = 0;
|
||||
tx_bytes = 0;
|
||||
rx_packets = 0;
|
||||
rx_bytes = 0;
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_iq *iq = oct->iq[q];
|
||||
struct octep_oq *oq = oct->oq[q];
|
||||
|
||||
tx_packets += iq->stats.instr_completed;
|
||||
tx_bytes += iq->stats.bytes_sent;
|
||||
rx_packets += oq->stats.packets;
|
||||
rx_bytes += oq->stats.bytes;
|
||||
for (q = 0; q < OCTEP_MAX_QUEUES; q++) {
|
||||
tx_packets += oct->stats_iq[q].instr_completed;
|
||||
tx_bytes += oct->stats_iq[q].bytes_sent;
|
||||
rx_packets += oct->stats_oq[q].packets;
|
||||
rx_bytes += oct->stats_oq[q].bytes;
|
||||
}
|
||||
stats->tx_packets = tx_packets;
|
||||
stats->tx_bytes = tx_bytes;
|
||||
stats->rx_packets = rx_packets;
|
||||
stats->rx_bytes = rx_bytes;
|
||||
stats->multicast = oct->iface_rx_stats.mcast_pkts;
|
||||
stats->rx_errors = oct->iface_rx_stats.err_pkts;
|
||||
stats->collisions = oct->iface_tx_stats.xscol;
|
||||
stats->tx_fifo_errors = oct->iface_tx_stats.undflw;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -257,11 +257,17 @@ struct octep_device {
|
|||
/* Pointers to Octeon Tx queues */
|
||||
struct octep_iq *iq[OCTEP_MAX_IQ];
|
||||
|
||||
/* Per iq stats */
|
||||
struct octep_iq_stats stats_iq[OCTEP_MAX_IQ];
|
||||
|
||||
/* Rx queues (OQ: Output Queue) */
|
||||
u16 num_oqs;
|
||||
/* Pointers to Octeon Rx queues */
|
||||
struct octep_oq *oq[OCTEP_MAX_OQ];
|
||||
|
||||
/* Per oq stats */
|
||||
struct octep_oq_stats stats_oq[OCTEP_MAX_OQ];
|
||||
|
||||
/* Hardware port number of the PCIe interface */
|
||||
u16 pcie_port;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static int octep_oq_refill(struct octep_device *oct, struct octep_oq *oq)
|
|||
page = dev_alloc_page();
|
||||
if (unlikely(!page)) {
|
||||
dev_err(oq->dev, "refill: rx buffer alloc failed\n");
|
||||
oq->stats.alloc_failures++;
|
||||
oq->stats->alloc_failures++;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ static int octep_oq_refill(struct octep_device *oct, struct octep_oq *oq)
|
|||
"OQ-%d buffer refill: DMA mapping error!\n",
|
||||
oq->q_no);
|
||||
put_page(page);
|
||||
oq->stats.alloc_failures++;
|
||||
oq->stats->alloc_failures++;
|
||||
break;
|
||||
}
|
||||
oq->buff_info[refill_idx].page = page;
|
||||
|
|
@ -134,6 +134,7 @@ static int octep_setup_oq(struct octep_device *oct, int q_no)
|
|||
oq->netdev = oct->netdev;
|
||||
oq->dev = &oct->pdev->dev;
|
||||
oq->q_no = q_no;
|
||||
oq->stats = &oct->stats_oq[q_no];
|
||||
oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf);
|
||||
oq->ring_size_mask = oq->max_count - 1;
|
||||
oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf);
|
||||
|
|
@ -443,7 +444,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
|||
if (!skb) {
|
||||
octep_oq_drop_rx(oq, buff_info,
|
||||
&read_idx, &desc_used);
|
||||
oq->stats.alloc_failures++;
|
||||
oq->stats->alloc_failures++;
|
||||
continue;
|
||||
}
|
||||
skb_reserve(skb, data_offset);
|
||||
|
|
@ -494,8 +495,8 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
|||
|
||||
oq->host_read_idx = read_idx;
|
||||
oq->refill_count += desc_used;
|
||||
oq->stats.packets += pkt;
|
||||
oq->stats.bytes += rx_bytes;
|
||||
oq->stats->packets += pkt;
|
||||
oq->stats->bytes += rx_bytes;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,8 +186,8 @@ struct octep_oq {
|
|||
*/
|
||||
u8 __iomem *pkts_sent_reg;
|
||||
|
||||
/* Statistics for this OQ. */
|
||||
struct octep_oq_stats stats;
|
||||
/* Pointer to statistics for this OQ. */
|
||||
struct octep_oq_stats *stats;
|
||||
|
||||
/* Packets pending to be processed */
|
||||
u32 pkts_pending;
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget)
|
|||
}
|
||||
|
||||
iq->pkts_processed += compl_pkts;
|
||||
iq->stats.instr_completed += compl_pkts;
|
||||
iq->stats.bytes_sent += compl_bytes;
|
||||
iq->stats.sgentry_sent += compl_sg;
|
||||
iq->stats->instr_completed += compl_pkts;
|
||||
iq->stats->bytes_sent += compl_bytes;
|
||||
iq->stats->sgentry_sent += compl_sg;
|
||||
iq->flush_index = fi;
|
||||
|
||||
netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes);
|
||||
|
|
@ -187,6 +187,7 @@ static int octep_setup_iq(struct octep_device *oct, int q_no)
|
|||
iq->netdev = oct->netdev;
|
||||
iq->dev = &oct->pdev->dev;
|
||||
iq->q_no = q_no;
|
||||
iq->stats = &oct->stats_iq[q_no];
|
||||
iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
iq->ring_size_mask = iq->max_count - 1;
|
||||
iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf);
|
||||
|
|
|
|||
|
|
@ -170,8 +170,8 @@ struct octep_iq {
|
|||
*/
|
||||
u16 flush_index;
|
||||
|
||||
/* Statistics for this input queue. */
|
||||
struct octep_iq_stats stats;
|
||||
/* Pointer to statistics for this input queue. */
|
||||
struct octep_iq_stats *stats;
|
||||
|
||||
/* Pointer to the Virtual Base addr of the input ring. */
|
||||
struct octep_tx_desc_hw *desc_ring;
|
||||
|
|
|
|||
|
|
@ -114,12 +114,9 @@ static void octep_vf_get_ethtool_stats(struct net_device *netdev,
|
|||
iface_tx_stats = &oct->iface_tx_stats;
|
||||
iface_rx_stats = &oct->iface_rx_stats;
|
||||
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_vf_iq *iq = oct->iq[q];
|
||||
struct octep_vf_oq *oq = oct->oq[q];
|
||||
|
||||
tx_busy_errors += iq->stats.tx_busy;
|
||||
rx_alloc_errors += oq->stats.alloc_failures;
|
||||
for (q = 0; q < OCTEP_VF_MAX_QUEUES; q++) {
|
||||
tx_busy_errors += oct->stats_iq[q].tx_busy;
|
||||
rx_alloc_errors += oct->stats_oq[q].alloc_failures;
|
||||
}
|
||||
i = 0;
|
||||
data[i++] = rx_alloc_errors;
|
||||
|
|
@ -134,22 +131,18 @@ static void octep_vf_get_ethtool_stats(struct net_device *netdev,
|
|||
data[i++] = iface_rx_stats->dropped_octets_fifo_full;
|
||||
|
||||
/* Per Tx Queue stats */
|
||||
for (q = 0; q < oct->num_iqs; q++) {
|
||||
struct octep_vf_iq *iq = oct->iq[q];
|
||||
|
||||
data[i++] = iq->stats.instr_posted;
|
||||
data[i++] = iq->stats.instr_completed;
|
||||
data[i++] = iq->stats.bytes_sent;
|
||||
data[i++] = iq->stats.tx_busy;
|
||||
for (q = 0; q < OCTEP_VF_MAX_QUEUES; q++) {
|
||||
data[i++] = oct->stats_iq[q].instr_posted;
|
||||
data[i++] = oct->stats_iq[q].instr_completed;
|
||||
data[i++] = oct->stats_iq[q].bytes_sent;
|
||||
data[i++] = oct->stats_iq[q].tx_busy;
|
||||
}
|
||||
|
||||
/* Per Rx Queue stats */
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_vf_oq *oq = oct->oq[q];
|
||||
|
||||
data[i++] = oq->stats.packets;
|
||||
data[i++] = oq->stats.bytes;
|
||||
data[i++] = oq->stats.alloc_failures;
|
||||
data[i++] = oct->stats_oq[q].packets;
|
||||
data[i++] = oct->stats_oq[q].bytes;
|
||||
data[i++] = oct->stats_oq[q].alloc_failures;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ static int octep_vf_iq_full_check(struct octep_vf_iq *iq)
|
|||
* caused queues to get re-enabled after
|
||||
* being stopped
|
||||
*/
|
||||
iq->stats.restart_cnt++;
|
||||
iq->stats->restart_cnt++;
|
||||
fallthrough;
|
||||
case 1: /* Queue left enabled, since IQ is not yet full*/
|
||||
return 0;
|
||||
|
|
@ -731,7 +731,7 @@ static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb,
|
|||
/* Flush the hw descriptors before writing to doorbell */
|
||||
smp_wmb();
|
||||
writel(iq->fill_cnt, iq->doorbell_reg);
|
||||
iq->stats.instr_posted += iq->fill_cnt;
|
||||
iq->stats->instr_posted += iq->fill_cnt;
|
||||
iq->fill_cnt = 0;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -786,27 +786,16 @@ static void octep_vf_get_stats64(struct net_device *netdev,
|
|||
tx_bytes = 0;
|
||||
rx_packets = 0;
|
||||
rx_bytes = 0;
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_vf_iq *iq = oct->iq[q];
|
||||
struct octep_vf_oq *oq = oct->oq[q];
|
||||
|
||||
tx_packets += iq->stats.instr_completed;
|
||||
tx_bytes += iq->stats.bytes_sent;
|
||||
rx_packets += oq->stats.packets;
|
||||
rx_bytes += oq->stats.bytes;
|
||||
for (q = 0; q < OCTEP_VF_MAX_QUEUES; q++) {
|
||||
tx_packets += oct->stats_iq[q].instr_completed;
|
||||
tx_bytes += oct->stats_iq[q].bytes_sent;
|
||||
rx_packets += oct->stats_oq[q].packets;
|
||||
rx_bytes += oct->stats_oq[q].bytes;
|
||||
}
|
||||
stats->tx_packets = tx_packets;
|
||||
stats->tx_bytes = tx_bytes;
|
||||
stats->rx_packets = rx_packets;
|
||||
stats->rx_bytes = rx_bytes;
|
||||
if (!octep_vf_get_if_stats(oct)) {
|
||||
stats->multicast = oct->iface_rx_stats.mcast_pkts;
|
||||
stats->rx_errors = oct->iface_rx_stats.err_pkts;
|
||||
stats->rx_dropped = oct->iface_rx_stats.dropped_pkts_fifo_full +
|
||||
oct->iface_rx_stats.err_pkts;
|
||||
stats->rx_missed_errors = oct->iface_rx_stats.dropped_pkts_fifo_full;
|
||||
stats->tx_dropped = oct->iface_tx_stats.dropped;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -246,11 +246,17 @@ struct octep_vf_device {
|
|||
/* Pointers to Octeon Tx queues */
|
||||
struct octep_vf_iq *iq[OCTEP_VF_MAX_IQ];
|
||||
|
||||
/* Per iq stats */
|
||||
struct octep_vf_iq_stats stats_iq[OCTEP_VF_MAX_IQ];
|
||||
|
||||
/* Rx queues (OQ: Output Queue) */
|
||||
u16 num_oqs;
|
||||
/* Pointers to Octeon Rx queues */
|
||||
struct octep_vf_oq *oq[OCTEP_VF_MAX_OQ];
|
||||
|
||||
/* Per oq stats */
|
||||
struct octep_vf_oq_stats stats_oq[OCTEP_VF_MAX_OQ];
|
||||
|
||||
/* Hardware port number of the PCIe interface */
|
||||
u16 pcie_port;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static int octep_vf_oq_refill(struct octep_vf_device *oct, struct octep_vf_oq *o
|
|||
page = dev_alloc_page();
|
||||
if (unlikely(!page)) {
|
||||
dev_err(oq->dev, "refill: rx buffer alloc failed\n");
|
||||
oq->stats.alloc_failures++;
|
||||
oq->stats->alloc_failures++;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ static int octep_vf_oq_refill(struct octep_vf_device *oct, struct octep_vf_oq *o
|
|||
"OQ-%d buffer refill: DMA mapping error!\n",
|
||||
oq->q_no);
|
||||
put_page(page);
|
||||
oq->stats.alloc_failures++;
|
||||
oq->stats->alloc_failures++;
|
||||
break;
|
||||
}
|
||||
oq->buff_info[refill_idx].page = page;
|
||||
|
|
@ -134,6 +134,7 @@ static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no)
|
|||
oq->netdev = oct->netdev;
|
||||
oq->dev = &oct->pdev->dev;
|
||||
oq->q_no = q_no;
|
||||
oq->stats = &oct->stats_oq[q_no];
|
||||
oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf);
|
||||
oq->ring_size_mask = oq->max_count - 1;
|
||||
oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf);
|
||||
|
|
@ -458,8 +459,8 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
|
|||
|
||||
oq->host_read_idx = read_idx;
|
||||
oq->refill_count += desc_used;
|
||||
oq->stats.packets += pkt;
|
||||
oq->stats.bytes += rx_bytes;
|
||||
oq->stats->packets += pkt;
|
||||
oq->stats->bytes += rx_bytes;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ struct octep_vf_oq {
|
|||
u8 __iomem *pkts_sent_reg;
|
||||
|
||||
/* Statistics for this OQ. */
|
||||
struct octep_vf_oq_stats stats;
|
||||
struct octep_vf_oq_stats *stats;
|
||||
|
||||
/* Packets pending to be processed */
|
||||
u32 pkts_pending;
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget)
|
|||
}
|
||||
|
||||
iq->pkts_processed += compl_pkts;
|
||||
iq->stats.instr_completed += compl_pkts;
|
||||
iq->stats.bytes_sent += compl_bytes;
|
||||
iq->stats.sgentry_sent += compl_sg;
|
||||
iq->stats->instr_completed += compl_pkts;
|
||||
iq->stats->bytes_sent += compl_bytes;
|
||||
iq->stats->sgentry_sent += compl_sg;
|
||||
iq->flush_index = fi;
|
||||
|
||||
netif_subqueue_completed_wake(iq->netdev, iq->q_no, compl_pkts,
|
||||
|
|
@ -186,6 +186,7 @@ static int octep_vf_setup_iq(struct octep_vf_device *oct, int q_no)
|
|||
iq->netdev = oct->netdev;
|
||||
iq->dev = &oct->pdev->dev;
|
||||
iq->q_no = q_no;
|
||||
iq->stats = &oct->stats_iq[q_no];
|
||||
iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf);
|
||||
iq->ring_size_mask = iq->max_count - 1;
|
||||
iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf);
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ struct octep_vf_iq {
|
|||
u16 flush_index;
|
||||
|
||||
/* Statistics for this input queue. */
|
||||
struct octep_vf_iq_stats stats;
|
||||
struct octep_vf_iq_stats *stats;
|
||||
|
||||
/* Pointer to the Virtual Base addr of the input ring. */
|
||||
struct octep_vf_tx_desc_hw *desc_ring;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user