diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-22 15:58:00 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-22 15:58:00 -1000 |
| commit | 734bef548a96e8774d6eef5dfa2026c6edc4e80b (patch) | |
| tree | ce2520b2602ce3b82f9842490d21836f9838d441 /drivers/net/ethernet/intel | |
| parent | 864c07de0c7dcbca58b61625dfa2e461ae63b242 (diff) | |
| parent | 1a2c35c49cc7c6be860038b8442b52424a8f123c (diff) | |
| download | linux-next-stable.tar.gz linux-next-stable.zip | |
Merge tag 'net-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-nextstable
Pull networking updates from Paolo Abeni:
"This includes a significant number of low-priority fixes - especially
in the NIC drivers area - that we deferred from the last few RCs in
the previous cycle, which can't be easily outlined in the synopsis
below.
Core & protocols:
- Continue the work on removing rtnl_lock dependencies:
- per-netns ARP and ND neighbour tables, with the default settings
now configurable per netns (inheritance from init_net is
controlled by the new net.core.neigh_inherit_init_net sysctl)
- RCU-protected configuration and rtnl_lock-less fill_info() for
hsr, netkit, sit, vlan and vxlan devices
- per-netns device unregistration for ip tunnel and gre devices
- use the netdev instance lock instead of rtnl_lock when reading
speed and duplex via sysfs
- batch the flushing of uncached routes at device unregistration
time, relieving rtnl_lock contention on netns dismantle.
- Add hardware pacing offload support, admin-controlled via a new
rtnetlink attribute, with sch_fq integration (implemented in idpf).
- Re-segment BIG TCP GSO packets into GSO packets fitting the egress
device limits instead of plain MSS-sized segments, improving
throughput for mixed BIG TCP / non-BIG TCP paths by up to 70%.
- Generate RSS keys that spread flows over all the RX queues; the
previous random keys could leave some queues unused.
- Optimize the bridge VLAN forwarding paths: cache the port-VLAN in
fdb entries and consider only VLAN members when flooding, for ~10%
more Mpps in the fdb forwarding path.
- A few TCP/IP performance improvements aimed at efficient cache
usage and reducing contention.
- Add the TCP ROCCET congestion control, a CUBIC variant aimed at
avoiding bufferbloat in cellular networks.
- Continue the conversion of getsockopt callbacks to sockopt_t.
- Add an ethtool command to list the front-facing ports of an
interface, including SFP cages and modules, using the phy_port
representation.
- Enable BIG TCP support for bareudp tunnels.
- Remove the IPV6_ADDRFORM socket option and disallow buggy TCP state
transitions (listen() + shutdown() + connect() and connect() +
connect(AF_UNSPEC) + listen()).
- Remove most BUG_ON()s from core packet processing, replacing them
with error paths.
Wireless:
- Latency improvements, including lockless station get/dump and
beacon updates, plus RTNL reduction and locking cleanups.
- Infrastructure for non-station TX/RX with MLO.
- NAN (Wi-Fi Aware) Instant Communication support and other NAN
improvements.
- Control frame Integrity Protocol (CIP) and protected TWT support.
- Improvements for AP regulatory checks.
Netfilter:
- Disable br_netfilter in user namespaces and schedule it for removal
in 2027.
- Restrict the raw table in nft_compat to the specific family, hook
and priority.
- Prepare the flowtable for mixed IPv4-over-IPv6 tunneling (and vice
versa).
- Use GFP_KERNEL_ACCOUNT for most netfilter allocations, for better
integration with memcg.
- Allow discovering conntrack zone filtering support in ctnetlink
dumps, and fix nfnetlink_hook handling of large dumps.
Deletions:
- Move the LLC type 2 sockets out of tree. There are no known users
and the code attracts a never-ending stream of LLM-driven fixes.
Device drivers:
- New drivers:
- Meta Platforms NIC (mpnic), the second-generation NIC from Meta
- initial skeleton of the Nebula-matrix NICs driver (nbl)
- X-Powers AC200/AC300 Fast Ethernet PHYs
- Ethernet high-speed NICs:
- Intel:
- i40e: XDP metadata support for RX hash and VLAN tag
- ice: expose the E825 TSPLL state via the DPLL subsystem
- nVidia/Mellanox:
- move the data direct infrastructure from IB to core, in
preparation for netdev support.
- reduce the memory used per offloaded TC rule
- Meta (fbnic):
- support large io_uring zero-copy RX buffers
- Microsoft vNIC (mana):
- add BQL support
- Ethernet NICs consumer, and embedded:
- Airoha:
- LRO offload support
- Cadence (macb):
- context swapping for ringparam and MTU changes, avoiding
buffer loss under memory pressure
- Mucse (rnpgbe):
- TX/RX and link status support
- NXP (enetc):
- SR-IOV improvements and VF support for ENETC v4
- Qualcomm (ppe):
- IPQ5424 support
- Realtek PCI (r8169):
- phylink support
- RSS support for RTL8127
- Renesas (ravb):
- gPTP support for R-Car Gen4
- Synopsys (stmmac):
- XDP multi-buffer support on the TX side
- tc mqprio hw queue priority offload
- support for RK3568 SGMII, Allwinner H616 EMAC1, UltraRISC
DP1000 and Qualcomm sa8255p
- Ethernet switches:
- Mediatek (mt7530):
- fast age and change conduit support
- Microchip (ksz):
- support for KSZ8995XA/KS8995XA
- Microchip (lan966x):
- PCIe FDMA support, ~20x throughput increase in PCIe endpoint
- Microchip (sparx5):
- Time Aware Shaper (taprio) offload
- Motorcomm (yt921x):
- LED and SerDes PCS support
- Realtek (rtl8365mb):
- EEE support
- Ethernet PHYs:
- Broadcom:
- enable jumbo frames on BCM54xx
- Realtek:
- support for RTL8261CE_CG and RTL8261D_VM
- MDIO support for RTL838x and RTL839x
- WiFi drivers:
- Broadcom (brcmfmac):
- FT/OKC roaming offload
- Intel (iwlwifi):
- UHR sniffer support
- support for newer UEFI/BIOS tables
- MediaTek (mt76):
- mt7925 NAN improvements
- offchannel/scan improvements and MLO fixes
- Morse Micro (mm81x):
- monitor mode support
- Qualcomm (ath12k):
- IPQ5332 platform infrastructure
- Realtek (rtw88):
- RTL8723BS support
- SDIO TX performance improvements
- Realtek (rtw89):
- P2P_DEVICE support
- BT-coex updates for RTL8922D
- Bluetooth:
- move H:4 reassembly into the Bluetooth core
- add generic support for vendor packets
- MGMT: add security level changed event
- Bluetooth drivers:
- btusb: support Bulk Serialization Mode
- Intel: support Draco and Titan Lake, allow unsigned firmware
- Mediatek: MT7928 support
- Qualcomm: QCC2072 support
- Broadcom: Synaptics 4384 support"
* tag 'net-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2126 commits)
Bluetooth: btusb: disable by default Qualcomm multi-subsystem
tipc: fix broadcast sender hang on last acker departure
tipc: fix use-after-free of broadcast reception link at node release
r8169: clear TX LPI on RTL8168h at link up after phylink conversion
tun: Require CAP_NET_ADMIN to attach to an ownerless device
net/sched/sch_cake: drop dead nla_nest_end() error check
net/sched/sch_cake: widen buffer_used to u64
net/sched/sch_cake: reduce parent backlog when clearing a tin
net/sched/sch_cake: serialize reconfiguration with the datapath
tg3: Add Datto SIRIS 5 1U Server to restart AER quirk table
net/mlx5e: Stop asserting for RTNL when closing channels
net: shrink the payload-only part of skb dataref to one bit
net: wwan: iosm: validate msg_head before indexing msg_ring
net: bgmac: rate limit RX error messages
selftests: net: veth: test XDP_TX to a peer with GRO enabled
veth: schedule the peer's NAPI after XDP_TX when only GRO is enabled
pppoe: delete session hash entries by pointer match
net: lan969x: don't disable hardirqs in fdma tx clear
net: sparx5/lan969x: do not clobber the PSFP cycle timer update period
net: lan969x: fix DSM calendar for empty taxis
...
Diffstat (limited to 'drivers/net/ethernet/intel')
43 files changed, 1313 insertions, 445 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index c282f65199e4..6f85dab5c55c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2118,7 +2118,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter) static int e1000_request_msix(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int err = 0, vector = 0; + int err = 0, vector = 0, i; if (strlen(netdev->name) < (IFNAMSIZ - 5)) snprintf(adapter->rx_ring->name, @@ -2130,7 +2130,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) e1000_intr_msix_rx, 0, adapter->rx_ring->name, netdev); if (err) - return err; + goto err_free; adapter->rx_ring->itr_register = adapter->hw.hw_addr + E1000_EITR_82574(vector); adapter->rx_ring->itr_val = adapter->itr; @@ -2146,7 +2146,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) e1000_intr_msix_tx, 0, adapter->tx_ring->name, netdev); if (err) - return err; + goto err_free; adapter->tx_ring->itr_register = adapter->hw.hw_addr + E1000_EITR_82574(vector); adapter->tx_ring->itr_val = adapter->itr; @@ -2155,11 +2155,16 @@ static int e1000_request_msix(struct e1000_adapter *adapter) err = request_irq(adapter->msix_entries[vector].vector, e1000_msix_other, 0, netdev->name, netdev); if (err) - return err; + goto err_free; e1000_configure_msix(adapter); return 0; + +err_free: + for (i = vector - 1; i >= 0; i--) + free_irq(adapter->msix_entries[i].vector, netdev); + return err; } /** @@ -7457,6 +7462,12 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mmio_len = pci_resource_len(pdev, 0); err = -EIO; + /* Smallest BAR0 that covers every register the driver accesses */ + if (mmio_len < SZ_64K) { + dev_err(&pdev->dev, "MMIO len is too small\n"); + goto err_ioremap; + } + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); if (!adapter->hw.hw_addr) goto err_ioremap; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index c86701be4364..669a02c6415c 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -561,13 +561,8 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* The minimum packet size for a single buffer is 17B so pad the skb * in order to meet this minimum size requirement. */ - if (unlikely(skb->len < 17)) { - int pad_len = 17 - skb->len; - - if (skb_pad(skb, pad_len)) - return NETDEV_TX_OK; - __skb_put(skb, pad_len); - } + if (skb_put_padto(skb, 17)) + return NETDEV_TX_OK; if (r_idx >= num_tx_queues) r_idx %= num_tx_queues; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index f5b4d062709a..afe939f8f4ef 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -2111,8 +2111,6 @@ static int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); - if (err) - err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "DMA configuration failed: %d\n", err); diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 8dadfef2c09f..026b35e5a000 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -676,7 +676,7 @@ int i40e_pf_reset(struct i40e_hw *hw) grst_del = FIELD_GET(I40E_GLGEN_RSTCTL_GRSTDEL_MASK, rd32(hw, I40E_GLGEN_RSTCTL)); - /* It can take upto 15 secs for GRST steady state. + /* It can take up to 15 secs for GRST steady state. * Bump it to 16 secs max to be safe. */ grst_del = grst_del * 20; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 3da9ec49cc74..6a992df06fa1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2614,7 +2614,7 @@ static u64 i40e_eeprom_test(struct net_device *netdev, u64 *data) netif_info(pf, hw, netdev, "eeprom test\n"); *data = i40e_diag_eeprom_test(&pf->hw); - /* forcebly clear the NVM Update state machine */ + /* forcibly clear the NVM Update state machine */ pf->hw.nvmupd_state = I40E_NVMUPD_STATE_INIT; return *data; @@ -5263,10 +5263,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) test_bit(priv_flag->bitno, orig_flags) != new_val) return -EOPNOTSUPP; - if (new_val) - set_bit(priv_flag->bitno, new_flags); - else - clear_bit(priv_flag->bitno, new_flags); + assign_bit(priv_flag->bitno, new_flags, new_val); } if (pf->hw.pf_id != 0) @@ -5284,10 +5281,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) test_bit(priv_flag->bitno, orig_flags) != new_val) return -EOPNOTSUPP; - if (new_val) - set_bit(priv_flag->bitno, new_flags); - else - clear_bit(priv_flag->bitno, new_flags); + assign_bit(priv_flag->bitno, new_flags, new_val); } flags_complete: diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 0cd0e5597c90..abbc71e815ae 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4,6 +4,7 @@ #include <generated/utsrelease.h> #include <linux/crash_dump.h> #include <linux/net/intel/libie/pctype.h> +#include <linux/net/intel/libie/rx.h> #include <linux/if_bridge.h> #include <linux/if_macvlan.h> #include <linux/module.h> @@ -2411,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name, if (fcnt != num_add) { if (vsi->type == I40E_VSI_MAIN) { - set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state); - dev_warn(&vsi->back->pdev->dev, - "Error %s adding RX filters on %s, promiscuous mode forced on\n", - libie_aq_str(aq_status), vsi_name); + if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, + vsi->state)) { + dev_warn(&vsi->back->pdev->dev, + "Error %s adding RX filters on %s, promiscuous mode forced on\n", + libie_aq_str(aq_status), vsi_name); + } } else if (vsi->type == I40E_VSI_SRIOV || vsi->type == I40E_VSI_VMDQ1 || vsi->type == I40E_VSI_VMDQ2) { @@ -2464,10 +2467,11 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name, } if (aq_ret) { - set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state); - dev_warn(&vsi->back->pdev->dev, - "Error %s, forcing overflow promiscuous on %s\n", - libie_aq_str(hw->aq.asq_last_status), vsi_name); + if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state)) { + dev_warn(&vsi->back->pdev->dev, + "Error %s, forcing overflow promiscuous on %s\n", + libie_aq_str(hw->aq.asq_last_status), vsi_name); + } } return aq_ret; @@ -3622,7 +3626,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) } skip: - xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq); + xdp_init_buff(&ring->xdp_ctx.xdp, xdp_frame_sz, &ring->xdp_rxq); rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len, BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT)); @@ -13582,6 +13586,53 @@ static int i40e_xdp(struct net_device *dev, } } +static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) +{ + const struct i40e_xdp_buff *ctx = (const void *)_ctx; + const union i40e_rx_desc *desc = ctx->desc; + struct libeth_rx_pt rx_ptype; + u8 raw_rx_ptype; + u64 status; + + status = le64_to_cpu(desc->wb.qword1.status_error_len); + raw_rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, status); + rx_ptype = libie_rx_pt_parse(raw_rx_ptype); + + if (!libeth_rx_pt_has_hash(ctx->xdp.rxq->dev, rx_ptype) || + FIELD_GET(I40E_RX_DESC_STATUS_FLTSTAT_MASK, status) != + I40E_RX_DESC_FLTSTAT_RSS_HASH) + return -ENODATA; + + *hash = le32_to_cpu(desc->wb.qword0.hi_dword.rss); + *rss_type = rx_ptype.hash_type; + + return 0; +} + +static int i40e_xdp_rx_vlan_tag(const struct xdp_md *_ctx, __be16 *vlan_proto, + u16 *vlan_tci) +{ + const struct i40e_xdp_buff *ctx = (const void *)_ctx; + const union i40e_rx_desc *desc = ctx->desc; + u64 status; + + status = le64_to_cpu(desc->wb.qword1.status_error_len); + + if (!(status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT))) + return -ENODATA; + + *vlan_proto = cpu_to_be16(ETH_P_8021Q); + *vlan_tci = le16_to_cpu(desc->wb.qword0.lo_dword.l2tag1); + + return 0; +} + +static const struct xdp_metadata_ops i40e_xdp_metadata_ops = { + .xmo_rx_hash = i40e_xdp_rx_hash, + .xmo_rx_vlan_tag = i40e_xdp_rx_vlan_tag, +}; + static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -13784,6 +13835,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); netdev->netdev_ops = &i40e_netdev_ops; + netdev->xdp_metadata_ops = &i40e_xdp_metadata_ops; netdev->watchdog_timeo = 5 * HZ; i40e_set_ethtool_ops(netdev); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index ef5e657816f0..7f68adb5109b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2438,10 +2438,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget, unsigned int *rx_cleaned) { unsigned int total_rx_bytes = 0, total_rx_packets = 0; + struct i40e_xdp_buff *xdp_ctx = &rx_ring->xdp_ctx; u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); u16 clean_threshold = rx_ring->count / 2; unsigned int offset = rx_ring->rx_offset; - struct xdp_buff *xdp = &rx_ring->xdp; + struct xdp_buff *xdp = &xdp_ctx->xdp; unsigned int xdp_xmit = 0; struct bpf_prog *xdp_prog; bool failure = false; @@ -2530,6 +2531,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget, if (neop) continue; + xdp_ctx->desc = rx_desc; + xdp_res = i40e_run_xdp(rx_ring, xdp, xdp_prog); if (xdp_res) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 1e5fd63d47f4..bb741ff3e5f2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -283,6 +283,11 @@ struct i40e_rx_buffer { __u32 page_count; }; +struct i40e_xdp_buff { + struct xdp_buff xdp; + const union i40e_rx_desc *desc; +}; + struct i40e_queue_stats { u64 packets; u64 bytes; @@ -345,7 +350,7 @@ struct i40e_ring { * and to resume packet building for this ring in the next call to * i40e_clean_rx_ring_irq(). */ - struct xdp_buff xdp; + struct i40e_xdp_buff xdp_ctx; /* Next descriptor to be processed; next_to_clean is updated only on * processing EOP descriptor diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index ed8bbdb586da..16a65c6e5153 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -4,6 +4,7 @@ #ifndef _I40E_TYPE_H_ #define _I40E_TYPE_H_ +#include <linux/bits.h> #include <uapi/linux/if_ether.h> #include "i40e_adminq.h" #include "i40e_hmc.h" @@ -699,6 +700,10 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; +#define I40E_RX_DESC_STATUS_FLTSTAT_MASK \ + GENMASK_ULL(I40E_RX_DESC_STATUS_FLTSTAT_SHIFT + 1, \ + I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) + #define I40E_RXD_QW1_STATUS_SHIFT 0 #define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index c6732a24b640..74b6c0ed8480 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1158,10 +1158,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf) pf->queues_left -= total_queue_pairs - I40E_DEFAULT_QUEUES_PER_VF; - if (vf->trusted) - set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); - else - clear_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); + assign_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps, vf->trusted); /* store the total qps number for the runtime * VF req validation diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 9f47388eaba5..51a05ce4c7ce 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -246,6 +246,8 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) u32 nb_buffs, i; dma_addr_t dma; + XSK_CHECK_PRIV_TYPE(struct i40e_xdp_buff); + rx_desc = I40E_RX_DESC(rx_ring, ntu); xdp = i40e_rx_bi(rx_ring, ntu); @@ -396,6 +398,14 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring, WARN_ON_ONCE(1); } +static struct i40e_xdp_buff *xsk_buff_to_i40e_ctx(struct xdp_buff *xdp) +{ + /* xdp_buff pointer used by ZC code path is allocated as xdp_buff_xsk. + * i40e_xdp_buff private fields overlap with xdp_buff_xsk->cb. + */ + return (struct i40e_xdp_buff *)xdp; +} + /** * i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring * @rx_ring: Rx ring @@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) if (i40e_is_non_eop(rx_ring, rx_desc)) continue; + xsk_buff_to_i40e_ctx(first)->desc = rx_desc; + xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog); i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets, &rx_bytes, xdp_res, &failure); diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index c30abf17cf5d..8982cf75466f 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -2396,12 +2396,8 @@ netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* hardware can't handle really short frames, hardware padding works * beyond this point */ - if (unlikely(skb->len < IAVF_MIN_TX_LEN)) { - if (skb_pad(skb, IAVF_MIN_TX_LEN - skb->len)) - return NETDEV_TX_OK; - skb->len = IAVF_MIN_TX_LEN; - skb_set_tail_pointer(skb, IAVF_MIN_TX_LEN); - } + if (skb_put_padto(skb, IAVF_MIN_TX_LEN)) + return NETDEV_TX_OK; return iavf_xmit_frame_ring(skb, tx_ring); } diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 95fd0c49800f..a952bacb7ec7 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -24,7 +24,7 @@ ice-y := ice_main.o \ ice_vsi_vlan_ops.o \ ice_vsi_vlan_lib.o \ ice_fdir.o \ - ice_ethtool_fdir.o \ + ice_ethtool_ntuple.o \ ice_vlan_mode.o \ ice_flex_pipe.o \ ice_flow.o \ diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index db3c7015c56c..432da05c48c0 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -302,7 +302,6 @@ enum ice_pf_state { ICE_CFG_BUSY, ICE_SERVICE_SCHED, ICE_SERVICE_DIS, - ICE_FD_FLUSH_REQ, ICE_OICR_INTR_DIS, /* Global OICR interrupt disabled */ ICE_MDD_VF_PRINT_PENDING, /* set when MDD event handle */ ICE_VF_RESETS_DISABLED, /* disable resets during ice_remove */ @@ -328,6 +327,8 @@ enum ice_vsi_state { struct ice_vsi_stats { struct ice_ring_stats **tx_ring_stats; /* Tx ring stats array */ struct ice_ring_stats **rx_ring_stats; /* Rx ring stats array */ + u16 tx_ring_stats_len; /* Length of the Tx ring stats array */ + u16 rx_ring_stats_len; /* Length of the Rx ring stats array */ }; /* struct that defines a VSI, associated with a dev */ @@ -401,9 +402,11 @@ struct ice_vsi { u8 rx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ u16 *txq_map; /* index in pf->avail_txqs */ u16 *rxq_map; /* index in pf->avail_rxqs */ - u16 alloc_txq; /* Allocated Tx queues */ + struct_group_tagged(ice_vsi_alloc_queues_params, alloc_txq_rxq, + u16 alloc_txq; /* Allocated Tx queues */ + u16 alloc_rxq; /* Allocated Rx queues */ + ); u16 num_txq; /* Used Tx queues */ - u16 alloc_rxq; /* Allocated Rx queues */ u16 num_rxq; /* Used Rx queues */ u16 req_txq; /* User requested Tx queues */ u16 req_rxq; /* User requested Rx queues */ @@ -1018,11 +1021,11 @@ void ice_deinit_rdma(struct ice_pf *pf); bool ice_is_wol_supported(struct ice_hw *hw); void ice_fdir_del_all_fltrs(struct ice_vsi *vsi); int -ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add, +ice_fdir_write_fltr(struct ice_pf *pf, struct ice_ntuple_fltr *input, bool add, bool is_tun); void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena); -int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd); -int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd); +int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd); +int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd); int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd); int ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd, @@ -1105,7 +1108,7 @@ extern const struct xdp_metadata_ops ice_xdp_md_ops; * ice_is_dual - Check if given config is multi-NAC * @hw: pointer to HW structure * - * Return: true if the device is running in mutli-NAC (Network + * Return: true if the device is running in multi-NAC (Network * Acceleration Complex) configuration variant, false otherwise * (always false for non-E825 devices). */ diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c index 53b6e2b09eb9..e0335f5e18fe 100644 --- a/drivers/net/ethernet/intel/ice/ice_arfs.c +++ b/drivers/net/ethernet/intel/ice/ice_arfs.c @@ -302,7 +302,7 @@ ice_arfs_build_entry(struct ice_vsi *vsi, const struct flow_keys *fk, u16 rxq_idx, u32 flow_id) { struct ice_arfs_entry *arfs_entry; - struct ice_fdir_fltr *fltr_info; + struct ice_ntuple_fltr *fltr_info; u8 ip_proto; arfs_entry = devm_kzalloc(ice_pf_to_dev(vsi->back), @@ -392,8 +392,8 @@ ice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto) * * false - fltr_info and fk refer to different flows. */ static bool -ice_arfs_cmp(const struct ice_fdir_fltr *fltr_info, const struct flow_keys *fk, - __be16 n_proto, u8 ip_proto) +ice_arfs_cmp(const struct ice_ntuple_fltr *fltr_info, + const struct flow_keys *fk, __be16 n_proto, u8 ip_proto) { /* Determine if the filter is for IPv4 or IPv6 based on flow_type, * which is one of ICE_FLTR_PTYPE_NONF_IPV{4,6}_{TCP,UDP}. @@ -485,7 +485,7 @@ ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb, spin_lock_bh(&vsi->arfs_lock); hlist_for_each_entry(arfs_entry, &vsi->arfs_fltr_list[idx], list_entry) { - struct ice_fdir_fltr *fltr_info; + struct ice_ntuple_fltr *fltr_info; /* keep searching for the already existing arfs_entry flow */ if (arfs_entry->flow_id != flow_id) diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.h b/drivers/net/ethernet/intel/ice/ice_arfs.h index 9706293128c3..7393254b7e0a 100644 --- a/drivers/net/ethernet/intel/ice/ice_arfs.h +++ b/drivers/net/ethernet/intel/ice/ice_arfs.h @@ -13,7 +13,7 @@ enum ice_arfs_fltr_state { }; struct ice_arfs_entry { - struct ice_fdir_fltr fltr_info; + struct ice_ntuple_fltr fltr_info; struct hlist_node list_entry; u64 time_activated; /* only valid for UDP flows */ u32 flow_id; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c index a10c1c8d8697..bb5cc0a2ba69 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c @@ -872,7 +872,7 @@ static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app) int ret = 0; if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) { - netdev_err(netdev, "can't delete DSCP netlink app when FW DCB agent is active\n"); + netdev_dbg(netdev, "can't delete DSCP netlink app when FW DCB agent is active\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 85a74cd6ea1f..ade1fb3dd067 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -22,6 +22,8 @@ #define E825_RCLK_PARENT_0_PIN_IDX 0 #define E825_RCLK_PARENT_1_PIN_IDX 1 +#define E825_DPLL_TSPLL_BASE_IDX 0 +#define E825_DPLL_TXCLK_BASE_IDX 1 #define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \ (ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx)) @@ -84,6 +86,7 @@ static const char * const ice_dpll_sw_pin_sma[] = { "SMA1", "SMA2" }; static const char * const ice_dpll_sw_pin_ufl[] = { "U.FL1", "U.FL2" }; static const char * const ice_dpll_ext_eref_pin = "EXT_EREF0"; static const char * const ice_dpll_fwnode_ext_synce = "clk_ref_synce"; +static const char * const ice_dpll_fwnode_time_ref = "time_ref"; static const struct dpll_pin_frequency ice_esync_range[] = { DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ), @@ -2814,6 +2817,160 @@ static const struct dpll_pin_ops ice_dpll_txclk_ops = { .direction_get = ice_dpll_input_direction, }; +/** + * ice_dpll_tspll_lock_status_get - derive TSPLL state for dpll subsystem + * @pf: board private structure + * @use_cached: if true, read lock state from pf->ptp.tspll_locked (maintained + * by the PTP periodic worker); if false, query hardware directly + * + * If TIME_REF is not selected, TSPLL is treated as unlocked from the dpll + * subsystem perspective, regardless of raw lock bit. + * + * Return: TSPLL lock status + */ +static enum dpll_lock_status +ice_dpll_tspll_lock_status_get(struct ice_pf *pf, bool use_cached) +{ + enum ice_clk_src clk_src; + bool locked; + + if (ice_tspll_get_clk_src(&pf->hw, &clk_src) || + clk_src != ICE_CLK_SRC_TIME_REF) + return DPLL_LOCK_STATUS_UNLOCKED; + + if (use_cached) { + locked = READ_ONCE(pf->ptp.tspll_locked); + } else { + bool lock_lost; + + if (ice_tspll_lost_lock_e825c(&pf->hw, &lock_lost)) + return DPLL_LOCK_STATUS_UNLOCKED; + locked = !lock_lost; + } + return locked ? DPLL_LOCK_STATUS_LOCKED : DPLL_LOCK_STATUS_UNLOCKED; +} + +/** + * ice_dpll_tspll_state_on_dpll_get - get TIME_REF pin state on TSPLL DPLL + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: on success holds pin state on parent dpll + * @extack: error reporting + * + * Dpll subsystem callback. Returns CONNECTED if the TSPLL is using + * TIME_REF as its clock source, DISCONNECTED otherwise. + * + * Return: + * * 0 - success + * * negative - failed to read clock source + */ +static int +ice_dpll_tspll_state_on_dpll_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + enum ice_clk_src clk_src; + int err; + + if (ice_dpll_is_reset(p->pf, extack)) + return -EBUSY; + + err = ice_tspll_get_clk_src(&p->pf->hw, &clk_src); + if (err) + return err; + + *state = clk_src == ICE_CLK_SRC_TIME_REF ? DPLL_PIN_STATE_CONNECTED : + DPLL_PIN_STATE_DISCONNECTED; + return 0; +} + +/** + * ice_dpll_tspll_state_on_dpll_set - set TIME_REF pin state on TSPLL DPLL + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: requested state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Enables (CONNECTED) or disables (DISCONNECTED) + * the TIME_REF signal as the TSPLL clock source. Selects TCXO when disabled. + * + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_tspll_state_on_dpll_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; + enum ice_clk_src clk_src; + bool changed = false; + struct ice_dpll *tp; + int ret; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + if (state != DPLL_PIN_STATE_CONNECTED && + state != DPLL_PIN_STATE_DISCONNECTED) { + NL_SET_ERR_MSG(extack, + "unsupported pin state for TSPLL reference clock"); + return -EINVAL; + } + + clk_src = (state == DPLL_PIN_STATE_CONNECTED) ? ICE_CLK_SRC_TIME_REF : + ICE_CLK_SRC_TCXO; + tp = &pf->dplls.tspll; + /* Serialize multi-register TSPLL reconfiguration with restart path. */ + mutex_lock(&pf->dplls.lock); + ret = ice_tspll_set_cfg(&pf->hw, ICE_TSPLL_FREQ_156_250, clk_src); + if (!ret || ret == -EAGAIN) { + enum dpll_lock_status new_state; + + new_state = ice_dpll_tspll_lock_status_get(pf, false); + + /* Sync the cached lock state to what we just observed from HW + * so ice_dpll_periodic_work_e825() (cached path) does not emit + * a spurious UNLOCKED notification between now and the next + * PTP monitor tick. + */ + WRITE_ONCE(pf->ptp.tspll_locked, + new_state == DPLL_LOCK_STATUS_LOCKED); + + if (tp->prev_dpll_state != new_state) { + tp->dpll_state = new_state; + tp->prev_dpll_state = new_state; + changed = true; + } + } + mutex_unlock(&pf->dplls.lock); + if (changed) + __dpll_device_change_ntf(tp->dpll); + /* TSPLL reconfiguration may complete before lock is reacquired. + * PTP periodic monitoring tracks and restores the final lock state. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +static const struct dpll_pin_ops ice_dpll_tspll_in_ops = { + .state_on_dpll_set = ice_dpll_tspll_state_on_dpll_set, + .state_on_dpll_get = ice_dpll_tspll_state_on_dpll_get, + .direction_get = ice_dpll_input_direction, +}; + static const struct dpll_pin_ops ice_dpll_pin_sma_ops = { .state_on_dpll_set = ice_dpll_sma_pin_state_set, .state_on_dpll_get = ice_dpll_sw_pin_state_get, @@ -2903,6 +3060,68 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) } /** + * ice_generate_dpll_clock_id - generate clock_id for a specific dpll device + * @pf: board private structure + * @d: dpll device context + * @type: dpll type being registered + * + * For E825 generic DPLLs, use per-interface permanent MAC as the clock_id + * basis so userspace can unambiguously map DPLL devices to interfaces. + * TX-CLK keeps plain MAC-derived ID, while TSPLL uses the same basis with + * a dedicated tag bit to remain distinct on source-timer owner PFs. + * Other DPLL objects keep board-level DSN-derived clock_id. + * + * Return: generated clock id for a dpll device + */ +static u64 ice_generate_dpll_clock_id(struct ice_pf *pf, struct ice_dpll *d, + enum dpll_type type) +{ + struct ice_hw *hw = &pf->hw; + u64 mac_clock_id; + + if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 && + type == DPLL_TYPE_GENERIC && + hw->port_info && + is_valid_ether_addr(hw->port_info->mac.perm_addr)) { + mac_clock_id = ether_addr_to_u64(hw->port_info->mac.perm_addr); + + if (d->dpll_idx >= E825_DPLL_TXCLK_BASE_IDX) + return mac_clock_id; + + if (d->dpll_idx == E825_DPLL_TSPLL_BASE_IDX) + return mac_clock_id | BIT_ULL(63); + } + + return pf->dplls.clock_id; +} + +/** + * ice_dpll_is_own_dpll_clock_id - check if clock_id belongs to this pf's DPLLs + * @pf: board private structure + * @clock_id: clock_id from a DPLL notification + * + * Match info->src_clock_id from a DPLL pin notification against any DPLL + * device this PF has registered. Used to suppress self-notifications + * generated as a side effect of our own dpll_pin_register() and + * dpll_pin_unregister() calls on the fwnode-backed SYNCE and TIME_REF pins, + * whose DPLLs (TXC and TSPLL) use MAC-derived clock_ids on E825. + * + * Return: true if clock_id matches one of this PF's registered DPLL devices. + */ +static bool ice_dpll_is_own_dpll_clock_id(struct ice_pf *pf, u64 clock_id) +{ + if (clock_id == pf->dplls.clock_id) + return true; + if (pf->hw.mac_type != ICE_MAC_GENERIC_3K_E825) + return false; + if (clock_id == ice_generate_dpll_clock_id(pf, &pf->dplls.txc, + DPLL_TYPE_GENERIC)) + return true; + return clock_id == ice_generate_dpll_clock_id(pf, &pf->dplls.tspll, + DPLL_TYPE_GENERIC); +} + +/** * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers * @dplls: pointer to dplls struct * @pin: the dpll_pin that changed @@ -3135,11 +3354,43 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) } /** + * ice_dpll_periodic_work_e825 - TSPLL DPLL periodic update for E825 + * @pf: board private structure + * + * Publish TSPLL lock status to the dpll subsystem. The PTP periodic worker + * owns TSPLL lock polling and recovery; this function consumes the cached + * result for dpll notifications. + * + * Context: Must be called without pf->dplls.lock held. + */ +static void ice_dpll_periodic_work_e825(struct ice_pf *pf) +{ + struct ice_dpll *tp = &pf->dplls.tspll; + enum dpll_lock_status new_state; + bool changed = false; + + mutex_lock(&pf->dplls.lock); + new_state = ice_dpll_tspll_lock_status_get(pf, true); + + if (tp->prev_dpll_state != new_state) { + tp->dpll_state = new_state; + tp->prev_dpll_state = new_state; + changed = true; + } + mutex_unlock(&pf->dplls.lock); + if (changed) + dpll_device_change_ntf(tp->dpll); +} + +/** * ice_dpll_periodic_work - DPLLs periodic worker * @work: pointer to kthread_work structure * - * DPLLs periodic worker is responsible for polling state of dpll. - * Context: Holds pf->dplls.lock + * Periodic worker responsible for polling DPLL state. On E810 devices it + * polls the EEC and PPS DPLLs. On E825 devices, when this PF owns the + * source timer, it publishes TSPLL lock status to the dpll subsystem. + * + * Context: Acquires and releases pf->dplls.lock */ static void ice_dpll_periodic_work(struct kthread_work *work) { @@ -3147,38 +3398,43 @@ static void ice_dpll_periodic_work(struct kthread_work *work) struct ice_pf *pf = container_of(d, struct ice_pf, dplls); struct ice_dpll *de = &pf->dplls.eec; struct ice_dpll *dp = &pf->dplls.pps; - u32 phase_offset_ntf = 0; + u32 ntf_mask = 0; int ret = 0; if (ice_is_reset_in_progress(pf->state)) goto resched; - mutex_lock(&pf->dplls.lock); - d->periodic_counter++; - ret = ice_dpll_update_state(pf, de, false); - if (!ret) - ret = ice_dpll_update_state(pf, dp, false); - if (!ret && dp->phase_offset_monitor_period && - d->periodic_counter % dp->phase_offset_monitor_period == 0) - ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf); - if (ret) { - /* EBUSY is expected during reset recovery */ - if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY) - d->cgu_state_acq_err_num++; - /* stop rescheduling this worker */ - if (d->cgu_state_acq_err_num > - ICE_CGU_STATE_ACQ_ERR_THRESHOLD) { - dev_err(ice_pf_to_dev(pf), - "EEC/PPS DPLLs periodic work disabled\n"); - mutex_unlock(&pf->dplls.lock); - return; + + if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) { + ice_dpll_periodic_work_e825(pf); + } else { + mutex_lock(&pf->dplls.lock); + d->periodic_counter++; + ret = ice_dpll_update_state(pf, de, false); + if (!ret) + ret = ice_dpll_update_state(pf, dp, false); + if (!ret && dp->phase_offset_monitor_period && + d->periodic_counter % dp->phase_offset_monitor_period == 0) + ret = ice_dpll_pps_update_phase_offsets(pf, &ntf_mask); + if (ret) { + /* EBUSY is expected during reset recovery */ + if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY) + d->cgu_state_acq_err_num++; + /* stop rescheduling this worker */ + if (d->cgu_state_acq_err_num > + ICE_CGU_STATE_ACQ_ERR_THRESHOLD) { + dev_err(ice_pf_to_dev(pf), + "EEC/PPS DPLLs periodic work disabled\n"); + mutex_unlock(&pf->dplls.lock); + return; + } } + mutex_unlock(&pf->dplls.lock); + ice_dpll_notify_changes(de); + ice_dpll_notify_changes(dp); + if (ntf_mask) + ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, + ntf_mask); } - mutex_unlock(&pf->dplls.lock); - ice_dpll_notify_changes(de); - ice_dpll_notify_changes(dp); - if (phase_offset_ntf) - ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, - phase_offset_ntf); resched: /* Run twice a second or reschedule if update failed */ @@ -3536,6 +3792,7 @@ static void ice_dpll_pin_notify_work(struct work_struct *work) work); struct ice_dpll_pin *pin, *parent = w->pin; bool is_tx_synce_parent = false; + bool is_tspll_time_ref = false; struct ice_pf *pf = parent->pf; bool is_rclk_parent = false; int ret; @@ -3556,7 +3813,11 @@ static void ice_dpll_pin_notify_work(struct work_struct *work) is_tx_synce_parent = ice_dpll_fwnode_eq(parent->fwnode, pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX].fwnode); - if (!is_rclk_parent && !is_tx_synce_parent) + + is_tspll_time_ref = + ice_dpll_fwnode_eq(parent->fwnode, pf->dplls.tspll_in.fwnode); + + if (!is_rclk_parent && !is_tx_synce_parent && !is_tspll_time_ref) goto out; switch (w->action) { @@ -3597,6 +3858,18 @@ static void ice_dpll_pin_notify_work(struct work_struct *work) ERR_PTR(ret)); goto drop_parent_ref; } + } else if (is_tspll_time_ref) { + /* Register TIME_REF pin directly to TSPLL DPLL */ + ret = dpll_pin_register(pf->dplls.tspll.dpll, + parent->pin, + &ice_dpll_tspll_in_ops, + parent); + if (ret) { + dev_err(ice_pf_to_dev(pf), + "TSPLL TIME_REF pin register failed: %pe\n", + ERR_PTR(ret)); + goto drop_parent_ref; + } } break; case DPLL_PIN_DELETED: @@ -3615,6 +3888,11 @@ static void ice_dpll_pin_notify_work(struct work_struct *work) pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX]; dpll_pin_unregister(pf->dplls.txc.dpll, pin->pin, &ice_dpll_txclk_ops, pin); + } else if (is_tspll_time_ref) { + /* Unregister TIME_REF pin from TSPLL DPLL */ + dpll_pin_unregister(pf->dplls.tspll.dpll, + parent->pin, + &ice_dpll_tspll_in_ops, parent); } drop_parent_ref: /* Drop fwnode pin reference */ @@ -3642,10 +3920,12 @@ static int ice_dpll_pin_notify(struct notifier_block *nb, unsigned long action, if (pin->fwnode != info->fwnode) return NOTIFY_DONE; /* Not this pin */ - /* Ignore notification which are the outcome of internal pin - * registration/unregistration calls - synce pin case. + /* Ignore notifications that are a side effect of internal pin + * registration/unregistration calls. E825 uses per-device + * MAC-derived clock_ids for the TXC and TSPLL generic DPLLs, so + * info->src_clock_id may not equal pf->dplls.clock_id. */ - if (info->src_clock_id == pin->pf->dplls.clock_id) + if (ice_dpll_is_own_dpll_clock_id(pin->pf, info->src_clock_id)) return NOTIFY_DONE; work = kzalloc_obj(*work); @@ -3786,12 +4066,12 @@ ice_dpll_deinit_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins, destroy_workqueue(pf->dplls.wq); } -static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf) +static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf, bool flush) { struct ice_dpll_pin *synce_pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX]; struct ice_dpll *dt = &pf->dplls.txc; - ice_dpll_stop_fwnode_pin_activity(synce_pin, true); + ice_dpll_stop_fwnode_pin_activity(synce_pin, flush); ice_dpll_unregister_pins(dt->dpll, pf->dplls.txclks, &ice_dpll_txclk_ops, ARRAY_SIZE(pf->dplls.txclks)); @@ -3807,6 +4087,25 @@ static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf) } /** + * ice_dpll_deinit_tspll_pins - deinitialize TSPLL fwnode pin + * @pf: board private structure + * + * Stop notifier activity and release the TIME_REF fwnode pin, unregistering + * it from the TSPLL DPLL if it was registered. + */ +static void ice_dpll_deinit_tspll_pins(struct ice_pf *pf) +{ + struct ice_dpll_pin *time_ref = &pf->dplls.tspll_in; + struct ice_dpll *tp = &pf->dplls.tspll; + + ice_dpll_stop_fwnode_pin_activity(time_ref, true); + if (!IS_ERR_OR_NULL(time_ref->pin)) + dpll_pin_unregister(tp->dpll, time_ref->pin, + &ice_dpll_tspll_in_ops, time_ref); + ice_dpll_release_fwnode_pin(time_ref); +} + +/** * ice_dpll_deinit_pins - deinitialize direct pins * @pf: board private structure * @cgu: if cgu is controlled by this pf @@ -3826,7 +4125,10 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) ice_dpll_deinit_rclk_pin(pf); if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) { - ice_dpll_deinit_txclk_pins(pf); + if (ice_pf_src_tmr_owned(pf) && + test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) + ice_dpll_deinit_tspll_pins(pf); + ice_dpll_deinit_txclk_pins(pf, true); ice_dpll_deinit_fwnode_pins(pf, pf->dplls.inputs, 0); } if (cgu) { @@ -3919,7 +4221,6 @@ ice_dpll_init_fwnode_pin(struct ice_dpll_pin *pin, const char *name) * @pf: board private structure * @pins: pointer to pins array * @start_idx: starting index for pins - * @count: number of pins to initialize * * Initialize input pins for E825 RCLK support. The parent pins (rclk0, rclk1) * are expected to be defined by the system firmware (ACPI). This function @@ -3968,10 +4269,16 @@ static int ice_dpll_init_txclk_pins(struct ice_pf *pf, int start_idx) { struct ice_dpll_pin *ref_pin = pf->dplls.txclks; struct ice_dpll *txc = &pf->dplls.txc; + u64 clock_id; int ret; + /* EXT_EREF0 is a non-fwnode pin; its clock_id must match the TX-CLK + * DPLL device clock_id (see dpll_pin_register()). + */ + clock_id = ice_generate_dpll_clock_id(pf, txc, DPLL_TYPE_GENERIC); + /* Configure EXT_EREF0 pin */ - ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, pf->dplls.clock_id); + ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, clock_id); if (ret) return ret; ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops, @@ -4023,9 +4330,47 @@ err_release_ext_eref: } /** + * ice_dpll_init_tspll_pins - init and register TSPLL TIME_REF fwnode pin + * @pf: board private structure + * + * Initialize the fwnode-based TIME_REF input pin for the TSPLL DPLL on E825. + * If the pin is not yet available in the dpll subsystem, registration will + * be deferred via the notifier path. + * + * Return: + * * 0 - success + * * negative - initialization failure reason + */ +static int ice_dpll_init_tspll_pins(struct ice_pf *pf) +{ + struct ice_dpll_pin *time_ref = &pf->dplls.tspll_in; + struct ice_dpll *tp = &pf->dplls.tspll; + int ret; + + time_ref->pf = pf; + ret = ice_dpll_init_fwnode_pin(time_ref, ice_dpll_fwnode_time_ref); + if (ret) + return ret; + + if (IS_ERR_OR_NULL(time_ref->pin)) { + dev_dbg(ice_pf_to_dev(pf), + "TSPLL TIME_REF pin not registered yet\n"); + return 0; + } + + ret = dpll_pin_register(tp->dpll, time_ref->pin, + &ice_dpll_tspll_in_ops, time_ref); + if (ret) { + ice_dpll_stop_fwnode_pin_activity(time_ref, false); + ice_dpll_release_fwnode_pin(time_ref); + } + + return ret; +} + +/** * ice_dpll_init_pins_e825 - init pins and register pins with a dplls * @pf: board private structure - * @cgu: if cgu is present and controlled by this NIC * * Initialize directly connected pf's pins within pf's dplls in a Linux dpll * subsystem. @@ -4049,8 +4394,24 @@ static int ice_dpll_init_pins_e825(struct ice_pf *pf) goto unregister_pins; ret = ice_dpll_init_txclk_pins(pf, 0); - if (ret) + if (ret) { ice_dpll_deinit_rclk_pin(pf); + goto unregister_pins; + } + + if (ice_pf_src_tmr_owned(pf) && + test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) { + ret = ice_dpll_init_tspll_pins(pf); + if (ret) { + /* Avoid flushing pf->dplls.wq here: notifier work + * items block on pf->dplls.dpll_init which is + * completed by the unregister_pins path below. + * destroy_workqueue() there drains queued items. + */ + ice_dpll_deinit_txclk_pins(pf, false); + ice_dpll_deinit_rclk_pin(pf); + } + } unregister_pins: if (ret) { @@ -4194,7 +4555,7 @@ static int ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, enum dpll_type type) { - u64 clock_id = pf->dplls.clock_id; + u64 clock_id = ice_generate_dpll_clock_id(pf, d, type); int ret; d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE, @@ -4237,6 +4598,7 @@ static void ice_dpll_deinit_worker(struct ice_pf *pf) kthread_cancel_delayed_work_sync(&d->work); kthread_destroy_worker(d->kworker); + d->kworker = NULL; } /** @@ -4673,6 +5035,7 @@ static void ice_dpll_deinit_info(struct ice_pf *pf) static int ice_dpll_init_info_e825c(struct ice_pf *pf) { struct ice_dplls *d = &pf->dplls; + struct ice_dpll *tp = &d->tspll; struct ice_dpll *dt = &d->txc; int ret = 0; int i; @@ -4681,7 +5044,11 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf) d->num_inputs = ICE_SYNCE_CLK_NUM; dt->dpll_state = ice_txclk_lock_status(pf->ptp.port.tx_clk); dt->mode = DPLL_MODE_MANUAL; - dt->dpll_idx = pf->ptp.port.port_num; + dt->dpll_idx = E825_DPLL_TXCLK_BASE_IDX + pf->ptp.port.port_num; + tp->dpll_state = ice_dpll_tspll_lock_status_get(pf, false); + tp->prev_dpll_state = tp->dpll_state; + tp->mode = DPLL_MODE_MANUAL; + tp->dpll_idx = E825_DPLL_TSPLL_BASE_IDX; d->inputs = kzalloc_objs(*d->inputs, d->num_inputs); if (!d->inputs) @@ -4824,7 +5191,8 @@ deinit_info: * resources and unregistering the dpll, pin and all resources used for * handling them. * - * Context: Destroys pf->dplls.lock mutex. Call only if ICE_FLAG_DPLL was set. + * Context: Call only if ICE_FLAG_DPLL was set. pf->dplls.lock lifetime is + * managed by ice_init_features()/ice_deinit_features(). */ void ice_dpll_deinit(struct ice_pf *pf) { @@ -4848,7 +5216,7 @@ void ice_dpll_deinit(struct ice_pf *pf) up_write(&pf->dplls.txclk_notify_rwsem); } - if (cgu) + if (pf->dplls.kworker) ice_dpll_deinit_worker(pf); if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) @@ -4861,9 +5229,10 @@ void ice_dpll_deinit(struct ice_pf *pf) ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu); if (!IS_ERR_OR_NULL(pf->dplls.txc.dpll)) ice_dpll_deinit_dpll(pf, &pf->dplls.txc, false); + if (!IS_ERR_OR_NULL(pf->dplls.tspll.dpll)) + ice_dpll_deinit_dpll(pf, &pf->dplls.tspll, false); ice_dpll_deinit_info(pf); - mutex_destroy(&pf->dplls.lock); } /** @@ -4873,8 +5242,6 @@ void ice_dpll_deinit(struct ice_pf *pf) * Set up the device dplls, register them and pins connected within Linux dpll * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL * configuration requests. - * - * Context: Initializes pf->dplls.lock mutex. */ static void ice_dpll_init_e825(struct ice_pf *pf) { @@ -4892,7 +5259,6 @@ static void ice_dpll_init_e825(struct ice_pf *pf) pf->ptp.port.port_num = pf->hw.lane_num; } - mutex_init(&d->lock); /* Initialize the txclk worker and its notification rwsem before any * code path can fail: ice_dpll_deinit() runs unconditionally on * failure and calls cancel_work_sync() / down_write() on these. @@ -4904,9 +5270,30 @@ static void ice_dpll_init_e825(struct ice_pf *pf) err = ice_dpll_init_info_e825c(pf); if (err) goto err_exit; + if (ice_pf_src_tmr_owned(pf) && + test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) { + err = ice_dpll_init_dpll(pf, &pf->dplls.tspll, false, + DPLL_TYPE_GENERIC); + if (err) + goto deinit_info; + /* Start the periodic worker before registering fwnode pins. The + * fwnode notifier path (ice_dpll_pin_notify_work()) blocks on + * pf->dplls.dpll_init, which is only signalled on the success + * return below. Starting the worker before any fwnode notifier + * is registered means a subsequent init failure cannot leave + * notifier work items queued on pf->dplls.wq, so the deinit + * flush_workqueue() paths in ice_dpll_deinit_pins() cannot + * deadlock. The E825 periodic worker only touches + * pf->dplls.tspll (already registered above) and pf->ptp state, + * so it is safe to run before pins. + */ + err = ice_dpll_init_worker(pf); + if (err) + goto deinit_tspll; + } err = ice_dpll_init_dpll(pf, &pf->dplls.txc, false, DPLL_TYPE_GENERIC); if (err) - goto deinit_info; + goto deinit_worker; err = ice_dpll_init_pins_e825(pf); if (err) goto deinit_txclk; @@ -4917,10 +5304,15 @@ static void ice_dpll_init_e825(struct ice_pf *pf) deinit_txclk: ice_dpll_deinit_dpll(pf, &pf->dplls.txc, false); +deinit_worker: + if (pf->dplls.kworker) + ice_dpll_deinit_worker(pf); +deinit_tspll: + if (!IS_ERR_OR_NULL(pf->dplls.tspll.dpll)) + ice_dpll_deinit_dpll(pf, &pf->dplls.tspll, false); deinit_info: ice_dpll_deinit_info(pf); err_exit: - mutex_destroy(&d->lock); dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err); } @@ -4931,16 +5323,12 @@ err_exit: * Set up the device dplls, register them and pins connected within Linux dpll * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL * configuration requests. - * - * Context: Initializes pf->dplls.lock mutex. */ static void ice_dpll_init_e810(struct ice_pf *pf) { bool cgu = ice_is_feature_supported(pf, ICE_F_CGU); - struct ice_dplls *d = &pf->dplls; int err = 0; - mutex_init(&d->lock); err = ice_dpll_init_info(pf, cgu); if (err) goto err_exit; @@ -4971,7 +5359,6 @@ deinit_eec: deinit_info: ice_dpll_deinit_info(pf); err_exit: - mutex_destroy(&d->lock); dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err); } diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index 103ba3e49068..bce0bea9a664 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -133,10 +133,12 @@ struct ice_dpll { * @eec: pointer to EEC dpll dev * @pps: pointer to PPS dpll dev * @txc: pointer to TXC dpll dev + * @tspll: pointer to TSPLL dpll dev (E825 only) * @inputs: input pins pointer * @outputs: output pins pointer * @rclk: recovered pins pointer * @txclks: TX clock reference pins pointer + * @tspll_in: TSPLL TIME_REF fwnode input pin (E825 only) * @num_inputs: number of input pins available on dpll * @num_outputs: number of output pins available on dpll * @cgu_state_acq_err_num: number of errors returned during periodic work @@ -177,12 +179,14 @@ struct ice_dplls { struct ice_dpll eec; struct ice_dpll pps; struct ice_dpll txc; + struct ice_dpll tspll; struct ice_dpll_pin *inputs; struct ice_dpll_pin *outputs; struct ice_dpll_pin sma[ICE_DPLL_PIN_SW_NUM]; struct ice_dpll_pin ufl[ICE_DPLL_PIN_SW_NUM]; struct ice_dpll_pin rclk; struct ice_dpll_pin txclks[ICE_DPLL_TXCLK_NUM_MAX]; + struct ice_dpll_pin tspll_in; u8 num_inputs; u8 num_outputs; u8 sma_data; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index bf9a821c543b..dffa213734f1 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1751,10 +1751,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) priv_flag = &ice_gstrings_priv_flags[i]; - if (flags & BIT(i)) - set_bit(priv_flag->bitno, pf->flags); - else - clear_bit(priv_flag->bitno, pf->flags); + assign_bit(priv_flag->bitno, pf->flags, flags & BIT(i)); } bitmap_xor(change_flags, pf->flags, orig_flags, ICE_PF_FLAGS_NBITS); @@ -3088,9 +3085,9 @@ static int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS: - return ice_add_fdir_ethtool(vsi, cmd); + return ice_add_ntuple_ethtool(vsi, cmd); case ETHTOOL_SRXCLSRLDEL: - return ice_del_fdir_ethtool(vsi, cmd); + return ice_del_ntuple_ethtool(vsi, cmd); default: break; } @@ -3132,7 +3129,7 @@ ice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, switch (cmd->cmd) { case ETHTOOL_GRXCLSRLCNT: - cmd->rule_cnt = hw->fdir_active_fltr; + cmd->rule_cnt = hw->ntuple_active_fltr_cnt; /* report total rule count */ cmd->data = ice_get_fdir_cnt_all(hw); ret = 0; @@ -3908,7 +3905,8 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) return -EOPNOTSUPP; } - if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) { + if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && + pf->hw.ntuple_active_fltr_cnt) { netdev_err(dev, "Cannot set channels when Flow Director filters are active\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c index aceec184e89b..ad519a8513db 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c @@ -8,23 +8,10 @@ #include "ice_fdir.h" #include "ice_flow.h" -static struct in6_addr full_ipv6_addr_mask = { - .in6_u = { - .u6_addr8 = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - } - } -}; - -static struct in6_addr zero_ipv6_addr_mask = { - .in6_u = { - .u6_addr8 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - } - } -}; +static bool ice_ipv6_mask_full(const __be32 *a) +{ + return (a[0] & a[1] & a[2] & a[3]) == cpu_to_be32(0xffffffff); +} /* calls to ice_flow_add_prof require the number of segments in the array * for segs_cnt. In this code that is one more than the index. @@ -120,7 +107,7 @@ static bool ice_is_mask_valid(u64 mask, u64 field) int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd) { struct ethtool_rx_flow_spec *fsp; - struct ice_fdir_fltr *rule; + struct ice_ntuple_fltr *rule; int ret = 0; u16 idx; @@ -240,7 +227,7 @@ int ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd, u32 *rule_locs) { - struct ice_fdir_fltr *f_rule; + struct ice_ntuple_fltr *f_rule; unsigned int cnt = 0; int val = 0; @@ -1070,10 +1057,8 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg, enum ice_flow_field src_port, dst_port; /* make sure we don't have any empty rule */ - if (!memcmp(tcp_ip6_spec->ip6src, &zero_ipv6_addr_mask, - sizeof(struct in6_addr)) && - !memcmp(tcp_ip6_spec->ip6dst, &zero_ipv6_addr_mask, - sizeof(struct in6_addr)) && + if (ipv6_addr_any((struct in6_addr *)tcp_ip6_spec->ip6src) && + ipv6_addr_any((struct in6_addr *)tcp_ip6_spec->ip6dst) && !tcp_ip6_spec->psrc && !tcp_ip6_spec->pdst) return -EINVAL; @@ -1097,24 +1082,20 @@ ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg, *perfect_fltr = true; ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | l4_proto); - if (!memcmp(tcp_ip6_spec->ip6src, &full_ipv6_addr_mask, - sizeof(struct in6_addr))) + if (ice_ipv6_mask_full(tcp_ip6_spec->ip6src)) ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_SA, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false); - else if (!memcmp(tcp_ip6_spec->ip6src, &zero_ipv6_addr_mask, - sizeof(struct in6_addr))) + else if (ipv6_addr_any((struct in6_addr *)tcp_ip6_spec->ip6src)) *perfect_fltr = false; else return -EOPNOTSUPP; - if (!memcmp(tcp_ip6_spec->ip6dst, &full_ipv6_addr_mask, - sizeof(struct in6_addr))) + if (ice_ipv6_mask_full(tcp_ip6_spec->ip6dst)) ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_DA, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false); - else if (!memcmp(tcp_ip6_spec->ip6dst, &zero_ipv6_addr_mask, - sizeof(struct in6_addr))) + else if (ipv6_addr_any((struct in6_addr *)tcp_ip6_spec->ip6dst)) *perfect_fltr = false; else return -EOPNOTSUPP; @@ -1167,33 +1148,27 @@ ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg, if (usr_ip6_spec->l4_proto) return -EOPNOTSUPP; /* empty rules are not valid */ - if (!memcmp(usr_ip6_spec->ip6src, &zero_ipv6_addr_mask, - sizeof(struct in6_addr)) && - !memcmp(usr_ip6_spec->ip6dst, &zero_ipv6_addr_mask, - sizeof(struct in6_addr))) + if (ipv6_addr_any((struct in6_addr *)usr_ip6_spec->ip6src) && + ipv6_addr_any((struct in6_addr *)usr_ip6_spec->ip6dst)) return -EINVAL; *perfect_fltr = true; ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6); - if (!memcmp(usr_ip6_spec->ip6src, &full_ipv6_addr_mask, - sizeof(struct in6_addr))) + if (ice_ipv6_mask_full(usr_ip6_spec->ip6src)) ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_SA, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false); - else if (!memcmp(usr_ip6_spec->ip6src, &zero_ipv6_addr_mask, - sizeof(struct in6_addr))) + else if (ipv6_addr_any((struct in6_addr *)usr_ip6_spec->ip6src)) *perfect_fltr = false; else return -EOPNOTSUPP; - if (!memcmp(usr_ip6_spec->ip6dst, &full_ipv6_addr_mask, - sizeof(struct in6_addr))) + if (ice_ipv6_mask_full(usr_ip6_spec->ip6dst)) ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_DA, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false); - else if (!memcmp(usr_ip6_spec->ip6dst, &zero_ipv6_addr_mask, - sizeof(struct in6_addr))) + else if (ipv6_addr_any((struct in6_addr *)usr_ip6_spec->ip6dst)) *perfect_fltr = false; else return -EOPNOTSUPP; @@ -1487,10 +1462,10 @@ static void ice_update_per_q_fltr(struct ice_vsi *vsi, u32 q_index, bool inc) * @add: true adds filter and false removed filter * @is_tun: true adds inner filter on tunnel and false outer headers * - * returns 0 on success and negative value on error + * Return: 0 on success and negative value on error */ int -ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add, +ice_fdir_write_fltr(struct ice_pf *pf, struct ice_ntuple_fltr *input, bool add, bool is_tun) { struct device *dev = ice_pf_to_dev(pf); @@ -1557,10 +1532,10 @@ err_frag: * @input: filter structure * @add: true adds filter and false removed filter * - * returns 0 on success and negative value on error + * Return: 0 on success and negative value on error */ static int -ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, +ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_ntuple_fltr *input, bool add) { u16 port_num; @@ -1585,7 +1560,7 @@ ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, */ void ice_fdir_replay_fltrs(struct ice_pf *pf) { - struct ice_fdir_fltr *f_rule; + struct ice_ntuple_fltr *f_rule; struct ice_hw *hw = &pf->hw; list_for_each_entry(f_rule, &hw->fdir_list_head, fltr_node) { @@ -1623,6 +1598,25 @@ int ice_fdir_create_dflt_rules(struct ice_pf *pf) } /** + * ice_ntuple_update_cntrs - increment or decrement filter counter + * @hw: pointer to hardware structure + * @flow: filter flow type + * @add: true to increment, false to decrement + */ +static void ice_ntuple_update_cntrs(struct ice_hw *hw, + enum ice_fltr_ptype flow, bool add) +{ + int incr = add ? 1 : -1; + + hw->ntuple_active_fltr_cnt += incr; + + if (flow == ICE_FLTR_PTYPE_NONF_NONE || flow >= ICE_FLTR_PTYPE_MAX) + ice_debug(hw, ICE_DBG_SW, "Unknown filter type %d\n", flow); + else + hw->fdir_fltr_cnt[flow] += incr; +} + +/** * ice_fdir_del_all_fltrs - Delete all flow director filters * @vsi: the VSI being changed * @@ -1630,13 +1624,13 @@ int ice_fdir_create_dflt_rules(struct ice_pf *pf) */ void ice_fdir_del_all_fltrs(struct ice_vsi *vsi) { - struct ice_fdir_fltr *f_rule, *tmp; + struct ice_ntuple_fltr *f_rule, *tmp; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; list_for_each_entry_safe(f_rule, tmp, &hw->fdir_list_head, fltr_node) { ice_fdir_write_all_fltr(pf, f_rule, false); - ice_fdir_update_cntrs(hw, f_rule->flow_type, false); + ice_ntuple_update_cntrs(hw, f_rule->flow_type, false); list_del(&f_rule->fltr_node); devm_kfree(ice_pf_to_dev(pf), f_rule); } @@ -1701,18 +1695,18 @@ ice_fdir_do_rem_flow(struct ice_pf *pf, enum ice_fltr_ptype flow_type) } /** - * ice_fdir_update_list_entry - add or delete a filter from the filter list + * ice_ntuple_update_list_entry - add or delete a filter from the filter list * @pf: PF structure * @input: filter structure * @fltr_idx: ethtool index of filter to modify * - * returns 0 on success and negative on errors + * Return: 0 on success and negative on errors */ static int -ice_fdir_update_list_entry(struct ice_pf *pf, struct ice_fdir_fltr *input, - int fltr_idx) +ice_ntuple_update_list_entry(struct ice_pf *pf, struct ice_ntuple_fltr *input, + int fltr_idx) { - struct ice_fdir_fltr *old_fltr; + struct ice_ntuple_fltr *old_fltr; struct ice_hw *hw = &pf->hw; struct ice_vsi *vsi; int err = -ENOENT; @@ -1730,7 +1724,7 @@ ice_fdir_update_list_entry(struct ice_pf *pf, struct ice_fdir_fltr *input, err = ice_fdir_write_all_fltr(pf, old_fltr, false); if (err) return err; - ice_fdir_update_cntrs(hw, old_fltr->flow_type, false); + ice_ntuple_update_cntrs(hw, old_fltr->flow_type, false); /* update sb-filters count, specific to ring->channel */ ice_update_per_q_fltr(vsi, old_fltr->orig_q_index, false); if (!input && !hw->fdir_fltr_cnt[old_fltr->flow_type]) @@ -1746,18 +1740,18 @@ ice_fdir_update_list_entry(struct ice_pf *pf, struct ice_fdir_fltr *input, ice_fdir_list_add_fltr(hw, input); /* update sb-filters count, specific to ring->channel */ ice_update_per_q_fltr(vsi, input->orig_q_index, true); - ice_fdir_update_cntrs(hw, input->flow_type, true); + ice_ntuple_update_cntrs(hw, input->flow_type, true); return 0; } /** - * ice_del_fdir_ethtool - delete Flow Director filter + * ice_del_ntuple_ethtool - delete Flow Director or ACL filter * @vsi: pointer to target VSI - * @cmd: command to add or delete Flow Director filter + * @cmd: command to add or delete the filter * - * Returns 0 on success and negative values for failure + * Return: 0 on success and negative values for failure */ -int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) +int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) { struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; @@ -1774,11 +1768,8 @@ int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) return -EBUSY; } - if (test_bit(ICE_FD_FLUSH_REQ, pf->state)) - return -EBUSY; - mutex_lock(&hw->fdir_fltr_lock); - val = ice_fdir_update_list_entry(pf, NULL, fsp->location); + val = ice_ntuple_update_list_entry(pf, NULL, fsp->location); mutex_unlock(&hw->fdir_fltr_lock); return val; @@ -1818,14 +1809,16 @@ ice_update_ring_dest_vsi(struct ice_vsi *vsi, u16 *dest_vsi, u32 *ring) } /** - * ice_set_fdir_input_set - Set the input set for Flow Director + * ice_ntuple_set_input_set - Set the input set for Flow Director * @vsi: pointer to target VSI * @fsp: pointer to ethtool Rx flow specification * @input: filter structure + * + * Return: 0 on success, negative on failure */ static int -ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp, - struct ice_fdir_fltr *input) +ice_ntuple_set_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp, + struct ice_ntuple_fltr *input) { s16 q_index = ICE_FDIR_NO_QUEUE_IDX; u16 orig_q_index = 0; @@ -1968,17 +1961,17 @@ ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp, } /** - * ice_add_fdir_ethtool - Add/Remove Flow Director filter + * ice_add_ntuple_ethtool - Add/Remove Flow Director or ACL filter * @vsi: pointer to target VSI - * @cmd: command to add or delete Flow Director filter + * @cmd: command to add or delete the filter * - * Returns 0 on success and negative values for failure + * Return: 0 on success and negative values for failure */ -int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) +int ice_add_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) { struct ice_rx_flow_userdef userdata; struct ethtool_rx_flow_spec *fsp; - struct ice_fdir_fltr *input; + struct ice_ntuple_fltr *input; struct device *dev; struct ice_pf *pf; struct ice_hw *hw; @@ -2034,7 +2027,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) if (!input) return -ENOMEM; - ret = ice_set_fdir_input_set(vsi, fsp, input); + ret = ice_ntuple_set_input_set(vsi, fsp, input); if (ret) goto free_input; @@ -2055,7 +2048,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW_FAIL; /* input struct is added to the HW filter list */ - ret = ice_fdir_update_list_entry(pf, input, fsp->location); + ret = ice_ntuple_update_list_entry(pf, input, fsp->location); if (ret) goto release_lock; @@ -2066,7 +2059,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) goto release_lock; remove_sw_rule: - ice_fdir_update_cntrs(hw, input->flow_type, false); + ice_ntuple_update_cntrs(hw, input->flow_type, false); /* update sb-filters count, specific to ring->channel */ ice_update_per_q_fltr(vsi, input->orig_q_index, false); list_del(&input->fltr_node); diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.c b/drivers/net/ethernet/intel/ice/ice_fdir.c index b29fbdec9442..1bc91cb41769 100644 --- a/drivers/net/ethernet/intel/ice/ice_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_fdir.c @@ -648,7 +648,7 @@ ice_set_fd_desc_val(struct ice_fd_fltr_desc_ctx *ctx, * @add: if add is true, this is an add operation, false implies delete */ void -ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_fdir_fltr *input, +ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_ntuple_fltr *input, struct ice_fltr_desc *fdesc, bool add) { struct ice_fd_fltr_desc_ctx fdir_fltr_ctx = { 0 }; @@ -855,7 +855,7 @@ static void ice_pkt_insert_mac_addr(u8 *pkt, u8 *addr) * @tun: true implies generate a tunnel packet */ int -ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input, +ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_ntuple_fltr *input, u8 *pkt, bool frag, bool tun) { enum ice_fltr_ptype flow; @@ -1138,10 +1138,10 @@ bool ice_fdir_has_frag(enum ice_fltr_ptype flow) * * Returns pointer to filter if found or null */ -struct ice_fdir_fltr * +struct ice_ntuple_fltr * ice_fdir_find_fltr_by_idx(struct ice_hw *hw, u32 fltr_idx) { - struct ice_fdir_fltr *rule; + struct ice_ntuple_fltr *rule; list_for_each_entry(rule, &hw->fdir_list_head, fltr_node) { /* rule ID found in the list */ @@ -1158,9 +1158,9 @@ ice_fdir_find_fltr_by_idx(struct ice_hw *hw, u32 fltr_idx) * @hw: hardware structure * @fltr: filter node to add to structure */ -void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_fdir_fltr *fltr) +void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_ntuple_fltr *fltr) { - struct ice_fdir_fltr *rule, *parent = NULL; + struct ice_ntuple_fltr *rule, *parent = NULL; list_for_each_entry(rule, &hw->fdir_list_head, fltr_node) { /* rule ID found or pass its spot in the list */ @@ -1176,26 +1176,6 @@ void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_fdir_fltr *fltr) } /** - * ice_fdir_update_cntrs - increment / decrement filter counter - * @hw: pointer to hardware structure - * @flow: filter flow type - * @add: true implies filters added - */ -void -ice_fdir_update_cntrs(struct ice_hw *hw, enum ice_fltr_ptype flow, bool add) -{ - int incr; - - incr = add ? 1 : -1; - hw->fdir_active_fltr += incr; - - if (flow == ICE_FLTR_PTYPE_NONF_NONE || flow >= ICE_FLTR_PTYPE_MAX) - ice_debug(hw, ICE_DBG_SW, "Unknown filter type %d\n", flow); - else - hw->fdir_fltr_cnt[flow] += incr; -} - -/** * ice_cmp_ipv6_addr - compare 2 IP v6 addresses * @a: IP v6 address * @b: IP v6 address @@ -1215,7 +1195,7 @@ static int ice_cmp_ipv6_addr(__be32 *a, __be32 *b) * Returns true if the filters match */ static bool -ice_fdir_comp_rules(struct ice_fdir_fltr *a, struct ice_fdir_fltr *b) +ice_fdir_comp_rules(struct ice_ntuple_fltr *a, struct ice_ntuple_fltr *b) { enum ice_fltr_ptype flow_type = a->flow_type; @@ -1275,9 +1255,9 @@ ice_fdir_comp_rules(struct ice_fdir_fltr *a, struct ice_fdir_fltr *b) * * Returns true if the filter is found in the list */ -bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input) +bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_ntuple_fltr *input) { - struct ice_fdir_fltr *rule; + struct ice_ntuple_fltr *rule; bool ret = false; list_for_each_entry(rule, &hw->fdir_list_head, fltr_node) { diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.h b/drivers/net/ethernet/intel/ice/ice_fdir.h index 820023c0271f..54f51ae31b40 100644 --- a/drivers/net/ethernet/intel/ice/ice_fdir.h +++ b/drivers/net/ethernet/intel/ice/ice_fdir.h @@ -160,7 +160,7 @@ struct ice_fdir_extra { __be16 vlan_tag; /* VLAN tag info */ }; -struct ice_fdir_fltr { +struct ice_ntuple_fltr { struct list_head fltr_node; enum ice_fltr_ptype flow_type; @@ -216,18 +216,16 @@ int ice_free_fd_res_cntr(struct ice_hw *hw, u16 cntr_id); int ice_alloc_fd_guar_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr); int ice_alloc_fd_shrd_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr); void -ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_fdir_fltr *input, +ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_ntuple_fltr *input, struct ice_fltr_desc *fdesc, bool add); int -ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input, +ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_ntuple_fltr *input, u8 *pkt, bool frag, bool tun); int ice_get_fdir_cnt_all(struct ice_hw *hw); int ice_fdir_num_avail_fltr(struct ice_hw *hw, struct ice_vsi *vsi); -bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input); +bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_ntuple_fltr *input); bool ice_fdir_has_frag(enum ice_fltr_ptype flow); -struct ice_fdir_fltr * +struct ice_ntuple_fltr * ice_fdir_find_fltr_by_idx(struct ice_hw *hw, u32 fltr_idx); -void -ice_fdir_update_cntrs(struct ice_hw *hw, enum ice_fltr_ptype flow, bool add); -void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input); +void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_ntuple_fltr *input); #endif /* _ICE_FDIR_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 9e08db376d3d..7cd2dd066ef5 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -153,23 +153,61 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi) } } -static u16 ice_get_rxq_count(struct ice_pf *pf) +static u16 ice_get_rxq_count(struct ice_pf *pf, u16 held) { - return min(ice_get_avail_rxq_count(pf), - netif_get_num_default_rss_queues()); + return min_t(u16, ice_get_avail_rxq_count(pf) + held, + netif_get_num_default_rss_queues()); } -static u16 ice_get_txq_count(struct ice_pf *pf) +static u16 ice_get_txq_count(struct ice_pf *pf, u16 held) { - return min(ice_get_avail_txq_count(pf), - netif_get_num_default_rss_queues()); + return min_t(u16, ice_get_avail_txq_count(pf) + held, + netif_get_num_default_rss_queues()); +} + +/* @held_txq, @held_rxq: queues the VSI still owns but is about to return to the + * PF pool, so that the result matches what it will be once they are back there. + */ +static struct ice_vsi_alloc_queues_params +ice_vsi_get_num_qs(struct ice_vsi *vsi, u16 held_txq, u16 held_rxq) +{ + struct ice_vsi_alloc_queues_params qs = {}; + struct ice_pf *pf = vsi->back; + + switch (vsi->type) { + case ICE_VSI_PF: + qs.alloc_txq = vsi->req_txq ?: ice_get_txq_count(pf, held_txq); + + /* only 1 Rx queue unless RSS is enabled */ + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + qs.alloc_rxq = 1; + else + qs.alloc_rxq = vsi->req_rxq ?: + ice_get_rxq_count(pf, held_rxq); + break; + case ICE_VSI_SF: + case ICE_VSI_CTRL: + case ICE_VSI_LB: + qs.alloc_txq = 1; + qs.alloc_rxq = 1; + break; + case ICE_VSI_VF: + qs.alloc_txq = vsi->vf->num_req_qs ?: vsi->vf->num_vf_qs; + qs.alloc_rxq = qs.alloc_txq; + break; + case ICE_VSI_CHNL: + break; + default: + dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi->type); + return vsi->alloc_txq_rxq; + } + + return qs; } /** * ice_vsi_set_num_qs - Set number of queues, descriptors and vectors for a VSI * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error */ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) { @@ -180,44 +218,27 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) if (WARN_ON(vsi_type == ICE_VSI_VF && !vf)) return; + vsi->alloc_txq_rxq = ice_vsi_get_num_qs(vsi, 0, 0); + switch (vsi_type) { case ICE_VSI_PF: - if (vsi->req_txq) { - vsi->alloc_txq = vsi->req_txq; + if (vsi->req_txq) vsi->num_txq = vsi->req_txq; - } else { - vsi->alloc_txq = ice_get_txq_count(pf); - } + if (vsi->req_rxq && test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + vsi->num_rxq = vsi->req_rxq; pf->num_lan_tx = vsi->alloc_txq; - - /* only 1 Rx queue unless RSS is enabled */ - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { - vsi->alloc_rxq = 1; - } else { - if (vsi->req_rxq) { - vsi->alloc_rxq = vsi->req_rxq; - vsi->num_rxq = vsi->req_rxq; - } else { - vsi->alloc_rxq = ice_get_rxq_count(pf); - } - } - pf->num_lan_rx = vsi->alloc_rxq; vsi->num_q_vectors = max(vsi->alloc_rxq, vsi->alloc_txq); break; case ICE_VSI_SF: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; vsi->num_q_vectors = 1; vsi->irq_dyn_alloc = true; break; case ICE_VSI_VF: if (vf->num_req_qs) vf->num_vf_qs = vf->num_req_qs; - vsi->alloc_txq = vf->num_vf_qs; - vsi->alloc_rxq = vf->num_vf_qs; /* pf->vfs.num_msix_per includes (VF miscellaneous vector + * data queue interrupts). Since vsi->num_q_vectors is number * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the @@ -226,22 +247,15 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) vsi->num_q_vectors = vf->num_msix - ICE_NONQ_VECS_VF; break; case ICE_VSI_CTRL: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; vsi->num_q_vectors = 1; break; case ICE_VSI_CHNL: - vsi->alloc_txq = 0; - vsi->alloc_rxq = 0; break; case ICE_VSI_LB: - vsi->alloc_txq = 1; - vsi->alloc_rxq = 1; /* A dummy q_vector, no actual IRQ. */ vsi->num_q_vectors = 1; break; default: - dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type); break; } @@ -330,6 +344,32 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi) vsi->rxq_map = NULL; } +/* free single stats memory */ +static void __ice_vsi_free_stats(struct ice_vsi_stats *vsi_stat, bool free_entries) +{ + if (!vsi_stat) + return; + + if (free_entries) { + for (int i = 0; i < vsi_stat->tx_ring_stats_len; i++) { + if (vsi_stat->tx_ring_stats[i]) { + kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); + } + } + for (int i = 0; i < vsi_stat->rx_ring_stats_len; i++) { + if (vsi_stat->rx_ring_stats[i]) { + kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); + } + } + } + + kfree(vsi_stat->tx_ring_stats); + kfree(vsi_stat->rx_ring_stats); + kfree(vsi_stat); +} + /** * ice_vsi_free_stats - Free the ring statistics structures * @vsi: VSI pointer @@ -338,7 +378,6 @@ static void ice_vsi_free_stats(struct ice_vsi *vsi) { struct ice_vsi_stats *vsi_stat; struct ice_pf *pf = vsi->back; - int i; if (vsi->type == ICE_VSI_CHNL) return; @@ -346,26 +385,7 @@ static void ice_vsi_free_stats(struct ice_vsi *vsi) return; vsi_stat = pf->vsi_stats[vsi->idx]; - if (!vsi_stat) - return; - - ice_for_each_alloc_txq(vsi, i) { - if (vsi_stat->tx_ring_stats[i]) { - kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); - } - } - - ice_for_each_alloc_rxq(vsi, i) { - if (vsi_stat->rx_ring_stats[i]) { - kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); - } - } - - kfree(vsi_stat->tx_ring_stats); - kfree(vsi_stat->rx_ring_stats); - kfree(vsi_stat); + __ice_vsi_free_stats(vsi_stat, true); pf->vsi_stats[vsi->idx] = NULL; } @@ -513,13 +533,116 @@ static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) return IRQ_HANDLED; } +static struct ice_vsi_stats *ice_vsi_new_stat_arrays(int txq, int rxq) +{ + struct ice_ring_stats **tx_ring_stats; + struct ice_ring_stats **rx_ring_stats; + struct ice_vsi_stats *vsi_stat; + + vsi_stat = kzalloc_obj(*vsi_stat); + tx_ring_stats = kzalloc_objs(*tx_ring_stats, txq); + rx_ring_stats = kzalloc_objs(*rx_ring_stats, rxq); + if (!vsi_stat || !tx_ring_stats || !rx_ring_stats) { + kfree(vsi_stat); + kfree(tx_ring_stats); + kfree(rx_ring_stats); + return NULL; + } + + vsi_stat->tx_ring_stats = tx_ring_stats; + vsi_stat->rx_ring_stats = rx_ring_stats; + vsi_stat->tx_ring_stats_len = txq; + vsi_stat->rx_ring_stats_len = rxq; + + return vsi_stat; +} + +static void ice_vsi_free_unused_stat_arrays(struct ice_vsi_stats *vsi_stat, + struct ice_vsi_stats *new_vsi_stat) +{ + int new_txq = new_vsi_stat->tx_ring_stats_len; + int new_rxq = new_vsi_stat->rx_ring_stats_len; + int prev_txq = vsi_stat->tx_ring_stats_len; + int prev_rxq = vsi_stat->rx_ring_stats_len; + + for (int i = new_txq; i < prev_txq; i++) { + if (vsi_stat->tx_ring_stats[i]) { + kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); + } + } + for (int i = new_rxq; i < prev_rxq; i++) { + if (vsi_stat->rx_ring_stats[i]) { + kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); + WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); + } + } +} + +static void ice_vsi_set_stat_arrays(struct ice_vsi *vsi, + struct ice_vsi_stats *new_vsi_stat) +{ + u16 new_txq, new_rxq, prev_txq, prev_rxq; + struct ice_vsi_stats *vsi_stat; + struct ice_pf *pf = vsi->back; + + new_txq = new_vsi_stat->tx_ring_stats_len; + new_rxq = new_vsi_stat->rx_ring_stats_len; + vsi_stat = pf->vsi_stats[vsi->idx]; + pf->vsi_stats[vsi->idx] = new_vsi_stat; + if (!vsi_stat) + return; /* don't copy if there is no source */ + + prev_txq = vsi_stat->tx_ring_stats_len; + prev_rxq = vsi_stat->rx_ring_stats_len; + + memcpy(new_vsi_stat->tx_ring_stats, vsi_stat->tx_ring_stats, + sizeof(*vsi_stat->tx_ring_stats) * min(prev_txq, new_txq)); + memcpy(new_vsi_stat->rx_ring_stats, vsi_stat->rx_ring_stats, + sizeof(*vsi_stat->rx_ring_stats) * min(prev_rxq, new_rxq)); +} + +/** + * ice_vsi_install_stat_arrays - swap in freshly sized ring stats arrays + * @vsi: VSI to install the ring stats arrays of + * @txq: number of Tx ring stats entries to make room for + * @rxq: number of Rx ring stats entries to make room for + * + * Surviving entries are carried over, the rest is freed together with the old + * container. + * + * Return: 0 on success and negative value on failure. + */ +static int ice_vsi_install_stat_arrays(struct ice_vsi *vsi, u16 txq, u16 rxq) +{ + struct ice_vsi_stats *old_stat, *new_stat; + + new_stat = ice_vsi_new_stat_arrays(txq, rxq); + if (!new_stat) + return -ENOMEM; + + old_stat = vsi->back->vsi_stats[vsi->idx]; + ice_vsi_set_stat_arrays(vsi, new_stat); + if (old_stat) { + ice_vsi_free_unused_stat_arrays(old_stat, new_stat); + __ice_vsi_free_stats(old_stat, false); + } + + return 0; +} + /** * ice_vsi_alloc_stat_arrays - Allocate statistics arrays * @vsi: VSI pointer + * + * Runs after ice_vsi_set_num_qs(), so this is the first point where the queue + * count is final. Grow the arrays if an earlier sizing guessed too low. + * + * Return: 0 on success, negative error code otherwise. */ static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) { - struct ice_vsi_stats *vsi_stat; + struct ice_vsi_stats *old_stat; struct ice_pf *pf = vsi->back; if (vsi->type == ICE_VSI_CHNL) @@ -527,35 +650,13 @@ static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi) if (!pf->vsi_stats) return -ENOENT; - if (pf->vsi_stats[vsi->idx]) - /* realloc will happen in rebuild path */ + old_stat = pf->vsi_stats[vsi->idx]; + if (old_stat && old_stat->tx_ring_stats_len >= vsi->alloc_txq && + old_stat->rx_ring_stats_len >= vsi->alloc_rxq) return 0; - vsi_stat = kzalloc_obj(*vsi_stat); - if (!vsi_stat) - return -ENOMEM; - - vsi_stat->tx_ring_stats = - kzalloc_objs(*vsi_stat->tx_ring_stats, vsi->alloc_txq); - if (!vsi_stat->tx_ring_stats) - goto err_alloc_tx; - - vsi_stat->rx_ring_stats = - kzalloc_objs(*vsi_stat->rx_ring_stats, vsi->alloc_rxq); - if (!vsi_stat->rx_ring_stats) - goto err_alloc_rx; - - pf->vsi_stats[vsi->idx] = vsi_stat; - - return 0; - -err_alloc_rx: - kfree(vsi_stat->rx_ring_stats); -err_alloc_tx: - kfree(vsi_stat->tx_ring_stats); - kfree(vsi_stat); - pf->vsi_stats[vsi->idx] = NULL; - return -ENOMEM; + return ice_vsi_install_stat_arrays(vsi, vsi->alloc_txq, + vsi->alloc_rxq); } /** @@ -1705,16 +1806,7 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) */ bool ice_pf_state_is_nominal(struct ice_pf *pf) { - DECLARE_BITMAP(check_bits, ICE_STATE_NBITS) = { 0 }; - - if (!pf) - return false; - - bitmap_set(check_bits, 0, ICE_STATE_NOMINAL_CHECK_BITS); - if (bitmap_intersects(pf->state, check_bits, ICE_STATE_NBITS)) - return false; - - return true; + return bitmap_empty(pf->state, ICE_STATE_NOMINAL_CHECK_BITS); } #define ICE_FW_MODE_REC_M BIT(1) @@ -3015,63 +3107,27 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, } /** - * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones - * @vsi: VSI pointer + * ice_vsi_resize_stat_arrays - resize ring stats arrays for new queue count + * @vsi: VSI to swap the ring stats arrays of + * + * Call while @vsi still owns its queues and before ice_vsi_decfg() returns them + * to the PF pool, so that the new size is what ice_vsi_set_num_qs() will compute + * afterwards. Surviving entries are carried over, the rest is freed. + * + * Return: 0 on success and negative value on failure. */ -static int -ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi) +static int ice_vsi_resize_stat_arrays(struct ice_vsi *vsi) { - u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq; - u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq; - struct ice_ring_stats **tx_ring_stats; - struct ice_ring_stats **rx_ring_stats; - struct ice_vsi_stats *vsi_stat; - struct ice_pf *pf = vsi->back; - u16 prev_txq = vsi->alloc_txq; - u16 prev_rxq = vsi->alloc_rxq; - int i; - - vsi_stat = pf->vsi_stats[vsi->idx]; - - if (req_txq < prev_txq) { - for (i = req_txq; i < prev_txq; i++) { - if (vsi_stat->tx_ring_stats[i]) { - kfree_rcu(vsi_stat->tx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL); - } - } - } - - tx_ring_stats = vsi_stat->tx_ring_stats; - vsi_stat->tx_ring_stats = - krealloc_array(vsi_stat->tx_ring_stats, req_txq, - sizeof(*vsi_stat->tx_ring_stats), - GFP_KERNEL | __GFP_ZERO); - if (!vsi_stat->tx_ring_stats) { - vsi_stat->tx_ring_stats = tx_ring_stats; - return -ENOMEM; - } + struct ice_vsi_alloc_queues_params qs; - if (req_rxq < prev_rxq) { - for (i = req_rxq; i < prev_rxq; i++) { - if (vsi_stat->rx_ring_stats[i]) { - kfree_rcu(vsi_stat->rx_ring_stats[i], rcu); - WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL); - } - } - } + /* channel VSIs have no entry in pf->vsi_stats[] */ + if (vsi->type == ICE_VSI_CHNL) + return 0; - rx_ring_stats = vsi_stat->rx_ring_stats; - vsi_stat->rx_ring_stats = - krealloc_array(vsi_stat->rx_ring_stats, req_rxq, - sizeof(*vsi_stat->rx_ring_stats), - GFP_KERNEL | __GFP_ZERO); - if (!vsi_stat->rx_ring_stats) { - vsi_stat->rx_ring_stats = rx_ring_stats; - return -ENOMEM; - } + qs = ice_vsi_get_num_qs(vsi, vsi->alloc_txq + vsi->num_xdp_txq, + vsi->alloc_rxq); - return 0; + return ice_vsi_install_stat_arrays(vsi, qs.alloc_txq, qs.alloc_rxq); } /** @@ -3101,7 +3157,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags) mutex_lock(&vsi->xdp_state_lock); - ret = ice_vsi_realloc_stat_arrays(vsi); + ret = ice_vsi_resize_stat_arrays(vsi); if (ret) goto unlock; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d88835482d3a..454fba07d4ec 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3428,7 +3428,7 @@ skip_req_irq: ((pf->ll_ts_irq.index + pf_intr_start_offset) & PFINT_SB_CTL_MSIX_INDX_M) | PFINT_SB_CTL_CAUSE_ENA_M); wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index), - ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S); + ITR_REG_ALIGN(ICE_ITR_20K) >> ICE_ITR_GRAN_S); ice_flush(hw); ice_irq_dynamic_ena(hw, NULL, NULL); @@ -4725,6 +4725,14 @@ static void ice_init_features(struct ice_pf *pf) if (ice_is_safe_mode(pf)) return; + /* pf->dplls.lock guards TSPLL/CGU access shared between the DPLL + * subsystem callbacks and the PTP periodic worker's TSPLL monitor. + * Initialize it before ice_ptp_init() so the PTP kworker never sees + * an uninitialized mutex, and destroy it in ice_deinit_features() + * only after ice_ptp_release() has drained the kworker. + */ + mutex_init(&pf->dplls.lock); + /* initialize DDP driven features */ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) ice_ptp_init(pf); @@ -4769,6 +4777,7 @@ static void ice_deinit_features(struct ice_pf *pf) ice_ptp_release(pf); if (test_bit(ICE_FLAG_DPLL, pf->flags)) ice_dpll_deinit(pf); + mutex_destroy(&pf->dplls.lock); if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) xa_destroy(&pf->eswitch.reprs); ice_hwmon_exit(pf); @@ -5521,7 +5530,7 @@ static int ice_suspend(struct device *dev) pf = pci_get_drvdata(pdev); - if (!ice_pf_state_is_nominal(pf)) { + if (!pf || !ice_pf_state_is_nominal(pf)) { dev_err(dev, "Device is not ready, no need to suspend it\n"); return -EBUSY; } @@ -6202,7 +6211,7 @@ ice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[], * * Features that need fixing: * Cannot simultaneously enable CTAG and STAG stripping and/or insertion. - * These are mutually exlusive as the VSI context cannot support multiple + * These are mutually exclusive as the VSI context cannot support multiple * VLAN ethertypes simultaneously for stripping and/or insertion. If this * is not done, then default to clearing the requested STAG offload * settings. diff --git a/drivers/net/ethernet/intel/ice/ice_parser.c b/drivers/net/ethernet/intel/ice/ice_parser.c index 3ede4c1a5a8a..d239102c52ff 100644 --- a/drivers/net/ethernet/intel/ice/ice_parser.c +++ b/drivers/net/ethernet/intel/ice/ice_parser.c @@ -102,7 +102,7 @@ ice_parser_create_table(struct ice_hw *hw, u32 sect_type, if (!seg) return ERR_PTR(-EINVAL); - table = kzalloc(item_size * length, GFP_KERNEL); + table = kcalloc(length, item_size, GFP_KERNEL); if (!table) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index eaec36ab6ae3..b781004f856d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -4,8 +4,11 @@ #include "ice.h" #include "ice_lib.h" #include "ice_trace.h" +#include "ice_tspll.h" #include "ice_txclk.h" +#define ICE_TSPLL_LOG_INTERVAL 120 + static const char ice_pin_names[][64] = { "SDP0", "SDP1", @@ -2327,6 +2330,8 @@ u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, ts_high = le32_to_cpu(rx_desc->wb.flex_ts.ts_high); ts_ns = ice_ptp_extend_32b_ts(cached_time, ts_high); + ice_trace(rx_hwtstamp, cached_time, ts_high, ts_ns); + return ts_ns; } @@ -2849,6 +2854,79 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) } } +/** + * ice_ptp_tspll_monitor - poll and recover TSPLL lock on E825 owner PFs + * @pf: Board private structure + * + * Called from the PTP periodic worker. On E825 devices that own the source + * timer, poll the TSPLL lock status via CGU registers and trigger a restart + * if the lock has been lost. The result is cached in @pf->ptp.tspll_locked + * so it can be consumed by the DPLL periodic worker via READ_ONCE(). + * + * TSPLL lock is critical for PHC operation and must be monitored regardless + * of whether DPLL init succeeded or CONFIG_DPLL is enabled. Placing the + * monitor here makes recovery independent of the dpll subsystem. + * + * AQ read errors are rate-limited and do not stop monitoring. Lock-lost + * events are logged every 120 retries (~60 s at normal poll rate) to + * surface persistent failures without flooding the log. + */ +static void ice_ptp_tspll_monitor(struct ice_pf *pf) +{ + bool lock_lost; + int err; + + if (pf->hw.mac_type != ICE_MAC_GENERIC_3K_E825 || + !ice_pf_src_tmr_owned(pf)) + return; + + /* Serialize the entire monitor tick against TSPLL userspace reconfig + * (ice_dpll_tspll_state_on_dpll_set()). Both paths read HW state and + * write pf->ptp.tspll_locked; without holding pf->dplls.lock across + * the HW read here, a preempted monitor could observe stale HW state + * and then overwrite an accurate cache update from the DPLL callback. + * pf->dplls.lock is initialized in ice_init_features() before the PTP + * kworker starts and destroyed in ice_deinit_features() only after + * ice_ptp_release() has drained the kworker, so it is always valid. + */ + mutex_lock(&pf->dplls.lock); + err = ice_tspll_lost_lock_e825c(&pf->hw, &lock_lost); + if (err) { + mutex_unlock(&pf->dplls.lock); + dev_err_ratelimited(ice_pf_to_dev(pf), + "Failed reading TimeSync PLL lock status (err: %d). Retrying.\n", + err); + return; + } + + if (lock_lost) { + WRITE_ONCE(pf->ptp.tspll_locked, false); + if (!(pf->ptp.tspll_lock_retries % ICE_TSPLL_LOG_INTERVAL)) + dev_warn(ice_pf_to_dev(pf), + "TimeSync PLL lock lost. Retrying to acquire lock.\n"); + err = ice_tspll_restart_e825c(&pf->hw); + if (err) + dev_err_ratelimited(ice_pf_to_dev(pf), + "Failed to restart TimeSync PLL (err: %d).\n", + err); + pf->ptp.tspll_lock_retries++; + } else { + if (pf->ptp.tspll_lock_retries) { + const char *src_str = "unknown"; + enum ice_clk_src clk_src; + + if (!ice_tspll_get_clk_src(&pf->hw, &clk_src)) + src_str = ice_tspll_clk_src_str(clk_src); + dev_info(ice_pf_to_dev(pf), + "TimeSync PLL lock acquired with %s clock source after %u retries.\n", + src_str, pf->ptp.tspll_lock_retries); + } + WRITE_ONCE(pf->ptp.tspll_locked, true); + pf->ptp.tspll_lock_retries = 0; + } + mutex_unlock(&pf->dplls.lock); +} + static void ice_ptp_periodic_work(struct kthread_work *work) { struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work); @@ -2858,6 +2936,8 @@ static void ice_ptp_periodic_work(struct kthread_work *work) if (pf->ptp.state != ICE_PTP_READY) return; + ice_ptp_tspll_monitor(pf); + err = ice_ptp_update_cached_phctime(pf); ice_ptp_maybe_trigger_tx_interrupt(pf); @@ -2975,6 +3055,9 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) err = ice_tspll_init(hw); if (err) return err; + /* Rebuild reinitialized TSPLL, so reset monitor retry state. */ + WRITE_ONCE(ptp->tspll_locked, true); + ptp->tspll_lock_retries = 0; /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { @@ -3319,6 +3402,7 @@ void ice_ptp_init(struct ice_pf *pf) } ptp->port.port_num = hw->lane_num; + ptp->tspll_locked = true; ice_ptp_init_hw(hw); ice_ptp_init_tx_interrupt_mode(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index c4b0da7ce20e..0e40fef3b4e8 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -249,6 +249,15 @@ struct ice_ptp_pin_desc { * @tx_hwtstamp_discarded: number of Tx skbs discarded due to cached PHC time * being too old to correctly extend timestamp * @late_cached_phc_updates: number of times cached PHC update is late + * @tspll_locked: last observed TSPLL lock state on E825 owner PFs. + * Written by the PTP periodic worker after polling the TSPLL and + * intended to be read (without pf->dplls.lock) by the DPLL periodic + * worker in a follow-up change. Access via READ_ONCE()/WRITE_ONCE(); + * precise synchronization is not required because both workers + * converge on the same value within one poll period. + * @tspll_lock_retries: counts consecutive poll cycles in which the TSPLL + * was found unlocked. Reset to zero when lock is re-acquired. Used to + * rate-limit the lock-lost log message (~every 120 retries / ~60 s). */ struct ice_ptp { enum ice_ptp_state state; @@ -274,6 +283,8 @@ struct ice_ptp { u32 tx_hwtstamp_flushed; u32 tx_hwtstamp_discarded; u32 late_cached_phc_updates; + bool tspll_locked; + u32 tspll_lock_retries; }; #define __ptp_port_to_ptp(p) \ diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index f893dff39aac..c49f48b5ae38 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -924,7 +924,7 @@ static void ice_sriov_remap_vectors(struct ice_pf *pf, u16 restricted_id) * is correct etc. Then disable old mapping (MSI-X and queues registers), change * MSI-X and queues, rebuild VSI and enable new mapping. * - * If it is possible (driver not binded to VF) try to remap also other VFs to + * If it is possible (driver not bound to VF) try to remap also other VFs to * linearize irqs register usage. */ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 6a5875bd9c6b..4daee252e2a6 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -2612,7 +2612,6 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, u16 vlan_id = ICE_MAX_VLAN_ID + 1; u16 vlan_tpid = ETH_P_8021Q; void *daddr = NULL; - u16 eth_hdr_sz; u8 *eth_hdr; u32 act = 0; __be16 *off; @@ -2625,11 +2624,10 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, return; } - eth_hdr_sz = sizeof(dummy_eth_header); eth_hdr = s_rule->hdr_data; /* initialize the ether header with a dummy header */ - memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); + ice_fill_eth_hdr(eth_hdr); ice_fill_sw_info(hw, f_info); switch (f_info->fltr_act) { @@ -2730,7 +2728,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, /* Create the switch rule with the final dummy Ethernet header */ if (opc != ice_aqc_opc_update_sw_rules) - s_rule->hdr_len = cpu_to_le16(eth_hdr_sz); + s_rule->hdr_len = cpu_to_le16(DUMMY_ETH_HDR_LEN); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h index 7568c917cdbe..7c43683a77d4 100644 --- a/drivers/net/ethernet/intel/ice/ice_trace.h +++ b/drivers/net/ethernet/intel/ice/ice_trace.h @@ -261,6 +261,24 @@ DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_req); DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_done); DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_complete); +/* Trace event for Rx timestamp */ +TRACE_EVENT(ice_rx_hwtstamp, + TP_PROTO(u64 cached_time, u32 ts_high, u64 ts_ns), + + TP_ARGS(cached_time, ts_high, ts_ns), + + TP_STRUCT__entry(__field(u64, cached_time) + __field(u32, ts_high) + __field(u64, ts_ns)), + + TP_fast_assign(__entry->cached_time = cached_time; + __entry->ts_high = ts_high; + __entry->ts_ns = ts_ns;), + + TP_printk("cached_time=%llu ts_high=%u ts_ns=%llu", + __entry->cached_time, __entry->ts_high, __entry->ts_ns) +); + DECLARE_EVENT_CLASS(ice_esw_br_fdb_template, TP_PROTO(struct ice_esw_br_fdb_entry *fdb), TP_ARGS(fdb), diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.c b/drivers/net/ethernet/intel/ice/ice_tspll.c index fd4b58eb9bc0..85bacb7c3a79 100644 --- a/drivers/net/ethernet/intel/ice/ice_tspll.c +++ b/drivers/net/ethernet/intel/ice/ice_tspll.c @@ -129,7 +129,7 @@ static bool ice_tspll_check_params(struct ice_hw *hw, * * Return: specified clock source converted to its string name */ -static const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src) +const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src) { switch (clk_src) { case ICE_CLK_SRC_TCXO: @@ -334,8 +334,9 @@ static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw) * Return: * * %0 - success * * %-EINVAL - input parameters are incorrect - * * %-EBUSY - failed to lock TSPLL - * * %other - CGU read/write failure + * * %-EAGAIN - TSPLL configuration succeeded but lock is not acquired yet + * * %-EBUSY - CGU access is busy (for example during reset) + * * %other - other CGU read/write failures */ static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, enum ice_clk_src clk_src) @@ -467,7 +468,7 @@ static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, if (!(val & ICE_CGU_RO_LOCK_TRUE_LOCK)) { dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); - return -EBUSY; + return -EAGAIN; } err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); @@ -532,6 +533,62 @@ int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable) } /** + * ice_tspll_lost_lock_e825c - check if TSPLL lost lock + * @hw: Pointer to the HW struct + * @lost_lock: Output flag for reporting lost lock + * + * Get E825 device TSPLL DPLL lock status. + * + * Return: + * * 0 - OK + * * negative - error + */ +int ice_tspll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock) +{ + u32 val; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); + if (err) + return err; + + *lost_lock = !FIELD_GET(ICE_CGU_RO_LOCK_TRUE_LOCK, val); + + return 0; +} + +/** + * ice_tspll_restart_e825c - trigger TSPLL restart + * @hw: Pointer to the HW struct + * + * Re-enable TSPLL for E825 device. + * + * Return: + * * 0 - OK + * * negative - error + */ +int ice_tspll_restart_e825c(struct ice_hw *hw) +{ + u32 val; + int err; + + /* Read the initial values of r23 and disable the PLL */ + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &val); + if (err) + return err; + + val &= ~ICE_CGU_R23_R24_TSPLL_ENABLE; + err = ice_write_cgu_reg(hw, ICE_CGU_R23, val); + if (err) + return err; + + /* Wait at least 1 ms before reenabling PLL */ + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); + val |= ICE_CGU_R23_R24_TSPLL_ENABLE; + return ice_write_cgu_reg(hw, ICE_CGU_R23, val); +} + +/** * ice_tspll_cfg - Configure the Clock Generation Unit TSPLL * @hw: Pointer to the HW struct * @clk_freq: Clock frequency to program @@ -578,6 +635,61 @@ static int ice_tspll_dis_sticky_bits(struct ice_hw *hw) } /** + * ice_tspll_get_clk_src - get current TSPLL clock source + * @hw: board private hw structure + * @clk_src: pointer to store clk_src value + * + * Get current TSPLL clock source settings. + * + * Return: + * * 0 - OK + * * negative - error + */ +int ice_tspll_get_clk_src(struct ice_hw *hw, enum ice_clk_src *clk_src) +{ + u32 val; + int err; + + err = (hw->mac_type == ICE_MAC_GENERIC_3K_E825) ? + ice_read_cgu_reg(hw, ICE_CGU_R23, &val) : + ice_read_cgu_reg(hw, ICE_CGU_R24, &val); + if (err) + return err; + + *clk_src = (enum ice_clk_src)FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, + val); + + return 0; +} + +/** + * ice_tspll_set_cfg - configure TS PLL with new settings + * @hw: board private hw structure + * @clk_freq: clock frequency to program + * @clk_src: clock source to select (TIME_REF, or TCXO) + * + * Configure CGU with new clock source and clock frequency settings. + * + * Return: + * * 0 - OK + * * negative - error + */ +int ice_tspll_set_cfg(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + int ret; + + if (!ice_tspll_check_params(hw, clk_freq, clk_src)) + return -EINVAL; + + ret = ice_tspll_dis_sticky_bits(hw); + if (ret) + return ret; + + return ice_tspll_cfg(hw, clk_freq, clk_src); +} + +/** * ice_tspll_init - Initialize TSPLL with settings from firmware * @hw: Pointer to the HW structure * diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.h b/drivers/net/ethernet/intel/ice/ice_tspll.h index d650867004d1..832c049e686c 100644 --- a/drivers/net/ethernet/intel/ice/ice_tspll.h +++ b/drivers/net/ethernet/intel/ice/ice_tspll.h @@ -32,6 +32,11 @@ struct ice_tspll_params_e82x { #define ICE_TSPLL_FBDIV_INTGR_E825 256 int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable); +int ice_tspll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock); +int ice_tspll_restart_e825c(struct ice_hw *hw); +int ice_tspll_get_clk_src(struct ice_hw *hw, enum ice_clk_src *clk_src); +int ice_tspll_set_cfg(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src); int ice_tspll_init(struct ice_hw *hw); int ice_tspll_bypass_mux_active_e825c(struct ice_hw *hw, u8 port, bool *active, enum ice_synce_clk output); @@ -39,4 +44,5 @@ int ice_tspll_cfg_bypass_mux_e825c(struct ice_hw *hw, bool ena, u32 port_num, enum ice_synce_clk output); int ice_tspll_cfg_synce_ethdiv_e825c(struct ice_hw *hw, enum ice_synce_clk output); +const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src); #endif /* _ICE_TSPLL_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_txclk.c b/drivers/net/ethernet/intel/ice/ice_txclk.c index 48459f971cbf..3bca4443f03a 100644 --- a/drivers/net/ethernet/intel/ice/ice_txclk.c +++ b/drivers/net/ethernet/intel/ice/ice_txclk.c @@ -286,12 +286,9 @@ void ice_txclk_update_and_notify(struct ice_pf *pf) if (ctrl_pf != pf) mutex_lock(&ctrl_pf->dplls.lock); for (int i = 0; i < ICE_REF_CLK_MAX; i++) { - if (clk == i) - set_bit(ptp_port->port_num, - &ctrl_pf->ptp.tx_refclks[phy][i]); - else - clear_bit(ptp_port->port_num, - &ctrl_pf->ptp.tx_refclks[phy][i]); + assign_bit(ptp_port->port_num, + &ctrl_pf->ptp.tx_refclks[phy][i], + clk == i); } if (ctrl_pf != pf) mutex_unlock(&ctrl_pf->dplls.lock); @@ -315,13 +312,10 @@ void ice_txclk_update_and_notify(struct ice_pf *pf) */ if (ctrl_pf != pf) mutex_lock(&ctrl_pf->dplls.lock); - for (int i = 0; i < ICE_REF_CLK_MAX; i++) - if (clk == i) - set_bit(ptp_port->port_num, - &ctrl_pf->ptp.tx_refclks[phy][i]); - else - clear_bit(ptp_port->port_num, - &ctrl_pf->ptp.tx_refclks[phy][i]); + for (int i = 0; i < ICE_REF_CLK_MAX; i++) { + assign_bit(ptp_port->port_num, + &ctrl_pf->ptp.tx_refclks[phy][i], clk == i); + } if (ctrl_pf != pf) mutex_unlock(&ctrl_pf->dplls.lock); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index cf147a212707..b8bdd7e8c768 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -529,8 +529,8 @@ struct ice_flash_info { struct ice_nvm_info nvm; /* NVM version information */ struct ice_netlist_info netlist;/* Netlist version info */ struct ice_bank_info banks; /* Flash Bank information */ - u16 sr_words; /* Shadow RAM size in words */ u32 flash_size; /* Size of available flash in bytes */ + u16 sr_words; /* Shadow RAM size in words */ u8 blank_nvm_mode; /* is NVM empty (no FW present) */ }; @@ -1019,8 +1019,8 @@ struct ice_hw { struct mutex fl_profs_locks[ICE_BLK_COUNT]; /* lock fltr profiles */ struct list_head fl_profs[ICE_BLK_COUNT]; - /* Flow Director filter info */ - int fdir_active_fltr; + /* ntuple filter info */ + int ntuple_active_fltr_cnt; struct mutex fdir_fltr_lock; /* protect Flow Director */ struct list_head fdir_list_head; diff --git a/drivers/net/ethernet/intel/ice/virt/fdir.c b/drivers/net/ethernet/intel/ice/virt/fdir.c index 4f1f3442e52c..eca9eda04f31 100644 --- a/drivers/net/ethernet/intel/ice/virt/fdir.c +++ b/drivers/net/ethernet/intel/ice/virt/fdir.c @@ -38,7 +38,7 @@ enum ice_fdir_tunnel_type { }; struct virtchnl_fdir_fltr_conf { - struct ice_fdir_fltr input; + struct ice_ntuple_fltr input; enum ice_fdir_tunnel_type ttype; u64 inset_flag; u32 flow_id; @@ -567,12 +567,12 @@ static bool ice_vc_fdir_has_prof_conflict(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf) { - struct ice_fdir_fltr *desc; + struct ice_ntuple_fltr *desc; list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { struct virtchnl_fdir_fltr_conf *existing_conf; enum ice_fltr_ptype flow_type_a, flow_type_b; - struct ice_fdir_fltr *a, *b; + struct ice_ntuple_fltr *a, *b; existing_conf = to_fltr_conf_from_desc(desc); a = &existing_conf->input; @@ -748,7 +748,7 @@ static int ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, struct virtchnl_fdir_fltr_conf *conf, int tun) { - struct ice_fdir_fltr *input = &conf->input; + struct ice_ntuple_fltr *input = &conf->input; struct device *dev = ice_pf_to_dev(vf->pf); struct ice_flow_seg_info *seg; enum ice_fltr_ptype flow; @@ -924,8 +924,8 @@ ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE; enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE; + struct ice_ntuple_fltr *input = &conf->input; struct device *dev = ice_pf_to_dev(vf->pf); - struct ice_fdir_fltr *input = &conf->input; int i; if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) { @@ -1150,8 +1150,8 @@ ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, struct virtchnl_fdir_fltr_conf *conf) { struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set; + struct ice_ntuple_fltr *input = &conf->input; struct device *dev = ice_pf_to_dev(vf->pf); - struct ice_fdir_fltr *input = &conf->input; u32 dest_num = 0; u32 mark_num = 0; int i; @@ -1249,8 +1249,8 @@ static bool ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a, struct virtchnl_fdir_fltr_conf *conf_b) { - struct ice_fdir_fltr *a = &conf_a->input; - struct ice_fdir_fltr *b = &conf_b->input; + struct ice_ntuple_fltr *a = &conf_a->input; + struct ice_ntuple_fltr *b = &conf_b->input; if (conf_a->ttype != conf_b->ttype) return false; @@ -1288,7 +1288,7 @@ ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a, static bool ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf) { - struct ice_fdir_fltr *desc; + struct ice_ntuple_fltr *desc; bool ret; list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { @@ -1317,7 +1317,7 @@ static int ice_vc_fdir_insert_entry(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, u32 *id) { - struct ice_fdir_fltr *input = &conf->input; + struct ice_ntuple_fltr *input = &conf->input; int i; /* alloc ID corresponding with conf */ @@ -1341,7 +1341,7 @@ static void ice_vc_fdir_remove_entry(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, u32 id) { - struct ice_fdir_fltr *input = &conf->input; + struct ice_ntuple_fltr *input = &conf->input; idr_remove(&vf->fdir.fdir_rule_idr, id); list_del(&input->fltr_node); @@ -1367,7 +1367,7 @@ ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id) static void ice_vc_fdir_flush_entry(struct ice_vf *vf) { struct virtchnl_fdir_fltr_conf *conf; - struct ice_fdir_fltr *desc, *temp; + struct ice_ntuple_fltr *desc, *temp; list_for_each_entry_safe(desc, temp, &vf->fdir.fdir_rule_list, fltr_node) { @@ -1390,7 +1390,7 @@ static int ice_vc_fdir_write_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, bool add, bool is_tun) { - struct ice_fdir_fltr *input = &conf->input; + struct ice_ntuple_fltr *input = &conf->input; struct ice_vsi *vsi, *ctrl_vsi; struct ice_fltr_desc desc; struct device *dev; @@ -2315,7 +2315,7 @@ int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg) struct virtchnl_fdir_fltr_conf *conf; struct ice_vf_fdir *fdir = &vf->fdir; enum virtchnl_status_code v_ret; - struct ice_fdir_fltr *input; + struct ice_ntuple_fltr *input; enum ice_fltr_ptype flow; struct device *dev; struct ice_pf *pf; diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c index 431c9c546b04..ac7f98479b13 100644 --- a/drivers/net/ethernet/intel/ice/virt/queues.c +++ b/drivers/net/ethernet/intel/ice/virt/queues.c @@ -375,6 +375,8 @@ int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id) * @msg: pointer to the msg buffer * * called from the VF to disable all or specific queue(s) + * + * Return: exit code of sending the virtchnl response. */ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) { @@ -424,20 +426,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) } q_map = vqs->rx_queues; - /* speed up Rx queue disable by batching them if possible */ - if (q_map && - bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) { - if (ice_vsi_stop_all_rx_rings(vsi)) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n", - vsi->vsi_num); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) - ice_vf_dis_rxq_interrupt(vsi, vf_q_id); - bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF); - } else if (q_map) { + if (q_map) { for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 470bc23c844c..f214023095ee 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -604,6 +604,16 @@ struct idpf_vport_config { DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS); }; +/** + * struct idpf_edt_caps_ilog2 - Host parsed EDT capabilities. + * @time_horizon_ns: Total time window in nanoseconds. + * @tstamp_granularity_pow2: Log2 of timestamp granularity in nanoseconds. + */ +struct idpf_edt_caps_ilog2 { + u32 time_horizon_ns; + u8 tstamp_granularity_pow2; +}; + #define idpf_for_each_vport(adapter, iter) \ for (struct idpf_vport **__##iter = &(adapter)->vports[0], \ *iter = (adapter)->max_vports ? *__##iter : NULL; \ @@ -657,6 +667,7 @@ struct idpf_vport_config { * @stats_task: Periodic statistics retrieval task * @stats_wq: Workqueue for statistics task * @caps: Negotiated capabilities with device + * @edt_caps: Negotiated EDT capabilities with device * @dev_ops: See idpf_dev_ops * @cdev_info: IDC core device info pointer * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk @@ -720,6 +731,7 @@ struct idpf_adapter { struct delayed_work stats_task; struct workqueue_struct *stats_wq; struct virtchnl2_get_capabilities caps; + struct idpf_edt_caps_ilog2 edt_caps; struct idpf_dev_ops dev_ops; struct iidc_rdma_core_dev_info *cdev_info; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 827c795afcb6..cd1b173e3b27 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -817,6 +817,21 @@ static void idpf_attach_and_open(struct idpf_adapter *adapter) } } +static void idpf_vport_set_pacing_offload(struct idpf_vport *vport, + struct net_device *netdev) +{ + struct idpf_adapter *adapter = vport->adapter; + u32 max_horizon = 0; + + if (adapter->edt_caps.time_horizon_ns && + idpf_is_queue_model_split(vport->dflt_qv_rsrc.txq_model) && + !idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, + VIRTCHNL2_CAP_SPLITQ_QSCHED)) + max_horizon = adapter->edt_caps.time_horizon_ns; + + WRITE_ONCE(netdev->max_pacing_offload_horizon, max_horizon); +} + /** * idpf_cfg_netdev - Allocate, configure and register a netdev * @vport: main vport structure @@ -850,6 +865,8 @@ static int idpf_cfg_netdev(struct idpf_vport *vport) np->max_tx_hdr_size = idpf_get_max_tx_hdr_size(adapter); vport->netdev = netdev; + idpf_vport_set_pacing_offload(vport, netdev); + return idpf_init_mac_addr(vport, netdev); } @@ -890,6 +907,8 @@ static int idpf_cfg_netdev(struct idpf_vport *vport) netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = vport->max_mtu; + idpf_vport_set_pacing_offload(vport, netdev); + dflt_features = NETIF_F_SG | NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 4311ffa30bb1..885df6294ad9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -487,7 +487,6 @@ static void idpf_rx_desc_rel_bufq(struct idpf_buf_queue *bufq, /** * idpf_rx_desc_rel_all - Free Rx Resources for All Queues - * @vport: virtual port structure * @rsrc: pointer to queue and vector resources * * Free all rx queues resources @@ -1394,7 +1393,6 @@ static void idpf_rxq_group_rel(struct idpf_q_vec_rsrc *rsrc) /** * idpf_vport_queue_grp_rel_all - Release all queue groups - * @vport: vport to release queue groups for * @rsrc: pointer to queue and vector resources */ static void idpf_vport_queue_grp_rel_all(struct idpf_q_vec_rsrc *rsrc) @@ -1742,6 +1740,7 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, q->desc_count = rsrc->txq_desc_count; q->tx_max_bufs = idpf_get_max_tx_bufs(adapter); q->tx_min_pkt_len = idpf_get_min_tx_pkt_len(adapter); + q->ts_gran_pow2 = adapter->edt_caps.tstamp_granularity_pow2; q->netdev = vport->netdev; q->txq_grp = tx_qgrp; q->rel_q_id = j; @@ -2408,7 +2407,12 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc, struct idpf_tx_splitq_params *params, u16 td_cmd, u16 size) { - *(__le32 *)&desc->flow.qw1.cmd_dtype = cpu_to_le32((u8)(params->dtype | td_cmd)); + desc->flow.qw1.cmd_dtype = (u8)(params->dtype | td_cmd); + + desc->flow.qw1.ts[0] = params->offload.desc_ts[0]; + desc->flow.qw1.ts[1] = params->offload.desc_ts[1]; + desc->flow.qw1.ts[2] = params->offload.desc_ts[2]; + desc->flow.qw1.rxr_bufsize = cpu_to_le16((u16)size); desc->flow.qw1.compl_tag = cpu_to_le16(params->compl_tag); } @@ -3011,6 +3015,63 @@ static bool idpf_tx_splitq_need_re(struct idpf_tx_queue *tx_q) return gap >= IDPF_TX_SPLITQ_RE_MIN_GAP; } +static void idpf_tx_splitq_set_txtime(const struct sk_buff *skb, + const struct idpf_tx_queue *tx_q, + struct idpf_tx_splitq_params *tx_params) +{ + const int offload_slack_ns = 400; + u64 ts, now, horizon; + + if (!tx_q->netdev->pacing_offload) + return; + + horizon = READ_ONCE(tx_q->netdev->max_pacing_offload_horizon); + if (!horizon) + return; + + switch (skb->tstamp_type) { + case SKB_CLOCK_REALTIME: + ts = ktime_to_ns(ktime_add(skb->tstamp, + ktime_mono_to_any(0, TK_OFFS_TAI) - + ktime_mono_to_any(0, TK_OFFS_REAL))); + break; + case SKB_CLOCK_MONOTONIC: + ts = ktime_to_ns(ktime_mono_to_any(skb->tstamp, TK_OFFS_TAI)); + break; + case SKB_CLOCK_TAI: + ts = ktime_to_ns(skb->tstamp); + break; + default: + WARN_ON_ONCE(1); + return; + } + + now = ktime_get_clocktai_ns(); + if (ts < now + offload_slack_ns) + return; + + /* beyond offload horizon? set overflow bit only */ + if (ts > now + horizon) { + tx_params->offload.desc_ts[2] = + IDPF_TXD_FLOW_SCH_HORIZON_OVERFLOW_M; + return; + } + + ts >>= tx_q->ts_gran_pow2; + + /* 0 is valid 23b timestamp, but also means field unset. + * Increase by one to avoid this case + */ + if ((ts & 0x7fffff) == 0) { + tx_params->offload.desc_ts[0] = 1; + return; + } + + tx_params->offload.desc_ts[0] = ts & 0xff; + tx_params->offload.desc_ts[1] = (ts >> 8) & 0xff; + tx_params->offload.desc_ts[2] = ((ts >> 16) & 0x7f); +} + /** * idpf_tx_splitq_frame - Sends buffer on Tx ring using flex descriptors * @skb: send buffer @@ -3097,6 +3158,10 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE; tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP; + + if (skb->tstamp) + idpf_tx_splitq_set_txtime(skb, tx_q, &tx_params); + /* Set the RE bit periodically to "clean" the descriptor ring */ if (idpf_tx_splitq_need_re(tx_q)) { tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 93547597efd2..fe0c913f9bb9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -161,6 +161,7 @@ union idpf_tx_flex_desc { * @tso_segs: Number of segments to be sent * @tso_hdr_len: Length of headers to be duplicated * @td_cmd: Command field to be inserted into descriptor + * @desc_ts: Flow scheduling offload timestamp */ struct idpf_tx_offload_params { u32 tx_flags; @@ -174,6 +175,7 @@ struct idpf_tx_offload_params { u16 tso_hdr_len; u16 td_cmd; + u8 desc_ts[3]; }; /** @@ -608,6 +610,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, * hot path TX pointers stored in vport. Used in both singleq/splitq. * @desc_count: Number of descriptors * @tx_min_pkt_len: Min supported packet length + * @ts_gran_pow2: Txtime timestamp granularity in nanoseconds (log2). * @thresh: XDP queue cleaning threshold * @netdev: &net_device corresponding to this queue * @next_to_use: Next descriptor to use @@ -666,7 +669,10 @@ struct idpf_tx_queue { u16 desc_count; union { - u16 tx_min_pkt_len; + struct { + u16 tx_min_pkt_len; + u8 ts_gran_pow2; + }; u32 thresh; }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 1caf52706973..928de868fa62 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3,6 +3,7 @@ #include <linux/export.h> #include <linux/net/intel/libie/pci.h> +#include <linux/log2.h> #include <net/libeth/rx.h> #include "idpf.h" @@ -553,7 +554,8 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter) VIRTCHNL2_CAP_SPLITQ_QSCHED | VIRTCHNL2_CAP_PROMISC | VIRTCHNL2_CAP_LOOPBACK | - VIRTCHNL2_CAP_PTP); + VIRTCHNL2_CAP_PTP | + VIRTCHNL2_CAP_EDT); err = idpf_send_mb_msg_stack(adapter, &xn_params, &caps); if (err) @@ -574,6 +576,54 @@ free_rx_buf: } /** + * idpf_send_get_edt_caps_msg - Send virtchnl get EDT caps msg + * @adapter: Driver specific private struct + * + * Return: 0 on success or error code on failure. + */ +static int idpf_send_get_edt_caps_msg(struct idpf_adapter *adapter) +{ + struct libie_ctlq_xn_send_params xn_params = { + .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC, + .chnl_opcode = VIRTCHNL2_OP_GET_EDT_CAPS, + }; + struct virtchnl2_edt_caps caps = {}; + u64 gran_ns, horizon_ns; + int err; + + err = idpf_send_mb_msg_stack(adapter, &xn_params, &caps); + if (err) + return err; + + if (xn_params.recv_mem.iov_len < sizeof(caps)) { + err = -EIO; + goto free_rx_buf; + } + + memcpy(&caps, xn_params.recv_mem.iov_base, sizeof(caps)); + horizon_ns = le64_to_cpu(caps.time_horizon_ns); + gran_ns = le64_to_cpu(caps.tstamp_granularity_ns); + if (horizon_ns > U32_MAX) { + dev_warn(&adapter->pdev->dev, "EDT horizon exceeds U32\n"); + err = -EINVAL; + goto free_rx_buf; + } + if (!gran_ns || !is_power_of_2(gran_ns)) { + dev_warn(&adapter->pdev->dev, "Invalid EDT granularity\n"); + err = -EINVAL; + goto free_rx_buf; + } + + adapter->edt_caps.time_horizon_ns = horizon_ns; + adapter->edt_caps.tstamp_granularity_pow2 = ilog2(gran_ns); + +free_rx_buf: + libie_ctlq_release_rx_buf(&xn_params.recv_mem); + + return err; +} + +/** * idpf_mmio_region_non_static - Check if region is not static * @mmio_info: PCI resources info * @reg: region to check @@ -3085,6 +3135,14 @@ restart: } } + memset(&adapter->edt_caps, 0, sizeof(adapter->edt_caps)); + if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_EDT)) { + err = idpf_send_get_edt_caps_msg(adapter); + if (err) + dev_err(&adapter->pdev->dev, + "EDT init failed, err=%d\n", err); + } + pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter)); num_max_vports = idpf_get_max_vports(adapter); adapter->vports = kzalloc_objs(*adapter->vports, num_max_vports); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 7ce46b4b4821..7eb4acf59dab 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3995,7 +3995,7 @@ static void ixgbevf_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc, if (tx_flags & IXGBE_TX_FLAGS_CSUM) olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM); - /* enble IPv4 checksum for TSO */ + /* enable IPv4 checksum for TSO */ if (tx_flags & IXGBE_TX_FLAGS_IPV4) olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM); |
