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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
igc: Add support for Frame Preemption

Faizal Rahim says:

Introduce support for the FPE feature in the IGC driver.

The patches aligns with the upstream FPE API:
https://patchwork.kernel.org/project/netdevbpf/cover/20230220122343.1156614-1-vladimir.oltean@nxp.com/
https://patchwork.kernel.org/project/netdevbpf/cover/20230119122705.73054-1-vladimir.oltean@nxp.com/

It builds upon earlier work:
https://patchwork.kernel.org/project/netdevbpf/cover/20220520011538.1098888-1-vinicius.gomes@intel.com/

The patch series adds the following functionalities to the IGC driver:
a) Configure FPE using `ethtool --set-mm`.
b) Display FPE settings via `ethtool --show-mm`.
c) View FPE statistics using `ethtool --include-statistics --show-mm'.
e) Block setting preemptible tc in taprio since it is not supported yet.
Existing code already blocks it in mqprio.

Tested:
Enabled CONFIG_PROVE_LOCKING, CONFIG_DEBUG_ATOMIC_SLEEP, CONFIG_DMA_API_DEBUG, and CONFIG_KASAN
1) selftests
2) netdev down/up cycles
3) suspend/resume cycles
4) fpe verification

No bugs or unusual dmesg logs were observed.
Ran 1), 2) and 3) with and without the patch series, compared dmesg and selftest logs - no differences found.

* '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
igc: add support to get frame preemption statistics via ethtool
igc: add support to get MAC Merge data via ethtool
igc: block setting preemptible traffic class in taprio
igc: add support to set tx-min-frag-size
igc: add support for frame preemption verification
igc: set the RX packet buffer size for TSN mode
igc: use FIELD_PREP and GENMASK for existing RX packet buffer size
igc: optimize TX packet buffer utilization for TSN mode
igc: use FIELD_PREP and GENMASK for existing TX packet buffer size
igc: rename I225_RXPBSIZE_DEFAULT and I225_TXPBSIZE_DEFAULT
igc: rename xdp_get_tx_ring() for non-xdp usage
net: ethtool: mm: reset verification status when link is down
net: ethtool: mm: extract stmmac verification logic into common library
net: stmmac: move frag_size handling out of spin_lock
====================

Link: https://patch.msgid.link/20250418163822.3519810-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+875 -220
+1
drivers/net/ethernet/intel/Kconfig
··· 369 369 default n 370 370 depends on PCI 371 371 depends on PTP_1588_CLOCK_OPTIONAL 372 + depends on ETHTOOL_NETLINK 372 373 help 373 374 This driver supports Intel(R) Ethernet Controller I225-LM/I225-V 374 375 family of adapters.
+13 -2
drivers/net/ethernet/intel/igc/igc.h
··· 40 40 41 41 #define IGC_MAX_TX_TSTAMP_REGS 4 42 42 43 + struct igc_fpe_t { 44 + struct ethtool_mmsv mmsv; 45 + u32 tx_min_frag_size; 46 + }; 47 + 43 48 enum igc_mac_filter_type { 44 49 IGC_MAC_FILTER_TYPE_DST = 0, 45 50 IGC_MAC_FILTER_TYPE_SRC ··· 338 333 struct timespec64 period; 339 334 } perout[IGC_N_PEROUT]; 340 335 336 + struct igc_fpe_t fpe; 337 + 341 338 /* LEDs */ 342 339 struct mutex led_mutex; 343 340 struct igc_led_classdev *leds; ··· 395 388 #define IGC_FLAG_TSN_QBV_ENABLED BIT(17) 396 389 #define IGC_FLAG_TSN_QAV_ENABLED BIT(18) 397 390 #define IGC_FLAG_TSN_LEGACY_ENABLED BIT(19) 391 + #define IGC_FLAG_TSN_PREEMPT_ENABLED BIT(20) 398 392 399 393 #define IGC_FLAG_TSN_ANY_ENABLED \ 400 394 (IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED | \ 401 - IGC_FLAG_TSN_LEGACY_ENABLED) 395 + IGC_FLAG_TSN_LEGACY_ENABLED | IGC_FLAG_TSN_PREEMPT_ENABLED) 402 396 403 397 #define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6) 404 398 #define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7) ··· 744 736 u32 location); 745 737 int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); 746 738 void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); 747 - 739 + void igc_disable_empty_addr_recv(struct igc_adapter *adapter); 740 + int igc_enable_empty_addr_recv(struct igc_adapter *adapter); 741 + struct igc_ring *igc_get_tx_ring(struct igc_adapter *adapter, int cpu); 742 + void igc_flush_tx_descriptors(struct igc_ring *ring); 748 743 void igc_ptp_init(struct igc_adapter *adapter); 749 744 void igc_ptp_reset(struct igc_adapter *adapter); 750 745 void igc_ptp_suspend(struct igc_adapter *adapter);
+1
drivers/net/ethernet/intel/igc/igc_base.h
··· 49 49 #define IGC_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */ 50 50 #define IGC_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */ 51 51 #define IGC_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ 52 + #define IGC_ADVTXD_PAYLEN_MASK 0XFFFFC000 /* Adv desc PAYLEN mask */ 52 53 #define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ 53 54 54 55 #define IGC_RAR_ENTRIES 16
+48 -5
drivers/net/ethernet/intel/igc/igc_defines.h
··· 308 308 #define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */ 309 309 #define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ 310 310 #define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ 311 + #define IGC_TXD_POPTS_SMD_MASK 0x3000 /* Indicates whether it's SMD-V or SMD-R */ 312 + 311 313 #define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */ 312 314 #define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */ 313 315 #define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ ··· 365 363 #define IGC_SRRCTL_TIMER0SEL(timer) (((timer) & 0x3) << 17) 366 364 367 365 /* Receive Descriptor bit definitions */ 366 + #define IGC_RXD_STAT_SMD_TYPE_V 0x01 /* SMD-V Packet */ 367 + #define IGC_RXD_STAT_SMD_TYPE_R 0x02 /* SMD-R Packet */ 368 368 #define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ 369 369 #define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */ 370 370 #define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ ··· 376 372 #define IGC_RXDEXT_STATERR_LB 0x00040000 377 373 378 374 /* Advanced Receive Descriptor bit definitions */ 379 - #define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */ 375 + #define IGC_RXDADV_STAT_SMD_TYPE_MASK 0x06000 376 + #define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */ 380 377 381 378 #define IGC_RXDEXT_STATERR_L4E 0x20000000 382 379 #define IGC_RXDEXT_STATERR_IPE 0x40000000 ··· 401 396 #define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */ 402 397 #define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ 403 398 404 - #define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ 405 - #define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ 406 - #define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */ 399 + /* Mask for RX packet buffer size */ 400 + #define IGC_RXPBSIZE_EXP_MASK GENMASK(5, 0) 401 + #define IGC_BMC2OSPBSIZE_MASK GENMASK(11, 6) 402 + #define IGC_RXPBSIZE_BE_MASK GENMASK(17, 12) 403 + /* Mask for timestamp in RX buffer */ 404 + #define IGC_RXPBS_CFG_TS_EN_MASK GENMASK(31, 31) 405 + /* High-priority RX packet buffer size (KB). Used for Express traffic when preemption is enabled */ 406 + #define IGC_RXPBSIZE_EXP(x) FIELD_PREP(IGC_RXPBSIZE_EXP_MASK, (x)) 407 + /* BMC to OS packet buffer size in KB */ 408 + #define IGC_BMC2OSPBSIZE(x) FIELD_PREP(IGC_BMC2OSPBSIZE_MASK, (x)) 409 + /* Low-priority RX packet buffer size (KB). Used for BE traffic when preemption is enabled */ 410 + #define IGC_RXPBSIZE_BE(x) FIELD_PREP(IGC_RXPBSIZE_BE_MASK, (x)) 411 + /* Enable RX packet buffer for timestamp descriptor, saving 16 bytes per packet if set */ 412 + #define IGC_RXPBS_CFG_TS_EN FIELD_PREP(IGC_RXPBS_CFG_TS_EN_MASK, 1) 413 + /* Default value following I225/I226 SW User Manual Section 8.3.1 */ 414 + #define IGC_RXPBSIZE_EXP_BMC_DEFAULT ( \ 415 + IGC_RXPBSIZE_EXP(34) | IGC_BMC2OSPBSIZE(2)) 416 + #define IGC_RXPBSIZE_EXP_BMC_BE_TSN ( \ 417 + IGC_RXPBSIZE_EXP(15) | IGC_BMC2OSPBSIZE(2) | IGC_RXPBSIZE_BE(15)) 407 418 408 - #define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */ 419 + /* Mask for TX packet buffer size */ 420 + #define IGC_TXPB0SIZE_MASK GENMASK(5, 0) 421 + #define IGC_TXPB1SIZE_MASK GENMASK(11, 6) 422 + #define IGC_TXPB2SIZE_MASK GENMASK(17, 12) 423 + #define IGC_TXPB3SIZE_MASK GENMASK(23, 18) 424 + /* Mask for OS to BMC packet buffer size */ 425 + #define IGC_OS2BMCPBSIZE_MASK GENMASK(29, 24) 426 + /* TX Packet buffer size in KB */ 427 + #define IGC_TXPB0SIZE(x) FIELD_PREP(IGC_TXPB0SIZE_MASK, (x)) 428 + #define IGC_TXPB1SIZE(x) FIELD_PREP(IGC_TXPB1SIZE_MASK, (x)) 429 + #define IGC_TXPB2SIZE(x) FIELD_PREP(IGC_TXPB2SIZE_MASK, (x)) 430 + #define IGC_TXPB3SIZE(x) FIELD_PREP(IGC_TXPB3SIZE_MASK, (x)) 431 + /* OS to BMC packet buffer size in KB */ 432 + #define IGC_OS2BMCPBSIZE(x) FIELD_PREP(IGC_OS2BMCPBSIZE_MASK, (x)) 433 + /* Default value following I225/I226 SW User Manual Section 8.3.2 */ 434 + #define IGC_TXPBSIZE_DEFAULT ( \ 435 + IGC_TXPB0SIZE(20) | IGC_TXPB1SIZE(0) | IGC_TXPB2SIZE(0) | \ 436 + IGC_TXPB3SIZE(0) | IGC_OS2BMCPBSIZE(4)) 437 + #define IGC_TXPBSIZE_TSN ( \ 438 + IGC_TXPB0SIZE(7) | IGC_TXPB1SIZE(7) | IGC_TXPB2SIZE(7) | \ 439 + IGC_TXPB3SIZE(7) | IGC_OS2BMCPBSIZE(4)) 409 440 410 441 #define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */ 411 442 #define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */ ··· 580 539 581 540 /* Transmit Scheduling */ 582 541 #define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001 542 + #define IGC_TQAVCTRL_PREEMPT_ENA 0x00000002 583 543 #define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008 584 544 #define IGC_TQAVCTRL_FUTSCDDIS 0x00000080 545 + #define IGC_TQAVCTRL_MIN_FRAG_MASK 0x0000C000 585 546 586 547 #define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001 587 548 #define IGC_TXQCTL_STRICT_CYCLE 0x00000002
+81
drivers/net/ethernet/intel/igc/igc_ethtool.c
··· 8 8 9 9 #include "igc.h" 10 10 #include "igc_diag.h" 11 + #include "igc_tsn.h" 11 12 12 13 /* forward declaration */ 13 14 struct igc_stats { ··· 1782 1781 return 0; 1783 1782 } 1784 1783 1784 + static int igc_ethtool_get_mm(struct net_device *netdev, 1785 + struct ethtool_mm_state *cmd) 1786 + { 1787 + struct igc_adapter *adapter = netdev_priv(netdev); 1788 + struct igc_fpe_t *fpe = &adapter->fpe; 1789 + 1790 + ethtool_mmsv_get_mm(&fpe->mmsv, cmd); 1791 + cmd->tx_min_frag_size = fpe->tx_min_frag_size; 1792 + cmd->rx_min_frag_size = IGC_RX_MIN_FRAG_SIZE; 1793 + 1794 + return 0; 1795 + } 1796 + 1797 + static int igc_ethtool_set_mm(struct net_device *netdev, 1798 + struct ethtool_mm_cfg *cmd, 1799 + struct netlink_ext_ack *extack) 1800 + { 1801 + struct igc_adapter *adapter = netdev_priv(netdev); 1802 + struct igc_fpe_t *fpe = &adapter->fpe; 1803 + 1804 + fpe->tx_min_frag_size = igc_fpe_get_supported_frag_size(cmd->tx_min_frag_size); 1805 + if (fpe->tx_min_frag_size != cmd->tx_min_frag_size) 1806 + NL_SET_ERR_MSG_MOD(extack, 1807 + "tx-min-frag-size value set is unsupported. Rounded up to supported value (64, 128, 192, 256)"); 1808 + 1809 + if (fpe->mmsv.pmac_enabled != cmd->pmac_enabled) { 1810 + if (cmd->pmac_enabled) 1811 + static_branch_inc(&igc_fpe_enabled); 1812 + else 1813 + static_branch_dec(&igc_fpe_enabled); 1814 + } 1815 + 1816 + ethtool_mmsv_set_mm(&fpe->mmsv, cmd); 1817 + 1818 + return igc_tsn_offload_apply(adapter); 1819 + } 1820 + 1821 + /** 1822 + * igc_ethtool_get_frame_ass_error - Get the frame assembly error count. 1823 + * @reg_value: Register value for IGC_PRMEXCPRCNT 1824 + * Return: The count of frame assembly errors. 1825 + */ 1826 + static u64 igc_ethtool_get_frame_ass_error(u32 reg_value) 1827 + { 1828 + /* Out of order statistics */ 1829 + u32 ooo_frame_cnt, ooo_frag_cnt; 1830 + u32 miss_frame_frag_cnt; 1831 + 1832 + ooo_frame_cnt = FIELD_GET(IGC_PRMEXCPRCNT_OOO_FRAME_CNT, reg_value); 1833 + ooo_frag_cnt = FIELD_GET(IGC_PRMEXCPRCNT_OOO_FRAG_CNT, reg_value); 1834 + miss_frame_frag_cnt = FIELD_GET(IGC_PRMEXCPRCNT_MISS_FRAME_FRAG_CNT, 1835 + reg_value); 1836 + 1837 + return ooo_frame_cnt + ooo_frag_cnt + miss_frame_frag_cnt; 1838 + } 1839 + 1840 + static u64 igc_ethtool_get_frame_smd_error(u32 reg_value) 1841 + { 1842 + return FIELD_GET(IGC_PRMEXCPRCNT_OOO_SMDC, reg_value); 1843 + } 1844 + 1845 + static void igc_ethtool_get_mm_stats(struct net_device *dev, 1846 + struct ethtool_mm_stats *stats) 1847 + { 1848 + struct igc_adapter *adapter = netdev_priv(dev); 1849 + struct igc_hw *hw = &adapter->hw; 1850 + u32 reg_value; 1851 + 1852 + reg_value = rd32(IGC_PRMEXCPRCNT); 1853 + 1854 + stats->MACMergeFrameAssErrorCount = igc_ethtool_get_frame_ass_error(reg_value); 1855 + stats->MACMergeFrameSmdErrorCount = igc_ethtool_get_frame_smd_error(reg_value); 1856 + stats->MACMergeFrameAssOkCount = rd32(IGC_PRMPTDRCNT); 1857 + stats->MACMergeFragCountRx = rd32(IGC_PRMEVNTRCNT); 1858 + stats->MACMergeFragCountTx = rd32(IGC_PRMEVNTTCNT); 1859 + } 1860 + 1785 1861 static int igc_ethtool_get_link_ksettings(struct net_device *netdev, 1786 1862 struct ethtool_link_ksettings *cmd) 1787 1863 { ··· 2154 2076 .get_link_ksettings = igc_ethtool_get_link_ksettings, 2155 2077 .set_link_ksettings = igc_ethtool_set_link_ksettings, 2156 2078 .self_test = igc_ethtool_diag_test, 2079 + .get_mm = igc_ethtool_get_mm, 2080 + .get_mm_stats = igc_ethtool_get_mm_stats, 2081 + .set_mm = igc_ethtool_set_mm, 2157 2082 }; 2158 2083 2159 2084 void igc_ethtool_set_ops(struct net_device *netdev)
+61 -8
drivers/net/ethernet/intel/igc/igc_main.c
··· 2464 2464 return -ENOMEM; 2465 2465 } 2466 2466 2467 - static struct igc_ring *igc_xdp_get_tx_ring(struct igc_adapter *adapter, 2468 - int cpu) 2467 + struct igc_ring *igc_get_tx_ring(struct igc_adapter *adapter, int cpu) 2469 2468 { 2470 2469 int index = cpu; 2471 2470 ··· 2488 2489 if (unlikely(!xdpf)) 2489 2490 return -EFAULT; 2490 2491 2491 - ring = igc_xdp_get_tx_ring(adapter, cpu); 2492 + ring = igc_get_tx_ring(adapter, cpu); 2492 2493 nq = txring_txq(ring); 2493 2494 2494 2495 __netif_tx_lock(nq, cpu); ··· 2548 2549 } 2549 2550 2550 2551 /* This function assumes __netif_tx_lock is held by the caller. */ 2551 - static void igc_flush_tx_descriptors(struct igc_ring *ring) 2552 + void igc_flush_tx_descriptors(struct igc_ring *ring) 2552 2553 { 2553 2554 /* Once tail pointer is updated, hardware can fetch the descriptors 2554 2555 * any time so we issue a write membar here to ensure all memory ··· 2565 2566 struct igc_ring *ring; 2566 2567 2567 2568 if (status & IGC_XDP_TX) { 2568 - ring = igc_xdp_get_tx_ring(adapter, cpu); 2569 + ring = igc_get_tx_ring(adapter, cpu); 2569 2570 nq = txring_txq(ring); 2570 2571 2571 2572 __netif_tx_lock(nq, cpu); ··· 2635 2636 ctx.rx_ts = pktbuf; 2636 2637 pkt_offset = IGC_TS_HDR_LEN; 2637 2638 size -= IGC_TS_HDR_LEN; 2639 + } 2640 + 2641 + if (igc_fpe_is_pmac_enabled(adapter) && 2642 + igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf)) { 2643 + /* Advance the ring next-to-clean */ 2644 + igc_is_non_eop(rx_ring, rx_desc); 2645 + cleaned_count++; 2646 + continue; 2638 2647 } 2639 2648 2640 2649 if (!skb) { ··· 3151 3144 /* if DD is not set pending work has not been completed */ 3152 3145 if (!(eop_desc->wb.status & cpu_to_le32(IGC_TXD_STAT_DD))) 3153 3146 break; 3147 + 3148 + if (igc_fpe_is_pmac_enabled(adapter) && 3149 + igc_fpe_transmitted_smd_v(tx_desc)) 3150 + ethtool_mmsv_event_handle(&adapter->fpe.mmsv, 3151 + ETHTOOL_MMSV_LD_SENT_VERIFY_MPACKET); 3154 3152 3155 3153 /* Hold the completions while there's a pending tx hardware 3156 3154 * timestamp request from XDP Tx metadata. ··· 4046 4034 4047 4035 igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, addr); 4048 4036 return 0; 4037 + } 4038 + 4039 + /** 4040 + * igc_enable_empty_addr_recv - Enable Rx of packets with all-zeroes MAC address 4041 + * @adapter: Pointer to the igc_adapter structure. 4042 + * 4043 + * Frame preemption verification requires that packets with the all-zeroes 4044 + * MAC address are allowed to be received by the driver. This function adds the 4045 + * all-zeroes destination address to the list of acceptable addresses. 4046 + * 4047 + * Return: 0 on success, negative value otherwise. 4048 + */ 4049 + int igc_enable_empty_addr_recv(struct igc_adapter *adapter) 4050 + { 4051 + u8 empty[ETH_ALEN] = {}; 4052 + 4053 + return igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, empty, -1); 4054 + } 4055 + 4056 + void igc_disable_empty_addr_recv(struct igc_adapter *adapter) 4057 + { 4058 + u8 empty[ETH_ALEN] = {}; 4059 + 4060 + igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, empty); 4049 4061 } 4050 4062 4051 4063 /** ··· 5347 5311 igc_disable_all_tx_rings_hw(adapter); 5348 5312 igc_clean_all_tx_rings(adapter); 5349 5313 igc_clean_all_rx_rings(adapter); 5314 + 5315 + if (adapter->fpe.mmsv.pmac_enabled) 5316 + ethtool_mmsv_stop(&adapter->fpe.mmsv); 5350 5317 } 5351 5318 5352 5319 void igc_reinit_locked(struct igc_adapter *adapter) ··· 5874 5835 */ 5875 5836 igc_tsn_adjust_txtime_offset(adapter); 5876 5837 5838 + if (adapter->fpe.mmsv.pmac_enabled) 5839 + ethtool_mmsv_link_state_handle(&adapter->fpe.mmsv, 5840 + true); 5841 + 5877 5842 if (adapter->link_speed != SPEED_1000) 5878 5843 goto no_wait; 5879 5844 ··· 5912 5869 /* Links status message must follow this format */ 5913 5870 netdev_info(netdev, "NIC Link is Down\n"); 5914 5871 netif_carrier_off(netdev); 5872 + 5873 + if (adapter->fpe.mmsv.pmac_enabled) 5874 + ethtool_mmsv_link_state_handle(&adapter->fpe.mmsv, 5875 + false); 5915 5876 5916 5877 /* link state has changed, schedule phy info update */ 5917 5878 if (!test_bit(__IGC_DOWN, &adapter->state)) ··· 6486 6439 if (!validate_schedule(adapter, qopt)) 6487 6440 return -EINVAL; 6488 6441 6442 + /* preemptible isn't supported yet */ 6443 + if (qopt->mqprio.preemptible_tcs) 6444 + return -EOPNOTSUPP; 6445 + 6489 6446 igc_ptp_read(adapter, &now); 6490 6447 6491 6448 if (igc_tsn_is_taprio_activated_by_user(adapter) && ··· 6830 6779 if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) 6831 6780 return -EINVAL; 6832 6781 6833 - ring = igc_xdp_get_tx_ring(adapter, cpu); 6782 + ring = igc_get_tx_ring(adapter, cpu); 6834 6783 nq = txring_txq(ring); 6835 6784 6836 6785 __netif_tx_lock(nq, cpu); ··· 7211 7160 } 7212 7161 7213 7162 /* configure RXPBSIZE and TXPBSIZE */ 7214 - wr32(IGC_RXPBS, I225_RXPBSIZE_DEFAULT); 7215 - wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); 7163 + wr32(IGC_RXPBS, IGC_RXPBSIZE_EXP_BMC_DEFAULT); 7164 + wr32(IGC_TXPBS, IGC_TXPBSIZE_DEFAULT); 7216 7165 7217 7166 timer_setup(&adapter->watchdog_timer, igc_watchdog, 0); 7218 7167 timer_setup(&adapter->phy_info_timer, igc_update_phy_info, 0); ··· 7243 7192 igc_ptp_init(adapter); 7244 7193 7245 7194 igc_tsn_clear_schedule(adapter); 7195 + 7196 + igc_fpe_init(adapter); 7246 7197 7247 7198 /* reset the hardware with the new settings */ 7248 7199 igc_reset(adapter);
+16
drivers/net/ethernet/intel/igc/igc_regs.h
··· 222 222 223 223 #define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */ 224 224 225 + /* Time sync registers - preemption statistics */ 226 + #define IGC_PRMPTDRCNT 0x04284 /* Good RX Preempted Packets */ 227 + #define IGC_PRMEVNTTCNT 0x04298 /* TX Preemption event counter */ 228 + #define IGC_PRMEVNTRCNT 0x0429C /* RX Preemption event counter */ 229 + 230 + /* Preemption Exception Counter */ 231 + #define IGC_PRMEXCPRCNT 0x42A0 232 + /* Received out of order packets with SMD-C */ 233 + #define IGC_PRMEXCPRCNT_OOO_SMDC 0x000000FF 234 + /* Received out of order packets with SMD-C and wrong Frame CNT */ 235 + #define IGC_PRMEXCPRCNT_OOO_FRAME_CNT 0x0000FF00 236 + /* Received out of order packets with SMD-C and wrong Frag CNT */ 237 + #define IGC_PRMEXCPRCNT_OOO_FRAG_CNT 0x00FF0000 238 + /* Received packets with SMD-S and wrong Frag CNT and Frame CNT */ 239 + #define IGC_PRMEXCPRCNT_MISS_FRAME_FRAG_CNT 0xFF000000 240 + 225 241 /* Transmit Scheduling Registers */ 226 242 #define IGC_TQAVCTRL 0x3570 227 243 #define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n))
+206 -4
drivers/net/ethernet/intel/igc/igc_tsn.c
··· 2 2 /* Copyright (c) 2019 Intel Corporation */ 3 3 4 4 #include "igc.h" 5 + #include "igc_base.h" 5 6 #include "igc_hw.h" 6 7 #include "igc_tsn.h" 8 + 9 + #define MIN_MULTPLIER_TX_MIN_FRAG 0 10 + #define MAX_MULTPLIER_TX_MIN_FRAG 3 11 + /* Frag size is based on the Section 8.12.2 of the SW User Manual */ 12 + #define TX_MIN_FRAG_SIZE 64 13 + #define TX_MAX_FRAG_SIZE (TX_MIN_FRAG_SIZE * \ 14 + (MAX_MULTPLIER_TX_MIN_FRAG + 1)) 15 + 16 + DEFINE_STATIC_KEY_FALSE(igc_fpe_enabled); 17 + 18 + static int igc_fpe_init_smd_frame(struct igc_ring *ring, 19 + struct igc_tx_buffer *buffer, 20 + struct sk_buff *skb) 21 + { 22 + dma_addr_t dma = dma_map_single(ring->dev, skb->data, skb->len, 23 + DMA_TO_DEVICE); 24 + 25 + if (dma_mapping_error(ring->dev, dma)) { 26 + netdev_err_once(ring->netdev, "Failed to map DMA for TX\n"); 27 + return -ENOMEM; 28 + } 29 + 30 + buffer->skb = skb; 31 + buffer->protocol = 0; 32 + buffer->bytecount = skb->len; 33 + buffer->gso_segs = 1; 34 + buffer->time_stamp = jiffies; 35 + dma_unmap_len_set(buffer, len, skb->len); 36 + dma_unmap_addr_set(buffer, dma, dma); 37 + 38 + return 0; 39 + } 40 + 41 + static int igc_fpe_init_tx_descriptor(struct igc_ring *ring, 42 + struct sk_buff *skb, 43 + enum igc_txd_popts_type type) 44 + { 45 + u32 cmd_type, olinfo_status = 0; 46 + struct igc_tx_buffer *buffer; 47 + union igc_adv_tx_desc *desc; 48 + int err; 49 + 50 + if (!igc_desc_unused(ring)) 51 + return -EBUSY; 52 + 53 + buffer = &ring->tx_buffer_info[ring->next_to_use]; 54 + err = igc_fpe_init_smd_frame(ring, buffer, skb); 55 + if (err) 56 + return err; 57 + 58 + cmd_type = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT | 59 + IGC_ADVTXD_DCMD_IFCS | IGC_TXD_DCMD | 60 + buffer->bytecount; 61 + 62 + olinfo_status |= FIELD_PREP(IGC_ADVTXD_PAYLEN_MASK, buffer->bytecount); 63 + 64 + switch (type) { 65 + case SMD_V: 66 + case SMD_R: 67 + olinfo_status |= FIELD_PREP(IGC_TXD_POPTS_SMD_MASK, type); 68 + break; 69 + } 70 + 71 + desc = IGC_TX_DESC(ring, ring->next_to_use); 72 + desc->read.cmd_type_len = cpu_to_le32(cmd_type); 73 + desc->read.olinfo_status = cpu_to_le32(olinfo_status); 74 + desc->read.buffer_addr = cpu_to_le64(dma_unmap_addr(buffer, dma)); 75 + 76 + netdev_tx_sent_queue(txring_txq(ring), skb->len); 77 + 78 + buffer->next_to_watch = desc; 79 + ring->next_to_use = (ring->next_to_use + 1) % ring->count; 80 + 81 + return 0; 82 + } 83 + 84 + static int igc_fpe_xmit_smd_frame(struct igc_adapter *adapter, 85 + enum igc_txd_popts_type type) 86 + { 87 + int cpu = smp_processor_id(); 88 + struct netdev_queue *nq; 89 + struct igc_ring *ring; 90 + struct sk_buff *skb; 91 + int err; 92 + 93 + ring = igc_get_tx_ring(adapter, cpu); 94 + nq = txring_txq(ring); 95 + 96 + skb = alloc_skb(SMD_FRAME_SIZE, GFP_ATOMIC); 97 + if (!skb) 98 + return -ENOMEM; 99 + 100 + skb_put_zero(skb, SMD_FRAME_SIZE); 101 + 102 + __netif_tx_lock(nq, cpu); 103 + 104 + err = igc_fpe_init_tx_descriptor(ring, skb, type); 105 + igc_flush_tx_descriptors(ring); 106 + 107 + __netif_tx_unlock(nq); 108 + 109 + return err; 110 + } 111 + 112 + static void igc_fpe_send_mpacket(struct ethtool_mmsv *mmsv, 113 + enum ethtool_mpacket type) 114 + { 115 + struct igc_fpe_t *fpe = container_of(mmsv, struct igc_fpe_t, mmsv); 116 + struct igc_adapter *adapter; 117 + int err; 118 + 119 + adapter = container_of(fpe, struct igc_adapter, fpe); 120 + 121 + if (type == ETHTOOL_MPACKET_VERIFY) { 122 + err = igc_fpe_xmit_smd_frame(adapter, SMD_V); 123 + if (err && net_ratelimit()) 124 + netdev_err(adapter->netdev, "Error sending SMD-V\n"); 125 + } else if (type == ETHTOOL_MPACKET_RESPONSE) { 126 + err = igc_fpe_xmit_smd_frame(adapter, SMD_R); 127 + if (err && net_ratelimit()) 128 + netdev_err(adapter->netdev, "Error sending SMD-R frame\n"); 129 + } 130 + } 131 + 132 + static const struct ethtool_mmsv_ops igc_mmsv_ops = { 133 + .send_mpacket = igc_fpe_send_mpacket, 134 + }; 135 + 136 + void igc_fpe_init(struct igc_adapter *adapter) 137 + { 138 + adapter->fpe.tx_min_frag_size = TX_MIN_FRAG_SIZE; 139 + ethtool_mmsv_init(&adapter->fpe.mmsv, adapter->netdev, &igc_mmsv_ops); 140 + } 7 141 8 142 static bool is_any_launchtime(struct igc_adapter *adapter) 9 143 { ··· 182 48 183 49 if (adapter->strict_priority_enable) 184 50 new_flags |= IGC_FLAG_TSN_LEGACY_ENABLED; 51 + 52 + if (adapter->fpe.mmsv.pmac_enabled) 53 + new_flags |= IGC_FLAG_TSN_PREEMPT_ENABLED; 185 54 186 55 return new_flags; 187 56 } ··· 262 125 wr32(IGC_TXARB, txarb); 263 126 } 264 127 128 + /** 129 + * igc_tsn_set_rxpbsize - Set the receive packet buffer size 130 + * @adapter: Pointer to the igc_adapter structure 131 + * @rxpbs_exp_bmc_be: Value to set the receive packet buffer size, including 132 + * express buffer, BMC buffer, and Best Effort buffer 133 + * 134 + * The IGC_RXPBS register value may include allocations for the Express buffer, 135 + * BMC buffer, Best Effort buffer, and the timestamp descriptor buffer 136 + * (IGC_RXPBS_CFG_TS_EN). 137 + */ 138 + static void igc_tsn_set_rxpbsize(struct igc_adapter *adapter, 139 + u32 rxpbs_exp_bmc_be) 140 + { 141 + struct igc_hw *hw = &adapter->hw; 142 + u32 rxpbs = rd32(IGC_RXPBS); 143 + 144 + rxpbs &= ~(IGC_RXPBSIZE_EXP_MASK | IGC_BMC2OSPBSIZE_MASK | 145 + IGC_RXPBSIZE_BE_MASK); 146 + rxpbs |= rxpbs_exp_bmc_be; 147 + 148 + wr32(IGC_RXPBS, rxpbs); 149 + } 150 + 265 151 /* Returns the TSN specific registers to their default values after 266 152 * the adapter is reset. 267 153 */ ··· 296 136 int i; 297 137 298 138 wr32(IGC_GTXOFFSET, 0); 299 - wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); 139 + wr32(IGC_TXPBS, IGC_TXPBSIZE_DEFAULT); 300 140 wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT); 141 + 142 + igc_tsn_set_rxpbsize(adapter, IGC_RXPBSIZE_EXP_BMC_DEFAULT); 301 143 302 144 if (igc_is_device_id_i226(hw)) 303 145 igc_tsn_restore_retx_default(adapter); 304 146 305 147 tqavctrl = rd32(IGC_TQAVCTRL); 306 148 tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN | 307 - IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS); 149 + IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS | 150 + IGC_TQAVCTRL_PREEMPT_ENA | IGC_TQAVCTRL_MIN_FRAG_MASK); 308 151 309 152 wr32(IGC_TQAVCTRL, tqavctrl); 310 153 ··· 353 190 wr32(IGC_RETX_CTL, retxctl); 354 191 } 355 192 193 + static u8 igc_fpe_get_frag_size_mult(const struct igc_fpe_t *fpe) 194 + { 195 + u8 mult = (fpe->tx_min_frag_size / TX_MIN_FRAG_SIZE) - 1; 196 + 197 + return clamp_t(u8, mult, MIN_MULTPLIER_TX_MIN_FRAG, 198 + MAX_MULTPLIER_TX_MIN_FRAG); 199 + } 200 + 201 + u32 igc_fpe_get_supported_frag_size(u32 frag_size) 202 + { 203 + const u32 supported_sizes[] = {64, 128, 192, 256}; 204 + 205 + /* Find the smallest supported size that is >= frag_size */ 206 + for (int i = 0; i < ARRAY_SIZE(supported_sizes); i++) { 207 + if (frag_size <= supported_sizes[i]) 208 + return supported_sizes[i]; 209 + } 210 + 211 + /* Should not happen */ 212 + return TX_MAX_FRAG_SIZE; 213 + } 214 + 356 215 static int igc_tsn_enable_offload(struct igc_adapter *adapter) 357 216 { 358 217 struct igc_hw *hw = &adapter->hw; 359 218 u32 tqavctrl, baset_l, baset_h; 360 219 u32 sec, nsec, cycle; 361 220 ktime_t base_time, systim; 221 + u32 frag_size_mult; 362 222 int i; 363 223 364 224 wr32(IGC_TSAUXC, 0); 365 225 wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN); 366 226 wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN); 227 + 228 + igc_tsn_set_rxpbsize(adapter, IGC_RXPBSIZE_EXP_BMC_BE_TSN); 367 229 368 230 if (igc_is_device_id_i226(hw)) 369 231 igc_tsn_set_retx_qbvfullthreshold(adapter); ··· 549 361 wr32(IGC_TXQCTL(i), txqctl); 550 362 } 551 363 552 - tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS; 553 - 364 + tqavctrl = rd32(IGC_TQAVCTRL) & ~(IGC_TQAVCTRL_FUTSCDDIS | 365 + IGC_TQAVCTRL_PREEMPT_ENA | IGC_TQAVCTRL_MIN_FRAG_MASK); 554 366 tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; 367 + 368 + if (adapter->fpe.mmsv.pmac_enabled) 369 + tqavctrl |= IGC_TQAVCTRL_PREEMPT_ENA; 370 + 371 + frag_size_mult = igc_fpe_get_frag_size_mult(&adapter->fpe); 372 + tqavctrl |= FIELD_PREP(IGC_TQAVCTRL_MIN_FRAG_MASK, frag_size_mult); 555 373 556 374 adapter->qbv_count++; 557 375 ··· 618 424 { 619 425 unsigned int new_flags; 620 426 int err = 0; 427 + 428 + if (adapter->fpe.mmsv.pmac_enabled) { 429 + err = igc_enable_empty_addr_recv(adapter); 430 + if (err && net_ratelimit()) 431 + netdev_err(adapter->netdev, "Error adding empty address to MAC filter\n"); 432 + } else { 433 + igc_disable_empty_addr_recv(adapter); 434 + } 621 435 622 436 new_flags = igc_tsn_new_flags(adapter); 623 437
+52
drivers/net/ethernet/intel/igc/igc_tsn.h
··· 4 4 #ifndef _IGC_TSN_H_ 5 5 #define _IGC_TSN_H_ 6 6 7 + #define IGC_RX_MIN_FRAG_SIZE 60 8 + #define SMD_FRAME_SIZE 60 9 + 10 + enum igc_txd_popts_type { 11 + SMD_V = 0x01, 12 + SMD_R = 0x02, 13 + }; 14 + 15 + DECLARE_STATIC_KEY_FALSE(igc_fpe_enabled); 16 + 17 + void igc_fpe_init(struct igc_adapter *adapter); 18 + u32 igc_fpe_get_supported_frag_size(u32 frag_size); 7 19 int igc_tsn_offload_apply(struct igc_adapter *adapter); 8 20 int igc_tsn_reset(struct igc_adapter *adapter); 9 21 void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter); 10 22 bool igc_tsn_is_taprio_activated_by_user(struct igc_adapter *adapter); 23 + 24 + static inline bool igc_fpe_is_pmac_enabled(struct igc_adapter *adapter) 25 + { 26 + return static_branch_unlikely(&igc_fpe_enabled) && 27 + adapter->fpe.mmsv.pmac_enabled; 28 + } 29 + 30 + static inline bool igc_fpe_handle_mpacket(struct igc_adapter *adapter, 31 + union igc_adv_rx_desc *rx_desc, 32 + unsigned int size, void *pktbuf) 33 + { 34 + u32 status_error = le32_to_cpu(rx_desc->wb.upper.status_error); 35 + int smd; 36 + 37 + smd = FIELD_GET(IGC_RXDADV_STAT_SMD_TYPE_MASK, status_error); 38 + if (smd != IGC_RXD_STAT_SMD_TYPE_V && smd != IGC_RXD_STAT_SMD_TYPE_R) 39 + return false; 40 + 41 + if (size == SMD_FRAME_SIZE && mem_is_zero(pktbuf, SMD_FRAME_SIZE)) { 42 + struct ethtool_mmsv *mmsv = &adapter->fpe.mmsv; 43 + enum ethtool_mmsv_event event; 44 + 45 + if (smd == IGC_RXD_STAT_SMD_TYPE_V) 46 + event = ETHTOOL_MMSV_LP_SENT_VERIFY_MPACKET; 47 + else 48 + event = ETHTOOL_MMSV_LP_SENT_RESPONSE_MPACKET; 49 + 50 + ethtool_mmsv_event_handle(mmsv, event); 51 + } 52 + 53 + return true; 54 + } 55 + 56 + static inline bool igc_fpe_transmitted_smd_v(union igc_adv_tx_desc *tx_desc) 57 + { 58 + u32 olinfo_status = le32_to_cpu(tx_desc->read.olinfo_status); 59 + u8 smd = FIELD_GET(IGC_TXD_POPTS_SMD_MASK, olinfo_status); 60 + 61 + return smd == SMD_V; 62 + } 11 63 12 64 #endif /* _IGC_BASE_H */
+1
drivers/net/ethernet/stmicro/stmmac/Kconfig
··· 3 3 tristate "STMicroelectronics Multi-Gigabit Ethernet driver" 4 4 depends on HAS_IOMEM && HAS_DMA 5 5 depends on PTP_1588_CLOCK_OPTIONAL 6 + depends on ETHTOOL_NETLINK 6 7 select MII 7 8 select PCS_XPCS 8 9 select PAGE_POOL
+2 -14
drivers/net/ethernet/stmicro/stmmac/stmmac.h
··· 149 149 }; 150 150 151 151 struct stmmac_fpe_cfg { 152 - /* Serialize access to MAC Merge state between ethtool requests 153 - * and link state updates. 154 - */ 155 - spinlock_t lock; 156 - 152 + struct ethtool_mmsv mmsv; 157 153 const struct stmmac_fpe_reg *reg; 158 - u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ 159 - 160 - enum ethtool_mm_verify_status status; 161 - struct timer_list verify_timer; 162 - bool verify_enabled; 163 - int verify_retries; 164 - bool pmac_enabled; 165 - u32 verify_time; 166 - bool tx_enabled; 154 + u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ 167 155 }; 168 156 169 157 struct stmmac_tc_entry {
+2 -39
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
··· 1210 1210 struct ethtool_mm_state *state) 1211 1211 { 1212 1212 struct stmmac_priv *priv = netdev_priv(ndev); 1213 - unsigned long flags; 1214 1213 u32 frag_size; 1215 1214 1216 1215 if (!stmmac_fpe_supported(priv)) 1217 1216 return -EOPNOTSUPP; 1218 1217 1219 - spin_lock_irqsave(&priv->fpe_cfg.lock, flags); 1220 - 1221 - state->max_verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; 1222 - state->verify_enabled = priv->fpe_cfg.verify_enabled; 1223 - state->pmac_enabled = priv->fpe_cfg.pmac_enabled; 1224 - state->verify_time = priv->fpe_cfg.verify_time; 1225 - state->tx_enabled = priv->fpe_cfg.tx_enabled; 1226 - state->verify_status = priv->fpe_cfg.status; 1227 1218 state->rx_min_frag_size = ETH_ZLEN; 1228 - 1229 - /* FPE active if common tx_enabled and 1230 - * (verification success or disabled(forced)) 1231 - */ 1232 - if (state->tx_enabled && 1233 - (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED || 1234 - state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED)) 1235 - state->tx_active = true; 1236 - else 1237 - state->tx_active = false; 1238 - 1239 1219 frag_size = stmmac_fpe_get_add_frag_size(priv); 1240 1220 state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size); 1241 1221 1242 - spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags); 1222 + ethtool_mmsv_get_mm(&priv->fpe_cfg.mmsv, state); 1243 1223 1244 1224 return 0; 1245 1225 } ··· 1228 1248 struct netlink_ext_ack *extack) 1229 1249 { 1230 1250 struct stmmac_priv *priv = netdev_priv(ndev); 1231 - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; 1232 - unsigned long flags; 1233 1251 u32 frag_size; 1234 1252 int err; 1235 1253 ··· 1236 1258 if (err) 1237 1259 return err; 1238 1260 1239 - /* Wait for the verification that's currently in progress to finish */ 1240 - timer_shutdown_sync(&fpe_cfg->verify_timer); 1241 - 1242 - spin_lock_irqsave(&fpe_cfg->lock, flags); 1243 - 1244 - fpe_cfg->verify_enabled = cfg->verify_enabled; 1245 - fpe_cfg->pmac_enabled = cfg->pmac_enabled; 1246 - fpe_cfg->verify_time = cfg->verify_time; 1247 - fpe_cfg->tx_enabled = cfg->tx_enabled; 1248 - 1249 - if (!cfg->verify_enabled) 1250 - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; 1251 - 1252 1261 stmmac_fpe_set_add_frag_size(priv, frag_size); 1253 - stmmac_fpe_apply(priv); 1254 - 1255 - spin_unlock_irqrestore(&fpe_cfg->lock, flags); 1262 + ethtool_mmsv_set_mm(&priv->fpe_cfg.mmsv, cfg); 1256 1263 1257 1264 return 0; 1258 1265 }
+36 -138
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
··· 27 27 #define STMMAC_MAC_FPE_CTRL_STS_SVER BIT(1) 28 28 #define STMMAC_MAC_FPE_CTRL_STS_EFPE BIT(0) 29 29 30 - /* FPE link-partner hand-shaking mPacket type */ 31 - enum stmmac_mpacket_type { 32 - MPACKET_VERIFY = 0, 33 - MPACKET_RESPONSE = 1, 34 - }; 35 - 36 30 struct stmmac_fpe_reg { 37 31 const u32 mac_fpe_reg; /* offset of MAC_FPE_CTRL_STS */ 38 32 const u32 mtl_fpe_reg; /* offset of MTL_FPE_CTRL_STS */ ··· 42 48 priv->hw->mac->fpe_map_preemption_class; 43 49 } 44 50 45 - static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable, 46 - bool pmac_enable) 51 + static void stmmac_fpe_configure_tx(struct ethtool_mmsv *mmsv, bool tx_enable) 47 52 { 48 - struct stmmac_fpe_cfg *cfg = &priv->fpe_cfg; 53 + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); 54 + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); 49 55 const struct stmmac_fpe_reg *reg = cfg->reg; 50 56 u32 num_rxq = priv->plat->rx_queues_to_use; 51 57 void __iomem *ioaddr = priv->ioaddr; ··· 62 68 cfg->fpe_csr = 0; 63 69 } 64 70 writel(cfg->fpe_csr, ioaddr + reg->mac_fpe_reg); 71 + } 72 + 73 + static void stmmac_fpe_configure_pmac(struct ethtool_mmsv *mmsv, bool pmac_enable) 74 + { 75 + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); 76 + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); 77 + const struct stmmac_fpe_reg *reg = cfg->reg; 78 + void __iomem *ioaddr = priv->ioaddr; 79 + u32 value; 65 80 66 81 value = readl(ioaddr + reg->int_en_reg); 67 82 ··· 88 85 writel(value, ioaddr + reg->int_en_reg); 89 86 } 90 87 91 - static void stmmac_fpe_send_mpacket(struct stmmac_priv *priv, 92 - enum stmmac_mpacket_type type) 88 + static void stmmac_fpe_send_mpacket(struct ethtool_mmsv *mmsv, 89 + enum ethtool_mpacket type) 93 90 { 94 - const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; 91 + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); 92 + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); 93 + const struct stmmac_fpe_reg *reg = cfg->reg; 95 94 void __iomem *ioaddr = priv->ioaddr; 96 - u32 value = priv->fpe_cfg.fpe_csr; 95 + u32 value = cfg->fpe_csr; 97 96 98 - if (type == MPACKET_VERIFY) 97 + if (type == ETHTOOL_MPACKET_VERIFY) 99 98 value |= STMMAC_MAC_FPE_CTRL_STS_SVER; 100 - else if (type == MPACKET_RESPONSE) 99 + else if (type == ETHTOOL_MPACKET_RESPONSE) 101 100 value |= STMMAC_MAC_FPE_CTRL_STS_SRSP; 102 101 103 102 writel(value, ioaddr + reg->mac_fpe_reg); 104 103 } 105 104 105 + static const struct ethtool_mmsv_ops stmmac_mmsv_ops = { 106 + .configure_tx = stmmac_fpe_configure_tx, 107 + .configure_pmac = stmmac_fpe_configure_pmac, 108 + .send_mpacket = stmmac_fpe_send_mpacket, 109 + }; 110 + 106 111 static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status) 107 112 { 108 113 struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; 114 + struct ethtool_mmsv *mmsv = &fpe_cfg->mmsv; 109 115 110 - /* This is interrupt context, just spin_lock() */ 111 - spin_lock(&fpe_cfg->lock); 116 + if (status == FPE_EVENT_UNKNOWN) 117 + return; 112 118 113 - if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN) 114 - goto unlock_out; 115 - 116 - /* LP has sent verify mPacket */ 117 119 if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER) 118 - stmmac_fpe_send_mpacket(priv, MPACKET_RESPONSE); 120 + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LP_SENT_VERIFY_MPACKET); 119 121 120 - /* Local has sent verify mPacket */ 121 - if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER && 122 - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) 123 - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; 122 + if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER) 123 + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LD_SENT_VERIFY_MPACKET); 124 124 125 - /* LP has sent response mPacket */ 126 - if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP && 127 - fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING) 128 - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; 129 - 130 - unlock_out: 131 - spin_unlock(&fpe_cfg->lock); 125 + if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP) 126 + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LP_SENT_RESPONSE_MPACKET); 132 127 } 133 128 134 129 void stmmac_fpe_irq_status(struct stmmac_priv *priv) ··· 165 164 stmmac_fpe_event_status(priv, status); 166 165 } 167 166 168 - /** 169 - * stmmac_fpe_verify_timer - Timer for MAC Merge verification 170 - * @t: timer_list struct containing private info 171 - * 172 - * Verify the MAC Merge capability in the local TX direction, by 173 - * transmitting Verify mPackets up to 3 times. Wait until link 174 - * partner responds with a Response mPacket, otherwise fail. 175 - */ 176 - static void stmmac_fpe_verify_timer(struct timer_list *t) 177 - { 178 - struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer); 179 - struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv, 180 - fpe_cfg); 181 - unsigned long flags; 182 - bool rearm = false; 183 - 184 - spin_lock_irqsave(&fpe_cfg->lock, flags); 185 - 186 - switch (fpe_cfg->status) { 187 - case ETHTOOL_MM_VERIFY_STATUS_INITIAL: 188 - case ETHTOOL_MM_VERIFY_STATUS_VERIFYING: 189 - if (fpe_cfg->verify_retries != 0) { 190 - stmmac_fpe_send_mpacket(priv, MPACKET_VERIFY); 191 - rearm = true; 192 - } else { 193 - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED; 194 - } 195 - 196 - fpe_cfg->verify_retries--; 197 - break; 198 - 199 - case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: 200 - stmmac_fpe_configure(priv, true, true); 201 - break; 202 - 203 - default: 204 - break; 205 - } 206 - 207 - if (rearm) { 208 - mod_timer(&fpe_cfg->verify_timer, 209 - jiffies + msecs_to_jiffies(fpe_cfg->verify_time)); 210 - } 211 - 212 - spin_unlock_irqrestore(&fpe_cfg->lock, flags); 213 - } 214 - 215 - static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg) 216 - { 217 - if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled && 218 - fpe_cfg->verify_enabled && 219 - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED && 220 - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) { 221 - timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0); 222 - mod_timer(&fpe_cfg->verify_timer, jiffies); 223 - } 224 - } 225 - 226 167 void stmmac_fpe_init(struct stmmac_priv *priv) 227 168 { 228 - priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; 229 - priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; 230 - priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; 231 - timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0); 232 - spin_lock_init(&priv->fpe_cfg.lock); 169 + ethtool_mmsv_init(&priv->fpe_cfg.mmsv, priv->dev, 170 + &stmmac_mmsv_ops); 233 171 234 172 if ((!priv->fpe_cfg.reg || !priv->hw->mac->fpe_map_preemption_class) && 235 173 priv->dma_cap.fpesel) 236 174 dev_info(priv->device, "FPE is not supported by driver.\n"); 237 - } 238 - 239 - void stmmac_fpe_apply(struct stmmac_priv *priv) 240 - { 241 - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; 242 - 243 - /* If verification is disabled, configure FPE right away. 244 - * Otherwise let the timer code do it. 245 - */ 246 - if (!fpe_cfg->verify_enabled) { 247 - stmmac_fpe_configure(priv, fpe_cfg->tx_enabled, 248 - fpe_cfg->pmac_enabled); 249 - } else { 250 - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; 251 - fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; 252 - 253 - if (netif_running(priv->dev)) 254 - stmmac_fpe_verify_timer_arm(fpe_cfg); 255 - } 256 - } 257 - 258 - void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) 259 - { 260 - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; 261 - unsigned long flags; 262 - 263 - timer_shutdown_sync(&fpe_cfg->verify_timer); 264 - 265 - spin_lock_irqsave(&fpe_cfg->lock, flags); 266 - 267 - if (is_up && fpe_cfg->pmac_enabled) { 268 - /* VERIFY process requires pmac enabled when NIC comes up */ 269 - stmmac_fpe_configure(priv, false, true); 270 - 271 - /* New link => maybe new partner => new verification process */ 272 - stmmac_fpe_apply(priv); 273 - } else { 274 - /* No link => turn off EFPE */ 275 - stmmac_fpe_configure(priv, false, false); 276 - } 277 - 278 - spin_unlock_irqrestore(&fpe_cfg->lock, flags); 279 175 } 280 176 281 177 int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv)
-5
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
··· 9 9 #include <linux/types.h> 10 10 #include <linux/netdevice.h> 11 11 12 - #define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3 13 - #define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128 14 - 15 12 struct stmmac_priv; 16 13 17 - void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up); 18 14 bool stmmac_fpe_supported(struct stmmac_priv *priv); 19 15 void stmmac_fpe_init(struct stmmac_priv *priv); 20 - void stmmac_fpe_apply(struct stmmac_priv *priv); 21 16 void stmmac_fpe_irq_status(struct stmmac_priv *priv); 22 17 int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv); 23 18 void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size);
+4 -4
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 946 946 stmmac_set_eee_pls(priv, priv->hw, false); 947 947 948 948 if (stmmac_fpe_supported(priv)) 949 - stmmac_fpe_link_state_handle(priv, false); 949 + ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv, false); 950 950 } 951 951 952 952 static void stmmac_mac_link_up(struct phylink_config *config, ··· 1064 1064 stmmac_set_eee_pls(priv, priv->hw, true); 1065 1065 1066 1066 if (stmmac_fpe_supported(priv)) 1067 - stmmac_fpe_link_state_handle(priv, true); 1067 + ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv, true); 1068 1068 1069 1069 if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY) 1070 1070 stmmac_hwtstamp_correct_latency(priv, priv); ··· 4152 4152 stmmac_release_ptp(priv); 4153 4153 4154 4154 if (stmmac_fpe_supported(priv)) 4155 - timer_shutdown_sync(&priv->fpe_cfg.verify_timer); 4155 + ethtool_mmsv_stop(&priv->fpe_cfg.mmsv); 4156 4156 4157 4157 pm_runtime_put(priv->device); 4158 4158 ··· 7871 7871 rtnl_unlock(); 7872 7872 7873 7873 if (stmmac_fpe_supported(priv)) 7874 - timer_shutdown_sync(&priv->fpe_cfg.verify_timer); 7874 + ethtool_mmsv_stop(&priv->fpe_cfg.mmsv); 7875 7875 7876 7876 return 0; 7877 7877 }
+73
include/linux/ethtool.h
··· 17 17 #include <linux/compat.h> 18 18 #include <linux/if_ether.h> 19 19 #include <linux/netlink.h> 20 + #include <linux/timer_types.h> 20 21 #include <uapi/linux/ethtool.h> 21 22 #include <uapi/linux/net_tstamp.h> 23 + 24 + #define ETHTOOL_MM_MAX_VERIFY_TIME_MS 128 25 + #define ETHTOOL_MM_MAX_VERIFY_RETRIES 3 22 26 23 27 struct compat_ethtool_rx_flow_spec { 24 28 u32 flow_type; ··· 721 717 u64 MACMergeFragCountTx; 722 718 u64 MACMergeHoldCount; 723 719 }; 720 + 721 + enum ethtool_mmsv_event { 722 + ETHTOOL_MMSV_LP_SENT_VERIFY_MPACKET, 723 + ETHTOOL_MMSV_LD_SENT_VERIFY_MPACKET, 724 + ETHTOOL_MMSV_LP_SENT_RESPONSE_MPACKET, 725 + }; 726 + 727 + /* MAC Merge verification mPacket type */ 728 + enum ethtool_mpacket { 729 + ETHTOOL_MPACKET_VERIFY, 730 + ETHTOOL_MPACKET_RESPONSE, 731 + }; 732 + 733 + struct ethtool_mmsv; 734 + 735 + /** 736 + * struct ethtool_mmsv_ops - Operations for MAC Merge Software Verification 737 + * @configure_tx: Driver callback for the event where the preemptible TX 738 + * becomes active or inactive. Preemptible traffic 739 + * classes must be committed to hardware only while 740 + * preemptible TX is active. 741 + * @configure_pmac: Driver callback for the event where the pMAC state 742 + * changes as result of an administrative setting 743 + * (ethtool) or a call to ethtool_mmsv_link_state_handle(). 744 + * @send_mpacket: Driver-provided method for sending a Verify or a Response 745 + * mPacket. 746 + */ 747 + struct ethtool_mmsv_ops { 748 + void (*configure_tx)(struct ethtool_mmsv *mmsv, bool tx_active); 749 + void (*configure_pmac)(struct ethtool_mmsv *mmsv, bool pmac_enabled); 750 + void (*send_mpacket)(struct ethtool_mmsv *mmsv, enum ethtool_mpacket mpacket); 751 + }; 752 + 753 + /** 754 + * struct ethtool_mmsv - MAC Merge Software Verification 755 + * @ops: operations for MAC Merge Software Verification 756 + * @dev: pointer to net_device structure 757 + * @lock: serialize access to MAC Merge state between 758 + * ethtool requests and link state updates. 759 + * @status: current verification FSM state 760 + * @verify_timer: timer for verification in local TX direction 761 + * @verify_enabled: indicates if verification is enabled 762 + * @verify_retries: number of retries for verification 763 + * @pmac_enabled: indicates if the preemptible MAC is enabled 764 + * @verify_time: time for verification in milliseconds 765 + * @tx_enabled: indicates if transmission is enabled 766 + */ 767 + struct ethtool_mmsv { 768 + const struct ethtool_mmsv_ops *ops; 769 + struct net_device *dev; 770 + spinlock_t lock; 771 + enum ethtool_mm_verify_status status; 772 + struct timer_list verify_timer; 773 + bool verify_enabled; 774 + int verify_retries; 775 + bool pmac_enabled; 776 + u32 verify_time; 777 + bool tx_enabled; 778 + }; 779 + 780 + void ethtool_mmsv_stop(struct ethtool_mmsv *mmsv); 781 + void ethtool_mmsv_link_state_handle(struct ethtool_mmsv *mmsv, bool up); 782 + void ethtool_mmsv_event_handle(struct ethtool_mmsv *mmsv, 783 + enum ethtool_mmsv_event event); 784 + void ethtool_mmsv_get_mm(struct ethtool_mmsv *mmsv, 785 + struct ethtool_mm_state *state); 786 + void ethtool_mmsv_set_mm(struct ethtool_mmsv *mmsv, struct ethtool_mm_cfg *cfg); 787 + void ethtool_mmsv_init(struct ethtool_mmsv *mmsv, struct net_device *dev, 788 + const struct ethtool_mmsv_ops *ops); 724 789 725 790 /** 726 791 * struct ethtool_rxfh_param - RXFH (RSS) parameters
+278 -1
net/ethtool/mm.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Copyright 2022-2023 NXP 3 + * Copyright 2022-2025 NXP 4 + * Copyright 2024 Furong Xu <0x1207@gmail.com> 4 5 */ 5 6 #include "common.h" 6 7 #include "netlink.h" ··· 283 282 return supported; 284 283 } 285 284 EXPORT_SYMBOL_GPL(ethtool_dev_mm_supported); 285 + 286 + static void ethtool_mmsv_configure_tx(struct ethtool_mmsv *mmsv, 287 + bool tx_active) 288 + { 289 + if (mmsv->ops->configure_tx) 290 + mmsv->ops->configure_tx(mmsv, tx_active); 291 + } 292 + 293 + static void ethtool_mmsv_configure_pmac(struct ethtool_mmsv *mmsv, 294 + bool pmac_enabled) 295 + { 296 + if (mmsv->ops->configure_pmac) 297 + mmsv->ops->configure_pmac(mmsv, pmac_enabled); 298 + } 299 + 300 + static void ethtool_mmsv_send_mpacket(struct ethtool_mmsv *mmsv, 301 + enum ethtool_mpacket mpacket) 302 + { 303 + if (mmsv->ops->send_mpacket) 304 + mmsv->ops->send_mpacket(mmsv, mpacket); 305 + } 306 + 307 + /** 308 + * ethtool_mmsv_verify_timer - Timer for MAC Merge verification 309 + * @t: timer_list struct containing private info 310 + * 311 + * Verify the MAC Merge capability in the local TX direction, by 312 + * transmitting Verify mPackets up to 3 times. Wait until link 313 + * partner responds with a Response mPacket, otherwise fail. 314 + */ 315 + static void ethtool_mmsv_verify_timer(struct timer_list *t) 316 + { 317 + struct ethtool_mmsv *mmsv = from_timer(mmsv, t, verify_timer); 318 + unsigned long flags; 319 + bool rearm = false; 320 + 321 + spin_lock_irqsave(&mmsv->lock, flags); 322 + 323 + switch (mmsv->status) { 324 + case ETHTOOL_MM_VERIFY_STATUS_INITIAL: 325 + case ETHTOOL_MM_VERIFY_STATUS_VERIFYING: 326 + if (mmsv->verify_retries != 0) { 327 + ethtool_mmsv_send_mpacket(mmsv, ETHTOOL_MPACKET_VERIFY); 328 + rearm = true; 329 + } else { 330 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_FAILED; 331 + } 332 + 333 + mmsv->verify_retries--; 334 + break; 335 + 336 + case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: 337 + ethtool_mmsv_configure_tx(mmsv, true); 338 + break; 339 + 340 + default: 341 + break; 342 + } 343 + 344 + if (rearm) { 345 + mod_timer(&mmsv->verify_timer, 346 + jiffies + msecs_to_jiffies(mmsv->verify_time)); 347 + } 348 + 349 + spin_unlock_irqrestore(&mmsv->lock, flags); 350 + } 351 + 352 + static void ethtool_mmsv_verify_timer_arm(struct ethtool_mmsv *mmsv) 353 + { 354 + if (mmsv->pmac_enabled && mmsv->tx_enabled && mmsv->verify_enabled && 355 + mmsv->status != ETHTOOL_MM_VERIFY_STATUS_FAILED && 356 + mmsv->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) { 357 + timer_setup(&mmsv->verify_timer, ethtool_mmsv_verify_timer, 0); 358 + mod_timer(&mmsv->verify_timer, jiffies); 359 + } 360 + } 361 + 362 + static void ethtool_mmsv_apply(struct ethtool_mmsv *mmsv) 363 + { 364 + /* If verification is disabled, configure FPE right away. 365 + * Otherwise let the timer code do it. 366 + */ 367 + if (!mmsv->verify_enabled) { 368 + ethtool_mmsv_configure_pmac(mmsv, mmsv->pmac_enabled); 369 + ethtool_mmsv_configure_tx(mmsv, mmsv->tx_enabled); 370 + } else { 371 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; 372 + mmsv->verify_retries = ETHTOOL_MM_MAX_VERIFY_RETRIES; 373 + 374 + if (netif_running(mmsv->dev)) 375 + ethtool_mmsv_verify_timer_arm(mmsv); 376 + } 377 + } 378 + 379 + /** 380 + * ethtool_mmsv_stop() - Stop MAC Merge Software Verification 381 + * @mmsv: MAC Merge Software Verification state 382 + * 383 + * Drivers should call this method in a state where the hardware is 384 + * about to lose state, like ndo_stop() or suspend(), and turning off 385 + * MAC Merge features would be superfluous. Otherwise, prefer 386 + * ethtool_mmsv_link_state_handle() with up=false. 387 + */ 388 + void ethtool_mmsv_stop(struct ethtool_mmsv *mmsv) 389 + { 390 + timer_shutdown_sync(&mmsv->verify_timer); 391 + } 392 + EXPORT_SYMBOL_GPL(ethtool_mmsv_stop); 393 + 394 + /** 395 + * ethtool_mmsv_link_state_handle() - Inform MAC Merge Software Verification 396 + * of link state changes 397 + * @mmsv: MAC Merge Software Verification state 398 + * @up: True if device carrier is up and able to pass verification packets 399 + * 400 + * Calling context is expected to be from a task, interrupts enabled. 401 + */ 402 + void ethtool_mmsv_link_state_handle(struct ethtool_mmsv *mmsv, bool up) 403 + { 404 + unsigned long flags; 405 + 406 + ethtool_mmsv_stop(mmsv); 407 + 408 + spin_lock_irqsave(&mmsv->lock, flags); 409 + 410 + if (up && mmsv->pmac_enabled) { 411 + /* VERIFY process requires pMAC enabled when NIC comes up */ 412 + ethtool_mmsv_configure_pmac(mmsv, true); 413 + 414 + /* New link => maybe new partner => new verification process */ 415 + ethtool_mmsv_apply(mmsv); 416 + } else { 417 + /* Reset the reported verification state while the link is down */ 418 + if (mmsv->verify_enabled) 419 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; 420 + 421 + /* No link or pMAC not enabled */ 422 + ethtool_mmsv_configure_pmac(mmsv, false); 423 + ethtool_mmsv_configure_tx(mmsv, false); 424 + } 425 + 426 + spin_unlock_irqrestore(&mmsv->lock, flags); 427 + } 428 + EXPORT_SYMBOL_GPL(ethtool_mmsv_link_state_handle); 429 + 430 + /** 431 + * ethtool_mmsv_event_handle() - Inform MAC Merge Software Verification 432 + * of interrupt-based events 433 + * @mmsv: MAC Merge Software Verification state 434 + * @event: Event which took place (packet transmission or reception) 435 + * 436 + * Calling context expects to have interrupts disabled. 437 + */ 438 + void ethtool_mmsv_event_handle(struct ethtool_mmsv *mmsv, 439 + enum ethtool_mmsv_event event) 440 + { 441 + /* This is interrupt context, just spin_lock() */ 442 + spin_lock(&mmsv->lock); 443 + 444 + if (!mmsv->pmac_enabled) 445 + goto unlock; 446 + 447 + switch (event) { 448 + case ETHTOOL_MMSV_LP_SENT_VERIFY_MPACKET: 449 + /* Link partner has sent verify mPacket */ 450 + ethtool_mmsv_send_mpacket(mmsv, ETHTOOL_MPACKET_RESPONSE); 451 + break; 452 + case ETHTOOL_MMSV_LD_SENT_VERIFY_MPACKET: 453 + /* Local device has sent verify mPacket */ 454 + if (mmsv->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) 455 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; 456 + break; 457 + case ETHTOOL_MMSV_LP_SENT_RESPONSE_MPACKET: 458 + /* Link partner has sent response mPacket */ 459 + if (mmsv->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING) 460 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; 461 + break; 462 + } 463 + 464 + unlock: 465 + spin_unlock(&mmsv->lock); 466 + } 467 + EXPORT_SYMBOL_GPL(ethtool_mmsv_event_handle); 468 + 469 + static bool ethtool_mmsv_is_tx_active(struct ethtool_mmsv *mmsv) 470 + { 471 + /* TX is active if administratively enabled, and verification either 472 + * succeeded, or was administratively disabled. 473 + */ 474 + return mmsv->tx_enabled && 475 + (mmsv->status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED || 476 + mmsv->status == ETHTOOL_MM_VERIFY_STATUS_DISABLED); 477 + } 478 + 479 + /** 480 + * ethtool_mmsv_get_mm() - get_mm() hook for MAC Merge Software Verification 481 + * @mmsv: MAC Merge Software Verification state 482 + * @state: see struct ethtool_mm_state 483 + * 484 + * Drivers are expected to call this from their ethtool_ops :: get_mm() 485 + * method. 486 + */ 487 + void ethtool_mmsv_get_mm(struct ethtool_mmsv *mmsv, 488 + struct ethtool_mm_state *state) 489 + { 490 + unsigned long flags; 491 + 492 + spin_lock_irqsave(&mmsv->lock, flags); 493 + 494 + state->max_verify_time = ETHTOOL_MM_MAX_VERIFY_TIME_MS; 495 + state->verify_enabled = mmsv->verify_enabled; 496 + state->pmac_enabled = mmsv->pmac_enabled; 497 + state->verify_time = mmsv->verify_time; 498 + state->tx_enabled = mmsv->tx_enabled; 499 + state->verify_status = mmsv->status; 500 + state->tx_active = ethtool_mmsv_is_tx_active(mmsv); 501 + 502 + spin_unlock_irqrestore(&mmsv->lock, flags); 503 + } 504 + EXPORT_SYMBOL_GPL(ethtool_mmsv_get_mm); 505 + 506 + /** 507 + * ethtool_mmsv_set_mm() - set_mm() hook for MAC Merge Software Verification 508 + * @mmsv: MAC Merge Software Verification state 509 + * @cfg: see struct ethtool_mm_cfg 510 + * 511 + * Drivers are expected to call this from their ethtool_ops :: set_mm() 512 + * method. 513 + */ 514 + void ethtool_mmsv_set_mm(struct ethtool_mmsv *mmsv, struct ethtool_mm_cfg *cfg) 515 + { 516 + unsigned long flags; 517 + 518 + /* Wait for the verification that's currently in progress to finish */ 519 + ethtool_mmsv_stop(mmsv); 520 + 521 + spin_lock_irqsave(&mmsv->lock, flags); 522 + 523 + mmsv->verify_enabled = cfg->verify_enabled; 524 + mmsv->pmac_enabled = cfg->pmac_enabled; 525 + mmsv->verify_time = cfg->verify_time; 526 + mmsv->tx_enabled = cfg->tx_enabled; 527 + 528 + if (!cfg->verify_enabled) 529 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; 530 + 531 + ethtool_mmsv_apply(mmsv); 532 + 533 + spin_unlock_irqrestore(&mmsv->lock, flags); 534 + } 535 + EXPORT_SYMBOL_GPL(ethtool_mmsv_set_mm); 536 + 537 + /** 538 + * ethtool_mmsv_init() - Initialize MAC Merge Software Verification state 539 + * @mmsv: MAC Merge Software Verification state 540 + * @dev: Pointer to network interface 541 + * @ops: Methods for implementing the generic functionality 542 + * 543 + * The MAC Merge Software Verification is a timer- and event-based state 544 + * machine intended for network interfaces which lack a hardware-based 545 + * TX verification process (as per IEEE 802.3 clause 99.4.3). The timer 546 + * is managed by the core code, whereas events are supplied by the 547 + * driver explicitly calling one of the other API functions. 548 + */ 549 + void ethtool_mmsv_init(struct ethtool_mmsv *mmsv, struct net_device *dev, 550 + const struct ethtool_mmsv_ops *ops) 551 + { 552 + mmsv->ops = ops; 553 + mmsv->dev = dev; 554 + mmsv->verify_retries = ETHTOOL_MM_MAX_VERIFY_RETRIES; 555 + mmsv->verify_time = ETHTOOL_MM_MAX_VERIFY_TIME_MS; 556 + mmsv->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; 557 + timer_setup(&mmsv->verify_timer, ethtool_mmsv_verify_timer, 0); 558 + spin_lock_init(&mmsv->lock); 559 + } 560 + EXPORT_SYMBOL_GPL(ethtool_mmsv_init);