summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel')
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c19
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c9
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c12
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c70
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c12
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.c8
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h17
-rw-r--r--drivers/net/ethernet/intel/ice/ice_arfs.c8
-rw-r--r--drivers/net/ethernet/intel/ice/ice_arfs.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_nl.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c495
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c14
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool_ntuple.c (renamed from drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c)145
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fdir.c38
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fdir.h14
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c354
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_parser.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c84
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.h11
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_trace.h18
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tspll.c120
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tspll.h6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txclk.c20
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h6
-rw-r--r--drivers/net/ethernet/intel/ice/virt/fdir.c28
-rw-r--r--drivers/net/ethernet/intel/ice/virt/queues.c17
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h12
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c19
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c71
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.h8
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c60
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c2
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);