Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: stmmac: protect updates of 64-bit statistics counters

As explained by a comment in <linux/u64_stats_sync.h>, write side of struct
u64_stats_sync must ensure mutual exclusion, or one seqcount update could
be lost on 32-bit platforms, thus blocking readers forever. Such lockups
have been observed in real world after stmmac_xmit() on one CPU raced with
stmmac_napi_poll_tx() on another CPU.

To fix the issue without introducing a new lock, split the statics into
three parts:

1. fields updated only under the tx queue lock,
2. fields updated only during NAPI poll,
3. fields updated only from interrupt context,

Updates to fields in the first two groups are already serialized through
other locks. It is sufficient to split the existing struct u64_stats_sync
so that each group has its own.

Note that tx_set_ic_bit is updated from both contexts. Split this counter
so that each context gets its own, and calculate their sum to get the total
value in stmmac_get_ethtool_stats().

For the third group, multiple interrupts may be processed by different CPUs
at the same time, but interrupts on the same CPU will not nest. Move fields
from this group to a newly created per-cpu struct stmmac_pcpu_stats.

Fixes: 133466c3bbe1 ("net: stmmac: use per-queue 64 bit statistics where necessary")
Link: https://lore.kernel.org/netdev/Za173PhviYg-1qIn@torres.zugschlus.de/t/
Cc: stable@vger.kernel.org
Signed-off-by: Petr Tesarik <petr@tesarici.cz>
Reviewed-by: Jisheng Zhang <jszhang@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Petr Tesarik and committed by
David S. Miller
38cc3c6d cb88cb53

+219 -155
+40 -16
drivers/net/ethernet/stmicro/stmmac/common.h
··· 59 59 #undef FRAME_FILTER_DEBUG 60 60 /* #define FRAME_FILTER_DEBUG */ 61 61 62 + struct stmmac_q_tx_stats { 63 + u64_stats_t tx_bytes; 64 + u64_stats_t tx_set_ic_bit; 65 + u64_stats_t tx_tso_frames; 66 + u64_stats_t tx_tso_nfrags; 67 + }; 68 + 69 + struct stmmac_napi_tx_stats { 70 + u64_stats_t tx_packets; 71 + u64_stats_t tx_pkt_n; 72 + u64_stats_t poll; 73 + u64_stats_t tx_clean; 74 + u64_stats_t tx_set_ic_bit; 75 + }; 76 + 62 77 struct stmmac_txq_stats { 63 - u64 tx_bytes; 64 - u64 tx_packets; 65 - u64 tx_pkt_n; 66 - u64 tx_normal_irq_n; 67 - u64 napi_poll; 68 - u64 tx_clean; 69 - u64 tx_set_ic_bit; 70 - u64 tx_tso_frames; 71 - u64 tx_tso_nfrags; 72 - struct u64_stats_sync syncp; 78 + /* Updates protected by tx queue lock. */ 79 + struct u64_stats_sync q_syncp; 80 + struct stmmac_q_tx_stats q; 81 + 82 + /* Updates protected by NAPI poll logic. */ 83 + struct u64_stats_sync napi_syncp; 84 + struct stmmac_napi_tx_stats napi; 73 85 } ____cacheline_aligned_in_smp; 74 86 87 + struct stmmac_napi_rx_stats { 88 + u64_stats_t rx_bytes; 89 + u64_stats_t rx_packets; 90 + u64_stats_t rx_pkt_n; 91 + u64_stats_t poll; 92 + }; 93 + 75 94 struct stmmac_rxq_stats { 76 - u64 rx_bytes; 77 - u64 rx_packets; 78 - u64 rx_pkt_n; 79 - u64 rx_normal_irq_n; 80 - u64 napi_poll; 81 - struct u64_stats_sync syncp; 95 + /* Updates protected by NAPI poll logic. */ 96 + struct u64_stats_sync napi_syncp; 97 + struct stmmac_napi_rx_stats napi; 82 98 } ____cacheline_aligned_in_smp; 99 + 100 + /* Updates on each CPU protected by not allowing nested irqs. */ 101 + struct stmmac_pcpu_stats { 102 + struct u64_stats_sync syncp; 103 + u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES]; 104 + u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES]; 105 + }; 83 106 84 107 /* Extra statistic and debug information exposed by ethtool */ 85 108 struct stmmac_extra_stats { ··· 228 205 /* per queue statistics */ 229 206 struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; 230 207 struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; 208 + struct stmmac_pcpu_stats __percpu *pcpu_stats; 231 209 unsigned long rx_dropped; 232 210 unsigned long rx_errors; 233 211 unsigned long tx_dropped;
+7 -8
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
··· 441 441 struct stmmac_extra_stats *x, u32 chan, 442 442 u32 dir) 443 443 { 444 - struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; 445 - struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; 444 + struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); 446 445 int ret = 0; 447 446 u32 v; 448 447 ··· 454 455 455 456 if (v & EMAC_TX_INT) { 456 457 ret |= handle_tx; 457 - u64_stats_update_begin(&txq_stats->syncp); 458 - txq_stats->tx_normal_irq_n++; 459 - u64_stats_update_end(&txq_stats->syncp); 458 + u64_stats_update_begin(&stats->syncp); 459 + u64_stats_inc(&stats->tx_normal_irq_n[chan]); 460 + u64_stats_update_end(&stats->syncp); 460 461 } 461 462 462 463 if (v & EMAC_TX_DMA_STOP_INT) ··· 478 479 479 480 if (v & EMAC_RX_INT) { 480 481 ret |= handle_rx; 481 - u64_stats_update_begin(&rxq_stats->syncp); 482 - rxq_stats->rx_normal_irq_n++; 483 - u64_stats_update_end(&rxq_stats->syncp); 482 + u64_stats_update_begin(&stats->syncp); 483 + u64_stats_inc(&stats->rx_normal_irq_n[chan]); 484 + u64_stats_update_end(&stats->syncp); 484 485 } 485 486 486 487 if (v & EMAC_RX_BUF_UA_INT)
+7 -8
drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
··· 171 171 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 172 172 u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); 173 173 u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 174 - struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; 175 - struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; 174 + struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); 176 175 int ret = 0; 177 176 178 177 if (dir == DMA_DIR_RX) ··· 200 201 } 201 202 /* TX/RX NORMAL interrupts */ 202 203 if (likely(intr_status & DMA_CHAN_STATUS_RI)) { 203 - u64_stats_update_begin(&rxq_stats->syncp); 204 - rxq_stats->rx_normal_irq_n++; 205 - u64_stats_update_end(&rxq_stats->syncp); 204 + u64_stats_update_begin(&stats->syncp); 205 + u64_stats_inc(&stats->rx_normal_irq_n[chan]); 206 + u64_stats_update_end(&stats->syncp); 206 207 ret |= handle_rx; 207 208 } 208 209 if (likely(intr_status & DMA_CHAN_STATUS_TI)) { 209 - u64_stats_update_begin(&txq_stats->syncp); 210 - txq_stats->tx_normal_irq_n++; 211 - u64_stats_update_end(&txq_stats->syncp); 210 + u64_stats_update_begin(&stats->syncp); 211 + u64_stats_inc(&stats->tx_normal_irq_n[chan]); 212 + u64_stats_update_end(&stats->syncp); 212 213 ret |= handle_tx; 213 214 } 214 215
+7 -8
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
··· 162 162 int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, 163 163 struct stmmac_extra_stats *x, u32 chan, u32 dir) 164 164 { 165 - struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; 166 - struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; 165 + struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); 167 166 int ret = 0; 168 167 /* read the status register (CSR5) */ 169 168 u32 intr_status = readl(ioaddr + DMA_STATUS); ··· 214 215 u32 value = readl(ioaddr + DMA_INTR_ENA); 215 216 /* to schedule NAPI on real RIE event. */ 216 217 if (likely(value & DMA_INTR_ENA_RIE)) { 217 - u64_stats_update_begin(&rxq_stats->syncp); 218 - rxq_stats->rx_normal_irq_n++; 219 - u64_stats_update_end(&rxq_stats->syncp); 218 + u64_stats_update_begin(&stats->syncp); 219 + u64_stats_inc(&stats->rx_normal_irq_n[chan]); 220 + u64_stats_update_end(&stats->syncp); 220 221 ret |= handle_rx; 221 222 } 222 223 } 223 224 if (likely(intr_status & DMA_STATUS_TI)) { 224 - u64_stats_update_begin(&txq_stats->syncp); 225 - txq_stats->tx_normal_irq_n++; 226 - u64_stats_update_end(&txq_stats->syncp); 225 + u64_stats_update_begin(&stats->syncp); 226 + u64_stats_inc(&stats->tx_normal_irq_n[chan]); 227 + u64_stats_update_end(&stats->syncp); 227 228 ret |= handle_tx; 228 229 } 229 230 if (unlikely(intr_status & DMA_STATUS_ERI))
+7 -8
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
··· 337 337 struct stmmac_extra_stats *x, u32 chan, 338 338 u32 dir) 339 339 { 340 - struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; 341 - struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; 340 + struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); 342 341 u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); 343 342 u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); 344 343 int ret = 0; ··· 366 367 /* TX/RX NORMAL interrupts */ 367 368 if (likely(intr_status & XGMAC_NIS)) { 368 369 if (likely(intr_status & XGMAC_RI)) { 369 - u64_stats_update_begin(&rxq_stats->syncp); 370 - rxq_stats->rx_normal_irq_n++; 371 - u64_stats_update_end(&rxq_stats->syncp); 370 + u64_stats_update_begin(&stats->syncp); 371 + u64_stats_inc(&stats->rx_normal_irq_n[chan]); 372 + u64_stats_update_end(&stats->syncp); 372 373 ret |= handle_rx; 373 374 } 374 375 if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { 375 - u64_stats_update_begin(&txq_stats->syncp); 376 - txq_stats->tx_normal_irq_n++; 377 - u64_stats_update_end(&txq_stats->syncp); 376 + u64_stats_update_begin(&stats->syncp); 377 + u64_stats_inc(&stats->tx_normal_irq_n[chan]); 378 + u64_stats_update_end(&stats->syncp); 378 379 ret |= handle_tx; 379 380 } 380 381 }
+85 -40
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
··· 549 549 } 550 550 } 551 551 552 + static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q) 553 + { 554 + u64 total; 555 + int cpu; 556 + 557 + total = 0; 558 + for_each_possible_cpu(cpu) { 559 + struct stmmac_pcpu_stats *pcpu; 560 + unsigned int start; 561 + u64 irq_n; 562 + 563 + pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); 564 + do { 565 + start = u64_stats_fetch_begin(&pcpu->syncp); 566 + irq_n = u64_stats_read(&pcpu->rx_normal_irq_n[q]); 567 + } while (u64_stats_fetch_retry(&pcpu->syncp, start)); 568 + total += irq_n; 569 + } 570 + return total; 571 + } 572 + 573 + static u64 stmmac_get_tx_normal_irq_n(struct stmmac_priv *priv, int q) 574 + { 575 + u64 total; 576 + int cpu; 577 + 578 + total = 0; 579 + for_each_possible_cpu(cpu) { 580 + struct stmmac_pcpu_stats *pcpu; 581 + unsigned int start; 582 + u64 irq_n; 583 + 584 + pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); 585 + do { 586 + start = u64_stats_fetch_begin(&pcpu->syncp); 587 + irq_n = u64_stats_read(&pcpu->tx_normal_irq_n[q]); 588 + } while (u64_stats_fetch_retry(&pcpu->syncp, start)); 589 + total += irq_n; 590 + } 591 + return total; 592 + } 593 + 552 594 static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) 553 595 { 554 596 u32 tx_cnt = priv->plat->tx_queues_to_use; 555 597 u32 rx_cnt = priv->plat->rx_queues_to_use; 556 598 unsigned int start; 557 - int q, stat; 558 - char *p; 599 + int q; 559 600 560 601 for (q = 0; q < tx_cnt; q++) { 561 602 struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q]; 562 - struct stmmac_txq_stats snapshot; 603 + u64 pkt_n; 563 604 564 605 do { 565 - start = u64_stats_fetch_begin(&txq_stats->syncp); 566 - snapshot = *txq_stats; 567 - } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); 606 + start = u64_stats_fetch_begin(&txq_stats->napi_syncp); 607 + pkt_n = u64_stats_read(&txq_stats->napi.tx_pkt_n); 608 + } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); 568 609 569 - p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n); 570 - for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { 571 - *data++ = (*(u64 *)p); 572 - p += sizeof(u64); 573 - } 610 + *data++ = pkt_n; 611 + *data++ = stmmac_get_tx_normal_irq_n(priv, q); 574 612 } 575 613 576 614 for (q = 0; q < rx_cnt; q++) { 577 615 struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q]; 578 - struct stmmac_rxq_stats snapshot; 616 + u64 pkt_n; 579 617 580 618 do { 581 - start = u64_stats_fetch_begin(&rxq_stats->syncp); 582 - snapshot = *rxq_stats; 583 - } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); 619 + start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); 620 + pkt_n = u64_stats_read(&rxq_stats->napi.rx_pkt_n); 621 + } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); 584 622 585 - p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n); 586 - for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { 587 - *data++ = (*(u64 *)p); 588 - p += sizeof(u64); 589 - } 623 + *data++ = pkt_n; 624 + *data++ = stmmac_get_rx_normal_irq_n(priv, q); 590 625 } 591 626 } 592 627 ··· 680 645 pos = j; 681 646 for (i = 0; i < rx_queues_count; i++) { 682 647 struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i]; 683 - struct stmmac_rxq_stats snapshot; 648 + struct stmmac_napi_rx_stats snapshot; 649 + u64 n_irq; 684 650 685 651 j = pos; 686 652 do { 687 - start = u64_stats_fetch_begin(&rxq_stats->syncp); 688 - snapshot = *rxq_stats; 689 - } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); 653 + start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); 654 + snapshot = rxq_stats->napi; 655 + } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); 690 656 691 - data[j++] += snapshot.rx_pkt_n; 692 - data[j++] += snapshot.rx_normal_irq_n; 693 - normal_irq_n += snapshot.rx_normal_irq_n; 694 - napi_poll += snapshot.napi_poll; 657 + data[j++] += u64_stats_read(&snapshot.rx_pkt_n); 658 + n_irq = stmmac_get_rx_normal_irq_n(priv, i); 659 + data[j++] += n_irq; 660 + normal_irq_n += n_irq; 661 + napi_poll += u64_stats_read(&snapshot.poll); 695 662 } 696 663 697 664 pos = j; 698 665 for (i = 0; i < tx_queues_count; i++) { 699 666 struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i]; 700 - struct stmmac_txq_stats snapshot; 667 + struct stmmac_napi_tx_stats napi_snapshot; 668 + struct stmmac_q_tx_stats q_snapshot; 669 + u64 n_irq; 701 670 702 671 j = pos; 703 672 do { 704 - start = u64_stats_fetch_begin(&txq_stats->syncp); 705 - snapshot = *txq_stats; 706 - } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); 673 + start = u64_stats_fetch_begin(&txq_stats->q_syncp); 674 + q_snapshot = txq_stats->q; 675 + } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start)); 676 + do { 677 + start = u64_stats_fetch_begin(&txq_stats->napi_syncp); 678 + napi_snapshot = txq_stats->napi; 679 + } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); 707 680 708 - data[j++] += snapshot.tx_pkt_n; 709 - data[j++] += snapshot.tx_normal_irq_n; 710 - normal_irq_n += snapshot.tx_normal_irq_n; 711 - data[j++] += snapshot.tx_clean; 712 - data[j++] += snapshot.tx_set_ic_bit; 713 - data[j++] += snapshot.tx_tso_frames; 714 - data[j++] += snapshot.tx_tso_nfrags; 715 - napi_poll += snapshot.napi_poll; 681 + data[j++] += u64_stats_read(&napi_snapshot.tx_pkt_n); 682 + n_irq = stmmac_get_tx_normal_irq_n(priv, i); 683 + data[j++] += n_irq; 684 + normal_irq_n += n_irq; 685 + data[j++] += u64_stats_read(&napi_snapshot.tx_clean); 686 + data[j++] += u64_stats_read(&q_snapshot.tx_set_ic_bit) + 687 + u64_stats_read(&napi_snapshot.tx_set_ic_bit); 688 + data[j++] += u64_stats_read(&q_snapshot.tx_tso_frames); 689 + data[j++] += u64_stats_read(&q_snapshot.tx_tso_nfrags); 690 + napi_poll += u64_stats_read(&napi_snapshot.poll); 716 691 } 717 692 normal_irq_n += priv->xstats.rx_early_irq; 718 693 data[j++] = normal_irq_n;
+66 -67
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 2482 2482 struct xdp_desc xdp_desc; 2483 2483 bool work_done = true; 2484 2484 u32 tx_set_ic_bit = 0; 2485 - unsigned long flags; 2486 2485 2487 2486 /* Avoids TX time-out as we are sharing with slow path */ 2488 2487 txq_trans_cond_update(nq); ··· 2565 2566 tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); 2566 2567 entry = tx_q->cur_tx; 2567 2568 } 2568 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 2569 - txq_stats->tx_set_ic_bit += tx_set_ic_bit; 2570 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 2569 + u64_stats_update_begin(&txq_stats->napi_syncp); 2570 + u64_stats_add(&txq_stats->napi.tx_set_ic_bit, tx_set_ic_bit); 2571 + u64_stats_update_end(&txq_stats->napi_syncp); 2571 2572 2572 2573 if (tx_desc) { 2573 2574 stmmac_flush_tx_descriptors(priv, queue); ··· 2615 2616 unsigned int bytes_compl = 0, pkts_compl = 0; 2616 2617 unsigned int entry, xmits = 0, count = 0; 2617 2618 u32 tx_packets = 0, tx_errors = 0; 2618 - unsigned long flags; 2619 2619 2620 2620 __netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue)); 2621 2621 ··· 2780 2782 if (tx_q->dirty_tx != tx_q->cur_tx) 2781 2783 *pending_packets = true; 2782 2784 2783 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 2784 - txq_stats->tx_packets += tx_packets; 2785 - txq_stats->tx_pkt_n += tx_packets; 2786 - txq_stats->tx_clean++; 2787 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 2785 + u64_stats_update_begin(&txq_stats->napi_syncp); 2786 + u64_stats_add(&txq_stats->napi.tx_packets, tx_packets); 2787 + u64_stats_add(&txq_stats->napi.tx_pkt_n, tx_packets); 2788 + u64_stats_inc(&txq_stats->napi.tx_clean); 2789 + u64_stats_update_end(&txq_stats->napi_syncp); 2788 2790 2789 2791 priv->xstats.tx_errors += tx_errors; 2790 2792 ··· 4211 4213 struct stmmac_tx_queue *tx_q; 4212 4214 bool has_vlan, set_ic; 4213 4215 u8 proto_hdr_len, hdr; 4214 - unsigned long flags; 4215 4216 u32 pay_len, mss; 4216 4217 dma_addr_t des; 4217 4218 int i; ··· 4375 4378 netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); 4376 4379 } 4377 4380 4378 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 4379 - txq_stats->tx_bytes += skb->len; 4380 - txq_stats->tx_tso_frames++; 4381 - txq_stats->tx_tso_nfrags += nfrags; 4381 + u64_stats_update_begin(&txq_stats->q_syncp); 4382 + u64_stats_add(&txq_stats->q.tx_bytes, skb->len); 4383 + u64_stats_inc(&txq_stats->q.tx_tso_frames); 4384 + u64_stats_add(&txq_stats->q.tx_tso_nfrags, nfrags); 4382 4385 if (set_ic) 4383 - txq_stats->tx_set_ic_bit++; 4384 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 4386 + u64_stats_inc(&txq_stats->q.tx_set_ic_bit); 4387 + u64_stats_update_end(&txq_stats->q_syncp); 4385 4388 4386 4389 if (priv->sarc_type) 4387 4390 stmmac_set_desc_sarc(priv, first, priv->sarc_type); ··· 4480 4483 struct stmmac_tx_queue *tx_q; 4481 4484 bool has_vlan, set_ic; 4482 4485 int entry, first_tx; 4483 - unsigned long flags; 4484 4486 dma_addr_t des; 4485 4487 4486 4488 tx_q = &priv->dma_conf.tx_queue[queue]; ··· 4649 4653 netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); 4650 4654 } 4651 4655 4652 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 4653 - txq_stats->tx_bytes += skb->len; 4656 + u64_stats_update_begin(&txq_stats->q_syncp); 4657 + u64_stats_add(&txq_stats->q.tx_bytes, skb->len); 4654 4658 if (set_ic) 4655 - txq_stats->tx_set_ic_bit++; 4656 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 4659 + u64_stats_inc(&txq_stats->q.tx_set_ic_bit); 4660 + u64_stats_update_end(&txq_stats->q_syncp); 4657 4661 4658 4662 if (priv->sarc_type) 4659 4663 stmmac_set_desc_sarc(priv, first, priv->sarc_type); ··· 4917 4921 set_ic = false; 4918 4922 4919 4923 if (set_ic) { 4920 - unsigned long flags; 4921 4924 tx_q->tx_count_frames = 0; 4922 4925 stmmac_set_tx_ic(priv, tx_desc); 4923 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 4924 - txq_stats->tx_set_ic_bit++; 4925 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 4926 + u64_stats_update_begin(&txq_stats->q_syncp); 4927 + u64_stats_inc(&txq_stats->q.tx_set_ic_bit); 4928 + u64_stats_update_end(&txq_stats->q_syncp); 4926 4929 } 4927 4930 4928 4931 stmmac_enable_dma_transmission(priv, priv->ioaddr); ··· 5071 5076 unsigned int len = xdp->data_end - xdp->data; 5072 5077 enum pkt_hash_types hash_type; 5073 5078 int coe = priv->hw->rx_csum; 5074 - unsigned long flags; 5075 5079 struct sk_buff *skb; 5076 5080 u32 hash; 5077 5081 ··· 5100 5106 skb_record_rx_queue(skb, queue); 5101 5107 napi_gro_receive(&ch->rxtx_napi, skb); 5102 5108 5103 - flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); 5104 - rxq_stats->rx_pkt_n++; 5105 - rxq_stats->rx_bytes += len; 5106 - u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); 5109 + u64_stats_update_begin(&rxq_stats->napi_syncp); 5110 + u64_stats_inc(&rxq_stats->napi.rx_pkt_n); 5111 + u64_stats_add(&rxq_stats->napi.rx_bytes, len); 5112 + u64_stats_update_end(&rxq_stats->napi_syncp); 5107 5113 } 5108 5114 5109 5115 static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) ··· 5185 5191 unsigned int desc_size; 5186 5192 struct bpf_prog *prog; 5187 5193 bool failure = false; 5188 - unsigned long flags; 5189 5194 int xdp_status = 0; 5190 5195 int status = 0; 5191 5196 ··· 5339 5346 5340 5347 stmmac_finalize_xdp_rx(priv, xdp_status); 5341 5348 5342 - flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); 5343 - rxq_stats->rx_pkt_n += count; 5344 - u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); 5349 + u64_stats_update_begin(&rxq_stats->napi_syncp); 5350 + u64_stats_add(&rxq_stats->napi.rx_pkt_n, count); 5351 + u64_stats_update_end(&rxq_stats->napi_syncp); 5345 5352 5346 5353 priv->xstats.rx_dropped += rx_dropped; 5347 5354 priv->xstats.rx_errors += rx_errors; ··· 5379 5386 unsigned int desc_size; 5380 5387 struct sk_buff *skb = NULL; 5381 5388 struct stmmac_xdp_buff ctx; 5382 - unsigned long flags; 5383 5389 int xdp_status = 0; 5384 5390 int buf_sz; 5385 5391 ··· 5638 5646 5639 5647 stmmac_rx_refill(priv, queue); 5640 5648 5641 - flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); 5642 - rxq_stats->rx_packets += rx_packets; 5643 - rxq_stats->rx_bytes += rx_bytes; 5644 - rxq_stats->rx_pkt_n += count; 5645 - u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); 5649 + u64_stats_update_begin(&rxq_stats->napi_syncp); 5650 + u64_stats_add(&rxq_stats->napi.rx_packets, rx_packets); 5651 + u64_stats_add(&rxq_stats->napi.rx_bytes, rx_bytes); 5652 + u64_stats_add(&rxq_stats->napi.rx_pkt_n, count); 5653 + u64_stats_update_end(&rxq_stats->napi_syncp); 5646 5654 5647 5655 priv->xstats.rx_dropped += rx_dropped; 5648 5656 priv->xstats.rx_errors += rx_errors; ··· 5657 5665 struct stmmac_priv *priv = ch->priv_data; 5658 5666 struct stmmac_rxq_stats *rxq_stats; 5659 5667 u32 chan = ch->index; 5660 - unsigned long flags; 5661 5668 int work_done; 5662 5669 5663 5670 rxq_stats = &priv->xstats.rxq_stats[chan]; 5664 - flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); 5665 - rxq_stats->napi_poll++; 5666 - u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); 5671 + u64_stats_update_begin(&rxq_stats->napi_syncp); 5672 + u64_stats_inc(&rxq_stats->napi.poll); 5673 + u64_stats_update_end(&rxq_stats->napi_syncp); 5667 5674 5668 5675 work_done = stmmac_rx(priv, budget, chan); 5669 5676 if (work_done < budget && napi_complete_done(napi, work_done)) { ··· 5684 5693 struct stmmac_txq_stats *txq_stats; 5685 5694 bool pending_packets = false; 5686 5695 u32 chan = ch->index; 5687 - unsigned long flags; 5688 5696 int work_done; 5689 5697 5690 5698 txq_stats = &priv->xstats.txq_stats[chan]; 5691 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 5692 - txq_stats->napi_poll++; 5693 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 5699 + u64_stats_update_begin(&txq_stats->napi_syncp); 5700 + u64_stats_inc(&txq_stats->napi.poll); 5701 + u64_stats_update_end(&txq_stats->napi_syncp); 5694 5702 5695 5703 work_done = stmmac_tx_clean(priv, budget, chan, &pending_packets); 5696 5704 work_done = min(work_done, budget); ··· 5719 5729 struct stmmac_rxq_stats *rxq_stats; 5720 5730 struct stmmac_txq_stats *txq_stats; 5721 5731 u32 chan = ch->index; 5722 - unsigned long flags; 5723 5732 5724 5733 rxq_stats = &priv->xstats.rxq_stats[chan]; 5725 - flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); 5726 - rxq_stats->napi_poll++; 5727 - u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); 5734 + u64_stats_update_begin(&rxq_stats->napi_syncp); 5735 + u64_stats_inc(&rxq_stats->napi.poll); 5736 + u64_stats_update_end(&rxq_stats->napi_syncp); 5728 5737 5729 5738 txq_stats = &priv->xstats.txq_stats[chan]; 5730 - flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); 5731 - txq_stats->napi_poll++; 5732 - u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); 5739 + u64_stats_update_begin(&txq_stats->napi_syncp); 5740 + u64_stats_inc(&txq_stats->napi.poll); 5741 + u64_stats_update_end(&txq_stats->napi_syncp); 5733 5742 5734 5743 tx_done = stmmac_tx_clean(priv, budget, chan, &tx_pending_packets); 5735 5744 tx_done = min(tx_done, budget); ··· 7054 7065 u64 tx_bytes; 7055 7066 7056 7067 do { 7057 - start = u64_stats_fetch_begin(&txq_stats->syncp); 7058 - tx_packets = txq_stats->tx_packets; 7059 - tx_bytes = txq_stats->tx_bytes; 7060 - } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); 7068 + start = u64_stats_fetch_begin(&txq_stats->q_syncp); 7069 + tx_bytes = u64_stats_read(&txq_stats->q.tx_bytes); 7070 + } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start)); 7071 + do { 7072 + start = u64_stats_fetch_begin(&txq_stats->napi_syncp); 7073 + tx_packets = u64_stats_read(&txq_stats->napi.tx_packets); 7074 + } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); 7061 7075 7062 7076 stats->tx_packets += tx_packets; 7063 7077 stats->tx_bytes += tx_bytes; ··· 7072 7080 u64 rx_bytes; 7073 7081 7074 7082 do { 7075 - start = u64_stats_fetch_begin(&rxq_stats->syncp); 7076 - rx_packets = rxq_stats->rx_packets; 7077 - rx_bytes = rxq_stats->rx_bytes; 7078 - } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); 7083 + start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); 7084 + rx_packets = u64_stats_read(&rxq_stats->napi.rx_packets); 7085 + rx_bytes = u64_stats_read(&rxq_stats->napi.rx_bytes); 7086 + } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); 7079 7087 7080 7088 stats->rx_packets += rx_packets; 7081 7089 stats->rx_bytes += rx_bytes; ··· 7469 7477 priv->dev = ndev; 7470 7478 7471 7479 for (i = 0; i < MTL_MAX_RX_QUEUES; i++) 7472 - u64_stats_init(&priv->xstats.rxq_stats[i].syncp); 7473 - for (i = 0; i < MTL_MAX_TX_QUEUES; i++) 7474 - u64_stats_init(&priv->xstats.txq_stats[i].syncp); 7480 + u64_stats_init(&priv->xstats.rxq_stats[i].napi_syncp); 7481 + for (i = 0; i < MTL_MAX_TX_QUEUES; i++) { 7482 + u64_stats_init(&priv->xstats.txq_stats[i].q_syncp); 7483 + u64_stats_init(&priv->xstats.txq_stats[i].napi_syncp); 7484 + } 7485 + 7486 + priv->xstats.pcpu_stats = 7487 + devm_netdev_alloc_pcpu_stats(device, struct stmmac_pcpu_stats); 7488 + if (!priv->xstats.pcpu_stats) 7489 + return -ENOMEM; 7475 7490 7476 7491 stmmac_set_ethtool_ops(ndev); 7477 7492 priv->pause = pause;