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/Kconfig2
-rw-r--r--drivers/net/ethernet/intel/Makefile1
-rw-r--r--drivers/net/ethernet/intel/e100.c11
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c30
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c22
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h1
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h4
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c25
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c34
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c535
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h14
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_client.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debug.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c8
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c44
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_hmc.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c150
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c19
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_register.h10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_trace.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c9
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c24
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h14
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq.h2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_common.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c158
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c205
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_prototype.h3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ptp.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_type.h2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_types.h4
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c89
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/devlink.c71
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/port.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h48
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adapter.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adapter.h7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_arfs.c9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c126
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_cpi.c362
-rw-r--r--drivers/net/ethernet/intel/ice/ice_cpi.h58
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.c14
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c1412
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.h66
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch_br.c22
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c177
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flex_pipe.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flow.c8
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fw_update.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_gnss.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_idc.c50
-rw-r--r--drivers/net/ethernet/intel/ice/ice_irq.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c160
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c456
-rw-r--r--drivers/net/ethernet/intel/ice/ice_nvm.c90
-rw-r--r--drivers/net/ethernet/intel/ice/ice_nvm.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_parser.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c312
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.h24
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_consts.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.c376
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.h24
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sbq_cmd.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sf_eth.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c16
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c18
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tc_lib.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_trace.h64
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tspll.c217
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tspll.h13
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txclk.c354
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txclk.h40
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c104
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.h205
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.c5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c45
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib_private.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c26
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c12
-rw-r--r--drivers/net/ethernet/intel/ice/virt/fdir.c6
-rw-r--r--drivers/net/ethernet/intel/ice/virt/queues.c23
-rw-r--r--drivers/net/ethernet/intel/ice/virt/rss.c2
-rw-r--r--drivers/net/ethernet/intel/ice/virt/virtchnl.c4
-rw-r--r--drivers/net/ethernet/intel/ice/virt/virtchnl.h2
-rw-r--r--drivers/net/ethernet/intel/idpf/Kconfig1
-rw-r--r--drivers/net/ethernet/intel/idpf/Makefile2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h287
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_controlq.c623
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_controlq.h144
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_controlq_api.h177
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c171
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_dev.c120
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ethtool.c214
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_idc.c59
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c572
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_main.c122
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_mem.h20
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ptp.c27
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c973
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.h50
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_vf_dev.c114
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c2923
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.h198
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c313
-rw-r--r--drivers/net/ethernet/intel/idpf/virtchnl2.h1813
-rw-r--r--drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h451
-rw-r--r--drivers/net/ethernet/intel/idpf/xdp.c87
-rw-r--r--drivers/net/ethernet/intel/idpf/xdp.h26
-rw-r--r--drivers/net/ethernet/intel/idpf/xsk.c13
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h21
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c6
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c2
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h3
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c87
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c116
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c5
-rw-r--r--drivers/net/ethernet/intel/igb/igb_xsk.c38
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c13
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h6
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c35
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h14
-rw-r--r--drivers/net/ethernet/intel/igc/igc_diag.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c283
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h10
-rw-r--r--drivers/net/ethernet/intel/igc/igc_leds.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c35
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c133
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c71
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.h1
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c83
-rw-r--r--drivers/net/ethernet/intel/igc/igc_tsn.c17
-rw-r--r--drivers/net/ethernet/intel/ixd/Kconfig14
-rw-r--r--drivers/net/ethernet/intel/ixd/Makefile13
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd.h67
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_ctlq.c141
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_ctlq.h34
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_dev.c89
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_devlink.c99
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_devlink.h50
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_lan_regs.h68
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_lib.c173
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_main.c144
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_virtchnl.c190
-rw-r--r--drivers/net/ethernet/intel/ixd/ixd_virtchnl.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbe/devlink/devlink.c4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h29
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c7
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c6
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c89
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c241
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c11
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c256
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c45
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c6
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h32
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ipsec.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c53
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c10
-rw-r--r--drivers/net/ethernet/intel/libeth/rx.c12
-rw-r--r--drivers/net/ethernet/intel/libeth/xsk.c1
-rw-r--r--drivers/net/ethernet/intel/libie/Kconfig14
-rw-r--r--drivers/net/ethernet/intel/libie/Makefile8
-rw-r--r--drivers/net/ethernet/intel/libie/controlq.c1294
-rw-r--r--drivers/net/ethernet/intel/libie/fwlog.c67
-rw-r--r--drivers/net/ethernet/intel/libie/pci.c229
196 files changed, 11833 insertions, 8855 deletions
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 288fa8ce53af..780f113986ea 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -398,4 +398,6 @@ config IGC_LEDS
source "drivers/net/ethernet/intel/idpf/Kconfig"
+source "drivers/net/ethernet/intel/ixd/Kconfig"
+
endif # NET_VENDOR_INTEL
diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
index 9a37dc76aef0..08b29f3b6801 100644
--- a/drivers/net/ethernet/intel/Makefile
+++ b/drivers/net/ethernet/intel/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_IAVF) += iavf/
obj-$(CONFIG_FM10K) += fm10k/
obj-$(CONFIG_ICE) += ice/
obj-$(CONFIG_IDPF) += idpf/
+obj-$(CONFIG_IXD) += ixd/
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index 5c56c1edd492..29960762e64a 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -176,9 +176,12 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
-#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
- PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
+#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) { \
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, (device_id)), \
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8, \
+ .class_mask = 0xFFFF00, \
+ .driver_data = (ich) }
+
static const struct pci_device_id e100_id_table[] = {
INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
@@ -2156,7 +2159,7 @@ static int e100_rx_alloc_list(struct nic *nic)
nic->rx_to_use = nic->rx_to_clean = NULL;
nic->ru_running = RU_UNINITIALIZED;
- if (!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_KERNEL)))
+ if (!(nic->rxs = kzalloc_objs(struct rx, count)))
return -ENOMEM;
for (rx = nic->rxs, i = 0; i < count; rx++, i++) {
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 726365c567ef..c15ad95c63c1 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -496,19 +496,26 @@ static int e1000_set_eeprom(struct net_device *netdev,
*/
ret_val = e1000_read_eeprom(hw, first_word, 1,
&eeprom_buff[0]);
+ if (ret_val)
+ goto out;
+
+ /* Device's eeprom is always little-endian, word addressable */
+ le16_to_cpus(&eeprom_buff[0]);
+
ptr++;
}
- if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
+ if ((eeprom->offset + eeprom->len) & 1) {
/* need read/modify/write of last changed EEPROM word
* only the first byte of the word is being modified
*/
ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
- }
+ if (ret_val)
+ goto out;
- /* Device's eeprom is always little-endian, word addressable */
- for (i = 0; i < last_word - first_word + 1; i++)
- le16_to_cpus(&eeprom_buff[i]);
+ /* Device's eeprom is always little-endian, word addressable */
+ le16_to_cpus(&eeprom_buff[last_word - first_word]);
+ }
memcpy(ptr, bytes, eeprom->len);
@@ -522,6 +529,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
if ((ret_val == 0) && (first_word <= EEPROM_CHECKSUM_REG))
e1000_update_eeprom_checksum(hw);
+out:
kfree(eeprom_buff);
return ret_val;
}
@@ -582,13 +590,11 @@ static int e1000_set_ringparam(struct net_device *netdev,
rx_old = adapter->rx_ring;
err = -ENOMEM;
- txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring),
- GFP_KERNEL);
+ txdr = kzalloc_objs(struct e1000_tx_ring, adapter->num_tx_queues);
if (!txdr)
goto err_alloc_tx;
- rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring),
- GFP_KERNEL);
+ rxdr = kzalloc_objs(struct e1000_rx_ring, adapter->num_rx_queues);
if (!rxdr)
goto err_alloc_rx;
@@ -984,8 +990,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!txdr->count)
txdr->count = E1000_DEFAULT_TXD;
- txdr->buffer_info = kcalloc(txdr->count, sizeof(struct e1000_tx_buffer),
- GFP_KERNEL);
+ txdr->buffer_info = kzalloc_objs(struct e1000_tx_buffer, txdr->count);
if (!txdr->buffer_info) {
ret_val = 1;
goto err_nomem;
@@ -1043,8 +1048,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!rxdr->count)
rxdr->count = E1000_DEFAULT_RXD;
- rxdr->buffer_info = kcalloc(rxdr->count, sizeof(struct e1000_rx_buffer),
- GFP_KERNEL);
+ rxdr->buffer_info = kzalloc_objs(struct e1000_rx_buffer, rxdr->count);
if (!rxdr->buffer_info) {
ret_val = 5;
goto err_nomem;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 292389aceb2d..d7f5c6f16142 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -1222,11 +1222,11 @@ err_eeprom:
if (hw->flash_address)
iounmap(hw->flash_address);
+err_mdio_ioremap:
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
err_dma:
err_sw_init:
-err_mdio_ioremap:
iounmap(hw->ce4100_gbe_mdio_base_virt);
iounmap(hw->hw_addr);
err_ioremap:
@@ -1322,13 +1322,13 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
**/
static int e1000_alloc_queues(struct e1000_adapter *adapter)
{
- adapter->tx_ring = kcalloc(adapter->num_tx_queues,
- sizeof(struct e1000_tx_ring), GFP_KERNEL);
+ adapter->tx_ring = kzalloc_objs(struct e1000_tx_ring,
+ adapter->num_tx_queues);
if (!adapter->tx_ring)
return -ENOMEM;
- adapter->rx_ring = kcalloc(adapter->num_rx_queues,
- sizeof(struct e1000_rx_ring), GFP_KERNEL);
+ adapter->rx_ring = kzalloc_objs(struct e1000_rx_ring,
+ adapter->num_rx_queues);
if (!adapter->rx_ring) {
kfree(adapter->tx_ring);
return -ENOMEM;
@@ -2952,8 +2952,6 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
@@ -4094,7 +4092,15 @@ static bool e1000_tbi_should_accept(struct e1000_adapter *adapter,
u32 length, const u8 *data)
{
struct e1000_hw *hw = &adapter->hw;
- u8 last_byte = *(data + length - 1);
+ u8 last_byte;
+
+ /* Guard against OOB on data[length - 1] */
+ if (unlikely(!length))
+ return false;
+ /* Upper bound: length must not exceed rx_buffer_len */
+ if (unlikely(length > adapter->rx_buffer_len))
+ return false;
+ last_byte = *(data + length - 1);
if (TBI_ACCEPT(hw, status, errors, length, last_byte)) {
unsigned long irq_flags;
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index ba331899d186..d4a1041e456d 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -33,6 +33,7 @@
/* Extended Device Control */
#define E1000_CTRL_EXT_LPCD 0x00000004 /* LCD Power Cycle Done */
+#define E1000_CTRL_EXT_DPG_EN 0x00000008 /* Dynamic Power Gating Enable */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index aa08f397988e..63ebe00376f5 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -117,7 +117,8 @@ enum e1000_boards {
board_pch_cnp,
board_pch_tgp,
board_pch_adp,
- board_pch_mtp
+ board_pch_mtp,
+ board_pch_ptp
};
struct e1000_ps_page {
@@ -527,6 +528,7 @@ extern const struct e1000_info e1000_pch_cnp_info;
extern const struct e1000_info e1000_pch_tgp_info;
extern const struct e1000_info e1000_pch_adp_info;
extern const struct e1000_info e1000_pch_mtp_info;
+extern const struct e1000_info e1000_pch_ptp_info;
extern const struct e1000_info e1000_es2_info;
void e1000e_ptp_init(struct e1000_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 7b1ac90b3de4..a8b35ae41141 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -583,20 +583,25 @@ static int e1000_set_eeprom(struct net_device *netdev,
/* need read/modify/write of first changed EEPROM word */
/* only the second byte of the word is being modified */
ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]);
+ if (ret_val)
+ goto out;
+
+ /* Device's eeprom is always little-endian, word addressable */
+ le16_to_cpus(&eeprom_buff[0]);
+
ptr++;
}
- if (((eeprom->offset + eeprom->len) & 1) && (!ret_val))
+ if ((eeprom->offset + eeprom->len) & 1) {
/* need read/modify/write of last changed EEPROM word */
/* only the first byte of the word is being modified */
ret_val = e1000_read_nvm(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
+ if (ret_val)
+ goto out;
- if (ret_val)
- goto out;
-
- /* Device's eeprom is always little-endian, word addressable */
- for (i = 0; i < last_word - first_word + 1; i++)
- le16_to_cpus(&eeprom_buff[i]);
+ /* Device's eeprom is always little-endian, word addressable */
+ le16_to_cpus(&eeprom_buff[last_word - first_word]);
+ }
memcpy(ptr, bytes, eeprom->len);
@@ -1173,8 +1178,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!tx_ring->count)
tx_ring->count = E1000_DEFAULT_TXD;
- tx_ring->buffer_info = kcalloc(tx_ring->count,
- sizeof(struct e1000_buffer), GFP_KERNEL);
+ tx_ring->buffer_info = kzalloc_objs(struct e1000_buffer, tx_ring->count);
if (!tx_ring->buffer_info) {
ret_val = 1;
goto err_nomem;
@@ -1234,8 +1238,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!rx_ring->count)
rx_ring->count = E1000_DEFAULT_RXD;
- rx_ring->buffer_info = kcalloc(rx_ring->count,
- sizeof(struct e1000_buffer), GFP_KERNEL);
+ rx_ring->buffer_info = kzalloc_objs(struct e1000_buffer, rx_ring->count);
if (!rx_ring->buffer_info) {
ret_val = 5;
goto err_nomem;
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index fc8ed38aa095..c7ac599e5a7a 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -118,8 +118,6 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_ARL_I219_V24 0x57A1
#define E1000_DEV_ID_PCH_PTP_I219_LM25 0x57B3
#define E1000_DEV_ID_PCH_PTP_I219_V25 0x57B4
-#define E1000_DEV_ID_PCH_PTP_I219_LM26 0x57B5
-#define E1000_DEV_ID_PCH_PTP_I219_V26 0x57B6
#define E1000_DEV_ID_PCH_PTP_I219_LM27 0x57B7
#define E1000_DEV_ID_PCH_PTP_I219_V27 0x57B8
#define E1000_DEV_ID_PCH_NVL_I219_LM29 0x57B9
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 0ff8688ac3b8..aa90e0ce8aca 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -528,7 +528,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->id = e1000_phy_unknown;
- if (hw->mac.type == e1000_pch_mtp) {
+ if (hw->mac.type == e1000_pch_mtp || hw->mac.type == e1000_pch_ptp) {
phy->retry_count = 2;
e1000e_enable_phy_retry(hw);
}
@@ -1594,6 +1594,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
if (speed == SPEED_100 || speed == SPEED_10)
phy_reg |= 0x3E8;
+ else if (hw->mac.type == e1000_pch_mtp ||
+ hw->mac.type == e1000_pch_ptp)
+ phy_reg |= 0x1D5;
else
phy_reg |= 0xFA;
e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg);
@@ -4932,6 +4935,15 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
reg |= E1000_KABGTXD_BGSQLBIAS;
ew32(KABGTXD, reg);
+ /* The hardware reset value of the DPG_EN bit is 1.
+ * Clear DPG_EN to prevent unexpected autonomous power gating.
+ */
+ if (hw->mac.type >= e1000_pch_ptp) {
+ reg = er32(CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_DPG_EN;
+ ew32(CTRL_EXT, reg);
+ }
+
return 0;
}
@@ -6208,3 +6220,23 @@ const struct e1000_info e1000_pch_mtp_info = {
.phy_ops = &ich8_phy_ops,
.nvm_ops = &spt_nvm_ops,
};
+
+const struct e1000_info e1000_pch_ptp_info = {
+ .mac = e1000_pch_ptp,
+ .flags = FLAG_IS_ICH
+ | FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_APME_IN_WUC,
+ .flags2 = FLAG2_HAS_PHY_STATS
+ | FLAG2_HAS_EEE,
+ .pba = 26,
+ .max_hw_frame_size = 9022,
+ .get_variants = e1000_get_variants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &spt_nvm_ops,
+};
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index ddbe2f7d8112..844f31ab37ad 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -25,6 +25,7 @@
#include <linux/pm_runtime.h>
#include <linux/prefetch.h>
#include <linux/suspend.h>
+#include <linux/dmi.h>
#include "e1000.h"
#define CREATE_TRACE_POINTS
@@ -55,6 +56,18 @@ static const struct e1000_info *e1000_info_tbl[] = {
[board_pch_tgp] = &e1000_pch_tgp_info,
[board_pch_adp] = &e1000_pch_adp_info,
[board_pch_mtp] = &e1000_pch_mtp_info,
+ [board_pch_ptp] = &e1000_pch_ptp_info,
+};
+
+static const struct dmi_system_id disable_k1_list[] = {
+ {
+ .ident = "Dell Pro 16 Plus PB16250",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro 16 Plus PB16250"),
+ },
+ },
+ {}
};
struct e1000_reg_info {
@@ -1802,7 +1815,7 @@ static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __napi_schedule(&adapter->napi);
+ __napi_schedule_irqoff(&adapter->napi);
}
return IRQ_HANDLED;
@@ -1881,7 +1894,7 @@ static irqreturn_t e1000_intr(int __always_unused irq, void *data)
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __napi_schedule(&adapter->napi);
+ __napi_schedule_irqoff(&adapter->napi);
}
return IRQ_HANDLED;
@@ -1950,7 +1963,7 @@ static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
if (napi_schedule_prep(&adapter->napi)) {
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __napi_schedule(&adapter->napi);
+ __napi_schedule_irqoff(&adapter->napi);
}
return IRQ_HANDLED;
}
@@ -2050,10 +2063,8 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
case E1000E_INT_MODE_MSIX:
if (adapter->flags & FLAG_HAS_MSIX) {
adapter->num_vectors = 3; /* RxQ0, TxQ0 and other */
- adapter->msix_entries = kcalloc(adapter->num_vectors,
- sizeof(struct
- msix_entry),
- GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry,
+ adapter->num_vectors);
if (adapter->msix_entries) {
struct e1000_adapter *a = adapter;
@@ -2370,9 +2381,8 @@ int e1000e_setup_rx_resources(struct e1000_ring *rx_ring)
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
- buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS,
- sizeof(struct e1000_ps_page),
- GFP_KERNEL);
+ buffer_info->ps_pages = kzalloc_objs(struct e1000_ps_page,
+ PS_PAGE_BUFFERS);
if (!buffer_info->ps_pages)
goto err_pages;
}
@@ -3945,7 +3955,7 @@ static void e1000e_systim_reset(struct e1000_adapter *adapter)
/* reset the systim ns time counter */
spin_lock_irqsave(&adapter->systim_lock, flags);
timecounter_init(&adapter->tc, &adapter->cc,
- ktime_to_ns(ktime_get_real()));
+ ktime_get_real_ns());
spin_unlock_irqrestore(&adapter->systim_lock, flags);
/* restore the previous hwtstamp configuration settings */
@@ -5654,8 +5664,6 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
dma_error:
dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
@@ -7674,7 +7682,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* init PTP hardware clock */
e1000e_ptp_init(adapter);
- if (hw->mac.type >= e1000_pch_mtp)
+ /* disable K1 by default on known problematic systems */
+ if (hw->mac.type >= e1000_pch_mtp && dmi_check_system(disable_k1_list))
adapter->flags2 |= FLAG2_DISABLE_K1;
/* reset the hardware with the new settings */
@@ -7710,6 +7719,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_register:
if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_release_hw_control(adapter);
+ e1000e_ptp_remove(adapter);
err_eeprom:
if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw))
e1000_phy_hw_reset(&adapter->hw);
@@ -7802,139 +7812,370 @@ static const struct pci_error_handlers e1000_err_handler = {
};
static const struct pci_device_id e1000_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP),
- board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574LA), board_82574 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82583V), board_82583 },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
- board_80003es2lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
- board_80003es2lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT),
- board_80003es2lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
- board_80003es2lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_82567V_3), board_ich8lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_V), board_ich10lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan },
-
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM2), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V2), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM3), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V3), board_pch_lpt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM2), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V2), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LBG_I219_LM3), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM4), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V4), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM5), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V5), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_LM6), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_V6), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_LM7), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_V7), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM8), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V8), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM9), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V9), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM10), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V10), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM11), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V11), board_pch_cnp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM12), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V12), board_pch_spt },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM13), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V13), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_tgp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM19), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V19), board_pch_adp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_LM24), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_V24), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_mtp },
-
- { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD),
+ .driver_data = board_82571,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER),
+ .driver_data = board_82571,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI),
+ .driver_data = board_82572,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER),
+ .driver_data = board_82572,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER),
+ .driver_data = board_82572,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES),
+ .driver_data = board_82572,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E),
+ .driver_data = board_82573,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT),
+ .driver_data = board_82573,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L),
+ .driver_data = board_82573,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L),
+ .driver_data = board_82574,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574LA),
+ .driver_data = board_82574,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_82583V),
+ .driver_data = board_82583,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
+ .driver_data = board_80003es2lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
+ .driver_data = board_80003es2lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT),
+ .driver_data = board_80003es2lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
+ .driver_data = board_80003es2lan,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT),
+ .driver_data = board_ich8lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_82567V_3),
+ .driver_data = board_ich8lan,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V),
+ .driver_data = board_ich9lan
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF),
+ .driver_data = board_ich9lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V),
+ .driver_data = board_ich9lan,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM),
+ .driver_data = board_ich10lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF),
+ .driver_data = board_ich10lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_V),
+ .driver_data = board_ich10lan,
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM),
+ .driver_data = board_pchlan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC),
+ .driver_data = board_pchlan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM),
+ .driver_data = board_pchlan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC),
+ .driver_data = board_pchlan
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM),
+ .driver_data = board_pch2lan,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V),
+ .driver_data = board_pch2lan
+ },
+
+ {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM2),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V2),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM3),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V3),
+ .driver_data = board_pch_lpt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM2),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V2),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LBG_I219_LM3),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM4),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V4),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM5),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V5),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_LM6),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_V6),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_LM7),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CNP_I219_V7),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM8),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V8),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM9),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V9),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM10),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V10),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM11),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V11),
+ .driver_data = board_pch_cnp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM12),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V12),
+ .driver_data = board_pch_spt,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM13),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V13),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15),
+ .driver_data = board_pch_tgp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM19),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V19),
+ .driver_data = board_pch_adp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_LM24),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_V24),
+ .driver_data = board_pch_mtp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25),
+ .driver_data = board_pch_ptp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25),
+ .driver_data = board_pch_ptp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27),
+ .driver_data = board_pch_ptp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27),
+ .driver_data = board_pch_ptp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29),
+ .driver_data = board_pch_ptp,
+ }, {
+ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29),
+ .driver_data = board_pch_ptp
+ },
+
+ { } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index b8c15b837fda..898deb3f11c4 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -1597,7 +1597,7 @@ static int fm10k_alloc_q_vector(struct fm10k_intfc *interface,
ring_count = txr_count + rxr_count;
/* allocate q_vector and rings */
- q_vector = kzalloc(struct_size(q_vector, ring, ring_count), GFP_KERNEL);
+ q_vector = kzalloc_flex(*q_vector, ring, ring_count);
if (!q_vector)
return -ENOMEM;
@@ -1825,8 +1825,7 @@ static int fm10k_init_msix_capability(struct fm10k_intfc *interface)
v_budget = min_t(int, v_budget, hw->mac.max_msix_vectors);
/* A failure in MSI-X entry allocation is fatal. */
- interface->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
- GFP_KERNEL);
+ interface->msix_entries = kzalloc_objs(struct msix_entry, v_budget);
if (!interface->msix_entries)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
index 34ab5ff9823b..c86701be4364 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
@@ -649,7 +649,7 @@ int fm10k_queue_vlan_request(struct fm10k_intfc *interface,
/* This must be atomic since we may be called while the netdev
* addr_list_lock is held
*/
- request = kzalloc(sizeof(*request), GFP_ATOMIC);
+ request = kzalloc_obj(*request, GFP_ATOMIC);
if (!request)
return -ENOMEM;
@@ -688,7 +688,7 @@ int fm10k_queue_mac_request(struct fm10k_intfc *interface, u16 glort,
/* This must be atomic since we may be called while the netdev
* addr_list_lock is held
*/
- request = kzalloc(sizeof(*request), GFP_ATOMIC);
+ request = kzalloc_obj(*request, GFP_ATOMIC);
if (!request)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index d75b8a50413d..f5b4d062709a 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -21,12 +21,12 @@ static const struct fm10k_info *fm10k_info_tbl[] = {
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id fm10k_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf },
- { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_QDA2), fm10k_device_pf },
- { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_DA2), fm10k_device_pf },
- { PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), fm10k_device_vf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), .driver_data = fm10k_device_pf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_QDA2), .driver_data = fm10k_device_pf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_DA2), .driver_data = fm10k_device_pf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), .driver_data = fm10k_device_vf },
/* required last entry */
- { 0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, fm10k_pci_tbl);
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index d2d03db2acec..1b6a8fbaa648 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -8,8 +8,8 @@
#include <linux/pci.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/types.h>
-#include <linux/avf/virtchnl.h>
#include <linux/net/intel/i40e_client.h>
+#include <linux/net/intel/virtchnl.h>
#include <net/devlink.h>
#include <net/pkt_cls.h>
#include <net/udp_tunnel.h>
@@ -1318,6 +1318,7 @@ void i40e_ptp_restore_hw_time(struct i40e_pf *pf);
void i40e_ptp_init(struct i40e_pf *pf);
void i40e_ptp_stop(struct i40e_pf *pf);
int i40e_ptp_alloc_pins(struct i40e_pf *pf);
+void i40e_ptp_free_pins(struct i40e_pf *pf);
int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset);
int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
int i40e_get_partition_bw_setting(struct i40e_pf *pf);
@@ -1422,4 +1423,15 @@ static inline struct i40e_veb *i40e_pf_get_main_veb(struct i40e_pf *pf)
return (pf->lan_veb != I40E_NO_VEB) ? pf->veb[pf->lan_veb] : NULL;
}
+static inline u32 i40e_get_max_num_descriptors(const struct i40e_pf *pf)
+{
+ const struct i40e_hw *hw = &pf->hw;
+
+ switch (hw->mac.type) {
+ case I40E_MAC_XL710:
+ return I40E_MAX_NUM_DESCRIPTORS_XL710;
+ default:
+ return I40E_MAX_NUM_DESCRIPTORS;
+ }
+}
#endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
index 1be97a3a86ce..dcf3baec7b73 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
@@ -109,7 +109,7 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
-EFBIG, /* I40E_AQ_RC_EFBIG */
};
- if (!((u32)aq_rc < (sizeof(aq_to_posix) / sizeof((aq_to_posix)[0]))))
+ if (aq_rc >= ARRAY_SIZE(aq_to_posix))
return -ERANGE;
return aq_to_posix[aq_rc];
diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c
index 518bc738ea3b..84a97ca8a6d8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_client.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_client.c
@@ -291,7 +291,7 @@ static int i40e_register_auxiliary_dev(struct i40e_info *ldev, const char *name)
struct auxiliary_device *aux_dev;
int ret;
- i40e_aux_dev = kzalloc(sizeof(*i40e_aux_dev), GFP_KERNEL);
+ i40e_aux_dev = kzalloc_obj(*i40e_aux_dev);
if (!i40e_aux_dev)
return -ENOMEM;
@@ -337,7 +337,7 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
struct i40e_client_instance *cdev = NULL;
struct netdev_hw_addr *mac = NULL;
- cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc_obj(*cdev);
if (!cdev)
return;
@@ -466,7 +466,7 @@ int i40e_lan_add_device(struct i40e_pf *pf)
goto out;
}
}
- ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ ldev = kzalloc_obj(*ldev);
if (!ldev) {
ret = -ENOMEM;
goto out;
@@ -566,8 +566,8 @@ static int i40e_client_setup_qvlist(struct i40e_info *ldev,
struct i40e_qv_info *qv_info;
u32 v_idx, i, reg_idx, reg;
- ldev->qvlist_info = kzalloc(struct_size(ldev->qvlist_info, qv_info,
- qvlist_info->num_vectors), GFP_KERNEL);
+ ldev->qvlist_info = kzalloc_flex(*ldev->qvlist_info, qv_info,
+ qvlist_info->num_vectors);
if (!ldev->qvlist_info)
return -ENOMEM;
ldev->qvlist_info->num_vectors = qvlist_info->num_vectors;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 59f5c1e810eb..8dadfef2c09f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2021 Intel Corporation. */
-#include <linux/avf/virtchnl.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/pci.h>
#include "i40e_adminq_cmd.h"
#include "i40e_devids.h"
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debug.h b/drivers/net/ethernet/intel/i40e/i40e_debug.h
index e9871dfb32bd..01fd70db9086 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debug.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_debug.h
@@ -42,7 +42,7 @@ struct device *i40e_hw_to_dev(struct i40e_hw *hw);
#define i40e_debug(h, m, s, ...) \
do { \
if (((m) & (h)->debug_mask)) \
- dev_info(i40e_hw_to_dev(hw), s, ##__VA_ARGS__); \
+ dev_info(i40e_hw_to_dev(h), s, ##__VA_ARGS__); \
} while (0)
#endif /* _I40E_DEBUG_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index c17b5d290f0a..0b52509cb14c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -983,9 +983,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
int i, ret;
u16 switch_id;
- bw_data = kzalloc(sizeof(
- struct i40e_aqc_query_port_ets_config_resp),
- GFP_KERNEL);
+ bw_data = kzalloc_obj(struct i40e_aqc_query_port_ets_config_resp);
if (!bw_data) {
ret = -ENOMEM;
goto command_write_done;
@@ -1229,7 +1227,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
struct libie_aq_desc *desc;
int ret;
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ desc = kzalloc_obj(*desc);
if (!desc)
goto command_write_done;
cnt = sscanf(&cmd_buf[11],
@@ -1277,7 +1275,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
u8 *buff;
int ret;
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ desc = kzalloc_obj(*desc);
if (!desc)
goto command_write_done;
cnt = sscanf(&cmd_buf[20],
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index f2c2646ea298..3da9ec49cc74 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -2013,18 +2013,6 @@ static void i40e_get_drvinfo(struct net_device *netdev,
drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN;
}
-static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf)
-{
- struct i40e_hw *hw = &pf->hw;
-
- switch (hw->mac.type) {
- case I40E_MAC_XL710:
- return I40E_MAX_NUM_DESCRIPTORS_XL710;
- default:
- return I40E_MAX_NUM_DESCRIPTORS;
- }
-}
-
static void i40e_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -2132,8 +2120,7 @@ static int i40e_set_ringparam(struct net_device *netdev,
netdev_info(netdev,
"Changing Tx descriptor count from %d to %d.\n",
vsi->tx_rings[0]->count, new_tx_count);
- tx_rings = kcalloc(tx_alloc_queue_pairs,
- sizeof(struct i40e_ring), GFP_KERNEL);
+ tx_rings = kzalloc_objs(struct i40e_ring, tx_alloc_queue_pairs);
if (!tx_rings) {
err = -ENOMEM;
goto done;
@@ -2171,8 +2158,8 @@ static int i40e_set_ringparam(struct net_device *netdev,
netdev_info(netdev,
"Changing Rx descriptor count from %d to %d\n",
vsi->rx_rings[0]->count, new_rx_count);
- rx_rings = kcalloc(vsi->alloc_queue_pairs,
- sizeof(struct i40e_ring), GFP_KERNEL);
+ rx_rings = kzalloc_objs(struct i40e_ring,
+ vsi->alloc_queue_pairs);
if (!rx_rings) {
err = -ENOMEM;
goto free_tx;
@@ -3637,6 +3624,7 @@ static int i40e_set_rxfh_fields(struct net_device *netdev,
((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
DECLARE_BITMAP(flow_pctypes, FLOW_PCTYPES_SIZE);
u64 i_set, i_setc;
+ u8 flow_id;
bitmap_zero(flow_pctypes, FLOW_PCTYPES_SIZE);
@@ -3720,20 +3708,14 @@ static int i40e_set_rxfh_fields(struct net_device *netdev,
return -EINVAL;
}
- if (bitmap_weight(flow_pctypes, FLOW_PCTYPES_SIZE)) {
- u8 flow_id;
+ for_each_set_bit(flow_id, flow_pctypes, FLOW_PCTYPES_SIZE) {
+ i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id)) |
+ ((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id)) << 32);
+ i_set = i40e_get_rss_hash_bits(&pf->hw, nfc, i_setc);
- for_each_set_bit(flow_id, flow_pctypes, FLOW_PCTYPES_SIZE) {
- i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id)) |
- ((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id)) << 32);
- i_set = i40e_get_rss_hash_bits(&pf->hw, nfc, i_setc);
-
- i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id),
- (u32)i_set);
- i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id),
- (u32)(i_set >> 32));
- hena |= BIT_ULL(flow_id);
- }
+ i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id), (u32)i_set);
+ i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id), (u32)(i_set >> 32));
+ hena |= BIT_ULL(flow_id);
}
i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
@@ -3988,7 +3970,7 @@ static int i40e_add_flex_offset(struct list_head *flex_pit_list,
{
struct i40e_flex_pit *new_pit, *entry;
- new_pit = kzalloc(sizeof(*entry), GFP_KERNEL);
+ new_pit = kzalloc_obj(*entry);
if (!new_pit)
return -ENOMEM;
@@ -4879,7 +4861,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
q_index = ring;
}
- input = kzalloc(sizeof(*input), GFP_KERNEL);
+ input = kzalloc_obj(*input);
if (!input)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h
index 480e3a883cc7..967711405919 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h
@@ -4,6 +4,8 @@
#ifndef _I40E_HMC_H_
#define _I40E_HMC_H_
+#include <linux/wordpart.h>
+
#include "i40e_alloc.h"
#include "i40e_io.h"
#include "i40e_register.h"
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index d8192aa23254..0cd0e5597c90 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -63,34 +63,43 @@ static bool i40e_is_total_port_shutdown_enabled(struct i40e_pf *pf);
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id i40e_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_XL710), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_QEMU), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_B), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_C), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_B), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_BC), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_BC), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_SFP), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_B), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_I_X722), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722_A), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_X710_N3000), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_XXV710_N3000), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28), 0},
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_XL710) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_QEMU) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_B) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_C) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_B) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_BC) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_BC) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_SFP) },
+ /*
+ * This ID conflicts with ipw2200, but the devices can be differentiated
+ * because i40e devices use PCI_CLASS_NETWORK_ETHERNET and ipw2200
+ * devices use PCI_CLASS_NETWORK_OTHER.
+ */
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, I40E_DEV_ID_10G_B),
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8,
+ .class_mask = 0xffff00,
+ },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_I_X722) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722_A) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_X710_N3000) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_XXV710_N3000) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B) },
+ { PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28) },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, i40e_pci_tbl);
@@ -1456,7 +1465,7 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
return -ENOMEM;
/* Create a temporary i40e_new_mac_filter */
- new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ new = kzalloc_obj(*new, GFP_ATOMIC);
if (!new)
return -ENOMEM;
@@ -1568,7 +1577,7 @@ static int i40e_correct_vf_mac_vlan_filters(struct i40e_vsi *vsi,
if (!add_head)
return -ENOMEM;
/* Create a temporary i40e_new_mac_filter */
- new_mac = kzalloc(sizeof(*new_mac), GFP_ATOMIC);
+ new_mac = kzalloc_obj(*new_mac, GFP_ATOMIC);
if (!new_mac)
return -ENOMEM;
new_mac->f = add_head;
@@ -1645,7 +1654,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
f = i40e_find_filter(vsi, macaddr, vlan);
if (!f) {
- f = kzalloc(sizeof(*f), GFP_ATOMIC);
+ f = kzalloc_obj(*f, GFP_ATOMIC);
if (!f)
return NULL;
@@ -2234,6 +2243,7 @@ static void i40e_set_rx_mode(struct net_device *netdev)
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state);
}
+ i40e_service_event_schedule(vsi->back);
}
/**
@@ -2599,7 +2609,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
}
if (f->state == I40E_FILTER_NEW) {
/* Create a temporary i40e_new_mac_filter */
- new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ new = kzalloc_obj(*new, GFP_ATOMIC);
if (!new)
goto err_no_memory_locked;
@@ -3562,6 +3572,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
u16 pf_q = vsi->base_queue + ring->queue_index;
struct i40e_hw *hw = &vsi->back->hw;
struct i40e_hmc_obj_rxq rx_ctx;
+ u32 xdp_frame_sz;
int err = 0;
bool ok;
@@ -3571,49 +3582,47 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
memset(&rx_ctx, 0, sizeof(rx_ctx));
ring->rx_buf_len = vsi->rx_buf_len;
+ xdp_frame_sz = i40e_rx_pg_size(ring) / 2;
/* XDP RX-queue info only needed for RX rings exposed to XDP */
if (ring->vsi->type != I40E_VSI_MAIN)
goto skip;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->queue_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
ring->xsk_pool = i40e_xsk_pool(ring);
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
+ xdp_frame_sz = xsk_pool_get_rx_frag_step(ring->xsk_pool);
ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->queue_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ xdp_frame_sz);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
dev_info(&vsi->back->pdev->dev,
"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->queue_index);
} else {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->queue_index,
+ ring->q_vector->napi.napi_id,
+ xdp_frame_sz);
+ if (err)
+ return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
}
skip:
- xdp_init_buff(&ring->xdp, i40e_rx_pg_size(ring) / 2, &ring->xdp_rxq);
+ xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
@@ -3647,7 +3656,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to clear LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* set the context in the HMC */
@@ -3656,7 +3666,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to set LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* configure Rx buffer alignment */
@@ -3664,7 +3675,8 @@ skip:
if (I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_info(&vsi->back->pdev->dev,
"2k Rx buffer is too small to fit standard MTU and skb_shared_info\n");
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto unreg_xdp;
}
clear_ring_build_skb_enabled(ring);
} else {
@@ -3694,6 +3706,11 @@ skip:
}
return 0;
+unreg_xdp:
+ if (ring->vsi->type == I40E_VSI_MAIN)
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
+
+ return err;
}
/**
@@ -4847,16 +4864,10 @@ static void i40e_control_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
**/
int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
{
- int ret = 0;
-
i40e_control_rx_q(pf, pf_q, enable);
/* wait for the change to finish */
- ret = i40e_pf_rxq_wait(pf, pf_q, enable);
- if (ret)
- return ret;
-
- return ret;
+ return i40e_pf_rxq_wait(pf, pf_q, enable);
}
/**
@@ -6679,7 +6690,7 @@ static int i40e_configure_queue_channels(struct i40e_vsi *vsi)
vsi->tc_seid_map[0] = vsi->seid;
for (i = 1; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (vsi->tc_config.enabled_tc & BIT(i)) {
- ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ ch = kzalloc_obj(*ch);
if (!ch) {
ret = -ENOMEM;
goto err_free;
@@ -7955,7 +7966,7 @@ static int i40e_setup_macvlans(struct i40e_vsi *vsi, u16 macvlan_cnt, u16 qcnt,
/* Create channels for macvlans */
INIT_LIST_HEAD(&vsi->macvlan_list);
for (i = 0; i < macvlan_cnt; i++) {
- ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ ch = kzalloc_obj(*ch);
if (!ch) {
ret = -ENOMEM;
goto err_free;
@@ -8067,7 +8078,7 @@ static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev)
return ERR_PTR(-EBUSY);
/* create the fwd struct */
- fwd = kzalloc(sizeof(*fwd), GFP_KERNEL);
+ fwd = kzalloc_obj(*fwd);
if (!fwd)
return ERR_PTR(-ENOMEM);
@@ -8828,7 +8839,7 @@ static int i40e_configure_clsflower(struct i40e_vsi *vsi,
clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, vsi->back->flags);
}
- filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ filter = kzalloc_obj(*filter);
if (!filter)
return -ENOMEM;
@@ -9029,7 +9040,6 @@ int i40e_open(struct net_device *netdev)
TCP_FLAG_FIN |
TCP_FLAG_CWR) >> 16);
wr32(&pf->hw, I40E_GLLAN_TSOMSK_L, be32_to_cpu(TCP_FLAG_CWR) >> 16);
- udp_tunnel_get_rx_info(netdev);
return 0;
}
@@ -11534,7 +11544,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
}
pf->next_vsi = ++i;
- vsi = kzalloc(sizeof(*vsi), GFP_KERNEL);
+ vsi = kzalloc_obj(*vsi);
if (!vsi) {
ret = -ENOMEM;
goto unlock_pf;
@@ -11705,7 +11715,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
/* Set basic values in the rings to be used later during open() */
for (i = 0; i < vsi->alloc_queue_pairs; i++) {
/* allocate space for both Tx and Rx in one shot */
- ring = kcalloc(qpv, sizeof(struct i40e_ring), GFP_KERNEL);
+ ring = kzalloc_objs(struct i40e_ring, qpv);
if (!ring)
goto err_out;
@@ -11908,8 +11918,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
"Calculation of remaining vectors underflowed. This is an accounting bug when determining total MSI-X vectors.\n");
v_budget += pf->num_lan_msix;
- pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
- GFP_KERNEL);
+ pf->msix_entries = kzalloc_objs(struct msix_entry, v_budget);
if (!pf->msix_entries)
return -ENOMEM;
@@ -12022,7 +12031,7 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
struct i40e_q_vector *q_vector;
/* allocate q_vector */
- q_vector = kzalloc(sizeof(struct i40e_q_vector), GFP_KERNEL);
+ q_vector = kzalloc_obj(struct i40e_q_vector);
if (!q_vector)
return -ENOMEM;
@@ -13771,7 +13780,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
netdev->neigh_priv_len = sizeof(u32) * 4;
netdev->priv_flags |= IFF_UNICAST_FLT;
- netdev->priv_flags |= IFF_SUPP_NOFCS;
/* Setup netdev TC information */
i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);
@@ -14575,7 +14583,7 @@ static int i40e_veb_mem_alloc(struct i40e_pf *pf)
goto err_alloc_veb; /* out of VEB slots! */
}
- veb = kzalloc(sizeof(*veb), GFP_KERNEL);
+ veb = kzalloc_obj(*veb);
if (!veb) {
ret = -ENOMEM;
goto err_alloc_veb;
@@ -15435,8 +15443,7 @@ static int i40e_init_recovery_mode(struct i40e_pf *pf, struct i40e_hw *hw)
pf->num_alloc_vsi = pf->hw.func_caps.num_vsis;
/* Set up the vsi struct and our local tracking of the MAIN PF vsi. */
- pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
- GFP_KERNEL);
+ pf->vsi = kzalloc_objs(struct i40e_vsi *, pf->num_alloc_vsi);
if (!pf->vsi) {
err = -ENOMEM;
goto err_switch_setup;
@@ -15859,8 +15866,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Set up the *vsi struct and our local tracking of the MAIN PF vsi. */
- pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
- GFP_KERNEL);
+ pf->vsi = kzalloc_objs(struct i40e_vsi *, pf->num_alloc_vsi);
if (!pf->vsi) {
err = -ENOMEM;
goto err_switch_setup;
@@ -16099,9 +16105,11 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Unwind what we've done if something failed in the setup */
err_vsis:
set_bit(__I40E_DOWN, pf->state);
+ i40e_ptp_stop(pf);
i40e_clear_interrupt_scheme(pf);
kfree(pf->vsi);
err_switch_setup:
+ i40e_ptp_free_pins(pf);
i40e_reset_interrupt_capability(pf);
timer_shutdown_sync(&pf->service_timer);
err_mac_addr:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 26bb7bffe361..e3d57550090e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -5,7 +5,7 @@
#define _I40E_PROTOTYPE_H_
#include <linux/ethtool.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include "i40e_debug.h"
#include "i40e_type.h"
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 33535418178b..ff62b5f2c815 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -24,9 +24,6 @@
#define I40E_PTP_1GB_INCVAL_MULT 20
#define I40E_ISGN 0x80000000
-#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
-#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (2 << \
- I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
#define I40E_SUBDEV_ID_25G_PTP_PIN 0xB
enum i40e_ptp_pin {
@@ -940,12 +937,13 @@ int i40e_ptp_hwtstamp_get(struct net_device *netdev,
*
* Release memory allocated for PTP pins.
**/
-static void i40e_ptp_free_pins(struct i40e_pf *pf)
+void i40e_ptp_free_pins(struct i40e_pf *pf)
{
if (i40e_is_ptp_pin_dev(&pf->hw)) {
kfree(pf->ptp_pins);
kfree(pf->ptp_caps.pin_config);
pf->ptp_pins = NULL;
+ pf->ptp_caps.pin_config = NULL;
}
}
@@ -1132,7 +1130,7 @@ int i40e_ptp_alloc_pins(struct i40e_pf *pf)
return 0;
pf->ptp_pins =
- kzalloc(sizeof(struct i40e_ptp_pins_settings), GFP_KERNEL);
+ kzalloc_obj(struct i40e_ptp_pins_settings);
if (!pf->ptp_pins) {
dev_warn(&pf->pdev->dev, "Cannot allocate memory for PTP pins structure.\n");
@@ -1219,7 +1217,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK |
I40E_PRTTSYN_CTL1_TSYNTYPE_V1 |
- I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
+ I40E_PRTTSYN_CTL1_UDP_ENA_319;
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
@@ -1236,9 +1234,9 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK |
- I40E_PRTTSYN_CTL1_TSYNTYPE_V2;
+ I40E_PRTTSYN_CTL1_TSYNTYPE_V2_EVENT;
if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) {
- tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
+ tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_319;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
} else {
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
@@ -1344,9 +1342,8 @@ static int i40e_init_pin_config(struct i40e_pf *pf)
pf->ptp_caps.pps = 1;
pf->ptp_caps.n_per_out = 2;
- pf->ptp_caps.pin_config = kcalloc(pf->ptp_caps.n_pins,
- sizeof(*pf->ptp_caps.pin_config),
- GFP_KERNEL);
+ pf->ptp_caps.pin_config = kzalloc_objs(*pf->ptp_caps.pin_config,
+ pf->ptp_caps.n_pins);
if (!pf->ptp_caps.pin_config)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h
index 432afbb64201..d426d83e0214 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_register.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_register.h
@@ -788,8 +788,18 @@
#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT 16
#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT)
#define I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT 24
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
+/* Timestamp UDP v1 packets */
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 \
+ FIELD_PREP(I40E_PRTTSYN_CTL1_TSYNTYPE_MASK, 1)
+/* Timestamp L2 and UDP v2 packets with message type < 8 */
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2_EVENT \
+ FIELD_PREP(I40E_PRTTSYN_CTL1_TSYNTYPE_MASK, 3)
#define I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT 26
#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT)
+/* Timestamp UDP packets on port 319 */
+#define I40E_PRTTSYN_CTL1_UDP_ENA_319 \
+ FIELD_PREP(I40E_PRTTSYN_CTL1_UDP_ENA_MASK, 1)
#define I40E_PRTTSYN_CTL1_TSYNENA_SHIFT 31
#define I40E_PRTTSYN_CTL1_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL1_TSYNENA_SHIFT)
#define I40E_PRTTSYN_INC_H 0x001E4060 /* Reset: GLOBR */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_trace.h b/drivers/net/ethernet/intel/i40e/i40e_trace.h
index 759f3d1c4c8f..dde0ccd789ed 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_trace.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_trace.h
@@ -88,7 +88,7 @@ TRACE_EVENT(i40e_napi_poll,
__entry->rx_clean_complete = rx_clean_complete;
__entry->tx_clean_complete = tx_clean_complete;
__entry->irq_num = q->irq_num;
- __entry->curr_cpu = get_cpu();
+ __entry->curr_cpu = smp_processor_id();
__assign_str(qname);
__assign_str(dev_name);
__assign_bitmask(irq_affinity, cpumask_bits(&q->affinity_mask),
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index cc0b9efc2637..ef5e657816f0 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1470,6 +1470,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
if (!rx_ring->rx_bi)
return;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
if (rx_ring->xsk_pool) {
i40e_xsk_clean_rx_ring(rx_ring);
goto skip_free;
@@ -1527,8 +1530,6 @@ skip_free:
void i40e_free_rx_resources(struct i40e_ring *rx_ring)
{
i40e_clean_rx_ring(rx_ring);
- if (rx_ring->vsi->type == I40E_VSI_MAIN)
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
rx_ring->xdp_prog = NULL;
kfree(rx_ring->rx_bi);
rx_ring->rx_bi = NULL;
@@ -1572,7 +1573,7 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
rx_ring->xdp_prog = rx_ring->vsi->xdp_prog;
rx_ring->rx_bi =
- kcalloc(rx_ring->count, sizeof(*rx_ring->rx_bi), GFP_KERNEL);
+ kzalloc_objs(*rx_ring->rx_bi, rx_ring->count);
if (!rx_ring->rx_bi)
return -ENOMEM;
@@ -3128,7 +3129,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 8b30a3accd31..a26c3d47ec15 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -656,7 +656,7 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id,
/* ring_len has to be multiple of 8 */
if (!IS_ALIGNED(info->ring_len, 8) ||
- info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) {
+ info->ring_len > i40e_get_max_num_descriptors(pf)) {
ret = -EINVAL;
goto error_context;
}
@@ -726,7 +726,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
/* ring_len has to be multiple of 32 */
if (!IS_ALIGNED(info->ring_len, 32) ||
- info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) {
+ info->ring_len > i40e_get_max_num_descriptors(pf)) {
ret = -EINVAL;
goto error_param;
}
@@ -1261,7 +1261,7 @@ static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, u16 *num_vlans,
spin_lock_bh(&vsi->mac_filter_hash_lock);
*num_vlans = __i40e_getnum_vf_vsi_vlan_filters(vsi);
- *vlan_list = kcalloc(*num_vlans, sizeof(**vlan_list), GFP_ATOMIC);
+ *vlan_list = kzalloc_objs(**vlan_list, *num_vlans, GFP_ATOMIC);
if (!(*vlan_list))
goto err;
@@ -1844,7 +1844,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
}
}
/* allocate memory */
- vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
+ vfs = kzalloc_objs(struct i40e_vf, num_alloc_vfs);
if (!vfs) {
ret = -ENOMEM;
goto err_alloc;
@@ -3833,10 +3833,10 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter.n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter.ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter.ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter.n_proto = ETH_P_IPV6;
@@ -3891,7 +3891,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
/* for ipv6, mask is set for all sixteen bytes (4 words) */
if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
- sizeof(cfilter.ip.v6.src_ip6)))
+ sizeof(cfilter.ip.v6.dst_ip6)))
continue;
if (mask.vlan_id)
if (cfilter.vlan_id != cf->vlan_id)
@@ -3956,7 +3956,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
goto err_out;
}
- cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL);
+ cfilter = kzalloc_obj(*cfilter);
if (!cfilter) {
aq_ret = -ENOMEM;
goto err_out;
@@ -3979,10 +3979,10 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter->n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter->ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter->ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter->n_proto = ETH_P_IPV6;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index f558b45725c8..4e119c0502f3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -4,7 +4,7 @@
#ifndef _I40E_VIRTCHNL_PF_H_
#define _I40E_VIRTCHNL_PF_H_
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/netdevice.h>
#include "i40e_type.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index a87e0c6d4017..dc31202b2a94 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -27,6 +27,7 @@
#include <linux/etherdevice.h>
#include <linux/socket.h>
#include <linux/jiffies.h>
+#include <linux/net/intel/virtchnl.h>
#include <net/ip6_checksum.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
@@ -37,7 +38,6 @@
#include <net/net_shaper.h>
#include "iavf_type.h"
-#include <linux/avf/virtchnl.h>
#include "iavf_txrx.h"
#include "iavf_fdir.h"
#include "iavf_adv_rss.h"
@@ -158,11 +158,10 @@ struct iavf_vlan {
enum iavf_vlan_state_t {
IAVF_VLAN_INVALID,
IAVF_VLAN_ADD, /* filter needs to be added */
- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */
- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */
- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */
- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */
- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */
+ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
+ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
+ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
+ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
};
struct iavf_vlan_filter {
@@ -260,7 +259,6 @@ struct iavf_adapter {
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
- wait_queue_head_t reset_waitqueue;
wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
@@ -626,5 +624,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr);
-int iavf_wait_for_reset(struct iavf_adapter *adapter);
+void iavf_reset_step(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.h b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
index bbf5c4b3a2ae..dd2f61172157 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adminq.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
@@ -113,7 +113,7 @@ static inline int iavf_aq_rc_to_posix(int aq_ret, int aq_rc)
if (aq_ret == IAVF_ERR_ADMIN_QUEUE_TIMEOUT)
return -EAGAIN;
- if (!((u32)aq_rc < (sizeof(aq_to_posix) / sizeof((aq_to_posix)[0]))))
+ if (aq_rc >= ARRAY_SIZE(aq_to_posix))
return -ERANGE;
return aq_to_posix[aq_rc];
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 614a886bca99..277193a97d91 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/bitfield.h>
#include "iavf_type.h"
#include "iavf_adminq.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index 2cc21289a707..e7cf12eaa268 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -32,7 +32,7 @@
* statistics array. Thus, every statistic string in an array should have the
* same type and number of format specifiers, to be formatted by variadic
* arguments to the iavf_add_stat_string() helper function.
- **/
+ */
struct iavf_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
@@ -116,7 +116,7 @@ iavf_add_one_ethtool_stat(u64 *data, void *pointer,
* the next empty location for successive calls to __iavf_add_ethtool_stats.
* If pointer is null, set the data values to zero and update the pointer to
* skip these stats.
- **/
+ */
static void
__iavf_add_ethtool_stats(u64 **data, void *pointer,
const struct iavf_stats stats[],
@@ -140,7 +140,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer,
*
* The parameter @stats is evaluated twice, so parameters with side effects
* should be avoided.
- **/
+ */
#define iavf_add_ethtool_stats(data, pointer, stats) \
__iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
@@ -157,7 +157,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer,
* buffer and update the data pointer when finished.
*
* This function expects to be called while under rcu_read_lock().
- **/
+ */
static void
iavf_add_queue_stats(u64 **data, struct iavf_ring *ring)
{
@@ -189,7 +189,7 @@ iavf_add_queue_stats(u64 **data, struct iavf_ring *ring)
*
* Format and copy the strings described by stats into the buffer pointed at
* by p.
- **/
+ */
static void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[],
const unsigned int size, ...)
{
@@ -216,7 +216,7 @@ static void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[],
* The parameter @stats is evaluated twice, so parameters with side effects
* should be avoided. Additionally, stats must be an array such that
* ARRAY_SIZE can be called on it.
- **/
+ */
#define iavf_add_stat_strings(p, stats, ...) \
__iavf_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
@@ -249,7 +249,7 @@ static const struct iavf_stats iavf_gstrings_stats[] = {
*
* Reports speed/duplex settings. Because this is a VF, we don't know what
* kind of link we really have, so we fake it.
- **/
+ */
static int iavf_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
@@ -308,19 +308,18 @@ static int iavf_get_link_ksettings(struct net_device *netdev,
* @sset: id of string set
*
* Reports size of various string tables.
- **/
+ */
static int iavf_get_sset_count(struct net_device *netdev, int sset)
{
/* Report the maximum number queues, even if not every queue is
* currently configured. Since allocation of queues is in pairs,
- * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set
- * at device creation and never changes.
+ * use netdev->num_tx_queues * 2. The num_tx_queues is set at
+ * device creation and never changes.
*/
if (sset == ETH_SS_STATS)
return IAVF_STATS_LEN +
- (IAVF_QUEUE_STATS_LEN * 2 *
- netdev->real_num_tx_queues);
+ (IAVF_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues);
else
return -EINVAL;
}
@@ -332,7 +331,7 @@ static int iavf_get_sset_count(struct net_device *netdev, int sset)
* @data: pointer to data buffer
*
* All statistics are added to the data buffer as an array of u64.
- **/
+ */
static void iavf_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
@@ -345,19 +344,19 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
rcu_read_lock();
- /* As num_active_queues describe both tx and rx queues, we can use
- * it to iterate over rings' stats.
+ /* Use num_tx_queues to report stats for the maximum number of queues.
+ * Queues beyond num_active_queues will report zero.
*/
- for (i = 0; i < adapter->num_active_queues; i++) {
- struct iavf_ring *ring;
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ struct iavf_ring *tx_ring = NULL, *rx_ring = NULL;
- /* Tx rings stats */
- ring = &adapter->tx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ if (i < adapter->num_active_queues) {
+ tx_ring = &adapter->tx_rings[i];
+ rx_ring = &adapter->rx_rings[i];
+ }
- /* Rx rings stats */
- ring = &adapter->rx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ iavf_add_queue_stats(&data, tx_ring);
+ iavf_add_queue_stats(&data, rx_ring);
}
rcu_read_unlock();
}
@@ -368,7 +367,7 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
* @data: buffer for string data
*
* Builds the statistics string table
- **/
+ */
static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
{
unsigned int i;
@@ -376,9 +375,9 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
iavf_add_stat_strings(&data, iavf_gstrings_stats);
/* Queues are always allocated in pairs, so we just use
- * real_num_tx_queues for both Tx and Rx queues.
+ * num_tx_queues for both Tx and Rx queues.
*/
- for (i = 0; i < netdev->real_num_tx_queues; i++) {
+ for (i = 0; i < netdev->num_tx_queues; i++) {
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
"tx", i);
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
@@ -393,7 +392,7 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
* @data: buffer for string data
*
* Builds string tables for various string sets
- **/
+ */
static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
{
switch (sset) {
@@ -409,8 +408,8 @@ static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
* iavf_get_msglevel - Get debug message level
* @netdev: network interface device structure
*
- * Returns current debug message level.
- **/
+ * Return: current debug message level.
+ */
static u32 iavf_get_msglevel(struct net_device *netdev)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
@@ -425,7 +424,7 @@ static u32 iavf_get_msglevel(struct net_device *netdev)
*
* Set current debug message level. Higher values cause the driver to
* be noisier.
- **/
+ */
static void iavf_set_msglevel(struct net_device *netdev, u32 data)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
@@ -440,8 +439,8 @@ static void iavf_set_msglevel(struct net_device *netdev, u32 data)
* @netdev: network interface device structure
* @drvinfo: ethool driver info structure
*
- * Returns information about the driver and device for display to the user.
- **/
+ * Fills @drvinfo with information about the driver and device.
+ */
static void iavf_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
@@ -459,9 +458,9 @@ static void iavf_get_drvinfo(struct net_device *netdev,
* @kernel_ring: ethtool extenal ringparam structure
* @extack: netlink extended ACK report struct
*
- * Returns current ring parameters. TX and RX rings are reported separately,
- * but the number of rings is not reported.
- **/
+ * Fills @ring with current ring parameters. TX and RX rings are reported
+ * separately, but the number of rings is not reported.
+ */
static void iavf_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -484,7 +483,7 @@ static void iavf_get_ringparam(struct net_device *netdev,
*
* Sets ring parameters. TX and RX rings are controlled separately, but the
* number of rings is not specified, so all rings get the same settings.
- **/
+ */
static int iavf_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -492,7 +491,6 @@ static int iavf_set_ringparam(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count;
- int ret = 0;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
@@ -537,13 +535,11 @@ static int iavf_set_ringparam(struct net_device *netdev,
}
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -555,7 +551,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
* Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs
* are per queue. If queue is <0 then we default to queue 0 as the
* representative value.
- **/
+ */
static int __iavf_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec, int queue)
{
@@ -592,11 +588,11 @@ static int __iavf_get_coalesce(struct net_device *netdev,
* @kernel_coal: ethtool CQE mode setting structure
* @extack: extack for reporting error messages
*
- * Returns current coalescing settings. This is referred to elsewhere in the
- * driver as Interrupt Throttle Rate, as this is how the hardware describes
- * this functionality. Note that if per-queue settings have been modified this
- * only represents the settings of queue 0.
- **/
+ * Fills @ec with current coalescing settings. This is referred to elsewhere
+ * in the driver as Interrupt Throttle Rate, as this is how the hardware
+ * describes this functionality. Note that if per-queue settings have been
+ * modified this only represents the settings of queue 0.
+ */
static int iavf_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kernel_coal,
@@ -612,7 +608,7 @@ static int iavf_get_coalesce(struct net_device *netdev,
* @queue: the queue to read
*
* Read specific queue's coalesce settings.
- **/
+ */
static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
struct ethtool_coalesce *ec)
{
@@ -626,7 +622,7 @@ static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
* @queue: the queue to modify
*
* Change the ITR settings for a specific queue.
- **/
+ */
static int iavf_set_itr_per_queue(struct iavf_adapter *adapter,
struct ethtool_coalesce *ec, int queue)
{
@@ -684,7 +680,7 @@ static int iavf_set_itr_per_queue(struct iavf_adapter *adapter,
* @queue: the queue to change
*
* Sets the coalesce settings for a particular queue.
- **/
+ */
static int __iavf_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec, int queue)
{
@@ -726,7 +722,7 @@ static int __iavf_set_coalesce(struct net_device *netdev,
* @extack: extack for reporting error messages
*
* Change current coalescing settings for every queue.
- **/
+ */
static int iavf_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kernel_coal,
@@ -1276,7 +1272,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
- fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
+ fltr = kzalloc_obj(*fltr);
if (!fltr)
return -ENOMEM;
@@ -1519,7 +1515,7 @@ iavf_set_rxfh_fields(struct net_device *netdev,
if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
return -EINVAL;
- rss_new = kzalloc(sizeof(*rss_new), GFP_KERNEL);
+ rss_new = kzalloc_obj(*rss_new);
if (!rss_new)
return -ENOMEM;
@@ -1643,7 +1639,7 @@ static int iavf_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
* @netdev: network interface device structure
*
* Return: number of RX rings.
- **/
+ */
static u32 iavf_get_rx_ring_count(struct net_device *netdev)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
@@ -1657,8 +1653,8 @@ static u32 iavf_get_rx_ring_count(struct net_device *netdev)
* @cmd: ethtool rxnfc command
* @rule_locs: pointer to store rule locations
*
- * Returns Success if the command is supported.
- **/
+ * Return: 0 on success, -EOPNOTSUPP if the command is not supported.
+ */
static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
@@ -1688,13 +1684,13 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
return ret;
}
/**
- * iavf_get_channels: get the number of channels supported by the device
+ * iavf_get_channels - get the number of channels supported by the device
* @netdev: network interface device structure
* @ch: channel information structure
*
* For the purposes of our device, we only use combined channels, i.e. a tx/rx
* queue pair. Report one extra channel to match our "other" MSI-X vector.
- **/
+ */
static void iavf_get_channels(struct net_device *netdev,
struct ethtool_channels *ch)
{
@@ -1710,20 +1706,20 @@ static void iavf_get_channels(struct net_device *netdev,
}
/**
- * iavf_set_channels: set the new channel count
+ * iavf_set_channels - set the new channel count
* @netdev: network interface device structure
* @ch: channel information structure
*
- * Negotiate a new number of channels with the PF then do a reset. During
- * reset we'll realloc queues and fix the RSS table. Returns 0 on success,
- * negative on failure.
- **/
+ * Negotiate a new number of channels with the PF then do a reset. During
+ * reset we'll realloc queues and fix the RSS table.
+ *
+ * Return: 0 on success, negative on failure.
+ */
static int iavf_set_channels(struct net_device *netdev,
struct ethtool_channels *ch)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 num_req = ch->combined_count;
- int ret = 0;
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
adapter->num_tc) {
@@ -1745,21 +1741,18 @@ static int iavf_set_channels(struct net_device *netdev,
adapter->num_req_queues = num_req;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
-
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
- return ret;
+ return 0;
}
/**
* iavf_get_rxfh_key_size - get the RSS hash key size
* @netdev: network interface device structure
*
- * Returns the table size.
- **/
+ * Return: the RSS hash key size.
+ */
static u32 iavf_get_rxfh_key_size(struct net_device *netdev)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
@@ -1771,8 +1764,8 @@ static u32 iavf_get_rxfh_key_size(struct net_device *netdev)
* iavf_get_rxfh_indir_size - get the rx flow hash indirection table size
* @netdev: network interface device structure
*
- * Returns the table size.
- **/
+ * Return: the indirection table size.
+ */
static u32 iavf_get_rxfh_indir_size(struct net_device *netdev)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
@@ -1785,8 +1778,10 @@ static u32 iavf_get_rxfh_indir_size(struct net_device *netdev)
* @netdev: network interface device structure
* @rxfh: pointer to param struct (indir, key, hfunc)
*
- * Reads the indirection table directly from the hardware. Always returns 0.
- **/
+ * Reads the indirection table directly from the hardware.
+ *
+ * Return: 0 always.
+ */
static int iavf_get_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh)
{
@@ -1814,9 +1809,9 @@ static int iavf_get_rxfh(struct net_device *netdev,
* @rxfh: pointer to param struct (indir, key, hfunc)
* @extack: extended ACK from the Netlink message
*
- * Returns -EINVAL if the table specifies an invalid queue id, otherwise
- * returns 0 after programming the table.
- **/
+ * Return: 0 on success, -EOPNOTSUPP if the hash function is not supported,
+ * -EINVAL if the table specifies an invalid queue id.
+ */
static int iavf_set_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
@@ -1860,6 +1855,7 @@ static const struct ethtool_ops iavf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE,
.supported_input_xfrm = RXH_XFRM_SYM_XOR,
+ .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_GLINK,
.get_drvinfo = iavf_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = iavf_get_ringparam,
@@ -1893,7 +1889,7 @@ static const struct ethtool_ops iavf_ethtool_ops = {
*
* Sets ethtool ops struct in our netdev so that ethtool can call
* our functions.
- **/
+ */
void iavf_set_ethtool_ops(struct net_device *netdev)
{
netdev->ethtool_ops = &iavf_ethtool_ops;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index c2fbe443ef85..29b8403a066b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -36,12 +36,12 @@ static const char iavf_copyright[] =
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id iavf_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF), 0},
- {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF_HV), 0},
- {PCI_VDEVICE(INTEL, IAVF_DEV_ID_X722_VF), 0},
- {PCI_VDEVICE(INTEL, IAVF_DEV_ID_ADAPTIVE_VF), 0},
+ { PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF) },
+ { PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF_HV) },
+ { PCI_VDEVICE(INTEL, IAVF_DEV_ID_X722_VF) },
+ { PCI_VDEVICE(INTEL, IAVF_DEV_ID_ADAPTIVE_VF) },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, iavf_pci_tbl);
@@ -186,31 +186,6 @@ static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter)
}
/**
- * iavf_wait_for_reset - Wait for reset to finish.
- * @adapter: board private structure
- *
- * Returns 0 if reset finished successfully, negative on timeout or interrupt.
- */
-int iavf_wait_for_reset(struct iavf_adapter *adapter)
-{
- int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue,
- !iavf_is_reset_in_progress(adapter),
- msecs_to_jiffies(5000));
-
- /* If ret < 0 then it means wait was interrupted.
- * If ret == 0 then it means we got a timeout while waiting
- * for reset to finish.
- * If ret > 0 it means reset has finished.
- */
- if (ret > 0)
- return 0;
- else if (ret < 0)
- return -EINTR;
- else
- return -EBUSY;
-}
-
-/**
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
@@ -771,7 +746,7 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
f = iavf_find_vlan(adapter, vlan);
if (!f) {
- f = kzalloc(sizeof(*f), GFP_ATOMIC);
+ f = kzalloc_obj(*f, GFP_ATOMIC);
if (!f)
goto clearout;
@@ -782,10 +757,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
- /* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed.
- * We can safely only change the state here.
- */
+ /* DEL not yet sent to PF, cancel it */
f->state = IAVF_VLAN_ACTIVE;
+ } else if (f->state == IAVF_VLAN_REMOVING) {
+ /* DEL already sent to PF, re-add after completion */
+ f->state = IAVF_VLAN_ADD;
+ iavf_schedule_aq_request(adapter,
+ IAVF_FLAG_AQ_ADD_VLAN_FILTER);
}
clearout:
@@ -813,37 +791,19 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
- } else {
+ } else if (f->state != IAVF_VLAN_REMOVING) {
f->state = IAVF_VLAN_REMOVE;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
}
+ /* If REMOVING, DEL is already sent to PF; completion
+ * handler will free the filter when PF confirms.
+ */
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
-/**
- * iavf_restore_filters
- * @adapter: board private structure
- *
- * Restore existing non MAC filters when VF netdev comes back up
- **/
-static void iavf_restore_filters(struct iavf_adapter *adapter)
-{
- struct iavf_vlan_filter *f;
-
- /* re-add all VLAN filters */
- spin_lock_bh(&adapter->mac_vlan_list_lock);
-
- list_for_each_entry(f, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_INACTIVE)
- f->state = IAVF_VLAN_ADD;
- }
-
- spin_unlock_bh(&adapter->mac_vlan_list_lock);
- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
-}
/**
* iavf_get_num_vlans_added - get number of VLANs added
@@ -978,7 +938,7 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
f = iavf_find_filter(adapter, macaddr);
if (!f) {
- f = kzalloc(sizeof(*f), GFP_ATOMIC);
+ f = kzalloc_obj(*f, GFP_ATOMIC);
if (!f)
return f;
@@ -1172,20 +1132,28 @@ bool iavf_promiscuous_mode_changed(struct iavf_adapter *adapter)
/**
* iavf_set_rx_mode - NDO callback to set the netdev filters
* @netdev: network interface device structure
+ * @uc: snapshot of uc address list
+ * @mc: snapshot of mc address list
+ *
+ * Return: 0 on success.
**/
-static void iavf_set_rx_mode(struct net_device *netdev)
+static int iavf_set_rx_mode(struct net_device *netdev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
spin_lock_bh(&adapter->mac_vlan_list_lock);
- __dev_uc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
- __dev_mc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
+ __hw_addr_sync_dev(uc, netdev, iavf_addr_sync, iavf_addr_unsync);
+ __hw_addr_sync_dev(mc, netdev, iavf_addr_sync, iavf_addr_unsync);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
spin_lock_bh(&adapter->current_netdev_promisc_flags_lock);
if (iavf_promiscuous_mode_changed(adapter))
adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE;
spin_unlock_bh(&adapter->current_netdev_promisc_flags_lock);
+
+ return 0;
}
/**
@@ -1232,7 +1200,9 @@ static void iavf_configure(struct iavf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int i;
- iavf_set_rx_mode(netdev);
+ netif_addr_lock_bh(netdev);
+ iavf_set_rx_mode(netdev, &netdev->uc, &netdev->mc);
+ netif_addr_unlock_bh(netdev);
iavf_configure_tx(adapter);
iavf_configure_rx(adapter);
@@ -1262,13 +1232,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
}
/**
- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF
- * yet and mark other to be removed.
+ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark
+ * others to be removed.
* @adapter: board private structure
**/
-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
+static void iavf_clear_mac_filters(struct iavf_adapter *adapter)
{
- struct iavf_vlan_filter *vlf, *vlftmp;
struct iavf_mac_filter *f, *ftmp;
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1287,11 +1256,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
}
}
- /* disable all VLAN filters */
- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list,
- list)
- vlf->state = IAVF_VLAN_DISABLE;
-
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
@@ -1387,7 +1351,7 @@ void iavf_down(struct iavf_adapter *adapter)
iavf_napi_disable_all(adapter);
iavf_irq_disable(adapter);
- iavf_clear_mac_vlan_filters(adapter);
+ iavf_clear_mac_filters(adapter);
iavf_clear_cloud_filters(adapter);
iavf_clear_fdir_filters(adapter);
iavf_clear_adv_rss_conf(adapter);
@@ -1404,8 +1368,6 @@ void iavf_down(struct iavf_adapter *adapter)
*/
if (!list_empty(&adapter->mac_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
- if (!list_empty(&adapter->vlan_filter_list))
- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
if (!list_empty(&adapter->cloud_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
if (!list_empty(&adapter->fdir_list_head))
@@ -1585,12 +1547,10 @@ static int iavf_alloc_queues(struct iavf_adapter *adapter)
(int)(num_online_cpus()));
- adapter->tx_rings = kcalloc(num_active_queues,
- sizeof(struct iavf_ring), GFP_KERNEL);
+ adapter->tx_rings = kzalloc_objs(struct iavf_ring, num_active_queues);
if (!adapter->tx_rings)
goto err_out;
- adapter->rx_rings = kcalloc(num_active_queues,
- sizeof(struct iavf_ring), GFP_KERNEL);
+ adapter->rx_rings = kzalloc_objs(struct iavf_ring, num_active_queues);
if (!adapter->rx_rings)
goto err_out;
@@ -1653,8 +1613,7 @@ static int iavf_set_interrupt_capability(struct iavf_adapter *adapter)
v_budget = min_t(int, pairs + NONQ_VECS,
(int)adapter->vf_res->max_vectors);
- adapter->msix_entries = kcalloc(v_budget,
- sizeof(struct msix_entry), GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, v_budget);
if (!adapter->msix_entries) {
err = -ENOMEM;
goto out;
@@ -1726,11 +1685,11 @@ static int iavf_config_rss_reg(struct iavf_adapter *adapter)
u16 i;
dw = (u32 *)adapter->rss_key;
- for (i = 0; i <= adapter->rss_key_size / 4; i++)
+ for (i = 0; i < adapter->rss_key_size / 4; i++)
wr32(hw, IAVF_VFQF_HKEY(i), dw[i]);
dw = (u32 *)adapter->rss_lut;
- for (i = 0; i <= adapter->rss_lut_size / 4; i++)
+ for (i = 0; i < adapter->rss_lut_size / 4; i++)
wr32(hw, IAVF_VFQF_HLUT(i), dw[i]);
iavf_flush(hw);
@@ -1812,8 +1771,7 @@ static int iavf_alloc_q_vectors(struct iavf_adapter *adapter)
struct iavf_q_vector *q_vector;
num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
- adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector),
- GFP_KERNEL);
+ adapter->q_vectors = kzalloc_objs(*q_vector, num_q_vectors);
if (!adapter->q_vectors)
return -ENOMEM;
@@ -2797,7 +2755,22 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
netdev->watchdog_timeo = 5 * HZ;
netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = LIBIE_MAX_MTU;
+
+ /* PF/VF API: vf_res->max_mtu is max frame size (not MTU).
+ * Convert to MTU.
+ */
+ if (!adapter->vf_res->max_mtu) {
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else if (adapter->vf_res->max_mtu < LIBETH_RX_LL_LEN + ETH_MIN_MTU ||
+ adapter->vf_res->max_mtu >
+ LIBETH_RX_LL_LEN + LIBIE_MAX_MTU) {
+ netdev_warn_once(adapter->netdev,
+ "invalid max frame size %d from PF, using default MTU %d",
+ adapter->vf_res->max_mtu, LIBIE_MAX_MTU);
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else {
+ netdev->max_mtu = adapter->vf_res->max_mtu - LIBETH_RX_LL_LEN;
+ }
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
@@ -3025,6 +2998,8 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
+ iavf_ptp_release(adapter);
+
/* We don't use netif_running() because it may be true prior to
* ndo_open() returning, so we can't assume it means all our open
* tasks have finished, since we're not holding the rtnl_lock here.
@@ -3100,18 +3075,16 @@ static void iavf_reconfig_qs_bw(struct iavf_adapter *adapter)
}
/**
- * iavf_reset_task - Call-back task to handle hardware reset
- * @work: pointer to work_struct
+ * iavf_reset_step - Perform the VF reset sequence
+ * @adapter: board private structure
*
- * During reset we need to shut down and reinitialize the admin queue
- * before we can use it to communicate with the PF again. We also clear
- * and reinit the rings because that context is lost as well.
- **/
-static void iavf_reset_task(struct work_struct *work)
+ * Requests a reset from PF, polls for completion, and reconfigures
+ * the driver. Caller must hold the netdev instance lock.
+ *
+ * This can sleep for several seconds while polling HW registers.
+ */
+void iavf_reset_step(struct iavf_adapter *adapter)
{
- struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- reset_task);
struct virtchnl_vf_resource *vfres = adapter->vf_res;
struct net_device *netdev = adapter->netdev;
struct iavf_hw *hw = &adapter->hw;
@@ -3122,7 +3095,7 @@ static void iavf_reset_task(struct work_struct *work)
int i = 0, err;
bool running;
- netdev_lock(netdev);
+ netdev_assert_locked(netdev);
iavf_misc_irq_disable(adapter);
if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
@@ -3167,7 +3140,6 @@ static void iavf_reset_task(struct work_struct *work)
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val);
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -3179,7 +3151,6 @@ continue_reset:
iavf_startup(adapter);
queue_delayed_work(adapter->wq, &adapter->watchdog_task,
msecs_to_jiffies(30));
- netdev_unlock(netdev);
return;
}
@@ -3200,6 +3171,8 @@ continue_reset:
iavf_change_state(adapter, __IAVF_RESETTING);
adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ iavf_ptp_release(adapter);
+
/* free the Tx/Rx rings and descriptors, might be better to just
* re-use them sometime in the future
*/
@@ -3320,9 +3293,6 @@ continue_reset:
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
- wake_up(&adapter->reset_waitqueue);
- netdev_unlock(netdev);
-
return;
reset_err:
if (running) {
@@ -3331,10 +3301,21 @@ reset_err:
}
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
}
+static void iavf_reset_task(struct work_struct *work)
+{
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
+ reset_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netdev_lock(netdev);
+ iavf_reset_step(adapter);
+ netdev_unlock(netdev);
+}
+
/**
* iavf_adminq_task - worker thread to clean the admin queue
* @work: pointer to work_struct containing our data
@@ -4119,7 +4100,7 @@ static int iavf_configure_clsflower(struct iavf_adapter *adapter,
return -EINVAL;
}
- filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ filter = kzalloc_obj(*filter);
if (!filter)
return -ENOMEM;
filter->cookie = cls_flower->cookie;
@@ -4234,7 +4215,7 @@ static int iavf_add_cls_u32(struct iavf_adapter *adapter,
return -EOPNOTSUPP;
}
- fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
+ fltr = kzalloc_obj(*fltr);
if (!fltr)
return -ENOMEM;
@@ -4491,8 +4472,6 @@ static int iavf_open(struct net_device *netdev)
iavf_add_filter(adapter, adapter->hw.mac.addr);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- /* Restore filters that were removed with IFF_DOWN */
- iavf_restore_filters(adapter);
iavf_restore_fdir_filters(adapter);
iavf_configure(adapter);
@@ -4600,22 +4579,17 @@ static int iavf_close(struct net_device *netdev)
static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
- int ret = 0;
netdev_dbg(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu);
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret < 0)
- netdev_warn(netdev, "MTU change interrupted waiting for reset");
- else if (ret)
- netdev_warn(netdev, "MTU change timed out waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -5161,7 +5135,7 @@ static const struct net_device_ops iavf_netdev_ops = {
.ndo_open = iavf_open,
.ndo_stop = iavf_close,
.ndo_start_xmit = iavf_xmit_frame,
- .ndo_set_rx_mode = iavf_set_rx_mode,
+ .ndo_set_rx_mode_async = iavf_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = iavf_set_mac,
.ndo_change_mtu = iavf_change_mtu,
@@ -5420,9 +5394,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
- /* Setup the wait queue for indicating transition to running state */
- init_waitqueue_head(&adapter->reset_waitqueue);
-
/* Setup the wait queue for indicating virtchannel events */
init_waitqueue_head(&adapter->vc_waitqueue);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
index 7f9f9dbf959a..1b1f6ede3920 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
@@ -4,9 +4,10 @@
#ifndef _IAVF_PROTOTYPE_H_
#define _IAVF_PROTOTYPE_H_
+#include <linux/net/intel/virtchnl.h>
+
#include "iavf_type.h"
#include "iavf_alloc.h"
-#include <linux/avf/virtchnl.h>
/* Prototypes for shared code functions that are not in
* the standard function pointer structures. These are
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c
index 9cbd8c154031..87b97e09df14 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ptp.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.c
@@ -133,7 +133,7 @@ static struct iavf_ptp_aq_cmd *iavf_allocate_ptp_cmd(enum virtchnl_ops v_opcode,
{
struct iavf_ptp_aq_cmd *cmd;
- cmd = kzalloc(struct_size(cmd, msg, msglen), GFP_KERNEL);
+ cmd = kzalloc_flex(*cmd, msg, msglen);
if (!cmd)
return NULL;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index 363c42bf3dcf..c30abf17cf5d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -1774,7 +1774,7 @@ static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h
index 1d8cf29cb65a..5bb1de1cfd33 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_type.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_type.h
@@ -277,7 +277,7 @@ struct iavf_rx_desc {
/* L2 Tag 2 Presence */
#define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0)
/* Stripped S-TAG VLAN from the receive packet */
-#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32)
+#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48)
/* The packet is a UDP tunneled packet */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_types.h b/drivers/net/ethernet/intel/iavf/iavf_types.h
index a095855122bf..35d6d8fcca04 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_types.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_types.h
@@ -4,9 +4,7 @@
#ifndef _IAVF_TYPES_H_
#define _IAVF_TYPES_H_
-#include "iavf_types.h"
-
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/ptp_clock_kernel.h>
/* structure used to queue PTP commands for processing */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 88156082a41d..ec234cc8bd9d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_IS_NEW) {
+ if (f->state == IAVF_VLAN_ADDING) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
@@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
if (f->state == IAVF_VLAN_ADD) {
vvfl->vlan_id[i] = f->vlan.vid;
i++;
- f->state = IAVF_VLAN_IS_NEW;
+ f->state = IAVF_VLAN_ADDING;
if (i == count)
break;
}
@@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
vlan->tpid = f->vlan.tpid;
i++;
- f->state = IAVF_VLAN_IS_NEW;
+ f->state = IAVF_VLAN_ADDING;
}
}
@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- /* since VLAN capabilities are not allowed, we dont want to send
- * a VLAN delete request because it will most likely fail and
- * create unnecessary errors/noise, so just free the VLAN
- * filters marked for removal to enable bailing out before
- * sending a virtchnl message
- */
if (f->state == IAVF_VLAN_REMOVE &&
!VLAN_FILTERING_ALLOWED(adapter)) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
- } else if (f->state == IAVF_VLAN_DISABLE &&
- !VLAN_FILTERING_ALLOWED(adapter)) {
- f->state = IAVF_VLAN_INACTIVE;
- } else if (f->state == IAVF_VLAN_REMOVE ||
- f->state == IAVF_VLAN_DISABLE) {
+ } else if (f->state == IAVF_VLAN_REMOVE) {
count++;
}
}
@@ -958,18 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_DISABLE) {
- vvfl->vlan_id[i] = f->vlan.vid;
- f->state = IAVF_VLAN_INACTIVE;
- i++;
- if (i == count)
- break;
- } else if (f->state == IAVF_VLAN_REMOVE) {
+ list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+ if (f->state == IAVF_VLAN_REMOVE) {
vvfl->vlan_id[i] = f->vlan.vid;
- list_del(&f->list);
- kfree(f);
- adapter->num_vlan_filters--;
+ f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -1006,9 +988,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
vvfl_v2->num_elements = count;
- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_DISABLE ||
- f->state == IAVF_VLAN_REMOVE) {
+ list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+ if (f->state == IAVF_VLAN_REMOVE) {
struct virtchnl_vlan_supported_caps *filtering_support =
&adapter->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan;
@@ -1022,13 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vlan->tci = f->vlan.vid;
vlan->tpid = f->vlan.tpid;
- if (f->state == IAVF_VLAN_DISABLE) {
- f->state = IAVF_VLAN_INACTIVE;
- } else {
- list_del(&f->list);
- kfree(f);
- adapter->num_vlan_filters--;
- }
+ f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -2391,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
wake_up(&adapter->vc_waitqueue);
break;
- case VIRTCHNL_OP_DEL_VLAN:
- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
- iavf_stat_str(&adapter->hw, v_retval));
- break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
iavf_stat_str(&adapter->hw, v_retval));
@@ -2579,13 +2550,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ADD_ETH_ADDR:
if (!v_retval)
iavf_mac_add_ok(adapter);
- if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr))
- if (!ether_addr_equal(netdev->dev_addr,
- adapter->hw.mac.addr)) {
- netif_addr_lock_bh(netdev);
- eth_hw_addr_set(netdev, adapter->hw.mac.addr);
- netif_addr_unlock_bh(netdev);
- }
+ if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr)) {
+ netif_addr_lock_bh(netdev);
+ eth_hw_addr_set(netdev, adapter->hw.mac.addr);
+ netif_addr_unlock_bh(netdev);
+ }
wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_GET_STATS: {
@@ -2736,7 +2705,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */
iavf_irq_enable(adapter, true);
- wake_up(&adapter->reset_waitqueue);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
@@ -2906,17 +2874,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
spin_unlock_bh(&adapter->adv_rss_lock);
}
break;
+ case VIRTCHNL_OP_ADD_VLAN:
case VIRTCHNL_OP_ADD_VLAN_V2: {
struct iavf_vlan_filter *f;
+ if (v_retval)
+ break;
+
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
- if (f->state == IAVF_VLAN_IS_NEW)
+ if (f->state == IAVF_VLAN_ADDING)
f->state = IAVF_VLAN_ACTIVE;
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
break;
+ case VIRTCHNL_OP_DEL_VLAN:
+ case VIRTCHNL_OP_DEL_VLAN_V2: {
+ struct iavf_vlan_filter *f, *ftmp;
+
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
+ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
+ list) {
+ if (f->state == IAVF_VLAN_REMOVING) {
+ if (v_retval) {
+ /* PF rejected DEL, keep filter */
+ f->state = IAVF_VLAN_ACTIVE;
+ } else {
+ list_del(&f->list);
+ kfree(f);
+ adapter->num_vlan_filters--;
+ }
+ }
+ }
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+ }
+ break;
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
/* PF enabled vlan strip on this VF.
* Update netdev->features if needed to be in sync with ethtool.
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 5b2c666496e7..95fd0c49800f 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -54,7 +54,7 @@ ice-$(CONFIG_PCI_IOV) += \
ice_vf_mbx.o \
ice_vf_vsi_vlan_ops.o \
ice_vf_lib.o
-ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o
+ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.o ice_cpi.o ice_txclk.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index d88b7f3fd1f9..8c2b63eef82b 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -285,7 +285,7 @@ static int ice_devlink_info_get(struct devlink *devlink,
return err;
}
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -460,6 +460,7 @@ static void ice_devlink_reinit_down(struct ice_pf *pf)
ice_vsi_decfg(ice_get_main_vsi(pf));
rtnl_unlock();
ice_deinit_pf(pf);
+ ice_deinit_hw(&pf->hw);
ice_deinit_dev(pf);
}
@@ -670,10 +671,10 @@ static int ice_devlink_tx_sched_layers_set(struct devlink *devlink, u32 id,
* error.
*/
static int ice_devlink_tx_sched_layers_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
- if (val.vu8 != ICE_SCHED_5_LAYERS && val.vu8 != ICE_SCHED_9_LAYERS) {
+ if (val->vu8 != ICE_SCHED_5_LAYERS && val->vu8 != ICE_SCHED_9_LAYERS) {
NL_SET_ERR_MSG_MOD(extack,
"Wrong number of tx scheduler layers provided.");
return -EINVAL;
@@ -1244,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
return err;
}
+ ice_init_dev_hw(pf);
+
/* load MSI-X values */
ice_set_min_max_msix(pf);
@@ -1359,7 +1362,7 @@ ice_devlink_enable_roce_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_ROCEV2);
@@ -1395,7 +1398,7 @@ static int ice_devlink_enable_roce_set(struct devlink *devlink, u32 id,
static int
ice_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
@@ -1426,7 +1429,7 @@ ice_devlink_enable_iw_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_IWARP);
@@ -1462,7 +1465,7 @@ static int ice_devlink_enable_iw_set(struct devlink *devlink, u32 id,
static int
ice_devlink_enable_iw_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
@@ -1588,10 +1591,10 @@ static int ice_devlink_local_fwd_set(struct devlink *devlink, u32 id,
* error.
*/
static int ice_devlink_local_fwd_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
- if (ice_devlink_local_fwd_str_to_mode(val.vstr) < 0) {
+ if (ice_devlink_local_fwd_str_to_mode(val->vstr) < 0) {
NL_SET_ERR_MSG_MOD(extack, "Error: Requested value is not supported.");
return -EINVAL;
}
@@ -1601,12 +1604,12 @@ static int ice_devlink_local_fwd_validate(struct devlink *devlink, u32 id,
static int
ice_devlink_msix_max_pf_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
- if (val.vu32 > pf->hw.func_caps.common_cap.num_msix_vectors)
+ if (val->vu32 > pf->hw.func_caps.common_cap.num_msix_vectors)
return -EINVAL;
return 0;
@@ -1614,21 +1617,21 @@ ice_devlink_msix_max_pf_validate(struct devlink *devlink, u32 id,
static int
ice_devlink_msix_min_pf_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
- if (val.vu32 < ICE_MIN_MSIX)
+ if (val->vu32 < ICE_MIN_MSIX)
return -EINVAL;
return 0;
}
static int ice_devlink_enable_rdma_validate(struct devlink *devlink, u32 id,
- union devlink_param_value val,
+ union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
- bool new_state = val.vbool;
+ bool new_state = val->vbool;
if (new_state && !test_bit(ICE_FLAG_RDMA_ENA, pf->flags))
return -EOPNOTSUPP;
@@ -1788,16 +1791,16 @@ int ice_devlink_register_params(struct ice_pf *pf)
value.vu32 = pf->msix.max;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
- value);
+ &value);
value.vu32 = pf->msix.min;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
- value);
+ &value);
value.vbool = test_bit(ICE_FLAG_RDMA_ENA, pf->flags);
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
- value);
+ &value);
return 0;
@@ -1887,27 +1890,18 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
*/
for (i = 0; i < num_blks; i++) {
u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left);
-
- status = ice_acquire_nvm(hw, ICE_RES_READ);
- if (status) {
- dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
- status, hw->adminq.sq_last_status);
- NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
- vfree(nvm_data);
- return -EIO;
- }
+ enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE,
- &read_sz, tmp, read_shadow_ram);
+ &read_sz, tmp, read_shadow_ram,
+ &read_aq_err);
if (status) {
dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
- read_sz, status, hw->adminq.sq_last_status);
+ read_sz, status, read_aq_err);
NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
- ice_release_nvm(hw);
vfree(nvm_data);
return -EIO;
}
- ice_release_nvm(hw);
tmp += read_sz;
left -= read_sz;
@@ -1940,6 +1934,7 @@ static int ice_devlink_nvm_read(struct devlink *devlink,
struct netlink_ext_ack *extack,
u64 offset, u32 size, u8 *data)
{
+ enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
struct ice_pf *pf = devlink_priv(devlink);
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
@@ -1963,24 +1958,14 @@ static int ice_devlink_nvm_read(struct devlink *devlink,
return -ERANGE;
}
- status = ice_acquire_nvm(hw, ICE_RES_READ);
- if (status) {
- dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
- status, hw->adminq.sq_last_status);
- NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
- return -EIO;
- }
-
status = ice_read_flat_nvm(hw, (u32)offset, &size, data,
- read_shadow_ram);
+ read_shadow_ram, &read_aq_err);
if (status) {
dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
- size, status, hw->adminq.sq_last_status);
+ size, status, read_aq_err);
NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
- ice_release_nvm(hw);
return -EIO;
}
- ice_release_nvm(hw);
return 0;
}
diff --git a/drivers/net/ethernet/intel/ice/devlink/port.c b/drivers/net/ethernet/intel/ice/devlink/port.c
index 63fb36fc4b3d..2a2e56777f9f 100644
--- a/drivers/net/ethernet/intel/ice/devlink/port.c
+++ b/drivers/net/ethernet/intel/ice/devlink/port.c
@@ -58,8 +58,8 @@ static void ice_devlink_port_options_print(struct ice_pf *pf)
const char *str;
int status;
- options = kcalloc(ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV,
- sizeof(*options), GFP_KERNEL);
+ options = kzalloc_objs(*options,
+ ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV);
if (!options)
return;
@@ -920,7 +920,7 @@ ice_alloc_dynamic_port(struct ice_pf *pf,
if (err)
return err;
- dyn_port = kzalloc(sizeof(*dyn_port), GFP_KERNEL);
+ dyn_port = kzalloc_obj(*dyn_port);
if (!dyn_port) {
err = -ENOMEM;
goto unroll_reserve_sf_num;
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 147aaee192a7..db3c7015c56c 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -36,7 +36,7 @@
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/auxiliary_bus.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/cpu_rmap.h>
#include <linux/dim.h>
#include <linux/gnss.h>
@@ -753,7 +753,7 @@ static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi)
static inline void ice_set_ring_xdp(struct ice_tx_ring *ring)
{
- ring->flags |= ICE_TX_FLAGS_RING_XDP;
+ set_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
/**
@@ -767,6 +767,9 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
struct ice_vsi *vsi = ring->vsi;
struct ice_pf *pf = vsi->back;
+ if (vsi->type != ICE_VSI_PF)
+ return false;
+
return test_bit(ring->q_index, pf->txtime_txqs);
}
@@ -778,7 +781,7 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)
*/
static inline bool ice_is_txtime_cfg(const struct ice_tx_ring *ring)
{
- return !!(ring->flags & ICE_TX_FLAGS_TXTIME);
+ return test_bit(ICE_TX_RING_FLAGS_TXTIME, ring->flags);
}
/**
@@ -840,6 +843,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid)
}
/**
+ * ice_get_max_txq - return the maximum number of Tx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Tx queues
+ */
+static inline int ice_get_max_txq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
+}
+
+/**
+ * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Rx queues
+ */
+static inline int ice_get_max_rxq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
+}
+
+/**
* ice_get_main_vsi - Get the PF VSI
* @pf: PF instance
*
@@ -957,9 +982,6 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf);
int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);
void ice_update_vsi_stats(struct ice_vsi *vsi);
void ice_update_pf_stats(struct ice_pf *pf);
-void
-ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp,
- struct ice_q_stats stats, u64 *pkts, u64 *bytes);
int ice_up(struct ice_vsi *vsi);
int ice_down(struct ice_vsi *vsi);
int ice_down_up(struct ice_vsi *vsi);
@@ -979,6 +1001,7 @@ void ice_map_xdp_rings(struct ice_vsi *vsi);
int
ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
u32 flags);
+int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
int ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size);
int ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size);
int ice_set_rss_key(struct ice_vsi *vsi, u8 *seed);
@@ -989,6 +1012,7 @@ int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
int ice_plug_aux_dev(struct ice_pf *pf);
void ice_unplug_aux_dev(struct ice_pf *pf);
+void ice_rdma_finalize_setup(struct ice_pf *pf);
int ice_init_rdma(struct ice_pf *pf);
void ice_deinit_rdma(struct ice_pf *pf);
bool ice_is_wol_supported(struct ice_hw *hw);
@@ -1134,4 +1158,16 @@ static inline struct ice_hw *ice_get_primary_hw(struct ice_pf *pf)
else
return &pf->adapter->ctrl_pf->hw;
}
+
+/**
+ * ice_get_ctrl_pf - Get pointer to Control PF of the adapter
+ * @pf: pointer to the current PF structure
+ *
+ * Return: A pointer to ice_pf structure which is Control PF,
+ * NULL if it's not initialized yet.
+ */
+static inline struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf)
+{
+ return !pf->adapter ? NULL : pf->adapter->ctrl_pf;
+}
#endif /* _ICE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c
index 0a8a48cd4bce..2dc3629d6d0f 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.c
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.c
@@ -55,13 +55,15 @@ static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
{
struct ice_adapter *adapter;
- adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ adapter = kzalloc_obj(*adapter);
if (!adapter)
return NULL;
adapter->index = ice_adapter_index(pdev);
spin_lock_init(&adapter->ptp_gltsyn_time_lock);
spin_lock_init(&adapter->txq_ctx_lock);
+ for (int i = 0; i < ARRAY_SIZE(adapter->cpi_phy_lock); i++)
+ mutex_init(&adapter->cpi_phy_lock[i]);
refcount_set(&adapter->refcount, 1);
mutex_init(&adapter->ports.lock);
@@ -73,6 +75,8 @@ static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
static void ice_adapter_free(struct ice_adapter *adapter)
{
WARN_ON(!list_empty(&adapter->ports.ports));
+ for (int i = 0; i < ARRAY_SIZE(adapter->cpi_phy_lock); i++)
+ mutex_destroy(&adapter->cpi_phy_lock[i]);
mutex_destroy(&adapter->ports.lock);
kfree(adapter);
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h
index e95266c7f20b..4f695f32da3d 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.h
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.h
@@ -5,9 +5,12 @@
#define _ICE_ADAPTER_H_
#include <linux/types.h>
+#include <linux/mutex.h>
#include <linux/spinlock_types.h>
#include <linux/refcount_types.h>
+#include "ice_type.h"
+
struct pci_dev;
struct ice_pf;
@@ -31,6 +34,8 @@ struct ice_port_list {
* @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME
* register of the PTP clock.
* @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register
+ * @cpi_phy_lock: Per-PHY mutex serializing CPI REQ/ACK transactions.
+ * Index 0 = PHY0, index 1 = PHY1. Used on E825C devices.
* @ctrl_pf: Control PF of the adapter
* @ports: Ports list
* @index: 64-bit index cached for collision detection on 32bit systems
@@ -41,6 +46,8 @@ struct ice_adapter {
spinlock_t ptp_gltsyn_time_lock;
/* For access to GLCOMM_QTX_CNTX_CTL register */
spinlock_t txq_ctx_lock;
+ /* Serialize CPI REQ/ACK transactions per PHY (E825C only) */
+ struct mutex cpi_phy_lock[ICE_E825_MAX_PHYS];
struct ice_pf *ctrl_pf;
struct ice_port_list ports;
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 859e9c66f3e7..42878abac9eb 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1169,6 +1169,8 @@ struct ice_aqc_restart_an {
u8 cmd_flags;
#define ICE_AQC_RESTART_AN_LINK_RESTART BIT(1)
#define ICE_AQC_RESTART_AN_LINK_ENABLE BIT(2)
+#define ICE_AQC_RESTART_AN_REFCLK_M GENMASK(4, 3)
+#define ICE_AQC_RESTART_AN_REFCLK_NOCHANGE 0
u8 reserved2[13];
};
@@ -1252,7 +1254,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2
#define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3
__le16 link_speed;
-#define ICE_AQ_LINK_SPEED_M 0x7FF
+#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0)
#define ICE_AQ_LINK_SPEED_10MB BIT(0)
#define ICE_AQ_LINK_SPEED_100MB BIT(1)
#define ICE_AQ_LINK_SPEED_1000MB BIT(2)
diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c
index 1f7834c03550..53b6e2b09eb9 100644
--- a/drivers/net/ethernet/intel/ice/ice_arfs.c
+++ b/drivers/net/ethernet/intel/ice/ice_arfs.c
@@ -534,13 +534,11 @@ static int ice_init_arfs_cntrs(struct ice_vsi *vsi)
if (!vsi || vsi->type != ICE_VSI_PF)
return -EINVAL;
- vsi->arfs_fltr_cntrs = kzalloc(sizeof(*vsi->arfs_fltr_cntrs),
- GFP_KERNEL);
+ vsi->arfs_fltr_cntrs = kzalloc_obj(*vsi->arfs_fltr_cntrs);
if (!vsi->arfs_fltr_cntrs)
return -ENOMEM;
- vsi->arfs_last_fltr_id = kzalloc(sizeof(*vsi->arfs_last_fltr_id),
- GFP_KERNEL);
+ vsi->arfs_last_fltr_id = kzalloc_obj(*vsi->arfs_last_fltr_id);
if (!vsi->arfs_last_fltr_id) {
kfree(vsi->arfs_fltr_cntrs);
vsi->arfs_fltr_cntrs = NULL;
@@ -562,8 +560,7 @@ void ice_init_arfs(struct ice_vsi *vsi)
if (!vsi || vsi->type != ICE_VSI_PF || ice_is_arfs_active(vsi))
return;
- arfs_fltr_list = kcalloc(ICE_MAX_ARFS_LIST, sizeof(*arfs_fltr_list),
- GFP_KERNEL);
+ arfs_fltr_list = kzalloc_objs(*arfs_fltr_list, ICE_MAX_ARFS_LIST);
if (!arfs_fltr_list)
return;
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index eadb1e3d12b3..1667f686ff75 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -107,7 +107,7 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
int err;
/* allocate q_vector */
- q_vector = kzalloc(sizeof(*q_vector), GFP_KERNEL);
+ q_vector = kzalloc_obj(*q_vector);
if (!q_vector)
return -ENOMEM;
@@ -124,6 +124,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
if (vsi->type == ICE_VSI_VF) {
ice_calc_vf_reg_idx(vsi->vf, q_vector);
goto out;
+ } else if (vsi->type == ICE_VSI_LB) {
+ goto skip_alloc;
} else if (vsi->type == ICE_VSI_CTRL && vsi->vf) {
struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi);
@@ -659,33 +661,22 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{
struct device *dev = ice_pf_to_dev(ring->vsi->back);
u32 num_bufs = ICE_DESC_UNUSED(ring);
- u32 rx_buf_len;
int err;
- if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
+ if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
+ ring->vsi->type == ICE_VSI_LB) {
ice_rx_xsk_pool(ring);
err = ice_realloc_rx_xdp_bufs(ring, ring->xsk_pool);
if (err)
return err;
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
-
- rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ u32 frag_size =
+ xsk_pool_get_rx_frag_step(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- rx_buf_len);
+ frag_size);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -702,14 +693,13 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (err)
return err;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- goto err_destroy_fq;
- }
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->truesize);
+ if (err)
+ goto err_destroy_fq;
+
xdp_rxq_info_attach_page_pool(&ring->xdp_rxq,
ring->pp);
}
@@ -1414,8 +1404,8 @@ static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx)
if (!vsi_stat)
return;
- memset(&vsi_stat->rx_ring_stats[q_idx]->rx_stats, 0,
- sizeof(vsi_stat->rx_ring_stats[q_idx]->rx_stats));
+ memset(&vsi_stat->rx_ring_stats[q_idx]->stats, 0,
+ sizeof(vsi_stat->rx_ring_stats[q_idx]->stats));
memset(&vsi_stat->tx_ring_stats[q_idx]->stats, 0,
sizeof(vsi_stat->tx_ring_stats[q_idx]->stats));
if (vsi->xdp_rings)
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 046bc9c65c51..04633103e3e6 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -204,42 +204,6 @@ bool ice_is_generic_mac(struct ice_hw *hw)
}
/**
- * ice_is_pf_c827 - check if pf contains c827 phy
- * @hw: pointer to the hw struct
- *
- * Return: true if the device has c827 phy.
- */
-static bool ice_is_pf_c827(struct ice_hw *hw)
-{
- struct ice_aqc_get_link_topo cmd = {};
- u8 node_part_number;
- u16 node_handle;
- int status;
-
- if (hw->mac_type != ICE_MAC_E810)
- return false;
-
- if (hw->device_id != ICE_DEV_ID_E810C_QSFP)
- return true;
-
- cmd.addr.topo_params.node_type_ctx =
- FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY) |
- FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ICE_AQC_LINK_TOPO_NODE_CTX_PORT);
- cmd.addr.topo_params.index = 0;
-
- status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number,
- &node_handle);
-
- if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827)
- return false;
-
- if (node_handle == E810C_QSFP_C827_0_HANDLE || node_handle == E810C_QSFP_C827_1_HANDLE)
- return true;
-
- return false;
-}
-
-/**
* ice_clear_pf_cfg - Clear PF configuration
* @hw: pointer to the hardware structure
*
@@ -958,30 +922,31 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw)
}
/**
- * ice_wait_for_fw - wait for full FW readiness
+ * ice_wait_fw_load - wait for PHY firmware loading to complete
* @hw: pointer to the hardware structure
- * @timeout: milliseconds that can elapse before timing out
+ * @timeout: milliseconds that can elapse before timing out, 0 to bypass waiting
*
- * Return: 0 on success, -ETIMEDOUT on timeout.
+ * Return:
+ * * 0 on success
+ * * negative on timeout
*/
-static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout)
+static int ice_wait_fw_load(struct ice_hw *hw, u32 timeout)
{
- int fw_loading;
- u32 elapsed = 0;
+ int fw_loading_reg;
- while (elapsed <= timeout) {
- fw_loading = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M;
+ if (!timeout)
+ return 0;
- /* firmware was not yet loaded, we have to wait more */
- if (fw_loading) {
- elapsed += 100;
- msleep(100);
- continue;
- }
+ fw_loading_reg = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M;
+ /* notify the user only once if PHY FW is still loading */
+ if (fw_loading_reg)
+ dev_info(ice_hw_to_dev(hw), "Link initialization is blocked by PHY FW initialization. Link initialization will continue after PHY FW initialization completes.\n");
+ else
return 0;
- }
- return -ETIMEDOUT;
+ return rd32_poll_timeout(hw, GL_MNG_FWSM, fw_loading_reg,
+ !(fw_loading_reg & GL_MNG_FWSM_FW_LOADING_M),
+ 10000, timeout * 1000);
}
static int __fwlog_send_cmd(void *priv, struct libie_aq_desc *desc, void *buf,
@@ -1086,14 +1051,13 @@ int ice_init_hw(struct ice_hw *hw)
hw->evb_veb = true;
- /* init xarray for identifying scheduling nodes uniquely */
- xa_init_flags(&hw->port_info->sched_node_ids, XA_FLAGS_ALLOC);
+ xa_init_flags(&hw->sched_node_ids, XA_FLAGS_ALLOC);
/* Query the allocated resources for Tx scheduler */
status = ice_sched_query_res_alloc(hw);
if (status) {
ice_debug(hw, ICE_DBG_SCHED, "Failed to get scheduler allocated resources\n");
- goto err_unroll_alloc;
+ goto err_unroll_xarray;
}
ice_sched_get_psm_clk_freq(hw);
@@ -1102,7 +1066,7 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_sched;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps) {
status = -ENOMEM;
goto err_unroll_sched;
@@ -1138,8 +1102,7 @@ int ice_init_hw(struct ice_hw *hw)
/* Get MAC information */
/* A single port can report up to two (LAN and WoL) addresses */
- mac_buf = kcalloc(2, sizeof(struct ice_aqc_manage_mac_read_resp),
- GFP_KERNEL);
+ mac_buf = kzalloc_objs(struct ice_aqc_manage_mac_read_resp, 2);
if (!mac_buf) {
status = -ENOMEM;
goto err_unroll_fltr_mgmt_struct;
@@ -1162,8 +1125,6 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_fltr_mgmt_struct;
- ice_init_dev_hw(hw->back);
-
mutex_init(&hw->tnl_lock);
ice_init_chk_recipe_reuse_support(hw);
@@ -1171,12 +1132,10 @@ int ice_init_hw(struct ice_hw *hw)
* due to necessity of loading FW from an external source.
* This can take even half a minute.
*/
- if (ice_is_pf_c827(hw)) {
- status = ice_wait_for_fw(hw, 30000);
- if (status) {
- dev_err(ice_hw_to_dev(hw), "ice_wait_for_fw timed out");
- goto err_unroll_fltr_mgmt_struct;
- }
+ status = ice_wait_fw_load(hw, 30000);
+ if (status) {
+ dev_err(ice_hw_to_dev(hw), "ice_wait_fw_load timed out");
+ goto err_unroll_fltr_mgmt_struct;
}
hw->lane_num = ice_get_phy_lane_number(hw);
@@ -1186,6 +1145,8 @@ err_unroll_fltr_mgmt_struct:
ice_cleanup_fltr_mgmt_struct(hw);
err_unroll_sched:
ice_sched_cleanup_all(hw);
+err_unroll_xarray:
+ xa_destroy(&hw->sched_node_ids);
err_unroll_alloc:
devm_kfree(ice_hw_to_dev(hw), hw->port_info);
err_unroll_cqinit:
@@ -1226,6 +1187,8 @@ void ice_deinit_hw(struct ice_hw *hw)
/* Clear VSI contexts if not already cleared */
ice_clear_all_vsi_ctx(hw);
+
+ xa_destroy(&hw->sched_node_ids);
}
/**
@@ -1854,6 +1817,7 @@ static bool ice_should_retry_sq_send_cmd(u16 opcode)
case ice_aqc_opc_lldp_stop:
case ice_aqc_opc_lldp_start:
case ice_aqc_opc_lldp_filter_ctrl:
+ case ice_aqc_opc_sff_eeprom:
return true;
}
@@ -1879,6 +1843,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
{
struct libie_aq_desc desc_cpy;
bool is_cmd_for_retry;
+ u8 *buf_cpy = NULL;
u8 idx = 0;
u16 opcode;
int status;
@@ -1888,8 +1853,11 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
memset(&desc_cpy, 0, sizeof(desc_cpy));
if (is_cmd_for_retry) {
- /* All retryable cmds are direct, without buf. */
- WARN_ON(buf);
+ if (buf) {
+ buf_cpy = kmemdup(buf, buf_size, GFP_KERNEL);
+ if (!buf_cpy)
+ return -ENOMEM;
+ }
memcpy(&desc_cpy, desc, sizeof(desc_cpy));
}
@@ -1901,12 +1869,14 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
break;
+ if (buf_cpy)
+ memcpy(buf, buf_cpy, buf_size);
memcpy(desc, &desc_cpy, sizeof(desc_cpy));
-
msleep(ICE_SQ_SEND_DELAY_TIME_MS);
} while (++idx < ICE_SQ_SEND_MAX_EXECUTE);
+ kfree(buf_cpy);
return status;
}
@@ -2251,7 +2221,7 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
/* there are some rare cases when trying to release the resource
* results in an admin queue timeout, so handle them correctly
*/
- timeout = jiffies + 10 * ICE_CTL_Q_SQ_CMD_TIMEOUT;
+ timeout = jiffies + 10 * usecs_to_jiffies(ICE_CTL_Q_SQ_CMD_TIMEOUT);
do {
status = ice_aq_release_res(hw, res, 0, NULL);
if (status != -EIO)
@@ -3667,7 +3637,7 @@ int ice_update_link_info(struct ice_port_info *pi)
if (li->link_info & ICE_AQ_MEDIA_AVAILABLE) {
struct ice_aqc_get_phy_caps_data *pcaps __free(kfree) = NULL;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -3915,10 +3885,9 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
if (!pi || !aq_failures)
return -EINVAL;
- *aq_failures = 0;
hw = pi->hw;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -4057,7 +4026,7 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
hw = pi->hw;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -4157,12 +4126,13 @@ int ice_get_link_status(struct ice_port_info *pi, bool *link_up)
* @pi: pointer to the port information structure
* @ena_link: if true: enable link, if false: disable link
* @cd: pointer to command details structure or NULL
+ * @refclk: the new TX reference clock, 0 if no change
*
* Sets up the link and restarts the Auto-Negotiation over the link.
*/
int
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
- struct ice_sq_cd *cd)
+ struct ice_sq_cd *cd, u8 refclk)
{
struct ice_aqc_restart_an *cmd;
struct libie_aq_desc desc;
@@ -4178,6 +4148,8 @@ ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
else
cmd->cmd_flags &= ~ICE_AQC_RESTART_AN_LINK_ENABLE;
+ cmd->cmd_flags |= FIELD_PREP(ICE_AQC_RESTART_AN_REFCLK_M, refclk);
+
return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd);
}
@@ -4395,7 +4367,7 @@ int ice_get_phy_lane_number(struct ice_hw *hw)
hw->device_id == ICE_DEV_ID_E825C_SGMII)
return hw->pf_id;
- options = kcalloc(ICE_AQC_PORT_OPT_MAX, sizeof(*options), GFP_KERNEL);
+ options = kzalloc_objs(*options, ICE_AQC_PORT_OPT_MAX);
if (!options)
return -ENOMEM;
@@ -6429,7 +6401,7 @@ int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add)
struct ice_aqc_lldp_filter_ctrl *cmd;
struct libie_aq_desc desc;
- if (vsi->type != ICE_VSI_PF || !ice_fw_supports_lldp_fltr_ctrl(hw))
+ if (!ice_fw_supports_lldp_fltr_ctrl(hw))
return -EOPNOTSUPP;
cmd = libie_aq_raw(&desc);
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index e700ac0dc347..d1d674ca644f 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -5,13 +5,13 @@
#define _ICE_COMMON_H_
#include <linux/bitfield.h>
+#include <linux/net/intel/virtchnl.h>
#include "ice.h"
#include "ice_type.h"
#include "ice_nvm.h"
#include "ice_flex_pipe.h"
#include "ice_parser.h"
-#include <linux/avf/virtchnl.h>
#include "ice_switch.h"
#include "ice_fdir.h"
@@ -215,7 +215,7 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
enum ice_fec_mode fec);
int
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
- struct ice_sq_cd *cd);
+ struct ice_sq_cd *cd, u8 refclk);
int
ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd);
int
diff --git a/drivers/net/ethernet/intel/ice/ice_cpi.c b/drivers/net/ethernet/intel/ice/ice_cpi.c
new file mode 100644
index 000000000000..0faa7f1de321
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_cpi.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2026 Intel Corporation */
+
+#include "ice_type.h"
+#include "ice_common.h"
+#include "ice_ptp_hw.h"
+#include "ice.h"
+#include "ice_cpi.h"
+
+/**
+ * ice_cpi_get_dest_dev - get destination PHY for given phy index
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ *
+ * Return: sideband queue destination PHY device.
+ */
+static enum ice_sbq_dev_id ice_cpi_get_dest_dev(struct ice_hw *hw, u8 phy)
+{
+ u8 curr_phy = hw->lane_num / hw->ptp.ports_per_phy;
+
+ /* In the driver, lanes 4..7 are in fact 0..3 on a second PHY.
+ * On a single complex E825C, PHY 0 is always destination device phy_0
+ * and PHY 1 is phy_0_peer.
+ * On dual complex E825C, device phy_0 points to PHY on a current
+ * complex and phy_0_peer to PHY on a different complex.
+ */
+ if ((!ice_is_dual(hw) && phy) ||
+ (ice_is_dual(hw) && phy != curr_phy))
+ return ice_sbq_dev_phy_0_peer;
+ else
+ return ice_sbq_dev_phy_0;
+}
+
+/**
+ * ice_cpi_write_phy - Write a CPI port register
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @addr: PHY register address
+ * @val: Value to write
+ *
+ * Return:
+ * * 0 on success
+ * * other error codes when failed to write to PHY
+ */
+static int ice_cpi_write_phy(struct ice_hw *hw, u8 phy, u32 addr, u32 val)
+{
+ struct ice_sbq_msg_input msg = {
+ .dest_dev = ice_cpi_get_dest_dev(hw, phy),
+ .opcode = ice_sbq_msg_wr_np,
+ .msg_addr_low = lower_16_bits(addr),
+ .msg_addr_high = upper_16_bits(addr),
+ .data = val
+ };
+ int err;
+
+ err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to write CPI msg to phy %d, err: %d\n",
+ phy, err);
+
+ return err;
+}
+
+/**
+ * ice_cpi_read_phy - Read a CPI port register
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @addr: PHY register address
+ * @val: storage for register value
+ *
+ * Return:
+ * * 0 on success
+ * * other error codes when failed to read from PHY
+ */
+static int ice_cpi_read_phy(struct ice_hw *hw, u8 phy, u32 addr, u32 *val)
+{
+ struct ice_sbq_msg_input msg = {
+ .dest_dev = ice_cpi_get_dest_dev(hw, phy),
+ .opcode = ice_sbq_msg_rd,
+ .msg_addr_low = lower_16_bits(addr),
+ .msg_addr_high = upper_16_bits(addr)
+ };
+ int err;
+
+ err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to read CPI msg from phy %d, err: %d\n",
+ phy, err);
+ return err;
+ }
+
+ *val = msg.data;
+
+ return 0;
+}
+
+/**
+ * ice_cpi_wait_req0_ack0 - waits for CPI interface to be available
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ *
+ * This function checks if CPI interface is ready to use by CPI client.
+ * It's done by assuring LM.CMD.REQ and PHY.CMD.ACK bit in CPI
+ * interface registers to be 0.
+ *
+ * Return: 0 on success, negative on error
+ */
+static int ice_cpi_wait_req0_ack0(struct ice_hw *hw, int phy)
+{
+ u32 phy_val;
+ u32 lm_val;
+
+ for (int i = 0; i < CPI_RETRIES_COUNT; i++) {
+ int err;
+
+ /* check if another CPI Client is also accessing CPI */
+ err = ice_cpi_read_phy(hw, phy, CPI0_LM1_CMD_DATA, &lm_val);
+ if (err)
+ return err;
+ if (FIELD_GET(CPI_LM_CMD_REQ_M, lm_val))
+ goto retry;
+
+ /* check if PHY.ACK is deasserted */
+ err = ice_cpi_read_phy(hw, phy, CPI0_PHY1_CMD_DATA, &phy_val);
+ if (err)
+ return err;
+ if (!FIELD_GET(CPI_PHY_CMD_ACK_M, phy_val))
+ /* req0 and ack0 at this point - ready to go */
+ return 0;
+
+retry:
+ msleep(CPI_RETRIES_CADENCE_MS);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * ice_cpi_wait_ack - Waits for the PHY.ACK bit to be asserted/deasserted
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @asserted: desired state of PHY.ACK bit
+ * @data: pointer to the user data where PHY.data is stored
+ *
+ * This function checks if PHY.ACK bit is asserted or deasserted, depending
+ * on the phase of CPI handshake. If 'asserted' state is required, PHY command
+ * data is stored in the 'data' storage.
+ *
+ * Return: 0 on success, negative on error
+ */
+static int ice_cpi_wait_ack(struct ice_hw *hw, u8 phy, bool asserted,
+ u32 *data)
+{
+ u32 phy_val;
+
+ for (int i = 0; i < CPI_RETRIES_COUNT; i++) {
+ int err;
+
+ err = ice_cpi_read_phy(hw, phy, CPI0_PHY1_CMD_DATA, &phy_val);
+ if (err)
+ return err;
+ if (asserted && FIELD_GET(CPI_PHY_CMD_ERROR_M, phy_val))
+ return -EFAULT;
+ if (asserted && FIELD_GET(CPI_PHY_CMD_ACK_M, phy_val)) {
+ if (data)
+ *data = phy_val;
+ return 0;
+ }
+ if (!asserted && !FIELD_GET(CPI_PHY_CMD_ACK_M, phy_val))
+ return 0;
+
+ msleep(CPI_RETRIES_CADENCE_MS);
+ }
+
+ return -ETIMEDOUT;
+}
+
+#define ice_cpi_wait_ack0(hw, port) \
+ ice_cpi_wait_ack(hw, port, false, NULL)
+
+#define ice_cpi_wait_ack1(hw, port, data) \
+ ice_cpi_wait_ack(hw, port, true, data)
+
+/**
+ * ice_cpi_req0 - deasserts LM.REQ bit
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @data: the command data
+ *
+ * Return: 0 on success, negative on CPI write error
+ */
+static int ice_cpi_req0(struct ice_hw *hw, u8 phy, u32 data)
+{
+ data &= ~CPI_LM_CMD_REQ_M;
+
+ return ice_cpi_write_phy(hw, phy, CPI0_LM1_CMD_DATA, data);
+}
+
+/**
+ * ice_cpi_exec_cmd - writes command data to CPI interface
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @data: the command data
+ *
+ * Return: 0 on success, otherwise negative on error
+ */
+static int ice_cpi_exec_cmd(struct ice_hw *hw, int phy, u32 data)
+{
+ return ice_cpi_write_phy(hw, phy, CPI0_LM1_CMD_DATA, data);
+}
+
+/**
+ * ice_cpi_phy_lock - get per-PHY lock for CPI transaction serialization
+ * @hw: pointer to the HW struct
+ * @phy: PHY index
+ *
+ * Return: pointer to PHY mutex, or %NULL when context is unavailable.
+ */
+static struct mutex *ice_cpi_phy_lock(struct ice_hw *hw, u8 phy)
+{
+ struct ice_pf *pf = hw->back;
+
+ if (!pf || !pf->adapter || phy >= ICE_E825_MAX_PHYS)
+ return NULL;
+
+ return &pf->adapter->cpi_phy_lock[phy];
+}
+
+/**
+ * ice_cpi_exec - executes CPI command
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port the CPI action is taken on
+ * @cmd: pointer to the command struct to execute
+ * @resp: pointer to user allocated CPI response struct
+ *
+ * This function executes CPI request with respect to CPI handshake
+ * mechanism.
+ *
+ * Return: 0 on success, otherwise negative on error
+ */
+int ice_cpi_exec(struct ice_hw *hw, u8 phy,
+ const struct ice_cpi_cmd *cmd,
+ struct ice_cpi_resp *resp)
+{
+ struct mutex *cpi_lock; /* serializes CPI transactions per PHY */
+ u32 phy_cmd, lm_cmd = 0;
+ int err, err1 = 0;
+
+ if (!cmd || !resp)
+ return -EINVAL;
+
+ cpi_lock = ice_cpi_phy_lock(hw, phy);
+ if (!cpi_lock)
+ return -EINVAL;
+
+ mutex_lock(cpi_lock);
+
+ lm_cmd =
+ FIELD_PREP(CPI_LM_CMD_REQ_M, CPI_LM_CMD_REQ) |
+ FIELD_PREP(CPI_LM_CMD_GET_SET_M, cmd->set) |
+ FIELD_PREP(CPI_LM_CMD_OPCODE_M, cmd->opcode) |
+ FIELD_PREP(CPI_LM_CMD_PORTLANE_M, cmd->port) |
+ FIELD_PREP(CPI_LM_CMD_DATA_M, cmd->data);
+
+ /* 1. Try to acquire the bus, PHY ACK should be low before we begin */
+ err = ice_cpi_wait_req0_ack0(hw, phy);
+ if (err)
+ goto cpi_exec_exit;
+
+ /* 2. We start the CPI request */
+ err = ice_cpi_exec_cmd(hw, phy, lm_cmd);
+ if (err)
+ goto cpi_deassert;
+
+ /*
+ * 3. Wait for CPI confirmation, PHY ACK should be asserted and opcode
+ * echoed in the response
+ */
+ err = ice_cpi_wait_ack1(hw, phy, &phy_cmd);
+ if (err)
+ goto cpi_deassert;
+
+ if (FIELD_GET(CPI_LM_CMD_OPCODE_M, lm_cmd) !=
+ FIELD_GET(CPI_PHY_CMD_OPCODE_M, phy_cmd)) {
+ err = -EFAULT;
+ goto cpi_deassert;
+ }
+
+ resp->opcode = FIELD_GET(CPI_PHY_CMD_OPCODE_M, phy_cmd);
+ resp->data = FIELD_GET(CPI_PHY_CMD_DATA_M, phy_cmd);
+ resp->port = FIELD_GET(CPI_PHY_CMD_PORTLANE_M, phy_cmd);
+
+cpi_deassert:
+ /* 4. We deassert REQ */
+ err1 = ice_cpi_req0(hw, phy, lm_cmd);
+ if (err1)
+ goto cpi_exec_exit;
+
+ /* 5. PHY ACK should be deasserted in response */
+ err1 = ice_cpi_wait_ack0(hw, phy);
+
+cpi_exec_exit:
+ if (!err)
+ err = err1;
+
+ mutex_unlock(cpi_lock);
+
+ return err;
+}
+
+/**
+ * ice_cpi_set_cmd - execute CPI SET command
+ * @hw: pointer to the HW struct
+ * @opcode: CPI command opcode
+ * @phy: phy index CPI command is applied for
+ * @port_lane: ephy index CPI command is applied for
+ * @data: CPI opcode context specific data
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int ice_cpi_set_cmd(struct ice_hw *hw, u8 opcode, u8 phy, u8 port_lane,
+ u16 data)
+{
+ struct ice_cpi_resp cpi_resp = {0};
+ struct ice_cpi_cmd cpi_cmd = {
+ .opcode = opcode,
+ .set = true,
+ .port = port_lane,
+ .data = data,
+ };
+
+ return ice_cpi_exec(hw, phy, &cpi_cmd, &cpi_resp);
+}
+
+/**
+ * ice_cpi_ena_dis_clk_ref - enables/disables Tx reference clock on port
+ * @hw: pointer to the HW struct
+ * @phy: phy index of port for which Tx reference clock is enabled/disabled
+ * @clk: Tx reference clock to enable or disable
+ * @enable: bool value to enable or disable Tx reference clock
+ *
+ * This function executes CPI request to enable or disable specific
+ * Tx reference clock on given PHY.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int ice_cpi_ena_dis_clk_ref(struct ice_hw *hw, u8 phy,
+ enum ice_e825c_ref_clk clk, bool enable)
+{
+ u16 val;
+
+ val = FIELD_PREP(CPI_OPCODE_PHY_CLK_PHY_SEL_M, phy) |
+ FIELD_PREP(CPI_OPCODE_PHY_CLK_REF_CTRL_M,
+ enable ? CPI_OPCODE_PHY_CLK_ENABLE :
+ CPI_OPCODE_PHY_CLK_DISABLE) |
+ FIELD_PREP(CPI_OPCODE_PHY_CLK_REF_SEL_M, clk);
+
+ return ice_cpi_set_cmd(hw, CPI_OPCODE_PHY_CLK, phy, 0, val);
+}
+
diff --git a/drivers/net/ethernet/intel/ice/ice_cpi.h b/drivers/net/ethernet/intel/ice/ice_cpi.h
new file mode 100644
index 000000000000..6a45a920f8c2
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_cpi.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef _ICE_CPI_H_
+#define _ICE_CPI_H_
+
+#include "ice_type.h"
+#include "ice_ptp_hw.h"
+
+#define CPI0_PHY1_CMD_DATA 0x7FD028
+#define CPI0_LM1_CMD_DATA 0x7FD024
+#define CPI_RETRIES_COUNT 10
+#define CPI_RETRIES_CADENCE_MS 100
+
+/* CPI PHY CMD DATA register (CPI0_PHY1_CMD_DATA) */
+#define CPI_PHY_CMD_DATA_M GENMASK(15, 0)
+#define CPI_PHY_CMD_OPCODE_M GENMASK(23, 16)
+#define CPI_PHY_CMD_PORTLANE_M GENMASK(26, 24)
+#define CPI_PHY_CMD_RSVD_M GENMASK(29, 27)
+#define CPI_PHY_CMD_ERROR_M BIT(30)
+#define CPI_PHY_CMD_ACK_M BIT(31)
+
+/* CPI LM CMD DATA register (CPI0_LM1_CMD_DATA) */
+#define CPI_LM_CMD_DATA_M GENMASK(15, 0)
+#define CPI_LM_CMD_OPCODE_M GENMASK(23, 16)
+#define CPI_LM_CMD_PORTLANE_M GENMASK(26, 24)
+#define CPI_LM_CMD_RSVD_M GENMASK(28, 27)
+#define CPI_LM_CMD_GET_SET_M BIT(29)
+#define CPI_LM_CMD_REQ_M BIT(31)
+
+#define CPI_OPCODE_PHY_CLK 0xF1
+#define CPI_OPCODE_PHY_CLK_PHY_SEL_M GENMASK(9, 6)
+#define CPI_OPCODE_PHY_CLK_REF_CTRL_M GENMASK(5, 4)
+#define CPI_OPCODE_PHY_CLK_DISABLE 1
+#define CPI_OPCODE_PHY_CLK_ENABLE 2
+#define CPI_OPCODE_PHY_CLK_REF_SEL_M GENMASK(3, 0)
+
+#define CPI_LM_CMD_REQ 1
+
+struct ice_cpi_cmd {
+ u8 port;
+ u8 opcode;
+ u16 data;
+ bool set;
+};
+
+struct ice_cpi_resp {
+ u8 port;
+ u8 opcode;
+ u16 data;
+};
+
+int ice_cpi_exec(struct ice_hw *hw, u8 phy,
+ const struct ice_cpi_cmd *cmd,
+ struct ice_cpi_resp *resp);
+int ice_cpi_ena_dis_clk_ref(struct ice_hw *hw, u8 phy,
+ enum ice_e825c_ref_clk clk, bool enable);
+#endif /* _ICE_CPI_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
index 9fc8681cc58e..0bc6dd375687 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
@@ -399,7 +399,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked)
}
/* Notify AUX drivers about impending change to TCs */
- event = kzalloc(sizeof(*event), GFP_KERNEL);
+ event = kzalloc_obj(*event);
if (!event) {
ret = -ENOMEM;
goto free_cfg;
@@ -537,14 +537,14 @@ void ice_dcb_rebuild(struct ice_pf *pf)
struct ice_dcbx_cfg *err_cfg;
int ret;
+ mutex_lock(&pf->tc_mutex);
+
ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL);
if (ret) {
dev_err(dev, "Query Port ETS failed\n");
goto dcb_error;
}
- mutex_lock(&pf->tc_mutex);
-
if (!pf->hw.port_info->qos_cfg.is_sw_lldp)
ice_cfg_etsrec_defaults(pf->hw.port_info);
@@ -575,7 +575,7 @@ void ice_dcb_rebuild(struct ice_pf *pf)
dcb_error:
dev_err(dev, "Disabling DCB until new settings occur\n");
- err_cfg = kzalloc(sizeof(*err_cfg), GFP_KERNEL);
+ err_cfg = kzalloc_obj(*err_cfg);
if (!err_cfg) {
mutex_unlock(&pf->tc_mutex);
return;
@@ -641,7 +641,7 @@ int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool ets_willing, bool locked)
hw = &pf->hw;
pi = hw->port_info;
- dcbcfg = kzalloc(sizeof(*dcbcfg), GFP_KERNEL);
+ dcbcfg = kzalloc_obj(*dcbcfg);
if (!dcbcfg)
return -ENOMEM;
@@ -791,7 +791,7 @@ void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked)
privd = cdev->iidc_priv;
ice_setup_dcb_qos_info(pf, &privd->qos_info);
/* Notify the AUX drivers that TC change is finished */
- event = kzalloc(sizeof(*event), GFP_KERNEL);
+ event = kzalloc_obj(*event);
if (!event)
return;
@@ -943,7 +943,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring,
/* if this is not already set it means a VLAN 0 + priority needs
* to be offloaded
*/
- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
+ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 53b54e395a2e..85a74cd6ea1f 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -4,7 +4,9 @@
#include "ice.h"
#include "ice_lib.h"
#include "ice_trace.h"
+#include "ice_txclk.h"
#include <linux/dpll.h>
+#include <linux/property.h>
#define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50
#define ICE_DPLL_PIN_IDX_INVALID 0xff
@@ -18,6 +20,9 @@
#define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP 6
#define ICE_DPLL_SW_PIN_OUTPUT_BASE 0
+#define E825_RCLK_PARENT_0_PIN_IDX 0
+#define E825_RCLK_PARENT_1_PIN_IDX 1
+
#define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \
(ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx))
@@ -56,6 +61,7 @@
* @ICE_DPLL_PIN_TYPE_OUTPUT: output pin
* @ICE_DPLL_PIN_TYPE_RCLK_INPUT: recovery clock input pin
* @ICE_DPLL_PIN_TYPE_SOFTWARE: software controlled SMA/U.FL pins
+ * @ICE_DPLL_PIN_TYPE_TXCLK: transmit clock reference input pin
*/
enum ice_dpll_pin_type {
ICE_DPLL_PIN_INVALID,
@@ -63,6 +69,7 @@ enum ice_dpll_pin_type {
ICE_DPLL_PIN_TYPE_OUTPUT,
ICE_DPLL_PIN_TYPE_RCLK_INPUT,
ICE_DPLL_PIN_TYPE_SOFTWARE,
+ ICE_DPLL_PIN_TYPE_TXCLK,
};
static const char * const pin_type_name[] = {
@@ -70,10 +77,13 @@ static const char * const pin_type_name[] = {
[ICE_DPLL_PIN_TYPE_OUTPUT] = "output",
[ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input",
[ICE_DPLL_PIN_TYPE_SOFTWARE] = "software",
+ [ICE_DPLL_PIN_TYPE_TXCLK] = "txclk-input",
};
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 struct dpll_pin_frequency ice_esync_range[] = {
DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),
@@ -529,6 +539,94 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin,
}
/**
+ * ice_dpll_pin_store_state - updates the state of pin in SW bookkeeping
+ * @pin: pointer to a pin
+ * @parent: parent pin index
+ * @state: pin state (connected or disconnected)
+ */
+static void
+ice_dpll_pin_store_state(struct ice_dpll_pin *pin, int parent, bool state)
+{
+ pin->state[parent] = state ? DPLL_PIN_STATE_CONNECTED :
+ DPLL_PIN_STATE_DISCONNECTED;
+}
+
+/**
+ * ice_dpll_rclk_update_e825c - updates the state of rclk pin on e825c device
+ * @pf: private board struct
+ * @pin: pointer to a pin
+ *
+ * Update struct holding pin states info, states are separate for each parent
+ *
+ * Context: Called under pf->dplls.lock
+ * Return:
+ * * 0 - OK
+ * * negative - error
+ */
+static int ice_dpll_rclk_update_e825c(struct ice_pf *pf,
+ struct ice_dpll_pin *pin)
+{
+ u8 rclk_bits;
+ int err;
+ u32 reg;
+
+ if (pf->dplls.rclk.num_parents > ICE_SYNCE_CLK_NUM)
+ return -EINVAL;
+
+ err = ice_read_cgu_reg(&pf->hw, ICE_CGU_R10, &reg);
+ if (err)
+ return err;
+
+ rclk_bits = FIELD_GET(ICE_CGU_R10_SYNCE_S_REF_CLK, reg);
+ ice_dpll_pin_store_state(pin, ICE_SYNCE_CLK0, rclk_bits ==
+ (pf->ptp.port.port_num + ICE_CGU_BYPASS_MUX_OFFSET_E825C));
+
+ err = ice_read_cgu_reg(&pf->hw, ICE_CGU_R11, &reg);
+ if (err)
+ return err;
+
+ rclk_bits = FIELD_GET(ICE_CGU_R11_SYNCE_S_BYP_CLK, reg);
+ ice_dpll_pin_store_state(pin, ICE_SYNCE_CLK1, rclk_bits ==
+ (pf->ptp.port.port_num + ICE_CGU_BYPASS_MUX_OFFSET_E825C));
+
+ return 0;
+}
+
+/**
+ * ice_dpll_rclk_update - updates the state of rclk pin on a device
+ * @pf: private board struct
+ * @pin: pointer to a pin
+ * @port_num: port number
+ *
+ * Update struct holding pin states info, states are separate for each parent
+ *
+ * Context: Called under pf->dplls.lock
+ * Return:
+ * * 0 - OK
+ * * negative - error
+ */
+static int ice_dpll_rclk_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
+ u8 port_num)
+{
+ int ret;
+
+ for (u8 parent = 0; parent < pf->dplls.rclk.num_parents; parent++) {
+ u8 p = parent;
+
+ ret = ice_aq_get_phy_rec_clk_out(&pf->hw, &p, &port_num,
+ &pin->flags[parent], NULL);
+ if (ret)
+ return ret;
+
+ ice_dpll_pin_store_state(pin, parent,
+ ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN &
+ pin->flags[parent]);
+ }
+
+ return 0;
+}
+
+/**
* ice_dpll_sw_pins_update - update status of all SW pins
* @pf: private board struct
*
@@ -668,22 +766,14 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
}
break;
case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
- for (parent = 0; parent < pf->dplls.rclk.num_parents;
- parent++) {
- u8 p = parent;
-
- ret = ice_aq_get_phy_rec_clk_out(&pf->hw, &p,
- &port_num,
- &pin->flags[parent],
- NULL);
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ ret = ice_dpll_rclk_update_e825c(pf, pin);
+ if (ret)
+ goto err;
+ } else {
+ ret = ice_dpll_rclk_update(pf, pin, port_num);
if (ret)
goto err;
- if (ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN &
- pin->flags[parent])
- pin->state[parent] = DPLL_PIN_STATE_CONNECTED;
- else
- pin->state[parent] =
- DPLL_PIN_STATE_DISCONNECTED;
}
break;
case ICE_DPLL_PIN_TYPE_SOFTWARE:
@@ -703,7 +793,7 @@ err:
ret,
libie_aq_str(pf->hw.adminq.sq_last_status),
pin_type_name[pin_type], pin->idx);
- else
+ else if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
dev_err_ratelimited(ice_pf_to_dev(pf),
"err:%d %s failed to update %s pin:%u\n",
ret,
@@ -1074,6 +1164,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv,
}
/**
+ * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change
+ * @d: pointer to dplls struct
+ * @changed: the SW pin that was explicitly changed (already notified by dpll core)
+ *
+ * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and
+ * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO
+ * expander, the paired pin's state may also change. Send a change
+ * notification for the peer pin so userspace consumers monitoring the
+ * peer via dpll netlink learn about the update.
+ *
+ * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is
+ * released. Uses __dpll_pin_change_ntf() because dpll_lock is
+ * still held by the dpll netlink layer.
+ */
+static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d,
+ struct ice_dpll_pin *changed)
+{
+ struct ice_dpll_pin *peer;
+
+ peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ?
+ &d->ufl[changed->idx] : &d->sma[changed->idx];
+ if (peer->pin)
+ __dpll_pin_change_ntf(peer->pin);
+}
+
+/**
* ice_dpll_sma_direction_set - set direction of SMA pin
* @p: pointer to a pin
* @direction: requested direction of the pin
@@ -1090,6 +1206,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
enum dpll_pin_direction direction,
struct netlink_ext_ack *extack)
{
+ struct ice_dplls *d = &p->pf->dplls;
+ struct ice_dpll_pin *peer;
u8 data;
int ret;
@@ -1108,8 +1226,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
case ICE_DPLL_PIN_SW_2_IDX:
if (direction == DPLL_PIN_DIRECTION_INPUT) {
data &= ~ICE_SMA2_DIR_EN;
+ data |= ICE_SMA2_UFL2_RX_DIS;
} else {
- data &= ~ICE_SMA2_TX_EN;
+ data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS);
data |= ICE_SMA2_DIR_EN;
}
break;
@@ -1121,6 +1240,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
ret = ice_dpll_pin_state_update(p->pf, p,
ICE_DPLL_PIN_TYPE_SOFTWARE,
extack);
+ if (ret)
+ return ret;
+
+ /* When a direction change activates the paired U.FL pin, enable
+ * its backing CGU pin so the pin reports as connected. Without
+ * this the U.FL routing is correct but the CGU pin stays disabled
+ * and userspace sees the pin as disconnected. Do not disable the
+ * backing pin when U.FL becomes inactive because the SMA pin may
+ * still be using it.
+ */
+ peer = &d->ufl[p->idx];
+ if (peer->active) {
+ struct ice_dpll_pin *target;
+ enum ice_dpll_pin_type type;
+
+ if (peer->output) {
+ target = peer->output;
+ type = ICE_DPLL_PIN_TYPE_OUTPUT;
+ } else {
+ target = peer->input;
+ type = ICE_DPLL_PIN_TYPE_INPUT;
+ }
+ ret = ice_dpll_pin_enable(&p->pf->hw, target,
+ d->eec.dpll_idx, type, extack);
+ if (!ret)
+ ret = ice_dpll_pin_state_update(p->pf, target,
+ type, extack);
+ }
return ret;
}
@@ -1172,6 +1319,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA1_MASK;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
+ /* Skip if U.FL1 is not active, setting TX_EN
+ * while DIR_EN is set would also deactivate
+ * the paired SMA1 output.
+ */
+ if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) {
+ ret = 0;
+ goto unlock;
+ }
data |= ICE_SMA1_TX_EN;
enable = false;
} else {
@@ -1186,6 +1341,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA2_UFL2_RX_DIS;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
+ /* Skip if U.FL2 is not active, setting
+ * UFL2_RX_DIS could also disable the paired
+ * SMA2 input.
+ */
+ if (!(data & ICE_SMA2_DIR_EN) ||
+ (data & ICE_SMA2_UFL2_RX_DIS)) {
+ ret = 0;
+ goto unlock;
+ }
data |= ICE_SMA2_UFL2_RX_DIS;
enable = false;
} else {
@@ -1215,6 +1379,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1333,6 +1499,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, sma);
return ret;
}
@@ -1528,6 +1696,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv,
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_sma_direction_set(p, direction, extack);
mutex_unlock(&pf->dplls.lock);
+ if (!ret)
+ ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1834,7 +2004,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
d->active_input == p->input->pin))
*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
else if (d->phase_offset_monitor_period)
- *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
+ *phase_offset = (p->input &&
+ p->direction == DPLL_PIN_DIRECTION_INPUT ?
+ p->input->phase_offset :
+ p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR;
else
*phase_offset = 0;
mutex_unlock(&pf->dplls.lock);
@@ -1843,6 +2016,40 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
}
/**
+ * ice_dpll_synce_update_e825c - setting PHY recovered clock pins on e825c
+ * @hw: Pointer to the HW struct
+ * @ena: true if enable, false in disable
+ * @port_num: port number
+ * @output: output pin, we have two in E825C
+ *
+ * DPLL subsystem callback. Set proper signals to recover clock from port.
+ *
+ * Context: Called under pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int ice_dpll_synce_update_e825c(struct ice_hw *hw, bool ena,
+ u32 port_num, enum ice_synce_clk output)
+{
+ int err;
+
+ /* configure the mux to deliver proper signal to DPLL from the MUX */
+ err = ice_tspll_cfg_bypass_mux_e825c(hw, ena, port_num, output);
+ if (err)
+ return err;
+
+ err = ice_tspll_cfg_synce_ethdiv_e825c(hw, output);
+ if (err)
+ return err;
+
+ dev_dbg(ice_hw_to_dev(hw), "CLK_SYNCE%u recovered clock: pin %s\n",
+ output, str_enabled_disabled(ena));
+
+ return 0;
+}
+
+/**
* ice_dpll_output_esync_set - callback for setting embedded sync
* @pin: pointer to a pin
* @pin_priv: private data pointer passed on pin registration
@@ -2263,6 +2470,28 @@ ice_dpll_sw_input_ref_sync_get(const struct dpll_pin *pin, void *pin_priv,
state, extack);
}
+static int
+ice_dpll_pin_get_parent_num(struct ice_dpll_pin *pin,
+ const struct dpll_pin *parent)
+{
+ int i;
+
+ for (i = 0; i < pin->num_parents; i++)
+ if (pin->pf->dplls.inputs[pin->parent_idx[i]].pin == parent)
+ return i;
+
+ return -ENOENT;
+}
+
+static int
+ice_dpll_pin_get_parent_idx(struct ice_dpll_pin *pin,
+ const struct dpll_pin *parent)
+{
+ int num = ice_dpll_pin_get_parent_num(pin, parent);
+
+ return num < 0 ? num : pin->parent_idx[num];
+}
+
/**
* ice_dpll_rclk_state_on_pin_set - set a state on rclk pin
* @pin: pointer to a pin
@@ -2286,35 +2515,47 @@ ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv,
enum dpll_pin_state state,
struct netlink_ext_ack *extack)
{
- struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv;
bool enable = state == DPLL_PIN_STATE_CONNECTED;
+ struct ice_dpll_pin *p = pin_priv;
struct ice_pf *pf = p->pf;
+ struct ice_hw *hw;
int ret = -EINVAL;
- u32 hw_idx;
+ int hw_idx;
+
+ hw = &pf->hw;
if (ice_dpll_is_reset(pf, extack))
return -EBUSY;
mutex_lock(&pf->dplls.lock);
- hw_idx = parent->idx - pf->dplls.base_rclk_idx;
- if (hw_idx >= pf->dplls.num_inputs)
+ hw_idx = ice_dpll_pin_get_parent_idx(p, parent_pin);
+ if (hw_idx < 0)
+ goto unlock;
+ hw_idx -= pf->dplls.base_rclk_idx;
+ if (hw_idx >= ICE_DPLL_RCLK_NUM_MAX)
goto unlock;
if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) ||
(!enable && p->state[hw_idx] == DPLL_PIN_STATE_DISCONNECTED)) {
NL_SET_ERR_MSG_FMT(extack,
"pin:%u state:%u on parent:%u already set",
- p->idx, state, parent->idx);
+ p->idx, state,
+ ice_dpll_pin_get_parent_num(p, parent_pin));
goto unlock;
}
- ret = ice_aq_set_phy_rec_clk_out(&pf->hw, hw_idx, enable,
- &p->freq);
+
+ ret = hw->mac_type == ICE_MAC_GENERIC_3K_E825 ?
+ ice_dpll_synce_update_e825c(hw, enable,
+ pf->ptp.port.port_num,
+ (enum ice_synce_clk)hw_idx) :
+ ice_aq_set_phy_rec_clk_out(hw, hw_idx, enable, &p->freq);
if (ret)
NL_SET_ERR_MSG_FMT(extack,
"err:%d %s failed to set pin state:%u for pin:%u on parent:%u",
ret,
- libie_aq_str(pf->hw.adminq.sq_last_status),
- state, p->idx, parent->idx);
+ libie_aq_str(hw->adminq.sq_last_status),
+ state, p->idx,
+ ice_dpll_pin_get_parent_num(p, parent_pin));
unlock:
mutex_unlock(&pf->dplls.lock);
@@ -2344,17 +2585,20 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
{
- struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv;
+ struct ice_dpll_pin *p = pin_priv;
struct ice_pf *pf = p->pf;
int ret = -EINVAL;
- u32 hw_idx;
+ int hw_idx;
if (ice_dpll_is_reset(pf, extack))
return -EBUSY;
mutex_lock(&pf->dplls.lock);
- hw_idx = parent->idx - pf->dplls.base_rclk_idx;
- if (hw_idx >= pf->dplls.num_inputs)
+ hw_idx = ice_dpll_pin_get_parent_idx(p, parent_pin);
+ if (hw_idx < 0)
+ goto unlock;
+ hw_idx -= pf->dplls.base_rclk_idx;
+ if (hw_idx >= ICE_DPLL_RCLK_NUM_MAX)
goto unlock;
ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_INPUT,
@@ -2370,12 +2614,206 @@ unlock:
return ret;
}
+/**
+ * ice_dpll_txclk_work - apply a pending TX reference clock change
+ * @work: work_struct embedded in struct ice_dplls
+ *
+ * This worker executes an outstanding TX reference clock switch request
+ * that was previously queued via the DPLL TXCLK pin set callback.
+ *
+ * The worker performs only the operational part of the switch, issuing
+ * the necessary firmware commands to request a new TX reference clock
+ * selection (e.g. triggering an AN restart). It does not verify whether
+ * the requested clock was ultimately accepted by the hardware.
+ *
+ * Hardware verification, software state reconciliation, pin state
+ * notification, and TXC DPLL lock-status updates are performed later,
+ * after link-up, by ice_txclk_update_and_notify().
+ *
+ * Context:
+ * - Runs in process context on pf->dplls.wq and may sleep.
+ * - Serializes access to shared TXCLK state using pf->dplls.lock.
+ */
+static void ice_dpll_txclk_work(struct work_struct *work)
+{
+ struct ice_dplls *dplls =
+ container_of(work, struct ice_dplls, txclk_work);
+ struct ice_pf *pf = container_of(dplls, struct ice_pf, dplls);
+ struct dpll_pin *old_pin = NULL;
+ struct dpll_pin *new_pin = NULL;
+ enum ice_e825c_ref_clk clk;
+ bool do_switch;
+ int err;
+
+ mutex_lock(&pf->dplls.lock);
+ do_switch = pf->dplls.txclk_switch_requested;
+ clk = pf->ptp.port.tx_clk_req;
+ mutex_unlock(&pf->dplls.lock);
+
+ if (!do_switch)
+ return;
+
+ err = ice_txclk_set_clk(pf, clk);
+
+ mutex_lock(&pf->dplls.lock);
+ /* Only clear the request flag if no newer request arrived while
+ * the lock was dropped. Otherwise leave it set so the re-queued
+ * worker run picks up the updated tx_clk_req value.
+ */
+ if (pf->ptp.port.tx_clk_req == clk)
+ pf->dplls.txclk_switch_requested = false;
+ if (err) {
+ /* Roll back the requested clock to match the current hardware
+ * state so that ice_txclk_update_and_notify() does not
+ * misinterpret a future link-up as a failed switch. Only roll
+ * back if no newer request arrived in the meantime; otherwise
+ * the re-queued worker run will apply the updated value.
+ */
+ dev_err(ice_pf_to_dev(pf),
+ "TX clock switch to %u failed, err=%d; reverting\n",
+ clk, err);
+ if (pf->ptp.port.tx_clk_req == clk) {
+ /* Capture pins for post-unlock notification so that
+ * userspace observes the requested pin flipping back
+ * to DISCONNECTED and the effective pin to CONNECTED.
+ */
+ new_pin = ice_txclk_get_pin(pf, clk);
+ old_pin = ice_txclk_get_pin(pf, pf->ptp.port.tx_clk);
+ pf->ptp.port.tx_clk_req = pf->ptp.port.tx_clk;
+ }
+ }
+ mutex_unlock(&pf->dplls.lock);
+
+ if (old_pin)
+ dpll_pin_change_ntf(old_pin);
+ if (new_pin)
+ dpll_pin_change_ntf(new_pin);
+}
+
+/**
+ * ice_dpll_txclk_state_on_dpll_set - set a state on TX clk pin
+ * @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: state to be set on pin
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback, set a state of a Tx reference clock pin
+ *
+ * Context: Acquires and releases pf->dplls.lock.
+ * Return:
+ * * 0 - success
+ * * negative - failure
+ */
+static int
+ice_dpll_txclk_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_e825c_ref_clk new_clk;
+ int ret = 0;
+
+ 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 TX reference clock");
+ return -EINVAL;
+ }
+
+ /* Check ICE_FLAG_DPLL and queue_work() under pf->dplls.lock.
+ * ice_dpll_deinit() clears the flag under the same lock before
+ * cancel_work_sync() and wq destruction, so a callback arriving
+ * after teardown observes the cleared flag and bails out.
+ */
+ mutex_lock(&pf->dplls.lock);
+ if (!test_bit(ICE_FLAG_DPLL, pf->flags)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+ if (state == DPLL_PIN_STATE_DISCONNECTED &&
+ p->tx_ref_src != pf->ptp.port.tx_clk_req)
+ goto unlock;
+
+ new_clk = (state == DPLL_PIN_STATE_DISCONNECTED) ? ICE_REF_CLK_ENET :
+ p->tx_ref_src;
+ if (new_clk == pf->ptp.port.tx_clk_req)
+ goto unlock;
+
+ pf->ptp.port.tx_clk_req = new_clk;
+ pf->dplls.txclk_switch_requested = true;
+ queue_work(pf->dplls.wq, &pf->dplls.txclk_work);
+unlock:
+ mutex_unlock(&pf->dplls.lock);
+ return ret;
+}
+
+/**
+ * ice_dpll_txclk_state_on_dpll_get - get a state of Tx clk reference pin
+ * @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 pin
+ * @extack: error reporting
+ *
+ * TXCLK DPLL pin state is derived and not stored explicitly.
+ *
+ * Only external TX reference clocks (SYNCE, EREF0) are modeled
+ * as DPLL pins. The internal ENET (TXCO) clock has no pin and,
+ * when selected, all TXCLK pins are reported DISCONNECTED.
+ *
+ * During a pending TXCLK switch, the requested pin may be
+ * reported as CONNECTED before hardware verification.
+ * Hardware acceptance and synchronization are reported
+ * exclusively via TXC DPLL lock-status.
+ *
+ * Context: Acquires and releases pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - failure
+ */
+static int
+ice_dpll_txclk_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;
+ struct ice_pf *pf = p->pf;
+
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
+ mutex_lock(&pf->dplls.lock);
+ if (pf->ptp.port.tx_clk_req == p->tx_ref_src)
+ *state = DPLL_PIN_STATE_CONNECTED;
+ else
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+ mutex_unlock(&pf->dplls.lock);
+
+ return 0;
+}
+
static const struct dpll_pin_ops ice_dpll_rclk_ops = {
.state_on_pin_set = ice_dpll_rclk_state_on_pin_set,
.state_on_pin_get = ice_dpll_rclk_state_on_pin_get,
.direction_get = ice_dpll_input_direction,
};
+static const struct dpll_pin_ops ice_dpll_txclk_ops = {
+ .state_on_dpll_set = ice_dpll_txclk_state_on_dpll_set,
+ .state_on_dpll_get = ice_dpll_txclk_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,
@@ -2398,6 +2836,8 @@ static const struct dpll_pin_ops ice_dpll_pin_ufl_ops = {
.state_on_dpll_set = ice_dpll_ufl_pin_state_set,
.state_on_dpll_get = ice_dpll_sw_pin_state_get,
.direction_get = ice_dpll_pin_sw_direction_get,
+ .prio_get = ice_dpll_sw_input_prio_get,
+ .prio_set = ice_dpll_sw_input_prio_set,
.frequency_get = ice_dpll_sw_pin_frequency_get,
.frequency_set = ice_dpll_sw_pin_frequency_set,
.esync_set = ice_dpll_sw_esync_set,
@@ -2463,6 +2903,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
}
/**
+ * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers
+ * @dplls: pointer to dplls struct
+ * @pin: the dpll_pin that changed
+ *
+ * Send a change notification for @pin and for any registered SMA/U.FL pin
+ * whose backing CGU input matches @pin.
+ */
+static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin)
+{
+ dpll_pin_change_ntf(pin);
+ for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) {
+ if (dplls->sma[i].pin && dplls->sma[i].input &&
+ dplls->sma[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->sma[i].pin);
+ if (dplls->ufl[i].pin && dplls->ufl[i].input &&
+ dplls->ufl[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->ufl[i].pin);
+ }
+}
+
+/**
* ice_dpll_notify_changes - notify dpll subsystem about changes
* @d: pointer do dpll
*
@@ -2470,6 +2931,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
*/
static void ice_dpll_notify_changes(struct ice_dpll *d)
{
+ struct ice_dplls *dplls = &d->pf->dplls;
bool pin_notified = false;
if (d->prev_dpll_state != d->dpll_state) {
@@ -2478,17 +2940,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
}
if (d->prev_input != d->active_input) {
if (d->prev_input)
- dpll_pin_change_ntf(d->prev_input);
+ ice_dpll_pin_ntf(dplls, d->prev_input);
d->prev_input = d->active_input;
if (d->active_input) {
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
pin_notified = true;
}
}
if (d->prev_phase_offset != d->phase_offset) {
d->prev_phase_offset = d->phase_offset;
if (!pin_notified && d->active_input)
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
}
}
@@ -2517,6 +2979,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
/**
* ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes
+ * @dplls: pointer to dplls struct
* @pins: array of ice_dpll_pin pointers registered within dpll subsystem
* @pin_num: number of pins
* @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2526,15 +2989,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
*
* Context: Must be called while pf->dplls.lock is released.
*/
-static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins,
+static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls,
+ struct ice_dpll_pin *pins,
u8 pin_num,
u32 phase_offset_ntf_mask)
{
- int i = 0;
-
- for (i = 0; i < pin_num; i++)
- if (phase_offset_ntf_mask & (1 << i))
- dpll_pin_change_ntf(pins[i].pin);
+ for (int i = 0; i < pin_num; i++)
+ if (phase_offset_ntf_mask & BIT(i))
+ ice_dpll_pin_ntf(dplls, pins[i].pin);
}
/**
@@ -2562,7 +3024,8 @@ static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf,
*phase_offset_pins_updated = 0;
ret = ice_aq_get_cgu_input_pin_measure(&pf->hw, DPLL_TYPE_PPS, meas,
ARRAY_SIZE(meas));
- if (ret && pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN) {
+ if (ret && (pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN ||
+ pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EBUSY)) {
return 0;
} else if (ret) {
dev_err(ice_pf_to_dev(pf),
@@ -2624,10 +3087,12 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init)
d->dpll_idx, d->prev_input_idx, d->input_idx,
d->dpll_state, d->prev_dpll_state, d->mode);
if (ret) {
- dev_err(ice_pf_to_dev(pf),
- "update dpll=%d state failed, ret=%d %s\n",
- d->dpll_idx, ret,
- libie_aq_str(pf->hw.adminq.sq_last_status));
+ /* EBUSY is expected during reset recovery, don't log error */
+ if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
+ dev_err(ice_pf_to_dev(pf),
+ "update dpll=%d state failed, ret=%d %s\n",
+ d->dpll_idx, ret,
+ libie_aq_str(pf->hw.adminq.sq_last_status));
return ret;
}
if (init) {
@@ -2696,7 +3161,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
d->periodic_counter % dp->phase_offset_monitor_period == 0)
ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf);
if (ret) {
- d->cgu_state_acq_err_num++;
+ /* 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) {
@@ -2710,7 +3177,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
ice_dpll_notify_changes(de);
ice_dpll_notify_changes(dp);
if (phase_offset_ntf)
- ice_dpll_pins_notify_mask(d->inputs, d->num_inputs,
+ ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs,
phase_offset_ntf);
resched:
@@ -2814,7 +3281,8 @@ static void ice_dpll_release_pins(struct ice_dpll_pin *pins, int count)
int i;
for (i = 0; i < count; i++)
- dpll_pin_put(pins[i].pin);
+ if (!IS_ERR_OR_NULL(pins[i].pin))
+ dpll_pin_put(pins[i].pin, &pins[i].tracker);
}
/**
@@ -2836,11 +3304,15 @@ static int
ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
int start_idx, int count, u64 clock_id)
{
+ u32 pin_index;
int i, ret;
for (i = 0; i < count; i++) {
- pins[i].pin = dpll_pin_get(clock_id, i + start_idx, THIS_MODULE,
- &pins[i].prop);
+ pin_index = start_idx;
+ if (start_idx != DPLL_PIN_IDX_UNSPEC)
+ pin_index += i;
+ pins[i].pin = dpll_pin_get(clock_id, pin_index, THIS_MODULE,
+ &pins[i].prop, &pins[i].tracker);
if (IS_ERR(pins[i].pin)) {
ret = PTR_ERR(pins[i].pin);
goto release_pins;
@@ -2851,7 +3323,7 @@ ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
release_pins:
while (--i >= 0)
- dpll_pin_put(pins[i].pin);
+ dpll_pin_put(pins[i].pin, &pins[i].tracker);
return ret;
}
@@ -2871,9 +3343,13 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins,
{
int i;
- for (i = 0; i < count; i++)
- if (!pins[i].hidden)
- dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]);
+ for (i = 0; i < count; i++) {
+ if (pins[i].hidden)
+ continue;
+ if (IS_ERR_OR_NULL(pins[i].pin))
+ continue;
+ dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]);
+ }
}
/**
@@ -2944,6 +3420,7 @@ unregister_pins:
/**
* ice_dpll_deinit_direct_pins - deinitialize direct pins
+ * @pf: board private structure
* @cgu: if cgu is present and controlled by this NIC
* @pins: pointer to pins array
* @count: number of pins
@@ -2955,7 +3432,8 @@ unregister_pins:
* Release pins resources to the dpll subsystem.
*/
static void
-ice_dpll_deinit_direct_pins(bool cgu, struct ice_dpll_pin *pins, int count,
+ice_dpll_deinit_direct_pins(struct ice_pf *pf, bool cgu,
+ struct ice_dpll_pin *pins, int count,
const struct dpll_pin_ops *ops,
struct dpll_device *first,
struct dpll_device *second)
@@ -3024,77 +3502,311 @@ static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf)
{
struct ice_dpll_pin *rclk = &pf->dplls.rclk;
struct ice_vsi *vsi = ice_get_main_vsi(pf);
- struct dpll_pin *parent;
+ struct ice_dpll_pin *parent;
int i;
for (i = 0; i < rclk->num_parents; i++) {
- parent = pf->dplls.inputs[rclk->parent_idx[i]].pin;
- if (!parent)
+ parent = &pf->dplls.inputs[rclk->parent_idx[i]];
+ if (IS_ERR_OR_NULL(parent->pin))
continue;
- dpll_pin_on_pin_unregister(parent, rclk->pin,
+ dpll_pin_on_pin_unregister(parent->pin, rclk->pin,
&ice_dpll_rclk_ops, rclk);
}
if (WARN_ON_ONCE(!vsi || !vsi->netdev))
return;
dpll_netdev_pin_clear(vsi->netdev);
- dpll_pin_put(rclk->pin);
+ dpll_pin_put(rclk->pin, &rclk->tracker);
+}
+
+static bool ice_dpll_is_fwnode_pin(struct ice_dpll_pin *pin)
+{
+ return !IS_ERR_OR_NULL(pin->fwnode);
+}
+
+static bool ice_dpll_fwnode_eq(const struct fwnode_handle *a,
+ const struct fwnode_handle *b)
+{
+ return a && a == b;
+}
+
+static void ice_dpll_pin_notify_work(struct work_struct *work)
+{
+ struct ice_dpll_pin_work *w = container_of(work,
+ struct ice_dpll_pin_work,
+ work);
+ struct ice_dpll_pin *pin, *parent = w->pin;
+ bool is_tx_synce_parent = false;
+ struct ice_pf *pf = parent->pf;
+ bool is_rclk_parent = false;
+ int ret;
+
+ wait_for_completion(&pf->dplls.dpll_init);
+ if (!test_bit(ICE_FLAG_DPLL, pf->flags))
+ goto out; /* DPLL initialization failed */
+
+ /* Decide which parent we are handling, defensively checking FWNs */
+ for (int i = 0; i < pf->dplls.rclk.num_parents; i++) {
+ if (ice_dpll_fwnode_eq(parent->fwnode,
+ pf->dplls.inputs[i].fwnode)) {
+ is_rclk_parent = true;
+ break;
+ }
+ }
+
+ 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)
+ goto out;
+
+ switch (w->action) {
+ case DPLL_PIN_CREATED:
+ if (!IS_ERR_OR_NULL(parent->pin)) {
+ /* We have already our pin registered */
+ goto out;
+ }
+
+ /* Grab reference on fwnode pin */
+ parent->pin = fwnode_dpll_pin_find(parent->fwnode,
+ &parent->tracker);
+ if (IS_ERR_OR_NULL(parent->pin)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Cannot get fwnode pin reference\n");
+ goto out;
+ }
+
+ if (is_rclk_parent) {
+ /* Register rclk pin via on-pin relationship */
+ pin = &pf->dplls.rclk;
+ ret = dpll_pin_on_pin_register(parent->pin, pin->pin,
+ &ice_dpll_rclk_ops, pin);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "RCLK pin register failed: %pe\n",
+ ERR_PTR(ret));
+ goto drop_parent_ref;
+ }
+ } else if (is_tx_synce_parent) {
+ /* Register TX-CLK SYNCE pin directly to TXC DPLL */
+ pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
+ ret = dpll_pin_register(pf->dplls.txc.dpll, pin->pin,
+ &ice_dpll_txclk_ops, pin);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "TX SYNCE pin register failed: %pe\n",
+ ERR_PTR(ret));
+ goto drop_parent_ref;
+ }
+ }
+ break;
+ case DPLL_PIN_DELETED:
+ if (IS_ERR_OR_NULL(parent->pin)) {
+ /* We have already our pin unregistered */
+ goto out;
+ }
+
+ if (is_rclk_parent) {
+ /* Unregister rclk pin */
+ pin = &pf->dplls.rclk;
+ dpll_pin_on_pin_unregister(parent->pin, pin->pin,
+ &ice_dpll_rclk_ops, pin);
+ } else if (is_tx_synce_parent) {
+ /* Unregister TX-CLK SYNCE pin from TXC DPLL */
+ pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
+ dpll_pin_unregister(pf->dplls.txc.dpll, pin->pin,
+ &ice_dpll_txclk_ops, pin);
+ }
+drop_parent_ref:
+ /* Drop fwnode pin reference */
+ dpll_pin_put(parent->pin, &parent->tracker);
+ parent->pin = NULL;
+ break;
+ default:
+ break;
+ }
+out:
+ kfree(w);
+}
+
+static int ice_dpll_pin_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct ice_dpll_pin *pin = container_of(nb, struct ice_dpll_pin, nb);
+ struct dpll_pin_notifier_info *info = data;
+ struct ice_dpll_pin_work *work;
+
+ if (action != DPLL_PIN_CREATED && action != DPLL_PIN_DELETED)
+ return NOTIFY_DONE;
+
+ /* Check if the reported pin is this one */
+ 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.
+ */
+ if (info->src_clock_id == pin->pf->dplls.clock_id)
+ return NOTIFY_DONE;
+
+ work = kzalloc_obj(*work);
+ if (!work)
+ return NOTIFY_DONE;
+
+ INIT_WORK(&work->work, ice_dpll_pin_notify_work);
+ work->action = action;
+ work->pin = pin;
+
+ queue_work(pin->pf->dplls.wq, &work->work);
+
+ return NOTIFY_OK;
}
/**
- * ice_dpll_init_rclk_pins - initialize recovered clock pin
+ * ice_dpll_init_pin_common - initialize pin
* @pf: board private structure
* @pin: pin to register
* @start_idx: on which index shall allocation start in dpll subsystem
* @ops: callback ops registered with the pins
*
- * Allocate resource for recovered clock pin in dpll subsystem. Register the
- * pin with the parents it has in the info. Register pin with the pf's main vsi
- * netdev.
+ * Allocate resource for given pin in dpll subsystem. Register the pin with
+ * the parents it has in the info.
*
* Return:
* * 0 - success
* * negative - registration failure reason
*/
static int
-ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin,
- int start_idx, const struct dpll_pin_ops *ops)
+ice_dpll_init_pin_common(struct ice_pf *pf, struct ice_dpll_pin *pin,
+ int start_idx, const struct dpll_pin_ops *ops)
{
- struct ice_vsi *vsi = ice_get_main_vsi(pf);
- struct dpll_pin *parent;
+ struct ice_dpll_pin *parent;
int ret, i;
- if (WARN_ON((!vsi || !vsi->netdev)))
- return -EINVAL;
- ret = ice_dpll_get_pins(pf, pin, start_idx, ICE_DPLL_RCLK_NUM_PER_PF,
- pf->dplls.clock_id);
+ ret = ice_dpll_get_pins(pf, pin, start_idx, 1, pf->dplls.clock_id);
if (ret)
return ret;
- for (i = 0; i < pf->dplls.rclk.num_parents; i++) {
- parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin;
- if (!parent) {
- ret = -ENODEV;
- goto unregister_pins;
+
+ for (i = 0; i < pin->num_parents; i++) {
+ parent = &pf->dplls.inputs[pin->parent_idx[i]];
+ if (IS_ERR_OR_NULL(parent->pin)) {
+ if (!ice_dpll_is_fwnode_pin(parent)) {
+ ret = -ENODEV;
+ goto unregister_pins;
+ }
+ parent->pin = fwnode_dpll_pin_find(parent->fwnode,
+ &parent->tracker);
+ if (IS_ERR_OR_NULL(parent->pin)) {
+ dev_info(ice_pf_to_dev(pf),
+ "Mux pin not registered yet\n");
+ continue;
+ }
}
- ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin,
- ops, &pf->dplls.rclk);
+ ret = dpll_pin_on_pin_register(parent->pin, pin->pin, ops, pin);
if (ret)
goto unregister_pins;
}
- dpll_netdev_pin_set(vsi->netdev, pf->dplls.rclk.pin);
return 0;
unregister_pins:
while (i) {
- parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[--i]].pin;
- dpll_pin_on_pin_unregister(parent, pf->dplls.rclk.pin,
- &ice_dpll_rclk_ops, &pf->dplls.rclk);
+ parent = &pf->dplls.inputs[pin->parent_idx[--i]];
+ if (IS_ERR_OR_NULL(parent->pin))
+ continue;
+ dpll_pin_on_pin_unregister(parent->pin, pin->pin, ops, pin);
}
- ice_dpll_release_pins(pin, ICE_DPLL_RCLK_NUM_PER_PF);
+ ice_dpll_release_pins(pin, 1);
+
return ret;
}
/**
+ * ice_dpll_init_rclk_pin - initialize recovered clock pin
+ * @pf: board private structure
+ * @start_idx: on which index shall allocation start in dpll subsystem
+ * @ops: callback ops registered with the pins
+ *
+ * Allocate resource for recovered clock pin in dpll subsystem. Register the
+ * pin with the parents it has in the info.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - registration failure reason
+ */
+static int
+ice_dpll_init_rclk_pin(struct ice_pf *pf, int start_idx,
+ const struct dpll_pin_ops *ops)
+{
+ struct ice_vsi *vsi = ice_get_main_vsi(pf);
+ int ret;
+
+ ret = ice_dpll_init_pin_common(pf, &pf->dplls.rclk, start_idx, ops);
+ if (ret)
+ return ret;
+
+ dpll_netdev_pin_set(vsi->netdev, pf->dplls.rclk.pin);
+
+ return 0;
+}
+
+static void
+ice_dpll_stop_fwnode_pin_activity(struct ice_dpll_pin *pin, bool flush)
+{
+ unregister_dpll_notifier(&pin->nb);
+ if (flush)
+ flush_workqueue(pin->pf->dplls.wq);
+}
+
+static void
+ice_dpll_release_fwnode_pin(struct ice_dpll_pin *pin)
+{
+ if (!IS_ERR_OR_NULL(pin->pin)) {
+ dpll_pin_put(pin->pin, &pin->tracker);
+ pin->pin = NULL;
+ }
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
+}
+
+static void
+ice_dpll_deinit_fwnode_pin(struct ice_dpll_pin *pin)
+{
+ ice_dpll_stop_fwnode_pin_activity(pin, true);
+ ice_dpll_release_fwnode_pin(pin);
+}
+
+static void
+ice_dpll_deinit_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
+ int start_idx)
+{
+ int i;
+
+ for (i = 0; i < pf->dplls.rclk.num_parents; i++)
+ ice_dpll_deinit_fwnode_pin(&pins[start_idx + i]);
+ destroy_workqueue(pf->dplls.wq);
+}
+
+static int ice_dpll_deinit_txclk_pins(struct ice_pf *pf)
+{
+ 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_unregister_pins(dt->dpll, pf->dplls.txclks,
+ &ice_dpll_txclk_ops,
+ ARRAY_SIZE(pf->dplls.txclks));
+ ice_dpll_release_pins(&pf->dplls.txclks[E825_EXT_EREF_PIN_IDX], 1);
+ /* ice_dpll_release_pins() puts the pin but does not clear the slot,
+ * unlike ice_dpll_release_fwnode_pin() used for SYNCE below. NULL it
+ * so a late ice_txclk_get_pin() returns NULL rather than a dangling
+ * pointer.
+ */
+ pf->dplls.txclks[E825_EXT_EREF_PIN_IDX].pin = NULL;
+ ice_dpll_release_fwnode_pin(synce_pin);
+ return 0;
+}
+
+/**
* ice_dpll_deinit_pins - deinitialize direct pins
* @pf: board private structure
* @cgu: if cgu is controlled by this pf
@@ -3113,6 +3825,10 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
struct ice_dpll *dp = &d->pps;
ice_dpll_deinit_rclk_pin(pf);
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ ice_dpll_deinit_txclk_pins(pf);
+ ice_dpll_deinit_fwnode_pins(pf, pf->dplls.inputs, 0);
+ }
if (cgu) {
ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_input_ops,
num_inputs);
@@ -3127,12 +3843,12 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
&ice_dpll_output_ops, num_outputs);
ice_dpll_release_pins(outputs, num_outputs);
if (!pf->dplls.generic) {
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.ufl,
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.ufl,
ICE_DPLL_PIN_SW_NUM,
&ice_dpll_pin_ufl_ops,
pf->dplls.pps.dpll,
pf->dplls.eec.dpll);
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.sma,
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.sma,
ICE_DPLL_PIN_SW_NUM,
&ice_dpll_pin_sma_ops,
pf->dplls.pps.dpll,
@@ -3141,6 +3857,213 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
}
}
+static struct fwnode_handle *
+ice_dpll_pin_node_get(struct ice_pf *pf, const char *name)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(ice_pf_to_dev(pf));
+ int index;
+
+ index = fwnode_property_match_string(fwnode, "dpll-pin-names", name);
+ if (index < 0)
+ return ERR_PTR(-ENOENT);
+
+ return fwnode_find_reference(fwnode, "dpll-pins", index);
+}
+
+static int
+ice_dpll_init_fwnode_pin(struct ice_dpll_pin *pin, const char *name)
+{
+ struct ice_pf *pf = pin->pf;
+ int ret;
+
+ pin->fwnode = ice_dpll_pin_node_get(pf, name);
+ if (IS_ERR(pin->fwnode)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Failed to find %s firmware node: %pe\n", name,
+ pin->fwnode);
+ pin->fwnode = NULL;
+ return -ENODEV;
+ }
+
+ dev_dbg(ice_pf_to_dev(pf), "Found fwnode node for %s\n", name);
+
+ pin->pin = fwnode_dpll_pin_find(pin->fwnode, &pin->tracker);
+ if (IS_ERR_OR_NULL(pin->pin)) {
+ dev_info(ice_pf_to_dev(pf),
+ "DPLL pin for %pfwp not registered yet\n",
+ pin->fwnode);
+ pin->pin = NULL;
+ }
+
+ pin->nb.notifier_call = ice_dpll_pin_notify;
+ ret = register_dpll_notifier(&pin->nb);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "Failed to subscribe for DPLL notifications\n");
+
+ if (!IS_ERR_OR_NULL(pin->pin)) {
+ dpll_pin_put(pin->pin, &pin->tracker);
+ pin->pin = NULL;
+ }
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
+
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * ice_dpll_init_fwnode_pins - initialize pins from device tree
+ * @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
+ * allocates them in the dpll subsystem and stores their indices for later
+ * registration with the rclk pin.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - initialization failure reason
+ */
+static int
+ice_dpll_init_fwnode_pins(struct ice_pf *pf, struct ice_dpll_pin *pins,
+ int start_idx)
+{
+ char pin_name[16];
+ int i, ret;
+
+ pf->dplls.wq = create_singlethread_workqueue("ice_dpll_wq");
+ if (!pf->dplls.wq)
+ return -ENOMEM;
+
+ for (i = 0; i < pf->dplls.rclk.num_parents; i++) {
+ pins[start_idx + i].pf = pf;
+ snprintf(pin_name, sizeof(pin_name), "rclk%u", i);
+ ret = ice_dpll_init_fwnode_pin(&pins[start_idx + i], pin_name);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+error:
+ /*
+ * A notifier worker may already be queued and blocked on dpll_init;
+ * release it so the per-pin flush below does not deadlock.
+ */
+ complete_all(&pf->dplls.dpll_init);
+ while (i--)
+ ice_dpll_deinit_fwnode_pin(&pins[start_idx + i]);
+
+ destroy_workqueue(pf->dplls.wq);
+
+ return ret;
+}
+
+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;
+ int ret;
+
+ /* Configure EXT_EREF0 pin */
+ ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, pf->dplls.clock_id);
+ if (ret)
+ return ret;
+ ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops,
+ ref_pin);
+ if (ret)
+ goto err_release_ext_eref;
+
+ /*
+ * Configure EXT_SYNCE pin (fwnode-backed).
+ * The pin may not yet be available; in that case registration
+ * will be deferred via the notifier path.
+ */
+ ref_pin++;
+ ret = ice_dpll_init_fwnode_pin(ref_pin, ice_dpll_fwnode_ext_synce);
+ if (ret)
+ goto err_unregister_ext_eref;
+
+ if (IS_ERR_OR_NULL(ref_pin->pin)) {
+ dev_dbg(ice_pf_to_dev(pf),
+ "Tx-clk SYNCE pin not registered yet\n");
+ return 0;
+ }
+
+ ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops,
+ ref_pin);
+ if (ret)
+ goto err_deinit_synce;
+
+ return 0;
+
+err_deinit_synce:
+ /*
+ * Avoid deadlock against notifier workers blocked on dpll_init.
+ * The outer init error path will complete dpll_init and flush the
+ * shared workqueue before destroying it.
+ */
+ ice_dpll_stop_fwnode_pin_activity(ref_pin, false);
+ ice_dpll_release_fwnode_pin(ref_pin);
+err_unregister_ext_eref:
+ dpll_pin_unregister(txc->dpll,
+ pf->dplls.txclks[E825_EXT_EREF_PIN_IDX].pin,
+ &ice_dpll_txclk_ops,
+ &pf->dplls.txclks[E825_EXT_EREF_PIN_IDX]);
+
+err_release_ext_eref:
+ ice_dpll_release_pins(&pf->dplls.txclks[E825_EXT_EREF_PIN_IDX], 1);
+
+ 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.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - initialization failure reason
+ */
+static int ice_dpll_init_pins_e825(struct ice_pf *pf)
+{
+ int ret;
+
+ ret = ice_dpll_init_fwnode_pins(pf, pf->dplls.inputs, 0);
+ if (ret)
+ return ret;
+
+ ret = ice_dpll_init_rclk_pin(pf, DPLL_PIN_IDX_UNSPEC,
+ &ice_dpll_rclk_ops);
+
+ if (ret)
+ goto unregister_pins;
+
+ ret = ice_dpll_init_txclk_pins(pf, 0);
+ if (ret)
+ ice_dpll_deinit_rclk_pin(pf);
+
+unregister_pins:
+ if (ret) {
+ /* Inform DPLL notifier works that DPLL init was finished
+ * unsuccessfully (ICE_DPLL_FLAG not set).
+ */
+ complete_all(&pf->dplls.dpll_init);
+ ice_dpll_deinit_fwnode_pins(pf, pf->dplls.inputs, 0);
+ }
+
+ return ret;
+}
+
/**
* ice_dpll_init_pins - init pins and register pins with a dplls
* @pf: board private structure
@@ -3155,21 +4078,24 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
*/
static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
{
+ const struct dpll_pin_ops *output_ops;
+ const struct dpll_pin_ops *input_ops;
int ret, count;
+ input_ops = &ice_dpll_input_ops;
+ output_ops = &ice_dpll_output_ops;
+
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0,
- pf->dplls.num_inputs,
- &ice_dpll_input_ops,
- pf->dplls.eec.dpll, pf->dplls.pps.dpll);
+ pf->dplls.num_inputs, input_ops,
+ pf->dplls.eec.dpll,
+ pf->dplls.pps.dpll);
if (ret)
return ret;
count = pf->dplls.num_inputs;
if (cgu) {
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs,
- count,
- pf->dplls.num_outputs,
- &ice_dpll_output_ops,
- pf->dplls.eec.dpll,
+ count, pf->dplls.num_outputs,
+ output_ops, pf->dplls.eec.dpll,
pf->dplls.pps.dpll);
if (ret)
goto deinit_inputs;
@@ -3205,30 +4131,30 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
} else {
count += pf->dplls.num_outputs + 2 * ICE_DPLL_PIN_SW_NUM;
}
- ret = ice_dpll_init_rclk_pins(pf, &pf->dplls.rclk, count + pf->hw.pf_id,
- &ice_dpll_rclk_ops);
+
+ ret = ice_dpll_init_rclk_pin(pf, count + pf->ptp.port.port_num,
+ &ice_dpll_rclk_ops);
if (ret)
goto deinit_ufl;
return 0;
deinit_ufl:
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.ufl,
- ICE_DPLL_PIN_SW_NUM,
- &ice_dpll_pin_ufl_ops,
- pf->dplls.pps.dpll, pf->dplls.eec.dpll);
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.ufl, ICE_DPLL_PIN_SW_NUM,
+ &ice_dpll_pin_ufl_ops, pf->dplls.pps.dpll,
+ pf->dplls.eec.dpll);
deinit_sma:
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.sma,
- ICE_DPLL_PIN_SW_NUM,
- &ice_dpll_pin_sma_ops,
- pf->dplls.pps.dpll, pf->dplls.eec.dpll);
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.sma, ICE_DPLL_PIN_SW_NUM,
+ &ice_dpll_pin_sma_ops, pf->dplls.pps.dpll,
+ pf->dplls.eec.dpll);
deinit_outputs:
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.outputs,
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.outputs,
pf->dplls.num_outputs,
- &ice_dpll_output_ops, pf->dplls.pps.dpll,
+ output_ops, pf->dplls.pps.dpll,
pf->dplls.eec.dpll);
deinit_inputs:
- ice_dpll_deinit_direct_pins(cgu, pf->dplls.inputs, pf->dplls.num_inputs,
- &ice_dpll_input_ops, pf->dplls.pps.dpll,
+ ice_dpll_deinit_direct_pins(pf, cgu, pf->dplls.inputs,
+ pf->dplls.num_inputs,
+ input_ops, pf->dplls.pps.dpll,
pf->dplls.eec.dpll);
return ret;
}
@@ -3239,15 +4165,15 @@ deinit_inputs:
* @d: pointer to ice_dpll
* @cgu: if cgu is present and controlled by this NIC
*
- * If cgu is owned unregister the dpll from dpll subsystem.
- * Release resources of dpll device from dpll subsystem.
+ * If cgu is owned, unregister the DPLL from DPLL subsystem.
+ * Release resources of DPLL device from DPLL subsystem.
*/
static void
ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu)
{
- if (cgu)
+ if (cgu || pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
dpll_device_unregister(d->dpll, d->ops, d);
- dpll_device_put(d->dpll);
+ dpll_device_put(d->dpll, &d->tracker);
}
/**
@@ -3257,8 +4183,8 @@ ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu)
* @cgu: if cgu is present and controlled by this NIC
* @type: type of dpll being initialized
*
- * Allocate dpll instance for this board in dpll subsystem, if cgu is controlled
- * by this NIC, register dpll with the callback ops.
+ * Allocate DPLL instance for this board in dpll subsystem, if cgu is controlled
+ * by this NIC, register DPLL with the callback ops.
*
* Return:
* * 0 - success
@@ -3271,7 +4197,8 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
u64 clock_id = pf->dplls.clock_id;
int ret;
- d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE);
+ d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE,
+ &d->tracker);
if (IS_ERR(d->dpll)) {
ret = PTR_ERR(d->dpll);
dev_err(ice_pf_to_dev(pf),
@@ -3279,15 +4206,17 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
return ret;
}
d->pf = pf;
- if (cgu) {
+ if (cgu || pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
const struct dpll_device_ops *ops = &ice_dpll_ops;
if (type == DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf))
ops = &ice_dpll_pom_ops;
- ice_dpll_update_state(pf, d, true);
+ if (cgu)
+ ice_dpll_update_state(pf, d, true);
ret = dpll_device_register(d->dpll, type, ops, d);
if (ret) {
- dpll_device_put(d->dpll);
+ dpll_device_put(d->dpll, &d->tracker);
+ d->dpll = NULL;
return ret;
}
d->ops = ops;
@@ -3506,6 +4435,26 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
}
/**
+ * ice_dpll_init_info_pin_on_pin_e825c - initializes rclk pin information
+ * @pf: board private structure
+ *
+ * Init information for rclk pin, cache them in pf->dplls.rclk.
+ *
+ * Return:
+ * * 0 - success
+ */
+static int ice_dpll_init_info_pin_on_pin_e825c(struct ice_pf *pf)
+{
+ struct ice_dpll_pin *rclk_pin = &pf->dplls.rclk;
+
+ rclk_pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT;
+ rclk_pin->prop.capabilities |= DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ rclk_pin->pf = pf;
+
+ return 0;
+}
+
+/**
* ice_dpll_init_info_rclk_pin - initializes rclk pin information
* @pf: board private structure
*
@@ -3545,6 +4494,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
struct ice_dpll_pin *pin;
u32 phase_adj_max, caps;
int i, ret;
+ u8 data;
if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP)
input_idx_offset = ICE_E810_RCLK_PINS_NUM;
@@ -3604,6 +4554,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
}
ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max);
}
+
+ /* Initialize the SMA control register to a known-good default state.
+ * Without this write the PCA9575 GPIO expander retains its power-on
+ * default (all outputs high) which makes all SW pins appear inactive.
+ * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and
+ * U.FL2 input.
+ */
+ ret = ice_read_sma_ctrl(&pf->hw, &data);
+ if (ret)
+ return ret;
+ data &= ~ICE_ALL_SMA_MASK;
+ data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS;
+ ret = ice_write_sma_ctrl(&pf->hw, data);
+ if (ret)
+ return ret;
+
ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE,
NULL);
if (ret)
@@ -3613,6 +4579,36 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
}
/**
+ * ice_dpll_init_info_txclk_pins_e825c - initializes tx-clk pins information
+ * @pf: board private structure
+ *
+ * Init information for tx-clks pin, cache them in pf->dplls.txclks
+ *
+ * Return:
+ * * 0 - success
+ */
+static int ice_dpll_init_info_txclk_pins_e825c(struct ice_pf *pf)
+{
+ struct ice_dpll_pin *tx_pin;
+
+ for (int i = 0; i < ICE_DPLL_TXCLK_NUM_MAX; i++) {
+ tx_pin = &pf->dplls.txclks[i];
+ tx_pin->prop.type = DPLL_PIN_TYPE_EXT;
+ tx_pin->prop.capabilities |=
+ DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ tx_pin->pf = pf;
+ if (i == E825_EXT_EREF_PIN_IDX) {
+ tx_pin->prop.board_label = ice_dpll_ext_eref_pin;
+ tx_pin->tx_ref_src = ICE_REF_CLK_EREF0;
+ } else if (i == E825_EXT_SYNCE_PIN_IDX) {
+ tx_pin->tx_ref_src = ICE_REF_CLK_SYNCE;
+ }
+ }
+
+ return 0;
+}
+
+/**
* ice_dpll_init_pins_info - init pins info wrapper
* @pf: board private structure
* @pin_type: type of pins being initialized
@@ -3631,9 +4627,15 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type)
case ICE_DPLL_PIN_TYPE_OUTPUT:
return ice_dpll_init_info_direct_pins(pf, pin_type);
case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
- return ice_dpll_init_info_rclk_pin(pf);
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
+ return ice_dpll_init_info_pin_on_pin_e825c(pf);
+ else
+ return ice_dpll_init_info_rclk_pin(pf);
case ICE_DPLL_PIN_TYPE_SOFTWARE:
return ice_dpll_init_info_sw_pins(pf);
+
+ case ICE_DPLL_PIN_TYPE_TXCLK:
+ return ice_dpll_init_info_txclk_pins_e825c(pf);
default:
return -EINVAL;
}
@@ -3648,9 +4650,66 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type)
static void ice_dpll_deinit_info(struct ice_pf *pf)
{
kfree(pf->dplls.inputs);
+ pf->dplls.inputs = NULL;
kfree(pf->dplls.outputs);
+ pf->dplls.outputs = NULL;
kfree(pf->dplls.eec.input_prio);
+ pf->dplls.eec.input_prio = NULL;
kfree(pf->dplls.pps.input_prio);
+ pf->dplls.pps.input_prio = NULL;
+}
+
+/**
+ * ice_dpll_init_info_e825c - prepare pf's dpll information structure for e825c
+ * device
+ * @pf: board private structure
+ *
+ * Acquire (from HW) and set basic DPLL information (on pf->dplls struct).
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_init_info_e825c(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ struct ice_dpll *dt = &d->txc;
+ int ret = 0;
+ int i;
+
+ d->clock_id = ice_generate_clock_id(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;
+
+ d->inputs = kzalloc_objs(*d->inputs, d->num_inputs);
+ if (!d->inputs)
+ return -ENOMEM;
+
+ ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx,
+ &pf->dplls.rclk.num_parents);
+ if (ret)
+ goto deinit_info;
+
+ for (i = 0; i < pf->dplls.rclk.num_parents; i++)
+ pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i;
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT);
+ if (ret)
+ goto deinit_info;
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_TXCLK);
+ if (ret)
+ goto deinit_info;
+
+ dev_dbg(ice_pf_to_dev(pf),
+ "%s - success, inputs: %u, outputs: %u, rclk-parents: %u\n",
+ __func__, d->num_inputs, d->num_outputs, d->rclk.num_parents);
+ return 0;
+deinit_info:
+ ice_dpll_deinit_info(pf);
+ return ret;
}
/**
@@ -3698,12 +4757,16 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu)
alloc_size = sizeof(*de->input_prio) * d->num_inputs;
de->input_prio = kzalloc(alloc_size, GFP_KERNEL);
- if (!de->input_prio)
- return -ENOMEM;
+ if (!de->input_prio) {
+ ret = -ENOMEM;
+ goto deinit_info;
+ }
dp->input_prio = kzalloc(alloc_size, GFP_KERNEL);
- if (!dp->input_prio)
- return -ENOMEM;
+ if (!dp->input_prio) {
+ ret = -ENOMEM;
+ goto deinit_info;
+ }
ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT);
if (ret)
@@ -3728,12 +4791,12 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu)
ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx,
&pf->dplls.rclk.num_parents);
if (ret)
- return ret;
+ goto deinit_info;
for (i = 0; i < pf->dplls.rclk.num_parents; i++)
pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i;
ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT);
if (ret)
- return ret;
+ goto deinit_info;
de->mode = DPLL_MODE_AUTOMATIC;
dp->mode = DPLL_MODE_AUTOMATIC;
@@ -3767,19 +4830,44 @@ void ice_dpll_deinit(struct ice_pf *pf)
{
bool cgu = ice_is_feature_supported(pf, ICE_F_CGU);
+ /* Clear ICE_FLAG_DPLL under the lock so that any new caller of
+ * ice_txclk_update_and_notify() observes the cleared flag and
+ * returns early. In-flight callers that already passed the flag
+ * check hold txclk_notify_rwsem for read across the out-of-lock
+ * dpll_*_change_ntf() calls; the down_write/up_write barrier
+ * below waits for them to finish before pins and the TXC DPLL
+ * device may be freed.
+ */
+ mutex_lock(&pf->dplls.lock);
clear_bit(ICE_FLAG_DPLL, pf->flags);
+ mutex_unlock(&pf->dplls.lock);
+
+ /* Wait for in-flight ice_txclk_update_and_notify() readers */
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ down_write(&pf->dplls.txclk_notify_rwsem);
+ up_write(&pf->dplls.txclk_notify_rwsem);
+ }
+
if (cgu)
ice_dpll_deinit_worker(pf);
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
+ cancel_work_sync(&pf->dplls.txclk_work);
+
ice_dpll_deinit_pins(pf, cgu);
- ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu);
- ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu);
+ if (!IS_ERR_OR_NULL(pf->dplls.pps.dpll))
+ ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu);
+ if (!IS_ERR_OR_NULL(pf->dplls.eec.dpll))
+ 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);
+
ice_dpll_deinit_info(pf);
mutex_destroy(&pf->dplls.lock);
}
/**
- * ice_dpll_init - initialize support for dpll subsystem
+ * ice_dpll_init_e825 - initialize support for dpll subsystem
* @pf: board private structure
*
* Set up the device dplls, register them and pins connected within Linux dpll
@@ -3788,7 +4876,65 @@ void ice_dpll_deinit(struct ice_pf *pf)
*
* Context: Initializes pf->dplls.lock mutex.
*/
-void ice_dpll_init(struct ice_pf *pf)
+static void ice_dpll_init_e825(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ int err;
+
+ /* E825 sets ICE_F_PHY_RCLK unconditionally, so DPLL may run without
+ * PTP. Populate the HW-topology fields the TX-clk path divides by,
+ * otherwise userspace can trigger div-by-zero in ice_txclk_set_clk().
+ * When PTP is supported, ice_ptp_init() handles this.
+ */
+ if (!test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) {
+ ice_ptp_init_hw(&pf->hw);
+ if (pf->hw.lane_num >= 0)
+ 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.
+ */
+ INIT_WORK(&d->txclk_work, ice_dpll_txclk_work);
+ init_rwsem(&d->txclk_notify_rwsem);
+ init_completion(&d->dpll_init);
+
+ err = ice_dpll_init_info_e825c(pf);
+ if (err)
+ goto err_exit;
+ err = ice_dpll_init_dpll(pf, &pf->dplls.txc, false, DPLL_TYPE_GENERIC);
+ if (err)
+ goto deinit_info;
+ err = ice_dpll_init_pins_e825(pf);
+ if (err)
+ goto deinit_txclk;
+ set_bit(ICE_FLAG_DPLL, pf->flags);
+ complete_all(&d->dpll_init);
+
+ return;
+
+deinit_txclk:
+ ice_dpll_deinit_dpll(pf, &pf->dplls.txc, 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);
+}
+
+/**
+ * ice_dpll_init_e810 - initialize support for dpll subsystem
+ * @pf: board private structure
+ *
+ * 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;
@@ -3828,3 +4974,15 @@ err_exit:
mutex_destroy(&d->lock);
dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err);
}
+
+void ice_dpll_init(struct ice_pf *pf)
+{
+ switch (pf->hw.mac_type) {
+ case ICE_MAC_GENERIC_3K_E825:
+ ice_dpll_init_e825(pf);
+ break;
+ default:
+ ice_dpll_init_e810(pf);
+ break;
+ }
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
index c0da03384ce9..103ba3e49068 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.h
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
@@ -7,6 +7,25 @@
#include "ice.h"
#define ICE_DPLL_RCLK_NUM_MAX 4
+#define ICE_DPLL_TXCLK_NUM_MAX 2
+#define E825_EXT_EREF_PIN_IDX 0
+#define E825_EXT_SYNCE_PIN_IDX 1
+
+#define ICE_CGU_R10 0x28
+#define ICE_CGU_R10_SYNCE_CLKO_SEL GENMASK(8, 5)
+#define ICE_CGU_R10_SYNCE_CLKODIV_M1 GENMASK(13, 9)
+#define ICE_CGU_R10_SYNCE_CLKODIV_LOAD BIT(14)
+#define ICE_CGU_R10_SYNCE_DCK_RST BIT(15)
+#define ICE_CGU_R10_SYNCE_ETHCLKO_SEL GENMASK(18, 16)
+#define ICE_CGU_R10_SYNCE_ETHDIV_M1 GENMASK(23, 19)
+#define ICE_CGU_R10_SYNCE_ETHDIV_LOAD BIT(24)
+#define ICE_CGU_R10_SYNCE_DCK2_RST BIT(25)
+#define ICE_CGU_R10_SYNCE_S_REF_CLK GENMASK(31, 27)
+
+#define ICE_CGU_R11 0x2C
+#define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1)
+
+#define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3
/**
* enum ice_dpll_pin_sw - enumerate ice software pin indices:
@@ -20,9 +39,16 @@ enum ice_dpll_pin_sw {
ICE_DPLL_PIN_SW_NUM
};
+struct ice_dpll_pin_work {
+ struct work_struct work;
+ unsigned long action;
+ struct ice_dpll_pin *pin;
+};
+
/** ice_dpll_pin - store info about pins
* @pin: dpll pin structure
* @pf: pointer to pf, which has registered the dpll_pin
+ * @tracker: reference count tracker
* @idx: ice pin private idx
* @num_parents: hols number of parent pins
* @parent_idx: hold indexes of parent pins
@@ -37,6 +63,9 @@ enum ice_dpll_pin_sw {
struct ice_dpll_pin {
struct dpll_pin *pin;
struct ice_pf *pf;
+ dpll_tracker tracker;
+ struct fwnode_handle *fwnode;
+ struct notifier_block nb;
u8 idx;
u8 num_parents;
u8 parent_idx[ICE_DPLL_RCLK_NUM_MAX];
@@ -53,11 +82,13 @@ struct ice_dpll_pin {
u8 ref_sync;
bool active;
bool hidden;
+ enum ice_e825c_ref_clk tx_ref_src;
};
/** ice_dpll - store info required for DPLL control
* @dpll: pointer to dpll dev
* @pf: pointer to pf, which has registered the dpll_device
+ * @tracker: reference count tracker
* @dpll_idx: index of dpll on the NIC
* @input_idx: currently selected input index
* @prev_input_idx: previously selected input index
@@ -76,6 +107,7 @@ struct ice_dpll_pin {
struct ice_dpll {
struct dpll_device *dpll;
struct ice_pf *pf;
+ dpll_tracker tracker;
u8 dpll_idx;
u8 input_idx;
u8 prev_input_idx;
@@ -96,12 +128,15 @@ struct ice_dpll {
/** ice_dplls - store info required for CCU (clock controlling unit)
* @kworker: periodic worker
* @work: periodic work
- * @lock: locks access to configuration of a dpll
+ * @wq: workqueue used to schedule DPLL-related deferred work
+ * @lock: protects DPLL configuration (see Locking below)
* @eec: pointer to EEC dpll dev
* @pps: pointer to PPS dpll dev
+ * @txc: pointer to TXC dpll dev
* @inputs: input pins pointer
* @outputs: output pins pointer
* @rclk: recovered pins pointer
+ * @txclks: TX clock reference pins pointer
* @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
@@ -110,18 +145,44 @@ struct ice_dpll {
* @input_phase_adj_max: max phase adjust value for an input pins
* @output_phase_adj_max: max phase adjust value for an output pins
* @periodic_counter: counter of periodic work executions
+ * @generic: true when generic DPLL ops are used
+ * @txclk_work: deferred TX reference clock switch worker
+ * @txclk_switch_requested: a TX ref clock switch is queued in @txclk_work
+ * @txclk_notify_rwsem: drains in-flight TXCLK notifications on teardown
+ *
+ * Locking:
+ * Acquisition order (top to bottom):
+ *
+ * txclk_notify_rwsem (read)
+ * -> pf->dplls.lock
+ * -> ctrl_pf->dplls.lock
+ *
+ * - @lock serializes all DPLL state mutations on this PF. When the
+ * controlling PF's lock must also be taken (e.g. updating the shared
+ * tx_refclks usage map), acquire pf->dplls.lock first, then
+ * ctrl_pf->dplls.lock. Skip the second acquire when pf == ctrl_pf
+ * to avoid recursive locking.
+ * - @txclk_notify_rwsem is held for read across
+ * ice_txclk_update_and_notify(), including the out-of-lock
+ * dpll_*_change_ntf() calls. ice_dpll_deinit() takes the write side
+ * standalone (not nested under any other lock) to drain in-flight
+ * readers before pins and the TXC DPLL device are freed.
*/
struct ice_dplls {
struct kthread_worker *kworker;
struct kthread_delayed_work work;
+ struct workqueue_struct *wq;
struct mutex lock;
+ struct completion dpll_init;
struct ice_dpll eec;
struct ice_dpll pps;
+ struct ice_dpll txc;
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];
u8 num_inputs;
u8 num_outputs;
u8 sma_data;
@@ -132,6 +193,9 @@ struct ice_dplls {
s32 output_phase_adj_max;
u32 periodic_counter;
bool generic;
+ struct work_struct txclk_work;
+ bool txclk_switch_requested;
+ struct rw_semaphore txclk_notify_rwsem;
};
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index 2e4f0969035f..b069e6c514fb 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -117,8 +117,6 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
if (!repr->dst)
return -ENOMEM;
- netif_keep_dst(uplink_vsi->netdev);
-
dst = repr->dst;
dst->u.port_info.port_id = vsi->vsi_num;
dst->u.port_info.lower_dev = uplink_vsi->netdev;
@@ -312,6 +310,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
if (ice_eswitch_br_offloads_init(pf))
goto err_br_offloads;
+ netif_keep_dst(uplink_vsi->netdev);
+
pf->eswitch.is_running = true;
return 0;
@@ -512,9 +512,6 @@ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
struct ice_repr *repr;
int err;
- if (!ice_is_eswitch_mode_switchdev(pf))
- return 0;
-
repr = ice_repr_create_vf(vf);
if (IS_ERR(repr))
return PTR_ERR(repr);
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
index cccb7ddf61c9..1d8a6b95ccda 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
@@ -129,11 +129,11 @@ ice_eswitch_br_fwd_rule_create(struct ice_hw *hw, int vsi_idx, int port_type,
lkups_cnt = ice_eswitch_br_get_lkups_cnt(vid);
- rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ rule = kzalloc_obj(*rule);
if (!rule)
return ERR_PTR(-ENOMEM);
- list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ list = kzalloc_objs(*list, lkups_cnt, GFP_ATOMIC);
if (!list) {
err = -ENOMEM;
goto err_list_alloc;
@@ -190,11 +190,11 @@ ice_eswitch_br_guard_rule_create(struct ice_hw *hw, u16 vsi_idx,
lkups_cnt = ice_eswitch_br_get_lkups_cnt(vid);
- rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ rule = kzalloc_obj(*rule);
if (!rule)
goto err_exit;
- list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ list = kzalloc_objs(*list, lkups_cnt, GFP_ATOMIC);
if (!list)
goto err_list_alloc;
@@ -233,7 +233,7 @@ ice_eswitch_br_flow_create(struct device *dev, struct ice_hw *hw, int vsi_idx,
struct ice_esw_br_flow *flow;
int err;
- flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ flow = kzalloc_obj(*flow);
if (!flow)
return ERR_PTR(-ENOMEM);
@@ -418,7 +418,7 @@ ice_eswitch_br_fdb_entry_create(struct net_device *netdev,
if (fdb_entry)
ice_eswitch_br_fdb_entry_notify_and_cleanup(bridge, fdb_entry);
- fdb_entry = kzalloc(sizeof(*fdb_entry), GFP_KERNEL);
+ fdb_entry = kzalloc_obj(*fdb_entry);
if (!fdb_entry) {
err = -ENOMEM;
goto err_exit;
@@ -513,7 +513,7 @@ ice_eswitch_br_fdb_work_alloc(struct switchdev_notifier_fdb_info *fdb_info,
struct ice_esw_br_fdb_work *work;
unsigned char *mac;
- work = kzalloc(sizeof(*work), GFP_ATOMIC);
+ work = kzalloc_obj(*work, GFP_ATOMIC);
if (!work)
return ERR_PTR(-ENOMEM);
@@ -698,7 +698,7 @@ ice_eswitch_br_vlan_create(u16 vid, u16 flags, struct ice_esw_br_port *port)
struct ice_esw_br_vlan *vlan;
int err;
- vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
+ vlan = kzalloc_obj(*vlan);
if (!vlan)
return ERR_PTR(-ENOMEM);
@@ -916,7 +916,7 @@ ice_eswitch_br_port_init(struct ice_esw_br *bridge)
{
struct ice_esw_br_port *br_port;
- br_port = kzalloc(sizeof(*br_port), GFP_KERNEL);
+ br_port = kzalloc_obj(*br_port);
if (!br_port)
return ERR_PTR(-ENOMEM);
@@ -1013,7 +1013,7 @@ ice_eswitch_br_init(struct ice_esw_br_offloads *br_offloads, int ifindex)
struct ice_esw_br *bridge;
int err;
- bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ bridge = kzalloc_obj(*bridge);
if (!bridge)
return ERR_PTR(-ENOMEM);
@@ -1217,7 +1217,7 @@ ice_eswitch_br_offloads_alloc(struct ice_pf *pf)
if (pf->eswitch.br_offloads)
return ERR_PTR(-EEXIST);
- br_offloads = kzalloc(sizeof(*br_offloads), GFP_KERNEL);
+ br_offloads = kzalloc_obj(*br_offloads);
if (!br_offloads)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 969d4f8f9c02..bf9a821c543b 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -33,8 +33,8 @@ static int ice_q_stats_len(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
- return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) *
- (sizeof(struct ice_q_stats) / sizeof(u64)));
+ /* One packets and one bytes count per queue */
+ return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) * 2);
}
#define ICE_PF_STATS_LEN ARRAY_SIZE(ice_gstrings_pf_stats)
@@ -853,6 +853,7 @@ static int
ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
u8 *bytes)
{
+ enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
struct ice_pf *pf = ice_netdev_to_pf(netdev);
struct ice_hw *hw = &pf->hw;
struct device *dev;
@@ -869,24 +870,15 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
if (!buf)
return -ENOMEM;
- ret = ice_acquire_nvm(hw, ICE_RES_READ);
- if (ret) {
- dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %s\n",
- ret, libie_aq_str(hw->adminq.sq_last_status));
- goto out;
- }
-
ret = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf,
- false);
+ false, &read_aq_err);
if (ret) {
dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n",
- ret, libie_aq_str(hw->adminq.sq_last_status));
- goto release;
+ ret, libie_aq_str(read_aq_err));
+ goto out;
}
memcpy(bytes, buf, eeprom->len);
-release:
- ice_release_nvm(hw);
out:
kfree(buf);
return ret;
@@ -1069,18 +1061,18 @@ static int ice_lbtest_prepare_rings(struct ice_vsi *vsi)
status = ice_vsi_cfg_lan(vsi);
if (status)
- goto err_setup_rx_ring;
+ goto err_cfg_lan;
status = ice_vsi_start_all_rx_rings(vsi);
if (status)
- goto err_start_rx_ring;
+ goto err_cfg_lan;
return 0;
-err_start_rx_ring:
- ice_vsi_free_rx_rings(vsi);
-err_setup_rx_ring:
+err_cfg_lan:
ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
+err_setup_rx_ring:
+ ice_vsi_free_rx_rings(vsi);
err_setup_tx_ring:
ice_vsi_free_tx_rings(vsi);
@@ -1251,7 +1243,7 @@ static int ice_lbtest_receive_frames(struct ice_rx_ring *rx_ring)
rx_buf = &rx_ring->rx_fqes[i];
page = __netmem_to_page(rx_buf->netmem);
received_buf = page_address(page) + rx_buf->offset +
- page->pp->p.offset;
+ pp_page_to_nmdesc(page)->pp->p.offset;
if (ice_lbtest_check_frame(received_buf))
valid_frames++;
@@ -1289,6 +1281,10 @@ static u64 ice_loopback_test(struct net_device *netdev)
test_vsi->netdev = netdev;
tx_ring = test_vsi->tx_rings[0];
rx_ring = test_vsi->rx_rings[0];
+ /* Dummy q_vector and napi. Fill the minimum required for
+ * ice_rxq_pp_create().
+ */
+ rx_ring->q_vector->napi.dev = netdev;
if (ice_lbtest_prepare_rings(test_vsi)) {
ret = 2;
@@ -1652,7 +1648,7 @@ ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
break;
}
- caps = kzalloc(sizeof(*caps), GFP_KERNEL);
+ caps = kzalloc_obj(*caps);
if (!caps)
return -ENOMEM;
@@ -1926,6 +1922,17 @@ __ice_get_ethtool_stats(struct net_device *netdev,
int i = 0;
char *p;
+ if (ice_is_port_repr_netdev(netdev)) {
+ ice_update_eth_stats(vsi);
+
+ for (j = 0; j < ICE_VSI_STATS_LEN; j++) {
+ p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset;
+ data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ return;
+ }
+
ice_update_pf_stats(pf);
ice_update_vsi_stats(vsi);
@@ -1935,32 +1942,39 @@ __ice_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
- if (ice_is_port_repr_netdev(netdev))
- return;
-
/* populate per queue stats */
rcu_read_lock();
ice_for_each_alloc_txq(vsi, j) {
+ u64 pkts, bytes;
+
tx_ring = READ_ONCE(vsi->tx_rings[j]);
- if (tx_ring && tx_ring->ring_stats) {
- data[i++] = tx_ring->ring_stats->stats.pkts;
- data[i++] = tx_ring->ring_stats->stats.bytes;
- } else {
+ if (!tx_ring || !tx_ring->ring_stats) {
data[i++] = 0;
data[i++] = 0;
+ continue;
}
+
+ ice_fetch_tx_ring_stats(tx_ring, &pkts, &bytes);
+
+ data[i++] = pkts;
+ data[i++] = bytes;
}
ice_for_each_alloc_rxq(vsi, j) {
+ u64 pkts, bytes;
+
rx_ring = READ_ONCE(vsi->rx_rings[j]);
- if (rx_ring && rx_ring->ring_stats) {
- data[i++] = rx_ring->ring_stats->stats.pkts;
- data[i++] = rx_ring->ring_stats->stats.bytes;
- } else {
+ if (!rx_ring || !rx_ring->ring_stats) {
data[i++] = 0;
data[i++] = 0;
+ continue;
}
+
+ ice_fetch_rx_ring_stats(rx_ring, &pkts, &bytes);
+
+ data[i++] = pkts;
+ data[i++] = bytes;
}
rcu_read_unlock();
@@ -2354,7 +2368,7 @@ ice_get_link_ksettings(struct net_device *netdev,
/* flow control is symmetric and always supported */
ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
- caps = kzalloc(sizeof(*caps), GFP_KERNEL);
+ caps = kzalloc_obj(*caps);
if (!caps)
return -ENOMEM;
@@ -2619,7 +2633,7 @@ ice_set_link_ksettings(struct net_device *netdev,
pi->phy.link_info.link_info & ICE_AQ_LINK_UP)
return -EOPNOTSUPP;
- phy_caps = kzalloc(sizeof(*phy_caps), GFP_KERNEL);
+ phy_caps = kzalloc_obj(*phy_caps);
if (!phy_caps)
return -ENOMEM;
@@ -3255,7 +3269,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n",
vsi->tx_rings[0]->count, new_tx_cnt);
- tx_rings = kcalloc(vsi->num_txq, sizeof(*tx_rings), GFP_KERNEL);
+ tx_rings = kzalloc_objs(*tx_rings, vsi->num_txq);
if (!tx_rings) {
err = -ENOMEM;
goto done;
@@ -3268,6 +3282,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
tx_rings[i].desc = NULL;
tx_rings[i].tx_buf = NULL;
tx_rings[i].tstamp_ring = NULL;
+ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_rings[i].flags);
tx_rings[i].tx_tstamps = &pf->ptp.port.tx;
err = ice_setup_tx_ring(&tx_rings[i]);
if (err) {
@@ -3285,7 +3300,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
netdev_info(netdev, "Changing XDP descriptor count from %d to %d\n",
vsi->xdp_rings[0]->count, new_tx_cnt);
- xdp_rings = kcalloc(vsi->num_xdp_txq, sizeof(*xdp_rings), GFP_KERNEL);
+ xdp_rings = kzalloc_objs(*xdp_rings, vsi->num_xdp_txq);
if (!xdp_rings) {
err = -ENOMEM;
goto free_tx;
@@ -3315,10 +3330,10 @@ process_rx:
netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n",
vsi->rx_rings[0]->count, new_rx_cnt);
- rx_rings = kcalloc(vsi->num_rxq, sizeof(*rx_rings), GFP_KERNEL);
+ rx_rings = kzalloc_objs(*rx_rings, vsi->num_rxq);
if (!rx_rings) {
err = -ENOMEM;
- goto done;
+ goto free_xdp;
}
ice_for_each_rxq(vsi, i) {
@@ -3328,6 +3343,7 @@ process_rx:
rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
rx_rings[i].desc = NULL;
rx_rings[i].xdp_buf = NULL;
+ rx_rings[i].xdp_rxq = (struct xdp_rxq_info){ };
/* this is to allow wr32 to have something to write to
* during early allocation of Rx buffers
@@ -3345,7 +3361,7 @@ rx_unwind:
}
kfree(rx_rings);
err = -ENOMEM;
- goto free_tx;
+ goto free_xdp;
}
}
@@ -3378,7 +3394,6 @@ process_link:
*/
rx_rings[i].next_to_use = 0;
rx_rings[i].next_to_clean = 0;
- rx_rings[i].next_to_alloc = 0;
*vsi->rx_rings[i] = rx_rings[i];
}
kfree(rx_rings);
@@ -3398,6 +3413,13 @@ process_link:
}
goto done;
+free_xdp:
+ if (xdp_rings) {
+ ice_for_each_xdp_txq(vsi, i)
+ ice_free_tx_ring(&xdp_rings[i]);
+ kfree(xdp_rings);
+ }
+
free_tx:
/* error cleanup if the Rx allocations failed after getting Tx */
if (tx_rings) {
@@ -3436,7 +3458,7 @@ ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return;
@@ -3478,7 +3500,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
struct ice_vsi *vsi = np->vsi;
struct ice_hw *hw = &pf->hw;
struct ice_port_info *pi;
- u8 aq_failures;
+ u8 aq_failures = 0;
bool link_up;
u32 is_an;
int err;
@@ -3502,7 +3524,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
* so compare pause->autoneg with SW configured to prevent the user from
* using set pause param to chance autoneg.
*/
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -3549,18 +3571,22 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
/* Set the FC mode and only restart AN if link is up */
err = ice_set_fc(pi, &aq_failures, link_up);
- if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) {
+ switch (aq_failures) {
+ case ICE_SET_FC_AQ_FAIL_GET:
netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
- } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) {
+ break;
+ case ICE_SET_FC_AQ_FAIL_SET:
netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
- } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) {
+ break;
+ case ICE_SET_FC_AQ_FAIL_UPDATE:
netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
+ break;
}
return err;
@@ -3626,11 +3652,7 @@ ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh)
if (!lut)
return -ENOMEM;
- err = ice_get_rss_key(vsi, rxfh->key);
- if (err)
- goto out;
-
- err = ice_get_rss_lut(vsi, lut, vsi->rss_table_size);
+ err = ice_get_rss(vsi, rxfh->key, lut, vsi->rss_table_size);
if (err)
goto out;
@@ -3757,24 +3779,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
}
/**
- * ice_get_max_txq - return the maximum number of Tx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_txq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
-}
-
-/**
- * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_rxq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
-}
-
-/**
* ice_get_combined_cnt - return the current number of combined channels
* @vsi: PF VSI pointer
*
@@ -4500,7 +4504,7 @@ ice_get_module_eeprom(struct net_device *netdev,
u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
struct ice_hw *hw = &pf->hw;
bool is_sfp = false;
- unsigned int i, j;
+ unsigned int i;
u16 offset = 0;
u8 page = 0;
int status;
@@ -4542,26 +4546,19 @@ ice_get_module_eeprom(struct net_device *netdev,
if (page == 0 || !(data[0x2] & 0x4)) {
u32 copy_len;
- /* If i2c bus is busy due to slow page change or
- * link management access, call can fail. This is normal.
- * So we retry this a few times.
- */
- for (j = 0; j < 4; j++) {
- status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
- !is_sfp, value,
- SFF_READ_BLOCK_SIZE,
- 0, NULL);
- netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
- addr, offset, page, is_sfp,
- value[0], value[1], value[2], value[3],
- value[4], value[5], value[6], value[7],
- status);
- if (status) {
- usleep_range(1500, 2500);
- memset(value, 0, SFF_READ_BLOCK_SIZE);
- continue;
- }
- break;
+ status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
+ !is_sfp, value,
+ SFF_READ_BLOCK_SIZE,
+ 0, NULL);
+ netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%pe)\n",
+ addr, offset, page, is_sfp,
+ value[0], value[1], value[2], value[3],
+ value[4], value[5], value[6], value[7],
+ ERR_PTR(status));
+ if (status) {
+ netdev_err(netdev, "%s: error reading module EEPROM: status %pe\n",
+ __func__, ERR_PTR(status));
+ return status;
}
/* Make sure we have enough room for the new block */
diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
index c0dbec369366..bb1d12f952cf 100644
--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
@@ -3734,7 +3734,7 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
int status = 0;
u16 idx;
- attr_used = kcalloc(ICE_MAX_PTG_ATTRS, sizeof(*attr_used), GFP_KERNEL);
+ attr_used = kzalloc_objs(*attr_used, ICE_MAX_PTG_ATTRS);
if (!attr_used)
return -ENOMEM;
@@ -4021,7 +4021,7 @@ ice_find_prof_vsig(struct ice_hw *hw, enum ice_block blk, u64 hdl, u16 *vsig)
INIT_LIST_HEAD(&lst);
- t = kzalloc(sizeof(*t), GFP_KERNEL);
+ t = kzalloc_obj(*t);
if (!t)
return false;
diff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c
index c9b6d0a84bd1..121552c644cd 100644
--- a/drivers/net/ethernet/intel/ice/ice_flow.c
+++ b/drivers/net/ethernet/intel/ice/ice_flow.c
@@ -1468,7 +1468,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
if (prof_id >= ids->count)
return -ENOSPC;
- params = kzalloc(sizeof(*params), GFP_KERNEL);
+ params = kzalloc_obj(*params);
if (!params)
return -ENOMEM;
@@ -1661,7 +1661,7 @@ ice_flow_set_parser_prof(struct ice_hw *hw, u16 dest_vsi, u16 fdir_vsi,
int status;
int i, idx;
- params = kzalloc(sizeof(*params), GFP_KERNEL);
+ params = kzalloc_obj(*params);
if (!params)
return -ENOMEM;
@@ -2552,7 +2552,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle,
segs_cnt = (cfg->hdr_type == ICE_RSS_OUTER_HEADERS) ?
ICE_FLOW_SEG_SINGLE : ICE_FLOW_SEG_MAX;
- segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
+ segs = kzalloc_objs(*segs, segs_cnt);
if (!segs)
return -ENOMEM;
@@ -2699,7 +2699,7 @@ ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle,
segs_cnt = (cfg->hdr_type == ICE_RSS_OUTER_HEADERS) ?
ICE_FLOW_SEG_SINGLE : ICE_FLOW_SEG_MAX;
- segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
+ segs = kzalloc_objs(*segs, segs_cnt);
if (!segs)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index 973a13d3d92a..36314610927b 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -726,7 +726,7 @@ static int ice_finalize_update(struct pldmfw *context)
switch (priv->reset_level) {
case ICE_AQC_NVM_EMPR_FLAG:
devlink_flash_update_status_notify(devlink,
- "Activate new firmware by devlink reload",
+ "Activate new firmware by devlink reload action fw_activate",
NULL, 0, 0);
break;
case ICE_AQC_NVM_PERST_FLAG:
@@ -862,7 +862,7 @@ int ice_get_pending_updates(struct ice_pf *pf, u8 *pending,
struct ice_hw *hw = &pf->hw;
int err;
- dev_caps = kzalloc(sizeof(*dev_caps), GFP_KERNEL);
+ dev_caps = kzalloc_obj(*dev_caps);
if (!dev_caps)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
index 6b26290452d4..7d21c3417b0b 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2021-2022, Intel Corporation. */
#include "ice.h"
+#include <linux/slab.h>
#include "ice_lib.h"
/**
@@ -124,7 +125,7 @@ static void ice_gnss_read(struct kthread_work *work)
data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
- buf = (char *)get_zeroed_page(GFP_KERNEL);
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto requeue;
@@ -151,7 +152,7 @@ static void ice_gnss_read(struct kthread_work *work)
count, i);
delay = ICE_GNSS_TIMER_DELAY_TIME;
free_buf:
- free_page((unsigned long)buf);
+ kfree(buf);
requeue:
kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, delay);
if (err)
@@ -174,7 +175,7 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
struct kthread_worker *kworker;
struct gnss_serial *gnss;
- gnss = kzalloc(sizeof(*gnss), GFP_KERNEL);
+ gnss = kzalloc_obj(*gnss);
if (!gnss)
return NULL;
diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c
index 420d45c2558b..102d63c3018b 100644
--- a/drivers/net/ethernet/intel/ice/ice_idc.c
+++ b/drivers/net/ethernet/intel/ice/ice_idc.c
@@ -308,7 +308,7 @@ int ice_plug_aux_dev(struct ice_pf *pf)
if (!cdev)
return -ENODEV;
- iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
+ iadev = kzalloc_obj(*iadev);
if (!iadev)
return -ENOMEM;
@@ -361,6 +361,39 @@ void ice_unplug_aux_dev(struct ice_pf *pf)
}
/**
+ * ice_rdma_finalize_setup - Complete RDMA setup after VSI is ready
+ * @pf: ptr to ice_pf
+ *
+ * Sets VSI-dependent information and plugs aux device.
+ * Must be called after ice_init_rdma(), ice_vsi_rebuild(), and
+ * ice_dcb_rebuild() complete.
+ */
+void ice_rdma_finalize_setup(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct iidc_rdma_priv_dev_info *privd;
+ int ret;
+
+ if (!ice_is_rdma_ena(pf) || !pf->cdev_info)
+ return;
+
+ privd = pf->cdev_info->iidc_priv;
+ if (!privd || !pf->vsi || !pf->vsi[0] || !pf->vsi[0]->netdev)
+ return;
+
+ /* Assign VSI info now that VSI is valid */
+ privd->netdev = pf->vsi[0]->netdev;
+ privd->vport_id = pf->vsi[0]->vsi_num;
+
+ /* Update QoS info after DCB has been rebuilt */
+ ice_setup_dcb_qos_info(pf, &privd->qos_info);
+
+ ret = ice_plug_aux_dev(pf);
+ if (ret)
+ dev_warn(dev, "Failed to plug RDMA aux device: %d\n", ret);
+}
+
+/**
* ice_init_rdma - initializes PF for RDMA use
* @pf: ptr to ice_pf
*/
@@ -376,13 +409,13 @@ int ice_init_rdma(struct ice_pf *pf)
return 0;
}
- cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc_obj(*cdev);
if (!cdev)
return -ENOMEM;
pf->cdev_info = cdev;
- privd = kzalloc(sizeof(*privd), GFP_KERNEL);
+ privd = kzalloc_obj(*privd);
if (!privd) {
ret = -ENOMEM;
goto err_privd_alloc;
@@ -398,22 +431,14 @@ int ice_init_rdma(struct ice_pf *pf)
}
cdev->iidc_priv = privd;
- privd->netdev = pf->vsi[0]->netdev;
privd->hw_addr = (u8 __iomem *)pf->hw.hw_addr;
cdev->pdev = pf->pdev;
- privd->vport_id = pf->vsi[0]->vsi_num;
pf->cdev_info->rdma_protocol |= IIDC_RDMA_PROTOCOL_ROCEV2;
- ice_setup_dcb_qos_info(pf, &privd->qos_info);
- ret = ice_plug_aux_dev(pf);
- if (ret)
- goto err_plug_aux_dev;
+
return 0;
-err_plug_aux_dev:
- pf->cdev_info->adev = NULL;
- xa_erase(&ice_aux_id, pf->aux_idx);
err_alloc_xa:
kfree(privd);
err_privd_alloc:
@@ -432,7 +457,6 @@ void ice_deinit_rdma(struct ice_pf *pf)
if (!ice_is_rdma_ena(pf))
return;
- ice_unplug_aux_dev(pf);
xa_erase(&ice_aux_id, pf->aux_idx);
kfree(pf->cdev_info->iidc_priv);
kfree(pf->cdev_info);
diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c
index 30801fd375f0..cd59579568b7 100644
--- a/drivers/net/ethernet/intel/ice/ice_irq.c
+++ b/drivers/net/ethernet/intel/ice/ice_irq.c
@@ -81,7 +81,7 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf,
unsigned int index;
int ret;
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ entry = kzalloc_obj(*entry);
if (!entry)
return NULL;
@@ -106,9 +106,10 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf,
#define ICE_RDMA_AEQ_MSIX 1
static int ice_get_default_msix_amount(struct ice_pf *pf)
{
- return ICE_MIN_LAN_OICR_MSIX + num_online_cpus() +
+ return ICE_MIN_LAN_OICR_MSIX + netif_get_num_default_rss_queues() +
(test_bit(ICE_FLAG_FD_ENA, pf->flags) ? ICE_FDIR_MSIX : 0) +
- (ice_is_rdma_ena(pf) ? num_online_cpus() + ICE_RDMA_AEQ_MSIX : 0);
+ (ice_is_rdma_ena(pf) ? netif_get_num_default_rss_queues() +
+ ICE_RDMA_AEQ_MSIX : 0);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index d2576d606e10..08a17ded0ad5 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -742,7 +742,7 @@ static void ice_lag_build_netdev_list(struct ice_lag *lag,
INIT_LIST_HEAD(&ndlist->node);
rcu_read_lock();
for_each_netdev_in_bond_rcu(lag->upper_netdev, tmp_nd) {
- nl = kzalloc(sizeof(*nl), GFP_ATOMIC);
+ nl = kzalloc_obj(*nl, GFP_ATOMIC);
if (!nl)
break;
@@ -2310,7 +2310,7 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
return NOTIFY_DONE;
/* This memory will be freed at the end of ice_lag_process_event */
- lag_work = kzalloc(sizeof(*lag_work), GFP_KERNEL);
+ lag_work = kzalloc_obj(*lag_work);
if (!lag_work)
return -ENOMEM;
@@ -2332,7 +2332,7 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
rcu_read_lock();
for_each_netdev_in_bond_rcu(upper_netdev, tmp_nd) {
- nd_list = kzalloc(sizeof(*nd_list), GFP_ATOMIC);
+ nd_list = kzalloc_obj(*nd_list, GFP_ATOMIC);
if (!nd_list)
break;
@@ -2577,7 +2577,7 @@ int ice_init_lag(struct ice_pf *pf)
if (!ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
return 0;
- pf->lag = kzalloc(sizeof(*lag), GFP_KERNEL);
+ pf->lag = kzalloc_obj(*lag);
if (!pf->lag)
return -ENOMEM;
lag = pf->lag;
@@ -2623,7 +2623,7 @@ int ice_init_lag(struct ice_pf *pf)
goto free_lport_res;
/* associate recipes to profiles */
- for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) {
+ for (n = 0; n < ICE_MAX_NUM_PROFILES; n++) {
err = ice_aq_get_recipe_to_profile(&pf->hw, n,
&recipe_bits, NULL);
if (err)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 15621707fbf8..9e08db376d3d 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -107,10 +107,6 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
if (!vsi->rxq_map)
goto err_rxq_map;
- /* There is no need to allocate q_vectors for a loopback VSI. */
- if (vsi->type == ICE_VSI_LB)
- return 0;
-
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
@@ -159,12 +155,14 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)
static u16 ice_get_rxq_count(struct ice_pf *pf)
{
- return min(ice_get_avail_rxq_count(pf), num_online_cpus());
+ return min(ice_get_avail_rxq_count(pf),
+ netif_get_num_default_rss_queues());
}
static u16 ice_get_txq_count(struct ice_pf *pf)
{
- return min(ice_get_avail_txq_count(pf), num_online_cpus());
+ return min(ice_get_avail_txq_count(pf),
+ netif_get_num_default_rss_queues());
}
/**
@@ -239,6 +237,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
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);
@@ -288,7 +288,7 @@ static void ice_vsi_delete_from_hw(struct ice_vsi *vsi)
int status;
ice_fltr_remove_all(vsi);
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return;
@@ -394,10 +394,12 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
ring_stats = tx_ring_stats[i];
if (!ring_stats) {
- ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL);
+ ring_stats = kzalloc_obj(*ring_stats);
if (!ring_stats)
goto err_out;
+ u64_stats_init(&ring_stats->syncp);
+
WRITE_ONCE(tx_ring_stats[i], ring_stats);
}
@@ -413,10 +415,12 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
ring_stats = rx_ring_stats[i];
if (!ring_stats) {
- ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL);
+ ring_stats = kzalloc_obj(*ring_stats);
if (!ring_stats)
goto err_out;
+ u64_stats_init(&ring_stats->syncp);
+
WRITE_ONCE(rx_ring_stats[i], ring_stats);
}
@@ -527,19 +531,17 @@ static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi)
/* realloc will happen in rebuild path */
return 0;
- vsi_stat = kzalloc(sizeof(*vsi_stat), GFP_KERNEL);
+ vsi_stat = kzalloc_obj(*vsi_stat);
if (!vsi_stat)
return -ENOMEM;
vsi_stat->tx_ring_stats =
- kcalloc(vsi->alloc_txq, sizeof(*vsi_stat->tx_ring_stats),
- GFP_KERNEL);
+ 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 =
- kcalloc(vsi->alloc_rxq, sizeof(*vsi_stat->rx_ring_stats),
- GFP_KERNEL);
+ kzalloc_objs(*vsi_stat->rx_ring_stats, vsi->alloc_rxq);
if (!vsi_stat->rx_ring_stats)
goto err_alloc_rx;
@@ -907,13 +909,15 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
if (vsi->type == ICE_VSI_CHNL)
vsi->rss_size = min_t(u16, vsi->num_rxq, max_rss_size);
else
- vsi->rss_size = min_t(u16, num_online_cpus(),
+ vsi->rss_size = min_t(u16,
+ netif_get_num_default_rss_queues(),
max_rss_size);
vsi->rss_lut_type = ICE_LUT_PF;
break;
case ICE_VSI_SF:
vsi->rss_table_size = ICE_LUT_VSI_SIZE;
- vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size);
+ vsi->rss_size = min_t(u16, netif_get_num_default_rss_queues(),
+ max_rss_size);
vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_VF:
@@ -1231,7 +1235,7 @@ static int ice_vsi_init(struct ice_vsi *vsi, u32 vsi_flags)
int ret = 0;
dev = ice_pf_to_dev(pf);
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -1395,7 +1399,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
struct ice_tx_ring *ring;
/* allocate with kzalloc(), free with kfree_rcu() */
- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ ring = kzalloc_obj(*ring);
if (!ring)
goto err_out;
@@ -1408,9 +1412,9 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
ring->count = vsi->num_tx_desc;
ring->txq_teid = ICE_INVAL_TEID;
if (dvm_ena)
- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2;
+ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
else
- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG1;
+ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
WRITE_ONCE(vsi->tx_rings[i], ring);
}
@@ -1419,7 +1423,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
struct ice_rx_ring *ring;
/* allocate with kzalloc(), free with kfree_rcu() */
- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ ring = kzalloc_obj(*ring);
if (!ring)
goto err_out;
@@ -2420,14 +2424,21 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
}
break;
case ICE_VSI_LB:
- ret = ice_vsi_alloc_rings(vsi);
+ ret = ice_vsi_alloc_q_vectors(vsi);
if (ret)
goto unroll_vsi_init;
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
ret = ice_vsi_alloc_ring_stats(vsi);
if (ret)
goto unroll_vector_base;
+ /* Simply map the dummy q_vector to the only rx_ring */
+ vsi->rx_rings[0]->q_vector = vsi->q_vectors[0];
+
break;
default:
/* clean up the resources and exit */
@@ -2779,12 +2790,14 @@ void ice_vsi_set_napi_queues(struct ice_vsi *vsi)
ASSERT_RTNL();
ice_for_each_rxq(vsi, q_idx)
- netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX,
- &vsi->rx_rings[q_idx]->q_vector->napi);
+ if (vsi->rx_rings[q_idx] && vsi->rx_rings[q_idx]->q_vector)
+ netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX,
+ &vsi->rx_rings[q_idx]->q_vector->napi);
ice_for_each_txq(vsi, q_idx)
- netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX,
- &vsi->tx_rings[q_idx]->q_vector->napi);
+ if (vsi->tx_rings[q_idx] && vsi->tx_rings[q_idx]->q_vector)
+ netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX,
+ &vsi->tx_rings[q_idx]->q_vector->napi);
/* Also set the interrupt number for the NAPI */
ice_for_each_q_vector(vsi, v_idx) {
struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];
@@ -2858,6 +2871,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
return -ENODEV;
pf = vsi->back;
+ if (ice_is_vsi_dflt_vsi(vsi))
+ ice_clear_dflt_vsi(vsi);
+
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
ice_rss_clean(vsi);
@@ -3094,8 +3110,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags)
if (ret)
goto unlock;
- coalesce = kcalloc(vsi->num_q_vectors,
- sizeof(struct ice_coalesce_stored), GFP_KERNEL);
+ coalesce = kzalloc_objs(struct ice_coalesce_stored, vsi->num_q_vectors);
if (!coalesce) {
ret = -ENOMEM;
goto decfg;
@@ -3377,7 +3392,7 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc)
vsi->tc_cfg.ena_tc = ena_tc;
vsi->tc_cfg.numtc = num_tc;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -3425,20 +3440,6 @@ out:
}
/**
- * ice_update_ring_stats - Update ring statistics
- * @stats: stats to be updated
- * @pkts: number of processed packets
- * @bytes: number of processed bytes
- *
- * This function assumes that caller has acquired a u64_stats_sync lock.
- */
-static void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes)
-{
- stats->bytes += bytes;
- stats->pkts += pkts;
-}
-
-/**
* ice_update_tx_ring_stats - Update Tx ring specific counters
* @tx_ring: ring to update
* @pkts: number of processed packets
@@ -3447,7 +3448,8 @@ static void ice_update_ring_stats(struct ice_q_stats *stats, u64 pkts, u64 bytes
void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&tx_ring->ring_stats->syncp);
- ice_update_ring_stats(&tx_ring->ring_stats->stats, pkts, bytes);
+ u64_stats_add(&tx_ring->ring_stats->pkts, pkts);
+ u64_stats_add(&tx_ring->ring_stats->bytes, bytes);
u64_stats_update_end(&tx_ring->ring_stats->syncp);
}
@@ -3460,11 +3462,48 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *tx_ring, u64 pkts, u64 bytes)
void ice_update_rx_ring_stats(struct ice_rx_ring *rx_ring, u64 pkts, u64 bytes)
{
u64_stats_update_begin(&rx_ring->ring_stats->syncp);
- ice_update_ring_stats(&rx_ring->ring_stats->stats, pkts, bytes);
+ u64_stats_add(&rx_ring->ring_stats->pkts, pkts);
+ u64_stats_add(&rx_ring->ring_stats->bytes, bytes);
u64_stats_update_end(&rx_ring->ring_stats->syncp);
}
/**
+ * ice_fetch_tx_ring_stats - Fetch Tx ring packet and byte counters
+ * @ring: ring to update
+ * @pkts: number of processed packets
+ * @bytes: number of processed bytes
+ */
+void ice_fetch_tx_ring_stats(const struct ice_tx_ring *ring,
+ u64 *pkts, u64 *bytes)
+{
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
+ *pkts = u64_stats_read(&ring->ring_stats->pkts);
+ *bytes = u64_stats_read(&ring->ring_stats->bytes);
+ } while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
+}
+
+/**
+ * ice_fetch_rx_ring_stats - Fetch Rx ring packet and byte counters
+ * @ring: ring to read
+ * @pkts: number of processed packets
+ * @bytes: number of processed bytes
+ */
+void ice_fetch_rx_ring_stats(const struct ice_rx_ring *ring,
+ u64 *pkts, u64 *bytes)
+{
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&ring->ring_stats->syncp);
+ *pkts = u64_stats_read(&ring->ring_stats->pkts);
+ *bytes = u64_stats_read(&ring->ring_stats->bytes);
+ } while (u64_stats_fetch_retry(&ring->ring_stats->syncp, start));
+}
+
+/**
* ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used
* @pi: port info of the switch with default VSI
*
@@ -3733,7 +3772,8 @@ int ice_set_link(struct ice_vsi *vsi, bool ena)
if (vsi->type != ICE_VSI_PF)
return -EINVAL;
- status = ice_aq_set_link_restart_an(pi, ena, NULL);
+ status = ice_aq_set_link_restart_an(pi, ena, NULL,
+ ICE_AQC_RESTART_AN_REFCLK_NOCHANGE);
/* if link is owned by manageability, FW will return LIBIE_AQ_RC_EMODE.
* this is not a fatal error, so print a warning message and return
@@ -3805,22 +3845,31 @@ int ice_vsi_add_vlan_zero(struct ice_vsi *vsi)
int ice_vsi_del_vlan_zero(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
+ struct ice_pf *pf = vsi->back;
struct ice_vlan vlan;
int err;
- vlan = ICE_VLAN(0, 0, 0);
- err = vlan_ops->del_vlan(vsi, &vlan);
- if (err && err != -EEXIST)
- return err;
+ if (pf->lag && pf->lag->primary) {
+ dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting prune list\n");
+ } else {
+ vlan = ICE_VLAN(0, 0, 0);
+ err = vlan_ops->del_vlan(vsi, &vlan);
+ if (err && err != -EEXIST)
+ return err;
+ }
/* in SVM both VLAN 0 filters are identical */
if (!ice_is_dvm_ena(&vsi->back->hw))
return 0;
- vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
- err = vlan_ops->del_vlan(vsi, &vlan);
- if (err && err != -EEXIST)
- return err;
+ if (pf->lag && pf->lag->primary) {
+ dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting QinQ prune list\n");
+ } else {
+ vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
+ err = vlan_ops->del_vlan(vsi, &vlan);
+ if (err && err != -EEXIST)
+ return err;
+ }
/* when deleting the last VLAN filter, make sure to disable the VLAN
* promisc mode so the filter isn't left by accident
@@ -3946,6 +3995,9 @@ void ice_init_feature_support(struct ice_pf *pf)
break;
}
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
+ ice_set_feature_support(pf, ICE_F_PHY_RCLK);
+
if (pf->hw.mac_type == ICE_MAC_E830) {
ice_set_feature_support(pf, ICE_F_MBX_LIMIT);
ice_set_feature_support(pf, ICE_F_GCS);
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 2cb1eb98b9da..49454d98dcfe 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -92,6 +92,12 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *ring, u64 pkts, u64 bytes);
void ice_update_rx_ring_stats(struct ice_rx_ring *ring, u64 pkts, u64 bytes);
+void ice_fetch_tx_ring_stats(const struct ice_tx_ring *ring,
+ u64 *pkts, u64 *bytes);
+
+void ice_fetch_rx_ring_stats(const struct ice_rx_ring *ring,
+ u64 *pkts, u64 *bytes);
+
void ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl);
void ice_write_itr(struct ice_ring_container *rc, u16 itr);
void ice_set_q_vector_intrl(struct ice_q_vector *q_vector);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 4bb68e7a00f5..d88835482d3a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -159,8 +159,8 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
* prev_pkt would be negative if there was no
* pending work.
*/
- packets = ring_stats->stats.pkts & INT_MAX;
- if (ring_stats->tx_stats.prev_pkt == packets) {
+ packets = ice_stats_read(ring_stats, pkts) & INT_MAX;
+ if (ring_stats->tx.prev_pkt == packets) {
/* Trigger sw interrupt to revive the queue */
ice_trigger_sw_intr(hw, tx_ring->q_vector);
continue;
@@ -170,7 +170,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
* to ice_get_tx_pending()
*/
smp_rmb();
- ring_stats->tx_stats.prev_pkt =
+ ring_stats->tx.prev_pkt =
ice_get_tx_pending(tx_ring) ? packets : -1;
}
}
@@ -875,7 +875,7 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
an = "False";
/* Get FEC mode requested based on PHY caps last SW configuration */
- caps = kzalloc(sizeof(*caps), GFP_KERNEL);
+ caps = kzalloc_obj(*caps);
if (!caps) {
fec_req = "Unknown";
an_advertised = "Unknown";
@@ -1923,82 +1923,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
}
/**
- * ice_force_phys_link_state - Force the physical link state
- * @vsi: VSI to force the physical link state to up/down
- * @link_up: true/false indicates to set the physical link to up/down
- *
- * Force the physical link state by getting the current PHY capabilities from
- * hardware and setting the PHY config based on the determined capabilities. If
- * link changes a link event will be triggered because both the Enable Automatic
- * Link Update and LESM Enable bits are set when setting the PHY capabilities.
- *
- * Returns 0 on success, negative on failure
- */
-static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
-{
- struct ice_aqc_get_phy_caps_data *pcaps;
- struct ice_aqc_set_phy_cfg_data *cfg;
- struct ice_port_info *pi;
- struct device *dev;
- int retcode;
-
- if (!vsi || !vsi->port_info || !vsi->back)
- return -EINVAL;
- if (vsi->type != ICE_VSI_PF)
- return 0;
-
- dev = ice_pf_to_dev(vsi->back);
-
- pi = vsi->port_info;
-
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
- if (!pcaps)
- return -ENOMEM;
-
- retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
- NULL);
- if (retcode) {
- dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n",
- vsi->vsi_num, retcode);
- retcode = -EIO;
- goto out;
- }
-
- /* No change in link */
- if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
- link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
- goto out;
-
- /* Use the current user PHY configuration. The current user PHY
- * configuration is initialized during probe from PHY capabilities
- * software mode, and updated on set PHY configuration.
- */
- cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL);
- if (!cfg) {
- retcode = -ENOMEM;
- goto out;
- }
-
- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
- if (link_up)
- cfg->caps |= ICE_AQ_PHY_ENA_LINK;
- else
- cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
-
- retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL);
- if (retcode) {
- dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
- vsi->vsi_num, retcode);
- retcode = -EIO;
- }
-
- kfree(cfg);
-out:
- kfree(pcaps);
- return retcode;
-}
-
-/**
* ice_init_nvm_phy_type - Initialize the NVM PHY type
* @pi: port info structure
*
@@ -2010,7 +1934,7 @@ static int ice_init_nvm_phy_type(struct ice_port_info *pi)
struct ice_pf *pf = pi->hw->back;
int err;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -2066,7 +1990,7 @@ static void ice_init_link_dflt_override(struct ice_port_info *pi)
* first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state
* is used to indicate that the user PHY cfg default override is initialized
* and the PHY has not been configured with the default override settings. The
- * state is set here, and cleared in ice_configure_phy the first time the PHY is
+ * state is set here, and cleared in ice_phy_cfg the first time the PHY is
* configured.
*
* This function should be called only if the FW doesn't support default
@@ -2122,7 +2046,7 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi)
if (!(phy->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE))
return -EIO;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -2172,14 +2096,18 @@ err_out:
}
/**
- * ice_configure_phy - configure PHY
+ * ice_phy_cfg - configure PHY
* @vsi: VSI of PHY
+ * @link_en: true/false indicates to set link to enable/disable
*
* Set the PHY configuration. If the current PHY configuration is the same as
- * the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise
- * configure the based get PHY capabilities for topology with media.
+ * the curr_user_phy_cfg and link_en hasn't changed, then do nothing to avoid
+ * link flap. Otherwise configure the PHY based get PHY capabilities for
+ * topology with media and link_en.
+ *
+ * Return: 0 on success, negative on failure
*/
-static int ice_configure_phy(struct ice_vsi *vsi)
+static int ice_phy_cfg(struct ice_vsi *vsi, bool link_en)
{
struct device *dev = ice_pf_to_dev(vsi->back);
struct ice_port_info *pi = vsi->port_info;
@@ -2199,10 +2127,7 @@ static int ice_configure_phy(struct ice_vsi *vsi)
phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA)
return -EPERM;
- if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))
- return ice_force_phys_link_state(vsi, true);
-
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -2215,10 +2140,8 @@ static int ice_configure_phy(struct ice_vsi *vsi)
goto done;
}
- /* If PHY enable link is configured and configuration has not changed,
- * there's nothing to do
- */
- if (pcaps->caps & ICE_AQC_PHY_EN_LINK &&
+ /* Configuration has not changed. There's nothing to do. */
+ if (link_en == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
ice_phy_caps_equals_cfg(pcaps, &phy->curr_user_phy_cfg))
goto done;
@@ -2236,7 +2159,7 @@ static int ice_configure_phy(struct ice_vsi *vsi)
goto done;
}
- cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ cfg = kzalloc_obj(*cfg);
if (!cfg) {
err = -ENOMEM;
goto done;
@@ -2282,8 +2205,12 @@ static int ice_configure_phy(struct ice_vsi *vsi)
*/
ice_cfg_phy_fc(pi, cfg, phy->curr_user_fc_req);
- /* Enable link and link update */
- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK;
+ /* Enable/Disable link and link update */
+ cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ if (link_en)
+ cfg->caps |= ICE_AQ_PHY_ENA_LINK;
+ else
+ cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
err = ice_aq_set_phy_cfg(&pf->hw, pi, cfg, NULL);
if (err)
@@ -2336,7 +2263,7 @@ static void ice_check_media_subtask(struct ice_pf *pf)
test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags))
return;
- err = ice_configure_phy(vsi);
+ err = ice_phy_cfg(vsi, true);
if (!err)
clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@@ -2385,7 +2312,7 @@ static void ice_service_task(struct work_struct *work)
if (test_and_clear_bit(ICE_AUX_ERR_PENDING, pf->state)) {
struct iidc_rdma_event *event;
- event = kzalloc(sizeof(*event), GFP_KERNEL);
+ event = kzalloc_obj(*event);
if (event) {
set_bit(IIDC_RDMA_EVENT_CRIT_ERR, event->type);
/* report the entire OICR value to AUX driver */
@@ -2408,7 +2335,7 @@ static void ice_service_task(struct work_struct *work)
if (test_and_clear_bit(ICE_FLAG_MTU_CHANGED, pf->flags)) {
struct iidc_rdma_event *event;
- event = kzalloc(sizeof(*event), GFP_KERNEL);
+ event = kzalloc_obj(*event);
if (event) {
set_bit(IIDC_RDMA_EVENT_AFTER_MTU_CHANGE, event->type);
ice_send_event_to_aux(pf, event);
@@ -2609,11 +2536,11 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi)
struct ice_ring_stats *ring_stats;
struct ice_tx_ring *xdp_ring;
- xdp_ring = kzalloc(sizeof(*xdp_ring), GFP_KERNEL);
+ xdp_ring = kzalloc_obj(*xdp_ring);
if (!xdp_ring)
goto free_xdp_rings;
- ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL);
+ ring_stats = kzalloc_obj(*ring_stats);
if (!ring_stats) {
ice_free_tx_ring(xdp_ring);
goto free_xdp_rings;
@@ -3314,18 +3241,20 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
if (ice_is_reset_in_progress(pf->state))
goto skip_irq;
- if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) {
- /* Process outstanding Tx timestamps. If there is more work,
- * re-arm the interrupt to trigger again.
- */
- if (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) {
- wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
- ice_flush(hw);
- }
- }
+ if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread))
+ ice_ptp_process_ts(pf);
skip_irq:
ice_irq_dynamic_ena(hw, NULL, NULL);
+ ice_flush(hw);
+
+ if (ice_ptp_tx_tstamps_pending(pf)) {
+ /* If any new Tx timestamps happened while in interrupt,
+ * re-arm the interrupt to trigger it again.
+ */
+ wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
+ ice_flush(hw);
+ }
return IRQ_HANDLED;
}
@@ -3753,7 +3682,7 @@ int ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
ICE_MCAST_VLAN_PROMISC_BITS,
vid);
- if (ret)
+ if (ret && ret != -EEXIST)
goto finish;
}
@@ -4175,6 +4104,12 @@ int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked)
}
ice_pf_dcb_recfg(pf, locked);
ice_vsi_open(vsi);
+ /* Rx rings are reallocated during VSI rebuild and lose their ptp_rx
+ * flag. Restore timestamp mode so newly allocated rings are set up
+ * for hardware Rx timestamping.
+ */
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
+ ice_ptp_restore_timestamp_mode(pf);
goto done;
rebuild_err:
@@ -4202,7 +4137,7 @@ static void ice_set_safe_mode_vlan_cfg(struct ice_pf *pf)
if (!vsi)
return;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return;
@@ -4697,8 +4632,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
- netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
- vsi->alloc_rxq);
+ netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back),
+ ice_get_max_rxq(vsi->back));
if (!netdev)
return -ENOMEM;
@@ -4836,6 +4771,7 @@ static void ice_deinit_features(struct ice_pf *pf)
ice_dpll_deinit(pf);
if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
xa_destroy(&pf->eswitch.reprs);
+ ice_hwmon_exit(pf);
}
static void ice_init_wakeup(struct ice_pf *pf)
@@ -4853,16 +4789,14 @@ static void ice_init_wakeup(struct ice_pf *pf)
device_set_wakeup_enable(ice_pf_to_dev(pf), false);
}
-static int ice_init_link(struct ice_pf *pf)
+static void ice_init_link(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
int err;
err = ice_init_link_events(pf->hw.port_info);
- if (err) {
+ if (err)
dev_err(dev, "ice_init_link_events failed: %d\n", err);
- return err;
- }
/* not a fatal error if this fails */
err = ice_init_nvm_phy_type(pf->hw.port_info);
@@ -4889,15 +4823,19 @@ static int ice_init_link(struct ice_pf *pf)
if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) {
struct ice_vsi *vsi = ice_get_main_vsi(pf);
+ struct ice_link_default_override_tlv *ldo;
+ bool link_en;
+
+ ldo = &pf->link_dflt_override;
+ link_en = !(ldo->options &
+ ICE_LINK_OVERRIDE_AUTO_LINK_DIS);
if (vsi)
- ice_configure_phy(vsi);
+ ice_phy_cfg(vsi, link_en);
}
} else {
set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
}
-
- return err;
}
static int ice_init_pf_sw(struct ice_pf *pf)
@@ -4907,7 +4845,7 @@ static int ice_init_pf_sw(struct ice_pf *pf)
int err;
/* create switch struct for the switch element created by FW on boot */
- pf->first_sw = kzalloc(sizeof(*pf->first_sw), GFP_KERNEL);
+ pf->first_sw = kzalloc_obj(*pf->first_sw);
if (!pf->first_sw)
return -ENOMEM;
@@ -5025,7 +4963,7 @@ static int ice_init(struct ice_pf *pf)
}
if (pf->hw.mac_type == ICE_MAC_E830) {
- err = pci_enable_ptm(pf->pdev, NULL);
+ err = pci_enable_ptm(pf->pdev);
if (err)
dev_dbg(dev, "PCIe PTM not supported by PCIe bus/controller\n");
}
@@ -5040,13 +4978,11 @@ static int ice_init(struct ice_pf *pf)
ice_init_wakeup(pf);
- err = ice_init_link(pf);
- if (err)
- goto err_init_link;
+ ice_init_link(pf);
err = ice_send_version(pf);
if (err)
- goto err_init_link;
+ goto err_deinit_pf_sw;
ice_verify_cacheline_size(pf);
@@ -5065,7 +5001,7 @@ static int ice_init(struct ice_pf *pf)
return 0;
-err_init_link:
+err_deinit_pf_sw:
ice_deinit_pf_sw(pf);
err_init_pf_sw:
ice_dealloc_vsis(pf);
@@ -5135,6 +5071,9 @@ int ice_load(struct ice_pf *pf)
if (err)
goto err_init_rdma;
+ /* Finalize RDMA: VSI already created, assign info and plug device */
+ ice_rdma_finalize_setup(pf);
+
ice_service_task_restart(pf);
clear_bit(ICE_DOWN, pf->state);
@@ -5166,6 +5105,7 @@ void ice_unload(struct ice_pf *pf)
devl_assert_locked(priv_to_devlink(pf));
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
ice_deinit_features(pf);
ice_tc_indir_block_unregister(vsi);
@@ -5305,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
return err;
}
+ ice_init_dev_hw(pf);
+
adapter = ice_adapter_get(pdev);
if (IS_ERR(adapter)) {
err = PTR_ERR(adapter);
@@ -5437,8 +5379,6 @@ static void ice_remove(struct pci_dev *pdev)
ice_free_vfs(pf);
}
- ice_hwmon_exit(pf);
-
if (!ice_is_safe_mode(pf))
ice_remove_arfs(pf);
@@ -5594,6 +5534,7 @@ static int ice_suspend(struct device *dev)
*/
disabled = ice_service_task_stop(pf);
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
/* Already suspended?, then there is nothing to do */
@@ -5696,6 +5637,16 @@ static int ice_resume(struct device *dev)
/* Restart the service task */
mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ /* Best-effort wait for the scheduled reset to finish so that the
+ * device is operational before returning. Without this, userspace
+ * (e.g. NetworkManager) may try to open the net device while the
+ * asynchronous reset is still in progress, hitting -EBUSY.
+ */
+ ret = ice_wait_for_reset(pf, secs_to_jiffies(10));
+ if (ret)
+ dev_err(dev, "Wait for reset timed out (10s) during resume: %d\n",
+ ret);
+
return 0;
}
@@ -6823,58 +6774,132 @@ int ice_up(struct ice_vsi *vsi)
return err;
}
+struct ice_vsi_tx_stats {
+ u64 pkts;
+ u64 bytes;
+ u64 tx_restart_q;
+ u64 tx_busy;
+ u64 tx_linearize;
+};
+
+struct ice_vsi_rx_stats {
+ u64 pkts;
+ u64 bytes;
+ u64 rx_non_eop_descs;
+ u64 rx_page_failed;
+ u64 rx_buf_failed;
+};
+
+/**
+ * ice_fetch_u64_tx_stats - get Tx stats from a ring
+ * @ring: the Tx ring to copy stats from
+ * @copy: temporary storage for the ring statistics
+ *
+ * Fetch the u64 stats from the ring using u64_stats_fetch. This ensures each
+ * stat value is self-consistent, though not necessarily consistent w.r.t
+ * other stats.
+ */
+static void ice_fetch_u64_tx_stats(struct ice_tx_ring *ring,
+ struct ice_vsi_tx_stats *copy)
+{
+ struct ice_ring_stats *stats = ring->ring_stats;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&stats->syncp);
+ copy->pkts = u64_stats_read(&stats->pkts);
+ copy->bytes = u64_stats_read(&stats->bytes);
+ copy->tx_restart_q = u64_stats_read(&stats->tx_restart_q);
+ copy->tx_busy = u64_stats_read(&stats->tx_busy);
+ copy->tx_linearize = u64_stats_read(&stats->tx_linearize);
+ } while (u64_stats_fetch_retry(&stats->syncp, start));
+}
+
/**
- * ice_fetch_u64_stats_per_ring - get packets and bytes stats per ring
- * @syncp: pointer to u64_stats_sync
- * @stats: stats that pkts and bytes count will be taken from
- * @pkts: packets stats counter
- * @bytes: bytes stats counter
+ * ice_fetch_u64_rx_stats - get Rx stats from a ring
+ * @ring: the Rx ring to copy stats from
+ * @copy: temporary storage for the ring statistics
*
- * This function fetches stats from the ring considering the atomic operations
- * that needs to be performed to read u64 values in 32 bit machine.
+ * Fetch the u64 stats from the ring using u64_stats_fetch. This ensures each
+ * stat value is self-consistent, though not necessarily consistent w.r.t
+ * other stats.
*/
-void
-ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp,
- struct ice_q_stats stats, u64 *pkts, u64 *bytes)
+static void ice_fetch_u64_rx_stats(struct ice_rx_ring *ring,
+ struct ice_vsi_rx_stats *copy)
{
+ struct ice_ring_stats *stats = ring->ring_stats;
unsigned int start;
do {
- start = u64_stats_fetch_begin(syncp);
- *pkts = stats.pkts;
- *bytes = stats.bytes;
- } while (u64_stats_fetch_retry(syncp, start));
+ start = u64_stats_fetch_begin(&stats->syncp);
+ copy->pkts = u64_stats_read(&stats->pkts);
+ copy->bytes = u64_stats_read(&stats->bytes);
+ copy->rx_non_eop_descs =
+ u64_stats_read(&stats->rx_non_eop_descs);
+ copy->rx_page_failed = u64_stats_read(&stats->rx_page_failed);
+ copy->rx_buf_failed = u64_stats_read(&stats->rx_buf_failed);
+ } while (u64_stats_fetch_retry(&stats->syncp, start));
}
/**
* ice_update_vsi_tx_ring_stats - Update VSI Tx ring stats counters
* @vsi: the VSI to be updated
- * @vsi_stats: the stats struct to be updated
+ * @vsi_stats: accumulated stats for this VSI
* @rings: rings to work on
* @count: number of rings
*/
-static void
-ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
- struct rtnl_link_stats64 *vsi_stats,
- struct ice_tx_ring **rings, u16 count)
+static void ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
+ struct ice_vsi_tx_stats *vsi_stats,
+ struct ice_tx_ring **rings, u16 count)
{
+ struct ice_vsi_tx_stats copy = {};
u16 i;
for (i = 0; i < count; i++) {
struct ice_tx_ring *ring;
- u64 pkts = 0, bytes = 0;
ring = READ_ONCE(rings[i]);
if (!ring || !ring->ring_stats)
continue;
- ice_fetch_u64_stats_per_ring(&ring->ring_stats->syncp,
- ring->ring_stats->stats, &pkts,
- &bytes);
- vsi_stats->tx_packets += pkts;
- vsi_stats->tx_bytes += bytes;
- vsi->tx_restart += ring->ring_stats->tx_stats.restart_q;
- vsi->tx_busy += ring->ring_stats->tx_stats.tx_busy;
- vsi->tx_linearize += ring->ring_stats->tx_stats.tx_linearize;
+
+ ice_fetch_u64_tx_stats(ring, &copy);
+
+ vsi_stats->pkts += copy.pkts;
+ vsi_stats->bytes += copy.bytes;
+ vsi_stats->tx_restart_q += copy.tx_restart_q;
+ vsi_stats->tx_busy += copy.tx_busy;
+ vsi_stats->tx_linearize += copy.tx_linearize;
+ }
+}
+
+/**
+ * ice_update_vsi_rx_ring_stats - Update VSI Rx ring stats counters
+ * @vsi: the VSI to be updated
+ * @vsi_stats: accumulated stats for this VSI
+ * @rings: rings to work on
+ * @count: number of rings
+ */
+static void ice_update_vsi_rx_ring_stats(struct ice_vsi *vsi,
+ struct ice_vsi_rx_stats *vsi_stats,
+ struct ice_rx_ring **rings, u16 count)
+{
+ struct ice_vsi_rx_stats copy = {};
+ u16 i;
+
+ for (i = 0; i < count; i++) {
+ struct ice_rx_ring *ring;
+
+ ring = READ_ONCE(rings[i]);
+ if (!ring || !ring->ring_stats)
+ continue;
+
+ ice_fetch_u64_rx_stats(ring, &copy);
+
+ vsi_stats->pkts += copy.pkts;
+ vsi_stats->bytes += copy.bytes;
+ vsi_stats->rx_non_eop_descs += copy.rx_non_eop_descs;
+ vsi_stats->rx_page_failed += copy.rx_page_failed;
+ vsi_stats->rx_buf_failed += copy.rx_buf_failed;
}
}
@@ -6885,50 +6910,34 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
{
struct rtnl_link_stats64 *net_stats, *stats_prev;
- struct rtnl_link_stats64 *vsi_stats;
+ struct ice_vsi_tx_stats tx_stats = {};
+ struct ice_vsi_rx_stats rx_stats = {};
struct ice_pf *pf = vsi->back;
- u64 pkts, bytes;
- int i;
-
- vsi_stats = kzalloc(sizeof(*vsi_stats), GFP_ATOMIC);
- if (!vsi_stats)
- return;
-
- /* reset non-netdev (extended) stats */
- vsi->tx_restart = 0;
- vsi->tx_busy = 0;
- vsi->tx_linearize = 0;
- vsi->rx_buf_failed = 0;
- vsi->rx_page_failed = 0;
rcu_read_lock();
/* update Tx rings counters */
- ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->tx_rings,
+ ice_update_vsi_tx_ring_stats(vsi, &tx_stats, vsi->tx_rings,
vsi->num_txq);
/* update Rx rings counters */
- ice_for_each_rxq(vsi, i) {
- struct ice_rx_ring *ring = READ_ONCE(vsi->rx_rings[i]);
- struct ice_ring_stats *ring_stats;
-
- ring_stats = ring->ring_stats;
- ice_fetch_u64_stats_per_ring(&ring_stats->syncp,
- ring_stats->stats, &pkts,
- &bytes);
- vsi_stats->rx_packets += pkts;
- vsi_stats->rx_bytes += bytes;
- vsi->rx_buf_failed += ring_stats->rx_stats.alloc_buf_failed;
- vsi->rx_page_failed += ring_stats->rx_stats.alloc_page_failed;
- }
+ ice_update_vsi_rx_ring_stats(vsi, &rx_stats, vsi->rx_rings,
+ vsi->num_rxq);
/* update XDP Tx rings counters */
if (ice_is_xdp_ena_vsi(vsi))
- ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->xdp_rings,
+ ice_update_vsi_tx_ring_stats(vsi, &tx_stats, vsi->xdp_rings,
vsi->num_xdp_txq);
rcu_read_unlock();
+ /* Save non-netdev (extended) stats */
+ vsi->tx_restart = tx_stats.tx_restart_q;
+ vsi->tx_busy = tx_stats.tx_busy;
+ vsi->tx_linearize = tx_stats.tx_linearize;
+ vsi->rx_buf_failed = rx_stats.rx_buf_failed;
+ vsi->rx_page_failed = rx_stats.rx_page_failed;
+
net_stats = &vsi->net_stats;
stats_prev = &vsi->net_stats_prev;
@@ -6938,18 +6947,16 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
* let's skip this round.
*/
if (likely(pf->stat_prev_loaded)) {
- net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets;
- net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes;
- net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets;
- net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes;
+ net_stats->tx_packets += tx_stats.pkts - stats_prev->tx_packets;
+ net_stats->tx_bytes += tx_stats.bytes - stats_prev->tx_bytes;
+ net_stats->rx_packets += rx_stats.pkts - stats_prev->rx_packets;
+ net_stats->rx_bytes += rx_stats.bytes - stats_prev->rx_bytes;
}
- stats_prev->tx_packets = vsi_stats->tx_packets;
- stats_prev->tx_bytes = vsi_stats->tx_bytes;
- stats_prev->rx_packets = vsi_stats->rx_packets;
- stats_prev->rx_bytes = vsi_stats->rx_bytes;
-
- kfree(vsi_stats);
+ stats_prev->tx_packets = tx_stats.pkts;
+ stats_prev->tx_bytes = tx_stats.bytes;
+ stats_prev->rx_packets = rx_stats.pkts;
+ stats_prev->rx_bytes = rx_stats.bytes;
}
/**
@@ -6983,7 +6990,6 @@ void ice_update_vsi_stats(struct ice_vsi *vsi)
cur_ns->rx_errors = pf->stats.crc_errors +
pf->stats.illegal_bytes +
pf->stats.rx_undersize +
- pf->hw_csum_rx_error +
pf->stats.rx_jabber +
pf->stats.rx_fragments +
pf->stats.rx_oversize;
@@ -7803,12 +7809,15 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ice_health_clear(pf);
- ice_plug_aux_dev(pf);
+ ice_rdma_finalize_setup(pf);
if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
ice_lag_rebuild(pf);
/* Restore timestamp mode settings after VSI rebuild */
ice_ptp_restore_timestamp_mode(pf);
+
+ /* Start PTP periodic work after VSI is fully rebuilt */
+ ice_ptp_queue_work(pf);
return;
err_vsi_rebuild:
@@ -7989,6 +7998,34 @@ int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed)
}
/**
+ * ice_get_rss - Get RSS LUT and/or key
+ * @vsi: Pointer to VSI structure
+ * @seed: Buffer to store the key in
+ * @lut: Buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
+ *
+ * Return: 0 on success, negative on failure
+ */
+int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
+{
+ int err;
+
+ if (seed) {
+ err = ice_get_rss_key(vsi, seed);
+ if (err)
+ return err;
+ }
+
+ if (lut) {
+ err = ice_get_rss_lut(vsi, lut, lut_size);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
* ice_set_rss_hfunc - Set RSS HASH function
* @vsi: Pointer to VSI structure
* @hfunc: hash function (ICE_AQ_VSI_Q_OPT_RSS_*)
@@ -8009,7 +8046,7 @@ int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc)
hfunc != ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ)
return -EOPNOTSUPP;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -8019,7 +8056,7 @@ int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc)
ctx->info.q_opt_rss |=
FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hfunc);
ctx->info.q_opt_tc = vsi->info.q_opt_tc;
- ctx->info.q_opt_flags = vsi->info.q_opt_rss;
+ ctx->info.q_opt_flags = vsi->info.q_opt_flags;
err = ice_update_vsi(hw, vsi->idx, ctx, NULL);
if (err) {
@@ -8081,7 +8118,7 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode)
vsi_props = &vsi->info;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -9055,7 +9092,7 @@ static int ice_create_q_channels(struct ice_vsi *vsi)
if (!(vsi->all_enatc & BIT(i)))
continue;
- ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ ch = kzalloc_obj(*ch);
if (!ch) {
ret = -ENOMEM;
goto err_free;
@@ -9486,7 +9523,7 @@ ice_indr_setup_tc_block(struct net_device *netdev, struct Qdisc *sch,
if (indr_priv)
return -EEXIST;
- indr_priv = kzalloc(sizeof(*indr_priv), GFP_KERNEL);
+ indr_priv = kzalloc_obj(*indr_priv);
if (!indr_priv)
return -ENOMEM;
@@ -9615,7 +9652,7 @@ int ice_open_internal(struct net_device *netdev)
}
}
- err = ice_configure_phy(vsi);
+ err = ice_phy_cfg(vsi, true);
if (err) {
netdev_err(netdev, "Failed to set physical link up, error %d\n",
err);
@@ -9631,9 +9668,6 @@ int ice_open_internal(struct net_device *netdev)
netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n",
vsi->vsi_num, vsi->vsw->sw_id);
- /* Update existing tunnels information */
- udp_tunnel_get_rx_info(netdev);
-
return err;
}
@@ -9659,7 +9693,7 @@ int ice_stop(struct net_device *netdev)
}
if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) {
- int link_err = ice_force_phys_link_state(vsi, false);
+ int link_err = ice_phy_cfg(vsi, false);
if (link_err) {
if (link_err == -ENOMEDIUM)
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
index 7e187a804dfa..21f3b615dbbf 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -53,17 +53,27 @@ int ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
* @length: (in) number of bytes to read; (out) number of bytes actually read
* @data: buffer to return data in (sized to fit the specified length)
* @read_shadow_ram: if true, read from shadow RAM instead of NVM
+ * @read_aq_err: if non-NULL, receives the AQ error status of the failing read
*
* Reads a portion of the NVM, as a flat memory space. This function correctly
* breaks read requests across Shadow RAM sectors and ensures that no single
* read request exceeds the maximum 4KB read for a single AdminQ command.
*
+ * FW caps the read lock at a maximum of 3000ms, so a read spanning multiple
+ * 4KB sectors cannot be done under a single lock without FW reclaiming it
+ * mid-read. The NVM lock is therefore acquired and released around each AQ
+ * read, so this function must be called without the lock held.
+ *
+ * Since ice_release_nvm() issues an AQ command that overwrites
+ * hw->adminq.sq_last_status, callers that need the failing read's AQ error
+ * must use @read_aq_err rather than inspecting sq_last_status afterwards.
+ *
* Returns a status code on failure. Note that the data pointer may be
* partially updated if some reads succeed before a failure.
*/
int
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
- bool read_shadow_ram)
+ bool read_shadow_ram, enum libie_aq_err *read_aq_err)
{
u32 inlen = *length;
u32 bytes_read = 0;
@@ -92,12 +102,30 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
last_cmd = !(bytes_read + read_size < inlen);
+ status = ice_acquire_nvm(hw, ICE_RES_READ);
+ if (status) {
+ ice_debug(hw, ICE_DBG_NVM, "Failed to acquire NVM lock, err %d aq_err %s\n",
+ status, libie_aq_str(hw->adminq.sq_last_status));
+ break;
+ }
+
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT,
offset, read_size,
data + bytes_read, last_cmd,
read_shadow_ram, NULL);
- if (status)
+ if (status) {
+ /* Capture the read's AQ error before ice_release_nvm()
+ * issues its own AQ command and overwrites
+ * sq_last_status.
+ */
+ if (read_aq_err)
+ *read_aq_err = hw->adminq.sq_last_status;
+
+ ice_release_nvm(hw);
break;
+ }
+
+ ice_release_nvm(hw);
bytes_read += read_size;
offset += read_size;
@@ -177,14 +205,19 @@ int ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd)
}
/**
- * ice_read_sr_word_aq - Reads Shadow RAM via AQ
+ * ice_read_sr_word - Reads Shadow RAM word
* @hw: pointer to the HW structure
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
* @data: word read from the Shadow RAM
*
* Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm.
+ *
+ * The NVM lock is acquired and released internally by ice_read_flat_nvm()
+ * around the FW read, so this function must be called without the lock held.
+ *
+ * Return: zero on success, or a negative error code on failure.
*/
-static int ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
+int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
{
u32 bytes = sizeof(u16);
__le16 data_local;
@@ -194,7 +227,7 @@ static int ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
* Shadow RAM sector restrictions necessary when reading from the NVM.
*/
status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
- (__force u8 *)&data_local, true);
+ (__force u8 *)&data_local, true, NULL);
if (status)
return status;
@@ -330,13 +363,8 @@ ice_read_flash_module(struct ice_hw *hw, enum ice_bank_select bank, u16 module,
return -EINVAL;
}
- status = ice_acquire_nvm(hw, ICE_RES_READ);
- if (status)
- return status;
-
- status = ice_read_flat_nvm(hw, start + offset, &length, data, false);
-
- ice_release_nvm(hw);
+ status = ice_read_flat_nvm(hw, start + offset, &length, data, false,
+ NULL);
return status;
}
@@ -419,27 +447,6 @@ ice_read_netlist_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset
}
/**
- * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary
- * @hw: pointer to the HW structure
- * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
- * @data: word read from the Shadow RAM
- *
- * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq.
- */
-int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
-{
- int status;
-
- status = ice_acquire_nvm(hw, ICE_RES_READ);
- if (!status) {
- status = ice_read_sr_word_aq(hw, offset, data);
- ice_release_nvm(hw);
- }
-
- return status;
-}
-
-/**
* ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA
* @hw: pointer to hardware structure
* @module_tlv: pointer to module TLV to return
@@ -856,20 +863,18 @@ int ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *net
static int ice_discover_flash_size(struct ice_hw *hw)
{
u32 min_size = 0, max_size = ICE_AQC_NVM_MAX_OFFSET + 1;
- int status;
-
- status = ice_acquire_nvm(hw, ICE_RES_READ);
- if (status)
- return status;
+ int status = 0;
while ((max_size - min_size) > 1) {
+ enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
u32 offset = (max_size + min_size) / 2;
u32 len = 1;
u8 data;
- status = ice_read_flat_nvm(hw, offset, &len, &data, false);
+ status = ice_read_flat_nvm(hw, offset, &len, &data, false,
+ &read_aq_err);
if (status == -EIO &&
- hw->adminq.sq_last_status == LIBIE_AQ_RC_EINVAL) {
+ read_aq_err == LIBIE_AQ_RC_EINVAL) {
ice_debug(hw, ICE_DBG_NVM, "%s: New upper bound of %u bytes\n",
__func__, offset);
status = 0;
@@ -880,7 +885,7 @@ static int ice_discover_flash_size(struct ice_hw *hw)
min_size = offset;
} else {
/* an unexpected error occurred */
- goto err_read_flat_nvm;
+ return status;
}
}
@@ -888,9 +893,6 @@ static int ice_discover_flash_size(struct ice_hw *hw)
hw->flash.flash_size = max_size;
-err_read_flat_nvm:
- ice_release_nvm(hw);
-
return status;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.h b/drivers/net/ethernet/intel/ice/ice_nvm.h
index 63cdc6bdac58..e1d1a11f5ca4 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.h
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.h
@@ -19,7 +19,7 @@ int ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
bool read_shadow_ram, struct ice_sq_cd *cd);
int
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
- bool read_shadow_ram);
+ bool read_shadow_ram, enum libie_aq_err *read_aq_err);
int
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type);
diff --git a/drivers/net/ethernet/intel/ice/ice_parser.c b/drivers/net/ethernet/intel/ice/ice_parser.c
index 664beb64f557..3ede4c1a5a8a 100644
--- a/drivers/net/ethernet/intel/ice/ice_parser.c
+++ b/drivers/net/ethernet/intel/ice/ice_parser.c
@@ -1895,7 +1895,7 @@ static struct ice_xlt_kb *ice_xlt_kb_get(struct ice_hw *hw, u32 sect_type)
if (!seg)
return ERR_PTR(-EINVAL);
- kb = kzalloc(sizeof(*kb), GFP_KERNEL);
+ kb = kzalloc_obj(*kb);
if (!kb)
return ERR_PTR(-ENOMEM);
@@ -2000,7 +2000,7 @@ struct ice_parser *ice_parser_create(struct ice_hw *hw)
struct ice_parser *p;
void *err;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc_obj(*p);
if (!p)
return ERR_PTR(-ENOMEM);
@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_parser_result *rslt,
u16 proto_off = 0;
u16 off;
+ if (rslt->ptype >= ICE_FLOW_PTYPE_MAX)
+ return -EINVAL;
+
memset(prof, 0, sizeof(*prof));
set_bit(rslt->ptype, prof->ptypes);
if (blk == ICE_BLK_SW) {
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 4c8d20f2d2c0..eaec36ab6ae3 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -4,6 +4,7 @@
#include "ice.h"
#include "ice_lib.h"
#include "ice_trace.h"
+#include "ice_txclk.h"
static const char ice_pin_names[][64] = {
"SDP0",
@@ -54,11 +55,6 @@ static const struct ice_ptp_pin_desc ice_pin_desc_dpll[] = {
{ SDP3, { 3, -1 }, { 0, 0 }},
};
-static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf)
-{
- return !pf->adapter ? NULL : pf->adapter->ctrl_pf;
-}
-
static struct ice_ptp *ice_get_ctrl_ptp(struct ice_pf *pf)
{
struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);
@@ -350,7 +346,7 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
return 0;
}
- return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
+ return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time),
(in_tstamp >> 8) & mask);
}
@@ -573,6 +569,9 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
pf = ptp_port_to_pf(ptp_port);
hw = &pf->hw;
+ if (!tx->init)
+ return;
+
/* Read the Tx ready status first */
if (tx->has_ready_bitmap) {
err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready);
@@ -674,14 +673,9 @@ skip_ts_read:
pf->ptp.tx_hwtstamp_good += tstamp_good;
}
-/**
- * ice_ptp_tx_tstamp_owner - Process Tx timestamps for all ports on the device
- * @pf: Board private structure
- */
-static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
+static void ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
{
struct ice_ptp_port *port;
- unsigned int i;
mutex_lock(&pf->adapter->ports.lock);
list_for_each_entry(port, &pf->adapter->ports.ports, list_node) {
@@ -693,49 +687,6 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
ice_ptp_process_tx_tstamp(tx);
}
mutex_unlock(&pf->adapter->ports.lock);
-
- for (i = 0; i < ICE_GET_QUAD_NUM(pf->hw.ptp.num_lports); i++) {
- u64 tstamp_ready;
- int err;
-
- /* Read the Tx ready status first */
- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (err)
- break;
- else if (tstamp_ready)
- return ICE_TX_TSTAMP_WORK_PENDING;
- }
-
- return ICE_TX_TSTAMP_WORK_DONE;
-}
-
-/**
- * ice_ptp_tx_tstamp - Process Tx timestamps for this function.
- * @tx: Tx tracking structure to initialize
- *
- * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding incomplete
- * Tx timestamps, or ICE_TX_TSTAMP_WORK_DONE otherwise.
- */
-static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
-{
- bool more_timestamps;
- unsigned long flags;
-
- if (!tx->init)
- return ICE_TX_TSTAMP_WORK_DONE;
-
- /* Process the Tx timestamp tracker */
- ice_ptp_process_tx_tstamp(tx);
-
- /* Check if there are outstanding Tx timestamps */
- spin_lock_irqsave(&tx->lock, flags);
- more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len);
- spin_unlock_irqrestore(&tx->lock, flags);
-
- if (more_timestamps)
- return ICE_TX_TSTAMP_WORK_PENDING;
-
- return ICE_TX_TSTAMP_WORK_DONE;
}
/**
@@ -751,7 +702,7 @@ ice_ptp_alloc_tx_tracker(struct ice_ptp_tx *tx)
unsigned long *in_use, *stale;
struct ice_tx_tstamp *tstamps;
- tstamps = kcalloc(tx->len, sizeof(*tstamps), GFP_KERNEL);
+ tstamps = kzalloc_objs(*tstamps, tx->len);
in_use = bitmap_zalloc(tx->len, GFP_KERNEL);
stale = bitmap_zalloc(tx->len, GFP_KERNEL);
@@ -1341,15 +1292,55 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
if (pf->hw.reset_ongoing)
return;
+ if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
+ test_bit(ICE_FLAG_DPLL, pf->flags)) {
+ int pin, err;
+
+ mutex_lock(&pf->dplls.lock);
+ for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) {
+ enum ice_synce_clk clk_pin;
+ bool active;
+ u8 port_num;
+
+ port_num = ptp_port->port_num;
+ clk_pin = (enum ice_synce_clk)pin;
+ err = ice_tspll_bypass_mux_active_e825c(hw,
+ port_num,
+ &active,
+ clk_pin);
+ if (err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to read SyncE bypass mux for pin %d, err %d\n",
+ pin, err);
+ break;
+ }
+
+ err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin);
+ if (active && err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to configure SyncE ETH divider for pin %d, err %d\n",
+ pin, err);
+ break;
+ }
+ }
+ mutex_unlock(&pf->dplls.lock);
+
+ if (linkup)
+ ice_txclk_update_and_notify(pf);
+ }
+
switch (hw->mac_type) {
case ICE_MAC_E810:
case ICE_MAC_E830:
/* Do not reconfigure E810 or E830 PHY */
return;
case ICE_MAC_GENERIC:
- case ICE_MAC_GENERIC_3K_E825:
ice_ptp_port_phy_restart(ptp_port);
return;
+ case ICE_MAC_GENERIC_3K_E825:
+ if (linkup)
+ ice_ptp_port_phy_restart(ptp_port);
+ return;
default:
dev_warn(ice_pf_to_dev(pf), "%s: Unknown PHY type\n", __func__);
}
@@ -2073,11 +2064,13 @@ static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e830 = {
/**
* struct ice_crosststamp_ctx - Device cross timestamp context
* @snapshot: snapshot of system clocks for historic interpolation
+ * @snapshot_clock_id: System clock ID for @snapshot
* @pf: pointer to the PF private structure
* @cfg: pointer to hardware configuration for cross timestamp
*/
struct ice_crosststamp_ctx {
struct system_time_snapshot snapshot;
+ clockid_t snapshot_clock_id;
struct ice_pf *pf;
const struct ice_crosststamp_cfg *cfg;
};
@@ -2123,7 +2116,7 @@ static int ice_capture_crosststamp(ktime_t *device,
}
/* Snapshot system time for historic interpolation */
- ktime_get_snapshot(&ctx->snapshot);
+ ktime_get_snapshot_id(ctx->snapshot_clock_id, &ctx->snapshot);
/* Program cmd to master timer */
ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
@@ -2184,6 +2177,7 @@ static int ice_ptp_getcrosststamp(struct ptp_clock_info *info,
{
struct ice_pf *pf = ptp_info_to_pf(info);
struct ice_crosststamp_ctx ctx = {
+ .snapshot_clock_id = cts->clock_id,
.pf = pf,
};
@@ -2663,30 +2657,95 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
return idx + tx->offset;
}
-/**
- * ice_ptp_process_ts - Process the PTP Tx timestamps
- * @pf: Board private structure
- *
- * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding Tx
- * timestamps that need processing, and ICE_TX_TSTAMP_WORK_DONE otherwise.
- */
-enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf)
+void ice_ptp_process_ts(struct ice_pf *pf)
{
switch (pf->ptp.tx_interrupt_mode) {
case ICE_PTP_TX_INTERRUPT_NONE:
/* This device has the clock owner handle timestamps for it */
- return ICE_TX_TSTAMP_WORK_DONE;
+ return;
case ICE_PTP_TX_INTERRUPT_SELF:
/* This device handles its own timestamps */
- return ice_ptp_tx_tstamp(&pf->ptp.port.tx);
+ ice_ptp_process_tx_tstamp(&pf->ptp.port.tx);
+ return;
case ICE_PTP_TX_INTERRUPT_ALL:
/* This device handles timestamps for all ports */
- return ice_ptp_tx_tstamp_owner(pf);
+ ice_ptp_tx_tstamp_owner(pf);
+ return;
+ default:
+ WARN_ONCE(1, "Unexpected Tx timestamp interrupt mode %u\n",
+ pf->ptp.tx_interrupt_mode);
+ return;
+ }
+}
+
+static bool ice_port_has_timestamps(struct ice_ptp_tx *tx)
+{
+ bool more_timestamps;
+
+ scoped_guard(spinlock_irqsave, &tx->lock) {
+ if (!tx->init)
+ return false;
+
+ more_timestamps = !bitmap_empty(tx->in_use, tx->len);
+ }
+
+ return more_timestamps;
+}
+
+static bool ice_any_port_has_timestamps(struct ice_pf *pf)
+{
+ struct ice_ptp_port *port;
+
+ scoped_guard(mutex, &pf->adapter->ports.lock) {
+ list_for_each_entry(port, &pf->adapter->ports.ports,
+ list_node) {
+ struct ice_ptp_tx *tx = &port->tx;
+
+ if (ice_port_has_timestamps(tx))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ int ret;
+
+ /* Check software indicator */
+ switch (pf->ptp.tx_interrupt_mode) {
+ case ICE_PTP_TX_INTERRUPT_NONE:
+ return false;
+ case ICE_PTP_TX_INTERRUPT_SELF:
+ if (ice_port_has_timestamps(&pf->ptp.port.tx))
+ return true;
+ break;
+ case ICE_PTP_TX_INTERRUPT_ALL:
+ if (ice_any_port_has_timestamps(pf))
+ return true;
+ break;
default:
WARN_ONCE(1, "Unexpected Tx timestamp interrupt mode %u\n",
pf->ptp.tx_interrupt_mode);
- return ICE_TX_TSTAMP_WORK_DONE;
+ break;
}
+
+ /* Check hardware indicator */
+ ret = ice_check_phy_tx_tstamp_ready(hw);
+ if (ret < 0) {
+ dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n",
+ ret);
+ /* Stop triggering IRQs if we're unable to read PHY */
+ return false;
+ }
+
+ /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps
+ * available, 0 if there are no waiting timestamps, and a negative
+ * value if there was an error (which we checked for above).
+ */
+ return ret > 0;
}
/**
@@ -2738,7 +2797,9 @@ irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf)
return IRQ_WAKE_THREAD;
case ICE_MAC_E830:
/* E830 can read timestamps in the top half using rd32() */
- if (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) {
+ ice_ptp_process_ts(pf);
+
+ if (ice_ptp_tx_tstamps_pending(pf)) {
/* Process outstanding Tx timestamps. If there
* is more work, re-arm the interrupt to trigger again.
*/
@@ -2768,8 +2829,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
- bool trigger_oicr = false;
- unsigned int i;
+ int ret;
if (!pf->ptp.port.tx.has_ready_bitmap)
return;
@@ -2777,21 +2837,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
if (!ice_pf_src_tmr_owned(pf))
return;
- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
- u64 tstamp_ready;
- int err;
-
- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (!err && tstamp_ready) {
- trigger_oicr = true;
- break;
- }
- }
-
- if (trigger_oicr) {
- /* Trigger a software interrupt, to ensure this data
- * gets processed.
- */
+ ret = ice_check_phy_tx_tstamp_ready(hw);
+ if (ret < 0) {
+ dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n",
+ ret);
+ } else if (ret) {
dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n");
wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
@@ -2818,6 +2868,20 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
}
/**
+ * ice_ptp_queue_work - Queue PTP periodic work for a PF
+ * @pf: Board private structure
+ *
+ * Helper function to queue PTP periodic work after VSI rebuild completes.
+ * This ensures that PTP work only runs when VSI structures are ready.
+ */
+void ice_ptp_queue_work(struct ice_pf *pf)
+{
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags) &&
+ pf->ptp.state == ICE_PTP_READY)
+ kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work, 0);
+}
+
+/**
* ice_ptp_prepare_rebuild_sec - Prepare second NAC for PTP reset or rebuild
* @pf: Board private structure
* @rebuild: rebuild if true, prepare if false
@@ -2835,10 +2899,15 @@ static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
struct ice_pf *peer_pf = ptp_port_to_pf(port);
if (!ice_is_primary(&peer_pf->hw)) {
- if (rebuild)
+ if (rebuild) {
+ /* TODO: When implementing rebuild=true:
+ * 1. Ensure secondary PFs' VSIs are rebuilt
+ * 2. Call ice_ptp_queue_work(peer_pf) after VSI rebuild
+ */
ice_ptp_rebuild(peer_pf, reset_type);
- else
+ } else {
ice_ptp_prepare_for_reset(peer_pf, reset_type);
+ }
}
}
}
@@ -2968,6 +3037,11 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
struct ice_ptp *ptp = &pf->ptp;
int err;
+ if (ptp->state == ICE_PTP_UNINIT) {
+ dev_dbg(ice_pf_to_dev(pf), "PTP was not initialized, skipping rebuild\n");
+ return;
+ }
+
if (ptp->state == ICE_PTP_READY) {
ice_ptp_prepare_for_reset(pf, reset_type);
} else if (ptp->state != ICE_PTP_RESETTING) {
@@ -2984,9 +3058,6 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ptp->state = ICE_PTP_READY;
- /* Start periodic work going */
- kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
-
dev_info(ice_pf_to_dev(pf), "PTP reset successful\n");
return;
@@ -2995,14 +3066,9 @@ err:
dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err);
}
-static int ice_ptp_setup_adapter(struct ice_pf *pf)
+static void ice_ptp_setup_adapter(struct ice_pf *pf)
{
- if (!ice_pf_src_tmr_owned(pf) || !ice_is_primary(&pf->hw))
- return -EPERM;
-
pf->adapter->ctrl_pf = pf;
-
- return 0;
}
static int ice_ptp_setup_pf(struct ice_pf *pf)
@@ -3010,7 +3076,13 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf);
struct ice_ptp *ptp = &pf->ptp;
- if (WARN_ON(!ctrl_ptp) || pf->hw.mac_type == ICE_MAC_UNKNOWN)
+ if (!ctrl_ptp) {
+ dev_info(ice_pf_to_dev(pf),
+ "PTP unavailable: no controlling PF\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pf->hw.mac_type == ICE_MAC_UNKNOWN)
return -ENODEV;
INIT_LIST_HEAD(&ptp->port.list_node);
@@ -3020,6 +3092,21 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
&pf->adapter->ports.ports);
mutex_unlock(&pf->adapter->ports.lock);
+ /* Seed the per-PHY Tx reference clock usage map for this port.
+ * Only meaningful on E825 (other MAC types don't expose tx-clk
+ * selection). No locking is needed because this runs during
+ * ice_ptp_init() before pf->dplls.lock exists and before any
+ * link event or DPLL callback can observe the map.
+ */
+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ u8 port_num, phy;
+
+ port_num = ptp->port.port_num;
+ phy = port_num / pf->hw.ptp.ports_per_phy;
+ set_bit(port_num,
+ &ctrl_ptp->tx_refclks[phy][pf->ptp.port.tx_clk]);
+ }
+
return 0;
}
@@ -3191,8 +3278,9 @@ static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf)
{
switch (pf->hw.mac_type) {
case ICE_MAC_GENERIC:
- /* E822 based PHY has the clock owner process the interrupt
- * for all ports.
+ case ICE_MAC_GENERIC_3K_E825:
+ /* E82x hardware has the clock owner process timestamps for
+ * all ports.
*/
if (ice_pf_src_tmr_owned(pf))
pf->ptp.tx_interrupt_mode = ICE_PTP_TX_INTERRUPT_ALL;
@@ -3238,15 +3326,27 @@ void ice_ptp_init(struct ice_pf *pf)
/* If this function owns the clock hardware, it must allocate and
* configure the PTP clock device to represent it.
*/
- if (ice_pf_src_tmr_owned(pf) && ice_is_primary(hw)) {
- err = ice_ptp_setup_adapter(pf);
- if (err)
- goto err_exit;
+ if (ice_pf_src_tmr_owned(pf)) {
+ ice_ptp_setup_adapter(pf);
+
err = ice_ptp_init_owner(pf);
if (err)
goto err_exit;
}
+ ptp->port.tx_clk = ICE_REF_CLK_ENET;
+ ptp->port.tx_clk_req = ICE_REF_CLK_ENET;
+ if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) {
+ enum ice_e825c_ref_clk tx_ref_clk;
+
+ err = ice_get_serdes_ref_sel_e825c(hw, ptp->port.port_num,
+ &tx_ref_clk);
+ if (!err) {
+ ptp->port.tx_clk = tx_ref_clk;
+ ptp->port.tx_clk_req = tx_ref_clk;
+ }
+ }
+
err = ice_ptp_setup_pf(pf);
if (err)
goto err_exit;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h
index 27016aac4f1e..c4b0da7ce20e 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h
@@ -144,6 +144,8 @@ struct ice_ptp_tx {
* @link_up: indicates whether the link is up
* @tx_fifo_busy_cnt: number of times the Tx FIFO was busy
* @port_num: the port number this structure represents
+ * @tx_clk: currently active Tx reference clock source
+ * @tx_clk_req: requested Tx reference clock source (new target)
*/
struct ice_ptp_port {
struct list_head list_node;
@@ -153,6 +155,8 @@ struct ice_ptp_port {
bool link_up;
u8 tx_fifo_busy_cnt;
u8 port_num;
+ enum ice_e825c_ref_clk tx_clk;
+ enum ice_e825c_ref_clk tx_clk_req;
};
enum ice_ptp_tx_interrupt {
@@ -236,6 +240,7 @@ struct ice_ptp_pin_desc {
* @info: structure defining PTP hardware capabilities
* @clock: pointer to registered PTP clock device
* @tstamp_config: hardware timestamping configuration
+ * @tx_refclks: bitmaps table to store the information about TX reference clocks
* @reset_time: kernel time after clock stop on reset
* @tx_hwtstamp_good: number of completed Tx timestamp requests
* @tx_hwtstamp_skipped: number of Tx time stamp requests skipped
@@ -261,6 +266,7 @@ struct ice_ptp {
struct ptp_clock_info info;
struct ptp_clock *clock;
struct kernel_hwtstamp_config tstamp_config;
+ unsigned long tx_refclks[ICE_E825_MAX_PHYS][ICE_REF_CLK_MAX];
u64 reset_time;
u64 tx_hwtstamp_good;
u32 tx_hwtstamp_skipped;
@@ -304,8 +310,9 @@ void ice_ptp_extts_event(struct ice_pf *pf);
s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb);
void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx);
void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx);
-enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf);
+void ice_ptp_process_ts(struct ice_pf *pf);
irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf);
+bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf);
u64 ice_ptp_read_src_clk_reg(struct ice_pf *pf,
struct ptp_system_timestamp *sts);
@@ -317,6 +324,7 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf,
void ice_ptp_init(struct ice_pf *pf);
void ice_ptp_release(struct ice_pf *pf);
void ice_ptp_link_change(struct ice_pf *pf, bool linkup);
+void ice_ptp_queue_work(struct ice_pf *pf);
#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
static inline int ice_ptp_hwtstamp_get(struct net_device *netdev,
@@ -345,16 +353,18 @@ static inline void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
static inline void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) { }
-static inline bool ice_ptp_process_ts(struct ice_pf *pf)
-{
- return true;
-}
+static inline void ice_ptp_process_ts(struct ice_pf *pf) { }
static inline irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf)
{
return IRQ_HANDLED;
}
+static inline bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
+{
+ return false;
+}
+
static inline u64 ice_ptp_read_src_clk_reg(struct ice_pf *pf,
struct ptp_system_timestamp *sts)
{
@@ -383,6 +393,10 @@ static inline void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
{
}
+static inline void ice_ptp_queue_work(struct ice_pf *pf)
+{
+}
+
static inline int ice_ptp_clock_index(struct ice_pf *pf)
{
return -1;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
index 19dddd9b53dd..4d298c27bfb2 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
@@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.blktime = 0x666, /* 3.2 */
.tx_offset = {
.serdes = 0x234c, /* 17.6484848 */
- .no_fec = 0x8e80, /* 71.25 */
+ .no_fec = 0x93d9, /* 73 */
.fc = 0xb4a4, /* 90.32 */
.sfd = 0x4a4, /* 2.32 */
.onestep = 0x4ccd /* 38.4 */
},
.rx_offset = {
.serdes = 0xffffeb27, /* -10.42424 */
- .no_fec = 0xffffcccd, /* -25.6 */
+ .no_fec = 0xffffc7b6, /* -28 */
.fc = 0xfffc557b, /* -469.26 */
.sfd = 0x4a4, /* 2.32 */
.bs_ds = 0x32 /* 0.0969697 */
@@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = {
.mktime = 0x147b, /* 10.24, only if RS-FEC enabled */
.tx_offset = {
.serdes = 0xe1e, /* 7.0593939 */
- .no_fec = 0x3857, /* 28.17 */
+ .no_fec = 0x4266, /* 33 */
.fc = 0x48c3, /* 36.38 */
- .rs = 0x8100, /* 64.5 */
+ .rs = 0x8a00, /* 69 */
.sfd = 0x1dc, /* 0.93 */
.onestep = 0x1eb8 /* 15.36 */
},
.rx_offset = {
.serdes = 0xfffff7a9, /* -4.1697 */
- .no_fec = 0xffffe71a, /* -12.45 */
+ .no_fec = 0xffffe700, /* -12 */
.fc = 0xfffe894d, /* -187.35 */
- .rs = 0xfffff8cd, /* -3.6 */
+ .rs = 0xfffff8cc, /* -3 */
.sfd = 0x1dc, /* 0.93 */
.bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */
}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 35680dbe4a7f..3a41c711e751 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -378,6 +378,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)
*/
/**
+ * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization
+ * @hw: pointer to HW struct
+ *
+ * Perform E825C-specific PTP hardware clock initialization steps.
+ *
+ * Return: 0 on success, or a negative error value on failure.
+ */
+static int ice_ptp_init_phc_e825c(struct ice_hw *hw)
+{
+ int err;
+
+ /* Soft reset all ports, to ensure everything is at a clean state */
+ for (int port = 0; port < hw->ptp.num_lports; port++) {
+ err = ice_ptp_phy_soft_reset_eth56g(hw, port);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n",
+ port, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
* ice_ptp_get_dest_dev_e825 - get destination PHY for given port number
* @hw: pointer to the HW struct
* @port: destination port
@@ -462,6 +487,43 @@ static int ice_read_phy_eth56g(struct ice_hw *hw, u8 port, u32 addr, u32 *val)
}
/**
+ * ice_get_serdes_ref_sel_e825c - Read current Tx ref clock source
+ * @hw: pointer to the HW struct
+ * @port: port number for which Tx reference clock is read
+ * @clk: Tx reference clock value (output)
+ *
+ * Return: 0 on success, other error codes when failed to read from PHY
+ */
+int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port,
+ enum ice_e825c_ref_clk *clk)
+{
+ u8 lane = port % hw->ptp.ports_per_phy;
+ u32 serdes_rx_nt, serdes_tx_nt;
+ u32 val;
+ int ret;
+
+ ret = ice_read_phy_eth56g(hw, port,
+ SERDES_IP_IF_LN_FLXM_GENERAL(lane, 0),
+ &val);
+ if (ret)
+ return ret;
+
+ serdes_rx_nt = FIELD_GET(CFG_ICTL_PCS_REF_SEL_RX_NT, val);
+ serdes_tx_nt = FIELD_GET(CFG_ICTL_PCS_REF_SEL_TX_NT, val);
+
+ if (serdes_tx_nt == REF_SEL_NT_SYNCE &&
+ serdes_rx_nt == REF_SEL_NT_SYNCE)
+ *clk = ICE_REF_CLK_SYNCE;
+ else if (serdes_tx_nt == REF_SEL_NT_EREF0 &&
+ serdes_rx_nt == REF_SEL_NT_EREF0)
+ *clk = ICE_REF_CLK_EREF0;
+ else
+ *clk = ICE_REF_CLK_ENET;
+
+ return 0;
+}
+
+/**
* ice_phy_res_address_eth56g - Calculate a PHY port register address
* @hw: pointer to the HW struct
* @lane: Lane number to be written
@@ -1847,6 +1909,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port)
* @ena: enable or disable interrupt
* @threshold: interrupt threshold
*
+ * The threshold cannot be 0 while the interrupt is enabled.
+ *
* Configure TX timestamp interrupt for the specified port
*
* Return:
@@ -1858,19 +1922,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)
int err;
u32 val;
+ if (ena && !threshold)
+ return -EINVAL;
+
err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
if (err)
return err;
+ val &= ~PHY_TS_INT_CONFIG_ENA_M;
if (ena) {
- val |= PHY_TS_INT_CONFIG_ENA_M;
val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M;
val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold);
- } else {
- val &= ~PHY_TS_INT_CONFIG_ENA_M;
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG,
+ val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
+ }
+ val |= PHY_TS_INT_CONFIG_ENA_M;
}
- return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
+ }
+
+ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP,
+ "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n",
+ port, !!ena, threshold);
+ return err;
+ }
+
+ return 0;
}
/**
@@ -2088,16 +2178,23 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
}
incval = (u64)hi << 32 | lo;
+ if (!ice_ptp_lock(hw)) {
+ dev_err(ice_hw_to_dev(hw), "Failed to acquire PTP semaphore\n");
+ return -EBUSY;
+ }
+
err = ice_write_40b_ptp_reg_eth56g(hw, port, PHY_REG_TIMETUS_L, incval);
if (err)
- return err;
+ goto err_ptp_unlock;
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_INIT_INCVAL);
if (err)
- return err;
+ goto err_ptp_unlock;
ice_ptp_exec_tmr_cmd(hw);
+ ice_ptp_unlock(hw);
+
err = ice_sync_phy_timer_eth56g(hw, port);
if (err)
return err;
@@ -2113,6 +2210,39 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
return 0;
+
+err_ptp_unlock:
+ ice_ptp_unlock(hw);
+ return err;
+}
+
+/**
+ * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports
+ * @hw: pointer to the HW struct
+ *
+ * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates
+ * a waiting timestamp.
+ *
+ * Return: 1 if any port has at least one timestamp ready bit set,
+ * 0 otherwise, and a negative error code if unable to read the bitmap.
+ */
+static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw)
+{
+ int port;
+
+ for (port = 0; port < hw->ptp.num_lports; port++) {
+ u64 tstamp_ready;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready);
+ if (err)
+ return err;
+
+ if (tstamp_ready)
+ return 1;
+ }
+
+ return 0;
}
/**
@@ -2137,13 +2267,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
*ts_status = 0;
for (phy = 0; phy < params->num_phys; phy++) {
+ u8 port;
int err;
- err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status);
+ /* ice_read_phy_eth56g expects a port index, so use the first
+ * port of the PHY
+ */
+ port = phy * hw->ptp.ports_per_phy;
+
+ err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status);
if (err)
return err;
- *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy);
+ *ts_status |= (status & mask) << port;
}
ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status);
@@ -2152,6 +2288,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
}
/**
+ * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G
+ * @hw: pointer to the HW structure
+ * @port: PHY port number
+ *
+ * Trigger a soft reset of the ETH56G PHY by toggling the soft reset
+ * bit in the PHY global register. The reset sequence consists of:
+ * 1. Clearing the soft reset bit
+ * 2. Asserting the soft reset bit
+ * 3. Clearing the soft reset bit again
+ *
+ * Short delays are inserted between each step to allow the hardware
+ * to settle. This provides a controlled way to reinitialize the PHY
+ * without requiring a full device reset.
+ *
+ * Return: 0 on success, or a negative error code on failure when
+ * reading or writing the PHY register.
+ */
+int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port)
+{
+ u32 global_val;
+ int err;
+
+ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+
+ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+
+ usleep_range(5000, 6000);
+
+ global_val |= PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+ }
+ usleep_range(5000, 6000);
+
+ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M;
+ ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n",
+ port, global_val);
+ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val);
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n",
+ port, err);
+ return err;
+}
+
+/**
* ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register
* @hw: pointer to the HW struct
* @port: the PHY port to read from
@@ -4203,6 +4402,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
}
/**
+ * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads
+ * @hw: pointer to the HW struct
+ *
+ * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates
+ * a waiting timestamp.
+ *
+ * Return: 1 if any quad has at least one timestamp ready bit set,
+ * 0 otherwise, and a negative error value if unable to read the bitmap.
+ */
+static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw)
+{
+ int quad;
+
+ for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) {
+ u64 tstamp_ready;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready);
+ if (err)
+ return err;
+
+ if (tstamp_ready)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
* ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt
* @hw: pointer to the HW struct
* @quad: the timestamp quad
@@ -4323,18 +4551,17 @@ static int
ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
{
struct ice_e810_params *params = &hw->ptp.phy.e810;
- unsigned long flags;
u32 val;
int err;
- spin_lock_irqsave(&params->atqbal_wq.lock, flags);
+ spin_lock_irq(&params->atqbal_wq.lock);
/* Wait for any pending in-progress low latency interrupt */
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
!(params->atqbal_flags &
ATQBAL_FLAGS_INTR_IN_PROGRESS));
if (err) {
- spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
+ spin_unlock_irq(&params->atqbal_wq.lock);
return err;
}
@@ -4349,7 +4576,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
REG_LL_PROXY_H);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
- spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
+ spin_unlock_irq(&params->atqbal_wq.lock);
return err;
}
@@ -4359,7 +4586,7 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
/* Read the low 32 bit value and set the TS valid bit */
*lo = rd32(hw, REG_LL_PROXY_L) | TS_VALID;
- spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
+ spin_unlock_irq(&params->atqbal_wq.lock);
return 0;
}
@@ -4581,15 +4808,12 @@ static int ice_ptp_prep_phy_adj_ll_e810(struct ice_hw *hw, s32 adj)
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
REG_LL_PROXY_H);
- if (err) {
- ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
- spin_unlock_irq(&params->atqbal_wq.lock);
- return err;
- }
-
spin_unlock_irq(&params->atqbal_wq.lock);
- return 0;
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
+
+ return err;
}
/**
@@ -4610,8 +4834,12 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
u8 tmr_idx;
int err;
- if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
- return ice_ptp_prep_phy_adj_ll_e810(hw, adj);
+ if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update) {
+ err = ice_ptp_prep_phy_adj_ll_e810(hw, adj);
+ if (err != -ETIMEDOUT)
+ return err;
+ ice_debug(hw, ICE_DBG_PTP, "LL adj timed out, falling back to SBQ\n");
+ }
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
@@ -4674,15 +4902,12 @@ static int ice_ptp_prep_phy_incval_ll_e810(struct ice_hw *hw, u64 incval)
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
REG_LL_PROXY_H);
- if (err) {
- ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
- spin_unlock_irq(&params->atqbal_wq.lock);
- return err;
- }
-
spin_unlock_irq(&params->atqbal_wq.lock);
- return 0;
+ if (err)
+ ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
+
+ return err;
}
/**
@@ -4700,8 +4925,12 @@ static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
u8 tmr_idx;
int err;
- if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
- return ice_ptp_prep_phy_incval_ll_e810(hw, incval);
+ if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update) {
+ err = ice_ptp_prep_phy_incval_ll_e810(hw, incval);
+ if (err != -ETIMEDOUT)
+ return err;
+ ice_debug(hw, ICE_DBG_PTP, "LL incval timed out, falling back to SBQ\n");
+ }
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
low = lower_32_bits(incval);
@@ -4755,6 +4984,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
return 0;
}
+/**
+ * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register
+ * @hw: pointer to the HW struct
+ *
+ * The E810 devices do not have a Tx memory status register. Note this is
+ * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810
+ * which always says that all bits are ready. This function is called in cases
+ * where code will trigger interrupts if timestamps are waiting, and should
+ * not be called for E810 hardware.
+ *
+ * Return: 0.
+ */
+static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw)
+{
+ return 0;
+}
+
/* E810 SMA functions
*
* The following functions operate specifically on E810 hardware and are used
@@ -5010,6 +5256,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port,
}
/**
+ * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register
+ * @hw: pointer to the HW struct
+ *
+ * Return: 1 if the device has waiting timestamps, 0 otherwise.
+ */
+static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw)
+{
+ u64 tstamp_ready;
+
+ ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready);
+
+ return !!tstamp_ready;
+}
+
+/**
* ice_ptp_init_phy_e830 - initialize PHY parameters
* @ptp: pointer to the PTP HW struct
*/
@@ -5042,9 +5303,13 @@ static void ice_ptp_init_phy_e830(struct ice_ptp_hw *ptp)
*/
bool ice_ptp_lock(struct ice_hw *hw)
{
+ struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
u32 hw_lock;
int i;
+ if (!ice_is_primary(hw))
+ hw = ice_get_primary_hw(pf);
+
#define MAX_TRIES 15
for (i = 0; i < MAX_TRIES; i++) {
@@ -5071,6 +5336,11 @@ bool ice_ptp_lock(struct ice_hw *hw)
*/
void ice_ptp_unlock(struct ice_hw *hw)
{
+ struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
+
+ if (!ice_is_primary(hw))
+ hw = ice_get_primary_hw(pf);
+
wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
}
@@ -5381,8 +5651,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
*/
int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
{
+ int err = 0;
u8 tmr_idx;
- int err;
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
@@ -5399,8 +5669,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
err = ice_ptp_prep_phy_adj_e810(hw, adj);
break;
case ICE_MAC_E830:
- /* E830 sync PHYs automatically after setting GLTSYN_SHADJ */
- return 0;
+ /* E830 sync PHYs automatically after setting cmd register */
+ break;
case ICE_MAC_GENERIC:
err = ice_ptp_prep_phy_adj_e82x(hw, adj);
break;
@@ -5564,7 +5834,7 @@ int ice_ptp_init_phc(struct ice_hw *hw)
case ICE_MAC_GENERIC:
return ice_ptp_init_phc_e82x(hw);
case ICE_MAC_GENERIC_3K_E825:
- return 0;
+ return ice_ptp_init_phc_e825c(hw);
default:
return -EOPNOTSUPP;
}
@@ -5602,6 +5872,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
}
/**
+ * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status
+ * @hw: pointer to the HW struct
+ *
+ * Check the PHY for Tx timestamp memory status on all ports. If you need to
+ * see individual timestamp status for each index, use
+ * ice_get_phy_tx_tstamp_ready() instead.
+ *
+ * Return: 1 if any port has timestamps available, 0 if there are no timestamps
+ * available, and a negative error code on failure.
+ */
+int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw)
+{
+ switch (hw->mac_type) {
+ case ICE_MAC_E810:
+ return ice_check_phy_tx_tstamp_ready_e810(hw);
+ case ICE_MAC_E830:
+ return ice_check_phy_tx_tstamp_ready_e830(hw);
+ case ICE_MAC_GENERIC:
+ return ice_check_phy_tx_tstamp_ready_e82x(hw);
+ case ICE_MAC_GENERIC_3K_E825:
+ return ice_check_phy_tx_tstamp_ready_eth56g(hw);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/**
* ice_cgu_get_pin_desc_e823 - get pin description array
* @hw: pointer to the hw struct
* @input: if request is done against input or output pin
@@ -5903,7 +6200,14 @@ int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num)
*base_idx = SI_REF1P;
else
ret = -ENODEV;
-
+ break;
+ case ICE_DEV_ID_E825C_BACKPLANE:
+ case ICE_DEV_ID_E825C_QSFP:
+ case ICE_DEV_ID_E825C_SFP:
+ case ICE_DEV_ID_E825C_SGMII:
+ *pin_num = ICE_SYNCE_CLK_NUM;
+ *base_idx = 0;
+ ret = 0;
break;
default:
ret = -ENODEV;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 5896b346e579..16b1988e993d 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -258,13 +258,20 @@ enum ice_si_cgu_out_pins {
};
struct ice_cgu_pin_desc {
- char *name;
+ const char *name;
u8 index;
enum dpll_pin_type type;
u32 freq_supp_num;
struct dpll_pin_frequency *freq_supp;
};
+enum ice_e825c_ref_clk {
+ ICE_REF_CLK_ENET,
+ ICE_REF_CLK_SYNCE,
+ ICE_REF_CLK_EREF0,
+ ICE_REF_CLK_MAX,
+};
+
#define E810C_QSFP_C827_0_HANDLE 2
#define E810C_QSFP_C827_1_HANDLE 3
@@ -300,6 +307,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw);
int ice_ptp_init_phc(struct ice_hw *hw);
void ice_ptp_init_hw(struct ice_hw *hw);
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready);
+int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw);
int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
enum ice_ptp_tmr_cmd configured_cmd);
@@ -374,6 +382,9 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset);
int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port);
int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold);
int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port);
+int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port);
+int ice_get_serdes_ref_sel_e825c(struct ice_hw *hw, u8 port,
+ enum ice_e825c_ref_clk *clk);
#define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL
#define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL
@@ -676,6 +687,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)
#define ICE_P0_GNSS_PRSNT_N BIT(4)
/* ETH56G PHY register addresses */
+#define PHY_REG_GLOBAL 0x0
+#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11)
+
/* Timestamp PHY incval registers */
#define PHY_REG_TIMETUS_L 0x8
#define PHY_REG_TIMETUS_U 0xC
@@ -783,4 +797,12 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)
#define PHY_PTP_1STEP_PD_DELAY_M GENMASK(30, 1)
#define PHY_PTP_1STEP_PD_DLY_V_M BIT(31)
+#define SERDES_IP_IF_LN_FLXM_GENERAL(n, m) \
+ (0x32B800 + (m) * 0x100000 + (n) * 0x8000)
+#define CFG_ICTL_PCS_REF_SEL_RX_NT GENMASK(9, 6)
+#define CFG_ICTL_PCS_REF_SEL_TX_NT GENMASK(28, 25)
+#define REF_SEL_NT_ENET 0
+#define REF_SEL_NT_EREF0 1
+#define REF_SEL_NT_SYNCE 2
+
#endif /* _ICE_PTP_HW_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c
index cb08746556a6..096566c697f4 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.c
+++ b/drivers/net/ethernet/intel/ice/ice_repr.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice.h"
+#include "ice_lib.h"
#include "ice_eswitch.h"
#include "devlink/devlink.h"
#include "devlink/port.h"
@@ -67,7 +68,7 @@ ice_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
return;
vsi = repr->src_vsi;
- ice_update_vsi_stats(vsi);
+ ice_update_eth_stats(vsi);
eth_stats = &vsi->eth_stats;
stats->tx_packets = eth_stats->tx_unicast + eth_stats->tx_broadcast +
@@ -315,7 +316,7 @@ ice_repr_reg_netdev(struct net_device *netdev, const struct net_device_ops *ops)
static int ice_repr_ready_vf(struct ice_repr *repr)
{
- return !ice_check_vf_ready_for_cfg(repr->vf);
+ return ice_check_vf_ready_for_cfg(repr->vf);
}
static int ice_repr_ready_sf(struct ice_repr *repr)
@@ -369,7 +370,7 @@ static struct ice_repr *ice_repr_create(struct ice_vsi *src_vsi)
struct ice_repr *repr;
int err;
- repr = kzalloc(sizeof(*repr), GFP_KERNEL);
+ repr = kzalloc_obj(*repr);
if (!repr)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
index 21bb861febbf..226243d32968 100644
--- a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
@@ -54,8 +54,9 @@ enum ice_sbq_dev_id {
};
enum ice_sbq_msg_opcode {
- ice_sbq_msg_rd = 0x00,
- ice_sbq_msg_wr = 0x01
+ ice_sbq_msg_rd = 0x00,
+ ice_sbq_msg_wr = 0x01,
+ ice_sbq_msg_wr_np = 0x02
};
#define ICE_SBQ_MSG_FLAGS 0x40
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index fff0c1afdb41..ffa18d86729a 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -371,7 +371,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
devm_kfree(ice_hw_to_dev(hw), node->children);
kfree(node->name);
- xa_erase(&pi->sched_node_ids, node->id);
+ xa_erase(&hw->sched_node_ids, node->id);
devm_kfree(ice_hw_to_dev(hw), node);
}
@@ -977,7 +977,7 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
if (!new_node->name)
return -ENOMEM;
- status = xa_alloc(&pi->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX),
+ status = xa_alloc(&hw->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX),
GFP_KERNEL);
if (status) {
ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",
diff --git a/drivers/net/ethernet/intel/ice/ice_sf_eth.c b/drivers/net/ethernet/intel/ice/ice_sf_eth.c
index 1a2c94375ca7..a730aa368c92 100644
--- a/drivers/net/ethernet/intel/ice/ice_sf_eth.c
+++ b/drivers/net/ethernet/intel/ice/ice_sf_eth.c
@@ -273,7 +273,7 @@ ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
return err;
}
- sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL);
+ sf_dev = kzalloc_obj(*sf_dev);
if (!sf_dev) {
err = -ENOMEM;
NL_SET_ERR_MSG_MOD(extack, "Could not allocate SF memory");
@@ -305,6 +305,8 @@ ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
aux_dev_uninit:
auxiliary_device_uninit(&sf_dev->adev);
+ return err;
+
sf_dev_free:
kfree(sf_dev);
xa_erase:
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 6b1126ddb561..e04de0215596 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -484,12 +484,14 @@ static int ice_start_vfs(struct ice_pf *pf)
goto teardown;
}
- retval = ice_eswitch_attach_vf(pf, vf);
- if (retval) {
- dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
- vf->vf_id, retval);
- ice_vf_vsi_release(vf);
- goto teardown;
+ if (ice_is_eswitch_mode_switchdev(pf)) {
+ retval = ice_eswitch_attach_vf(pf, vf);
+ if (retval) {
+ dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
+ vf->vf_id, retval);
+ ice_vf_vsi_release(vf);
+ goto teardown;
+ }
}
set_bit(ICE_VF_STATE_INIT, vf->vf_states);
@@ -695,7 +697,7 @@ static int ice_create_vf_entries(struct ice_pf *pf, u16 num_vfs)
pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_pdev_id);
for (u16 vf_id = 0; vf_id < num_vfs; vf_id++) {
- vf = kzalloc(sizeof(*vf), GFP_KERNEL);
+ vf = kzalloc_obj(*vf);
if (!vf) {
err = -ENOMEM;
goto err_free_entries;
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 84848f0123e7..6a5875bd9c6b 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -1847,7 +1847,7 @@ ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
if (!cached_ctx)
return -ENOENT;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -2069,7 +2069,7 @@ ice_update_recipe_lkup_idx(struct ice_hw *hw,
u16 num_recps = ICE_MAX_NUM_RECIPES;
int status;
- rcp_list = kcalloc(num_recps, sizeof(*rcp_list), GFP_KERNEL);
+ rcp_list = kzalloc_objs(*rcp_list, num_recps);
if (!rcp_list)
return -ENOMEM;
@@ -2326,7 +2326,7 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
bitmap_zero(result_bm, ICE_MAX_FV_WORDS);
/* we need a buffer big enough to accommodate all the recipes */
- tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL);
+ tmp = kzalloc_objs(*tmp, ICE_MAX_NUM_RECIPES);
if (!tmp)
return -ENOMEM;
@@ -4984,10 +4984,8 @@ ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
hw->switch_info->recp_list[bit].res_idxs,
ICE_MAX_FV_WORDS);
- bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
-
/* return number of free indexes */
- return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS);
+ return (u16)bitmap_weighted_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS);
}
/**
@@ -5096,7 +5094,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
if (recp_cnt > ICE_MAX_CHAIN_RECIPE_RES)
return -E2BIG;
- buf = kcalloc(recp_cnt, sizeof(*buf), GFP_KERNEL);
+ buf = kzalloc_objs(*buf, recp_cnt);
if (!buf)
return -ENOMEM;
@@ -5324,7 +5322,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
if (!lkups_cnt)
return -EINVAL;
- lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL);
+ lkup_exts = kzalloc_obj(*lkup_exts);
if (!lkup_exts)
return -ENOMEM;
@@ -5346,7 +5344,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
}
}
- rm = kzalloc(sizeof(*rm), GFP_KERNEL);
+ rm = kzalloc_obj(*rm);
if (!rm) {
status = -ENOMEM;
goto err_free_lkup_exts;
@@ -5530,7 +5528,7 @@ ice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt,
memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off,
dummy_pkt->pkt_len - etype_off);
- profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+ profile = kzalloc_obj(*profile);
if (!profile) {
kfree(offsets);
kfree(pkt);
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
index fb9ea7f8ef44..d20357c04127 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
@@ -931,7 +931,7 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr)
return ice_pass_vf_tx_lldp(vsi, false);
lkups_cnt = ice_tc_count_lkups(flags, fltr);
- list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ list = kzalloc_objs(*list, lkups_cnt, GFP_ATOMIC);
if (!list)
return -ENOMEM;
@@ -1177,7 +1177,7 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi,
}
lkups_cnt = ice_tc_count_lkups(flags, tc_fltr);
- list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ list = kzalloc_objs(*list, lkups_cnt, GFP_ATOMIC);
if (!list)
return -ENOMEM;
@@ -2191,7 +2191,7 @@ ice_add_tc_fltr(struct net_device *netdev, struct ice_vsi *vsi,
/* by default, set output to be INVALID */
*__fltr = NULL;
- fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
+ fltr = kzalloc_obj(*fltr);
if (!fltr)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h
index 4f35ef8d6b29..7568c917cdbe 100644
--- a/drivers/net/ethernet/intel/ice/ice_trace.h
+++ b/drivers/net/ethernet/intel/ice/ice_trace.h
@@ -63,23 +63,33 @@
DECLARE_EVENT_CLASS(ice_rx_dim_template,
TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
TP_ARGS(q_vector, dim),
- TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
- __field(struct dim *, dim)
+ TP_STRUCT__entry(__field(u16, q_index)
+ __field(u8, state)
+ __field(u8, profile_ix)
+ __field(u8, tune_state)
+ __field(u8, steps_right)
+ __field(u8, steps_left)
+ __field(u8, tired)
__string(devname, q_vector->rx.rx_ring->netdev->name)),
- TP_fast_assign(__entry->q_vector = q_vector;
- __entry->dim = dim;
+ TP_fast_assign(__entry->q_index = q_vector->rx.rx_ring->q_index;
+ __entry->state = dim->state;
+ __entry->profile_ix = dim->profile_ix;
+ __entry->tune_state = dim->tune_state;
+ __entry->steps_right = dim->steps_right;
+ __entry->steps_left = dim->steps_left;
+ __entry->tired = dim->tired;
__assign_str(devname);),
TP_printk("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
__get_str(devname),
- __entry->q_vector->rx.rx_ring->q_index,
- __entry->dim->state,
- __entry->dim->profile_ix,
- __entry->dim->tune_state,
- __entry->dim->steps_right,
- __entry->dim->steps_left,
- __entry->dim->tired)
+ __entry->q_index,
+ __entry->state,
+ __entry->profile_ix,
+ __entry->tune_state,
+ __entry->steps_right,
+ __entry->steps_left,
+ __entry->tired)
);
DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
@@ -90,23 +100,33 @@ DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
DECLARE_EVENT_CLASS(ice_tx_dim_template,
TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
TP_ARGS(q_vector, dim),
- TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
- __field(struct dim *, dim)
+ TP_STRUCT__entry(__field(u16, q_index)
+ __field(u8, state)
+ __field(u8, profile_ix)
+ __field(u8, tune_state)
+ __field(u8, steps_right)
+ __field(u8, steps_left)
+ __field(u8, tired)
__string(devname, q_vector->tx.tx_ring->netdev->name)),
- TP_fast_assign(__entry->q_vector = q_vector;
- __entry->dim = dim;
+ TP_fast_assign(__entry->q_index = q_vector->tx.tx_ring->q_index;
+ __entry->state = dim->state;
+ __entry->profile_ix = dim->profile_ix;
+ __entry->tune_state = dim->tune_state;
+ __entry->steps_right = dim->steps_right;
+ __entry->steps_left = dim->steps_left;
+ __entry->tired = dim->tired;
__assign_str(devname);),
TP_printk("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
__get_str(devname),
- __entry->q_vector->tx.tx_ring->q_index,
- __entry->dim->state,
- __entry->dim->profile_ix,
- __entry->dim->tune_state,
- __entry->dim->steps_right,
- __entry->dim->steps_left,
- __entry->dim->tired)
+ __entry->q_index,
+ __entry->state,
+ __entry->profile_ix,
+ __entry->tune_state,
+ __entry->steps_right,
+ __entry->steps_left,
+ __entry->tired)
);
DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,
diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.c b/drivers/net/ethernet/intel/ice/ice_tspll.c
index 66320a4ab86f..fd4b58eb9bc0 100644
--- a/drivers/net/ethernet/intel/ice/ice_tspll.c
+++ b/drivers/net/ethernet/intel/ice/ice_tspll.c
@@ -624,3 +624,220 @@ int ice_tspll_init(struct ice_hw *hw)
return err;
}
+
+/**
+ * ice_tspll_bypass_mux_active_e825c - check if the given port is set active
+ * @hw: Pointer to the HW struct
+ * @port: Number of the port
+ * @active: Output flag showing if port is active
+ * @output: Output pin, we have two in E825C
+ *
+ * Check if given port is selected as recovered clock source for given output.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+int ice_tspll_bypass_mux_active_e825c(struct ice_hw *hw, u8 port, bool *active,
+ enum ice_synce_clk output)
+{
+ u8 active_clk;
+ u32 val;
+ int err;
+
+ switch (output) {
+ case ICE_SYNCE_CLK0:
+ err = ice_read_cgu_reg(hw, ICE_CGU_R10, &val);
+ if (err)
+ return err;
+ active_clk = FIELD_GET(ICE_CGU_R10_SYNCE_S_REF_CLK, val);
+ break;
+ case ICE_SYNCE_CLK1:
+ err = ice_read_cgu_reg(hw, ICE_CGU_R11, &val);
+ if (err)
+ return err;
+ active_clk = FIELD_GET(ICE_CGU_R11_SYNCE_S_BYP_CLK, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (active_clk == port % hw->ptp.ports_per_phy +
+ ICE_CGU_BYPASS_MUX_OFFSET_E825C)
+ *active = true;
+ else
+ *active = false;
+
+ return 0;
+}
+
+/**
+ * ice_tspll_cfg_bypass_mux_e825c - configure reference clock mux
+ * @hw: Pointer to the HW struct
+ * @ena: true to enable the reference, false if disable
+ * @port_num: Number of the port
+ * @output: Output pin, we have two in E825C
+ *
+ * Set reference clock source and output clock selection.
+ *
+ * Context: Called under pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+int ice_tspll_cfg_bypass_mux_e825c(struct ice_hw *hw, bool ena, u32 port_num,
+ enum ice_synce_clk output)
+{
+ u8 first_mux;
+ int err;
+ u32 r10;
+
+ err = ice_read_cgu_reg(hw, ICE_CGU_R10, &r10);
+ if (err)
+ return err;
+
+ if (!ena)
+ first_mux = ICE_CGU_NET_REF_CLK0;
+ else
+ first_mux = port_num + ICE_CGU_BYPASS_MUX_OFFSET_E825C;
+
+ r10 &= ~(ICE_CGU_R10_SYNCE_DCK_RST | ICE_CGU_R10_SYNCE_DCK2_RST);
+
+ switch (output) {
+ case ICE_SYNCE_CLK0:
+ r10 &= ~(ICE_CGU_R10_SYNCE_ETHCLKO_SEL |
+ ICE_CGU_R10_SYNCE_ETHDIV_LOAD |
+ ICE_CGU_R10_SYNCE_S_REF_CLK);
+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_S_REF_CLK, first_mux);
+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHCLKO_SEL,
+ ICE_CGU_REF_CLK_BYP0_DIV);
+ break;
+ case ICE_SYNCE_CLK1:
+ {
+ u32 val;
+
+ err = ice_read_cgu_reg(hw, ICE_CGU_R11, &val);
+ if (err)
+ return err;
+ val &= ~ICE_CGU_R11_SYNCE_S_BYP_CLK;
+ val |= FIELD_PREP(ICE_CGU_R11_SYNCE_S_BYP_CLK, first_mux);
+ err = ice_write_cgu_reg(hw, ICE_CGU_R11, val);
+ if (err)
+ return err;
+ r10 &= ~(ICE_CGU_R10_SYNCE_CLKODIV_LOAD |
+ ICE_CGU_R10_SYNCE_CLKO_SEL);
+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKO_SEL,
+ ICE_CGU_REF_CLK_BYP1_DIV);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ err = ice_write_cgu_reg(hw, ICE_CGU_R10, r10);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/**
+ * ice_tspll_get_div_e825c - get the divider for the given speed
+ * @link_speed: link speed of the port
+ * @divider: output value, calculated divider
+ *
+ * Get CGU divider value based on the link speed.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int ice_tspll_get_div_e825c(u16 link_speed, unsigned int *divider)
+{
+ switch (link_speed) {
+ case ICE_AQ_LINK_SPEED_100GB:
+ case ICE_AQ_LINK_SPEED_50GB:
+ case ICE_AQ_LINK_SPEED_25GB:
+ *divider = 10;
+ break;
+ case ICE_AQ_LINK_SPEED_40GB:
+ case ICE_AQ_LINK_SPEED_10GB:
+ *divider = 4;
+ break;
+ case ICE_AQ_LINK_SPEED_5GB:
+ case ICE_AQ_LINK_SPEED_2500MB:
+ case ICE_AQ_LINK_SPEED_1000MB:
+ *divider = 2;
+ break;
+ case ICE_AQ_LINK_SPEED_100MB:
+ *divider = 1;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_tspll_cfg_synce_ethdiv_e825c - set the divider on the mux
+ * @hw: Pointer to the HW struct
+ * @output: Output pin, we have two in E825C
+ *
+ * Set the correct CGU divider for RCLKA or RCLKB.
+ *
+ * Context: Called under pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+int ice_tspll_cfg_synce_ethdiv_e825c(struct ice_hw *hw,
+ enum ice_synce_clk output)
+{
+ unsigned int divider;
+ u16 link_speed;
+ u32 val;
+ int err;
+
+ link_speed = hw->port_info->phy.link_info.link_speed;
+ if (!link_speed)
+ return 0;
+
+ err = ice_tspll_get_div_e825c(link_speed, &divider);
+ if (err)
+ return err;
+
+ err = ice_read_cgu_reg(hw, ICE_CGU_R10, &val);
+ if (err)
+ return err;
+
+ /* programmable divider value (from 2 to 16) minus 1 for ETHCLKOUT */
+ switch (output) {
+ case ICE_SYNCE_CLK0:
+ val &= ~(ICE_CGU_R10_SYNCE_ETHDIV_M1 |
+ ICE_CGU_R10_SYNCE_ETHDIV_LOAD);
+ val |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHDIV_M1, divider - 1);
+ err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
+ if (err)
+ return err;
+ val |= ICE_CGU_R10_SYNCE_ETHDIV_LOAD;
+ break;
+ case ICE_SYNCE_CLK1:
+ val &= ~(ICE_CGU_R10_SYNCE_CLKODIV_M1 |
+ ICE_CGU_R10_SYNCE_CLKODIV_LOAD);
+ val |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKODIV_M1, divider - 1);
+ err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
+ if (err)
+ return err;
+ val |= ICE_CGU_R10_SYNCE_CLKODIV_LOAD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.h b/drivers/net/ethernet/intel/ice/ice_tspll.h
index c0b1232cc07c..d650867004d1 100644
--- a/drivers/net/ethernet/intel/ice/ice_tspll.h
+++ b/drivers/net/ethernet/intel/ice/ice_tspll.h
@@ -21,11 +21,22 @@ struct ice_tspll_params_e82x {
u32 frac_n_div;
};
+#define ICE_CGU_NET_REF_CLK0 0x0
+#define ICE_CGU_REF_CLK_BYP0 0x5
+#define ICE_CGU_REF_CLK_BYP0_DIV 0x0
+#define ICE_CGU_REF_CLK_BYP1 0x4
+#define ICE_CGU_REF_CLK_BYP1_DIV 0x1
+
#define ICE_TSPLL_CK_REFCLKFREQ_E825 0x1F
#define ICE_TSPLL_NDIVRATIO_E825 5
#define ICE_TSPLL_FBDIV_INTGR_E825 256
int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable);
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);
+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);
#endif /* _ICE_TSPLL_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_txclk.c b/drivers/net/ethernet/intel/ice/ice_txclk.c
new file mode 100644
index 000000000000..48459f971cbf
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_txclk.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2026 Intel Corporation */
+
+#include "ice.h"
+#include "ice_cpi.h"
+#include "ice_txclk.h"
+
+#define ICE_PHY0 0
+#define ICE_PHY1 1
+
+/**
+ * ice_txclk_get_pin - map TX reference clock to its DPLL pin
+ * @pf: pointer to the PF structure
+ * @ref_clk: TX reference clock selection
+ *
+ * Return the DPLL pin corresponding to a given external TX reference
+ * clock. Only external TX reference clocks (SYNCE and EREF0) are
+ * represented as DPLL pins. The internal ENET (TXCO) clock has no
+ * associated DPLL pin and therefore yields %NULL.
+ *
+ * This helper is used when emitting DPLL pin change notifications
+ * after TX reference clock transitions have been verified.
+ *
+ * Return: Pointer to the corresponding struct dpll_pin, or %NULL if
+ * the TX reference clock has no DPLL pin representation.
+ */
+struct dpll_pin *
+ice_txclk_get_pin(struct ice_pf *pf, enum ice_e825c_ref_clk ref_clk)
+{
+ switch (ref_clk) {
+ case ICE_REF_CLK_SYNCE:
+ return pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX].pin;
+ case ICE_REF_CLK_EREF0:
+ return pf->dplls.txclks[E825_EXT_EREF_PIN_IDX].pin;
+ case ICE_REF_CLK_ENET:
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * ice_txclk_enable_peer - Enable required TX reference clock on peer PHY
+ * @pf: pointer to the PF structure
+ * @clk: TX reference clock that must be enabled
+ *
+ * Some TX reference clocks on E825-class devices (SyncE and EREF0) must
+ * be enabled on both PHY complexes to allow proper routing:
+ *
+ * - SyncE must be enabled on both PHYs when used by PHY0
+ * - EREF0 must be enabled on both PHYs when used by PHY1
+ *
+ * If the requested clock is not yet enabled on the peer PHY, enable it.
+ * ENET does not require duplication and is ignored.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+static int ice_txclk_enable_peer(struct ice_pf *pf, enum ice_e825c_ref_clk clk)
+{
+ struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);
+ bool peer_clk_in_use;
+ u8 port_num, phy;
+ int err;
+
+ if (clk == ICE_REF_CLK_ENET)
+ return 0;
+
+ if (IS_ERR_OR_NULL(ctrl_pf)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Can't enable tx-clk on peer: no controlling PF\n");
+ return -EINVAL;
+ }
+
+ port_num = pf->ptp.port.port_num;
+ phy = port_num / pf->hw.ptp.ports_per_phy;
+ peer_clk_in_use = true;
+
+ /* Hold ctrl_pf->dplls.lock across both the peer-usage check and
+ * the enable AQ command so that two PFs racing to enable the same
+ * peer-PHY clock cannot both observe peer_clk_in_use == false and
+ * issue duplicate enables.
+ */
+ mutex_lock(&ctrl_pf->dplls.lock);
+ if (clk == ICE_REF_CLK_SYNCE && phy == ICE_PHY0)
+ peer_clk_in_use = ice_txclk_any_port_uses(ctrl_pf,
+ ICE_PHY1,
+ clk);
+ else if (clk == ICE_REF_CLK_EREF0 && phy == ICE_PHY1)
+ peer_clk_in_use = ice_txclk_any_port_uses(ctrl_pf,
+ ICE_PHY0,
+ clk);
+
+ if ((clk == ICE_REF_CLK_SYNCE && phy == ICE_PHY0 && !peer_clk_in_use) ||
+ (clk == ICE_REF_CLK_EREF0 && phy == ICE_PHY1 && !peer_clk_in_use)) {
+ u8 peer_phy = phy ? ICE_PHY0 : ICE_PHY1;
+
+ err = ice_cpi_ena_dis_clk_ref(&pf->hw, peer_phy, clk, true);
+ if (err) {
+ mutex_unlock(&ctrl_pf->dplls.lock);
+ dev_err(ice_pf_to_dev(pf),
+ "Failed to enable the %u TX clock for the %u PHY\n",
+ clk, peer_phy);
+ return err;
+ }
+ }
+ mutex_unlock(&ctrl_pf->dplls.lock);
+
+ return 0;
+}
+
+#define ICE_REFCLK_USER_TO_AQ_IDX(x) ((x) + 1)
+
+/**
+ * ice_txclk_set_clk - Set Tx reference clock
+ * @pf: pointer to pf structure
+ * @clk: new Tx clock
+ *
+ * Return: 0 on success, negative value otherwise.
+ */
+int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk)
+{
+ struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);
+ struct ice_port_info *port_info;
+ bool clk_in_use;
+ u8 port_num, phy;
+ int err;
+
+ if (pf->ptp.port.tx_clk == clk)
+ return 0;
+
+ if (IS_ERR_OR_NULL(ctrl_pf)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Can't set tx-clk: no controlling PF\n");
+ return -EINVAL;
+ }
+
+ if (!test_bit(ICE_FLAG_DPLL, ctrl_pf->flags)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Can't set tx-clk: ctrl PF DPLL not available\n");
+ return -EOPNOTSUPP;
+ }
+
+ port_num = pf->ptp.port.port_num;
+ phy = port_num / pf->hw.ptp.ports_per_phy;
+ port_info = pf->hw.port_info;
+
+ /* Hold ctrl_pf->dplls.lock across both the usage check and the
+ * enable AQ command so that two PFs racing to switch to the same
+ * (phy, clk) cannot both observe clk_in_use == false and issue
+ * duplicate enables. The tx_refclks bitmap is updated only later
+ * by ice_txclk_update_and_notify() after link-up, so without this
+ * the check-then-act window is wide open.
+ */
+ mutex_lock(&ctrl_pf->dplls.lock);
+ clk_in_use = ice_txclk_any_port_uses(ctrl_pf, phy, clk);
+ if (!clk_in_use) {
+ err = ice_cpi_ena_dis_clk_ref(&pf->hw, phy, clk, true);
+ if (err) {
+ mutex_unlock(&ctrl_pf->dplls.lock);
+ dev_err(ice_pf_to_dev(pf), "Failed to enable the %u TX clock for the %u PHY\n",
+ clk, phy);
+ return err;
+ }
+ }
+ mutex_unlock(&ctrl_pf->dplls.lock);
+
+ if (!clk_in_use) {
+ err = ice_txclk_enable_peer(pf, clk);
+ if (err)
+ return err;
+ }
+
+ /* We are ready to switch to the new TX clk. */
+ err = ice_aq_set_link_restart_an(port_info, true, NULL,
+ ICE_REFCLK_USER_TO_AQ_IDX(clk));
+ if (err) {
+ dev_err(ice_pf_to_dev(pf),
+ "AN restart AQ command failed with err %d\n",
+ err);
+ return err;
+ }
+
+ /* Clear txclk_switch_requested only after the AN restart AQ has been
+ * accepted by FW. Clearing earlier would race with any asynchronous
+ * link-up event: ice_txclk_update_and_notify() would observe the
+ * cleared flag, read the stale SERDES selector, and misinterpret the
+ * not-yet-applied switch as a HW rejection. Only clear if no newer
+ * request has overwritten tx_clk_req while we were dropping locks.
+ */
+ mutex_lock(&pf->dplls.lock);
+ if (pf->ptp.port.tx_clk_req == clk)
+ pf->dplls.txclk_switch_requested = false;
+ mutex_unlock(&pf->dplls.lock);
+
+ return 0;
+}
+
+/**
+ * ice_txclk_update_and_notify - Validate TX reference clock switching
+ * @pf: pointer to PF structure
+ *
+ * After a link-up event, verify whether the previously requested TX reference
+ * clock transition actually succeeded. The SERDES reference selector reflects
+ * the effective hardware choice, which may differ from the requested clock
+ * when Auto-Negotiation or firmware applies additional policy.
+ *
+ * If the hardware-selected clock differs from the requested one, update the
+ * software state accordingly and stop further processing.
+ *
+ * When the switch is successful, update the per‑PHY usage bitmaps so that the
+ * driver knows which reference clock is currently in use by this port.
+ *
+ * This function does not initiate a clock switch; it only validates the result
+ * of a previously triggered transition and performs cleanup of unused clocks.
+ */
+void ice_txclk_update_and_notify(struct ice_pf *pf)
+{
+ struct ice_ptp_port *ptp_port = &pf->ptp.port;
+ struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf);
+ struct dpll_pin *old_pin = NULL;
+ struct dpll_pin *new_pin = NULL;
+ struct ice_hw *hw = &pf->hw;
+ enum ice_e825c_ref_clk clk;
+ bool notify_dpll = false;
+ int err;
+ u8 phy;
+
+ phy = ptp_port->port_num / hw->ptp.ports_per_phy;
+
+ /* Hold txclk_notify_rwsem for read across the entire critical
+ * region, including the out-of-lock dpll_*_change_ntf() calls
+ * below. ice_dpll_deinit() takes the write side to wait for all
+ * in-flight notifications to complete before freeing pins and the
+ * TXC DPLL device, preventing a use-after-free on rmmod.
+ */
+ down_read(&pf->dplls.txclk_notify_rwsem);
+ mutex_lock(&pf->dplls.lock);
+ /* Bail out if DPLL subsystem is being torn down. ice_dpll_deinit()
+ * clears ICE_FLAG_DPLL before freeing pins and the dpll device, so a
+ * cleared flag under the lock means those objects can no longer be
+ * safely dereferenced.
+ */
+ if (!test_bit(ICE_FLAG_DPLL, pf->flags)) {
+ mutex_unlock(&pf->dplls.lock);
+ goto out;
+ }
+ /* If a switch is still pending, the link-up event preceded the
+ * worker's AN restart. Hardware hasn't applied the new clock yet,
+ * so reading the SERDES selector now would produce a false failure.
+ * Let the worker run first; the link-up that follows the AN restart
+ * will trigger the verification.
+ */
+ if (pf->dplls.txclk_switch_requested) {
+ mutex_unlock(&pf->dplls.lock);
+ goto out;
+ }
+ /* no TX clock change requested */
+ if (pf->ptp.port.tx_clk == pf->ptp.port.tx_clk_req) {
+ mutex_unlock(&pf->dplls.lock);
+ goto out;
+ }
+ /* verify current Tx reference settings */
+ err = ice_get_serdes_ref_sel_e825c(hw,
+ ptp_port->port_num,
+ &clk);
+ if (err) {
+ mutex_unlock(&pf->dplls.lock);
+ goto out;
+ }
+
+ if (clk != pf->ptp.port.tx_clk_req) {
+ dev_warn(ice_pf_to_dev(pf),
+ "Failed to switch tx-clk for phy %d and clk %u (current: %u)\n",
+ phy, pf->ptp.port.tx_clk_req, clk);
+ old_pin = ice_txclk_get_pin(pf, pf->ptp.port.tx_clk_req);
+ new_pin = ice_txclk_get_pin(pf, clk);
+ pf->ptp.port.tx_clk = clk;
+ pf->ptp.port.tx_clk_req = clk;
+ /* Update the reference clock bitmap to match the hardware
+ * clock that was actually accepted, so that
+ * ice_txclk_any_port_uses() reflects reality even on failure.
+ * The map is owned by ctrl_pf; take its lock per documented
+ * order (pf->dplls.lock first, then ctrl_pf->dplls.lock) so
+ * readers on other PFs observe a consistent snapshot.
+ */
+ if (!IS_ERR_OR_NULL(ctrl_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]);
+ }
+ if (ctrl_pf != pf)
+ mutex_unlock(&ctrl_pf->dplls.lock);
+ }
+ goto err_notify;
+ }
+
+ old_pin = ice_txclk_get_pin(pf, pf->ptp.port.tx_clk);
+ pf->ptp.port.tx_clk = clk;
+ pf->ptp.port.tx_clk_req = clk;
+
+ if (IS_ERR_OR_NULL(ctrl_pf)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Can't set tx-clk: no controlling PF\n");
+ goto err_notify;
+ }
+
+ /* update Tx reference clock usage map; map is owned by ctrl_pf,
+ * take its lock per documented order so readers on other PFs see
+ * a consistent view.
+ */
+ 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]);
+ if (ctrl_pf != pf)
+ mutex_unlock(&ctrl_pf->dplls.lock);
+
+err_notify:
+ /* Update TXC DPLL lock status based on effective TX clk, while still
+ * holding the lock to prevent concurrent link-up events from racing
+ * on dpll_state.
+ */
+ if (!IS_ERR_OR_NULL(pf->dplls.txc.dpll)) {
+ enum dpll_lock_status new_lock = ice_txclk_lock_status(clk);
+
+ if (pf->dplls.txc.dpll_state != new_lock) {
+ pf->dplls.txc.dpll_state = new_lock;
+ notify_dpll = true;
+ }
+ }
+ mutex_unlock(&pf->dplls.lock);
+
+ /* Notify TX clk pins state transition */
+ if (old_pin)
+ dpll_pin_change_ntf(old_pin);
+ if (new_pin)
+ dpll_pin_change_ntf(new_pin);
+
+ if (notify_dpll && !IS_ERR_OR_NULL(pf->dplls.txc.dpll))
+ dpll_device_change_ntf(pf->dplls.txc.dpll);
+
+out:
+ up_read(&pf->dplls.txclk_notify_rwsem);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_txclk.h b/drivers/net/ethernet/intel/ice/ice_txclk.h
new file mode 100644
index 000000000000..21d97afb2afc
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_txclk.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef _ICE_TXCLK_H_
+#define _ICE_TXCLK_H_
+
+/**
+ * ice_txclk_any_port_uses - check if any port on a PHY uses this TX refclk
+ * @ctrl_pf: control PF (owner of the shared tx_refclks map)
+ * @phy: PHY index
+ * @clk: TX reference clock
+ *
+ * Return: true if any bit (port) is set for this clock on this PHY
+ */
+static inline bool
+ice_txclk_any_port_uses(const struct ice_pf *ctrl_pf, u8 phy,
+ enum ice_e825c_ref_clk clk)
+{
+ return find_first_bit(&ctrl_pf->ptp.tx_refclks[phy][clk],
+ BITS_PER_LONG) < BITS_PER_LONG;
+}
+
+static inline enum dpll_lock_status
+ice_txclk_lock_status(enum ice_e825c_ref_clk clk)
+{
+ switch (clk) {
+ case ICE_REF_CLK_SYNCE:
+ case ICE_REF_CLK_EREF0:
+ return DPLL_LOCK_STATUS_LOCKED;
+ case ICE_REF_CLK_ENET:
+ default:
+ return DPLL_LOCK_STATUS_UNLOCKED;
+ }
+}
+
+int ice_txclk_set_clk(struct ice_pf *pf, enum ice_e825c_ref_clk clk);
+void ice_txclk_update_and_notify(struct ice_pf *pf);
+struct dpll_pin *ice_txclk_get_pin(struct ice_pf *pf,
+ enum ice_e825c_ref_clk ref_clk);
+#endif /* _ICE_TXCLK_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index ad76768a4232..31303ab5be17 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -190,9 +190,10 @@ void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring)
void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring)
{
ice_free_tstamp_ring(tx_ring);
+ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
+ smp_wmb(); /* order flag clear before pointer NULL */
kfree_rcu(tx_ring->tstamp_ring, rcu);
- tx_ring->tstamp_ring = NULL;
- tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME;
+ WRITE_ONCE(tx_ring->tstamp_ring, NULL);
}
/**
@@ -379,7 +380,7 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
if (netif_tx_queue_stopped(txring_txq(tx_ring)) &&
!test_bit(ICE_VSI_DOWN, vsi->state)) {
netif_tx_wake_queue(txring_txq(tx_ring));
- ++tx_ring->ring_stats->tx_stats.restart_q;
+ ice_stats_inc(tx_ring->ring_stats, tx_restart_q);
}
}
@@ -397,7 +398,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring)
struct ice_tstamp_ring *tstamp_ring;
/* allocate with kzalloc(), free with kfree_rcu() */
- tstamp_ring = kzalloc(sizeof(*tstamp_ring), GFP_KERNEL);
+ tstamp_ring = kzalloc_obj(*tstamp_ring);
if (!tstamp_ring)
return -ENOMEM;
@@ -405,7 +406,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring)
tx_ring->tstamp_ring = tstamp_ring;
tstamp_ring->desc = NULL;
tstamp_ring->count = ice_calc_ts_ring_count(tx_ring);
- tx_ring->flags |= ICE_TX_FLAGS_TXTIME;
+ set_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags);
return 0;
}
@@ -499,7 +500,7 @@ int ice_setup_tx_ring(struct ice_tx_ring *tx_ring)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
- tx_ring->ring_stats->tx_stats.prev_pkt = -1;
+ tx_ring->ring_stats->tx.prev_pkt = -1;
return 0;
err:
@@ -560,7 +561,9 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
i = 0;
}
- if (rx_ring->vsi->type == ICE_VSI_PF &&
+ if ((rx_ring->vsi->type == ICE_VSI_PF ||
+ rx_ring->vsi->type == ICE_VSI_SF ||
+ rx_ring->vsi->type == ICE_VSI_LB) &&
xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) {
xdp_rxq_info_detach_mem_model(&rx_ring->xdp_rxq);
xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
@@ -574,7 +577,6 @@ rx_skip_free:
PAGE_SIZE);
memset(rx_ring->desc, 0, size);
- rx_ring->next_to_alloc = 0;
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
}
@@ -849,7 +851,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
addr = libeth_rx_alloc(&fq, ntu);
if (addr == DMA_MAPPING_ERROR) {
- rx_ring->ring_stats->rx_stats.alloc_page_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_page_failed);
break;
}
@@ -863,7 +865,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
addr = libeth_rx_alloc(&hdr_fq, ntu);
if (addr == DMA_MAPPING_ERROR) {
- rx_ring->ring_stats->rx_stats.alloc_page_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_page_failed);
libeth_rx_recycle_slow(fq.fqes[ntu].netmem);
break;
@@ -1045,7 +1047,7 @@ construct_skb:
/* exit if we failed to retrieve a buffer */
if (!skb) {
libeth_xdp_return_buff_slow(xdp);
- rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_buf_failed);
continue;
}
@@ -1087,35 +1089,36 @@ static void __ice_update_sample(struct ice_q_vector *q_vector,
struct dim_sample *sample,
bool is_tx)
{
- u64 packets = 0, bytes = 0;
+ u64 total_packets = 0, total_bytes = 0, pkts, bytes;
if (is_tx) {
struct ice_tx_ring *tx_ring;
ice_for_each_tx_ring(tx_ring, *rc) {
- struct ice_ring_stats *ring_stats;
-
- ring_stats = tx_ring->ring_stats;
- if (!ring_stats)
+ if (!tx_ring->ring_stats)
continue;
- packets += ring_stats->stats.pkts;
- bytes += ring_stats->stats.bytes;
+
+ ice_fetch_tx_ring_stats(tx_ring, &pkts, &bytes);
+
+ total_packets += pkts;
+ total_bytes += bytes;
}
} else {
struct ice_rx_ring *rx_ring;
ice_for_each_rx_ring(rx_ring, *rc) {
- struct ice_ring_stats *ring_stats;
-
- ring_stats = rx_ring->ring_stats;
- if (!ring_stats)
+ if (!rx_ring->ring_stats)
continue;
- packets += ring_stats->stats.pkts;
- bytes += ring_stats->stats.bytes;
+
+ ice_fetch_rx_ring_stats(rx_ring, &pkts, &bytes);
+
+ total_packets += pkts;
+ total_bytes += bytes;
}
}
- dim_update_sample(q_vector->total_events, packets, bytes, sample);
+ dim_update_sample(q_vector->total_events,
+ total_packets, total_bytes, sample);
sample->comp_ctr = 0;
/* if dim settings get stale, like when not updated for 1
@@ -1362,7 +1365,7 @@ static int __ice_maybe_stop_tx(struct ice_tx_ring *tx_ring, unsigned int size)
/* A reprieve! - use start_queue because it doesn't call schedule */
netif_tx_start_queue(txring_txq(tx_ring));
- ++tx_ring->ring_stats->tx_stats.restart_q;
+ ice_stats_inc(tx_ring->ring_stats, tx_restart_q);
return 0;
}
@@ -1519,13 +1522,20 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
return;
if (ice_is_txtime_cfg(tx_ring)) {
- struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring;
- u32 tstamp_count = tstamp_ring->count;
- u32 j = tstamp_ring->next_to_use;
+ struct ice_tstamp_ring *tstamp_ring;
+ u32 tstamp_count, j;
struct ice_ts_desc *ts_desc;
struct timespec64 ts;
u32 tstamp;
+ smp_rmb(); /* order flag read before pointer read */
+ tstamp_ring = READ_ONCE(tx_ring->tstamp_ring);
+ if (unlikely(!tstamp_ring))
+ goto ring_kick;
+
+ tstamp_count = tstamp_ring->count;
+ j = tstamp_ring->next_to_use;
+
ts = ktime_to_timespec64(first->skb->tstamp);
tstamp = ts.tv_nsec >> ICE_TXTIME_CTX_RESOLUTION_128NS;
@@ -1553,6 +1563,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
tstamp_ring->next_to_use = j;
writel_relaxed(j, tstamp_ring->tail);
} else {
+ring_kick:
writel_relaxed(i, tx_ring->tail);
}
return;
@@ -1643,7 +1654,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
ret = ipv6_skip_exthdr(skb, exthdr - skb->data,
&l4_proto, &frag_off);
if (ret < 0)
- return -1;
+ goto checksum_sw_fb;
}
/* define outer transport */
@@ -1662,11 +1673,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
l4.hdr = skb_inner_network_header(skb);
break;
default:
- if (first->tx_flags & ICE_TX_FLAGS_TSO)
- return -1;
-
- skb_checksum_help(skb);
- return 0;
+ goto checksum_sw_fb;
}
/* compute outer L3 header size */
@@ -1725,7 +1732,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_proto,
&frag_off);
} else {
- return -1;
+ goto checksum_sw_fb;
}
/* compute inner L3 header size */
@@ -1778,15 +1785,17 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
break;
default:
- if (first->tx_flags & ICE_TX_FLAGS_TSO)
- return -1;
- skb_checksum_help(skb);
- return 0;
+ goto checksum_sw_fb;
}
off->td_cmd |= cmd;
off->td_offset |= offset;
return 1;
+
+checksum_sw_fb:
+ if (first->tx_flags & ICE_TX_FLAGS_TSO)
+ return -1;
+ return skb_checksum_help(skb);
}
/**
@@ -1812,7 +1821,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first)
*/
if (skb_vlan_tag_present(skb)) {
first->vid = skb_vlan_tag_get(skb);
- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2)
+ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags))
first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
else
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
@@ -1882,7 +1891,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_start = (u8)(l4.hdr - skb->data);
@@ -2156,15 +2165,15 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
ice_trace(xmit_frame_ring, tx_ring, skb);
- if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
- goto out_drop;
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buf[tx_ring->next_to_use];
count = ice_xmit_desc_count(skb);
if (ice_chk_linearize(skb, count)) {
if (__skb_linearize(skb))
goto out_drop;
count = ice_txd_use_count(skb->len);
- tx_ring->ring_stats->tx_stats.tx_linearize++;
+ ice_stats_inc(tx_ring->ring_stats, tx_linearize);
}
/* need: 1 descriptor per page * PAGE_SIZE/ICE_MAX_DATA_PER_TXD,
@@ -2175,7 +2184,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
*/
if (ice_maybe_stop_tx(tx_ring, count + ICE_DESCS_PER_CACHE_LINE +
ICE_DESCS_FOR_CTX_DESC)) {
- tx_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(tx_ring->ring_stats, tx_busy);
return NETDEV_TX_BUSY;
}
@@ -2184,8 +2193,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
offload.tx_ring = tx_ring;
- /* record the location of the first descriptor for this packet */
- first = &tx_ring->tx_buf[tx_ring->next_to_use];
first->skb = skb;
first->type = ICE_TX_BUF_SKB;
first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
@@ -2250,6 +2257,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
out_drop:
ice_trace(xmit_frame_ring_drop, tx_ring, skb);
dev_kfree_skb_any(skb);
+ first->type = ICE_TX_BUF_EMPTY;
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index e440c55d9e9f..5e517f219379 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -129,34 +129,65 @@ struct ice_tx_offload_params {
u8 header_len;
};
-struct ice_q_stats {
- u64 pkts;
- u64 bytes;
-};
-
-struct ice_txq_stats {
- u64 restart_q;
- u64 tx_busy;
- u64 tx_linearize;
- int prev_pkt; /* negative if no pending Tx descriptors */
-};
-
-struct ice_rxq_stats {
- u64 non_eop_descs;
- u64 alloc_page_failed;
- u64 alloc_buf_failed;
-};
-
struct ice_ring_stats {
struct rcu_head rcu; /* to avoid race on free */
- struct ice_q_stats stats;
struct u64_stats_sync syncp;
- union {
- struct ice_txq_stats tx_stats;
- struct ice_rxq_stats rx_stats;
- };
+ struct_group(stats,
+ u64_stats_t pkts;
+ u64_stats_t bytes;
+ union {
+ struct_group(tx,
+ u64_stats_t tx_restart_q;
+ u64_stats_t tx_busy;
+ u64_stats_t tx_linearize;
+ /* negative if no pending Tx descriptors */
+ int prev_pkt;
+ );
+ struct_group(rx,
+ u64_stats_t rx_non_eop_descs;
+ u64_stats_t rx_page_failed;
+ u64_stats_t rx_buf_failed;
+ );
+ };
+ );
};
+/**
+ * ice_stats_read - Read a single ring stat value
+ * @stats: pointer to ring_stats structure for a queue
+ * @member: the ice_ring_stats member to read
+ *
+ * Shorthand for reading a single 64-bit stat value from struct
+ * ice_ring_stats.
+ *
+ * Return: the value of the requested stat.
+ */
+#define ice_stats_read(stats, member) ({ \
+ struct ice_ring_stats *__stats = (stats); \
+ unsigned int start; \
+ u64 val; \
+ do { \
+ start = u64_stats_fetch_begin(&__stats->syncp); \
+ val = u64_stats_read(&__stats->member); \
+ } while (u64_stats_fetch_retry(&__stats->syncp, start)); \
+ val; \
+})
+
+/**
+ * ice_stats_inc - Increment a single ring stat value
+ * @stats: pointer to the ring_stats structure for a queue
+ * @member: the ice_ring_stats member to increment
+ *
+ * Shorthand for incrementing a single 64-bit stat value in struct
+ * ice_ring_stats.
+ */
+#define ice_stats_inc(stats, member) do { \
+ struct ice_ring_stats *__stats = (stats); \
+ u64_stats_update_begin(&__stats->syncp); \
+ u64_stats_inc(&__stats->member); \
+ u64_stats_update_end(&__stats->syncp); \
+} while (0)
+
enum ice_ring_state_t {
ICE_TX_XPS_INIT_DONE,
ICE_TX_NBITS,
@@ -181,6 +212,14 @@ enum ice_rx_dtype {
ICE_RX_DTYPE_SPLIT_ALWAYS = 2,
};
+enum ice_tx_ring_flags {
+ ICE_TX_RING_FLAGS_XDP,
+ ICE_TX_RING_FLAGS_VLAN_L2TAG1,
+ ICE_TX_RING_FLAGS_VLAN_L2TAG2,
+ ICE_TX_RING_FLAGS_TXTIME,
+ ICE_TX_RING_FLAGS_NBITS,
+};
+
struct ice_pkt_ctx {
u64 cached_phctime;
__be16 vlan_proto;
@@ -236,34 +275,49 @@ struct ice_tstamp_ring {
} ____cacheline_internodealigned_in_smp;
struct ice_rx_ring {
- /* CL1 - 1st cacheline starts here */
+ __cacheline_group_begin_aligned(read_mostly);
void *desc; /* Descriptor ring memory */
struct page_pool *pp;
struct net_device *netdev; /* netdev ring maps to */
- struct ice_vsi *vsi; /* Backreference to associated VSI */
struct ice_q_vector *q_vector; /* Backreference to associated vector */
u8 __iomem *tail;
- u16 q_index; /* Queue number of ring */
-
- u16 count; /* Number of descriptors */
- u16 reg_idx; /* HW register index of the ring */
- u16 next_to_alloc;
union {
struct libeth_fqe *rx_fqes;
struct xdp_buff **xdp_buf;
};
- /* CL2 - 2nd cacheline starts here */
- struct libeth_fqe *hdr_fqes;
+ u16 count; /* Number of descriptors */
+ u8 ptp_rx;
+
+ u8 flags;
+#define ICE_RX_FLAGS_CRC_STRIP_DIS BIT(2)
+#define ICE_RX_FLAGS_MULTIDEV BIT(3)
+#define ICE_RX_FLAGS_RING_GCS BIT(4)
+
+ u32 truesize;
+
struct page_pool *hdr_pp;
+ struct libeth_fqe *hdr_fqes;
+ struct bpf_prog *xdp_prog;
+ struct ice_tx_ring *xdp_ring;
+ struct xsk_buff_pool *xsk_pool;
+
+ /* stats structs */
+ struct ice_ring_stats *ring_stats;
+ struct ice_rx_ring *next; /* pointer to next ring in q_vector */
+
+ u32 hdr_truesize;
+
+ struct xdp_rxq_info xdp_rxq;
+ __cacheline_group_end_aligned(read_mostly);
+
+ __cacheline_group_begin_aligned(read_write);
union {
struct libeth_xdp_buff_stash xdp;
struct libeth_xdp_buff *xsk;
};
-
- /* CL3 - 3rd cacheline starts here */
union {
struct ice_pkt_ctx pkt_ctx;
struct {
@@ -271,75 +325,74 @@ struct ice_rx_ring {
__be16 vlan_proto;
};
};
- struct bpf_prog *xdp_prog;
/* used in interrupt processing */
u16 next_to_use;
u16 next_to_clean;
+ __cacheline_group_end_aligned(read_write);
- u32 hdr_truesize;
- u32 truesize;
-
- /* stats structs */
- struct ice_ring_stats *ring_stats;
-
+ __cacheline_group_begin_aligned(cold);
struct rcu_head rcu; /* to avoid race on free */
- /* CL4 - 4th cacheline starts here */
+ struct ice_vsi *vsi; /* Backreference to associated VSI */
struct ice_channel *ch;
- struct ice_tx_ring *xdp_ring;
- struct ice_rx_ring *next; /* pointer to next ring in q_vector */
- struct xsk_buff_pool *xsk_pool;
- u16 rx_hdr_len;
- u16 rx_buf_len;
+
dma_addr_t dma; /* physical address of ring */
+ u16 q_index; /* Queue number of ring */
+ u16 reg_idx; /* HW register index of the ring */
u8 dcb_tc; /* Traffic class of ring */
- u8 ptp_rx;
-#define ICE_RX_FLAGS_CRC_STRIP_DIS BIT(2)
-#define ICE_RX_FLAGS_MULTIDEV BIT(3)
-#define ICE_RX_FLAGS_RING_GCS BIT(4)
- u8 flags;
- /* CL5 - 5th cacheline starts here */
- struct xdp_rxq_info xdp_rxq;
+
+ u16 rx_hdr_len;
+ u16 rx_buf_len;
+ __cacheline_group_end_aligned(cold);
} ____cacheline_internodealigned_in_smp;
struct ice_tx_ring {
- /* CL1 - 1st cacheline starts here */
- struct ice_tx_ring *next; /* pointer to next ring in q_vector */
+ __cacheline_group_begin_aligned(read_mostly);
void *desc; /* Descriptor ring memory */
struct device *dev; /* Used for DMA mapping */
u8 __iomem *tail;
struct ice_tx_buf *tx_buf;
+
struct ice_q_vector *q_vector; /* Backreference to associated vector */
struct net_device *netdev; /* netdev ring maps to */
struct ice_vsi *vsi; /* Backreference to associated VSI */
- /* CL2 - 2nd cacheline starts here */
- dma_addr_t dma; /* physical address of ring */
- struct xsk_buff_pool *xsk_pool;
- u16 next_to_use;
- u16 next_to_clean;
- u16 q_handle; /* Queue handle per TC */
- u16 reg_idx; /* HW register index of the ring */
+
u16 count; /* Number of descriptors */
u16 q_index; /* Queue number of ring */
- u16 xdp_tx_active;
+
+ DECLARE_BITMAP(flags, ICE_TX_RING_FLAGS_NBITS);
+
+ struct xsk_buff_pool *xsk_pool;
+
/* stats structs */
struct ice_ring_stats *ring_stats;
- /* CL3 - 3rd cacheline starts here */
+ struct ice_tx_ring *next; /* pointer to next ring in q_vector */
+
+ struct ice_tstamp_ring *tstamp_ring;
+ struct ice_ptp_tx *tx_tstamps;
+ __cacheline_group_end_aligned(read_mostly);
+
+ __cacheline_group_begin_aligned(read_write);
+ u16 next_to_use;
+ u16 next_to_clean;
+
+ u16 xdp_tx_active;
+ spinlock_t tx_lock;
+ __cacheline_group_end_aligned(read_write);
+
+ __cacheline_group_begin_aligned(cold);
struct rcu_head rcu; /* to avoid race on free */
DECLARE_BITMAP(xps_state, ICE_TX_NBITS); /* XPS Config State */
struct ice_channel *ch;
- struct ice_ptp_tx *tx_tstamps;
- spinlock_t tx_lock;
- u32 txq_teid; /* Added Tx queue TEID */
- /* CL4 - 4th cacheline starts here */
- struct ice_tstamp_ring *tstamp_ring;
-#define ICE_TX_FLAGS_RING_XDP BIT(0)
-#define ICE_TX_FLAGS_RING_VLAN_L2TAG1 BIT(1)
-#define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2)
-#define ICE_TX_FLAGS_TXTIME BIT(3)
- u8 flags;
+
+ dma_addr_t dma; /* physical address of ring */
+ u16 q_handle; /* Queue handle per TC */
+ u16 reg_idx; /* HW register index of the ring */
u8 dcb_tc; /* Traffic class of ring */
+
u16 quanta_prof_id;
+ u32 txq_teid; /* Added Tx queue TEID */
+ __cacheline_group_end_aligned(cold);
} ____cacheline_internodealigned_in_smp;
static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)
@@ -349,7 +402,7 @@ static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)
static inline bool ice_ring_is_xdp(struct ice_tx_ring *ring)
{
- return !!(ring->flags & ICE_TX_FLAGS_RING_XDP);
+ return test_bit(ICE_TX_RING_FLAGS_XDP, ring->flags);
}
enum ice_container_type {
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index 956da38d63b0..e695a664e53d 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -20,9 +20,6 @@ void ice_release_rx_desc(struct ice_rx_ring *rx_ring, u16 val)
rx_ring->next_to_use = val;
- /* update next to alloc since we have filled the ring */
- rx_ring->next_to_alloc = val;
-
/* QRX_TAIL will be updated with any tail value, but hardware ignores
* the lower 3 bits. This makes it so we only bump tail on meaningful
* boundaries. Also, this allows us to bump tail on intervals of 8 up to
@@ -480,7 +477,7 @@ dma_unmap:
return ICE_XDP_CONSUMED;
busy:
- xdp_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(xdp_ring->ring_stats, tx_busy);
return ICE_XDP_CONSUMED;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
index 6a3f10f7a53f..f17990b68b62 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
@@ -38,7 +38,7 @@ ice_is_non_eop(const struct ice_rx_ring *rx_ring,
if (likely(ice_test_staterr(rx_desc->wb.status_error0, ICE_RXD_EOF)))
return false;
- rx_ring->ring_stats->rx_stats.non_eop_descs++;
+ ice_stats_inc(rx_ring->ring_stats, rx_non_eop_descs);
return true;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index 6a2ec8389a8f..cf147a212707 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -349,6 +349,12 @@ enum ice_clk_src {
NUM_ICE_CLK_SRC
};
+enum ice_synce_clk {
+ ICE_SYNCE_CLK0,
+ ICE_SYNCE_CLK1,
+ ICE_SYNCE_CLK_NUM
+};
+
struct ice_ts_func_info {
/* Function specific info */
enum ice_tspll_freq time_ref;
@@ -759,7 +765,6 @@ struct ice_port_info {
/* List contain profile ID(s) and other params per layer */
struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM];
struct ice_qos_cfg qos_cfg;
- struct xarray sched_node_ids;
u8 is_vf:1;
u8 is_custom_tx_enabled:1;
};
@@ -887,6 +892,8 @@ struct ice_ptp_hw {
u8 ports_per_phy;
};
+#define ICE_E825_MAX_PHYS 2
+
/* Port hardware description */
struct ice_hw {
u8 __iomem *hw_addr;
@@ -922,6 +929,7 @@ struct ice_hw {
u8 sw_entry_point_layer;
u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM];
struct list_head agg_list; /* lists all aggregator */
+ struct xarray sched_node_ids;
struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI];
u8 evb_veb; /* true for VEB, false for VEPA */
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index de9e81ccee66..a54cb2b8d3c7 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -801,13 +801,19 @@ void ice_reset_all_vfs(struct ice_pf *pf)
* setup only when VF creates its first FDIR rule.
*/
if (vf->ctrl_vsi_idx != ICE_NO_VSI)
- ice_vf_ctrl_invalidate_vsi(vf);
+ ice_vf_ctrl_vsi_release(vf);
ice_vf_pre_vsi_rebuild(vf);
- ice_vf_rebuild_vsi(vf);
+ if (ice_vf_rebuild_vsi(vf)) {
+ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n",
+ vf->vf_id);
+ mutex_unlock(&vf->cfg_lock);
+ continue;
+ }
ice_vf_post_vsi_rebuild(vf);
- ice_eswitch_attach_vf(pf, vf);
+ if (ice_is_eswitch_mode_switchdev(pf))
+ ice_eswitch_attach_vf(pf, vf);
mutex_unlock(&vf->cfg_lock);
}
@@ -843,6 +849,30 @@ static void ice_notify_vf_reset(struct ice_vf *vf)
}
/**
+ * ice_reset_interrupts - clear all queue interrupt configuration for a VSI
+ * @vsi: the VSI whose interrupt registers should be cleared
+ *
+ * Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues
+ * in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX,
+ * CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only
+ * clears the CAUSE_ENA bit.
+ */
+void ice_reset_interrupts(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int i;
+
+ ice_for_each_alloc_rxq(vsi, i)
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[i]), 0);
+
+ ice_for_each_alloc_txq(vsi, i)
+ wr32(hw, QINT_TQCTL(vsi->txq_map[i]), 0);
+
+ ice_flush(hw);
+}
+
+/**
* ice_reset_vf - Reset a particular VF
* @vf: pointer to the VF structure
* @flags: flags controlling behavior of the reset
@@ -913,6 +943,9 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
ice_dis_vf_qs(vf);
+ /* cleanup interrupt registers */
+ ice_reset_interrupts(vsi);
+
/* Call Disable LAN Tx queue AQ whether or not queues are
* enabled. This is needed for successful completion of VFR.
*/
@@ -1112,7 +1145,7 @@ static int ice_cfg_mac_antispoof(struct ice_vsi *vsi, bool enable)
struct ice_vsi_ctx *ctx;
int err;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -1210,8 +1243,8 @@ bool ice_is_vf_trusted(struct ice_vf *vf)
*/
bool ice_vf_has_no_qs_ena(struct ice_vf *vf)
{
- return (!bitmap_weight(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF) &&
- !bitmap_weight(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF));
+ return bitmap_empty(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF) &&
+ bitmap_empty(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 7a9c75d1d07c..fa436b3b1eac 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -8,9 +8,9 @@
#include <linux/hashtable.h>
#include <linux/bitmap.h>
#include <linux/mutex.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/pci.h>
#include <net/devlink.h>
-#include <linux/avf/virtchnl.h>
#include "ice_type.h"
#include "ice_flow.h"
#include "virt/fdir.h"
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
index 5392b0404986..321d29c25b7c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
@@ -26,6 +26,7 @@
void ice_initialize_vf_entry(struct ice_vf *vf);
void ice_deinitialize_vf_entry(struct ice_vf *vf);
void ice_dis_vf_qs(struct ice_vf *vf);
+void ice_reset_interrupts(struct ice_vsi *vsi);
int ice_check_vf_init(struct ice_vf *vf);
enum virtchnl_status_code ice_err_to_virt_err(int err);
struct ice_port_info *ice_vf_get_port_info(struct ice_vf *vf);
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
index ada78f83b3ac..54984966851d 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
@@ -94,7 +94,7 @@ static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
struct ice_vsi_ctx *ctxt;
int err;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -141,7 +141,7 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
if (vsi->info.port_based_inner_vlan)
return 0;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -239,7 +239,7 @@ static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info)
struct ice_vsi_ctx *ctxt;
int ret;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -292,7 +292,7 @@ int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi)
struct ice_vsi_ctx *ctxt;
int ret;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -336,7 +336,7 @@ static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
return 0;
pf = vsi->back;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -382,7 +382,7 @@ static int ice_cfg_vlan_antispoof(struct ice_vsi *vsi, bool enable)
struct ice_vsi_ctx *ctx;
int err;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -478,7 +478,7 @@ int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid)
if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
return -EINVAL;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -529,7 +529,7 @@ int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi)
if (vsi->info.port_based_outer_vlan)
return 0;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -584,7 +584,7 @@ int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid)
if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
return -EINVAL;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -636,7 +636,7 @@ int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi)
if (vsi->info.port_based_outer_vlan)
return 0;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -694,7 +694,7 @@ __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
return -EINVAL;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -767,7 +767,7 @@ int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi)
struct ice_vsi_ctx *ctxt;
int err;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
@@ -794,7 +794,7 @@ int ice_vsi_clear_port_vlan(struct ice_vsi *vsi)
struct ice_vsi_ctx *ctxt;
int err;
- ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc_obj(*ctxt);
if (!ctxt)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index 989ff1fd9110..0643017541c3 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -174,9 +174,8 @@ int
ice_realloc_rx_xdp_bufs(struct ice_rx_ring *rx_ring, bool pool_present)
{
if (pool_present) {
- rx_ring->xdp_buf = kcalloc(rx_ring->count,
- sizeof(*rx_ring->xdp_buf),
- GFP_KERNEL);
+ rx_ring->xdp_buf = kzalloc_objs(*rx_ring->xdp_buf,
+ rx_ring->count);
if (!rx_ring->xdp_buf)
return -ENOMEM;
} else {
@@ -497,7 +496,7 @@ static int ice_xmit_xdp_tx_zc(struct xdp_buff *xdp,
return ICE_XDP_TX;
busy:
- xdp_ring->ring_stats->tx_stats.tx_busy++;
+ ice_stats_inc(xdp_ring->ring_stats, tx_busy);
return ICE_XDP_CONSUMED;
}
@@ -659,7 +658,7 @@ construct_skb:
xsk_buff_free(first);
first = NULL;
- rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
+ ice_stats_inc(rx_ring->ring_stats, rx_buf_failed);
continue;
}
@@ -900,6 +899,9 @@ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
u16 ntc = rx_ring->next_to_clean;
u16 ntu = rx_ring->next_to_use;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
while (ntc != ntu) {
struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
diff --git a/drivers/net/ethernet/intel/ice/virt/fdir.c b/drivers/net/ethernet/intel/ice/virt/fdir.c
index ae83c3914e29..4f1f3442e52c 100644
--- a/drivers/net/ethernet/intel/ice/virt/fdir.c
+++ b/drivers/net/ethernet/intel/ice/virt/fdir.c
@@ -875,7 +875,7 @@ ice_vc_fdir_parse_raw(struct ice_vf *vf,
if (hw->debug_mask & ICE_DBG_PARSER)
ice_parser_result_dump(hw, &rslt);
- conf->prof = kzalloc(sizeof(*conf->prof), GFP_KERNEL);
+ conf->prof = kzalloc_obj(*conf->prof);
if (!conf->prof) {
status = -ENOMEM;
goto err_parser_destroy;
@@ -2128,7 +2128,7 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
goto err_exit;
}
- stat = kzalloc(sizeof(*stat), GFP_KERNEL);
+ stat = kzalloc_obj(*stat);
if (!stat) {
v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
@@ -2332,7 +2332,7 @@ int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg)
goto err_exit;
}
- stat = kzalloc(sizeof(*stat), GFP_KERNEL);
+ stat = kzalloc_obj(*stat);
if (!stat) {
v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index f73d5a3e83d4..431c9c546b04 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -225,6 +225,24 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
}
/**
+ * ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL
+ * @vsi: VSI of the VF to configure
+ * @q_idx: VF queue index used to determine the queue in the PF's space
+ */
+static void ice_vf_dis_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ u32 pfq = vsi->rxq_map[q_idx];
+ u32 reg;
+
+ reg = rd32(hw, QINT_RQCTL(pfq));
+ reg &= ~QINT_RQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_RQCTL(pfq), reg);
+
+ ice_flush(hw);
+}
+
+/**
* ice_vc_ena_qs_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
@@ -416,6 +434,8 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
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) {
for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
@@ -436,6 +456,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
+ ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
/* Clear enabled queues flag */
clear_bit(vf_q_id, vf->rxq_ena);
}
@@ -840,7 +861,7 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
if (qpi->rxq.databuffer_size != 0 &&
(qpi->rxq.databuffer_size > ((16 * 1024) - 128) ||
- qpi->rxq.databuffer_size < 1024))
+ qpi->rxq.databuffer_size < 128))
goto error_param;
ring->rx_buf_len = qpi->rxq.databuffer_size;
diff --git a/drivers/net/ethernet/intel/ice/virt/rss.c b/drivers/net/ethernet/intel/ice/virt/rss.c
index 085e69ec0cfc..960012ca91b5 100644
--- a/drivers/net/ethernet/intel/ice/virt/rss.c
+++ b/drivers/net/ethernet/intel/ice/virt/rss.c
@@ -380,7 +380,7 @@ ice_vc_rss_hash_update(struct ice_hw *hw, struct ice_vsi *vsi, u8 hash_type)
struct ice_vsi_ctx *ctx;
int ret;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.c b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
index f3f921134379..ca8018e3dd42 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
@@ -1658,7 +1658,7 @@ static int ice_vc_get_offload_vlan_v2_caps(struct ice_vf *vf)
goto out;
}
- caps = kzalloc(sizeof(*caps), GFP_KERNEL);
+ caps = kzalloc_obj(*caps);
if (!caps) {
v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
goto out;
@@ -2477,7 +2477,7 @@ static int ice_vc_get_phc_time(struct ice_vf *vf)
v_ret = VIRTCHNL_STATUS_SUCCESS;
- phc_time = kzalloc(sizeof(*phc_time), GFP_KERNEL);
+ phc_time = kzalloc_obj(*phc_time);
if (!phc_time) {
v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
goto err;
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.h b/drivers/net/ethernet/intel/ice/virt/virtchnl.h
index 71bb456e2d71..d11789b3ae1f 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.h
+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.h
@@ -7,7 +7,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/if_ether.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/net/intel/virtchnl.h>
#include "ice_vf_lib.h"
/* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */
diff --git a/drivers/net/ethernet/intel/idpf/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig
index adab2154125b..586df3a4afe9 100644
--- a/drivers/net/ethernet/intel/idpf/Kconfig
+++ b/drivers/net/ethernet/intel/idpf/Kconfig
@@ -6,6 +6,7 @@ config IDPF
depends on PCI_MSI
depends on PTP_1588_CLOCK_OPTIONAL
select DIMLIB
+ select LIBIE_CP
select LIBETH_XDP
help
This driver supports Intel(R) Infrastructure Data Path Function
diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile
index 651ddee942bd..4aaafa175ec3 100644
--- a/drivers/net/ethernet/intel/idpf/Makefile
+++ b/drivers/net/ethernet/intel/idpf/Makefile
@@ -6,8 +6,6 @@
obj-$(CONFIG_IDPF) += idpf.o
idpf-y := \
- idpf_controlq.o \
- idpf_controlq_setup.o \
idpf_dev.o \
idpf_ethtool.o \
idpf_idc.o \
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 8cfc68cbfa06..470bc23c844c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -8,6 +8,8 @@
struct idpf_adapter;
struct idpf_vport;
struct idpf_vport_max_q;
+struct idpf_q_vec_rsrc;
+struct idpf_rss_data;
#include <net/pkt_sched.h>
#include <linux/aer.h>
@@ -21,10 +23,10 @@ struct idpf_vport_max_q;
#include <linux/net/intel/iidc_rdma.h>
#include <linux/net/intel/iidc_rdma_idpf.h>
+#include <linux/net/intel/libie/controlq.h>
+#include <linux/net/intel/virtchnl2.h>
-#include "virtchnl2.h"
#include "idpf_txrx.h"
-#include "idpf_controlq.h"
#define GETMAXVAL(num_bits) GENMASK((num_bits) - 1, 0)
@@ -34,11 +36,10 @@ struct idpf_vport_max_q;
#define IDPF_NUM_FILTERS_PER_MSG 20
#define IDPF_NUM_DFLT_MBX_Q 2 /* includes both TX and RX */
#define IDPF_DFLT_MBX_Q_LEN 64
-#define IDPF_DFLT_MBX_ID -1
/* maximum number of times to try before resetting mailbox */
#define IDPF_MB_MAX_ERR 20
#define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz) \
- ((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
+ ((LIBIE_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
#define IDPF_WAIT_FOR_MARKER_TIMEO 500
#define IDPF_MAX_WAIT 500
@@ -199,9 +200,10 @@ struct idpf_vport_max_q {
* @ptp_reg_init: PTP register initialization
*/
struct idpf_reg_ops {
- void (*ctlq_reg_init)(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq);
- int (*intr_reg_init)(struct idpf_vport *vport);
+ void (*ctlq_reg_init)(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cctlq_info);
+ int (*intr_reg_init)(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
void (*reset_reg_init)(struct idpf_adapter *adapter);
void (*trigger_reset)(struct idpf_adapter *adapter,
@@ -284,59 +286,92 @@ struct idpf_port_stats {
struct idpf_fsteer_fltr {
struct list_head list;
- u32 loc;
- u32 q_index;
+ struct ethtool_rx_flow_spec fs;
};
/**
- * struct idpf_vport - Handle for netdevices and queue resources
- * @num_txq: Number of allocated TX queues
- * @num_complq: Number of allocated completion queues
+ * struct idpf_q_vec_rsrc - handle for queue and vector resources
+ * @dev: device pointer for DMA mapping
+ * @q_vectors: array of queue vectors
+ * @q_vector_idxs: starting index of queue vectors
+ * @num_q_vectors: number of IRQ vectors allocated
+ * @noirq_v_idx: ID of the NOIRQ vector
+ * @noirq_dyn_ctl_ena: value to write to the above to enable it
+ * @noirq_dyn_ctl: register to enable/disable the vector for NOIRQ queues
+ * @txq_grps: array of TX queue groups
* @txq_desc_count: TX queue descriptor count
- * @complq_desc_count: Completion queue descriptor count
- * @compln_clean_budget: Work budget for completion clean
- * @num_txq_grp: Number of TX queue groups
- * @txq_grps: Array of TX queue groups
- * @txq_model: Split queue or single queue queuing model
- * @txqs: Used only in hotpath to get to the right queue very fast
- * @crc_enable: Enable CRC insertion offload
- * @xdpsq_share: whether XDPSQ sharing is enabled
- * @num_xdp_txq: number of XDPSQs
+ * @complq_desc_count: completion queue descriptor count
+ * @txq_model: split queue or single queue queuing model
+ * @num_txq: number of allocated TX queues
+ * @num_complq: number of allocated completion queues
+ * @num_txq_grp: number of TX queue groups
* @xdp_txq_offset: index of the first XDPSQ (== number of regular SQs)
- * @xdp_prog: installed XDP program
- * @num_rxq: Number of allocated RX queues
- * @num_bufq: Number of allocated buffer queues
+ * @num_rxq_grp: number of RX queues in a group
+ * @rxq_model: splitq queue or single queue queuing model
+ * @rxq_grps: total number of RX groups. Number of groups * number of RX per
+ * group will yield total number of RX queues.
+ * @num_rxq: number of allocated RX queues
+ * @num_bufq: number of allocated buffer queues
* @rxq_desc_count: RX queue descriptor count. *MUST* have enough descriptors
* to complete all buffer descriptors for all buffer queues in
* the worst case.
- * @num_bufqs_per_qgrp: Buffer queues per RX queue in a given grouping
- * @bufq_desc_count: Buffer queue descriptor count
- * @num_rxq_grp: Number of RX queues in a group
- * @rxq_grps: Total number of RX groups. Number of groups * number of RX per
- * group will yield total number of RX queues.
- * @rxq_model: Splitq queue or single queue queuing model
- * @rx_ptype_lkup: Lookup table for ptypes on RX
+ * @bufq_desc_count: buffer queue descriptor count
+ * @num_bufqs_per_qgrp: buffer queues per RX queue in a given grouping
+ * @base_rxd: true if the driver should use base descriptors instead of flex
+ */
+struct idpf_q_vec_rsrc {
+ struct device *dev;
+ struct idpf_q_vector *q_vectors;
+ u16 *q_vector_idxs;
+ u16 num_q_vectors;
+ u16 noirq_v_idx;
+ u32 noirq_dyn_ctl_ena;
+ void __iomem *noirq_dyn_ctl;
+
+ struct idpf_txq_group *txq_grps;
+ u32 txq_desc_count;
+ u32 complq_desc_count;
+ u32 txq_model;
+ u16 num_txq;
+ u16 num_complq;
+ u16 num_txq_grp;
+ u16 xdp_txq_offset;
+
+ u16 num_rxq_grp;
+ u32 rxq_model;
+ struct idpf_rxq_group *rxq_grps;
+ u16 num_rxq;
+ u16 num_bufq;
+ u32 rxq_desc_count;
+ u32 bufq_desc_count[IDPF_MAX_BUFQS_PER_RXQ_GRP];
+ u8 num_bufqs_per_qgrp;
+ bool base_rxd;
+};
+
+/**
+ * struct idpf_vport - Handle for netdevices and queue resources
+ * @dflt_qv_rsrc: contains default queue and vector resources
+ * @txqs: Used only in hotpath to get to the right queue very fast
+ * @num_txq: Number of allocated TX queues
+ * @num_xdp_txq: number of XDPSQs
+ * @xdpsq_share: whether XDPSQ sharing is enabled
+ * @xdp_prog: installed XDP program
* @vdev_info: IDC vport device info pointer
* @adapter: back pointer to associated adapter
* @netdev: Associated net_device. Each vport should have one and only one
* associated netdev.
* @flags: See enum idpf_vport_flags
- * @vport_type: Default SRIOV, SIOV, etc.
+ * @compln_clean_budget: Work budget for completion clean
* @vport_id: Device given vport identifier
+ * @vport_type: Default SRIOV, SIOV, etc.
* @idx: Software index in adapter vports struct
- * @default_vport: Use this vport if one isn't specified
- * @base_rxd: True if the driver should use base descriptors instead of flex
- * @num_q_vectors: Number of IRQ vectors allocated
- * @q_vectors: Array of queue vectors
- * @q_vector_idxs: Starting index of queue vectors
- * @noirq_dyn_ctl: register to enable/disable the vector for NOIRQ queues
- * @noirq_dyn_ctl_ena: value to write to the above to enable it
- * @noirq_v_idx: ID of the NOIRQ vector
* @max_mtu: device given max possible MTU
* @default_mac_addr: device will give a default MAC to use
* @rx_itr_profile: RX profiles for Dynamic Interrupt Moderation
* @tx_itr_profile: TX profiles for Dynamic Interrupt Moderation
* @port_stats: per port csum, header split, and other offload stats
+ * @default_vport: Use this vport if one isn't specified
+ * @crc_enable: Enable CRC insertion offload
* @link_up: True if link is up
* @tx_tstamp_caps: Capabilities negotiated for Tx timestamping
* @tstamp_config: The Tx tstamp config
@@ -344,57 +379,31 @@ struct idpf_fsteer_fltr {
* @tstamp_stats: Tx timestamping statistics
*/
struct idpf_vport {
- u16 num_txq;
- u16 num_complq;
- u32 txq_desc_count;
- u32 complq_desc_count;
- u32 compln_clean_budget;
- u16 num_txq_grp;
- struct idpf_txq_group *txq_grps;
- u32 txq_model;
+ struct idpf_q_vec_rsrc dflt_qv_rsrc;
struct idpf_tx_queue **txqs;
- bool crc_enable;
-
- bool xdpsq_share;
+ u16 num_txq;
u16 num_xdp_txq;
- u16 xdp_txq_offset;
+ bool xdpsq_share;
struct bpf_prog *xdp_prog;
- u16 num_rxq;
- u16 num_bufq;
- u32 rxq_desc_count;
- u8 num_bufqs_per_qgrp;
- u32 bufq_desc_count[IDPF_MAX_BUFQS_PER_RXQ_GRP];
- u16 num_rxq_grp;
- struct idpf_rxq_group *rxq_grps;
- u32 rxq_model;
- struct libeth_rx_pt *rx_ptype_lkup;
-
struct iidc_rdma_vport_dev_info *vdev_info;
struct idpf_adapter *adapter;
struct net_device *netdev;
DECLARE_BITMAP(flags, IDPF_VPORT_FLAGS_NBITS);
- u16 vport_type;
+ u32 compln_clean_budget;
u32 vport_id;
+ u16 vport_type;
u16 idx;
- bool default_vport;
- bool base_rxd;
-
- u16 num_q_vectors;
- struct idpf_q_vector *q_vectors;
- u16 *q_vector_idxs;
-
- void __iomem *noirq_dyn_ctl;
- u32 noirq_dyn_ctl_ena;
- u16 noirq_v_idx;
u16 max_mtu;
u8 default_mac_addr[ETH_ALEN];
u16 rx_itr_profile[IDPF_DIM_PROFILE_SLOTS];
u16 tx_itr_profile[IDPF_DIM_PROFILE_SLOTS];
- struct idpf_port_stats port_stats;
+ struct idpf_port_stats port_stats;
+ bool default_vport;
+ bool crc_enable;
bool link_up;
struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
@@ -424,14 +433,12 @@ enum idpf_user_flags {
* @rss_key: RSS hash key
* @rss_lut_size: Size of RSS lookup table
* @rss_lut: RSS lookup table
- * @cached_lut: Used to restore previously init RSS lut
*/
struct idpf_rss_data {
u16 rss_key_size;
u8 *rss_key;
u16 rss_lut_size;
u32 *rss_lut;
- u32 *cached_lut;
};
/**
@@ -553,23 +560,50 @@ struct idpf_vector_lifo {
};
/**
+ * struct idpf_queue_id_reg_chunk - individual queue ID and register chunk
+ * @qtail_reg_start: queue tail register offset
+ * @qtail_reg_spacing: queue tail register spacing
+ * @type: queue type of the queues in the chunk
+ * @start_queue_id: starting queue ID in the chunk
+ * @num_queues: number of queues in the chunk
+ */
+struct idpf_queue_id_reg_chunk {
+ u64 qtail_reg_start;
+ u32 qtail_reg_spacing;
+ u32 type;
+ u32 start_queue_id;
+ u32 num_queues;
+};
+
+/**
+ * struct idpf_queue_id_reg_info - queue ID and register chunk info received
+ * over the mailbox
+ * @num_chunks: number of chunks
+ * @queue_chunks: array of chunks
+ */
+struct idpf_queue_id_reg_info {
+ u16 num_chunks;
+ struct idpf_queue_id_reg_chunk *queue_chunks;
+};
+
+/**
* struct idpf_vport_config - Vport configuration data
* @user_config: see struct idpf_vport_user_config_data
* @max_q: Maximum possible queues
- * @req_qs_chunks: Queue chunk data for requested queues
+ * @qid_reg_info: Struct to store the queue ID and register info
* @mac_filter_list_lock: Lock to protect mac filters
+ * @flow_steer_list_lock: Lock to protect fsteer filters
* @flags: See enum idpf_vport_config_flags
*/
struct idpf_vport_config {
struct idpf_vport_user_config_data user_config;
struct idpf_vport_max_q max_q;
- struct virtchnl2_add_queues *req_qs_chunks;
+ struct idpf_queue_id_reg_info qid_reg_info;
spinlock_t mac_filter_list_lock;
+ spinlock_t flow_steer_list_lock;
DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);
};
-struct idpf_vc_xn_manager;
-
#define idpf_for_each_vport(adapter, iter) \
for (struct idpf_vport **__##iter = &(adapter)->vports[0], \
*iter = (adapter)->max_vports ? *__##iter : NULL; \
@@ -587,7 +621,10 @@ struct idpf_vc_xn_manager;
* @state: Init state machine
* @flags: See enum idpf_flags
* @reset_reg: See struct idpf_reset_reg
- * @hw: Device access data
+ * @ctlq_ctx: controlq context
+ * @asq: Send control queue info
+ * @arq: Receive control queue info
+ * @xnm: Xn transaction manager
* @num_avail_msix: Available number of MSIX vectors
* @num_msix_entries: Number of entries in MSIX table
* @msix_entries: MSIX table
@@ -601,9 +638,10 @@ struct idpf_vc_xn_manager;
* @avail_queues: Device given queue limits
* @vports: Array to store vports created by the driver
* @netdevs: Associated Vport netdevs
- * @vport_params_reqd: Vport params requested
* @vport_params_recvd: Vport params received
* @vport_ids: Array of device given vport identifiers
+ * @singleq_pt_lkup: Lookup table for singleq RX ptypes
+ * @splitq_pt_lkup: Lookup table for splitq RX ptypes
* @vport_config: Vport config parameters
* @max_vports: Maximum vports that can be allocated
* @num_alloc_vports: Current number of vports allocated
@@ -619,7 +657,6 @@ struct idpf_vc_xn_manager;
* @stats_task: Periodic statistics retrieval task
* @stats_wq: Workqueue for statistics task
* @caps: Negotiated capabilities with device
- * @vcxn_mngr: Virtchnl transaction manager
* @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
@@ -643,7 +680,10 @@ struct idpf_adapter {
enum idpf_state state;
DECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);
struct idpf_reset_reg reset_reg;
- struct idpf_hw hw;
+ struct libie_ctlq_ctx ctlq_ctx;
+ struct libie_ctlq_info *asq;
+ struct libie_ctlq_info *arq;
+ struct libie_ctlq_xn_manager *xnm;
u16 num_avail_msix;
u16 num_msix_entries;
struct msix_entry *msix_entries;
@@ -658,10 +698,12 @@ struct idpf_adapter {
struct idpf_avail_queue_info avail_queues;
struct idpf_vport **vports;
struct net_device **netdevs;
- struct virtchnl2_create_vport **vport_params_reqd;
struct virtchnl2_create_vport **vport_params_recvd;
u32 *vport_ids;
+ struct libeth_rx_pt *singleq_pt_lkup;
+ struct libeth_rx_pt *splitq_pt_lkup;
+
struct idpf_vport_config **vport_config;
u16 max_vports;
u16 num_alloc_vports;
@@ -678,7 +720,6 @@ struct idpf_adapter {
struct delayed_work stats_task;
struct workqueue_struct *stats_wq;
struct virtchnl2_get_capabilities caps;
- struct idpf_vc_xn_manager *vcxn_mngr;
struct idpf_dev_ops dev_ops;
struct iidc_rdma_core_dev_info *cdev_info;
@@ -831,70 +872,6 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)
}
/**
- * idpf_get_mbx_reg_addr - Get BAR0 mailbox register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Return: BAR0 mailbox register address based on register offset.
- */
-static inline void __iomem *idpf_get_mbx_reg_addr(struct idpf_adapter *adapter,
- resource_size_t reg_offset)
-{
- return adapter->hw.mbx.vaddr + reg_offset;
-}
-
-/**
- * idpf_get_rstat_reg_addr - Get BAR0 rstat register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Return: BAR0 rstat register address based on register offset.
- */
-static inline void __iomem *idpf_get_rstat_reg_addr(struct idpf_adapter *adapter,
- resource_size_t reg_offset)
-{
- reg_offset -= adapter->dev_ops.static_reg_info[1].start;
-
- return adapter->hw.rstat.vaddr + reg_offset;
-}
-
-/**
- * idpf_get_reg_addr - Get BAR0 register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Based on the register offset, return the actual BAR0 register address
- */
-static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,
- resource_size_t reg_offset)
-{
- struct idpf_hw *hw = &adapter->hw;
-
- for (int i = 0; i < hw->num_lan_regs; i++) {
- struct idpf_mmio_reg *region = &hw->lan_regs[i];
-
- if (reg_offset >= region->addr_start &&
- reg_offset < (region->addr_start + region->addr_len)) {
- /* Convert the offset so that it is relative to the
- * start of the region. Then add the base address of
- * the region to get the final address.
- */
- reg_offset -= region->addr_start;
-
- return region->vaddr + reg_offset;
- }
- }
-
- /* It's impossible to hit this case with offsets from the CP. But if we
- * do for any other reason, the kernel will panic on that register
- * access. Might as well do it here to make it clear what's happening.
- */
- BUG();
-
- return NULL;
-}
-
-/**
* idpf_is_reset_detected - check if we were reset at some point
* @adapter: driver specific private structure
*
@@ -902,11 +879,12 @@ static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,
*/
static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)
{
- if (!adapter->hw.arq)
+ struct libie_ctlq_info *arq = adapter->arq;
+
+ if (!arq)
return true;
- return !(readl(idpf_get_mbx_reg_addr(adapter, adapter->hw.arq->reg.len)) &
- adapter->hw.arq->reg.len_mask);
+ return !(readl(arq->reg.len) & arq->reg.len_mask);
}
/**
@@ -1006,6 +984,7 @@ void idpf_vc_event_task(struct work_struct *work);
void idpf_dev_ops_init(struct idpf_adapter *adapter);
void idpf_vf_dev_ops_init(struct idpf_adapter *adapter);
int idpf_intr_req(struct idpf_adapter *adapter);
+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter);
void idpf_intr_rel(struct idpf_adapter *adapter);
u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter);
int idpf_initiate_soft_reset(struct idpf_vport *vport,
@@ -1024,7 +1003,7 @@ bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val);
int idpf_idc_init(struct idpf_adapter *adapter);
int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
enum iidc_function_type ftype);
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info);
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter);
void idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info *vdev_info);
void idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info *cdev_info);
void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c
deleted file mode 100644
index 67894eda2d29..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c
+++ /dev/null
@@ -1,623 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2023 Intel Corporation */
-
-#include "idpf_controlq.h"
-
-/**
- * idpf_ctlq_setup_regs - initialize control queue registers
- * @cq: pointer to the specific control queue
- * @q_create_info: structs containing info for each queue to be initialized
- */
-static void idpf_ctlq_setup_regs(struct idpf_ctlq_info *cq,
- struct idpf_ctlq_create_info *q_create_info)
-{
- /* set control queue registers in our local struct */
- cq->reg.head = q_create_info->reg.head;
- cq->reg.tail = q_create_info->reg.tail;
- cq->reg.len = q_create_info->reg.len;
- cq->reg.bah = q_create_info->reg.bah;
- cq->reg.bal = q_create_info->reg.bal;
- cq->reg.len_mask = q_create_info->reg.len_mask;
- cq->reg.len_ena_mask = q_create_info->reg.len_ena_mask;
- cq->reg.head_mask = q_create_info->reg.head_mask;
-}
-
-/**
- * idpf_ctlq_init_regs - Initialize control queue registers
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- * @is_rxq: true if receive control queue, false otherwise
- *
- * Initialize registers. The caller is expected to have already initialized the
- * descriptor ring memory and buffer memory
- */
-static void idpf_ctlq_init_regs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
- bool is_rxq)
-{
- /* Update tail to post pre-allocated buffers for rx queues */
- if (is_rxq)
- idpf_mbx_wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));
-
- /* For non-Mailbox control queues only TAIL need to be set */
- if (cq->q_id != -1)
- return;
-
- /* Clear Head for both send or receive */
- idpf_mbx_wr32(hw, cq->reg.head, 0);
-
- /* set starting point */
- idpf_mbx_wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
- idpf_mbx_wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
- idpf_mbx_wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
-}
-
-/**
- * idpf_ctlq_init_rxq_bufs - populate receive queue descriptors with buf
- * @cq: pointer to the specific Control queue
- *
- * Record the address of the receive queue DMA buffers in the descriptors.
- * The buffers must have been previously allocated.
- */
-static void idpf_ctlq_init_rxq_bufs(struct idpf_ctlq_info *cq)
-{
- int i;
-
- for (i = 0; i < cq->ring_size; i++) {
- struct idpf_ctlq_desc *desc = IDPF_CTLQ_DESC(cq, i);
- struct idpf_dma_mem *bi = cq->bi.rx_buff[i];
-
- /* No buffer to post to descriptor, continue */
- if (!bi)
- continue;
-
- desc->flags =
- cpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);
- desc->opcode = 0;
- desc->datalen = cpu_to_le16(bi->size);
- desc->ret_val = 0;
- desc->v_opcode_dtype = 0;
- desc->v_retval = 0;
- desc->params.indirect.addr_high =
- cpu_to_le32(upper_32_bits(bi->pa));
- desc->params.indirect.addr_low =
- cpu_to_le32(lower_32_bits(bi->pa));
- desc->params.indirect.param0 = 0;
- desc->params.indirect.sw_cookie = 0;
- desc->params.indirect.v_flags = 0;
- }
-}
-
-/**
- * idpf_ctlq_shutdown - shutdown the CQ
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * The main shutdown routine for any controq queue
- */
-static void idpf_ctlq_shutdown(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- spin_lock(&cq->cq_lock);
-
- /* free ring buffers and the ring itself */
- idpf_ctlq_dealloc_ring_res(hw, cq);
-
- /* Set ring_size to 0 to indicate uninitialized queue */
- cq->ring_size = 0;
-
- spin_unlock(&cq->cq_lock);
-}
-
-/**
- * idpf_ctlq_add - add one control queue
- * @hw: pointer to hardware struct
- * @qinfo: info for queue to be created
- * @cq_out: (output) double pointer to control queue to be created
- *
- * Allocate and initialize a control queue and add it to the control queue list.
- * The cq parameter will be allocated/initialized and passed back to the caller
- * if no errors occur.
- *
- * Note: idpf_ctlq_init must be called prior to any calls to idpf_ctlq_add
- */
-int idpf_ctlq_add(struct idpf_hw *hw,
- struct idpf_ctlq_create_info *qinfo,
- struct idpf_ctlq_info **cq_out)
-{
- struct idpf_ctlq_info *cq;
- bool is_rxq = false;
- int err;
-
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return -ENOMEM;
-
- cq->cq_type = qinfo->type;
- cq->q_id = qinfo->id;
- cq->buf_size = qinfo->buf_size;
- cq->ring_size = qinfo->len;
-
- cq->next_to_use = 0;
- cq->next_to_clean = 0;
- cq->next_to_post = cq->ring_size - 1;
-
- switch (qinfo->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_RX:
- is_rxq = true;
- fallthrough;
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- err = idpf_ctlq_alloc_ring_res(hw, cq);
- break;
- default:
- err = -EBADR;
- break;
- }
-
- if (err)
- goto init_free_q;
-
- if (is_rxq) {
- idpf_ctlq_init_rxq_bufs(cq);
- } else {
- /* Allocate the array of msg pointers for TX queues */
- cq->bi.tx_msg = kcalloc(qinfo->len,
- sizeof(struct idpf_ctlq_msg *),
- GFP_KERNEL);
- if (!cq->bi.tx_msg) {
- err = -ENOMEM;
- goto init_dealloc_q_mem;
- }
- }
-
- idpf_ctlq_setup_regs(cq, qinfo);
-
- idpf_ctlq_init_regs(hw, cq, is_rxq);
-
- spin_lock_init(&cq->cq_lock);
-
- list_add(&cq->cq_list, &hw->cq_list_head);
-
- *cq_out = cq;
-
- return 0;
-
-init_dealloc_q_mem:
- /* free ring buffers and the ring itself */
- idpf_ctlq_dealloc_ring_res(hw, cq);
-init_free_q:
- kfree(cq);
-
- return err;
-}
-
-/**
- * idpf_ctlq_remove - deallocate and remove specified control queue
- * @hw: pointer to hardware struct
- * @cq: pointer to control queue to be removed
- */
-void idpf_ctlq_remove(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- list_del(&cq->cq_list);
- idpf_ctlq_shutdown(hw, cq);
- kfree(cq);
-}
-
-/**
- * idpf_ctlq_init - main initialization routine for all control queues
- * @hw: pointer to hardware struct
- * @num_q: number of queues to initialize
- * @q_info: array of structs containing info for each queue to be initialized
- *
- * This initializes any number and any type of control queues. This is an all
- * or nothing routine; if one fails, all previously allocated queues will be
- * destroyed. This must be called prior to using the individual add/remove
- * APIs.
- */
-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
- struct idpf_ctlq_create_info *q_info)
-{
- struct idpf_ctlq_info *cq, *tmp;
- int err;
- int i;
-
- INIT_LIST_HEAD(&hw->cq_list_head);
-
- for (i = 0; i < num_q; i++) {
- struct idpf_ctlq_create_info *qinfo = q_info + i;
-
- err = idpf_ctlq_add(hw, qinfo, &cq);
- if (err)
- goto init_destroy_qs;
- }
-
- return 0;
-
-init_destroy_qs:
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- idpf_ctlq_remove(hw, cq);
-
- return err;
-}
-
-/**
- * idpf_ctlq_deinit - destroy all control queues
- * @hw: pointer to hw struct
- */
-void idpf_ctlq_deinit(struct idpf_hw *hw)
-{
- struct idpf_ctlq_info *cq, *tmp;
-
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- idpf_ctlq_remove(hw, cq);
-}
-
-/**
- * idpf_ctlq_send - send command to Control Queue (CTQ)
- * @hw: pointer to hw struct
- * @cq: handle to control queue struct to send on
- * @num_q_msg: number of messages to send on control queue
- * @q_msg: pointer to array of queue messages to be sent
- *
- * The caller is expected to allocate DMAable buffers and pass them to the
- * send routine via the q_msg struct / control queue specific data struct.
- * The control queue will hold a reference to each send message until
- * the completion for that message has been cleaned.
- */
-int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
- u16 num_q_msg, struct idpf_ctlq_msg q_msg[])
-{
- struct idpf_ctlq_desc *desc;
- int num_desc_avail;
- int err = 0;
- int i;
-
- spin_lock(&cq->cq_lock);
-
- /* Ensure there are enough descriptors to send all messages */
- num_desc_avail = IDPF_CTLQ_DESC_UNUSED(cq);
- if (num_desc_avail == 0 || num_desc_avail < num_q_msg) {
- err = -ENOSPC;
- goto err_unlock;
- }
-
- for (i = 0; i < num_q_msg; i++) {
- struct idpf_ctlq_msg *msg = &q_msg[i];
-
- desc = IDPF_CTLQ_DESC(cq, cq->next_to_use);
-
- desc->opcode = cpu_to_le16(msg->opcode);
- desc->pfid_vfid = cpu_to_le16(msg->func_id);
-
- desc->v_opcode_dtype = cpu_to_le32(msg->cookie.mbx.chnl_opcode);
- desc->v_retval = cpu_to_le32(msg->cookie.mbx.chnl_retval);
-
- desc->flags = cpu_to_le16((msg->host_id & IDPF_HOST_ID_MASK) <<
- IDPF_CTLQ_FLAG_HOST_ID_S);
- if (msg->data_len) {
- struct idpf_dma_mem *buff = msg->ctx.indirect.payload;
-
- desc->datalen |= cpu_to_le16(msg->data_len);
- desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_BUF);
- desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_RD);
-
- /* Update the address values in the desc with the pa
- * value for respective buffer
- */
- desc->params.indirect.addr_high =
- cpu_to_le32(upper_32_bits(buff->pa));
- desc->params.indirect.addr_low =
- cpu_to_le32(lower_32_bits(buff->pa));
-
- memcpy(&desc->params, msg->ctx.indirect.context,
- IDPF_INDIRECT_CTX_SIZE);
- } else {
- memcpy(&desc->params, msg->ctx.direct,
- IDPF_DIRECT_CTX_SIZE);
- }
-
- /* Store buffer info */
- cq->bi.tx_msg[cq->next_to_use] = msg;
-
- (cq->next_to_use)++;
- if (cq->next_to_use == cq->ring_size)
- cq->next_to_use = 0;
- }
-
- /* Force memory write to complete before letting hardware
- * know that there are new descriptors to fetch.
- */
- dma_wmb();
-
- idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_use);
-
-err_unlock:
- spin_unlock(&cq->cq_lock);
-
- return err;
-}
-
-/**
- * idpf_ctlq_clean_sq - reclaim send descriptors on HW write back for the
- * requested queue
- * @cq: pointer to the specific Control queue
- * @clean_count: (input|output) number of descriptors to clean as input, and
- * number of descriptors actually cleaned as output
- * @msg_status: (output) pointer to msg pointer array to be populated; needs
- * to be allocated by caller
- *
- * Returns an array of message pointers associated with the cleaned
- * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned
- * descriptors. The status will be returned for each; any messages that failed
- * to send will have a non-zero status. The caller is expected to free original
- * ctlq_msgs and free or reuse the DMA buffers.
- */
-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
- struct idpf_ctlq_msg *msg_status[])
-{
- struct idpf_ctlq_desc *desc;
- u16 i, num_to_clean;
- u16 ntc, desc_err;
-
- if (*clean_count == 0)
- return 0;
- if (*clean_count > cq->ring_size)
- return -EBADR;
-
- spin_lock(&cq->cq_lock);
-
- ntc = cq->next_to_clean;
-
- num_to_clean = *clean_count;
-
- for (i = 0; i < num_to_clean; i++) {
- /* Fetch next descriptor and check if marked as done */
- desc = IDPF_CTLQ_DESC(cq, ntc);
- if (!(le16_to_cpu(desc->flags) & IDPF_CTLQ_FLAG_DD))
- break;
-
- /* Ensure no other fields are read until DD flag is checked */
- dma_rmb();
-
- /* strip off FW internal code */
- desc_err = le16_to_cpu(desc->ret_val) & 0xff;
-
- msg_status[i] = cq->bi.tx_msg[ntc];
- msg_status[i]->status = desc_err;
-
- cq->bi.tx_msg[ntc] = NULL;
-
- /* Zero out any stale data */
- memset(desc, 0, sizeof(*desc));
-
- ntc++;
- if (ntc == cq->ring_size)
- ntc = 0;
- }
-
- cq->next_to_clean = ntc;
-
- spin_unlock(&cq->cq_lock);
-
- /* Return number of descriptors actually cleaned */
- *clean_count = i;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_post_rx_buffs - post buffers to descriptor ring
- * @hw: pointer to hw struct
- * @cq: pointer to control queue handle
- * @buff_count: (input|output) input is number of buffers caller is trying to
- * return; output is number of buffers that were not posted
- * @buffs: array of pointers to dma mem structs to be given to hardware
- *
- * Caller uses this function to return DMA buffers to the descriptor ring after
- * consuming them; buff_count will be the number of buffers.
- *
- * Note: this function needs to be called after a receive call even
- * if there are no DMA buffers to be returned, i.e. buff_count = 0,
- * buffs = NULL to support direct commands
- */
-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
- u16 *buff_count, struct idpf_dma_mem **buffs)
-{
- struct idpf_ctlq_desc *desc;
- u16 ntp = cq->next_to_post;
- bool buffs_avail = false;
- u16 tbp = ntp + 1;
- int i = 0;
-
- if (*buff_count > cq->ring_size)
- return -EBADR;
-
- if (*buff_count > 0)
- buffs_avail = true;
-
- spin_lock(&cq->cq_lock);
-
- if (tbp >= cq->ring_size)
- tbp = 0;
-
- if (tbp == cq->next_to_clean)
- /* Nothing to do */
- goto post_buffs_out;
-
- /* Post buffers for as many as provided or up until the last one used */
- while (ntp != cq->next_to_clean) {
- desc = IDPF_CTLQ_DESC(cq, ntp);
-
- if (cq->bi.rx_buff[ntp])
- goto fill_desc;
- if (!buffs_avail) {
- /* If the caller hasn't given us any buffers or
- * there are none left, search the ring itself
- * for an available buffer to move to this
- * entry starting at the next entry in the ring
- */
- tbp = ntp + 1;
-
- /* Wrap ring if necessary */
- if (tbp >= cq->ring_size)
- tbp = 0;
-
- while (tbp != cq->next_to_clean) {
- if (cq->bi.rx_buff[tbp]) {
- cq->bi.rx_buff[ntp] =
- cq->bi.rx_buff[tbp];
- cq->bi.rx_buff[tbp] = NULL;
-
- /* Found a buffer, no need to
- * search anymore
- */
- break;
- }
-
- /* Wrap ring if necessary */
- tbp++;
- if (tbp >= cq->ring_size)
- tbp = 0;
- }
-
- if (tbp == cq->next_to_clean)
- goto post_buffs_out;
- } else {
- /* Give back pointer to DMA buffer */
- cq->bi.rx_buff[ntp] = buffs[i];
- i++;
-
- if (i >= *buff_count)
- buffs_avail = false;
- }
-
-fill_desc:
- desc->flags =
- cpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);
-
- /* Post buffers to descriptor */
- desc->datalen = cpu_to_le16(cq->bi.rx_buff[ntp]->size);
- desc->params.indirect.addr_high =
- cpu_to_le32(upper_32_bits(cq->bi.rx_buff[ntp]->pa));
- desc->params.indirect.addr_low =
- cpu_to_le32(lower_32_bits(cq->bi.rx_buff[ntp]->pa));
-
- ntp++;
- if (ntp == cq->ring_size)
- ntp = 0;
- }
-
-post_buffs_out:
- /* Only update tail if buffers were actually posted */
- if (cq->next_to_post != ntp) {
- if (ntp)
- /* Update next_to_post to ntp - 1 since current ntp
- * will not have a buffer
- */
- cq->next_to_post = ntp - 1;
- else
- /* Wrap to end of end ring since current ntp is 0 */
- cq->next_to_post = cq->ring_size - 1;
-
- dma_wmb();
-
- idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_post);
- }
-
- spin_unlock(&cq->cq_lock);
-
- /* return the number of buffers that were not posted */
- *buff_count = *buff_count - i;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_recv - receive control queue message call back
- * @cq: pointer to control queue handle to receive on
- * @num_q_msg: (input|output) input number of messages that should be received;
- * output number of messages actually received
- * @q_msg: (output) array of received control queue messages on this q;
- * needs to be pre-allocated by caller for as many messages as requested
- *
- * Called by interrupt handler or polling mechanism. Caller is expected
- * to free buffers
- */
-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
- struct idpf_ctlq_msg *q_msg)
-{
- u16 num_to_clean, ntc, flags;
- struct idpf_ctlq_desc *desc;
- int err = 0;
- u16 i;
-
- /* take the lock before we start messing with the ring */
- spin_lock(&cq->cq_lock);
-
- ntc = cq->next_to_clean;
-
- num_to_clean = *num_q_msg;
-
- for (i = 0; i < num_to_clean; i++) {
- /* Fetch next descriptor and check if marked as done */
- desc = IDPF_CTLQ_DESC(cq, ntc);
- flags = le16_to_cpu(desc->flags);
-
- if (!(flags & IDPF_CTLQ_FLAG_DD))
- break;
-
- /* Ensure no other fields are read until DD flag is checked */
- dma_rmb();
-
- q_msg[i].vmvf_type = (flags &
- (IDPF_CTLQ_FLAG_FTYPE_VM |
- IDPF_CTLQ_FLAG_FTYPE_PF)) >>
- IDPF_CTLQ_FLAG_FTYPE_S;
-
- if (flags & IDPF_CTLQ_FLAG_ERR)
- err = -EBADMSG;
-
- q_msg[i].cookie.mbx.chnl_opcode =
- le32_to_cpu(desc->v_opcode_dtype);
- q_msg[i].cookie.mbx.chnl_retval =
- le32_to_cpu(desc->v_retval);
-
- q_msg[i].opcode = le16_to_cpu(desc->opcode);
- q_msg[i].data_len = le16_to_cpu(desc->datalen);
- q_msg[i].status = le16_to_cpu(desc->ret_val);
-
- if (desc->datalen) {
- memcpy(q_msg[i].ctx.indirect.context,
- &desc->params.indirect, IDPF_INDIRECT_CTX_SIZE);
-
- /* Assign pointer to dma buffer to ctlq_msg array
- * to be given to upper layer
- */
- q_msg[i].ctx.indirect.payload = cq->bi.rx_buff[ntc];
-
- /* Zero out pointer to DMA buffer info;
- * will be repopulated by post buffers API
- */
- cq->bi.rx_buff[ntc] = NULL;
- } else {
- memcpy(q_msg[i].ctx.direct, desc->params.raw,
- IDPF_DIRECT_CTX_SIZE);
- }
-
- /* Zero out stale data in descriptor */
- memset(desc, 0, sizeof(struct idpf_ctlq_desc));
-
- ntc++;
- if (ntc == cq->ring_size)
- ntc = 0;
- }
-
- cq->next_to_clean = ntc;
-
- spin_unlock(&cq->cq_lock);
-
- *num_q_msg = i;
- if (*num_q_msg == 0)
- err = -ENOMSG;
-
- return err;
-}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.h b/drivers/net/ethernet/intel/idpf/idpf_controlq.h
deleted file mode 100644
index de4ece40c2ff..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_CONTROLQ_H_
-#define _IDPF_CONTROLQ_H_
-
-#include <linux/slab.h>
-
-#include "idpf_controlq_api.h"
-
-/* Maximum buffer length for all control queue types */
-#define IDPF_CTLQ_MAX_BUF_LEN 4096
-
-#define IDPF_CTLQ_DESC(R, i) \
- (&(((struct idpf_ctlq_desc *)((R)->desc_ring.va))[i]))
-
-#define IDPF_CTLQ_DESC_UNUSED(R) \
- ((u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->ring_size) + \
- (R)->next_to_clean - (R)->next_to_use - 1))
-
-/* Control Queue default settings */
-#define IDPF_CTRL_SQ_CMD_TIMEOUT 250 /* msecs */
-
-struct idpf_ctlq_desc {
- /* Control queue descriptor flags */
- __le16 flags;
- /* Control queue message opcode */
- __le16 opcode;
- __le16 datalen; /* 0 for direct commands */
- union {
- __le16 ret_val;
- __le16 pfid_vfid;
-#define IDPF_CTLQ_DESC_VF_ID_S 0
-#define IDPF_CTLQ_DESC_VF_ID_M (0x7FF << IDPF_CTLQ_DESC_VF_ID_S)
-#define IDPF_CTLQ_DESC_PF_ID_S 11
-#define IDPF_CTLQ_DESC_PF_ID_M (0x1F << IDPF_CTLQ_DESC_PF_ID_S)
- };
-
- /* Virtchnl message opcode and virtchnl descriptor type
- * v_opcode=[27:0], v_dtype=[31:28]
- */
- __le32 v_opcode_dtype;
- /* Virtchnl return value */
- __le32 v_retval;
- union {
- struct {
- __le32 param0;
- __le32 param1;
- __le32 param2;
- __le32 param3;
- } direct;
- struct {
- __le32 param0;
- __le16 sw_cookie;
- /* Virtchnl flags */
- __le16 v_flags;
- __le32 addr_high;
- __le32 addr_low;
- } indirect;
- u8 raw[16];
- } params;
-};
-
-/* Flags sub-structure
- * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
- * |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| HOST_ID |
- */
-/* command flags and offsets */
-#define IDPF_CTLQ_FLAG_DD_S 0
-#define IDPF_CTLQ_FLAG_CMP_S 1
-#define IDPF_CTLQ_FLAG_ERR_S 2
-#define IDPF_CTLQ_FLAG_FTYPE_S 6
-#define IDPF_CTLQ_FLAG_RD_S 10
-#define IDPF_CTLQ_FLAG_VFC_S 11
-#define IDPF_CTLQ_FLAG_BUF_S 12
-#define IDPF_CTLQ_FLAG_HOST_ID_S 13
-
-#define IDPF_CTLQ_FLAG_DD BIT(IDPF_CTLQ_FLAG_DD_S) /* 0x1 */
-#define IDPF_CTLQ_FLAG_CMP BIT(IDPF_CTLQ_FLAG_CMP_S) /* 0x2 */
-#define IDPF_CTLQ_FLAG_ERR BIT(IDPF_CTLQ_FLAG_ERR_S) /* 0x4 */
-#define IDPF_CTLQ_FLAG_FTYPE_VM BIT(IDPF_CTLQ_FLAG_FTYPE_S) /* 0x40 */
-#define IDPF_CTLQ_FLAG_FTYPE_PF BIT(IDPF_CTLQ_FLAG_FTYPE_S + 1) /* 0x80 */
-#define IDPF_CTLQ_FLAG_RD BIT(IDPF_CTLQ_FLAG_RD_S) /* 0x400 */
-#define IDPF_CTLQ_FLAG_VFC BIT(IDPF_CTLQ_FLAG_VFC_S) /* 0x800 */
-#define IDPF_CTLQ_FLAG_BUF BIT(IDPF_CTLQ_FLAG_BUF_S) /* 0x1000 */
-
-/* Host ID is a special field that has 3b and not a 1b flag */
-#define IDPF_CTLQ_FLAG_HOST_ID_M MAKE_MASK(0x7000UL, IDPF_CTLQ_FLAG_HOST_ID_S)
-
-struct idpf_mbxq_desc {
- u8 pad[8]; /* CTLQ flags/opcode/len/retval fields */
- u32 chnl_opcode; /* avoid confusion with desc->opcode */
- u32 chnl_retval; /* ditto for desc->retval */
- u32 pf_vf_id; /* used by CP when sending to PF */
-};
-
-/* Max number of MMIO regions not including the mailbox and rstat regions in
- * the fallback case when the whole bar is mapped.
- */
-#define IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING 3
-
-struct idpf_mmio_reg {
- void __iomem *vaddr;
- resource_size_t addr_start;
- resource_size_t addr_len;
-};
-
-/* Define the driver hardware struct to replace other control structs as needed
- * Align to ctlq_hw_info
- */
-struct idpf_hw {
- struct idpf_mmio_reg mbx;
- struct idpf_mmio_reg rstat;
- /* Array of remaining LAN BAR regions */
- int num_lan_regs;
- struct idpf_mmio_reg *lan_regs;
-
- struct idpf_adapter *back;
-
- /* control queue - send and receive */
- struct idpf_ctlq_info *asq;
- struct idpf_ctlq_info *arq;
-
- /* pci info */
- u16 device_id;
- u16 vendor_id;
- u16 subsystem_device_id;
- u16 subsystem_vendor_id;
- u8 revision_id;
- bool adapter_stopped;
-
- struct list_head cq_list_head;
-};
-
-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq);
-
-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq);
-
-/* prototype for functions used for dynamic memory allocation */
-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem,
- u64 size);
-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem);
-#endif /* _IDPF_CONTROLQ_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
deleted file mode 100644
index 3414c5f9a831..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_CONTROLQ_API_H_
-#define _IDPF_CONTROLQ_API_H_
-
-#include "idpf_mem.h"
-
-struct idpf_hw;
-
-/* Used for queue init, response and events */
-enum idpf_ctlq_type {
- IDPF_CTLQ_TYPE_MAILBOX_TX = 0,
- IDPF_CTLQ_TYPE_MAILBOX_RX = 1,
- IDPF_CTLQ_TYPE_CONFIG_TX = 2,
- IDPF_CTLQ_TYPE_CONFIG_RX = 3,
- IDPF_CTLQ_TYPE_EVENT_RX = 4,
- IDPF_CTLQ_TYPE_RDMA_TX = 5,
- IDPF_CTLQ_TYPE_RDMA_RX = 6,
- IDPF_CTLQ_TYPE_RDMA_COMPL = 7
-};
-
-/* Generic Control Queue Structures */
-struct idpf_ctlq_reg {
- /* used for queue tracking */
- u32 head;
- u32 tail;
- /* Below applies only to default mb (if present) */
- u32 len;
- u32 bah;
- u32 bal;
- u32 len_mask;
- u32 len_ena_mask;
- u32 head_mask;
-};
-
-/* Generic queue msg structure */
-struct idpf_ctlq_msg {
- u8 vmvf_type; /* represents the source of the message on recv */
-#define IDPF_VMVF_TYPE_VF 0
-#define IDPF_VMVF_TYPE_VM 1
-#define IDPF_VMVF_TYPE_PF 2
- u8 host_id;
- /* 3b field used only when sending a message to CP - to be used in
- * combination with target func_id to route the message
- */
-#define IDPF_HOST_ID_MASK 0x7
-
- u16 opcode;
- u16 data_len; /* data_len = 0 when no payload is attached */
- union {
- u16 func_id; /* when sending a message */
- u16 status; /* when receiving a message */
- };
- union {
- struct {
- u32 chnl_opcode;
- u32 chnl_retval;
- } mbx;
- } cookie;
- union {
-#define IDPF_DIRECT_CTX_SIZE 16
-#define IDPF_INDIRECT_CTX_SIZE 8
- /* 16 bytes of context can be provided or 8 bytes of context
- * plus the address of a DMA buffer
- */
- u8 direct[IDPF_DIRECT_CTX_SIZE];
- struct {
- u8 context[IDPF_INDIRECT_CTX_SIZE];
- struct idpf_dma_mem *payload;
- } indirect;
- struct {
- u32 rsvd;
- u16 data;
- u16 flags;
- } sw_cookie;
- } ctx;
-};
-
-/* Generic queue info structures */
-/* MB, CONFIG and EVENT q do not have extended info */
-struct idpf_ctlq_create_info {
- enum idpf_ctlq_type type;
- int id; /* absolute queue offset passed as input
- * -1 for default mailbox if present
- */
- u16 len; /* Queue length passed as input */
- u16 buf_size; /* buffer size passed as input */
- u64 base_address; /* output, HPA of the Queue start */
- struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
-
- int ext_info_size;
- void *ext_info; /* Specific to q type */
-};
-
-/* Control Queue information */
-struct idpf_ctlq_info {
- struct list_head cq_list;
-
- enum idpf_ctlq_type cq_type;
- int q_id;
- spinlock_t cq_lock; /* control queue lock */
- /* used for interrupt processing */
- u16 next_to_use;
- u16 next_to_clean;
- u16 next_to_post; /* starting descriptor to post buffers
- * to after recev
- */
-
- struct idpf_dma_mem desc_ring; /* descriptor ring memory
- * idpf_dma_mem is defined in OSdep.h
- */
- union {
- struct idpf_dma_mem **rx_buff;
- struct idpf_ctlq_msg **tx_msg;
- } bi;
-
- u16 buf_size; /* queue buffer size */
- u16 ring_size; /* Number of descriptors */
- struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
-};
-
-/**
- * enum idpf_mbx_opc - PF/VF mailbox commands
- * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP
- * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to
- * any peer driver
- */
-enum idpf_mbx_opc {
- idpf_mbq_opc_send_msg_to_cp = 0x0801,
- idpf_mbq_opc_send_msg_to_peer_drv = 0x0804,
-};
-
-/* API supported for control queue management */
-/* Will init all required q including default mb. "q_info" is an array of
- * create_info structs equal to the number of control queues to be created.
- */
-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
- struct idpf_ctlq_create_info *q_info);
-
-/* Allocate and initialize a single control queue, which will be added to the
- * control queue list; returns a handle to the created control queue
- */
-int idpf_ctlq_add(struct idpf_hw *hw,
- struct idpf_ctlq_create_info *qinfo,
- struct idpf_ctlq_info **cq);
-
-/* Deinitialize and deallocate a single control queue */
-void idpf_ctlq_remove(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq);
-
-/* Sends messages to HW and will also free the buffer*/
-int idpf_ctlq_send(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq,
- u16 num_q_msg,
- struct idpf_ctlq_msg q_msg[]);
-
-/* Receives messages and called by interrupt handler/polling
- * initiated by app/process. Also caller is supposed to free the buffers
- */
-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
- struct idpf_ctlq_msg *q_msg);
-
-/* Reclaims send descriptors on HW write back */
-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
- struct idpf_ctlq_msg *msg_status[]);
-
-/* Indicate RX buffers are done being processed */
-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq,
- u16 *buff_count,
- struct idpf_dma_mem **buffs);
-
-/* Will destroy all q including the default mb */
-void idpf_ctlq_deinit(struct idpf_hw *hw);
-
-#endif /* _IDPF_CONTROLQ_API_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c b/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
deleted file mode 100644
index a942a6385d06..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2023 Intel Corporation */
-
-#include "idpf_controlq.h"
-
-/**
- * idpf_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- */
-static int idpf_ctlq_alloc_desc_ring(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- size_t size = cq->ring_size * sizeof(struct idpf_ctlq_desc);
-
- cq->desc_ring.va = idpf_alloc_dma_mem(hw, &cq->desc_ring, size);
- if (!cq->desc_ring.va)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Allocate the buffer head for all control queues, and if it's a receive
- * queue, allocate DMA buffers
- */
-static int idpf_ctlq_alloc_bufs(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- int i;
-
- /* Do not allocate DMA buffers for transmit queues */
- if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_TX)
- return 0;
-
- /* We'll be allocating the buffer info memory first, then we can
- * allocate the mapped buffers for the event processing
- */
- cq->bi.rx_buff = kcalloc(cq->ring_size, sizeof(struct idpf_dma_mem *),
- GFP_KERNEL);
- if (!cq->bi.rx_buff)
- return -ENOMEM;
-
- /* allocate the mapped buffers (except for the last one) */
- for (i = 0; i < cq->ring_size - 1; i++) {
- struct idpf_dma_mem *bi;
- int num = 1; /* number of idpf_dma_mem to be allocated */
-
- cq->bi.rx_buff[i] = kcalloc(num, sizeof(struct idpf_dma_mem),
- GFP_KERNEL);
- if (!cq->bi.rx_buff[i])
- goto unwind_alloc_cq_bufs;
-
- bi = cq->bi.rx_buff[i];
-
- bi->va = idpf_alloc_dma_mem(hw, bi, cq->buf_size);
- if (!bi->va) {
- /* unwind will not free the failed entry */
- kfree(cq->bi.rx_buff[i]);
- goto unwind_alloc_cq_bufs;
- }
- }
-
- return 0;
-
-unwind_alloc_cq_bufs:
- /* don't try to free the one that failed... */
- i--;
- for (; i >= 0; i--) {
- idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
- kfree(cq->bi.rx_buff[i]);
- }
- kfree(cq->bi.rx_buff);
-
- return -ENOMEM;
-}
-
-/**
- * idpf_ctlq_free_desc_ring - Free Control Queue (CQ) rings
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * This assumes the posted send buffers have already been cleaned
- * and de-allocated
- */
-static void idpf_ctlq_free_desc_ring(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- idpf_free_dma_mem(hw, &cq->desc_ring);
-}
-
-/**
- * idpf_ctlq_free_bufs - Free CQ buffer info elements
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX
- * queues. The upper layers are expected to manage freeing of TX DMA buffers
- */
-static void idpf_ctlq_free_bufs(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- void *bi;
-
- if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_RX) {
- int i;
-
- /* free DMA buffers for rx queues*/
- for (i = 0; i < cq->ring_size; i++) {
- if (cq->bi.rx_buff[i]) {
- idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
- kfree(cq->bi.rx_buff[i]);
- }
- }
-
- bi = (void *)cq->bi.rx_buff;
- } else {
- bi = (void *)cq->bi.tx_msg;
- }
-
- /* free the buffer header */
- kfree(bi);
-}
-
-/**
- * idpf_ctlq_dealloc_ring_res - Free memory allocated for control queue
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Free the memory used by the ring, buffers and other related structures
- */
-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- /* free ring buffers and the ring itself */
- idpf_ctlq_free_bufs(hw, cq);
- idpf_ctlq_free_desc_ring(hw, cq);
-}
-
-/**
- * idpf_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs
- * @hw: pointer to hw struct
- * @cq: pointer to control queue struct
- *
- * Do *NOT* hold cq_lock when calling this as the memory allocation routines
- * called are not going to be atomic context safe
- */
-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- int err;
-
- /* allocate the ring memory */
- err = idpf_ctlq_alloc_desc_ring(hw, cq);
- if (err)
- return err;
-
- /* allocate buffers in the rings */
- err = idpf_ctlq_alloc_bufs(hw, cq);
- if (err)
- goto idpf_init_cq_free_ring;
-
- /* success! */
- return 0;
-
-idpf_init_cq_free_ring:
- idpf_free_dma_mem(hw, &cq->desc_ring);
-
- return err;
-}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 3a04a6bd0d7c..083cf6319d26 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -10,45 +10,32 @@
/**
* idpf_ctlq_reg_init - initialize default mailbox registers
- * @adapter: adapter structure
- * @cq: pointer to the array of create control queues
+ * @mmio: struct that contains MMIO region info
+ * @cci: struct where the register offset pointer to be copied to
*/
-static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq)
+static void idpf_ctlq_reg_init(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cci)
{
- resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
- int i;
-
- for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
- struct idpf_ctlq_create_info *ccq = cq + i;
-
- switch (ccq->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = PF_FW_ATQH - mbx_start;
- ccq->reg.tail = PF_FW_ATQT - mbx_start;
- ccq->reg.len = PF_FW_ATQLEN - mbx_start;
- ccq->reg.bah = PF_FW_ATQBAH - mbx_start;
- ccq->reg.bal = PF_FW_ATQBAL - mbx_start;
- ccq->reg.len_mask = PF_FW_ATQLEN_ATQLEN_M;
- ccq->reg.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;
- ccq->reg.head_mask = PF_FW_ATQH_ATQH_M;
- break;
- case IDPF_CTLQ_TYPE_MAILBOX_RX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = PF_FW_ARQH - mbx_start;
- ccq->reg.tail = PF_FW_ARQT - mbx_start;
- ccq->reg.len = PF_FW_ARQLEN - mbx_start;
- ccq->reg.bah = PF_FW_ARQBAH - mbx_start;
- ccq->reg.bal = PF_FW_ARQBAL - mbx_start;
- ccq->reg.len_mask = PF_FW_ARQLEN_ARQLEN_M;
- ccq->reg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
- ccq->reg.head_mask = PF_FW_ARQH_ARQH_M;
- break;
- default:
- break;
- }
- }
+ struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+ struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
+
+ tx_reg->head = libie_pci_get_mmio_addr(mmio, PF_FW_ATQH);
+ tx_reg->tail = libie_pci_get_mmio_addr(mmio, PF_FW_ATQT);
+ tx_reg->len = libie_pci_get_mmio_addr(mmio, PF_FW_ATQLEN);
+ tx_reg->addr_high = libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAH);
+ tx_reg->addr_low = libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAL);
+ tx_reg->len_mask = PF_FW_ATQLEN_ATQLEN_M;
+ tx_reg->len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;
+ tx_reg->head_mask = PF_FW_ATQH_ATQH_M;
+
+ rx_reg->head = libie_pci_get_mmio_addr(mmio, PF_FW_ARQH);
+ rx_reg->tail = libie_pci_get_mmio_addr(mmio, PF_FW_ARQT);
+ rx_reg->len = libie_pci_get_mmio_addr(mmio, PF_FW_ARQLEN);
+ rx_reg->addr_high = libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAH);
+ rx_reg->addr_low = libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAL);
+ rx_reg->len_mask = PF_FW_ARQLEN_ARQLEN_M;
+ rx_reg->len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
+ rx_reg->head_mask = PF_FW_ARQH_ARQH_M;
}
/**
@@ -57,49 +44,55 @@ static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
*/
static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
{
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
- intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
+ intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
intr->dyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M;
- intr->icr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA);
+ intr->icr_ena = libie_pci_get_mmio_addr(mmio, PF_INT_DIR_OICR_ENA);
intr->icr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M;
}
/**
* idpf_intr_reg_init - Initialize interrupt registers
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
*/
-static int idpf_intr_reg_init(struct idpf_vport *vport)
+static int idpf_intr_reg_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_adapter *adapter = vport->adapter;
- int num_vecs = vport->num_q_vectors;
+ u16 num_vecs = rsrc->num_q_vectors;
struct idpf_vec_regs *reg_vals;
+ struct libie_mmio_info *mmio;
int num_regs, i, err = 0;
u32 rx_itr, tx_itr, val;
u16 total_vecs;
total_vecs = idpf_get_reserved_vecs(vport->adapter);
- reg_vals = kcalloc(total_vecs, sizeof(struct idpf_vec_regs),
- GFP_KERNEL);
+ reg_vals = kzalloc_objs(struct idpf_vec_regs, total_vecs);
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(vport, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
}
+ mmio = &adapter->ctlq_ctx.mmio_info;
+
for (i = 0; i < num_vecs; i++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[i];
- u16 vec_id = vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
+ u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
struct idpf_intr_reg *intr = &q_vector->intr_reg;
+ struct idpf_vec_regs *reg = &reg_vals[vec_id];
u32 spacing;
- intr->dyn_ctl = idpf_get_reg_addr(adapter,
- reg_vals[vec_id].dyn_ctl_reg);
+ intr->dyn_ctl = libie_pci_get_mmio_addr(mmio,
+ reg->dyn_ctl_reg);
intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
@@ -109,26 +102,25 @@ static int idpf_intr_reg_init(struct idpf_vport *vport)
intr->dyn_ctl_sw_itridx_ena_m =
PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
- spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
+ spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
IDPF_PF_ITR_IDX_SPACING);
rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0,
- reg_vals[vec_id].itrn_reg,
- spacing);
+ reg->itrn_reg, spacing);
tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1,
- reg_vals[vec_id].itrn_reg,
- spacing);
- intr->rx_itr = idpf_get_reg_addr(adapter, rx_itr);
- intr->tx_itr = idpf_get_reg_addr(adapter, tx_itr);
+ reg->itrn_reg, spacing);
+ intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+ intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
}
/* Data vector for NOIRQ queues */
- val = reg_vals[vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
- vport->noirq_dyn_ctl = idpf_get_reg_addr(adapter, val);
+ val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
+ rsrc->noirq_dyn_ctl =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
val = PF_GLINT_DYN_CTL_WB_ON_ITR_M | PF_GLINT_DYN_CTL_INTENA_MSK_M |
FIELD_PREP(PF_GLINT_DYN_CTL_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
- vport->noirq_dyn_ctl_ena = val;
+ rsrc->noirq_dyn_ctl_ena = val;
free_reg_vals:
kfree(reg_vals);
@@ -142,7 +134,9 @@ free_reg_vals:
*/
static void idpf_reset_reg_init(struct idpf_adapter *adapter)
{
- adapter->reset_reg.rstat = idpf_get_rstat_reg_addr(adapter, PFGEN_RSTAT);
+ adapter->reset_reg.rstat =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+ PFGEN_RSTAT);
adapter->reset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M;
}
@@ -154,11 +148,11 @@ static void idpf_reset_reg_init(struct idpf_adapter *adapter)
static void idpf_trigger_reset(struct idpf_adapter *adapter,
enum idpf_flags __always_unused trig_cause)
{
- u32 reset_reg;
+ void __iomem *addr;
- reset_reg = readl(idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
- writel(reset_reg | PFGEN_CTRL_PFSWR,
- idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
+ addr = libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+ PFGEN_CTRL);
+ writel(readl(addr) | PFGEN_CTRL_PFSWR, addr);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 2589e124e41c..95c45f12b0f9 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -18,7 +18,7 @@ static u32 idpf_get_rx_ring_count(struct net_device *netdev)
idpf_vport_ctrl_lock(netdev);
vport = idpf_netdev_to_vport(netdev);
- num_rxq = vport->num_rxq;
+ num_rxq = vport->dflt_qv_rsrc.num_rxq;
idpf_vport_ctrl_unlock(netdev);
return num_rxq;
@@ -37,6 +37,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_vport_user_config_data *user_config;
+ struct idpf_vport_config *vport_config;
struct idpf_fsteer_fltr *f;
struct idpf_vport *vport;
unsigned int cnt = 0;
@@ -44,7 +45,8 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
idpf_vport_ctrl_lock(netdev);
vport = idpf_netdev_to_vport(netdev);
- user_config = &np->adapter->vport_config[np->vport_idx]->user_config;
+ vport_config = np->adapter->vport_config[np->vport_idx];
+ user_config = &vport_config->user_config;
switch (cmd->cmd) {
case ETHTOOL_GRXCLSRLCNT:
@@ -52,26 +54,34 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
cmd->data = idpf_fsteer_max_rules(vport);
break;
case ETHTOOL_GRXCLSRULE:
- err = -EINVAL;
+ err = -ENOENT;
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
list_for_each_entry(f, &user_config->flow_steer_list, list)
- if (f->loc == cmd->fs.location) {
- cmd->fs.ring_cookie = f->q_index;
+ if (f->fs.location == cmd->fs.location) {
+ /* Avoid infoleak from padding: zero first,
+ * then assign fields
+ */
+ memset(&cmd->fs, 0, sizeof(cmd->fs));
+ cmd->fs = f->fs;
err = 0;
break;
}
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
break;
case ETHTOOL_GRXCLSRLALL:
cmd->data = idpf_fsteer_max_rules(vport);
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
list_for_each_entry(f, &user_config->flow_steer_list, list) {
if (cnt == cmd->rule_cnt) {
err = -EMSGSIZE;
break;
}
- rule_locs[cnt] = f->loc;
+ rule_locs[cnt] = f->fs.location;
cnt++;
}
if (!err)
cmd->rule_cnt = user_config->num_fsteer_fltrs;
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
break;
default:
break;
@@ -168,7 +178,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
struct idpf_vport *vport;
u32 flow_type, q_index;
u16 num_rxq;
- int err;
+ int err = 0;
vport = idpf_netdev_to_vport(netdev);
vport_config = vport->adapter->vport_config[np->vport_idx];
@@ -190,10 +200,33 @@ static int idpf_add_flow_steer(struct net_device *netdev,
if (q_index >= num_rxq)
return -EINVAL;
- rule = kzalloc(struct_size(rule, rule_info, 1), GFP_KERNEL);
+ rule = kzalloc_flex(*rule, rule_info, 1);
if (!rule)
return -ENOMEM;
+ fltr = kzalloc_obj(*fltr);
+ if (!fltr) {
+ err = -ENOMEM;
+ goto out_free_rule;
+ }
+
+ /* detect duplicate entry and reject before adding rules */
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
+ list_for_each_entry(f, &user_config->flow_steer_list, list) {
+ if (f->fs.location == fsp->location) {
+ err = -EEXIST;
+ break;
+ }
+
+ if (f->fs.location > fsp->location)
+ break;
+ parent = f;
+ }
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
+
+ if (err)
+ goto out_free_fltr;
+
rule->vport_id = cpu_to_le32(vport->vport_id);
rule->count = cpu_to_le32(1);
info = &rule->rule_info[0];
@@ -219,39 +252,32 @@ static int idpf_add_flow_steer(struct net_device *netdev,
break;
default:
err = -EINVAL;
- goto out;
+ goto out_free_fltr;
}
err = idpf_add_del_fsteer_filters(vport->adapter, rule,
VIRTCHNL2_OP_ADD_FLOW_RULE);
- if (err)
- goto out;
-
- if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
- err = -EIO;
- goto out;
- }
-
- fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
- if (!fltr) {
- err = -ENOMEM;
- goto out;
+ if (err) {
+ /* virtchnl2 rule is already consumed */
+ kfree(fltr);
+ return err;
}
- fltr->loc = fsp->location;
- fltr->q_index = q_index;
- list_for_each_entry(f, &user_config->flow_steer_list, list) {
- if (f->loc >= fltr->loc)
- break;
- parent = f;
- }
+ /* Save a copy of the user's flow spec so ethtool can later retrieve it */
+ fltr->fs = *fsp;
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
parent ? list_add(&fltr->list, &parent->list) :
list_add(&fltr->list, &user_config->flow_steer_list);
user_config->num_fsteer_fltrs++;
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
-out:
+ return 0;
+
+out_free_fltr:
+ kfree(fltr);
+out_free_rule:
kfree(rule);
return err;
}
@@ -280,10 +306,7 @@ static int idpf_del_flow_steer(struct net_device *netdev,
vport_config = vport->adapter->vport_config[np->vport_idx];
user_config = &vport_config->user_config;
- if (!idpf_sideband_action_ena(vport, fsp))
- return -EOPNOTSUPP;
-
- rule = kzalloc(struct_size(rule, rule_info, 1), GFP_KERNEL);
+ rule = kzalloc_flex(*rule, rule_info, 1);
if (!rule)
return -ENOMEM;
@@ -295,26 +318,22 @@ static int idpf_del_flow_steer(struct net_device *netdev,
err = idpf_add_del_fsteer_filters(vport->adapter, rule,
VIRTCHNL2_OP_DEL_FLOW_RULE);
if (err)
- goto out;
-
- if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
- err = -EIO;
- goto out;
- }
+ return err;
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
list_for_each_entry_safe(f, iter,
&user_config->flow_steer_list, list) {
- if (f->loc == fsp->location) {
+ if (f->fs.location == fsp->location) {
list_del(&f->list);
kfree(f);
user_config->num_fsteer_fltrs--;
- goto out;
+ goto out_unlock;
}
}
- err = -EINVAL;
+ err = -ENOENT;
-out:
- kfree(rule);
+out_unlock:
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
return err;
}
@@ -381,7 +400,10 @@ static u32 idpf_get_rxfh_indir_size(struct net_device *netdev)
* @netdev: network interface device structure
* @rxfh: pointer to param struct (indir, key, hfunc)
*
- * Reads the indirection table directly from the hardware. Always returns 0.
+ * RSS LUT and Key information are read from driver's cached
+ * copy. When rxhash is off, rss lut will be displayed as zeros.
+ *
+ * Return: 0 on success, -errno otherwise.
*/
static int idpf_get_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh)
@@ -389,10 +411,13 @@ static int idpf_get_rxfh(struct net_device *netdev,
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_rss_data *rss_data;
struct idpf_adapter *adapter;
+ struct idpf_vport *vport;
+ bool rxhash_ena;
int err = 0;
u16 i;
idpf_vport_ctrl_lock(netdev);
+ vport = idpf_netdev_to_vport(netdev);
adapter = np->adapter;
@@ -402,9 +427,8 @@ static int idpf_get_rxfh(struct net_device *netdev,
}
rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data;
- if (!test_bit(IDPF_VPORT_UP, np->state))
- goto unlock_mutex;
+ rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH);
rxfh->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->key)
@@ -412,7 +436,7 @@ static int idpf_get_rxfh(struct net_device *netdev,
if (rxfh->indir) {
for (i = 0; i < rss_data->rss_lut_size; i++)
- rxfh->indir[i] = rss_data->rss_lut[i];
+ rxfh->indir[i] = rxhash_ena ? rss_data->rss_lut[i] : 0;
}
unlock_mutex:
@@ -452,8 +476,6 @@ static int idpf_set_rxfh(struct net_device *netdev,
}
rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
- if (!test_bit(IDPF_VPORT_UP, np->state))
- goto unlock_mutex;
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
rxfh->hfunc != ETH_RSS_HASH_TOP) {
@@ -469,7 +491,8 @@ static int idpf_set_rxfh(struct net_device *netdev,
rss_data->rss_lut[lut] = rxfh->indir[lut];
}
- err = idpf_config_rss(vport);
+ if (test_bit(IDPF_VPORT_UP, np->state))
+ err = idpf_config_rss(vport, rss_data);
unlock_mutex:
idpf_vport_ctrl_unlock(netdev);
@@ -610,8 +633,8 @@ static void idpf_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = IDPF_MAX_RXQ_DESC;
ring->tx_max_pending = IDPF_MAX_TXQ_DESC;
- ring->rx_pending = vport->rxq_desc_count;
- ring->tx_pending = vport->txq_desc_count;
+ ring->rx_pending = vport->dflt_qv_rsrc.rxq_desc_count;
+ ring->tx_pending = vport->dflt_qv_rsrc.txq_desc_count;
kring->tcp_data_split = idpf_vport_get_hsplit(vport);
@@ -635,8 +658,9 @@ static int idpf_set_ringparam(struct net_device *netdev,
{
struct idpf_vport_user_config_data *config_data;
u32 new_rx_count, new_tx_count;
+ struct idpf_q_vec_rsrc *rsrc;
struct idpf_vport *vport;
- int i, err = 0;
+ int err = 0;
u16 idx;
idpf_vport_ctrl_lock(netdev);
@@ -670,8 +694,9 @@ static int idpf_set_ringparam(struct net_device *netdev,
netdev_info(netdev, "Requested Tx descriptor count rounded up to %u\n",
new_tx_count);
- if (new_tx_count == vport->txq_desc_count &&
- new_rx_count == vport->rxq_desc_count &&
+ rsrc = &vport->dflt_qv_rsrc;
+ if (new_tx_count == rsrc->txq_desc_count &&
+ new_rx_count == rsrc->rxq_desc_count &&
kring->tcp_data_split == idpf_vport_get_hsplit(vport))
goto unlock_mutex;
@@ -690,10 +715,10 @@ static int idpf_set_ringparam(struct net_device *netdev,
/* Since we adjusted the RX completion queue count, the RX buffer queue
* descriptor count needs to be adjusted as well
*/
- for (i = 0; i < vport->num_bufqs_per_qgrp; i++)
- vport->bufq_desc_count[i] =
+ for (unsigned int i = 0; i < rsrc->num_bufqs_per_qgrp; i++)
+ rsrc->bufq_desc_count[i] =
IDPF_RX_BUFQ_DESC_COUNT(new_rx_count,
- vport->num_bufqs_per_qgrp);
+ rsrc->num_bufqs_per_qgrp);
err = idpf_initiate_soft_reset(vport, IDPF_SR_Q_DESC_CHANGE);
@@ -1070,7 +1095,7 @@ static void idpf_add_port_stats(struct idpf_vport *vport, u64 **data)
static void idpf_collect_queue_stats(struct idpf_vport *vport)
{
struct idpf_port_stats *pstats = &vport->port_stats;
- int i, j;
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
/* zero out port stats since they're actually tracked in per
* queue stats; this is only for reporting
@@ -1086,22 +1111,22 @@ static void idpf_collect_queue_stats(struct idpf_vport *vport)
u64_stats_set(&pstats->tx_dma_map_errs, 0);
u64_stats_update_end(&pstats->stats_sync);
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rxq_grp = &vport->rxq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rxq_grp = &rsrc->rxq_grps[i];
u16 num_rxq;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
num_rxq = rxq_grp->splitq.num_rxq_sets;
else
num_rxq = rxq_grp->singleq.num_rxq;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
u64 hw_csum_err, hsplit, hsplit_hbo, bad_descs;
struct idpf_rx_queue_stats *stats;
struct idpf_rx_queue *rxq;
unsigned int start;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
rxq = &rxq_grp->splitq.rxq_sets[j]->rxq;
else
rxq = rxq_grp->singleq.rxqs[j];
@@ -1128,10 +1153,10 @@ static void idpf_collect_queue_stats(struct idpf_vport *vport)
}
}
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
- for (j = 0; j < txq_grp->num_txq; j++) {
+ for (unsigned int j = 0; j < txq_grp->num_txq; j++) {
u64 linearize, qbusy, skb_drops, dma_map_errs;
struct idpf_tx_queue *txq = txq_grp->txqs[j];
struct idpf_tx_queue_stats *stats;
@@ -1174,9 +1199,9 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_vport_config *vport_config;
+ struct idpf_q_vec_rsrc *rsrc;
struct idpf_vport *vport;
unsigned int total = 0;
- unsigned int i, j;
bool is_splitq;
u16 qtype;
@@ -1194,12 +1219,13 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
idpf_collect_queue_stats(vport);
idpf_add_port_stats(vport, &data);
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
+ rsrc = &vport->dflt_qv_rsrc;
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
qtype = VIRTCHNL2_QUEUE_TYPE_TX;
- for (j = 0; j < txq_grp->num_txq; j++, total++) {
+ for (unsigned int j = 0; j < txq_grp->num_txq; j++, total++) {
struct idpf_tx_queue *txq = txq_grp->txqs[j];
if (!txq)
@@ -1219,10 +1245,10 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
idpf_add_empty_queue_stats(&data, VIRTCHNL2_QUEUE_TYPE_TX);
total = 0;
- is_splitq = idpf_is_queue_model_split(vport->rxq_model);
+ is_splitq = idpf_is_queue_model_split(rsrc->rxq_model);
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rxq_grp = &vport->rxq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rxq_grp = &rsrc->rxq_grps[i];
u16 num_rxq;
qtype = VIRTCHNL2_QUEUE_TYPE_RX;
@@ -1232,7 +1258,7 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
else
num_rxq = rxq_grp->singleq.num_rxq;
- for (j = 0; j < num_rxq; j++, total++) {
+ for (unsigned int j = 0; j < num_rxq; j++, total++) {
struct idpf_rx_queue *rxq;
if (is_splitq)
@@ -1264,15 +1290,16 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
struct idpf_q_vector *idpf_find_rxq_vec(const struct idpf_vport *vport,
u32 q_num)
{
+ const struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
int q_grp, q_idx;
- if (!idpf_is_queue_model_split(vport->rxq_model))
- return vport->rxq_grps->singleq.rxqs[q_num]->q_vector;
+ if (!idpf_is_queue_model_split(rsrc->rxq_model))
+ return rsrc->rxq_grps->singleq.rxqs[q_num]->q_vector;
q_grp = q_num / IDPF_DFLT_SPLITQ_RXQ_PER_GROUP;
q_idx = q_num % IDPF_DFLT_SPLITQ_RXQ_PER_GROUP;
- return vport->rxq_grps[q_grp].splitq.rxq_sets[q_idx]->rxq.q_vector;
+ return rsrc->rxq_grps[q_grp].splitq.rxq_sets[q_idx]->rxq.q_vector;
}
/**
@@ -1285,14 +1312,15 @@ struct idpf_q_vector *idpf_find_rxq_vec(const struct idpf_vport *vport,
struct idpf_q_vector *idpf_find_txq_vec(const struct idpf_vport *vport,
u32 q_num)
{
+ const struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
int q_grp;
- if (!idpf_is_queue_model_split(vport->txq_model))
+ if (!idpf_is_queue_model_split(rsrc->txq_model))
return vport->txqs[q_num]->q_vector;
q_grp = q_num / IDPF_DFLT_SPLITQ_TXQ_PER_GROUP;
- return vport->txq_grps[q_grp].complq->q_vector;
+ return rsrc->txq_grps[q_grp].complq->q_vector;
}
/**
@@ -1329,7 +1357,8 @@ static int idpf_get_q_coalesce(struct net_device *netdev,
u32 q_num)
{
const struct idpf_netdev_priv *np = netdev_priv(netdev);
- const struct idpf_vport *vport;
+ struct idpf_q_vec_rsrc *rsrc;
+ struct idpf_vport *vport;
int err = 0;
idpf_vport_ctrl_lock(netdev);
@@ -1338,16 +1367,17 @@ static int idpf_get_q_coalesce(struct net_device *netdev,
if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
- if (q_num >= vport->num_rxq && q_num >= vport->num_txq) {
+ rsrc = &vport->dflt_qv_rsrc;
+ if (q_num >= rsrc->num_rxq && q_num >= rsrc->num_txq) {
err = -EINVAL;
goto unlock_mutex;
}
- if (q_num < vport->num_rxq)
+ if (q_num < rsrc->num_rxq)
__idpf_get_q_coalesce(ec, idpf_find_rxq_vec(vport, q_num),
VIRTCHNL2_QUEUE_TYPE_RX);
- if (q_num < vport->num_txq)
+ if (q_num < rsrc->num_txq)
__idpf_get_q_coalesce(ec, idpf_find_txq_vec(vport, q_num),
VIRTCHNL2_QUEUE_TYPE_TX);
@@ -1515,8 +1545,9 @@ static int idpf_set_coalesce(struct net_device *netdev,
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_vport_user_config_data *user_config;
struct idpf_q_coalesce *q_coal;
+ struct idpf_q_vec_rsrc *rsrc;
struct idpf_vport *vport;
- int i, err = 0;
+ int err = 0;
user_config = &np->adapter->vport_config[np->vport_idx]->user_config;
@@ -1526,14 +1557,15 @@ static int idpf_set_coalesce(struct net_device *netdev,
if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
- for (i = 0; i < vport->num_txq; i++) {
+ rsrc = &vport->dflt_qv_rsrc;
+ for (unsigned int i = 0; i < rsrc->num_txq; i++) {
q_coal = &user_config->q_coalesce[i];
err = idpf_set_q_coalesce(vport, q_coal, ec, i, false);
if (err)
goto unlock_mutex;
}
- for (i = 0; i < vport->num_rxq; i++) {
+ for (unsigned int i = 0; i < rsrc->num_rxq; i++) {
q_coal = &user_config->q_coalesce[i];
err = idpf_set_q_coalesce(vport, q_coal, ec, i, true);
if (err)
@@ -1714,6 +1746,7 @@ static void idpf_get_ts_stats(struct net_device *netdev,
struct ethtool_ts_stats *ts_stats)
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
+ struct idpf_q_vec_rsrc *rsrc;
struct idpf_vport *vport;
unsigned int start;
@@ -1729,8 +1762,9 @@ static void idpf_get_ts_stats(struct net_device *netdev,
if (!test_bit(IDPF_VPORT_UP, np->state))
goto exit;
- for (u16 i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
+ rsrc = &vport->dflt_qv_rsrc;
+ for (u16 i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
for (u16 j = 0; j < txq_grp->num_txq; j++) {
struct idpf_tx_queue *txq = txq_grp->txqs[j];
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index 7e20a07e98e5..b6cd1c25ae5d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -60,7 +60,7 @@ static int idpf_plug_vport_aux_dev(struct iidc_rdma_core_dev_info *cdev_info,
struct auxiliary_device *adev;
int ret;
- iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
+ iadev = kzalloc_obj(*iadev);
if (!iadev)
return -ENOMEM;
@@ -90,7 +90,10 @@ static int idpf_plug_vport_aux_dev(struct iidc_rdma_core_dev_info *cdev_info,
return 0;
err_aux_dev_add:
+ ida_free(&idpf_idc_ida, adev->id);
+ vdev_info->adev = NULL;
auxiliary_device_uninit(adev);
+ return ret;
err_aux_dev_init:
ida_free(&idpf_idc_ida, adev->id);
err_ida_alloc:
@@ -120,7 +123,7 @@ static int idpf_idc_init_aux_vport_dev(struct idpf_vport *vport)
if (!(le16_to_cpu(vport_msg->vport_flags) & VIRTCHNL2_VPORT_ENABLE_RDMA))
return 0;
- vport->vdev_info = kzalloc(sizeof(*vdev_info), GFP_KERNEL);
+ vport->vdev_info = kzalloc_obj(*vdev_info);
if (!vport->vdev_info)
return -ENOMEM;
@@ -198,7 +201,7 @@ static int idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info *cdev_info)
struct auxiliary_device *adev;
int ret;
- iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
+ iadev = kzalloc_obj(*iadev);
if (!iadev)
return -ENOMEM;
@@ -228,7 +231,10 @@ static int idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info *cdev_info)
return 0;
err_aux_dev_add:
+ ida_free(&idpf_idc_ida, adev->id);
+ cdev_info->adev = NULL;
auxiliary_device_uninit(adev);
+ return ret;
err_aux_dev_init:
ida_free(&idpf_idc_ida, adev->id);
err_ida_alloc:
@@ -322,7 +328,7 @@ static void idpf_idc_vport_dev_down(struct idpf_adapter *adapter)
for (i = 0; i < adapter->num_alloc_vports; i++) {
struct idpf_vport *vport = adapter->vports[i];
- if (!vport)
+ if (!vport || !vport->vdev_info)
continue;
idpf_unplug_aux_dev(vport->vdev_info->adev);
@@ -410,16 +416,19 @@ idpf_idc_init_msix_data(struct idpf_adapter *adapter)
int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
enum iidc_function_type ftype)
{
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct iidc_rdma_core_dev_info *cdev_info;
struct iidc_rdma_priv_dev_info *privd;
- int err, i;
+ struct libie_pci_mmio_region *mr;
+ size_t num_mem_regions;
+ int err, i = 0;
- adapter->cdev_info = kzalloc(sizeof(*cdev_info), GFP_KERNEL);
+ adapter->cdev_info = kzalloc_obj(*cdev_info);
if (!adapter->cdev_info)
return -ENOMEM;
cdev_info = adapter->cdev_info;
- privd = kzalloc(sizeof(*privd), GFP_KERNEL);
+ privd = kzalloc_obj(*privd);
if (!privd) {
err = -ENOMEM;
goto err_privd_alloc;
@@ -430,23 +439,31 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
cdev_info->rdma_protocol = IIDC_RDMA_PROTOCOL_ROCEV2;
privd->ftype = ftype;
+ num_mem_regions = list_count_nodes(&mmio->mmio_list);
+ if (num_mem_regions <= IDPF_MMIO_REG_NUM_STATIC) {
+ err = -EINVAL;
+ goto err_plug_aux_dev;
+ }
+
+ num_mem_regions -= IDPF_MMIO_REG_NUM_STATIC;
privd->mapped_mem_regions =
- kcalloc(adapter->hw.num_lan_regs,
- sizeof(struct iidc_rdma_lan_mapped_mem_region),
- GFP_KERNEL);
+ kzalloc_objs(struct iidc_rdma_lan_mapped_mem_region,
+ num_mem_regions);
if (!privd->mapped_mem_regions) {
err = -ENOMEM;
goto err_plug_aux_dev;
}
- privd->num_memory_regions = cpu_to_le16(adapter->hw.num_lan_regs);
- for (i = 0; i < adapter->hw.num_lan_regs; i++) {
- privd->mapped_mem_regions[i].region_addr =
- adapter->hw.lan_regs[i].vaddr;
- privd->mapped_mem_regions[i].size =
- cpu_to_le64(adapter->hw.lan_regs[i].addr_len);
- privd->mapped_mem_regions[i].start_offset =
- cpu_to_le64(adapter->hw.lan_regs[i].addr_start);
+ privd->num_memory_regions = cpu_to_le16(num_mem_regions);
+ list_for_each_entry(mr, &mmio->mmio_list, list) {
+ if (!idpf_mmio_region_non_static(&adapter->ctlq_ctx.mmio_info,
+ mr))
+ continue;
+
+ privd->mapped_mem_regions[i].region_addr = mr->addr;
+ privd->mapped_mem_regions[i].size = cpu_to_le64(mr->size);
+ privd->mapped_mem_regions[i++].start_offset =
+ cpu_to_le64(mr->offset);
}
idpf_idc_init_msix_data(adapter);
@@ -471,10 +488,11 @@ err_privd_alloc:
/**
* idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s)
- * @cdev_info: IDC core device info pointer
+ * @adapter: driver private data structure
*/
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter)
{
+ struct iidc_rdma_core_dev_info *cdev_info = adapter->cdev_info;
struct iidc_rdma_priv_dev_info *privd;
if (!cdev_info)
@@ -486,6 +504,7 @@ void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
kfree(privd->mapped_mem_regions);
kfree(privd);
kfree(cdev_info);
+ adapter->cdev_info = NULL;
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 7a7e101afeb6..827c795afcb6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -68,9 +68,11 @@ static void idpf_deinit_vector_stack(struct idpf_adapter *adapter)
* This will also disable interrupt mode and queue up mailbox task. Mailbox
* task will reschedule itself if not in interrupt mode.
*/
-static void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
{
- clear_bit(IDPF_MB_INTR_MODE, adapter->flags);
+ if (!test_and_clear_bit(IDPF_MB_INTR_MODE, adapter->flags))
+ return;
+
kfree(free_irq(adapter->msix_entries[0].vector, adapter));
queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
}
@@ -139,7 +141,7 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
if (err) {
dev_err(&adapter->pdev->dev,
"IRQ request for mailbox failed, error: %d\n", err);
-
+ kfree(name);
return err;
}
@@ -359,9 +361,8 @@ int idpf_intr_req(struct idpf_adapter *adapter)
num_rdma_vecs = IDPF_MIN_RDMA_VEC;
}
- adapter->rdma_msix_entries = kcalloc(num_rdma_vecs,
- sizeof(struct msix_entry),
- GFP_KERNEL);
+ adapter->rdma_msix_entries = kzalloc_objs(struct msix_entry,
+ num_rdma_vecs);
if (!adapter->rdma_msix_entries) {
err = -ENOMEM;
goto free_irq;
@@ -369,8 +370,7 @@ int idpf_intr_req(struct idpf_adapter *adapter)
}
num_lan_vecs = actual_vecs - num_rdma_vecs;
- adapter->msix_entries = kcalloc(num_lan_vecs, sizeof(struct msix_entry),
- GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, num_lan_vecs);
if (!adapter->msix_entries) {
err = -ENOMEM;
goto free_rdma_msix;
@@ -443,6 +443,29 @@ send_dealloc_vecs:
}
/**
+ * idpf_del_all_flow_steer_filters - Delete all flow steer filters in list
+ * @vport: main vport struct
+ *
+ * Takes flow_steer_list_lock spinlock. Deletes all filters
+ */
+static void idpf_del_all_flow_steer_filters(struct idpf_vport *vport)
+{
+ struct idpf_vport_config *vport_config;
+ struct idpf_fsteer_fltr *f, *ftmp;
+
+ vport_config = vport->adapter->vport_config[vport->idx];
+
+ spin_lock_bh(&vport_config->flow_steer_list_lock);
+ list_for_each_entry_safe(f, ftmp, &vport_config->user_config.flow_steer_list,
+ list) {
+ list_del(&f->list);
+ kfree(f);
+ }
+ vport_config->user_config.num_fsteer_fltrs = 0;
+ spin_unlock_bh(&vport_config->flow_steer_list_lock);
+}
+
+/**
* idpf_find_mac_filter - Search filter list for specific mac filter
* @vconfig: Vport config structure
* @macaddr: The MAC address
@@ -522,7 +545,9 @@ static int idpf_del_mac_filter(struct idpf_vport *vport,
if (test_bit(IDPF_VPORT_UP, np->state)) {
int err;
- err = idpf_add_del_mac_filters(vport, np, false, async);
+ err = idpf_add_del_mac_filters(np->adapter, vport_config,
+ vport->default_mac_addr,
+ np->vport_id, false, async);
if (err)
return err;
}
@@ -552,7 +577,7 @@ static int __idpf_add_mac_filter(struct idpf_vport_config *vport_config,
return 0;
}
- f = kzalloc(sizeof(*f), GFP_ATOMIC);
+ f = kzalloc_obj(*f, GFP_ATOMIC);
if (!f) {
spin_unlock_bh(&vport_config->mac_filter_list_lock);
@@ -591,7 +616,9 @@ static int idpf_add_mac_filter(struct idpf_vport *vport,
return err;
if (test_bit(IDPF_VPORT_UP, np->state))
- err = idpf_add_del_mac_filters(vport, np, true, async);
+ err = idpf_add_del_mac_filters(np->adapter, vport_config,
+ vport->default_mac_addr,
+ np->vport_id, true, async);
return err;
}
@@ -639,7 +666,8 @@ static void idpf_restore_mac_filters(struct idpf_vport *vport)
spin_unlock_bh(&vport_config->mac_filter_list_lock);
- idpf_add_del_mac_filters(vport, netdev_priv(vport->netdev),
+ idpf_add_del_mac_filters(vport->adapter, vport_config,
+ vport->default_mac_addr, vport->vport_id,
true, false);
}
@@ -663,7 +691,8 @@ static void idpf_remove_mac_filters(struct idpf_vport *vport)
spin_unlock_bh(&vport_config->mac_filter_list_lock);
- idpf_add_del_mac_filters(vport, netdev_priv(vport->netdev),
+ idpf_add_del_mac_filters(vport->adapter, vport_config,
+ vport->default_mac_addr, vport->vport_id,
false, false);
}
@@ -729,6 +758,65 @@ static int idpf_init_mac_addr(struct idpf_vport *vport,
return 0;
}
+static void idpf_detach_and_close(struct idpf_adapter *adapter)
+{
+ int max_vports = adapter->max_vports;
+
+ for (int i = 0; i < max_vports; i++) {
+ struct net_device *netdev = adapter->netdevs[i];
+
+ /* If the interface is in detached state, that means the
+ * previous reset was not handled successfully for this
+ * vport.
+ */
+ if (!netif_device_present(netdev))
+ continue;
+
+ /* Hold RTNL to protect racing with callbacks */
+ rtnl_lock();
+ netif_device_detach(netdev);
+ if (netif_running(netdev)) {
+ set_bit(IDPF_VPORT_UP_REQUESTED,
+ adapter->vport_config[i]->flags);
+ dev_close(netdev);
+ }
+ rtnl_unlock();
+ }
+}
+
+static void idpf_attach_and_open(struct idpf_adapter *adapter)
+{
+ int max_vports = adapter->max_vports;
+
+ for (int i = 0; i < max_vports; i++) {
+ struct idpf_vport *vport = adapter->vports[i];
+ struct idpf_vport_config *vport_config;
+ struct net_device *netdev;
+
+ /* In case of a critical error in the init task, the vport
+ * will be freed. Only continue to restore the netdevs
+ * if the vport is allocated.
+ */
+ if (!vport)
+ continue;
+
+ /* No need for RTNL on attach as this function is called
+ * following detach and dev_close(). We do take RTNL for
+ * dev_open() below as it can race with external callbacks
+ * following the call to netif_device_attach().
+ */
+ netdev = adapter->netdevs[i];
+ netif_device_attach(netdev);
+ vport_config = adapter->vport_config[vport->idx];
+ if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED,
+ vport_config->flags)) {
+ rtnl_lock();
+ dev_open(netdev, NULL);
+ rtnl_unlock();
+ }
+ }
+}
+
/**
* idpf_cfg_netdev - Allocate, configure and register a netdev
* @vport: main vport structure
@@ -893,6 +981,10 @@ static void idpf_remove_features(struct idpf_vport *vport)
static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
+ struct idpf_adapter *adapter = vport->adapter;
+ struct idpf_queue_id_reg_info *chunks;
+ u32 vport_id = vport->vport_id;
if (!test_bit(IDPF_VPORT_UP, np->state))
return;
@@ -903,24 +995,26 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl)
netif_carrier_off(vport->netdev);
netif_tx_disable(vport->netdev);
- idpf_send_disable_vport_msg(vport);
+ chunks = &adapter->vport_config[vport->idx]->qid_reg_info;
+
+ idpf_send_disable_vport_msg(adapter, vport_id);
idpf_send_disable_queues_msg(vport);
- idpf_send_map_unmap_queue_vector_msg(vport, false);
+ idpf_send_map_unmap_queue_vector_msg(adapter, rsrc, vport_id, false);
/* Normally we ask for queues in create_vport, but if the number of
* initially requested queues have changed, for example via ethtool
* set channels, we do delete queues and then add the queues back
* instead of deleting and reallocating the vport.
*/
if (test_and_clear_bit(IDPF_VPORT_DEL_QUEUES, vport->flags))
- idpf_send_delete_queues_msg(vport);
+ idpf_send_delete_queues_msg(adapter, chunks, vport_id);
idpf_remove_features(vport);
vport->link_up = false;
- idpf_vport_intr_deinit(vport);
- idpf_xdp_rxq_info_deinit_all(vport);
- idpf_vport_queues_rel(vport);
- idpf_vport_intr_rel(vport);
+ idpf_vport_intr_deinit(vport, rsrc);
+ idpf_xdp_rxq_info_deinit_all(rsrc);
+ idpf_vport_queues_rel(vport, rsrc);
+ idpf_vport_intr_rel(rsrc);
clear_bit(IDPF_VPORT_UP, np->state);
if (rtnl)
@@ -964,9 +1058,6 @@ static void idpf_decfg_netdev(struct idpf_vport *vport)
struct idpf_adapter *adapter = vport->adapter;
u16 idx = vport->idx;
- kfree(vport->rx_ptype_lkup);
- vport->rx_ptype_lkup = NULL;
-
if (test_and_clear_bit(IDPF_VPORT_REG_NETDEV,
adapter->vport_config[idx]->flags)) {
unregister_netdev(vport->netdev);
@@ -983,6 +1074,7 @@ static void idpf_decfg_netdev(struct idpf_vport *vport)
*/
static void idpf_vport_rel(struct idpf_vport *vport)
{
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_adapter *adapter = vport->adapter;
struct idpf_vport_config *vport_config;
struct idpf_vector_info vec_info;
@@ -991,12 +1083,12 @@ static void idpf_vport_rel(struct idpf_vport *vport)
u16 idx = vport->idx;
vport_config = adapter->vport_config[vport->idx];
- idpf_deinit_rss(vport);
rss_data = &vport_config->user_config.rss_data;
+ idpf_deinit_rss_lut(rss_data);
kfree(rss_data->rss_key);
rss_data->rss_key = NULL;
- idpf_send_destroy_vport_msg(vport);
+ idpf_send_destroy_vport_msg(adapter, vport->vport_id);
/* Release all max queues allocated to the adapter's pool */
max_q.max_rxq = vport_config->max_q.max_rxq;
@@ -1007,22 +1099,19 @@ static void idpf_vport_rel(struct idpf_vport *vport)
/* Release all the allocated vectors on the stack */
vec_info.num_req_vecs = 0;
- vec_info.num_curr_vecs = vport->num_q_vectors;
+ vec_info.num_curr_vecs = rsrc->num_q_vectors;
vec_info.default_vport = vport->default_vport;
- idpf_req_rel_vector_indexes(adapter, vport->q_vector_idxs, &vec_info);
+ idpf_req_rel_vector_indexes(adapter, rsrc->q_vector_idxs, &vec_info);
- kfree(vport->q_vector_idxs);
- vport->q_vector_idxs = NULL;
+ kfree(rsrc->q_vector_idxs);
+ rsrc->q_vector_idxs = NULL;
+
+ idpf_vport_deinit_queue_reg_chunks(vport_config);
kfree(adapter->vport_params_recvd[idx]);
adapter->vport_params_recvd[idx] = NULL;
- kfree(adapter->vport_params_reqd[idx]);
- adapter->vport_params_reqd[idx] = NULL;
- if (adapter->vport_config[idx]) {
- kfree(adapter->vport_config[idx]->req_qs_chunks);
- adapter->vport_config[idx]->req_qs_chunks = NULL;
- }
+
kfree(vport);
adapter->num_alloc_vports--;
}
@@ -1041,12 +1130,15 @@ static void idpf_vport_dealloc(struct idpf_vport *vport)
idpf_idc_deinit_vport_aux_device(vport->vdev_info);
idpf_deinit_mac_addr(vport);
- idpf_vport_stop(vport, true);
- if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags))
+ if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) {
+ idpf_vport_stop(vport, true);
idpf_decfg_netdev(vport);
- if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
+ }
+ if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) {
idpf_del_all_mac_filters(vport);
+ idpf_del_all_flow_steer_filters(vport);
+ }
if (adapter->netdevs[i]) {
struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]);
@@ -1068,7 +1160,7 @@ static void idpf_vport_dealloc(struct idpf_vport *vport)
*/
static bool idpf_is_hsplit_supported(const struct idpf_vport *vport)
{
- return idpf_is_queue_model_split(vport->rxq_model) &&
+ return idpf_is_queue_model_split(vport->dflt_qv_rsrc.rxq_model) &&
idpf_is_cap_ena_all(vport->adapter, IDPF_HSPLIT_CAPS,
IDPF_CAP_HSPLIT);
}
@@ -1137,13 +1229,15 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
{
struct idpf_rss_data *rss_data;
u16 idx = adapter->next_vport;
+ struct idpf_q_vec_rsrc *rsrc;
struct idpf_vport *vport;
u16 num_max_q;
+ int err;
if (idx == IDPF_NO_FREE_SLOT)
return NULL;
- vport = kzalloc(sizeof(*vport), GFP_KERNEL);
+ vport = kzalloc_obj(*vport);
if (!vport)
return vport;
@@ -1152,14 +1246,14 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
struct idpf_vport_config *vport_config;
struct idpf_q_coalesce *q_coal;
- vport_config = kzalloc(sizeof(*vport_config), GFP_KERNEL);
+ vport_config = kzalloc_obj(*vport_config);
if (!vport_config) {
kfree(vport);
return NULL;
}
- q_coal = kcalloc(num_max_q, sizeof(*q_coal), GFP_KERNEL);
+ q_coal = kzalloc_objs(*q_coal, num_max_q);
if (!q_coal) {
kfree(vport_config);
kfree(vport);
@@ -1183,25 +1277,35 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
vport->default_vport = adapter->num_alloc_vports <
idpf_get_default_vports(adapter);
- vport->q_vector_idxs = kcalloc(num_max_q, sizeof(u16), GFP_KERNEL);
- if (!vport->q_vector_idxs)
+ rsrc = &vport->dflt_qv_rsrc;
+ rsrc->dev = &adapter->pdev->dev;
+ rsrc->q_vector_idxs = kcalloc(num_max_q, sizeof(u16), GFP_KERNEL);
+ if (!rsrc->q_vector_idxs)
goto free_vport;
- idpf_vport_init(vport, max_q);
+ err = idpf_vport_init(vport, max_q);
+ if (err)
+ goto free_vector_idxs;
- /* This alloc is done separate from the LUT because it's not strictly
- * dependent on how many queues we have. If we change number of queues
- * and soft reset we'll need a new LUT but the key can remain the same
- * for as long as the vport exists.
+ /* LUT and key are both initialized here. Key is not strictly dependent
+ * on how many queues we have. If we change number of queues and soft
+ * reset is initiated, LUT will be freed and a new LUT will be allocated
+ * as per the updated number of queues during vport bringup. However,
+ * the key remains the same for as long as the vport exists.
*/
rss_data = &adapter->vport_config[idx]->user_config.rss_data;
rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL);
if (!rss_data->rss_key)
- goto free_vector_idxs;
+ goto free_qreg_chunks;
- /* Initialize default rss key */
+ /* Initialize default RSS key */
netdev_rss_key_fill((void *)rss_data->rss_key, rss_data->rss_key_size);
+ /* Initialize default RSS LUT */
+ err = idpf_init_rss_lut(vport, rss_data);
+ if (err)
+ goto free_rss_key;
+
/* fill vport slot in the adapter struct */
adapter->vports[idx] = vport;
adapter->vport_ids[idx] = idpf_get_vport_id(vport);
@@ -1212,8 +1316,13 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
return vport;
+free_rss_key:
+ kfree(rss_data->rss_key);
+ rss_data->rss_key = NULL;
+free_qreg_chunks:
+ idpf_vport_deinit_queue_reg_chunks(adapter->vport_config[idx]);
free_vector_idxs:
- kfree(vport->q_vector_idxs);
+ kfree(rsrc->q_vector_idxs);
free_vport:
kfree(vport);
@@ -1250,7 +1359,8 @@ void idpf_statistics_task(struct work_struct *work)
struct idpf_vport *vport = adapter->vports[i];
if (vport && !test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags))
- idpf_send_get_stats_msg(vport);
+ idpf_send_get_stats_msg(netdev_priv(vport->netdev),
+ &vport->port_stats);
}
queue_delayed_work(adapter->stats_wq, &adapter->stats_task,
@@ -1263,6 +1373,7 @@ void idpf_statistics_task(struct work_struct *work)
*/
void idpf_mbx_task(struct work_struct *work)
{
+ struct libie_ctlq_xn_recv_params xn_params;
struct idpf_adapter *adapter;
adapter = container_of(work, struct idpf_adapter, mbx_task.work);
@@ -1271,9 +1382,16 @@ void idpf_mbx_task(struct work_struct *work)
idpf_mb_irq_enable(adapter);
else
queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
- msecs_to_jiffies(300));
+ usecs_to_jiffies(300));
- idpf_recv_mb_msg(adapter);
+ xn_params = (struct libie_ctlq_xn_recv_params) {
+ .xnm = adapter->xnm,
+ .ctlq = adapter->arq,
+ .ctlq_msg_handler = idpf_recv_event_msg,
+ .budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
+ };
+
+ libie_ctlq_xn_recv(&xn_params);
}
/**
@@ -1321,9 +1439,10 @@ static void idpf_restore_features(struct idpf_vport *vport)
*/
static int idpf_set_real_num_queues(struct idpf_vport *vport)
{
- int err, txq = vport->num_txq - vport->num_xdp_txq;
+ int err, txq = vport->dflt_qv_rsrc.num_txq - vport->num_xdp_txq;
- err = netif_set_real_num_rx_queues(vport->netdev, vport->num_rxq);
+ err = netif_set_real_num_rx_queues(vport->netdev,
+ vport->dflt_qv_rsrc.num_rxq);
if (err)
return err;
@@ -1333,10 +1452,8 @@ static int idpf_set_real_num_queues(struct idpf_vport *vport)
/**
* idpf_up_complete - Complete interface up sequence
* @vport: virtual port structure
- *
- * Returns 0 on success, negative on failure.
*/
-static int idpf_up_complete(struct idpf_vport *vport)
+static void idpf_up_complete(struct idpf_vport *vport)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
@@ -1346,30 +1463,26 @@ static int idpf_up_complete(struct idpf_vport *vport)
}
set_bit(IDPF_VPORT_UP, np->state);
-
- return 0;
}
/**
* idpf_rx_init_buf_tail - Write initial buffer ring tail value
- * @vport: virtual port struct
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_rx_init_buf_tail(struct idpf_vport *vport)
+static void idpf_rx_init_buf_tail(struct idpf_q_vec_rsrc *rsrc)
{
- int i, j;
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *grp = &rsrc->rxq_grps[i];
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *grp = &vport->rxq_grps[i];
-
- if (idpf_is_queue_model_split(vport->rxq_model)) {
- for (j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ if (idpf_is_queue_model_split(rsrc->rxq_model)) {
+ for (unsigned int j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
const struct idpf_buf_queue *q =
&grp->splitq.bufq_sets[j].bufq;
writel(q->next_to_alloc, q->tail);
}
} else {
- for (j = 0; j < grp->singleq.num_rxq; j++) {
+ for (unsigned int j = 0; j < grp->singleq.num_rxq; j++) {
const struct idpf_rx_queue *q =
grp->singleq.rxqs[j];
@@ -1387,8 +1500,12 @@ static void idpf_rx_init_buf_tail(struct idpf_vport *vport)
static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_adapter *adapter = vport->adapter;
struct idpf_vport_config *vport_config;
+ struct idpf_queue_id_reg_info *chunks;
+ struct idpf_rss_data *rss_data;
+ u32 vport_id = vport->vport_id;
int err;
if (test_bit(IDPF_VPORT_UP, np->state))
@@ -1400,48 +1517,51 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
/* we do not allow interface up just yet */
netif_carrier_off(vport->netdev);
- err = idpf_vport_intr_alloc(vport);
+ err = idpf_vport_intr_alloc(vport, rsrc);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to allocate interrupts for vport %u: %d\n",
vport->vport_id, err);
goto err_rtnl_unlock;
}
- err = idpf_vport_queues_alloc(vport);
+ err = idpf_vport_queues_alloc(vport, rsrc);
if (err)
goto intr_rel;
- err = idpf_vport_queue_ids_init(vport);
+ vport_config = adapter->vport_config[vport->idx];
+ chunks = &vport_config->qid_reg_info;
+
+ err = idpf_vport_queue_ids_init(vport, rsrc, chunks);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to initialize queue ids for vport %u: %d\n",
vport->vport_id, err);
goto queues_rel;
}
- err = idpf_vport_intr_init(vport);
+ err = idpf_vport_intr_init(vport, rsrc);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to initialize interrupts for vport %u: %d\n",
vport->vport_id, err);
goto queues_rel;
}
- err = idpf_queue_reg_init(vport);
+ err = idpf_queue_reg_init(vport, rsrc, chunks);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to initialize queue registers for vport %u: %d\n",
vport->vport_id, err);
- goto queues_rel;
+ goto intr_deinit;
}
- err = idpf_rx_bufs_init_all(vport);
+ err = idpf_rx_bufs_init_all(vport, rsrc);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to initialize RX buffers for vport %u: %d\n",
vport->vport_id, err);
- goto queues_rel;
+ goto intr_deinit;
}
- idpf_rx_init_buf_tail(vport);
+ idpf_rx_init_buf_tail(rsrc);
- err = idpf_xdp_rxq_info_init_all(vport);
+ err = idpf_xdp_rxq_info_init_all(rsrc);
if (err) {
netdev_err(vport->netdev,
"Failed to initialize XDP RxQ info for vport %u: %pe\n",
@@ -1449,16 +1569,17 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
goto intr_deinit;
}
- idpf_vport_intr_ena(vport);
+ idpf_vport_intr_ena(vport, rsrc);
- err = idpf_send_config_queues_msg(vport);
+ err = idpf_send_config_queues_msg(adapter, rsrc, vport_id);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to configure queues for vport %u, %d\n",
vport->vport_id, err);
goto rxq_deinit;
}
- err = idpf_send_map_unmap_queue_vector_msg(vport, true);
+ err = idpf_send_map_unmap_queue_vector_msg(adapter, rsrc, vport_id,
+ true);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to map queue vectors for vport %u: %d\n",
vport->vport_id, err);
@@ -1472,7 +1593,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
goto unmap_queue_vectors;
}
- err = idpf_send_enable_vport_msg(vport);
+ err = idpf_send_enable_vport_msg(adapter, vport_id);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to enable vport %u: %d\n",
vport->vport_id, err);
@@ -1482,45 +1603,35 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl)
idpf_restore_features(vport);
- vport_config = adapter->vport_config[vport->idx];
- if (vport_config->user_config.rss_data.rss_lut)
- err = idpf_config_rss(vport);
- else
- err = idpf_init_rss(vport);
+ rss_data = &vport_config->user_config.rss_data;
+ err = idpf_config_rss(vport, rss_data);
if (err) {
- dev_err(&adapter->pdev->dev, "Failed to initialize RSS for vport %u: %d\n",
+ dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n",
vport->vport_id, err);
goto disable_vport;
}
- err = idpf_up_complete(vport);
- if (err) {
- dev_err(&adapter->pdev->dev, "Failed to complete interface up for vport %u: %d\n",
- vport->vport_id, err);
- goto deinit_rss;
- }
+ idpf_up_complete(vport);
if (rtnl)
rtnl_unlock();
return 0;
-deinit_rss:
- idpf_deinit_rss(vport);
disable_vport:
- idpf_send_disable_vport_msg(vport);
+ idpf_send_disable_vport_msg(adapter, vport_id);
disable_queues:
idpf_send_disable_queues_msg(vport);
unmap_queue_vectors:
- idpf_send_map_unmap_queue_vector_msg(vport, false);
+ idpf_send_map_unmap_queue_vector_msg(adapter, rsrc, vport_id, false);
rxq_deinit:
- idpf_xdp_rxq_info_deinit_all(vport);
+ idpf_xdp_rxq_info_deinit_all(rsrc);
intr_deinit:
- idpf_vport_intr_deinit(vport);
+ idpf_vport_intr_deinit(vport, rsrc);
queues_rel:
- idpf_vport_queues_rel(vport);
+ idpf_vport_queues_rel(vport, rsrc);
intr_rel:
- idpf_vport_intr_rel(vport);
+ idpf_vport_intr_rel(rsrc);
err_rtnl_unlock:
if (rtnl)
@@ -1544,7 +1655,6 @@ void idpf_init_task(struct work_struct *work)
struct idpf_vport_config *vport_config;
struct idpf_vport_max_q max_q;
struct idpf_adapter *adapter;
- struct idpf_netdev_priv *np;
struct idpf_vport *vport;
u16 num_default_vports;
struct pci_dev *pdev;
@@ -1583,6 +1693,7 @@ void idpf_init_task(struct work_struct *work)
vport_config = adapter->vport_config[index];
spin_lock_init(&vport_config->mac_filter_list_lock);
+ spin_lock_init(&vport_config->flow_steer_list_lock);
INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list);
INIT_LIST_HEAD(&vport_config->user_config.flow_steer_list);
@@ -1590,21 +1701,11 @@ void idpf_init_task(struct work_struct *work)
err = idpf_check_supported_desc_ids(vport);
if (err) {
dev_err(&pdev->dev, "failed to get required descriptor ids\n");
- goto cfg_netdev_err;
+ goto unwind_vports;
}
if (idpf_cfg_netdev(vport))
- goto cfg_netdev_err;
-
- err = idpf_send_get_rx_ptype_msg(vport);
- if (err)
- goto handle_err;
-
- /* Once state is put into DOWN, driver is ready for dev_open */
- np = netdev_priv(vport->netdev);
- clear_bit(IDPF_VPORT_UP, np->state);
- if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags))
- idpf_vport_open(vport, true);
+ goto unwind_vports;
/* Spawn and return 'idpf_init_task' work queue until all the
* default vports are created
@@ -1635,21 +1736,15 @@ void idpf_init_task(struct work_struct *work)
set_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags);
}
- /* As all the required vports are created, clear the reset flag
- * unconditionally here in case we were in reset and the link was down.
- */
+ /* Clear the reset and load bits as all vports are created */
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
+ clear_bit(IDPF_HR_DRV_LOAD, adapter->flags);
/* Start the statistics task now */
queue_delayed_work(adapter->stats_wq, &adapter->stats_task,
msecs_to_jiffies(10 * (pdev->devfn & 0x07)));
return;
-handle_err:
- idpf_decfg_netdev(vport);
-cfg_netdev_err:
- idpf_vport_rel(vport);
- adapter->vports[index] = NULL;
unwind_vports:
if (default_vport) {
for (index = 0; index < adapter->max_vports; index++) {
@@ -1657,6 +1752,15 @@ unwind_vports:
idpf_vport_dealloc(adapter->vports[index]);
}
}
+ /* Cleanup after vc_core_init, which has no way of knowing the
+ * init task failed on driver load.
+ */
+ if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
+ cancel_delayed_work_sync(&adapter->serv_task);
+ cancel_delayed_work_sync(&adapter->mbx_task);
+ }
+ idpf_ptp_release(adapter);
+
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
}
@@ -1753,15 +1857,14 @@ void idpf_deinit_task(struct idpf_adapter *adapter)
/**
* idpf_check_reset_complete - check that reset is complete
- * @hw: pointer to hw struct
+ * @adapter: adapter to check
* @reset_reg: struct with reset registers
*
* Returns 0 if device is ready to use, or -EBUSY if it's in reset.
**/
-static int idpf_check_reset_complete(struct idpf_hw *hw,
+static int idpf_check_reset_complete(struct idpf_adapter *adapter,
struct idpf_reset_reg *reset_reg)
{
- struct idpf_adapter *adapter = hw->back;
int i;
for (i = 0; i < 2000; i++) {
@@ -1787,27 +1890,6 @@ static int idpf_check_reset_complete(struct idpf_hw *hw,
}
/**
- * idpf_set_vport_state - Set the vport state to be after the reset
- * @adapter: Driver specific private structure
- */
-static void idpf_set_vport_state(struct idpf_adapter *adapter)
-{
- u16 i;
-
- for (i = 0; i < adapter->max_vports; i++) {
- struct idpf_netdev_priv *np;
-
- if (!adapter->netdevs[i])
- continue;
-
- np = netdev_priv(adapter->netdevs[i]);
- if (test_bit(IDPF_VPORT_UP, np->state))
- set_bit(IDPF_VPORT_UP_REQUESTED,
- adapter->vport_config[i]->flags);
- }
-}
-
-/**
* idpf_init_hard_reset - Initiate a hardware reset
* @adapter: Driver specific private structure
*
@@ -1815,37 +1897,25 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter)
* reallocate. Also reinitialize the mailbox. Return 0 on success,
* negative on failure.
*/
-static int idpf_init_hard_reset(struct idpf_adapter *adapter)
+static void idpf_init_hard_reset(struct idpf_adapter *adapter)
{
struct idpf_reg_ops *reg_ops = &adapter->dev_ops.reg_ops;
struct device *dev = &adapter->pdev->dev;
- struct net_device *netdev;
int err;
- u16 i;
+ idpf_detach_and_close(adapter);
mutex_lock(&adapter->vport_ctrl_lock);
dev_info(dev, "Device HW Reset initiated\n");
- /* Avoid TX hangs on reset */
- for (i = 0; i < adapter->max_vports; i++) {
- netdev = adapter->netdevs[i];
- if (!netdev)
- continue;
-
- netif_carrier_off(netdev);
- netif_tx_disable(netdev);
- }
-
/* Prepare for reset */
- if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
+ if (test_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD);
} else if (test_and_clear_bit(IDPF_HR_FUNC_RESET, adapter->flags)) {
bool is_reset = idpf_is_reset_detected(adapter);
idpf_idc_issue_reset_event(adapter->cdev_info);
- idpf_set_vport_state(adapter);
idpf_vc_core_deinit(adapter);
if (!is_reset)
reg_ops->trigger_reset(adapter, IDPF_HR_FUNC_RESET);
@@ -1857,7 +1927,7 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
}
/* Wait for reset to complete */
- err = idpf_check_reset_complete(&adapter->hw, &adapter->reset_reg);
+ err = idpf_check_reset_complete(adapter, &adapter->reset_reg);
if (err) {
dev_err(dev, "The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x%x\n",
adapter->state);
@@ -1871,14 +1941,11 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
goto unlock_mutex;
}
- queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
-
/* Initialize the state machine, also allocate memory and request
* resources
*/
err = idpf_vc_core_init(adapter);
if (err) {
- cancel_delayed_work_sync(&adapter->mbx_task);
idpf_deinit_dflt_mbx(adapter);
goto unlock_mutex;
}
@@ -1892,11 +1959,14 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
unlock_mutex:
mutex_unlock(&adapter->vport_ctrl_lock);
- /* Wait until all vports are created to init RDMA CORE AUX */
- if (!err)
- err = idpf_idc_init(adapter);
-
- return err;
+ /* Attempt to restore netdevs and initialize RDMA CORE AUX device,
+ * provided vc_core_init succeeded. It is still possible that
+ * vports are not allocated at this point if the init task failed.
+ */
+ if (!err) {
+ idpf_attach_and_open(adapter);
+ idpf_idc_init(adapter);
+ }
}
/**
@@ -1921,7 +1991,8 @@ void idpf_vc_event_task(struct work_struct *work)
return;
func_reset:
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
drv_load:
set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
idpf_init_hard_reset(adapter);
@@ -1940,9 +2011,13 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
bool vport_is_up = test_bit(IDPF_VPORT_UP, np->state);
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_adapter *adapter = vport->adapter;
+ struct idpf_vport_config *vport_config;
+ struct idpf_q_vec_rsrc *new_rsrc;
+ u32 vport_id = vport->vport_id;
struct idpf_vport *new_vport;
- int err;
+ int err, tmp_err = 0;
/* If the system is low on memory, we can end up in bad state if we
* free all the memory for queue resources and try to allocate them
@@ -1956,7 +2031,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
* error occurred, the existing vport will be untouched.
*
*/
- new_vport = kzalloc(sizeof(*vport), GFP_KERNEL);
+ new_vport = kzalloc_obj(*vport);
if (!new_vport)
return -ENOMEM;
@@ -1967,16 +2042,18 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
*/
memcpy(new_vport, vport, offsetof(struct idpf_vport, link_up));
+ new_rsrc = &new_vport->dflt_qv_rsrc;
+
/* Adjust resource parameters prior to reallocating resources */
switch (reset_cause) {
case IDPF_SR_Q_CHANGE:
- err = idpf_vport_adjust_qs(new_vport);
+ err = idpf_vport_adjust_qs(new_vport, new_rsrc);
if (err)
goto free_vport;
break;
case IDPF_SR_Q_DESC_CHANGE:
/* Update queue parameters before allocating resources */
- idpf_vport_calc_num_q_desc(new_vport);
+ idpf_vport_calc_num_q_desc(new_vport, new_rsrc);
break;
case IDPF_SR_MTU_CHANGE:
idpf_idc_vdev_mtu_event(vport->vdev_info,
@@ -1990,50 +2067,52 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
goto free_vport;
}
+ vport_config = adapter->vport_config[vport->idx];
+
if (!vport_is_up) {
- idpf_send_delete_queues_msg(vport);
+ idpf_send_delete_queues_msg(adapter, &vport_config->qid_reg_info,
+ vport_id);
} else {
set_bit(IDPF_VPORT_DEL_QUEUES, vport->flags);
idpf_vport_stop(vport, false);
}
- idpf_deinit_rss(vport);
- /* We're passing in vport here because we need its wait_queue
- * to send a message and it should be getting all the vport
- * config data out of the adapter but we need to be careful not
- * to add code to add_queues to change the vport config within
- * vport itself as it will be wiped with a memcpy later.
- */
- err = idpf_send_add_queues_msg(vport, new_vport->num_txq,
- new_vport->num_complq,
- new_vport->num_rxq,
- new_vport->num_bufq);
+ err = idpf_send_add_queues_msg(adapter, vport_config, new_rsrc,
+ vport_id);
if (err)
goto err_reset;
- /* Same comment as above regarding avoiding copying the wait_queues and
- * mutexes applies here. We do not want to mess with those if possible.
+ /* Avoid copying the wait_queues and mutexes. We do not want to mess
+ * with those if possible.
*/
memcpy(vport, new_vport, offsetof(struct idpf_vport, link_up));
if (reset_cause == IDPF_SR_Q_CHANGE)
- idpf_vport_alloc_vec_indexes(vport);
+ idpf_vport_alloc_vec_indexes(vport, &vport->dflt_qv_rsrc);
err = idpf_set_real_num_queues(vport);
if (err)
goto err_open;
+ if (reset_cause == IDPF_SR_Q_CHANGE &&
+ !netif_is_rxfh_configured(vport->netdev)) {
+ struct idpf_rss_data *rss_data;
+
+ rss_data = &vport_config->user_config.rss_data;
+ idpf_fill_dflt_rss_lut(vport, rss_data);
+ }
+
if (vport_is_up)
err = idpf_vport_open(vport, false);
goto free_vport;
err_reset:
- idpf_send_add_queues_msg(vport, vport->num_txq, vport->num_complq,
- vport->num_rxq, vport->num_bufq);
+ tmp_err = idpf_send_add_queues_msg(adapter, vport_config, rsrc,
+ vport_id);
err_open:
- if (vport_is_up)
+ if (!tmp_err && vport_is_up)
idpf_vport_open(vport, false);
free_vport:
@@ -2166,40 +2245,6 @@ static void idpf_set_rx_mode(struct net_device *netdev)
}
/**
- * idpf_vport_manage_rss_lut - disable/enable RSS
- * @vport: the vport being changed
- *
- * In the event of disable request for RSS, this function will zero out RSS
- * LUT, while in the event of enable request for RSS, it will reconfigure RSS
- * LUT with the default LUT configuration.
- */
-static int idpf_vport_manage_rss_lut(struct idpf_vport *vport)
-{
- bool ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH);
- struct idpf_rss_data *rss_data;
- u16 idx = vport->idx;
- int lut_size;
-
- rss_data = &vport->adapter->vport_config[idx]->user_config.rss_data;
- lut_size = rss_data->rss_lut_size * sizeof(u32);
-
- if (ena) {
- /* This will contain the default or user configured LUT */
- memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size);
- } else {
- /* Save a copy of the current LUT to be restored later if
- * requested.
- */
- memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size);
-
- /* Zero out the current LUT to disable */
- memset(rss_data->rss_lut, 0, lut_size);
- }
-
- return idpf_config_rss(vport);
-}
-
-/**
* idpf_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
* @features: the feature set that the stack is suggesting
@@ -2224,10 +2269,24 @@ static int idpf_set_features(struct net_device *netdev,
}
if (changed & NETIF_F_RXHASH) {
+ struct idpf_netdev_priv *np = netdev_priv(netdev);
+
netdev->features ^= NETIF_F_RXHASH;
- err = idpf_vport_manage_rss_lut(vport);
- if (err)
- goto unlock_mutex;
+
+ /* If the interface is not up when changing the rxhash, update
+ * to the HW is skipped. The updated LUT will be committed to
+ * the HW when the interface is brought up.
+ */
+ if (test_bit(IDPF_VPORT_UP, np->state)) {
+ struct idpf_vport_config *vport_config;
+ struct idpf_rss_data *rss_data;
+
+ vport_config = adapter->vport_config[vport->idx];
+ rss_data = &vport_config->user_config.rss_data;
+ err = idpf_config_rss(vport, rss_data);
+ if (err)
+ goto unlock_mutex;
+ }
}
if (changed & NETIF_F_GRO_HW) {
@@ -2238,8 +2297,13 @@ static int idpf_set_features(struct net_device *netdev,
}
if (changed & NETIF_F_LOOPBACK) {
+ bool loopback_ena;
+
netdev->features ^= NETIF_F_LOOPBACK;
- err = idpf_send_ena_dis_loopback_msg(vport);
+ loopback_ena = idpf_is_feature_ena(vport, NETIF_F_LOOPBACK);
+
+ err = idpf_send_ena_dis_loopback_msg(adapter, vport->vport_id,
+ loopback_ena);
}
unlock_mutex:
@@ -2511,44 +2575,6 @@ unlock_mutex:
return err;
}
-/**
- * idpf_alloc_dma_mem - Allocate dma memory
- * @hw: pointer to hw struct
- * @mem: pointer to dma_mem struct
- * @size: size of the memory to allocate
- */
-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem, u64 size)
-{
- struct idpf_adapter *adapter = hw->back;
- size_t sz = ALIGN(size, 4096);
-
- /* The control queue resources are freed under a spinlock, contiguous
- * pages will avoid IOMMU remapping and the use vmap (and vunmap in
- * dma_free_*() path.
- */
- mem->va = dma_alloc_attrs(&adapter->pdev->dev, sz, &mem->pa,
- GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
- mem->size = sz;
-
- return mem->va;
-}
-
-/**
- * idpf_free_dma_mem - Free the allocated dma memory
- * @hw: pointer to hw struct
- * @mem: pointer to dma_mem struct
- */
-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem)
-{
- struct idpf_adapter *adapter = hw->back;
-
- dma_free_attrs(&adapter->pdev->dev, mem->size,
- mem->va, mem->pa, DMA_ATTR_FORCE_CONTIGUOUS);
- mem->size = 0;
- mem->va = NULL;
- mem->pa = 0;
-}
-
static int idpf_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
index de5d722cc21d..129bccaa6baa 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -15,6 +15,8 @@
MODULE_DESCRIPTION(DRV_SUMMARY);
MODULE_IMPORT_NS("LIBETH");
+MODULE_IMPORT_NS("LIBIE_CP");
+MODULE_IMPORT_NS("LIBIE_PCI");
MODULE_IMPORT_NS("LIBETH_XDP");
MODULE_LICENSE("GPL");
@@ -56,8 +58,16 @@ static int idpf_get_device_type(struct pci_dev *pdev)
static int idpf_dev_init(struct idpf_adapter *adapter,
const struct pci_device_id *ent)
{
+ struct libie_mmio_info *mmio_info = &adapter->ctlq_ctx.mmio_info;
int ret;
+ ret = libie_pci_init_dev(adapter->pdev);
+ if (ret)
+ return ret;
+
+ mmio_info->pdev = adapter->pdev;
+ INIT_LIST_HEAD(&mmio_info->mmio_list);
+
if (ent->class == IDPF_CLASS_NETWORK_ETHERNET_PROGIF) {
ret = idpf_get_device_type(adapter->pdev);
switch (ret) {
@@ -91,6 +101,20 @@ static int idpf_dev_init(struct idpf_adapter *adapter,
}
/**
+ * idpf_decfg_device - deconfigure device and device specific resources
+ * @adapter: driver specific private structure
+ */
+static void idpf_decfg_device(struct idpf_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (pcie_ptm_enabled(pdev))
+ pci_disable_ptm(pdev);
+
+ libie_pci_unmap_all_mmio_regions(&adapter->ctlq_ctx.mmio_info);
+}
+
+/**
* idpf_remove - Device removal routine
* @pdev: PCI device information struct
*/
@@ -151,14 +175,13 @@ destroy_wqs:
adapter->vport_config = NULL;
kfree(adapter->netdevs);
adapter->netdevs = NULL;
- kfree(adapter->vcxn_mngr);
- adapter->vcxn_mngr = NULL;
mutex_destroy(&adapter->vport_ctrl_lock);
mutex_destroy(&adapter->vector_lock);
mutex_destroy(&adapter->queue_lock);
mutex_destroy(&adapter->vc_buf_lock);
+ idpf_decfg_device(adapter);
pci_set_drvdata(pdev, NULL);
kfree(adapter);
}
@@ -181,46 +204,44 @@ static void idpf_shutdown(struct pci_dev *pdev)
}
/**
- * idpf_cfg_hw - Initialize HW struct
- * @adapter: adapter to setup hw struct for
+ * idpf_cfg_device - configure device and device specific resources
+ * @adapter: driver specific private structure
*
- * Returns 0 on success, negative on failure
+ * Return: %0 on success, -%errno on failure.
*/
-static int idpf_cfg_hw(struct idpf_adapter *adapter)
+static int idpf_cfg_device(struct idpf_adapter *adapter)
{
- resource_size_t res_start, mbx_start, rstat_start;
+ struct libie_mmio_info *mmio_info = &adapter->ctlq_ctx.mmio_info;
struct pci_dev *pdev = adapter->pdev;
- struct idpf_hw *hw = &adapter->hw;
- struct device *dev = &pdev->dev;
- long len;
-
- res_start = pci_resource_start(pdev, 0);
+ struct resource *region;
+ bool mapped;
+ int err;
/* Map mailbox space for virtchnl communication */
- mbx_start = res_start + adapter->dev_ops.static_reg_info[0].start;
- len = resource_size(&adapter->dev_ops.static_reg_info[0]);
- hw->mbx.vaddr = devm_ioremap(dev, mbx_start, len);
- if (!hw->mbx.vaddr) {
- pci_err(pdev, "failed to allocate BAR0 mbx region\n");
-
+ region = &adapter->dev_ops.static_reg_info[0];
+ mapped = libie_pci_map_mmio_region(mmio_info, region->start,
+ resource_size(region));
+ if (!mapped) {
+ pci_err(pdev, "failed to map BAR0 mbx region\n");
return -ENOMEM;
}
- hw->mbx.addr_start = adapter->dev_ops.static_reg_info[0].start;
- hw->mbx.addr_len = len;
/* Map rstat space for resets */
- rstat_start = res_start + adapter->dev_ops.static_reg_info[1].start;
- len = resource_size(&adapter->dev_ops.static_reg_info[1]);
- hw->rstat.vaddr = devm_ioremap(dev, rstat_start, len);
- if (!hw->rstat.vaddr) {
- pci_err(pdev, "failed to allocate BAR0 rstat region\n");
+ region = &adapter->dev_ops.static_reg_info[1];
+ mapped = libie_pci_map_mmio_region(mmio_info, region->start,
+ resource_size(region));
+ if (!mapped) {
+ pci_err(pdev, "failed to map BAR0 rstat region\n");
+ libie_pci_unmap_all_mmio_regions(mmio_info);
return -ENOMEM;
}
- hw->rstat.addr_start = adapter->dev_ops.static_reg_info[1].start;
- hw->rstat.addr_len = len;
- hw->back = adapter;
+ err = pci_enable_ptm(pdev);
+ if (err)
+ pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
+
+ pci_set_drvdata(pdev, adapter);
return 0;
}
@@ -238,7 +259,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct idpf_adapter *adapter;
int err;
- adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ adapter = kzalloc_obj(*adapter);
if (!adapter)
return -ENOMEM;
@@ -246,32 +267,21 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->req_rx_splitq = true;
adapter->pdev = pdev;
- err = pcim_enable_device(pdev);
- if (err)
- goto err_free;
- err = pcim_request_region(pdev, 0, pci_name(pdev));
+ err = idpf_dev_init(adapter, ent);
if (err) {
- pci_err(pdev, "pcim_request_region failed %pe\n", ERR_PTR(err));
-
+ dev_err(&pdev->dev, "Failed to initialize device (ID 0x%x): %d\n",
+ ent->device, err);
goto err_free;
}
- err = pci_enable_ptm(pdev, NULL);
- if (err)
- pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
-
- /* set up for high or low dma */
- err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ err = idpf_cfg_device(adapter);
if (err) {
- pci_err(pdev, "DMA configuration failed: %pe\n", ERR_PTR(err));
-
+ pci_err(pdev, "Failed to configure device specific resources: %pe\n",
+ ERR_PTR(err));
goto err_free;
}
- pci_set_master(pdev);
- pci_set_drvdata(pdev, adapter);
-
adapter->init_wq = alloc_workqueue("%s-%s-init",
WQ_UNBOUND | WQ_MEM_RECLAIM, 0,
dev_driver_string(dev),
@@ -279,7 +289,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!adapter->init_wq) {
dev_err(dev, "Failed to allocate init workqueue\n");
err = -ENOMEM;
- goto err_free;
+ goto err_init_wq;
}
adapter->serv_wq = alloc_workqueue("%s-%s-service",
@@ -324,20 +334,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* setup msglvl */
adapter->msg_enable = netif_msg_init(-1, IDPF_AVAIL_NETIF_M);
- err = idpf_dev_init(adapter, ent);
- if (err) {
- dev_err(&pdev->dev, "Unexpected dev ID 0x%x in idpf probe\n",
- ent->device);
- goto destroy_vc_event_wq;
- }
-
- err = idpf_cfg_hw(adapter);
- if (err) {
- dev_err(dev, "Failed to configure HW structure for adapter: %d\n",
- err);
- goto destroy_vc_event_wq;
- }
-
mutex_init(&adapter->vport_ctrl_lock);
mutex_init(&adapter->vector_lock);
mutex_init(&adapter->queue_lock);
@@ -356,8 +352,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
-destroy_vc_event_wq:
- destroy_workqueue(adapter->vc_event_wq);
err_vc_event_wq_alloc:
destroy_workqueue(adapter->stats_wq);
err_stats_wq_alloc:
@@ -366,6 +360,8 @@ err_mbx_wq_alloc:
destroy_workqueue(adapter->serv_wq);
err_serv_wq_alloc:
destroy_workqueue(adapter->init_wq);
+err_init_wq:
+ idpf_decfg_device(adapter);
err_free:
kfree(adapter);
return err;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_mem.h b/drivers/net/ethernet/intel/idpf/idpf_mem.h
deleted file mode 100644
index 2aaabdc02dd2..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_mem.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_MEM_H_
-#define _IDPF_MEM_H_
-
-#include <linux/io.h>
-
-struct idpf_dma_mem {
- void *va;
- dma_addr_t pa;
- size_t size;
-};
-
-#define idpf_mbx_wr32(a, reg, value) writel((value), ((a)->mbx.vaddr + (reg)))
-#define idpf_mbx_rd32(a, reg) readl((a)->mbx.vaddr + (reg))
-#define idpf_mbx_wr64(a, reg, value) writeq((value), ((a)->mbx.vaddr + (reg)))
-#define idpf_mbx_rd64(a, reg) readq((a)->mbx.vaddr + (reg))
-
-#endif /* _IDPF_MEM_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c
index 3e1052d070cf..71fe8b2a8b4e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c
@@ -51,7 +51,7 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter)
/* Set the device clock time */
direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME;
- mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME;
+ mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB;
ptp->set_dev_clk_time_access = idpf_ptp_get_access(adapter,
direct,
mailbox);
@@ -108,11 +108,11 @@ static u64 idpf_ptp_read_src_clk_reg_direct(struct idpf_adapter *adapter,
ptp_read_system_prets(sts);
idpf_ptp_enable_shtime(adapter);
+ lo = readl(ptp->dev_clk_regs.dev_clk_ns_l);
/* Read the system timestamp post PHC read */
ptp_read_system_postts(sts);
- lo = readl(ptp->dev_clk_regs.dev_clk_ns_l);
hi = readl(ptp->dev_clk_regs.dev_clk_ns_h);
spin_unlock(&ptp->read_dev_clk_lock);
@@ -384,15 +384,17 @@ static int idpf_ptp_update_cached_phctime(struct idpf_adapter *adapter)
WRITE_ONCE(adapter->ptp->cached_phc_jiffies, jiffies);
idpf_for_each_vport(adapter, vport) {
+ struct idpf_q_vec_rsrc *rsrc;
bool split;
- if (!vport || !vport->rxq_grps)
+ if (!vport || !vport->dflt_qv_rsrc.rxq_grps)
continue;
- split = idpf_is_queue_model_split(vport->rxq_model);
+ rsrc = &vport->dflt_qv_rsrc;
+ split = idpf_is_queue_model_split(rsrc->rxq_model);
- for (u16 i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *grp = &vport->rxq_grps[i];
+ for (u16 i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *grp = &rsrc->rxq_grps[i];
idpf_ptp_update_phctime_rxq_grp(grp, split, systime);
}
@@ -681,9 +683,10 @@ int idpf_ptp_request_ts(struct idpf_tx_queue *tx_q, struct sk_buff *skb,
*/
static void idpf_ptp_set_rx_tstamp(struct idpf_vport *vport, int rx_filter)
{
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
bool enable = true, splitq;
- splitq = idpf_is_queue_model_split(vport->rxq_model);
+ splitq = idpf_is_queue_model_split(rsrc->rxq_model);
if (rx_filter == HWTSTAMP_FILTER_NONE) {
enable = false;
@@ -692,8 +695,8 @@ static void idpf_ptp_set_rx_tstamp(struct idpf_vport *vport, int rx_filter)
vport->tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL;
}
- for (u16 i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *grp = &vport->rxq_grps[i];
+ for (u16 i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *grp = &rsrc->rxq_grps[i];
struct idpf_rx_queue *rx_queue;
u16 j, num_rxq;
@@ -933,7 +936,7 @@ int idpf_ptp_init(struct idpf_adapter *adapter)
return -EOPNOTSUPP;
}
- adapter->ptp = kzalloc(sizeof(*adapter->ptp), GFP_KERNEL);
+ adapter->ptp = kzalloc_obj(*adapter->ptp);
if (!adapter->ptp)
return -ENOMEM;
@@ -949,6 +952,8 @@ int idpf_ptp_init(struct idpf_adapter *adapter)
goto free_ptp;
}
+ spin_lock_init(&adapter->ptp->read_dev_clk_lock);
+
err = idpf_ptp_create_clock(adapter);
if (err)
goto free_ptp;
@@ -974,8 +979,6 @@ int idpf_ptp_init(struct idpf_adapter *adapter)
goto remove_clock;
}
- spin_lock_init(&adapter->ptp->read_dev_clk_lock);
-
pci_dbg(adapter->pdev, "PTP init successful\n");
return 0;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 1d91c56f7469..4311ffa30bb1 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -19,6 +19,8 @@ LIBETH_SQE_CHECK_PRIV(u32);
* Make sure we don't exceed maximum scatter gather buffers for a single
* packet.
* TSO case has been handled earlier from idpf_features_check().
+ *
+ * Return: %true if skb exceeds max descriptors per packet, %false otherwise.
*/
static bool idpf_chk_linearize(const struct sk_buff *skb,
unsigned int max_bufs,
@@ -146,24 +148,22 @@ static void idpf_compl_desc_rel(struct idpf_compl_queue *complq)
/**
* idpf_tx_desc_rel_all - Free Tx Resources for All Queues
- * @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
*
* Free all transmit software resources
*/
-static void idpf_tx_desc_rel_all(struct idpf_vport *vport)
+static void idpf_tx_desc_rel_all(struct idpf_q_vec_rsrc *rsrc)
{
- int i, j;
-
- if (!vport->txq_grps)
+ if (!rsrc->txq_grps)
return;
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
- for (j = 0; j < txq_grp->num_txq; j++)
+ for (unsigned int j = 0; j < txq_grp->num_txq; j++)
idpf_tx_desc_rel(txq_grp->txqs[j]);
- if (idpf_is_queue_model_split(vport->txq_model))
+ if (idpf_is_queue_model_split(rsrc->txq_model))
idpf_compl_desc_rel(txq_grp->complq);
}
}
@@ -172,7 +172,7 @@ static void idpf_tx_desc_rel_all(struct idpf_vport *vport)
* idpf_tx_buf_alloc_all - Allocate memory for all buffer resources
* @tx_q: queue for which the buffers are allocated
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q)
{
@@ -183,8 +183,7 @@ static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q)
tx_q->buf_pool_size = U16_MAX;
else
tx_q->buf_pool_size = tx_q->desc_count;
- tx_q->tx_buf = kcalloc(tx_q->buf_pool_size, sizeof(*tx_q->tx_buf),
- GFP_KERNEL);
+ tx_q->tx_buf = kzalloc_objs(*tx_q->tx_buf, tx_q->buf_pool_size);
if (!tx_q->tx_buf)
return -ENOMEM;
@@ -196,7 +195,7 @@ static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q)
* @vport: vport to allocate resources for
* @tx_q: the tx ring to set up
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
static int idpf_tx_desc_alloc(const struct idpf_vport *vport,
struct idpf_tx_queue *tx_q)
@@ -263,7 +262,7 @@ err_alloc:
/**
* idpf_compl_desc_alloc - allocate completion descriptors
- * @vport: vport to allocate resources for
+ * @vport: virtual port private structure
* @complq: completion queue to set up
*
* Return: 0 on success, -errno on failure.
@@ -296,20 +295,21 @@ static int idpf_compl_desc_alloc(const struct idpf_vport *vport,
/**
* idpf_tx_desc_alloc_all - allocate all queues Tx resources
* @vport: virtual port private structure
+ * @rsrc: pointer to queue and vector resources
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_tx_desc_alloc_all(struct idpf_vport *vport)
+static int idpf_tx_desc_alloc_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
int err = 0;
- int i, j;
/* Setup buffer queues. In single queue model buffer queues and
* completion queues will be same
*/
- for (i = 0; i < vport->num_txq_grp; i++) {
- for (j = 0; j < vport->txq_grps[i].num_txq; j++) {
- struct idpf_tx_queue *txq = vport->txq_grps[i].txqs[j];
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ for (unsigned int j = 0; j < rsrc->txq_grps[i].num_txq; j++) {
+ struct idpf_tx_queue *txq = rsrc->txq_grps[i].txqs[j];
err = idpf_tx_desc_alloc(vport, txq);
if (err) {
@@ -320,11 +320,11 @@ static int idpf_tx_desc_alloc_all(struct idpf_vport *vport)
}
}
- if (!idpf_is_queue_model_split(vport->txq_model))
+ if (!idpf_is_queue_model_split(rsrc->txq_model))
continue;
/* Setup completion queues */
- err = idpf_compl_desc_alloc(vport, vport->txq_grps[i].complq);
+ err = idpf_compl_desc_alloc(vport, rsrc->txq_grps[i].complq);
if (err) {
pci_err(vport->adapter->pdev,
"Allocation for Tx Completion Queue %u failed\n",
@@ -335,7 +335,7 @@ static int idpf_tx_desc_alloc_all(struct idpf_vport *vport)
err_out:
if (err)
- idpf_tx_desc_rel_all(vport);
+ idpf_tx_desc_rel_all(rsrc);
return err;
}
@@ -488,38 +488,38 @@ 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
*/
-static void idpf_rx_desc_rel_all(struct idpf_vport *vport)
+static void idpf_rx_desc_rel_all(struct idpf_q_vec_rsrc *rsrc)
{
- struct device *dev = &vport->adapter->pdev->dev;
+ struct device *dev = rsrc->dev;
struct idpf_rxq_group *rx_qgrp;
u16 num_rxq;
- int i, j;
- if (!vport->rxq_grps)
+ if (!rsrc->rxq_grps)
return;
- for (i = 0; i < vport->num_rxq_grp; i++) {
- rx_qgrp = &vport->rxq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ rx_qgrp = &rsrc->rxq_grps[i];
- if (!idpf_is_queue_model_split(vport->rxq_model)) {
- for (j = 0; j < rx_qgrp->singleq.num_rxq; j++)
+ if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
+ for (unsigned int j = 0; j < rx_qgrp->singleq.num_rxq; j++)
idpf_rx_desc_rel(rx_qgrp->singleq.rxqs[j], dev,
VIRTCHNL2_QUEUE_MODEL_SINGLE);
continue;
}
num_rxq = rx_qgrp->splitq.num_rxq_sets;
- for (j = 0; j < num_rxq; j++)
+ for (unsigned int j = 0; j < num_rxq; j++)
idpf_rx_desc_rel(&rx_qgrp->splitq.rxq_sets[j]->rxq,
dev, VIRTCHNL2_QUEUE_MODEL_SPLIT);
if (!rx_qgrp->splitq.bufq_sets)
continue;
- for (j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (unsigned int j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
struct idpf_bufq_set *bufq_set =
&rx_qgrp->splitq.bufq_sets[j];
@@ -548,7 +548,7 @@ static void idpf_rx_buf_hw_update(struct idpf_buf_queue *bufq, u32 val)
* idpf_rx_hdr_buf_alloc_all - Allocate memory for header buffers
* @bufq: ring to use
*
- * Returns 0 on success, negative on failure.
+ * Return: 0 on success, negative on failure.
*/
static int idpf_rx_hdr_buf_alloc_all(struct idpf_buf_queue *bufq)
{
@@ -600,7 +600,7 @@ static void idpf_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id)
* @bufq: buffer queue to post to
* @buf_id: buffer id to post
*
- * Returns false if buffer could not be allocated, true otherwise.
+ * Return: %false if buffer could not be allocated, %true otherwise.
*/
static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16 buf_id)
{
@@ -649,7 +649,7 @@ static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16 buf_id)
* @bufq: buffer queue to post working set to
* @working_set: number of buffers to put in working set
*
- * Returns true if @working_set bufs were posted successfully, false otherwise.
+ * Return: %true if @working_set bufs were posted successfully, %false otherwise.
*/
static bool idpf_rx_post_init_bufs(struct idpf_buf_queue *bufq,
u16 working_set)
@@ -695,9 +695,10 @@ err:
static int idpf_rx_bufs_init_singleq(struct idpf_rx_queue *rxq)
{
struct libeth_fq fq = {
- .count = rxq->desc_count,
- .type = LIBETH_FQE_MTU,
- .nid = idpf_q_vector_to_mem(rxq->q_vector),
+ .count = rxq->desc_count,
+ .type = LIBETH_FQE_MTU,
+ .buf_len = IDPF_RX_MAX_BUF_SZ,
+ .nid = idpf_q_vector_to_mem(rxq->q_vector),
};
int ret;
@@ -717,7 +718,7 @@ static int idpf_rx_bufs_init_singleq(struct idpf_rx_queue *rxq)
* idpf_rx_buf_alloc_all - Allocate memory for all buffer resources
* @rxbufq: queue for which the buffers are allocated
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
static int idpf_rx_buf_alloc_all(struct idpf_buf_queue *rxbufq)
{
@@ -745,7 +746,7 @@ rx_buf_alloc_all_out:
* @bufq: buffer queue to create page pool for
* @type: type of Rx buffers to allocate
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq,
enum libeth_fqe_type type)
@@ -754,6 +755,7 @@ static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq,
.truesize = bufq->truesize,
.count = bufq->desc_count,
.type = type,
+ .buf_len = IDPF_RX_MAX_BUF_SZ,
.hsplit = idpf_queue_has(HSPLIT_EN, bufq),
.xdp = idpf_xdp_enabled(bufq->q_vector->vport),
.nid = idpf_q_vector_to_mem(bufq->q_vector),
@@ -777,26 +779,28 @@ static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq,
/**
* idpf_rx_bufs_init_all - Initialize all RX bufs
- * @vport: virtual port struct
+ * @vport: pointer to vport struct
+ * @rsrc: pointer to queue and vector resources
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-int idpf_rx_bufs_init_all(struct idpf_vport *vport)
+int idpf_rx_bufs_init_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
- bool split = idpf_is_queue_model_split(vport->rxq_model);
- int i, j, err;
+ bool split = idpf_is_queue_model_split(rsrc->rxq_model);
+ int err;
- idpf_xdp_copy_prog_to_rqs(vport, vport->xdp_prog);
+ idpf_xdp_copy_prog_to_rqs(rsrc, vport->xdp_prog);
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u32 truesize = 0;
/* Allocate bufs for the rxq itself in singleq */
if (!split) {
int num_rxq = rx_qgrp->singleq.num_rxq;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
struct idpf_rx_queue *q;
q = rx_qgrp->singleq.rxqs[j];
@@ -809,7 +813,7 @@ int idpf_rx_bufs_init_all(struct idpf_vport *vport)
}
/* Otherwise, allocate bufs for the buffer queues */
- for (j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (unsigned int j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
enum libeth_fqe_type type;
struct idpf_buf_queue *q;
@@ -834,7 +838,7 @@ int idpf_rx_bufs_init_all(struct idpf_vport *vport)
* @vport: vport to allocate resources for
* @rxq: Rx queue for which the resources are setup
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
static int idpf_rx_desc_alloc(const struct idpf_vport *vport,
struct idpf_rx_queue *rxq)
@@ -895,26 +899,28 @@ static int idpf_bufq_desc_alloc(const struct idpf_vport *vport,
/**
* idpf_rx_desc_alloc_all - allocate all RX queues resources
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_rx_desc_alloc_all(struct idpf_vport *vport)
+static int idpf_rx_desc_alloc_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_rxq_group *rx_qgrp;
- int i, j, err;
u16 num_rxq;
+ int err;
- for (i = 0; i < vport->num_rxq_grp; i++) {
- rx_qgrp = &vport->rxq_grps[i];
- if (idpf_is_queue_model_split(vport->rxq_model))
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ rx_qgrp = &rsrc->rxq_grps[i];
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
num_rxq = rx_qgrp->splitq.num_rxq_sets;
else
num_rxq = rx_qgrp->singleq.num_rxq;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
struct idpf_rx_queue *q;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
else
q = rx_qgrp->singleq.rxqs[j];
@@ -928,10 +934,10 @@ static int idpf_rx_desc_alloc_all(struct idpf_vport *vport)
}
}
- if (!idpf_is_queue_model_split(vport->rxq_model))
+ if (!idpf_is_queue_model_split(rsrc->rxq_model))
continue;
- for (j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (unsigned int j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
struct idpf_buf_queue *q;
q = &rx_qgrp->splitq.bufq_sets[j].bufq;
@@ -949,18 +955,18 @@ static int idpf_rx_desc_alloc_all(struct idpf_vport *vport)
return 0;
err_out:
- idpf_rx_desc_rel_all(vport);
+ idpf_rx_desc_rel_all(rsrc);
return err;
}
-static int idpf_init_queue_set(const struct idpf_queue_set *qs)
+static int idpf_init_queue_set(const struct idpf_vport *vport,
+ const struct idpf_queue_set *qs)
{
- const struct idpf_vport *vport = qs->vport;
bool splitq;
int err;
- splitq = idpf_is_queue_model_split(vport->rxq_model);
+ splitq = idpf_is_queue_model_split(qs->qv_rsrc->rxq_model);
for (u32 i = 0; i < qs->num; i++) {
const struct idpf_queue_ptr *q = &qs->qs[i];
@@ -1030,19 +1036,18 @@ static int idpf_init_queue_set(const struct idpf_queue_set *qs)
static void idpf_clean_queue_set(const struct idpf_queue_set *qs)
{
- const struct idpf_vport *vport = qs->vport;
- struct device *dev = vport->netdev->dev.parent;
+ const struct idpf_q_vec_rsrc *rsrc = qs->qv_rsrc;
for (u32 i = 0; i < qs->num; i++) {
const struct idpf_queue_ptr *q = &qs->qs[i];
switch (q->type) {
case VIRTCHNL2_QUEUE_TYPE_RX:
- idpf_xdp_rxq_info_deinit(q->rxq, vport->rxq_model);
- idpf_rx_desc_rel(q->rxq, dev, vport->rxq_model);
+ idpf_xdp_rxq_info_deinit(q->rxq, rsrc->rxq_model);
+ idpf_rx_desc_rel(q->rxq, rsrc->dev, rsrc->rxq_model);
break;
case VIRTCHNL2_QUEUE_TYPE_RX_BUFFER:
- idpf_rx_desc_rel_bufq(q->bufq, dev);
+ idpf_rx_desc_rel_bufq(q->bufq, rsrc->dev);
break;
case VIRTCHNL2_QUEUE_TYPE_TX:
idpf_tx_desc_rel(q->txq);
@@ -1109,7 +1114,8 @@ static void idpf_qvec_ena_irq(struct idpf_q_vector *qv)
static struct idpf_queue_set *
idpf_vector_to_queue_set(struct idpf_q_vector *qv)
{
- bool xdp = qv->vport->xdp_txq_offset && !qv->num_xsksq;
+ u32 xdp_txq_offset = qv->vport->dflt_qv_rsrc.xdp_txq_offset;
+ bool xdp = xdp_txq_offset && !qv->num_xsksq;
struct idpf_vport *vport = qv->vport;
struct idpf_queue_set *qs;
u32 num;
@@ -1119,7 +1125,8 @@ idpf_vector_to_queue_set(struct idpf_q_vector *qv)
if (!num)
return NULL;
- qs = idpf_alloc_queue_set(vport, num);
+ qs = idpf_alloc_queue_set(vport->adapter, &vport->dflt_qv_rsrc,
+ vport->vport_id, num);
if (!qs)
return NULL;
@@ -1145,12 +1152,12 @@ idpf_vector_to_queue_set(struct idpf_q_vector *qv)
qs->qs[num++].complq = qv->complq[i];
}
- if (!vport->xdp_txq_offset)
+ if (!xdp_txq_offset)
goto finalize;
if (xdp) {
for (u32 i = 0; i < qv->num_rxq; i++) {
- u32 idx = vport->xdp_txq_offset + qv->rx[i]->idx;
+ u32 idx = xdp_txq_offset + qv->rx[i]->idx;
qs->qs[num].type = VIRTCHNL2_QUEUE_TYPE_TX;
qs->qs[num++].txq = vport->txqs[idx];
@@ -1177,27 +1184,27 @@ finalize:
return qs;
}
-static int idpf_qp_enable(const struct idpf_queue_set *qs, u32 qid)
+static int idpf_qp_enable(const struct idpf_vport *vport,
+ const struct idpf_queue_set *qs, u32 qid)
{
- struct idpf_vport *vport = qs->vport;
+ const struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_q_vector *q_vector;
int err;
q_vector = idpf_find_rxq_vec(vport, qid);
- err = idpf_init_queue_set(qs);
+ err = idpf_init_queue_set(vport, qs);
if (err) {
netdev_err(vport->netdev, "Could not initialize queues in pair %u: %pe\n",
qid, ERR_PTR(err));
return err;
}
- if (!vport->xdp_txq_offset)
+ if (!rsrc->xdp_txq_offset)
goto config;
- q_vector->xsksq = kcalloc(DIV_ROUND_UP(vport->num_rxq_grp,
- vport->num_q_vectors),
- sizeof(*q_vector->xsksq), GFP_KERNEL);
+ q_vector->xsksq = kzalloc_objs(*q_vector->xsksq,
+ DIV_ROUND_UP(rsrc->num_rxq_grp, rsrc->num_q_vectors));
if (!q_vector->xsksq)
return -ENOMEM;
@@ -1239,9 +1246,9 @@ config:
return 0;
}
-static int idpf_qp_disable(const struct idpf_queue_set *qs, u32 qid)
+static int idpf_qp_disable(const struct idpf_vport *vport,
+ const struct idpf_queue_set *qs, u32 qid)
{
- struct idpf_vport *vport = qs->vport;
struct idpf_q_vector *q_vector;
int err;
@@ -1286,30 +1293,31 @@ int idpf_qp_switch(struct idpf_vport *vport, u32 qid, bool en)
if (!qs)
return -ENOMEM;
- return en ? idpf_qp_enable(qs, qid) : idpf_qp_disable(qs, qid);
+ return en ? idpf_qp_enable(vport, qs, qid) :
+ idpf_qp_disable(vport, qs, qid);
}
/**
* idpf_txq_group_rel - Release all resources for txq groups
- * @vport: vport to release txq groups on
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_txq_group_rel(struct idpf_vport *vport)
+static void idpf_txq_group_rel(struct idpf_q_vec_rsrc *rsrc)
{
- bool split, flow_sch_en;
- int i, j;
+ bool split;
- if (!vport->txq_grps)
+ if (!rsrc->txq_grps)
return;
- split = idpf_is_queue_model_split(vport->txq_model);
- flow_sch_en = !idpf_is_cap_ena(vport->adapter, IDPF_OTHER_CAPS,
- VIRTCHNL2_CAP_SPLITQ_QSCHED);
+ split = idpf_is_queue_model_split(rsrc->txq_model);
+
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
+ for (unsigned int j = 0; j < txq_grp->num_txq; j++) {
+ if (!txq_grp->txqs[j])
+ continue;
- for (j = 0; j < txq_grp->num_txq; j++) {
- if (flow_sch_en) {
+ if (idpf_queue_has(FLOW_SCH_EN, txq_grp->txqs[j])) {
kfree(txq_grp->txqs[j]->refillq);
txq_grp->txqs[j]->refillq = NULL;
}
@@ -1324,8 +1332,8 @@ static void idpf_txq_group_rel(struct idpf_vport *vport)
kfree(txq_grp->complq);
txq_grp->complq = NULL;
}
- kfree(vport->txq_grps);
- vport->txq_grps = NULL;
+ kfree(rsrc->txq_grps);
+ rsrc->txq_grps = NULL;
}
/**
@@ -1334,12 +1342,13 @@ static void idpf_txq_group_rel(struct idpf_vport *vport)
*/
static void idpf_rxq_sw_queue_rel(struct idpf_rxq_group *rx_qgrp)
{
- int i, j;
+ if (!rx_qgrp->splitq.bufq_sets)
+ return;
- for (i = 0; i < rx_qgrp->vport->num_bufqs_per_qgrp; i++) {
+ for (unsigned int i = 0; i < rx_qgrp->splitq.num_bufq_sets; i++) {
struct idpf_bufq_set *bufq_set = &rx_qgrp->splitq.bufq_sets[i];
- for (j = 0; j < bufq_set->num_refillqs; j++) {
+ for (unsigned int j = 0; j < bufq_set->num_refillqs; j++) {
kfree(bufq_set->refillqs[j].ring);
bufq_set->refillqs[j].ring = NULL;
}
@@ -1350,23 +1359,20 @@ static void idpf_rxq_sw_queue_rel(struct idpf_rxq_group *rx_qgrp)
/**
* idpf_rxq_group_rel - Release all resources for rxq groups
- * @vport: vport to release rxq groups on
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_rxq_group_rel(struct idpf_vport *vport)
+static void idpf_rxq_group_rel(struct idpf_q_vec_rsrc *rsrc)
{
- int i;
-
- if (!vport->rxq_grps)
+ if (!rsrc->rxq_grps)
return;
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u16 num_rxq;
- int j;
- if (idpf_is_queue_model_split(vport->rxq_model)) {
+ if (idpf_is_queue_model_split(rsrc->rxq_model)) {
num_rxq = rx_qgrp->splitq.num_rxq_sets;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
kfree(rx_qgrp->splitq.rxq_sets[j]);
rx_qgrp->splitq.rxq_sets[j] = NULL;
}
@@ -1376,41 +1382,44 @@ static void idpf_rxq_group_rel(struct idpf_vport *vport)
rx_qgrp->splitq.bufq_sets = NULL;
} else {
num_rxq = rx_qgrp->singleq.num_rxq;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
kfree(rx_qgrp->singleq.rxqs[j]);
rx_qgrp->singleq.rxqs[j] = NULL;
}
}
}
- kfree(vport->rxq_grps);
- vport->rxq_grps = NULL;
+ kfree(rsrc->rxq_grps);
+ rsrc->rxq_grps = NULL;
}
/**
* 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_vport *vport)
+static void idpf_vport_queue_grp_rel_all(struct idpf_q_vec_rsrc *rsrc)
{
- idpf_txq_group_rel(vport);
- idpf_rxq_group_rel(vport);
+ idpf_txq_group_rel(rsrc);
+ idpf_rxq_group_rel(rsrc);
}
/**
* idpf_vport_queues_rel - Free memory for all queues
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
*
* Free the memory allocated for queues associated to a vport
*/
-void idpf_vport_queues_rel(struct idpf_vport *vport)
+void idpf_vport_queues_rel(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
- idpf_xdp_copy_prog_to_rqs(vport, NULL);
+ idpf_xdp_copy_prog_to_rqs(rsrc, NULL);
- idpf_tx_desc_rel_all(vport);
- idpf_rx_desc_rel_all(vport);
+ idpf_tx_desc_rel_all(rsrc);
+ idpf_rx_desc_rel_all(rsrc);
idpf_xdpsqs_put(vport);
- idpf_vport_queue_grp_rel_all(vport);
+ idpf_vport_queue_grp_rel_all(rsrc);
kfree(vport->txqs);
vport->txqs = NULL;
@@ -1419,29 +1428,30 @@ void idpf_vport_queues_rel(struct idpf_vport *vport)
/**
* idpf_vport_init_fast_path_txqs - Initialize fast path txq array
* @vport: vport to init txqs on
+ * @rsrc: pointer to queue and vector resources
*
* We get a queue index from skb->queue_mapping and we need a fast way to
* dereference the queue from queue groups. This allows us to quickly pull a
* txq based on a queue index.
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_vport_init_fast_path_txqs(struct idpf_vport *vport)
+static int idpf_vport_init_fast_path_txqs(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_ptp_vport_tx_tstamp_caps *caps = vport->tx_tstamp_caps;
struct work_struct *tstamp_task = &vport->tstamp_task;
- int i, j, k = 0;
-
- vport->txqs = kcalloc(vport->num_txq, sizeof(*vport->txqs),
- GFP_KERNEL);
+ int k = 0;
+ vport->txqs = kzalloc_objs(*vport->txqs, rsrc->num_txq);
if (!vport->txqs)
return -ENOMEM;
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *tx_grp = &vport->txq_grps[i];
+ vport->num_txq = rsrc->num_txq;
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *tx_grp = &rsrc->txq_grps[i];
- for (j = 0; j < tx_grp->num_txq; j++, k++) {
+ for (unsigned int j = 0; j < tx_grp->num_txq; j++, k++) {
vport->txqs[k] = tx_grp->txqs[j];
vport->txqs[k]->idx = k;
@@ -1460,16 +1470,18 @@ static int idpf_vport_init_fast_path_txqs(struct idpf_vport *vport)
* idpf_vport_init_num_qs - Initialize number of queues
* @vport: vport to initialize queues
* @vport_msg: data to be filled into vport
+ * @rsrc: pointer to queue and vector resources
*/
void idpf_vport_init_num_qs(struct idpf_vport *vport,
- struct virtchnl2_create_vport *vport_msg)
+ struct virtchnl2_create_vport *vport_msg,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_vport_user_config_data *config_data;
u16 idx = vport->idx;
config_data = &vport->adapter->vport_config[idx]->user_config;
- vport->num_txq = le16_to_cpu(vport_msg->num_tx_q);
- vport->num_rxq = le16_to_cpu(vport_msg->num_rx_q);
+ rsrc->num_txq = le16_to_cpu(vport_msg->num_tx_q);
+ rsrc->num_rxq = le16_to_cpu(vport_msg->num_rx_q);
/* number of txqs and rxqs in config data will be zeros only in the
* driver load path and we dont update them there after
*/
@@ -1478,74 +1490,75 @@ void idpf_vport_init_num_qs(struct idpf_vport *vport,
config_data->num_req_rx_qs = le16_to_cpu(vport_msg->num_rx_q);
}
- if (idpf_is_queue_model_split(vport->txq_model))
- vport->num_complq = le16_to_cpu(vport_msg->num_tx_complq);
- if (idpf_is_queue_model_split(vport->rxq_model))
- vport->num_bufq = le16_to_cpu(vport_msg->num_rx_bufq);
+ if (idpf_is_queue_model_split(rsrc->txq_model))
+ rsrc->num_complq = le16_to_cpu(vport_msg->num_tx_complq);
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
+ rsrc->num_bufq = le16_to_cpu(vport_msg->num_rx_bufq);
vport->xdp_prog = config_data->xdp_prog;
if (idpf_xdp_enabled(vport)) {
- vport->xdp_txq_offset = config_data->num_req_tx_qs;
+ rsrc->xdp_txq_offset = config_data->num_req_tx_qs;
vport->num_xdp_txq = le16_to_cpu(vport_msg->num_tx_q) -
- vport->xdp_txq_offset;
+ rsrc->xdp_txq_offset;
vport->xdpsq_share = libeth_xdpsq_shared(vport->num_xdp_txq);
} else {
- vport->xdp_txq_offset = 0;
+ rsrc->xdp_txq_offset = 0;
vport->num_xdp_txq = 0;
vport->xdpsq_share = false;
}
/* Adjust number of buffer queues per Rx queue group. */
- if (!idpf_is_queue_model_split(vport->rxq_model)) {
- vport->num_bufqs_per_qgrp = 0;
+ if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
+ rsrc->num_bufqs_per_qgrp = 0;
return;
}
- vport->num_bufqs_per_qgrp = IDPF_MAX_BUFQS_PER_RXQ_GRP;
+ rsrc->num_bufqs_per_qgrp = IDPF_MAX_BUFQS_PER_RXQ_GRP;
}
/**
* idpf_vport_calc_num_q_desc - Calculate number of queue groups
* @vport: vport to calculate q groups for
+ * @rsrc: pointer to queue and vector resources
*/
-void idpf_vport_calc_num_q_desc(struct idpf_vport *vport)
+void idpf_vport_calc_num_q_desc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_vport_user_config_data *config_data;
- int num_bufqs = vport->num_bufqs_per_qgrp;
+ u8 num_bufqs = rsrc->num_bufqs_per_qgrp;
u32 num_req_txq_desc, num_req_rxq_desc;
u16 idx = vport->idx;
- int i;
config_data = &vport->adapter->vport_config[idx]->user_config;
num_req_txq_desc = config_data->num_req_txq_desc;
num_req_rxq_desc = config_data->num_req_rxq_desc;
- vport->complq_desc_count = 0;
+ rsrc->complq_desc_count = 0;
if (num_req_txq_desc) {
- vport->txq_desc_count = num_req_txq_desc;
- if (idpf_is_queue_model_split(vport->txq_model)) {
- vport->complq_desc_count = num_req_txq_desc;
- if (vport->complq_desc_count < IDPF_MIN_TXQ_COMPLQ_DESC)
- vport->complq_desc_count =
+ rsrc->txq_desc_count = num_req_txq_desc;
+ if (idpf_is_queue_model_split(rsrc->txq_model)) {
+ rsrc->complq_desc_count = num_req_txq_desc;
+ if (rsrc->complq_desc_count < IDPF_MIN_TXQ_COMPLQ_DESC)
+ rsrc->complq_desc_count =
IDPF_MIN_TXQ_COMPLQ_DESC;
}
} else {
- vport->txq_desc_count = IDPF_DFLT_TX_Q_DESC_COUNT;
- if (idpf_is_queue_model_split(vport->txq_model))
- vport->complq_desc_count =
+ rsrc->txq_desc_count = IDPF_DFLT_TX_Q_DESC_COUNT;
+ if (idpf_is_queue_model_split(rsrc->txq_model))
+ rsrc->complq_desc_count =
IDPF_DFLT_TX_COMPLQ_DESC_COUNT;
}
if (num_req_rxq_desc)
- vport->rxq_desc_count = num_req_rxq_desc;
+ rsrc->rxq_desc_count = num_req_rxq_desc;
else
- vport->rxq_desc_count = IDPF_DFLT_RX_Q_DESC_COUNT;
+ rsrc->rxq_desc_count = IDPF_DFLT_RX_Q_DESC_COUNT;
- for (i = 0; i < num_bufqs; i++) {
- if (!vport->bufq_desc_count[i])
- vport->bufq_desc_count[i] =
- IDPF_RX_BUFQ_DESC_COUNT(vport->rxq_desc_count,
+ for (unsigned int i = 0; i < num_bufqs; i++) {
+ if (!rsrc->bufq_desc_count[i])
+ rsrc->bufq_desc_count[i] =
+ IDPF_RX_BUFQ_DESC_COUNT(rsrc->rxq_desc_count,
num_bufqs);
}
}
@@ -1557,7 +1570,7 @@ void idpf_vport_calc_num_q_desc(struct idpf_vport *vport)
* @vport_msg: message to fill with data
* @max_q: vport max queue info
*
- * Return 0 on success, error value on failure.
+ * Return: 0 on success, error value on failure.
*/
int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
struct virtchnl2_create_vport *vport_msg,
@@ -1634,54 +1647,54 @@ int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
/**
* idpf_vport_calc_num_q_groups - Calculate number of queue groups
- * @vport: vport to calculate q groups for
+ * @rsrc: pointer to queue and vector resources
*/
-void idpf_vport_calc_num_q_groups(struct idpf_vport *vport)
+void idpf_vport_calc_num_q_groups(struct idpf_q_vec_rsrc *rsrc)
{
- if (idpf_is_queue_model_split(vport->txq_model))
- vport->num_txq_grp = vport->num_txq;
+ if (idpf_is_queue_model_split(rsrc->txq_model))
+ rsrc->num_txq_grp = rsrc->num_txq;
else
- vport->num_txq_grp = IDPF_DFLT_SINGLEQ_TX_Q_GROUPS;
+ rsrc->num_txq_grp = IDPF_DFLT_SINGLEQ_TX_Q_GROUPS;
- if (idpf_is_queue_model_split(vport->rxq_model))
- vport->num_rxq_grp = vport->num_rxq;
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
+ rsrc->num_rxq_grp = rsrc->num_rxq;
else
- vport->num_rxq_grp = IDPF_DFLT_SINGLEQ_RX_Q_GROUPS;
+ rsrc->num_rxq_grp = IDPF_DFLT_SINGLEQ_RX_Q_GROUPS;
}
/**
* idpf_vport_calc_numq_per_grp - Calculate number of queues per group
- * @vport: vport to calculate queues for
+ * @rsrc: pointer to queue and vector resources
* @num_txq: return parameter for number of TX queues
* @num_rxq: return parameter for number of RX queues
*/
-static void idpf_vport_calc_numq_per_grp(struct idpf_vport *vport,
+static void idpf_vport_calc_numq_per_grp(struct idpf_q_vec_rsrc *rsrc,
u16 *num_txq, u16 *num_rxq)
{
- if (idpf_is_queue_model_split(vport->txq_model))
+ if (idpf_is_queue_model_split(rsrc->txq_model))
*num_txq = IDPF_DFLT_SPLITQ_TXQ_PER_GROUP;
else
- *num_txq = vport->num_txq;
+ *num_txq = rsrc->num_txq;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
*num_rxq = IDPF_DFLT_SPLITQ_RXQ_PER_GROUP;
else
- *num_rxq = vport->num_rxq;
+ *num_rxq = rsrc->num_rxq;
}
/**
* idpf_rxq_set_descids - set the descids supported by this queue
- * @vport: virtual port data structure
+ * @rsrc: pointer to queue and vector resources
* @q: rx queue for which descids are set
*
*/
-static void idpf_rxq_set_descids(const struct idpf_vport *vport,
+static void idpf_rxq_set_descids(struct idpf_q_vec_rsrc *rsrc,
struct idpf_rx_queue *q)
{
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
return;
- if (vport->base_rxd)
+ if (rsrc->base_rxd)
q->rxdids = VIRTCHNL2_RXDID_1_32B_BASE_M;
else
q->rxdids = VIRTCHNL2_RXDID_2_FLEX_SQ_NIC_M;
@@ -1690,44 +1703,43 @@ static void idpf_rxq_set_descids(const struct idpf_vport *vport,
/**
* idpf_txq_group_alloc - Allocate all txq group resources
* @vport: vport to allocate txq groups for
+ * @rsrc: pointer to queue and vector resources
* @num_txq: number of txqs to allocate for each group
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq)
+static int idpf_txq_group_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ u16 num_txq)
{
bool split, flow_sch_en;
- int i;
- vport->txq_grps = kcalloc(vport->num_txq_grp,
- sizeof(*vport->txq_grps), GFP_KERNEL);
- if (!vport->txq_grps)
+ rsrc->txq_grps = kzalloc_objs(*rsrc->txq_grps, rsrc->num_txq_grp);
+ if (!rsrc->txq_grps)
return -ENOMEM;
- split = idpf_is_queue_model_split(vport->txq_model);
+ split = idpf_is_queue_model_split(rsrc->txq_model);
flow_sch_en = !idpf_is_cap_ena(vport->adapter, IDPF_OTHER_CAPS,
VIRTCHNL2_CAP_SPLITQ_QSCHED);
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (unsigned int i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
struct idpf_adapter *adapter = vport->adapter;
- int j;
tx_qgrp->vport = vport;
tx_qgrp->num_txq = num_txq;
- for (j = 0; j < tx_qgrp->num_txq; j++) {
- tx_qgrp->txqs[j] = kzalloc(sizeof(*tx_qgrp->txqs[j]),
- GFP_KERNEL);
+ for (unsigned int j = 0; j < tx_qgrp->num_txq; j++) {
+ tx_qgrp->txqs[j] = kzalloc_obj(*tx_qgrp->txqs[j]);
if (!tx_qgrp->txqs[j])
goto err_alloc;
}
- for (j = 0; j < tx_qgrp->num_txq; j++) {
+ for (unsigned int j = 0; j < tx_qgrp->num_txq; j++) {
struct idpf_tx_queue *q = tx_qgrp->txqs[j];
q->dev = &adapter->pdev->dev;
- q->desc_count = vport->txq_desc_count;
+ 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->netdev = vport->netdev;
@@ -1745,7 +1757,7 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq)
idpf_queue_set(FLOW_SCH_EN, q);
- q->refillq = kzalloc(sizeof(*q->refillq), GFP_KERNEL);
+ q->refillq = kzalloc_obj(*q->refillq);
if (!q->refillq)
goto err_alloc;
@@ -1756,13 +1768,12 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq)
if (!split)
continue;
- tx_qgrp->complq = kcalloc(IDPF_COMPLQ_PER_GROUP,
- sizeof(*tx_qgrp->complq),
- GFP_KERNEL);
+ tx_qgrp->complq = kzalloc_objs(*tx_qgrp->complq,
+ IDPF_COMPLQ_PER_GROUP);
if (!tx_qgrp->complq)
goto err_alloc;
- tx_qgrp->complq->desc_count = vport->complq_desc_count;
+ tx_qgrp->complq->desc_count = rsrc->complq_desc_count;
tx_qgrp->complq->txq_grp = tx_qgrp;
tx_qgrp->complq->netdev = vport->netdev;
tx_qgrp->complq->clean_budget = vport->compln_clean_budget;
@@ -1774,7 +1785,7 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq)
return 0;
err_alloc:
- idpf_txq_group_rel(vport);
+ idpf_txq_group_rel(rsrc);
return -ENOMEM;
}
@@ -1782,33 +1793,34 @@ err_alloc:
/**
* idpf_rxq_group_alloc - Allocate all rxq group resources
* @vport: vport to allocate rxq groups for
+ * @rsrc: pointer to queue and vector resources
* @num_rxq: number of rxqs to allocate for each group
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_rxq_group_alloc(struct idpf_vport *vport, u16 num_rxq)
+static int idpf_rxq_group_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ u16 num_rxq)
{
- int i, k, err = 0;
- bool hs;
+ struct idpf_adapter *adapter = vport->adapter;
+ bool hs, rsc;
+ int err = 0;
- vport->rxq_grps = kcalloc(vport->num_rxq_grp,
- sizeof(struct idpf_rxq_group), GFP_KERNEL);
- if (!vport->rxq_grps)
+ rsrc->rxq_grps = kzalloc_objs(struct idpf_rxq_group, rsrc->num_rxq_grp);
+ if (!rsrc->rxq_grps)
return -ENOMEM;
hs = idpf_vport_get_hsplit(vport) == ETHTOOL_TCP_DATA_SPLIT_ENABLED;
+ rsc = idpf_is_feature_ena(vport, NETIF_F_GRO_HW);
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
- int j;
+ for (unsigned int i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
rx_qgrp->vport = vport;
- if (!idpf_is_queue_model_split(vport->rxq_model)) {
+ if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
rx_qgrp->singleq.num_rxq = num_rxq;
- for (j = 0; j < num_rxq; j++) {
- rx_qgrp->singleq.rxqs[j] =
- kzalloc(sizeof(*rx_qgrp->singleq.rxqs[j]),
- GFP_KERNEL);
+ for (unsigned int j = 0; j < num_rxq; j++) {
+ rx_qgrp->singleq.rxqs[j] = kzalloc_obj(*rx_qgrp->singleq.rxqs[j]);
if (!rx_qgrp->singleq.rxqs[j]) {
err = -ENOMEM;
goto err_alloc;
@@ -1818,54 +1830,53 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport, u16 num_rxq)
}
rx_qgrp->splitq.num_rxq_sets = num_rxq;
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
rx_qgrp->splitq.rxq_sets[j] =
- kzalloc(sizeof(struct idpf_rxq_set),
- GFP_KERNEL);
+ kzalloc_obj(struct idpf_rxq_set);
if (!rx_qgrp->splitq.rxq_sets[j]) {
err = -ENOMEM;
goto err_alloc;
}
}
- rx_qgrp->splitq.bufq_sets = kcalloc(vport->num_bufqs_per_qgrp,
- sizeof(struct idpf_bufq_set),
- GFP_KERNEL);
+ rx_qgrp->splitq.bufq_sets = kzalloc_objs(struct idpf_bufq_set,
+ rsrc->num_bufqs_per_qgrp);
if (!rx_qgrp->splitq.bufq_sets) {
err = -ENOMEM;
goto err_alloc;
}
+ rx_qgrp->splitq.num_bufq_sets = rsrc->num_bufqs_per_qgrp;
- for (j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (unsigned int j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
struct idpf_bufq_set *bufq_set =
&rx_qgrp->splitq.bufq_sets[j];
int swq_size = sizeof(struct idpf_sw_queue);
struct idpf_buf_queue *q;
q = &rx_qgrp->splitq.bufq_sets[j].bufq;
- q->desc_count = vport->bufq_desc_count[j];
+ q->desc_count = rsrc->bufq_desc_count[j];
q->rx_buffer_low_watermark = IDPF_LOW_WATERMARK;
idpf_queue_assign(HSPLIT_EN, q, hs);
+ idpf_queue_assign(RSC_EN, q, rsc);
- bufq_set->num_refillqs = num_rxq;
bufq_set->refillqs = kcalloc(num_rxq, swq_size,
GFP_KERNEL);
if (!bufq_set->refillqs) {
err = -ENOMEM;
goto err_alloc;
}
- for (k = 0; k < bufq_set->num_refillqs; k++) {
+ bufq_set->num_refillqs = num_rxq;
+ for (unsigned int k = 0; k < bufq_set->num_refillqs; k++) {
struct idpf_sw_queue *refillq =
&bufq_set->refillqs[k];
refillq->desc_count =
- vport->bufq_desc_count[j];
+ rsrc->bufq_desc_count[j];
idpf_queue_set(GEN_CHK, refillq);
idpf_queue_set(RFL_GEN_CHK, refillq);
- refillq->ring = kcalloc(refillq->desc_count,
- sizeof(*refillq->ring),
- GFP_KERNEL);
+ refillq->ring = kzalloc_objs(*refillq->ring,
+ refillq->desc_count);
if (!refillq->ring) {
err = -ENOMEM;
goto err_alloc;
@@ -1874,37 +1885,39 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport, u16 num_rxq)
}
skip_splitq_rx_init:
- for (j = 0; j < num_rxq; j++) {
+ for (unsigned int j = 0; j < num_rxq; j++) {
struct idpf_rx_queue *q;
- if (!idpf_is_queue_model_split(vport->rxq_model)) {
+ if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
q = rx_qgrp->singleq.rxqs[j];
+ q->rx_ptype_lkup = adapter->singleq_pt_lkup;
goto setup_rxq;
}
q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
rx_qgrp->splitq.rxq_sets[j]->refillq[0] =
&rx_qgrp->splitq.bufq_sets[0].refillqs[j];
- if (vport->num_bufqs_per_qgrp > IDPF_SINGLE_BUFQ_PER_RXQ_GRP)
+ if (rsrc->num_bufqs_per_qgrp > IDPF_SINGLE_BUFQ_PER_RXQ_GRP)
rx_qgrp->splitq.rxq_sets[j]->refillq[1] =
&rx_qgrp->splitq.bufq_sets[1].refillqs[j];
idpf_queue_assign(HSPLIT_EN, q, hs);
+ idpf_queue_assign(RSC_EN, q, rsc);
+ q->rx_ptype_lkup = adapter->splitq_pt_lkup;
setup_rxq:
- q->desc_count = vport->rxq_desc_count;
- q->rx_ptype_lkup = vport->rx_ptype_lkup;
+ q->desc_count = rsrc->rxq_desc_count;
q->bufq_sets = rx_qgrp->splitq.bufq_sets;
q->idx = (i * num_rxq) + j;
q->rx_buffer_low_watermark = IDPF_LOW_WATERMARK;
q->rx_max_pkt_size = vport->netdev->mtu +
LIBETH_RX_LL_LEN;
- idpf_rxq_set_descids(vport, q);
+ idpf_rxq_set_descids(rsrc, q);
}
}
err_alloc:
if (err)
- idpf_rxq_group_rel(vport);
+ idpf_rxq_group_rel(rsrc);
return err;
}
@@ -1912,28 +1925,30 @@ err_alloc:
/**
* idpf_vport_queue_grp_alloc_all - Allocate all queue groups/resources
* @vport: vport with qgrps to allocate
+ * @rsrc: pointer to queue and vector resources
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-static int idpf_vport_queue_grp_alloc_all(struct idpf_vport *vport)
+static int idpf_vport_queue_grp_alloc_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
u16 num_txq, num_rxq;
int err;
- idpf_vport_calc_numq_per_grp(vport, &num_txq, &num_rxq);
+ idpf_vport_calc_numq_per_grp(rsrc, &num_txq, &num_rxq);
- err = idpf_txq_group_alloc(vport, num_txq);
+ err = idpf_txq_group_alloc(vport, rsrc, num_txq);
if (err)
goto err_out;
- err = idpf_rxq_group_alloc(vport, num_rxq);
+ err = idpf_rxq_group_alloc(vport, rsrc, num_rxq);
if (err)
goto err_out;
return 0;
err_out:
- idpf_vport_queue_grp_rel_all(vport);
+ idpf_vport_queue_grp_rel_all(rsrc);
return err;
}
@@ -1941,19 +1956,22 @@ err_out:
/**
* idpf_vport_queues_alloc - Allocate memory for all queues
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
+ *
+ * Allocate memory for queues associated with a vport.
*
- * Allocate memory for queues associated with a vport. Returns 0 on success,
- * negative on failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_vport_queues_alloc(struct idpf_vport *vport)
+int idpf_vport_queues_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
int err;
- err = idpf_vport_queue_grp_alloc_all(vport);
+ err = idpf_vport_queue_grp_alloc_all(vport, rsrc);
if (err)
goto err_out;
- err = idpf_vport_init_fast_path_txqs(vport);
+ err = idpf_vport_init_fast_path_txqs(vport, rsrc);
if (err)
goto err_out;
@@ -1961,18 +1979,18 @@ int idpf_vport_queues_alloc(struct idpf_vport *vport)
if (err)
goto err_out;
- err = idpf_tx_desc_alloc_all(vport);
+ err = idpf_tx_desc_alloc_all(vport, rsrc);
if (err)
goto err_out;
- err = idpf_rx_desc_alloc_all(vport);
+ err = idpf_rx_desc_alloc_all(vport, rsrc);
if (err)
goto err_out;
return 0;
err_out:
- idpf_vport_queues_rel(vport);
+ idpf_vport_queues_rel(vport, rsrc);
return err;
}
@@ -2004,7 +2022,7 @@ static void idpf_tx_read_tstamp(struct idpf_tx_queue *txq, struct sk_buff *skb)
/* Fetch timestamp from completion descriptor through
* virtchnl msg to report to stack.
*/
- queue_work(system_unbound_wq, txq->tstamp_task);
+ queue_work(system_dfl_wq, txq->tstamp_task);
break;
}
@@ -2170,7 +2188,7 @@ static void idpf_tx_handle_rs_completion(struct idpf_tx_queue *txq,
* @budget: Used to determine if we are in netpoll
* @cleaned: returns number of packets cleaned
*
- * Returns true if there's any budget left (e.g. the clean is finished)
+ * Return: %true if there's any budget left (e.g. the clean is finished)
*/
static bool idpf_tx_clean_complq(struct idpf_compl_queue *complq, int budget,
int *cleaned)
@@ -2324,7 +2342,7 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
do {
struct idpf_splitq_4b_tx_compl_desc *tx_desc;
- struct idpf_tx_queue *target;
+ struct idpf_tx_queue *target = NULL;
u32 ctype_gen, id;
tx_desc = flow ? &complq->comp[ntc].common :
@@ -2344,14 +2362,14 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
target = complq->txq_grp->txqs[id];
idpf_queue_clear(SW_MARKER, target);
- if (target == txq)
- break;
next:
if (unlikely(++ntc == complq->desc_count)) {
ntc = 0;
gen_flag = !gen_flag;
}
+ if (target == txq)
+ break;
} while (time_before(jiffies, timeout));
idpf_queue_assign(GEN_CHK, complq, gen_flag);
@@ -2390,13 +2408,13 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc,
struct idpf_tx_splitq_params *params,
u16 td_cmd, u16 size)
{
- *(u32 *)&desc->flow.qw1.cmd_dtype = (u8)(params->dtype | td_cmd);
+ *(__le32 *)&desc->flow.qw1.cmd_dtype = cpu_to_le32((u8)(params->dtype | td_cmd));
desc->flow.qw1.rxr_bufsize = cpu_to_le16((u16)size);
desc->flow.qw1.compl_tag = cpu_to_le16(params->compl_tag);
}
/**
- * idpf_tx_splitq_has_room - check if enough Tx splitq resources are available
+ * idpf_txq_has_room - check if enough Tx splitq resources are available
* @tx_q: the queue to be checked
* @descs_needed: number of descriptors required for this packet
* @bufs_needed: number of Tx buffers required for this packet
@@ -2527,6 +2545,8 @@ unsigned int idpf_tx_res_count_required(struct idpf_tx_queue *txq,
* idpf_tx_splitq_bump_ntu - adjust NTU and generation
* @txq: the tx ring to wrap
* @ntu: ring index to bump
+ *
+ * Return: the next ring index hopping to 0 when wraps around
*/
static unsigned int idpf_tx_splitq_bump_ntu(struct idpf_tx_queue *txq, u16 ntu)
{
@@ -2795,7 +2815,7 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q,
* @skb: pointer to skb
* @off: pointer to struct that holds offload parameters
*
- * Returns error (negative) if TSO was requested but cannot be applied to the
+ * Return: error (negative) if TSO was requested but cannot be applied to the
* given skb, 0 if TSO does not apply to the given skb, or 1 otherwise.
*/
int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off)
@@ -2851,7 +2871,7 @@ int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off)
(__force __wsum)htonl(paylen));
/* compute length of segmentation header */
off->tso_hdr_len = sizeof(struct udphdr) + l4_start;
- l4.udp->len = htons(shinfo->gso_size + sizeof(struct udphdr));
+ udp_set_len_short(l4.udp, shinfo->gso_size + sizeof(struct udphdr));
break;
default:
return -EINVAL;
@@ -2873,6 +2893,8 @@ int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off)
*
* Since the TX buffer rings mimics the descriptor ring, update the tx buffer
* ring entry to reflect that this index is a context descriptor
+ *
+ * Return: pointer to the next descriptor
*/
static union idpf_flex_tx_ctx_desc *
idpf_tx_splitq_get_ctx_desc(struct idpf_tx_queue *txq)
@@ -2891,6 +2913,8 @@ idpf_tx_splitq_get_ctx_desc(struct idpf_tx_queue *txq)
* idpf_tx_drop_skb - free the SKB and bump tail if necessary
* @tx_q: queue to send buffer on
* @skb: pointer to skb
+ *
+ * Return: always NETDEV_TX_OK
*/
netdev_tx_t idpf_tx_drop_skb(struct idpf_tx_queue *tx_q, struct sk_buff *skb)
{
@@ -2992,7 +3016,7 @@ static bool idpf_tx_splitq_need_re(struct idpf_tx_queue *tx_q)
* @skb: send buffer
* @tx_q: queue to send buffer on
*
- * Returns NETDEV_TX_OK if sent, else an error code
+ * Return: NETDEV_TX_OK if sent, else an error code
*/
static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
struct idpf_tx_queue *tx_q)
@@ -3073,10 +3097,7 @@ 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;
- /* Set the RE bit to periodically "clean" the descriptor ring.
- * MIN_GAP is set to MIN_RING size to ensure it will be set at
- * least once each time around the ring.
- */
+ /* 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;
tx_q->txq_grp->num_completions_pending++;
@@ -3118,7 +3139,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
* @skb: send buffer
* @netdev: network interface device structure
*
- * Returns NETDEV_TX_OK if sent, else an error code
+ * Return: NETDEV_TX_OK if sent, else an error code
*/
netdev_tx_t idpf_tx_start(struct sk_buff *skb, struct net_device *netdev)
{
@@ -3143,7 +3164,7 @@ netdev_tx_t idpf_tx_start(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
- if (idpf_is_queue_model_split(vport->txq_model))
+ if (idpf_is_queue_model_split(vport->dflt_qv_rsrc.txq_model))
return idpf_tx_splitq_frame(skb, tx_q);
else
return idpf_tx_singleq_frame(skb, tx_q);
@@ -3268,16 +3289,17 @@ idpf_rx_splitq_extract_csum_bits(const struct virtchnl2_rx_flex_desc_adv_nic_3 *
* @rx_desc: Receive descriptor
* @decoded: Decoded Rx packet type related fields
*
- * Return 0 on success and error code on failure
- *
* Populate the skb fields with the total number of RSC segments, RSC payload
* length and packet type.
+ *
+ * Return: 0 on success and error code on failure
*/
static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
const struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_desc,
struct libeth_rx_pt decoded)
{
u16 rsc_segments, rsc_seg_len;
+ u16 l3_start = 0;
bool ipv4, ipv6;
int len;
@@ -3300,7 +3322,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
NAPI_GRO_CB(skb)->count = rsc_segments;
skb_shinfo(skb)->gso_size = rsc_seg_len;
- skb_reset_network_header(skb);
+ if (unlikely(eth_type_vlan(skb->protocol)))
+ l3_start = VLAN_HLEN;
+
+ skb_set_network_header(skb, l3_start);
if (ipv4) {
struct iphdr *ipv4h = ip_hdr(skb);
@@ -3308,7 +3333,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
/* Reset and set transport header offset in skb */
- skb_set_transport_header(skb, sizeof(struct iphdr));
+ skb_set_transport_header(skb, l3_start + sizeof(struct iphdr));
len = skb->len - skb_transport_offset(skb);
/* Compute the TCP pseudo header checksum*/
@@ -3318,7 +3343,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
- skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+ skb_set_transport_header(skb, l3_start + sizeof(struct ipv6hdr));
len = skb->len - skb_transport_offset(skb);
tcp_hdr(skb)->check =
~tcp_v6_check(len, &ipv6h->saddr, &ipv6h->daddr, 0);
@@ -3369,6 +3394,8 @@ idpf_rx_hwtstamp(const struct idpf_rx_queue *rxq,
* This function checks the ring, descriptor, and packet information in
* order to populate the hash, checksum, protocol, and
* other fields within the skb.
+ *
+ * Return: 0 on success and error code on failure
*/
static int
__idpf_rx_process_skb_fields(struct idpf_rx_queue *rxq, struct sk_buff *skb,
@@ -3463,6 +3490,7 @@ static u32 idpf_rx_hsplit_wa(const struct libeth_fqe *hdr,
* @stat_err_field: field from descriptor to test bits in
* @stat_err_bits: value to mask
*
+ * Return: %true if any of given @stat_err_bits are set, %false otherwise.
*/
static bool idpf_rx_splitq_test_staterr(const u8 stat_err_field,
const u8 stat_err_bits)
@@ -3474,8 +3502,8 @@ static bool idpf_rx_splitq_test_staterr(const u8 stat_err_field,
* idpf_rx_splitq_is_eop - process handling of EOP buffers
* @rx_desc: Rx descriptor for current buffer
*
- * If the buffer is an EOP buffer, this function exits returning true,
- * otherwise return false indicating that this is in fact a non-EOP buffer.
+ * Return: %true if the buffer is an EOP buffer, %false otherwise, indicating
+ * that this is in fact a non-EOP buffer.
*/
static bool idpf_rx_splitq_is_eop(struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_desc)
{
@@ -3494,7 +3522,7 @@ static bool idpf_rx_splitq_is_eop(struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_de
* expensive overhead for IOMMU access this provides a means of avoiding
* it by maintaining the mapping of the page to the system.
*
- * Returns amount of work completed
+ * Return: amount of work completed
*/
static int idpf_rx_splitq_clean(struct idpf_rx_queue *rxq, int budget)
{
@@ -3624,7 +3652,7 @@ payload:
* @buf_id: buffer ID
* @buf_desc: Buffer queue descriptor
*
- * Return 0 on success and negative on failure.
+ * Return: 0 on success and negative on failure.
*/
static int idpf_rx_update_bufq_desc(struct idpf_buf_queue *bufq, u32 buf_id,
struct virtchnl2_splitq_rx_buf_desc *buf_desc)
@@ -3751,6 +3779,7 @@ static void idpf_rx_clean_refillq_all(struct idpf_buf_queue *bufq, int nid)
* @irq: interrupt number
* @data: pointer to a q_vector
*
+ * Return: always IRQ_HANDLED
*/
static irqreturn_t idpf_vport_intr_clean_queues(int __always_unused irq,
void *data)
@@ -3765,39 +3794,34 @@ static irqreturn_t idpf_vport_intr_clean_queues(int __always_unused irq,
/**
* idpf_vport_intr_napi_del_all - Unregister napi for all q_vectors in vport
- * @vport: virtual port structure
- *
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_napi_del_all(struct idpf_vport *vport)
+static void idpf_vport_intr_napi_del_all(struct idpf_q_vec_rsrc *rsrc)
{
- u16 v_idx;
-
- for (v_idx = 0; v_idx < vport->num_q_vectors; v_idx++)
- netif_napi_del(&vport->q_vectors[v_idx].napi);
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++)
+ netif_napi_del(&rsrc->q_vectors[v_idx].napi);
}
/**
* idpf_vport_intr_napi_dis_all - Disable NAPI for all q_vectors in the vport
- * @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_napi_dis_all(struct idpf_vport *vport)
+static void idpf_vport_intr_napi_dis_all(struct idpf_q_vec_rsrc *rsrc)
{
- int v_idx;
-
- for (v_idx = 0; v_idx < vport->num_q_vectors; v_idx++)
- napi_disable(&vport->q_vectors[v_idx].napi);
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++)
+ napi_disable(&rsrc->q_vectors[v_idx].napi);
}
/**
* idpf_vport_intr_rel - Free memory allocated for interrupt vectors
- * @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
*
* Free the memory allocated for interrupt vectors associated to a vport
*/
-void idpf_vport_intr_rel(struct idpf_vport *vport)
+void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc)
{
- for (u32 v_idx = 0; v_idx < vport->num_q_vectors; v_idx++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[v_idx];
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
kfree(q_vector->xsksq);
q_vector->xsksq = NULL;
@@ -3811,8 +3835,8 @@ void idpf_vport_intr_rel(struct idpf_vport *vport)
q_vector->rx = NULL;
}
- kfree(vport->q_vectors);
- vport->q_vectors = NULL;
+ kfree(rsrc->q_vectors);
+ rsrc->q_vectors = NULL;
}
static void idpf_q_vector_set_napi(struct idpf_q_vector *q_vector, bool link)
@@ -3832,21 +3856,22 @@ static void idpf_q_vector_set_napi(struct idpf_q_vector *q_vector, bool link)
/**
* idpf_vport_intr_rel_irq - Free the IRQ association with the OS
* @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
+static void idpf_vport_intr_rel_irq(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_adapter *adapter = vport->adapter;
- int vector;
- for (vector = 0; vector < vport->num_q_vectors; vector++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[vector];
+ for (u16 vector = 0; vector < rsrc->num_q_vectors; vector++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[vector];
int irq_num, vidx;
/* free only the irqs that were actually requested */
if (!q_vector)
continue;
- vidx = vport->q_vector_idxs[vector];
+ vidx = rsrc->q_vector_idxs[vector];
irq_num = adapter->msix_entries[vidx].vector;
idpf_q_vector_set_napi(q_vector, false);
@@ -3856,22 +3881,23 @@ static void idpf_vport_intr_rel_irq(struct idpf_vport *vport)
/**
* idpf_vport_intr_dis_irq_all - Disable all interrupt
- * @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_dis_irq_all(struct idpf_vport *vport)
+static void idpf_vport_intr_dis_irq_all(struct idpf_q_vec_rsrc *rsrc)
{
- struct idpf_q_vector *q_vector = vport->q_vectors;
- int q_idx;
+ struct idpf_q_vector *q_vector = rsrc->q_vectors;
- writel(0, vport->noirq_dyn_ctl);
+ writel(0, rsrc->noirq_dyn_ctl);
- for (q_idx = 0; q_idx < vport->num_q_vectors; q_idx++)
+ for (u16 q_idx = 0; q_idx < rsrc->num_q_vectors; q_idx++)
writel(0, q_vector[q_idx].intr_reg.dyn_ctl);
}
/**
* idpf_vport_intr_buildreg_itr - Enable default interrupt generation settings
* @q_vector: pointer to q_vector
+ *
+ * Return: value to be written back to HW to enable interrupt generation
*/
static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector)
{
@@ -3939,7 +3965,7 @@ static void idpf_update_dim_sample(struct idpf_q_vector *q_vector,
static void idpf_net_dim(struct idpf_q_vector *q_vector)
{
struct dim_sample dim_sample = { };
- u64 packets, bytes;
+ u64 packets, bytes, pkts, bts;
u32 i;
if (!IDPF_ITR_IS_DYNAMIC(q_vector->tx_intr_mode))
@@ -3951,9 +3977,12 @@ static void idpf_net_dim(struct idpf_q_vector *q_vector)
do {
start = u64_stats_fetch_begin(&txq->stats_sync);
- packets += u64_stats_read(&txq->q_stats.packets);
- bytes += u64_stats_read(&txq->q_stats.bytes);
+ pkts = u64_stats_read(&txq->q_stats.packets);
+ bts = u64_stats_read(&txq->q_stats.bytes);
} while (u64_stats_fetch_retry(&txq->stats_sync, start));
+
+ packets += pkts;
+ bytes += bts;
}
idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->tx_dim,
@@ -3970,9 +3999,12 @@ check_rx_itr:
do {
start = u64_stats_fetch_begin(&rxq->stats_sync);
- packets += u64_stats_read(&rxq->q_stats.packets);
- bytes += u64_stats_read(&rxq->q_stats.bytes);
+ pkts = u64_stats_read(&rxq->q_stats.packets);
+ bts = u64_stats_read(&rxq->q_stats.bytes);
} while (u64_stats_fetch_retry(&rxq->stats_sync, start));
+
+ packets += pkts;
+ bytes += bts;
}
idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->rx_dim,
@@ -4003,8 +4035,12 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector)
/**
* idpf_vport_intr_req_irq - get MSI-X vectors from the OS for the vport
* @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
+ *
+ * Return: 0 on success, negative on failure
*/
-static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
+static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_adapter *adapter = vport->adapter;
const char *drv_name, *if_name, *vec_name;
@@ -4013,11 +4049,11 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
drv_name = dev_driver_string(&adapter->pdev->dev);
if_name = netdev_name(vport->netdev);
- for (vector = 0; vector < vport->num_q_vectors; vector++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[vector];
+ for (vector = 0; vector < rsrc->num_q_vectors; vector++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[vector];
char *name;
- vidx = vport->q_vector_idxs[vector];
+ vidx = rsrc->q_vector_idxs[vector];
irq_num = adapter->msix_entries[vidx].vector;
if (q_vector->num_rxq && q_vector->num_txq)
@@ -4030,7 +4066,7 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
continue;
name = kasprintf(GFP_KERNEL, "%s-%s-%s-%d", drv_name, if_name,
- vec_name, vidx);
+ vec_name, vector);
err = request_irq(irq_num, idpf_vport_intr_clean_queues, 0,
name, q_vector);
@@ -4047,9 +4083,9 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport)
free_q_irqs:
while (--vector >= 0) {
- vidx = vport->q_vector_idxs[vector];
+ vidx = rsrc->q_vector_idxs[vector];
irq_num = adapter->msix_entries[vidx].vector;
- kfree(free_irq(irq_num, &vport->q_vectors[vector]));
+ kfree(free_irq(irq_num, &rsrc->q_vectors[vector]));
}
return err;
@@ -4078,15 +4114,16 @@ void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector, u16 itr, bool tx)
/**
* idpf_vport_intr_ena_irq_all - Enable IRQ for the given vport
* @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_ena_irq_all(struct idpf_vport *vport)
+static void idpf_vport_intr_ena_irq_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
bool dynamic;
- int q_idx;
u16 itr;
- for (q_idx = 0; q_idx < vport->num_q_vectors; q_idx++) {
- struct idpf_q_vector *qv = &vport->q_vectors[q_idx];
+ for (u16 q_idx = 0; q_idx < rsrc->num_q_vectors; q_idx++) {
+ struct idpf_q_vector *qv = &rsrc->q_vectors[q_idx];
/* Set the initial ITR values */
if (qv->num_txq) {
@@ -4109,19 +4146,42 @@ static void idpf_vport_intr_ena_irq_all(struct idpf_vport *vport)
idpf_vport_intr_update_itr_ena_irq(qv);
}
- writel(vport->noirq_dyn_ctl_ena, vport->noirq_dyn_ctl);
+ writel(rsrc->noirq_dyn_ctl_ena, rsrc->noirq_dyn_ctl);
+}
+
+/**
+ * idpf_vport_intr_dis_dim_all - Disable DIM work for all q_vectors
+ * @rsrc: pointer to queue and vector resources
+ *
+ * The DIM works are embedded in the q_vector array that
+ * idpf_vport_intr_rel() frees, and the poll arms them after
+ * napi_complete_done() has already cleared NAPI_STATE_SCHED. Disable
+ * rather than just cancel, so that a poll tail still running past
+ * napi_disable() cannot queue them again behind the drain.
+ */
+static void idpf_vport_intr_dis_dim_all(struct idpf_q_vec_rsrc *rsrc)
+{
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
+
+ disable_work_sync(&q_vector->tx_dim.work);
+ disable_work_sync(&q_vector->rx_dim.work);
+ }
}
/**
* idpf_vport_intr_deinit - Release all vector associations for the vport
* @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-void idpf_vport_intr_deinit(struct idpf_vport *vport)
+void idpf_vport_intr_deinit(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
- idpf_vport_intr_dis_irq_all(vport);
- idpf_vport_intr_napi_dis_all(vport);
- idpf_vport_intr_napi_del_all(vport);
- idpf_vport_intr_rel_irq(vport);
+ idpf_vport_intr_dis_irq_all(rsrc);
+ idpf_vport_intr_napi_dis_all(rsrc);
+ idpf_vport_intr_dis_dim_all(rsrc);
+ idpf_vport_intr_napi_del_all(rsrc);
+ idpf_vport_intr_rel_irq(vport, rsrc);
}
/**
@@ -4193,16 +4253,13 @@ static void idpf_init_dim(struct idpf_q_vector *qv)
/**
* idpf_vport_intr_napi_ena_all - Enable NAPI for all q_vectors in the vport
- * @vport: main vport structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_napi_ena_all(struct idpf_vport *vport)
+static void idpf_vport_intr_napi_ena_all(struct idpf_q_vec_rsrc *rsrc)
{
- int q_idx;
-
- for (q_idx = 0; q_idx < vport->num_q_vectors; q_idx++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[q_idx];
+ for (u16 q_idx = 0; q_idx < rsrc->num_q_vectors; q_idx++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[q_idx];
- idpf_init_dim(q_vector);
napi_enable(&q_vector->napi);
}
}
@@ -4213,7 +4270,7 @@ static void idpf_vport_intr_napi_ena_all(struct idpf_vport *vport)
* @budget: Used to determine if we are in netpoll
* @cleaned: returns number of packets cleaned
*
- * Returns false if clean is not complete else returns true
+ * Return: %false if clean is not complete else returns %true
*/
static bool idpf_tx_splitq_clean_all(struct idpf_q_vector *q_vec,
int budget, int *cleaned)
@@ -4240,7 +4297,7 @@ static bool idpf_tx_splitq_clean_all(struct idpf_q_vector *q_vec,
* @budget: Used to determine if we are in netpoll
* @cleaned: returns number of packets cleaned
*
- * Returns false if clean is not complete else returns true
+ * Return: %false if clean is not complete else returns %true
*/
static bool idpf_rx_splitq_clean_all(struct idpf_q_vector *q_vec, int budget,
int *cleaned)
@@ -4283,6 +4340,8 @@ static bool idpf_rx_splitq_clean_all(struct idpf_q_vector *q_vec, int budget,
* idpf_vport_splitq_napi_poll - NAPI handler
* @napi: struct from which you get q_vector
* @budget: budget provided by stack
+ *
+ * Return: how many packets were cleaned
*/
static int idpf_vport_splitq_napi_poll(struct napi_struct *napi, int budget)
{
@@ -4328,24 +4387,26 @@ static int idpf_vport_splitq_napi_poll(struct napi_struct *napi, int budget)
/**
* idpf_vport_intr_map_vector_to_qs - Map vectors to queues
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
*
* Mapping for vectors to queues
*/
-static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport)
+static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
- u16 num_txq_grp = vport->num_txq_grp - vport->num_xdp_txq;
- bool split = idpf_is_queue_model_split(vport->rxq_model);
+ u16 num_txq_grp = rsrc->num_txq_grp - vport->num_xdp_txq;
+ bool split = idpf_is_queue_model_split(rsrc->rxq_model);
struct idpf_rxq_group *rx_qgrp;
struct idpf_txq_group *tx_qgrp;
- u32 i, qv_idx, q_index;
+ u32 q_index;
- for (i = 0, qv_idx = 0; i < vport->num_rxq_grp; i++) {
+ for (unsigned int i = 0, qv_idx = 0; i < rsrc->num_rxq_grp; i++) {
u16 num_rxq;
- if (qv_idx >= vport->num_q_vectors)
+ if (qv_idx >= rsrc->num_q_vectors)
qv_idx = 0;
- rx_qgrp = &vport->rxq_grps[i];
+ rx_qgrp = &rsrc->rxq_grps[i];
if (split)
num_rxq = rx_qgrp->splitq.num_rxq_sets;
else
@@ -4358,7 +4419,7 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport)
q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
else
q = rx_qgrp->singleq.rxqs[j];
- q->q_vector = &vport->q_vectors[qv_idx];
+ q->q_vector = &rsrc->q_vectors[qv_idx];
q_index = q->q_vector->num_rxq;
q->q_vector->rx[q_index] = q;
q->q_vector->num_rxq++;
@@ -4368,11 +4429,11 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport)
}
if (split) {
- for (u32 j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (u32 j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
struct idpf_buf_queue *bufq;
bufq = &rx_qgrp->splitq.bufq_sets[j].bufq;
- bufq->q_vector = &vport->q_vectors[qv_idx];
+ bufq->q_vector = &rsrc->q_vectors[qv_idx];
q_index = bufq->q_vector->num_bufq;
bufq->q_vector->bufq[q_index] = bufq;
bufq->q_vector->num_bufq++;
@@ -4382,40 +4443,40 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport)
qv_idx++;
}
- split = idpf_is_queue_model_split(vport->txq_model);
+ split = idpf_is_queue_model_split(rsrc->txq_model);
- for (i = 0, qv_idx = 0; i < num_txq_grp; i++) {
+ for (unsigned int i = 0, qv_idx = 0; i < num_txq_grp; i++) {
u16 num_txq;
- if (qv_idx >= vport->num_q_vectors)
+ if (qv_idx >= rsrc->num_q_vectors)
qv_idx = 0;
- tx_qgrp = &vport->txq_grps[i];
+ tx_qgrp = &rsrc->txq_grps[i];
num_txq = tx_qgrp->num_txq;
for (u32 j = 0; j < num_txq; j++) {
struct idpf_tx_queue *q;
q = tx_qgrp->txqs[j];
- q->q_vector = &vport->q_vectors[qv_idx];
+ q->q_vector = &rsrc->q_vectors[qv_idx];
q->q_vector->tx[q->q_vector->num_txq++] = q;
}
if (split) {
struct idpf_compl_queue *q = tx_qgrp->complq;
- q->q_vector = &vport->q_vectors[qv_idx];
+ q->q_vector = &rsrc->q_vectors[qv_idx];
q->q_vector->complq[q->q_vector->num_complq++] = q;
}
qv_idx++;
}
- for (i = 0; i < vport->num_xdp_txq; i++) {
+ for (unsigned int i = 0; i < vport->num_xdp_txq; i++) {
struct idpf_tx_queue *xdpsq;
struct idpf_q_vector *qv;
- xdpsq = vport->txqs[vport->xdp_txq_offset + i];
+ xdpsq = vport->txqs[rsrc->xdp_txq_offset + i];
if (!idpf_queue_has(XSK, xdpsq))
continue;
@@ -4430,10 +4491,14 @@ static void idpf_vport_intr_map_vector_to_qs(struct idpf_vport *vport)
/**
* idpf_vport_intr_init_vec_idx - Initialize the vector indexes
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
*
- * Initialize vector indexes with values returened over mailbox
+ * Initialize vector indexes with values returned over mailbox.
+ *
+ * Return: 0 on success, negative on failure
*/
-static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport)
+static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_adapter *adapter = vport->adapter;
struct virtchnl2_alloc_vectors *ac;
@@ -4442,10 +4507,10 @@ static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport)
ac = adapter->req_vec_chunks;
if (!ac) {
- for (i = 0; i < vport->num_q_vectors; i++)
- vport->q_vectors[i].v_idx = vport->q_vector_idxs[i];
+ for (i = 0; i < rsrc->num_q_vectors; i++)
+ rsrc->q_vectors[i].v_idx = rsrc->q_vector_idxs[i];
- vport->noirq_v_idx = vport->q_vector_idxs[i];
+ rsrc->noirq_v_idx = rsrc->q_vector_idxs[i];
return 0;
}
@@ -4457,10 +4522,10 @@ static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport)
idpf_get_vec_ids(adapter, vecids, total_vecs, &ac->vchunks);
- for (i = 0; i < vport->num_q_vectors; i++)
- vport->q_vectors[i].v_idx = vecids[vport->q_vector_idxs[i]];
+ for (i = 0; i < rsrc->num_q_vectors; i++)
+ rsrc->q_vectors[i].v_idx = vecids[rsrc->q_vector_idxs[i]];
- vport->noirq_v_idx = vecids[vport->q_vector_idxs[i]];
+ rsrc->noirq_v_idx = vecids[rsrc->q_vector_idxs[i]];
kfree(vecids);
@@ -4470,21 +4535,24 @@ static int idpf_vport_intr_init_vec_idx(struct idpf_vport *vport)
/**
* idpf_vport_intr_napi_add_all- Register napi handler for all qvectors
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
*/
-static void idpf_vport_intr_napi_add_all(struct idpf_vport *vport)
+static void idpf_vport_intr_napi_add_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
int (*napi_poll)(struct napi_struct *napi, int budget);
- u16 v_idx, qv_idx;
int irq_num;
+ u16 qv_idx;
- if (idpf_is_queue_model_split(vport->txq_model))
+ if (idpf_is_queue_model_split(rsrc->txq_model))
napi_poll = idpf_vport_splitq_napi_poll;
else
napi_poll = idpf_vport_singleq_napi_poll;
- for (v_idx = 0; v_idx < vport->num_q_vectors; v_idx++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[v_idx];
- qv_idx = vport->q_vector_idxs[v_idx];
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
+
+ qv_idx = rsrc->q_vector_idxs[v_idx];
irq_num = vport->adapter->msix_entries[qv_idx].vector;
netif_napi_add_config(vport->netdev, &q_vector->napi,
@@ -4496,40 +4564,46 @@ static void idpf_vport_intr_napi_add_all(struct idpf_vport *vport)
/**
* idpf_vport_intr_alloc - Allocate memory for interrupt vectors
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
+ *
+ * Allocate one q_vector per queue interrupt.
*
- * We allocate one q_vector per queue interrupt. If allocation fails we
- * return -ENOMEM.
+ * Return: 0 on success, if allocation fails we return -ENOMEM.
*/
-int idpf_vport_intr_alloc(struct idpf_vport *vport)
+int idpf_vport_intr_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
u16 txqs_per_vector, rxqs_per_vector, bufqs_per_vector;
struct idpf_vport_user_config_data *user_config;
struct idpf_q_vector *q_vector;
struct idpf_q_coalesce *q_coal;
- u32 complqs_per_vector, v_idx;
+ u32 complqs_per_vector;
u16 idx = vport->idx;
user_config = &vport->adapter->vport_config[idx]->user_config;
- vport->q_vectors = kcalloc(vport->num_q_vectors,
- sizeof(struct idpf_q_vector), GFP_KERNEL);
- if (!vport->q_vectors)
+
+ rsrc->q_vectors = kzalloc_objs(struct idpf_q_vector,
+ rsrc->num_q_vectors);
+ if (!rsrc->q_vectors)
return -ENOMEM;
- txqs_per_vector = DIV_ROUND_UP(vport->num_txq_grp,
- vport->num_q_vectors);
- rxqs_per_vector = DIV_ROUND_UP(vport->num_rxq_grp,
- vport->num_q_vectors);
- bufqs_per_vector = vport->num_bufqs_per_qgrp *
- DIV_ROUND_UP(vport->num_rxq_grp,
- vport->num_q_vectors);
- complqs_per_vector = DIV_ROUND_UP(vport->num_txq_grp,
- vport->num_q_vectors);
-
- for (v_idx = 0; v_idx < vport->num_q_vectors; v_idx++) {
- q_vector = &vport->q_vectors[v_idx];
+ txqs_per_vector = DIV_ROUND_UP(rsrc->num_txq_grp,
+ rsrc->num_q_vectors);
+ rxqs_per_vector = DIV_ROUND_UP(rsrc->num_rxq_grp,
+ rsrc->num_q_vectors);
+ bufqs_per_vector = rsrc->num_bufqs_per_qgrp *
+ DIV_ROUND_UP(rsrc->num_rxq_grp,
+ rsrc->num_q_vectors);
+ complqs_per_vector = DIV_ROUND_UP(rsrc->num_txq_grp,
+ rsrc->num_q_vectors);
+
+ for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
+ q_vector = &rsrc->q_vectors[v_idx];
q_coal = &user_config->q_coalesce[v_idx];
q_vector->vport = vport;
+ idpf_init_dim(q_vector);
+
q_vector->tx_itr_value = q_coal->tx_coalesce_usecs;
q_vector->tx_intr_mode = q_coal->tx_intr_mode;
q_vector->tx_itr_idx = VIRTCHNL2_ITR_IDX_1;
@@ -4538,37 +4612,31 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport)
q_vector->rx_intr_mode = q_coal->rx_intr_mode;
q_vector->rx_itr_idx = VIRTCHNL2_ITR_IDX_0;
- q_vector->tx = kcalloc(txqs_per_vector, sizeof(*q_vector->tx),
- GFP_KERNEL);
+ q_vector->tx = kzalloc_objs(*q_vector->tx, txqs_per_vector);
if (!q_vector->tx)
goto error;
- q_vector->rx = kcalloc(rxqs_per_vector, sizeof(*q_vector->rx),
- GFP_KERNEL);
+ q_vector->rx = kzalloc_objs(*q_vector->rx, rxqs_per_vector);
if (!q_vector->rx)
goto error;
- if (!idpf_is_queue_model_split(vport->rxq_model))
+ if (!idpf_is_queue_model_split(rsrc->rxq_model))
continue;
- q_vector->bufq = kcalloc(bufqs_per_vector,
- sizeof(*q_vector->bufq),
- GFP_KERNEL);
+ q_vector->bufq = kzalloc_objs(*q_vector->bufq, bufqs_per_vector);
if (!q_vector->bufq)
goto error;
- q_vector->complq = kcalloc(complqs_per_vector,
- sizeof(*q_vector->complq),
- GFP_KERNEL);
+ q_vector->complq = kzalloc_objs(*q_vector->complq,
+ complqs_per_vector);
if (!q_vector->complq)
goto error;
- if (!vport->xdp_txq_offset)
+ if (!rsrc->xdp_txq_offset)
continue;
- q_vector->xsksq = kcalloc(rxqs_per_vector,
- sizeof(*q_vector->xsksq),
- GFP_KERNEL);
+ q_vector->xsksq = kzalloc_objs(*q_vector->xsksq,
+ rxqs_per_vector);
if (!q_vector->xsksq)
goto error;
}
@@ -4576,7 +4644,7 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport)
return 0;
error:
- idpf_vport_intr_rel(vport);
+ idpf_vport_intr_rel(rsrc);
return -ENOMEM;
}
@@ -4584,123 +4652,108 @@ error:
/**
* idpf_vport_intr_init - Setup all vectors for the given vport
* @vport: virtual port
+ * @rsrc: pointer to queue and vector resources
*
- * Returns 0 on success or negative on failure
+ * Return: 0 on success or negative on failure
*/
-int idpf_vport_intr_init(struct idpf_vport *vport)
+int idpf_vport_intr_init(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
{
int err;
- err = idpf_vport_intr_init_vec_idx(vport);
+ err = idpf_vport_intr_init_vec_idx(vport, rsrc);
if (err)
return err;
- idpf_vport_intr_map_vector_to_qs(vport);
- idpf_vport_intr_napi_add_all(vport);
+ idpf_vport_intr_map_vector_to_qs(vport, rsrc);
+ idpf_vport_intr_napi_add_all(vport, rsrc);
- err = vport->adapter->dev_ops.reg_ops.intr_reg_init(vport);
+ err = vport->adapter->dev_ops.reg_ops.intr_reg_init(vport, rsrc);
if (err)
goto unroll_vectors_alloc;
- err = idpf_vport_intr_req_irq(vport);
+ err = idpf_vport_intr_req_irq(vport, rsrc);
if (err)
goto unroll_vectors_alloc;
return 0;
unroll_vectors_alloc:
- idpf_vport_intr_napi_del_all(vport);
+ idpf_vport_intr_napi_del_all(rsrc);
return err;
}
-void idpf_vport_intr_ena(struct idpf_vport *vport)
+void idpf_vport_intr_ena(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
{
- idpf_vport_intr_napi_ena_all(vport);
- idpf_vport_intr_ena_irq_all(vport);
+ idpf_vport_intr_napi_ena_all(rsrc);
+ idpf_vport_intr_ena_irq_all(vport, rsrc);
}
/**
* idpf_config_rss - Send virtchnl messages to configure RSS
* @vport: virtual port
+ * @rss_data: pointer to RSS key and lut info
*
- * Return 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-int idpf_config_rss(struct idpf_vport *vport)
+int idpf_config_rss(struct idpf_vport *vport, struct idpf_rss_data *rss_data)
{
+ struct idpf_adapter *adapter = vport->adapter;
+ u32 vport_id = vport->vport_id;
int err;
- err = idpf_send_get_set_rss_key_msg(vport, false);
+ err = idpf_send_set_rss_key_msg(adapter, rss_data, vport_id);
if (err)
return err;
- return idpf_send_get_set_rss_lut_msg(vport, false);
+ return idpf_send_set_rss_lut_msg(adapter, rss_data, vport_id);
}
/**
* idpf_fill_dflt_rss_lut - Fill the indirection table with the default values
* @vport: virtual port structure
+ * @rss_data: pointer to RSS key and lut info
*/
-static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport)
+void idpf_fill_dflt_rss_lut(struct idpf_vport *vport,
+ struct idpf_rss_data *rss_data)
{
- struct idpf_adapter *adapter = vport->adapter;
- u16 num_active_rxq = vport->num_rxq;
- struct idpf_rss_data *rss_data;
+ u16 num_active_rxq = vport->dflt_qv_rsrc.num_rxq;
int i;
- rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
-
- for (i = 0; i < rss_data->rss_lut_size; i++) {
+ for (i = 0; i < rss_data->rss_lut_size; i++)
rss_data->rss_lut[i] = i % num_active_rxq;
- rss_data->cached_lut[i] = rss_data->rss_lut[i];
- }
}
/**
- * idpf_init_rss - Allocate and initialize RSS resources
+ * idpf_init_rss_lut - Allocate and initialize RSS LUT
* @vport: virtual port
+ * @rss_data: pointer to RSS key and lut info
*
- * Return 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-int idpf_init_rss(struct idpf_vport *vport)
+int idpf_init_rss_lut(struct idpf_vport *vport, struct idpf_rss_data *rss_data)
{
- struct idpf_adapter *adapter = vport->adapter;
- struct idpf_rss_data *rss_data;
- u32 lut_size;
-
- rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
-
- lut_size = rss_data->rss_lut_size * sizeof(u32);
- rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL);
- if (!rss_data->rss_lut)
- return -ENOMEM;
-
- rss_data->cached_lut = kzalloc(lut_size, GFP_KERNEL);
- if (!rss_data->cached_lut) {
- kfree(rss_data->rss_lut);
- rss_data->rss_lut = NULL;
+ if (!rss_data->rss_lut) {
+ u32 lut_size;
- return -ENOMEM;
+ lut_size = rss_data->rss_lut_size * sizeof(u32);
+ rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL);
+ if (!rss_data->rss_lut)
+ return -ENOMEM;
}
/* Fill the default RSS lut values */
- idpf_fill_dflt_rss_lut(vport);
+ idpf_fill_dflt_rss_lut(vport, rss_data);
- return idpf_config_rss(vport);
+ return 0;
}
/**
- * idpf_deinit_rss - Release RSS resources
- * @vport: virtual port
+ * idpf_deinit_rss_lut - Release RSS LUT
+ * @rss_data: pointer to RSS key and lut info
*/
-void idpf_deinit_rss(struct idpf_vport *vport)
+void idpf_deinit_rss_lut(struct idpf_rss_data *rss_data)
{
- struct idpf_adapter *adapter = vport->adapter;
- struct idpf_rss_data *rss_data;
-
- rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
- kfree(rss_data->cached_lut);
- rss_data->cached_lut = NULL;
kfree(rss_data->rss_lut);
rss_data->rss_lut = NULL;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 75b977094741..93547597efd2 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -5,6 +5,7 @@
#define _IDPF_TXRX_H_
#include <linux/dim.h>
+#include <linux/net/intel/virtchnl2_lan_desc.h>
#include <net/libeth/cache.h>
#include <net/libeth/types.h>
@@ -13,7 +14,6 @@
#include <net/xdp.h>
#include "idpf_lan_txrx.h"
-#include "virtchnl2_lan_desc.h"
#define IDPF_LARGE_MAX_Q 256
#define IDPF_MAX_Q 16
@@ -21,7 +21,7 @@
/* Mailbox Queue */
#define IDPF_MAX_MBXQ 1
-#define IDPF_MIN_TXQ_DESC 64
+#define IDPF_MIN_TXQ_DESC 128
#define IDPF_MIN_RXQ_DESC 64
#define IDPF_MIN_TXQ_COMPLQ_DESC 256
#define IDPF_MAX_QIDS 256
@@ -101,6 +101,7 @@ do { \
idx = 0; \
} while (0)
+#define IDPF_RX_MAX_BUF_SZ (16384 - 128)
#define IDPF_RX_BUF_STRIDE 32
#define IDPF_RX_BUF_POST_STRIDE 16
#define IDPF_LOW_WATERMARK 64
@@ -235,7 +236,7 @@ enum idpf_tx_ctx_desc_eipt_offload {
(sizeof(u16) * IDPF_RX_MAX_PTYPE_PROTO_IDS))
#define IDPF_RX_PTYPE_HDR_SZ sizeof(struct virtchnl2_get_ptype_info)
#define IDPF_RX_MAX_PTYPES_PER_BUF \
- DIV_ROUND_DOWN_ULL((IDPF_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ), \
+ DIV_ROUND_DOWN_ULL(LIBIE_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ, \
IDPF_RX_MAX_PTYPE_SZ)
#define IDPF_GET_PTYPE_SIZE(p) struct_size((p), proto_id, (p)->proto_id_count)
@@ -282,6 +283,7 @@ struct idpf_ptype_state {
* @__IDPF_Q_FLOW_SCH_EN: Enable flow scheduling
* @__IDPF_Q_SW_MARKER: Used to indicate TX queue marker completions
* @__IDPF_Q_CRC_EN: enable CRC offload in singleq mode
+ * @__IDPF_Q_RSC_EN: enable Receive Side Coalescing on Rx (splitq)
* @__IDPF_Q_HSPLIT_EN: enable header split on Rx (splitq)
* @__IDPF_Q_PTP: indicates whether the Rx timestamping is enabled for the
* queue
@@ -296,6 +298,7 @@ enum idpf_queue_flags_t {
__IDPF_Q_FLOW_SCH_EN,
__IDPF_Q_SW_MARKER,
__IDPF_Q_CRC_EN,
+ __IDPF_Q_RSC_EN,
__IDPF_Q_HSPLIT_EN,
__IDPF_Q_PTP,
__IDPF_Q_NOIRQ,
@@ -924,6 +927,7 @@ struct idpf_bufq_set {
* @singleq.rxqs: Array of RX queue pointers
* @splitq: Struct with split queue related members
* @splitq.num_rxq_sets: Number of RX queue sets
+ * @splitq.num_rxq_sets: Number of Buffer queue sets
* @splitq.rxq_sets: Array of RX queue sets
* @splitq.bufq_sets: Buffer queue set pointer
*
@@ -941,6 +945,7 @@ struct idpf_rxq_group {
} singleq;
struct {
u16 num_rxq_sets;
+ u16 num_bufq_sets;
struct idpf_rxq_set *rxq_sets[IDPF_LARGE_MAX_Q];
struct idpf_bufq_set *bufq_sets;
} splitq;
@@ -1071,24 +1076,35 @@ static inline u32 idpf_tx_splitq_get_free_bufs(struct idpf_sw_queue *refillq)
int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget);
void idpf_vport_init_num_qs(struct idpf_vport *vport,
- struct virtchnl2_create_vport *vport_msg);
-void idpf_vport_calc_num_q_desc(struct idpf_vport *vport);
+ struct virtchnl2_create_vport *vport_msg,
+ struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_calc_num_q_desc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_index,
struct virtchnl2_create_vport *vport_msg,
struct idpf_vport_max_q *max_q);
-void idpf_vport_calc_num_q_groups(struct idpf_vport *vport);
-int idpf_vport_queues_alloc(struct idpf_vport *vport);
-void idpf_vport_queues_rel(struct idpf_vport *vport);
-void idpf_vport_intr_rel(struct idpf_vport *vport);
-int idpf_vport_intr_alloc(struct idpf_vport *vport);
+void idpf_vport_calc_num_q_groups(struct idpf_q_vec_rsrc *rsrc);
+int idpf_vport_queues_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_queues_rel(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_intr_rel(struct idpf_q_vec_rsrc *rsrc);
+int idpf_vport_intr_alloc(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector);
-void idpf_vport_intr_deinit(struct idpf_vport *vport);
-int idpf_vport_intr_init(struct idpf_vport *vport);
-void idpf_vport_intr_ena(struct idpf_vport *vport);
-int idpf_config_rss(struct idpf_vport *vport);
-int idpf_init_rss(struct idpf_vport *vport);
-void idpf_deinit_rss(struct idpf_vport *vport);
-int idpf_rx_bufs_init_all(struct idpf_vport *vport);
+void idpf_vport_intr_deinit(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
+int idpf_vport_intr_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_intr_ena(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
+void idpf_fill_dflt_rss_lut(struct idpf_vport *vport,
+ struct idpf_rss_data *rss_data);
+int idpf_config_rss(struct idpf_vport *vport, struct idpf_rss_data *rss_data);
+int idpf_init_rss_lut(struct idpf_vport *vport, struct idpf_rss_data *rss_data);
+void idpf_deinit_rss_lut(struct idpf_rss_data *rss_data);
+int idpf_rx_bufs_init_all(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
struct idpf_q_vector *idpf_find_rxq_vec(const struct idpf_vport *vport,
u32 q_num);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index 4cc58c83688c..b537de3592f4 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -9,45 +9,32 @@
/**
* idpf_vf_ctlq_reg_init - initialize default mailbox registers
- * @adapter: adapter structure
- * @cq: pointer to the array of create control queues
+ * @mmio: struct that contains MMIO region info
+ * @cci: struct where the register offset pointer to be copied to
*/
-static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq)
+static void idpf_vf_ctlq_reg_init(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cci)
{
- resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
- int i;
-
- for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
- struct idpf_ctlq_create_info *ccq = cq + i;
-
- switch (ccq->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = VF_ATQH - mbx_start;
- ccq->reg.tail = VF_ATQT - mbx_start;
- ccq->reg.len = VF_ATQLEN - mbx_start;
- ccq->reg.bah = VF_ATQBAH - mbx_start;
- ccq->reg.bal = VF_ATQBAL - mbx_start;
- ccq->reg.len_mask = VF_ATQLEN_ATQLEN_M;
- ccq->reg.len_ena_mask = VF_ATQLEN_ATQENABLE_M;
- ccq->reg.head_mask = VF_ATQH_ATQH_M;
- break;
- case IDPF_CTLQ_TYPE_MAILBOX_RX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = VF_ARQH - mbx_start;
- ccq->reg.tail = VF_ARQT - mbx_start;
- ccq->reg.len = VF_ARQLEN - mbx_start;
- ccq->reg.bah = VF_ARQBAH - mbx_start;
- ccq->reg.bal = VF_ARQBAL - mbx_start;
- ccq->reg.len_mask = VF_ARQLEN_ARQLEN_M;
- ccq->reg.len_ena_mask = VF_ARQLEN_ARQENABLE_M;
- ccq->reg.head_mask = VF_ARQH_ARQH_M;
- break;
- default:
- break;
- }
- }
+ struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+ struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
+
+ tx_reg->head = libie_pci_get_mmio_addr(mmio, VF_ATQH);
+ tx_reg->tail = libie_pci_get_mmio_addr(mmio, VF_ATQT);
+ tx_reg->len = libie_pci_get_mmio_addr(mmio, VF_ATQLEN);
+ tx_reg->addr_high = libie_pci_get_mmio_addr(mmio, VF_ATQBAH);
+ tx_reg->addr_low = libie_pci_get_mmio_addr(mmio, VF_ATQBAL);
+ tx_reg->len_mask = VF_ATQLEN_ATQLEN_M;
+ tx_reg->len_ena_mask = VF_ATQLEN_ATQENABLE_M;
+ tx_reg->head_mask = VF_ATQH_ATQH_M;
+
+ rx_reg->head = libie_pci_get_mmio_addr(mmio, VF_ARQH);
+ rx_reg->tail = libie_pci_get_mmio_addr(mmio, VF_ARQT);
+ rx_reg->len = libie_pci_get_mmio_addr(mmio, VF_ARQLEN);
+ rx_reg->addr_high = libie_pci_get_mmio_addr(mmio, VF_ARQBAH);
+ rx_reg->addr_low = libie_pci_get_mmio_addr(mmio, VF_ARQBAL);
+ rx_reg->len_mask = VF_ARQLEN_ARQLEN_M;
+ rx_reg->len_ena_mask = VF_ARQLEN_ARQENABLE_M;
+ rx_reg->head_mask = VF_ARQH_ARQH_M;
}
/**
@@ -56,49 +43,55 @@ static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,
*/
static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
{
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
- intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
+ intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
intr->dyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M;
intr->dyn_ctl_itridx_m = VF_INT_DYN_CTL0_ITR_INDX_M;
- intr->icr_ena = idpf_get_reg_addr(adapter, VF_INT_ICR0_ENA1);
+ intr->icr_ena = libie_pci_get_mmio_addr(mmio, VF_INT_ICR0_ENA1);
intr->icr_ena_ctlq_m = VF_INT_ICR0_ENA1_ADMINQ_M;
}
/**
* idpf_vf_intr_reg_init - Initialize interrupt registers
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
*/
-static int idpf_vf_intr_reg_init(struct idpf_vport *vport)
+static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_adapter *adapter = vport->adapter;
- int num_vecs = vport->num_q_vectors;
+ u16 num_vecs = rsrc->num_q_vectors;
struct idpf_vec_regs *reg_vals;
+ struct libie_mmio_info *mmio;
int num_regs, i, err = 0;
u32 rx_itr, tx_itr, val;
u16 total_vecs;
total_vecs = idpf_get_reserved_vecs(vport->adapter);
- reg_vals = kcalloc(total_vecs, sizeof(struct idpf_vec_regs),
- GFP_KERNEL);
+ reg_vals = kzalloc_objs(struct idpf_vec_regs, total_vecs);
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(vport, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
}
+ mmio = &adapter->ctlq_ctx.mmio_info;
+
for (i = 0; i < num_vecs; i++) {
- struct idpf_q_vector *q_vector = &vport->q_vectors[i];
- u16 vec_id = vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
+ struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
+ u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
struct idpf_intr_reg *intr = &q_vector->intr_reg;
+ struct idpf_vec_regs *reg = &reg_vals[vec_id];
u32 spacing;
- intr->dyn_ctl = idpf_get_reg_addr(adapter,
- reg_vals[vec_id].dyn_ctl_reg);
+ intr->dyn_ctl = libie_pci_get_mmio_addr(mmio,
+ reg->dyn_ctl_reg);
intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
@@ -108,26 +101,25 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport)
intr->dyn_ctl_sw_itridx_ena_m =
VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
- spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
+ spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
IDPF_VF_ITR_IDX_SPACING);
rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0,
- reg_vals[vec_id].itrn_reg,
- spacing);
+ reg->itrn_reg, spacing);
tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1,
- reg_vals[vec_id].itrn_reg,
- spacing);
- intr->rx_itr = idpf_get_reg_addr(adapter, rx_itr);
- intr->tx_itr = idpf_get_reg_addr(adapter, tx_itr);
+ reg->itrn_reg, spacing);
+ intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+ intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
}
/* Data vector for NOIRQ queues */
- val = reg_vals[vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
- vport->noirq_dyn_ctl = idpf_get_reg_addr(adapter, val);
+ val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
+ rsrc->noirq_dyn_ctl =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
val = VF_INT_DYN_CTLN_WB_ON_ITR_M | VF_INT_DYN_CTLN_INTENA_MSK_M |
FIELD_PREP(VF_INT_DYN_CTLN_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
- vport->noirq_dyn_ctl_ena = val;
+ rsrc->noirq_dyn_ctl_ena = val;
free_reg_vals:
kfree(reg_vals);
@@ -141,7 +133,9 @@ free_reg_vals:
*/
static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter)
{
- adapter->reset_reg.rstat = idpf_get_rstat_reg_addr(adapter, VFGEN_RSTAT);
+ adapter->reset_reg.rstat =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+ VFGEN_RSTAT);
adapter->reset_reg.rstat_m = VFGEN_RSTAT_VFR_STATE_M;
}
@@ -156,7 +150,7 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
/* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */
if (trig_cause == IDPF_HR_FUNC_RESET &&
!test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
- idpf_send_mb_msg(adapter, VIRTCHNL2_OP_RESET_VF, 0, NULL, 0);
+ idpf_send_vf_reset_msg(adapter);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 44cd4b466c48..1caf52706973 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2023 Intel Corporation */
#include <linux/export.h>
+#include <linux/net/intel/libie/pci.h>
#include <net/libeth/rx.h>
#include "idpf.h"
@@ -9,20 +10,6 @@
#include "idpf_ptp.h"
/**
- * struct idpf_vc_xn_manager - Manager for tracking transactions
- * @ring: backing and lookup for transactions
- * @free_xn_bm: bitmap for free transactions
- * @xn_bm_lock: make bitmap access synchronous where necessary
- * @salt: used to make cookie unique every message
- */
-struct idpf_vc_xn_manager {
- struct idpf_vc_xn ring[IDPF_VC_XN_RING_LEN];
- DECLARE_BITMAP(free_xn_bm, IDPF_VC_XN_RING_LEN);
- spinlock_t xn_bm_lock;
- u8 salt;
-};
-
-/**
* idpf_vid_to_vport - Translate vport id to vport pointer
* @adapter: private data struct
* @v_id: vport id to translate
@@ -82,77 +69,62 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter,
/**
* idpf_recv_event_msg - Receive virtchnl event message
- * @adapter: Driver specific private structure
+ * @ctx: control queue context
* @ctlq_msg: message to copy from
*
* Receive virtchnl event message
*/
-static void idpf_recv_event_msg(struct idpf_adapter *adapter,
- struct idpf_ctlq_msg *ctlq_msg)
+void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_msg *ctlq_msg)
{
- int payload_size = ctlq_msg->ctx.indirect.payload->size;
+ struct kvec *buff = &ctlq_msg->recv_mem;
+ int payload_size = buff->iov_len;
+ struct idpf_adapter *adapter;
struct virtchnl2_event *v2e;
u32 event;
+ adapter = container_of(ctx, struct idpf_adapter, ctlq_ctx);
+ if (ctlq_msg->chnl_opcode != VIRTCHNL2_OP_EVENT) {
+ dev_dbg(&adapter->pdev->dev,
+ "Unhandled message with opcode %u from CP\n",
+ ctlq_msg->chnl_opcode);
+ goto free_rx_buf;
+ }
+
if (payload_size < sizeof(*v2e)) {
dev_err_ratelimited(&adapter->pdev->dev, "Failed to receive valid payload for event msg (op %d len %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode,
+ ctlq_msg->chnl_opcode,
payload_size);
- return;
+ goto free_rx_buf;
}
- v2e = (struct virtchnl2_event *)ctlq_msg->ctx.indirect.payload->va;
+ v2e = (struct virtchnl2_event *)buff->iov_base;
event = le32_to_cpu(v2e->event);
switch (event) {
case VIRTCHNL2_EVENT_LINK_CHANGE:
idpf_handle_event_link(adapter, v2e);
- return;
+ break;
default:
dev_err(&adapter->pdev->dev,
"Unknown event %d from PF\n", event);
break;
}
+
+free_rx_buf:
+ libie_ctlq_release_rx_buf(buff);
}
/**
* idpf_mb_clean - Reclaim the send mailbox queue entries
- * @adapter: Driver specific private structure
- *
- * Reclaim the send mailbox queue entries to be used to send further messages
+ * @asq: send control queue info
+ * @deinit: release all buffers before destroying the queue
*
- * Returns 0 on success, negative on failure
+ * This is a helper function to clean the send mailbox queue entries.
*/
-static int idpf_mb_clean(struct idpf_adapter *adapter)
+static void idpf_mb_clean(struct libie_ctlq_info *asq, bool deinit)
{
- u16 i, num_q_msg = IDPF_DFLT_MBX_Q_LEN;
- struct idpf_ctlq_msg **q_msg;
- struct idpf_dma_mem *dma_mem;
- int err;
-
- q_msg = kcalloc(num_q_msg, sizeof(struct idpf_ctlq_msg *), GFP_ATOMIC);
- if (!q_msg)
- return -ENOMEM;
-
- err = idpf_ctlq_clean_sq(adapter->hw.asq, &num_q_msg, q_msg);
- if (err)
- goto err_kfree;
-
- for (i = 0; i < num_q_msg; i++) {
- if (!q_msg[i])
- continue;
- dma_mem = q_msg[i]->ctx.indirect.payload;
- if (dma_mem)
- dma_free_coherent(&adapter->pdev->dev, dma_mem->size,
- dma_mem->va, dma_mem->pa);
- kfree(q_msg[i]);
- kfree(dma_mem);
- }
-
-err_kfree:
- kfree(q_msg);
-
- return err;
+ libie_ctlq_xn_send_clean(asq, kfree, deinit);
}
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
@@ -186,7 +158,7 @@ static bool idpf_ptp_is_mb_msg(u32 op)
* @ctlq_msg: Corresponding control queue message
*/
static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
- struct idpf_ctlq_msg *ctlq_msg)
+ struct libie_ctlq_msg *ctlq_msg)
{
/* If the message is PTP-related and the secondary mailbox is available,
* send the message through the secondary mailbox.
@@ -194,532 +166,111 @@ static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
if (!idpf_ptp_is_mb_msg(op) || !adapter->ptp->secondary_mbx.valid)
return;
- ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_peer_drv;
+ ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_PEER;
ctlq_msg->func_id = adapter->ptp->secondary_mbx.peer_mbx_q_id;
- ctlq_msg->host_id = adapter->ptp->secondary_mbx.peer_id;
+ ctlq_msg->flags = FIELD_PREP(LIBIE_CTLQ_DESC_FLAG_HOST_ID,
+ adapter->ptp->secondary_mbx.peer_id);
}
#else /* !CONFIG_PTP_1588_CLOCK */
static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
- struct idpf_ctlq_msg *ctlq_msg)
+ struct libie_ctlq_msg *ctlq_msg)
{ }
#endif /* CONFIG_PTP_1588_CLOCK */
/**
- * idpf_send_mb_msg - Send message over mailbox
- * @adapter: Driver specific private structure
- * @op: virtchnl opcode
- * @msg_size: size of the payload
- * @msg: pointer to buffer holding the payload
- * @cookie: unique SW generated cookie per message
- *
- * Will prepare the control queue message and initiates the send api
+ * idpf_send_mb_msg - send mailbox message to the device control plane
+ * @adapter: driver specific private structure
+ * @xn_params: Xn send parameters to fill
+ * @send_buf: buffer to send
+ * @send_buf_size: size of the send buffer
*
- * Returns 0 on success, negative on failure
- */
-int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
- u16 msg_size, u8 *msg, u16 cookie)
-{
- struct idpf_ctlq_msg *ctlq_msg;
- struct idpf_dma_mem *dma_mem;
- int err;
-
- /* If we are here and a reset is detected nothing much can be
- * done. This thread should silently abort and expected to
- * be corrected with a new run either by user or driver
- * flows after reset
- */
- if (idpf_is_reset_detected(adapter))
- return 0;
-
- err = idpf_mb_clean(adapter);
- if (err)
- return err;
-
- ctlq_msg = kzalloc(sizeof(*ctlq_msg), GFP_ATOMIC);
- if (!ctlq_msg)
- return -ENOMEM;
-
- dma_mem = kzalloc(sizeof(*dma_mem), GFP_ATOMIC);
- if (!dma_mem) {
- err = -ENOMEM;
- goto dma_mem_error;
- }
-
- ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_cp;
- ctlq_msg->func_id = 0;
-
- idpf_prepare_ptp_mb_msg(adapter, op, ctlq_msg);
-
- ctlq_msg->data_len = msg_size;
- ctlq_msg->cookie.mbx.chnl_opcode = op;
- ctlq_msg->cookie.mbx.chnl_retval = 0;
- dma_mem->size = IDPF_CTLQ_MAX_BUF_LEN;
- dma_mem->va = dma_alloc_coherent(&adapter->pdev->dev, dma_mem->size,
- &dma_mem->pa, GFP_ATOMIC);
- if (!dma_mem->va) {
- err = -ENOMEM;
- goto dma_alloc_error;
- }
-
- /* It's possible we're just sending an opcode but no buffer */
- if (msg && msg_size)
- memcpy(dma_mem->va, msg, msg_size);
- ctlq_msg->ctx.indirect.payload = dma_mem;
- ctlq_msg->ctx.sw_cookie.data = cookie;
-
- err = idpf_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg);
- if (err)
- goto send_error;
-
- return 0;
-
-send_error:
- dma_free_coherent(&adapter->pdev->dev, dma_mem->size, dma_mem->va,
- dma_mem->pa);
-dma_alloc_error:
- kfree(dma_mem);
-dma_mem_error:
- kfree(ctlq_msg);
-
- return err;
-}
-
-/* API for virtchnl "transaction" support ("xn" for short).
+ * Fill the Xn parameters with the required info to send a virtchnl message.
+ * The send buffer is DMA mapped in the libie to avoid memcpy.
*
- * We are reusing the completion lock to serialize the accesses to the
- * transaction state for simplicity, but it could be its own separate synchro
- * as well. For now, this API is only used from within a workqueue context;
- * raw_spin_lock() is enough.
- */
-/**
- * idpf_vc_xn_lock - Request exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_lock(xn) \
- raw_spin_lock(&(xn)->completed.wait.lock)
-
-/**
- * idpf_vc_xn_unlock - Release exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_unlock(xn) \
- raw_spin_unlock(&(xn)->completed.wait.lock)
-
-/**
- * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
- * reset the transaction state.
- * @xn: struct idpf_vc_xn to update
- */
-static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)
-{
- xn->reply.iov_base = NULL;
- xn->reply.iov_len = 0;
-
- if (xn->state != IDPF_VC_XN_SHUTDOWN)
- xn->state = IDPF_VC_XN_IDLE;
-}
-
-/**
- * idpf_vc_xn_init - Initialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
- */
-static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
-{
- int i;
-
- spin_lock_init(&vcxn_mngr->xn_bm_lock);
-
- for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
- struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
-
- xn->state = IDPF_VC_XN_IDLE;
- xn->idx = i;
- idpf_vc_xn_release_bufs(xn);
- init_completion(&xn->completed);
- }
-
- bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
-}
-
-/**
- * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
+ * Cleanup the mailbox queue entries of the previously sent message to
+ * unmap and release the buffer.
*
- * All waiting threads will be woken-up and their transaction aborted. Further
- * operations on that object will fail.
+ * Return: 0 if the request was successful, -%EBUSY if reset is detected
+ * or Tx control queue is full, other negative error code on failure.
*/
-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
+int idpf_send_mb_msg(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size)
{
- int i;
-
- spin_lock_bh(&vcxn_mngr->xn_bm_lock);
- bitmap_zero(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
- spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
+ struct libie_ctlq_msg ctlq_msg = {};
- for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
- struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
+ if (idpf_is_reset_detected(adapter)) {
+ if (!libie_cp_can_send_onstack(send_buf_size))
+ kfree(send_buf);
- idpf_vc_xn_lock(xn);
- xn->state = IDPF_VC_XN_SHUTDOWN;
- idpf_vc_xn_release_bufs(xn);
- idpf_vc_xn_unlock(xn);
- complete_all(&xn->completed);
+ return -EBUSY;
}
-}
-
-/**
- * idpf_vc_xn_pop_free - Pop a free transaction from free list
- * @vcxn_mngr: transaction manager to pop from
- *
- * Returns NULL if no free transactions
- */
-static
-struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr)
-{
- struct idpf_vc_xn *xn = NULL;
- unsigned long free_idx;
- spin_lock_bh(&vcxn_mngr->xn_bm_lock);
- free_idx = find_first_bit(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
- if (free_idx == IDPF_VC_XN_RING_LEN)
- goto do_unlock;
+ idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
+ xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
- clear_bit(free_idx, vcxn_mngr->free_xn_bm);
- xn = &vcxn_mngr->ring[free_idx];
- xn->salt = vcxn_mngr->salt++;
+ xn_params->send_buf.iov_base = send_buf;
+ xn_params->send_buf.iov_len = send_buf_size;
+ xn_params->xnm = adapter->xnm;
+ xn_params->ctlq = xn_params->ctlq ? xn_params->ctlq : adapter->asq;
+ xn_params->rel_tx_buf = kfree;
-do_unlock:
- spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
+ idpf_mb_clean(xn_params->ctlq, false);
- return xn;
-}
-
-/**
- * idpf_vc_xn_push_free - Push a free transaction to free list
- * @vcxn_mngr: transaction manager to push to
- * @xn: transaction to push
- */
-static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
- struct idpf_vc_xn *xn)
-{
- idpf_vc_xn_release_bufs(xn);
- set_bit(xn->idx, vcxn_mngr->free_xn_bm);
+ return libie_ctlq_xn_send(xn_params);
}
/**
- * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction
- * @adapter: driver specific private structure with vcxn_mngr
- * @params: parameters for this particular transaction including
- * -vc_op: virtchannel operation to send
- * -send_buf: kvec iov for send buf and len
- * -recv_buf: kvec iov for recv buf and len (ignored if NULL)
- * -timeout_ms: timeout waiting for a reply (milliseconds)
- * -async: don't wait for message reply, will lose caller context
- * -async_handler: callback to handle async replies
+ * idpf_send_mb_msg_kfree - send mailbox message and free the send buffer
+ * @adapter: driver specific private structure
+ * @xn_params: Xn send parameters to fill
+ * @send_buf: buffer to send, can be released with kfree()
+ * @send_buf_size: size of the send buffer
*
- * @returns >= 0 for success, the size of the initial reply (may or may not be
- * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for
- * error.
- */
-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
- const struct idpf_vc_xn_params *params)
-{
- const struct kvec *send_buf = &params->send_buf;
- struct idpf_vc_xn *xn;
- ssize_t retval;
- u16 cookie;
-
- xn = idpf_vc_xn_pop_free(adapter->vcxn_mngr);
- /* no free transactions available */
- if (!xn)
- return -ENOSPC;
-
- idpf_vc_xn_lock(xn);
- if (xn->state == IDPF_VC_XN_SHUTDOWN) {
- retval = -ENXIO;
- goto only_unlock;
- } else if (xn->state != IDPF_VC_XN_IDLE) {
- /* We're just going to clobber this transaction even though
- * it's not IDLE. If we don't reuse it we could theoretically
- * eventually leak all the free transactions and not be able to
- * send any messages. At least this way we make an attempt to
- * remain functional even though something really bad is
- * happening that's corrupting what was supposed to be free
- * transactions.
- */
- WARN_ONCE(1, "There should only be idle transactions in free list (idx %d op %d)\n",
- xn->idx, xn->vc_op);
- }
-
- xn->reply = params->recv_buf;
- xn->reply_sz = 0;
- xn->state = params->async ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING;
- xn->vc_op = params->vc_op;
- xn->async_handler = params->async_handler;
- idpf_vc_xn_unlock(xn);
-
- if (!params->async)
- reinit_completion(&xn->completed);
- cookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn->salt) |
- FIELD_PREP(IDPF_VC_XN_IDX_M, xn->idx);
-
- retval = idpf_send_mb_msg(adapter, params->vc_op,
- send_buf->iov_len, send_buf->iov_base,
- cookie);
- if (retval) {
- idpf_vc_xn_lock(xn);
- goto release_and_unlock;
- }
-
- if (params->async)
- return 0;
-
- wait_for_completion_timeout(&xn->completed,
- msecs_to_jiffies(params->timeout_ms));
-
- /* No need to check the return value; we check the final state of the
- * transaction below. It's possible the transaction actually gets more
- * timeout than specified if we get preempted here but after
- * wait_for_completion_timeout returns. This should be non-issue
- * however.
- */
- idpf_vc_xn_lock(xn);
- switch (xn->state) {
- case IDPF_VC_XN_SHUTDOWN:
- retval = -ENXIO;
- goto only_unlock;
- case IDPF_VC_XN_WAITING:
- dev_notice_ratelimited(&adapter->pdev->dev,
- "Transaction timed-out (op:%d cookie:%04x vc_op:%d salt:%02x timeout:%dms)\n",
- params->vc_op, cookie, xn->vc_op,
- xn->salt, params->timeout_ms);
- retval = -ETIME;
- break;
- case IDPF_VC_XN_COMPLETED_SUCCESS:
- retval = xn->reply_sz;
- break;
- case IDPF_VC_XN_COMPLETED_FAILED:
- dev_notice_ratelimited(&adapter->pdev->dev, "Transaction failed (op %d)\n",
- params->vc_op);
- retval = -EIO;
- break;
- default:
- /* Invalid state. */
- WARN_ON_ONCE(1);
- retval = -EIO;
- break;
- }
-
-release_and_unlock:
- idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
- /* If we receive a VC reply after here, it will be dropped. */
-only_unlock:
- idpf_vc_xn_unlock(xn);
-
- return retval;
-}
-
-/**
- * idpf_vc_xn_forward_async - Handle async reply receives
- * @adapter: private data struct
- * @xn: transaction to handle
- * @ctlq_msg: corresponding ctlq_msg
+ * libie_cp functions consume only buffers above certain size,
+ * smaller buffers are assumed to be on the stack. However, for some
+ * commands with variable message size it makes sense to always use kzalloc(),
+ * which means we have to free smaller buffers ourselves.
*
- * For async sends we're going to lose the caller's context so, if an
- * async_handler was provided, it can deal with the reply, otherwise we'll just
- * check and report if there is an error.
+ * Return: 0 if no unexpected errors were encountered,
+ * negative error code otherwise.
*/
-static int
-idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
- const struct idpf_ctlq_msg *ctlq_msg)
+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size)
{
- int err = 0;
-
- if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
- dev_err_ratelimited(&adapter->pdev->dev, "Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
- xn->reply_sz = 0;
- err = -EINVAL;
- goto release_bufs;
- }
-
- if (xn->async_handler) {
- err = xn->async_handler(adapter, xn, ctlq_msg);
- goto release_bufs;
- }
-
- if (ctlq_msg->cookie.mbx.chnl_retval) {
- xn->reply_sz = 0;
- dev_err_ratelimited(&adapter->pdev->dev, "Async message failure (op %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode);
- err = -EINVAL;
- }
+ int err = idpf_send_mb_msg(adapter, xn_params, send_buf, send_buf_size);
-release_bufs:
- idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
+ if (libie_cp_can_send_onstack(send_buf_size))
+ kfree(send_buf);
return err;
}
/**
- * idpf_vc_xn_forward_reply - copy a reply back to receiving thread
- * @adapter: driver specific private structure with vcxn_mngr
- * @ctlq_msg: controlq message to send back to receiving thread
+ * idpf_send_vf_reset_msg - send one way VF reset message
+ * @adapter: driver specific private structure
*/
-static int
-idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
- const struct idpf_ctlq_msg *ctlq_msg)
+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter)
{
- const void *payload = NULL;
- size_t payload_size = 0;
- struct idpf_vc_xn *xn;
- u16 msg_info;
- int err = 0;
- u16 xn_idx;
- u16 salt;
-
- msg_info = ctlq_msg->ctx.sw_cookie.data;
- xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);
- if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) {
- dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n",
- xn_idx);
- return -EINVAL;
- }
- xn = &adapter->vcxn_mngr->ring[xn_idx];
- idpf_vc_xn_lock(xn);
- salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);
- if (xn->salt != salt) {
- dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (exp:%d@%02x(%d) != got:%d@%02x)\n",
- xn->vc_op, xn->salt, xn->state,
- ctlq_msg->cookie.mbx.chnl_opcode, salt);
- idpf_vc_xn_unlock(xn);
- return -EINVAL;
- }
-
- switch (xn->state) {
- case IDPF_VC_XN_WAITING:
- /* success */
- break;
- case IDPF_VC_XN_IDLE:
- dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode);
- err = -EINVAL;
- goto out_unlock;
- case IDPF_VC_XN_SHUTDOWN:
- /* ENXIO is a bit special here as the recv msg loop uses that
- * know if it should stop trying to clean the ring if we lost
- * the virtchnl. We need to stop playing with registers and
- * yield.
- */
- err = -ENXIO;
- goto out_unlock;
- case IDPF_VC_XN_ASYNC:
- err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
- idpf_vc_xn_unlock(xn);
- return err;
- default:
- dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode);
- err = -EBUSY;
- goto out_unlock;
- }
+ struct libie_ctlq_info *ctlq = adapter->asq;
- if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
- dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
- xn->reply_sz = 0;
- xn->state = IDPF_VC_XN_COMPLETED_FAILED;
- err = -EINVAL;
- goto out_unlock;
- }
+ /* Forcefully claim send queue slot */
+ idpf_mb_clean(ctlq, true);
- if (ctlq_msg->cookie.mbx.chnl_retval) {
- xn->reply_sz = 0;
- xn->state = IDPF_VC_XN_COMPLETED_FAILED;
- err = -EINVAL;
- goto out_unlock;
- }
+ scoped_guard(spinlock, &ctlq->lock) {
+ *ctlq->tx_msg[ctlq->next_to_use] = (struct libie_ctlq_msg) {
+ .opcode = LIBIE_CTLQ_SEND_MSG_TO_CP,
+ .chnl_opcode = VIRTCHNL2_OP_RESET_VF,
+ };
- if (ctlq_msg->data_len) {
- payload = ctlq_msg->ctx.indirect.payload->va;
- payload_size = ctlq_msg->data_len;
+ libie_ctlq_send(adapter->asq, 1);
}
-
- xn->reply_sz = payload_size;
- xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
-
- if (xn->reply.iov_base && xn->reply.iov_len && payload_size)
- memcpy(xn->reply.iov_base, payload,
- min_t(size_t, xn->reply.iov_len, payload_size));
-
-out_unlock:
- idpf_vc_xn_unlock(xn);
- /* we _cannot_ hold lock while calling complete */
- complete(&xn->completed);
-
- return err;
-}
-
-/**
- * idpf_recv_mb_msg - Receive message over mailbox
- * @adapter: Driver specific private structure
- *
- * Will receive control queue message and posts the receive buffer. Returns 0
- * on success and negative on failure.
- */
-int idpf_recv_mb_msg(struct idpf_adapter *adapter)
-{
- struct idpf_ctlq_msg ctlq_msg;
- struct idpf_dma_mem *dma_mem;
- int post_err, err;
- u16 num_recv;
-
- while (1) {
- /* This will get <= num_recv messages and output how many
- * actually received on num_recv.
- */
- num_recv = 1;
- err = idpf_ctlq_recv(adapter->hw.arq, &num_recv, &ctlq_msg);
- if (err || !num_recv)
- break;
-
- if (ctlq_msg.data_len) {
- dma_mem = ctlq_msg.ctx.indirect.payload;
- } else {
- dma_mem = NULL;
- num_recv = 0;
- }
-
- if (ctlq_msg.cookie.mbx.chnl_opcode == VIRTCHNL2_OP_EVENT)
- idpf_recv_event_msg(adapter, &ctlq_msg);
- else
- err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg);
-
- post_err = idpf_ctlq_post_rx_buffs(&adapter->hw,
- adapter->hw.arq,
- &num_recv, &dma_mem);
-
- /* If post failed clear the only buffer we supplied */
- if (post_err) {
- if (dma_mem)
- dma_free_coherent(&adapter->pdev->dev,
- dma_mem->size, dma_mem->va,
- dma_mem->pa);
- break;
- }
-
- /* virtchnl trying to shutdown, stop cleaning */
- if (err == -ENXIO)
- break;
- }
-
- return err;
}
struct idpf_chunked_msg_params {
- u32 (*prepare_msg)(const struct idpf_vport *vport,
- void *buf, const void *pos,
- u32 num);
+ u32 (*prepare_msg)(u32 vport_id, void *buf,
+ const void *pos, u32 num);
const void *chunks;
u32 num_chunks;
@@ -728,17 +279,22 @@ struct idpf_chunked_msg_params {
u32 config_sz;
u32 vc_op;
+ u32 vport_id;
};
-struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_vport *vport, u32 num)
+struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *qv_rsrc,
+ u32 vport_id, u32 num)
{
struct idpf_queue_set *qp;
- qp = kzalloc(struct_size(qp, qs, num), GFP_KERNEL);
+ qp = kzalloc_flex(*qp, qs, num);
if (!qp)
return NULL;
- qp->vport = vport;
+ qp->adapter = adapter;
+ qp->qv_rsrc = qv_rsrc;
+ qp->vport_id = vport_id;
qp->num = num;
return qp;
@@ -746,7 +302,7 @@ struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_vport *vport, u32 num)
/**
* idpf_send_chunked_msg - send VC message consisting of chunks
- * @vport: virtual port data structure
+ * @adapter: Driver specific private structure
* @params: message params
*
* Helper function for preparing a message describing queues to be enabled
@@ -754,47 +310,46 @@ struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_vport *vport, u32 num)
*
* Return: the total size of the prepared message.
*/
-static int idpf_send_chunked_msg(struct idpf_vport *vport,
+static int idpf_send_chunked_msg(struct idpf_adapter *adapter,
const struct idpf_chunked_msg_params *params)
{
- struct idpf_vc_xn_params xn_params = {
- .vc_op = params->vc_op,
+ struct libie_ctlq_xn_send_params xn_params = {
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = params->vc_op,
};
const void *pos = params->chunks;
- u32 num_chunks, num_msgs, buf_sz;
- void *buf __free(kfree) = NULL;
u32 totqs = params->num_chunks;
+ u32 vid = params->vport_id;
+ u32 num_chunks, num_msgs;
- num_chunks = min(IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
- params->chunk_sz), totqs);
+ num_chunks = IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
+ params->chunk_sz);
num_msgs = DIV_ROUND_UP(totqs, num_chunks);
- buf_sz = params->config_sz + num_chunks * params->chunk_sz;
- buf = kzalloc(buf_sz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- xn_params.send_buf.iov_base = buf;
-
for (u32 i = 0; i < num_msgs; i++) {
- ssize_t reply_sz;
+ u32 buf_sz;
+ void *buf;
+ int err;
- memset(buf, 0, buf_sz);
- xn_params.send_buf.iov_len = buf_sz;
+ num_chunks = min(num_chunks, totqs);
+ buf_sz = params->config_sz + num_chunks * params->chunk_sz;
+ buf = kzalloc(buf_sz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- if (params->prepare_msg(vport, buf, pos, num_chunks) != buf_sz)
+ if (params->prepare_msg(vid, buf, pos, num_chunks) != buf_sz) {
+ kfree(buf);
return -EINVAL;
+ }
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, buf, buf_sz);
+ if (err)
+ return err;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ xn_params.recv_mem = (struct kvec) {};
pos += num_chunks * params->chunk_sz;
totqs -= num_chunks;
-
- num_chunks = min(num_chunks, totqs);
- buf_sz = params->config_sz + num_chunks * params->chunk_sz;
}
return 0;
@@ -809,6 +364,7 @@ static int idpf_send_chunked_msg(struct idpf_vport *vport,
*/
static int idpf_wait_for_marker_event_set(const struct idpf_queue_set *qs)
{
+ struct net_device *netdev;
struct idpf_tx_queue *txq;
bool markers_rcvd = true;
@@ -817,6 +373,8 @@ static int idpf_wait_for_marker_event_set(const struct idpf_queue_set *qs)
case VIRTCHNL2_QUEUE_TYPE_TX:
txq = qs->qs[i].txq;
+ netdev = txq->netdev;
+
idpf_queue_set(SW_MARKER, txq);
idpf_wait_for_sw_marker_completion(txq);
markers_rcvd &= !idpf_queue_has(SW_MARKER, txq);
@@ -827,7 +385,7 @@ static int idpf_wait_for_marker_event_set(const struct idpf_queue_set *qs)
}
if (!markers_rcvd) {
- netdev_warn(qs->vport->netdev,
+ netdev_warn(netdev,
"Failed to receive marker packets\n");
return -ETIMEDOUT;
}
@@ -845,7 +403,8 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport)
{
struct idpf_queue_set *qs __free(kfree) = NULL;
- qs = idpf_alloc_queue_set(vport, vport->num_txq);
+ qs = idpf_alloc_queue_set(vport->adapter, &vport->dflt_qv_rsrc,
+ vport->vport_id, vport->num_txq);
if (!qs)
return -ENOMEM;
@@ -865,11 +424,14 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport)
*/
static int idpf_send_ver_msg(struct idpf_adapter *adapter)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_VERSION,
+ };
+ struct virtchnl2_version_info *vvi_recv;
struct virtchnl2_version_info vvi;
- ssize_t reply_sz;
u32 major, minor;
- int err = 0;
+ int err;
if (adapter->virt_ver_maj) {
vvi.major = cpu_to_le32(adapter->virt_ver_maj);
@@ -879,24 +441,23 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
}
- xn_params.vc_op = VIRTCHNL2_OP_VERSION;
- xn_params.send_buf.iov_base = &vvi;
- xn_params.send_buf.iov_len = sizeof(vvi);
- xn_params.recv_buf = xn_params.send_buf;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &vvi);
+ if (err)
+ return err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz < sizeof(vvi))
- return -EIO;
+ if (xn_params.recv_mem.iov_len < sizeof(*vvi_recv)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- major = le32_to_cpu(vvi.major);
- minor = le32_to_cpu(vvi.minor);
+ vvi_recv = xn_params.recv_mem.iov_base;
+ major = le32_to_cpu(vvi_recv->major);
+ minor = le32_to_cpu(vvi_recv->minor);
if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto free_rx_buf;
}
if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
@@ -914,6 +475,9 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
adapter->virt_ver_maj = major;
adapter->virt_ver_min = minor;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
return err;
}
@@ -926,9 +490,12 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
*/
static int idpf_send_get_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_CAPS,
+ };
struct virtchnl2_get_capabilities caps = {};
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ int err;
caps.csum_caps =
cpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4 |
@@ -988,139 +555,154 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
VIRTCHNL2_CAP_LOOPBACK |
VIRTCHNL2_CAP_PTP);
- xn_params.vc_op = VIRTCHNL2_OP_GET_CAPS;
- xn_params.send_buf.iov_base = &caps;
- xn_params.send_buf.iov_len = sizeof(caps);
- xn_params.recv_buf.iov_base = &adapter->caps;
- xn_params.recv_buf.iov_len = sizeof(adapter->caps);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &caps);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len < sizeof(adapter->caps)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz < sizeof(adapter->caps))
- return -EIO;
+ memcpy(&adapter->caps, xn_params.recv_mem.iov_base,
+ sizeof(adapter->caps));
- return 0;
+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
+ *
+ * Return: %true if region can be received though virtchnl command,
+ * %false if region is related to mailbox or resetting
+ */
+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg)
+{
+ struct idpf_adapter *adapter =
+ container_of(mmio_info, struct idpf_adapter,
+ ctlq_ctx.mmio_info);
+
+ for (uint i = 0; i < IDPF_MMIO_REG_NUM_STATIC; i++) {
+ if (reg->bar_idx == 0 &&
+ reg->offset == adapter->dev_ops.static_reg_info[i].start)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * idpf_decfg_lan_memory_regions - Unmap non-static memory regions
+ * @adapter: Driver specific private structure
+ */
+static void idpf_decfg_lan_memory_regions(struct idpf_adapter *adapter)
+{
+ libie_pci_unmap_fltr_regs(&adapter->ctlq_ctx.mmio_info,
+ idpf_mmio_region_non_static);
}
/**
- * idpf_send_get_lan_memory_regions - Send virtchnl get LAN memory regions msg
+ * idpf_cfg_lan_memory_regions - Get (via virtchnl) and map LAN memory regions
* @adapter: Driver specific private struct
*
* Return: 0 on success or error code on failure.
*/
-static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter)
+static int idpf_cfg_lan_memory_regions(struct idpf_adapter *adapter)
{
- struct virtchnl2_get_lan_memory_regions *rcvd_regions __free(kfree);
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
- .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,
+ struct virtchnl2_get_lan_memory_regions *send_regions, *rcvd_regions;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int num_regions, size;
- struct idpf_hw *hw;
- ssize_t reply_sz;
+ size_t send_sz, reply_sz, size;
+ int num_regions;
int err = 0;
- rcvd_regions = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcvd_regions)
+ send_sz = sizeof(struct virtchnl2_get_lan_memory_regions) +
+ sizeof(struct virtchnl2_mem_region);
+ send_regions = kzalloc(send_sz, GFP_KERNEL);
+ if (!send_regions)
return -ENOMEM;
- xn_params.recv_buf.iov_base = rcvd_regions;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ send_regions->num_memory_regions = cpu_to_le16(1);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, send_regions,
+ send_sz);
+ if (err)
+ return err;
+ rcvd_regions = xn_params.recv_mem.iov_base;
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz < sizeof(*rcvd_regions)) {
+ err = -EIO;
+ goto rel_rx_buf;
+ }
num_regions = le16_to_cpu(rcvd_regions->num_memory_regions);
size = struct_size(rcvd_regions, mem_reg, num_regions);
- if (reply_sz < size)
- return -EIO;
-
- if (size > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
-
- hw = &adapter->hw;
- hw->lan_regs = kcalloc(num_regions, sizeof(*hw->lan_regs), GFP_KERNEL);
- if (!hw->lan_regs)
- return -ENOMEM;
+ if (reply_sz < size) {
+ err = -EIO;
+ goto rel_rx_buf;
+ }
for (int i = 0; i < num_regions; i++) {
- hw->lan_regs[i].addr_len =
- le64_to_cpu(rcvd_regions->mem_reg[i].size);
- hw->lan_regs[i].addr_start =
- le64_to_cpu(rcvd_regions->mem_reg[i].start_offset);
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
+ resource_size_t offset, len;
+
+ offset = le64_to_cpu(rcvd_regions->mem_reg[i].start_offset);
+ len = le64_to_cpu(rcvd_regions->mem_reg[i].size);
+ if (len && !libie_pci_map_mmio_region(mmio, offset, len)) {
+ idpf_decfg_lan_memory_regions(adapter);
+ err = -EIO;
+ goto rel_rx_buf;
+ }
}
- hw->num_lan_regs = num_regions;
+
+rel_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
return err;
}
/**
- * idpf_calc_remaining_mmio_regs - calculate MMIO regions outside mbx and rstat
+ * idpf_map_remaining_mmio_regs - map MMIO regions outside mbx and rstat
* @adapter: Driver specific private structure
*
- * Called when idpf_send_get_lan_memory_regions is not supported. This will
+ * Called when idpf_cfg_lan_memory_regions is not supported. This will
* calculate the offsets and sizes for the regions before, in between, and
- * after the mailbox and rstat MMIO mappings.
+ * after the mailbox and rstat MMIO mappings, and map those ranges.
*
* Return: 0 on success or error code on failure.
*/
-static int idpf_calc_remaining_mmio_regs(struct idpf_adapter *adapter)
+static int idpf_map_remaining_mmio_regs(struct idpf_adapter *adapter)
{
struct resource *rstat_reg = &adapter->dev_ops.static_reg_info[1];
struct resource *mbx_reg = &adapter->dev_ops.static_reg_info[0];
- struct idpf_hw *hw = &adapter->hw;
-
- hw->num_lan_regs = IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING;
- hw->lan_regs = kcalloc(hw->num_lan_regs, sizeof(*hw->lan_regs),
- GFP_KERNEL);
- if (!hw->lan_regs)
- return -ENOMEM;
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
+ resource_size_t reg_start, size;
+ bool ok = true;
/* Region preceding mailbox */
- hw->lan_regs[0].addr_start = 0;
- hw->lan_regs[0].addr_len = mbx_reg->start;
- /* Region between mailbox and rstat */
- hw->lan_regs[1].addr_start = mbx_reg->end + 1;
- hw->lan_regs[1].addr_len = rstat_reg->start -
- hw->lan_regs[1].addr_start;
- /* Region after rstat */
- hw->lan_regs[2].addr_start = rstat_reg->end + 1;
- hw->lan_regs[2].addr_len = pci_resource_len(adapter->pdev, 0) -
- hw->lan_regs[2].addr_start;
+ size = mbx_reg->start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, 0, size);
- return 0;
-}
-
-/**
- * idpf_map_lan_mmio_regs - map remaining LAN BAR regions
- * @adapter: Driver specific private structure
- *
- * Return: 0 on success or error code on failure.
- */
-static int idpf_map_lan_mmio_regs(struct idpf_adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- struct idpf_hw *hw = &adapter->hw;
- resource_size_t res_start;
-
- res_start = pci_resource_start(pdev, 0);
-
- for (int i = 0; i < hw->num_lan_regs; i++) {
- resource_size_t start;
- long len;
+ /* Region between mailbox and rstat */
+ reg_start = mbx_reg->end + 1;
+ size = rstat_reg->start - reg_start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, reg_start, size);
- len = hw->lan_regs[i].addr_len;
- if (!len)
- continue;
- start = hw->lan_regs[i].addr_start + res_start;
+ /* Region after rstat */
+ reg_start = rstat_reg->end + 1;
+ size = pci_resource_len(adapter->pdev, 0) - reg_start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, reg_start, size);
- hw->lan_regs[i].vaddr = devm_ioremap(&pdev->dev, start, len);
- if (!hw->lan_regs[i].vaddr) {
- pci_err(pdev, "failed to allocate BAR0 region\n");
- return -ENOMEM;
- }
+ if (!ok) {
+ idpf_decfg_lan_memory_regions(adapter);
+ return -ENOMEM;
}
return 0;
@@ -1141,24 +723,43 @@ int idpf_add_del_fsteer_filters(struct idpf_adapter *adapter,
struct virtchnl2_flow_rule_add_del *rule,
enum virtchnl2_op opcode)
{
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = opcode,
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ };
+ struct virtchnl2_flow_rule_add_del *rx_rule;
int rule_count = le32_to_cpu(rule->count);
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ size_t send_sz;
+ int err;
if (opcode != VIRTCHNL2_OP_ADD_FLOW_RULE &&
- opcode != VIRTCHNL2_OP_DEL_FLOW_RULE)
+ opcode != VIRTCHNL2_OP_DEL_FLOW_RULE) {
+ kfree(rule);
return -EINVAL;
+ }
+
+ send_sz = struct_size(rule, rule_info, rule_count);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rule, send_sz);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len < send_sz) {
+ err = -EIO;
+ goto rel_rx;
+ }
- xn_params.vc_op = opcode;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.async = false;
- xn_params.send_buf.iov_base = rule;
- xn_params.send_buf.iov_len = struct_size(rule, rule_info, rule_count);
- xn_params.recv_buf.iov_base = rule;
- xn_params.recv_buf.iov_len = struct_size(rule, rule_info, rule_count);
+ rx_rule = xn_params.recv_mem.iov_base;
+ for (int i = 0; i < rule_count; i++) {
+ if (rx_rule->rule_info[i].status !=
+ cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
+ err = -EIO;
+ goto rel_rx;
+ }
+ }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- return reply_sz < 0 ? reply_sz : 0;
+rel_rx:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -1258,21 +859,60 @@ static void idpf_init_avail_queues(struct idpf_adapter *adapter)
}
/**
+ * idpf_vport_init_queue_reg_chunks - initialize queue register chunks
+ * @vport_config: persistent vport structure to store the queue register info
+ * @schunks: source chunks to copy data from
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int
+idpf_vport_init_queue_reg_chunks(struct idpf_vport_config *vport_config,
+ struct virtchnl2_queue_reg_chunks *schunks)
+{
+ struct idpf_queue_id_reg_info *q_info = &vport_config->qid_reg_info;
+ u16 num_chunks = le16_to_cpu(schunks->num_chunks);
+
+ kfree(q_info->queue_chunks);
+
+ q_info->queue_chunks = kzalloc_objs(*q_info->queue_chunks, num_chunks);
+ if (!q_info->queue_chunks) {
+ q_info->num_chunks = 0;
+ return -ENOMEM;
+ }
+
+ q_info->num_chunks = num_chunks;
+
+ for (u16 i = 0; i < num_chunks; i++) {
+ struct idpf_queue_id_reg_chunk *dchunk = &q_info->queue_chunks[i];
+ struct virtchnl2_queue_reg_chunk *schunk = &schunks->chunks[i];
+
+ dchunk->qtail_reg_start = le64_to_cpu(schunk->qtail_reg_start);
+ dchunk->qtail_reg_spacing = le32_to_cpu(schunk->qtail_reg_spacing);
+ dchunk->type = le32_to_cpu(schunk->type);
+ dchunk->start_queue_id = le32_to_cpu(schunk->start_queue_id);
+ dchunk->num_queues = le32_to_cpu(schunk->num_queues);
+ }
+
+ return 0;
+}
+
+/**
* idpf_get_reg_intr_vecs - Get vector queue register offset
- * @vport: virtual port structure
+ * @adapter: adapter structure to get the vector chunks
* @reg_vals: Register offsets to store in
+ * @num_vecs: number of entries the @reg_vals array can hold
*
- * Returns number of registers that got populated
+ * Return: number of registers that got populated
*/
-int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
- struct idpf_vec_regs *reg_vals)
+int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
+ struct idpf_vec_regs *reg_vals, int num_vecs)
{
struct virtchnl2_vector_chunks *chunks;
struct idpf_vec_regs reg_val;
u16 num_vchunks, num_vec;
int num_regs = 0, i, j;
- chunks = &vport->adapter->req_vec_chunks->vchunks;
+ chunks = &adapter->req_vec_chunks->vchunks;
num_vchunks = le16_to_cpu(chunks->num_vchunks);
for (j = 0; j < num_vchunks; j++) {
@@ -1289,7 +929,7 @@ int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
dynctl_reg_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
- for (i = 0; i < num_vec; i++) {
+ for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg;
reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
reg_vals[num_regs].itrn_index_spacing =
@@ -1317,25 +957,25 @@ int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
* are filled.
*/
static int idpf_vport_get_q_reg(u32 *reg_vals, int num_regs, u32 q_type,
- struct virtchnl2_queue_reg_chunks *chunks)
+ struct idpf_queue_id_reg_info *chunks)
{
- u16 num_chunks = le16_to_cpu(chunks->num_chunks);
+ u16 num_chunks = chunks->num_chunks;
int reg_filled = 0, i;
u32 reg_val;
while (num_chunks--) {
- struct virtchnl2_queue_reg_chunk *chunk;
+ struct idpf_queue_id_reg_chunk *chunk;
u16 num_q;
- chunk = &chunks->chunks[num_chunks];
- if (le32_to_cpu(chunk->type) != q_type)
+ chunk = &chunks->queue_chunks[num_chunks];
+ if (chunk->type != q_type)
continue;
- num_q = le32_to_cpu(chunk->num_queues);
- reg_val = le64_to_cpu(chunk->qtail_reg_start);
+ num_q = chunk->num_queues;
+ reg_val = chunk->qtail_reg_start;
for (i = 0; i < num_q && reg_filled < num_regs ; i++) {
reg_vals[reg_filled++] = reg_val;
- reg_val += le32_to_cpu(chunk->qtail_reg_spacing);
+ reg_val += chunk->qtail_reg_spacing;
}
}
@@ -1345,53 +985,56 @@ static int idpf_vport_get_q_reg(u32 *reg_vals, int num_regs, u32 q_type,
/**
* __idpf_queue_reg_init - initialize queue registers
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
* @reg_vals: registers we are initializing
* @num_regs: how many registers there are in total
* @q_type: queue model
*
* Return number of queues that are initialized
*/
-static int __idpf_queue_reg_init(struct idpf_vport *vport, u32 *reg_vals,
+static int __idpf_queue_reg_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc, u32 *reg_vals,
int num_regs, u32 q_type)
{
- struct idpf_adapter *adapter = vport->adapter;
+ struct libie_mmio_info *mmio = &vport->adapter->ctlq_ctx.mmio_info;
int i, j, k = 0;
switch (q_type) {
case VIRTCHNL2_QUEUE_TYPE_TX:
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
for (j = 0; j < tx_qgrp->num_txq && k < num_regs; j++, k++)
tx_qgrp->txqs[j]->tail =
- idpf_get_reg_addr(adapter, reg_vals[k]);
+ libie_pci_get_mmio_addr(mmio,
+ reg_vals[k]);
}
break;
case VIRTCHNL2_QUEUE_TYPE_RX:
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u16 num_rxq = rx_qgrp->singleq.num_rxq;
for (j = 0; j < num_rxq && k < num_regs; j++, k++) {
struct idpf_rx_queue *q;
q = rx_qgrp->singleq.rxqs[j];
- q->tail = idpf_get_reg_addr(adapter,
- reg_vals[k]);
+ q->tail = libie_pci_get_mmio_addr(mmio,
+ reg_vals[k]);
}
}
break;
case VIRTCHNL2_QUEUE_TYPE_RX_BUFFER:
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
- u8 num_bufqs = vport->num_bufqs_per_qgrp;
+ for (i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
+ u8 num_bufqs = rsrc->num_bufqs_per_qgrp;
for (j = 0; j < num_bufqs && k < num_regs; j++, k++) {
struct idpf_buf_queue *q;
q = &rx_qgrp->splitq.bufq_sets[j].bufq;
- q->tail = idpf_get_reg_addr(adapter,
- reg_vals[k]);
+ q->tail = libie_pci_get_mmio_addr(mmio,
+ reg_vals[k]);
}
}
break;
@@ -1405,15 +1048,15 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport, u32 *reg_vals,
/**
* idpf_queue_reg_init - initialize queue registers
* @vport: virtual port structure
+ * @rsrc: pointer to queue and vector resources
+ * @chunks: queue registers received over mailbox
*
- * Return 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-int idpf_queue_reg_init(struct idpf_vport *vport)
+int idpf_queue_reg_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ struct idpf_queue_id_reg_info *chunks)
{
- struct virtchnl2_create_vport *vport_params;
- struct virtchnl2_queue_reg_chunks *chunks;
- struct idpf_vport_config *vport_config;
- u16 vport_idx = vport->idx;
int num_regs, ret = 0;
u32 *reg_vals;
@@ -1422,28 +1065,18 @@ int idpf_queue_reg_init(struct idpf_vport *vport)
if (!reg_vals)
return -ENOMEM;
- vport_config = vport->adapter->vport_config[vport_idx];
- if (vport_config->req_qs_chunks) {
- struct virtchnl2_add_queues *vc_aq =
- (struct virtchnl2_add_queues *)vport_config->req_qs_chunks;
- chunks = &vc_aq->chunks;
- } else {
- vport_params = vport->adapter->vport_params_recvd[vport_idx];
- chunks = &vport_params->chunks;
- }
-
/* Initialize Tx queue tail register address */
num_regs = idpf_vport_get_q_reg(reg_vals, IDPF_LARGE_MAX_Q,
VIRTCHNL2_QUEUE_TYPE_TX,
chunks);
- if (num_regs < vport->num_txq) {
+ if (num_regs < rsrc->num_txq) {
ret = -EINVAL;
goto free_reg_vals;
}
- num_regs = __idpf_queue_reg_init(vport, reg_vals, num_regs,
+ num_regs = __idpf_queue_reg_init(vport, rsrc, reg_vals, num_regs,
VIRTCHNL2_QUEUE_TYPE_TX);
- if (num_regs < vport->num_txq) {
+ if (num_regs < rsrc->num_txq) {
ret = -EINVAL;
goto free_reg_vals;
}
@@ -1451,18 +1084,18 @@ int idpf_queue_reg_init(struct idpf_vport *vport)
/* Initialize Rx/buffer queue tail register address based on Rx queue
* model
*/
- if (idpf_is_queue_model_split(vport->rxq_model)) {
+ if (idpf_is_queue_model_split(rsrc->rxq_model)) {
num_regs = idpf_vport_get_q_reg(reg_vals, IDPF_LARGE_MAX_Q,
VIRTCHNL2_QUEUE_TYPE_RX_BUFFER,
chunks);
- if (num_regs < vport->num_bufq) {
+ if (num_regs < rsrc->num_bufq) {
ret = -EINVAL;
goto free_reg_vals;
}
- num_regs = __idpf_queue_reg_init(vport, reg_vals, num_regs,
+ num_regs = __idpf_queue_reg_init(vport, rsrc, reg_vals, num_regs,
VIRTCHNL2_QUEUE_TYPE_RX_BUFFER);
- if (num_regs < vport->num_bufq) {
+ if (num_regs < rsrc->num_bufq) {
ret = -EINVAL;
goto free_reg_vals;
}
@@ -1470,14 +1103,14 @@ int idpf_queue_reg_init(struct idpf_vport *vport)
num_regs = idpf_vport_get_q_reg(reg_vals, IDPF_LARGE_MAX_Q,
VIRTCHNL2_QUEUE_TYPE_RX,
chunks);
- if (num_regs < vport->num_rxq) {
+ if (num_regs < rsrc->num_rxq) {
ret = -EINVAL;
goto free_reg_vals;
}
- num_regs = __idpf_queue_reg_init(vport, reg_vals, num_regs,
+ num_regs = __idpf_queue_reg_init(vport, rsrc, reg_vals, num_regs,
VIRTCHNL2_QUEUE_TYPE_RX);
- if (num_regs < vport->num_rxq) {
+ if (num_regs < rsrc->num_rxq) {
ret = -EINVAL;
goto free_reg_vals;
}
@@ -1501,21 +1134,19 @@ free_reg_vals:
int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q)
{
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_CREATE_VPORT,
+ };
struct virtchnl2_create_vport *vport_msg;
- struct idpf_vc_xn_params xn_params = {};
u16 idx = adapter->next_vport;
int err, buf_size;
- ssize_t reply_sz;
buf_size = sizeof(struct virtchnl2_create_vport);
- if (!adapter->vport_params_reqd[idx]) {
- adapter->vport_params_reqd[idx] = kzalloc(buf_size,
- GFP_KERNEL);
- if (!adapter->vport_params_reqd[idx])
- return -ENOMEM;
- }
+ vport_msg = kzalloc(buf_size, GFP_KERNEL);
+ if (!vport_msg)
+ return -ENOMEM;
- vport_msg = adapter->vport_params_reqd[idx];
vport_msg->vport_type = cpu_to_le16(VIRTCHNL2_VPORT_TYPE_DEFAULT);
vport_msg->vport_index = cpu_to_le16(idx);
@@ -1532,38 +1163,35 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
err = idpf_vport_calc_total_qs(adapter, idx, vport_msg, max_q);
if (err) {
dev_err(&adapter->pdev->dev, "Enough queues are not available");
-
- return err;
+ goto rel_buf;
}
if (!adapter->vport_params_recvd[idx]) {
- adapter->vport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN,
- GFP_KERNEL);
+ adapter->vport_params_recvd[idx] =
+ kzalloc(LIBIE_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
if (!adapter->vport_params_recvd[idx]) {
err = -ENOMEM;
- goto free_vport_params;
+ goto rel_buf;
}
}
- xn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT;
- xn_params.send_buf.iov_base = vport_msg;
- xn_params.send_buf.iov_len = buf_size;
- xn_params.recv_buf.iov_base = adapter->vport_params_recvd[idx];
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0) {
- err = reply_sz;
- goto free_vport_params;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, vport_msg,
+ sizeof(*vport_msg));
+ if (err) {
+ kfree(adapter->vport_params_recvd[idx]);
+ adapter->vport_params_recvd[idx] = NULL;
+ return err;
}
+ memcpy(adapter->vport_params_recvd[idx], xn_params.recv_mem.iov_base,
+ xn_params.recv_mem.iov_len);
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
return 0;
-free_vport_params:
- kfree(adapter->vport_params_recvd[idx]);
- adapter->vport_params_recvd[idx] = NULL;
- kfree(adapter->vport_params_reqd[idx]);
- adapter->vport_params_reqd[idx] = NULL;
+rel_buf:
+ kfree(vport_msg);
return err;
}
@@ -1576,6 +1204,7 @@ free_vport_params:
*/
int idpf_check_supported_desc_ids(struct idpf_vport *vport)
{
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_adapter *adapter = vport->adapter;
struct virtchnl2_create_vport *vport_msg;
u64 rx_desc_ids, tx_desc_ids;
@@ -1592,17 +1221,17 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport)
rx_desc_ids = le64_to_cpu(vport_msg->rx_desc_ids);
tx_desc_ids = le64_to_cpu(vport_msg->tx_desc_ids);
- if (idpf_is_queue_model_split(vport->rxq_model)) {
+ if (idpf_is_queue_model_split(rsrc->rxq_model)) {
if (!(rx_desc_ids & VIRTCHNL2_RXDID_2_FLEX_SPLITQ_M)) {
dev_info(&adapter->pdev->dev, "Minimum RX descriptor support not provided, using the default\n");
vport_msg->rx_desc_ids = cpu_to_le64(VIRTCHNL2_RXDID_2_FLEX_SPLITQ_M);
}
} else {
if (!(rx_desc_ids & VIRTCHNL2_RXDID_2_FLEX_SQ_NIC_M))
- vport->base_rxd = true;
+ rsrc->base_rxd = true;
}
- if (!idpf_is_queue_model_split(vport->txq_model))
+ if (!idpf_is_queue_model_split(rsrc->txq_model))
return 0;
if ((tx_desc_ids & MIN_SUPPORT_TXDID) != MIN_SUPPORT_TXDID) {
@@ -1615,96 +1244,105 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport)
/**
* idpf_send_destroy_vport_msg - Send virtchnl destroy vport message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Send virtchnl destroy vport message. Returns 0 on success, negative on
- * failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_destroy_vport_msg(struct idpf_vport *vport)
+int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DESTROY_VPORT,
+ };
struct virtchnl2_vport v_id;
- ssize_t reply_sz;
+ int err;
- v_id.vport_id = cpu_to_le32(vport->vport_id);
+ v_id.vport_id = cpu_to_le32(vport_id);
- xn_params.vc_op = VIRTCHNL2_OP_DESTROY_VPORT;
- xn_params.send_buf.iov_base = &v_id;
- xn_params.send_buf.iov_len = sizeof(v_id);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
- return reply_sz < 0 ? reply_sz : 0;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return 0;
}
/**
* idpf_send_enable_vport_msg - Send virtchnl enable vport message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Send enable vport virtchnl message. Returns 0 on success, negative on
- * failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_enable_vport_msg(struct idpf_vport *vport)
+int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_ENABLE_VPORT,
+ };
struct virtchnl2_vport v_id;
- ssize_t reply_sz;
+ int err;
+
+ v_id.vport_id = cpu_to_le32(vport_id);
- v_id.vport_id = cpu_to_le32(vport->vport_id);
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
- xn_params.vc_op = VIRTCHNL2_OP_ENABLE_VPORT;
- xn_params.send_buf.iov_base = &v_id;
- xn_params.send_buf.iov_len = sizeof(v_id);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
* idpf_send_disable_vport_msg - Send virtchnl disable vport message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Send disable vport virtchnl message. Returns 0 on success, negative on
- * failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_disable_vport_msg(struct idpf_vport *vport)
+int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DISABLE_VPORT,
+ };
struct virtchnl2_vport v_id;
- ssize_t reply_sz;
+ int err;
+
+ v_id.vport_id = cpu_to_le32(vport_id);
- v_id.vport_id = cpu_to_le32(vport->vport_id);
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
- xn_params.vc_op = VIRTCHNL2_OP_DISABLE_VPORT;
- xn_params.send_buf.iov_base = &v_id;
- xn_params.send_buf.iov_len = sizeof(v_id);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
* idpf_fill_txq_config_chunk - fill chunk describing the Tx queue
- * @vport: virtual port data structure
+ * @rsrc: pointer to queue and vector resources
* @q: Tx queue to be inserted into VC chunk
* @qi: pointer to the buffer containing the VC chunk
*/
-static void idpf_fill_txq_config_chunk(const struct idpf_vport *vport,
+static void idpf_fill_txq_config_chunk(const struct idpf_q_vec_rsrc *rsrc,
const struct idpf_tx_queue *q,
struct virtchnl2_txq_info *qi)
{
u32 val;
qi->queue_id = cpu_to_le32(q->q_id);
- qi->model = cpu_to_le16(vport->txq_model);
+ qi->model = cpu_to_le16(rsrc->txq_model);
qi->type = cpu_to_le32(VIRTCHNL2_QUEUE_TYPE_TX);
qi->ring_len = cpu_to_le16(q->desc_count);
qi->dma_ring_addr = cpu_to_le64(q->dma);
qi->relative_queue_id = cpu_to_le16(q->rel_q_id);
- if (!idpf_is_queue_model_split(vport->txq_model)) {
+ if (!idpf_is_queue_model_split(rsrc->txq_model)) {
qi->sched_mode = cpu_to_le16(VIRTCHNL2_TXQ_SCHED_MODE_QUEUE);
return;
}
@@ -1726,18 +1364,18 @@ static void idpf_fill_txq_config_chunk(const struct idpf_vport *vport,
/**
* idpf_fill_complq_config_chunk - fill chunk describing the completion queue
- * @vport: virtual port data structure
+ * @rsrc: pointer to queue and vector resources
* @q: completion queue to be inserted into VC chunk
* @qi: pointer to the buffer containing the VC chunk
*/
-static void idpf_fill_complq_config_chunk(const struct idpf_vport *vport,
+static void idpf_fill_complq_config_chunk(const struct idpf_q_vec_rsrc *rsrc,
const struct idpf_compl_queue *q,
struct virtchnl2_txq_info *qi)
{
u32 val;
qi->queue_id = cpu_to_le32(q->q_id);
- qi->model = cpu_to_le16(vport->txq_model);
+ qi->model = cpu_to_le16(rsrc->txq_model);
qi->type = cpu_to_le32(VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION);
qi->ring_len = cpu_to_le16(q->desc_count);
qi->dma_ring_addr = cpu_to_le64(q->dma);
@@ -1752,7 +1390,7 @@ static void idpf_fill_complq_config_chunk(const struct idpf_vport *vport,
/**
* idpf_prepare_cfg_txqs_msg - prepare message to configure selected Tx queues
- * @vport: virtual port data structure
+ * @vport_id: ID of virtual port queues are associated with
* @buf: buffer containing the message
* @pos: pointer to the first chunk describing the tx queue
* @num_chunks: number of chunks in the message
@@ -1762,13 +1400,12 @@ static void idpf_fill_complq_config_chunk(const struct idpf_vport *vport,
*
* Return: the total size of the prepared message.
*/
-static u32 idpf_prepare_cfg_txqs_msg(const struct idpf_vport *vport,
- void *buf, const void *pos,
+static u32 idpf_prepare_cfg_txqs_msg(u32 vport_id, void *buf, const void *pos,
u32 num_chunks)
{
struct virtchnl2_config_tx_queues *ctq = buf;
- ctq->vport_id = cpu_to_le32(vport->vport_id);
+ ctq->vport_id = cpu_to_le32(vport_id);
ctq->num_qinfo = cpu_to_le16(num_chunks);
memcpy(ctq->qinfo, pos, num_chunks * sizeof(*ctq->qinfo));
@@ -1789,13 +1426,14 @@ static int idpf_send_config_tx_queue_set_msg(const struct idpf_queue_set *qs)
{
struct virtchnl2_txq_info *qi __free(kfree) = NULL;
struct idpf_chunked_msg_params params = {
+ .vport_id = qs->vport_id,
.vc_op = VIRTCHNL2_OP_CONFIG_TX_QUEUES,
.prepare_msg = idpf_prepare_cfg_txqs_msg,
.config_sz = sizeof(struct virtchnl2_config_tx_queues),
.chunk_sz = sizeof(*qi),
};
- qi = kcalloc(qs->num, sizeof(*qi), GFP_KERNEL);
+ qi = kzalloc_objs(*qi, qs->num);
if (!qi)
return -ENOMEM;
@@ -1803,43 +1441,47 @@ static int idpf_send_config_tx_queue_set_msg(const struct idpf_queue_set *qs)
for (u32 i = 0; i < qs->num; i++) {
if (qs->qs[i].type == VIRTCHNL2_QUEUE_TYPE_TX)
- idpf_fill_txq_config_chunk(qs->vport, qs->qs[i].txq,
+ idpf_fill_txq_config_chunk(qs->qv_rsrc, qs->qs[i].txq,
&qi[params.num_chunks++]);
else if (qs->qs[i].type == VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION)
- idpf_fill_complq_config_chunk(qs->vport,
+ idpf_fill_complq_config_chunk(qs->qv_rsrc,
qs->qs[i].complq,
&qi[params.num_chunks++]);
}
- return idpf_send_chunked_msg(qs->vport, &params);
+ return idpf_send_chunked_msg(qs->adapter, &params);
}
/**
* idpf_send_config_tx_queues_msg - send virtchnl config Tx queues message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
* Return: 0 on success, -errno on failure.
*/
-static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport)
+static int idpf_send_config_tx_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id)
{
struct idpf_queue_set *qs __free(kfree) = NULL;
- u32 totqs = vport->num_txq + vport->num_complq;
+ u32 totqs = rsrc->num_txq + rsrc->num_complq;
u32 k = 0;
- qs = idpf_alloc_queue_set(vport, totqs);
+ qs = idpf_alloc_queue_set(adapter, rsrc, vport_id, totqs);
if (!qs)
return -ENOMEM;
/* Populate the queue info buffer with all queue context info */
- for (u32 i = 0; i < vport->num_txq_grp; i++) {
- const struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (u32 i = 0; i < rsrc->num_txq_grp; i++) {
+ const struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
for (u32 j = 0; j < tx_qgrp->num_txq; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_TX;
qs->qs[k++].txq = tx_qgrp->txqs[j];
}
- if (idpf_is_queue_model_split(vport->txq_model)) {
+ if (idpf_is_queue_model_split(rsrc->txq_model)) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION;
qs->qs[k++].complq = tx_qgrp->complq;
}
@@ -1854,28 +1496,28 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport)
/**
* idpf_fill_rxq_config_chunk - fill chunk describing the Rx queue
- * @vport: virtual port data structure
+ * @rsrc: pointer to queue and vector resources
* @q: Rx queue to be inserted into VC chunk
* @qi: pointer to the buffer containing the VC chunk
*/
-static void idpf_fill_rxq_config_chunk(const struct idpf_vport *vport,
+static void idpf_fill_rxq_config_chunk(const struct idpf_q_vec_rsrc *rsrc,
struct idpf_rx_queue *q,
struct virtchnl2_rxq_info *qi)
{
const struct idpf_bufq_set *sets;
qi->queue_id = cpu_to_le32(q->q_id);
- qi->model = cpu_to_le16(vport->rxq_model);
+ qi->model = cpu_to_le16(rsrc->rxq_model);
qi->type = cpu_to_le32(VIRTCHNL2_QUEUE_TYPE_RX);
qi->ring_len = cpu_to_le16(q->desc_count);
qi->dma_ring_addr = cpu_to_le64(q->dma);
qi->max_pkt_size = cpu_to_le32(q->rx_max_pkt_size);
qi->rx_buffer_low_watermark = cpu_to_le16(q->rx_buffer_low_watermark);
qi->qflags = cpu_to_le16(VIRTCHNL2_RX_DESC_SIZE_32BYTE);
- if (idpf_is_feature_ena(vport, NETIF_F_GRO_HW))
+ if (idpf_queue_has(RSC_EN, q))
qi->qflags |= cpu_to_le16(VIRTCHNL2_RXQ_RSC);
- if (!idpf_is_queue_model_split(vport->rxq_model)) {
+ if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
qi->data_buffer_size = cpu_to_le32(q->rx_buf_size);
qi->desc_ids = cpu_to_le64(q->rxdids);
@@ -1892,7 +1534,7 @@ static void idpf_fill_rxq_config_chunk(const struct idpf_vport *vport,
qi->data_buffer_size = cpu_to_le32(q->rx_buf_size);
qi->rx_bufq1_id = cpu_to_le16(sets[0].bufq.q_id);
- if (vport->num_bufqs_per_qgrp > IDPF_SINGLE_BUFQ_PER_RXQ_GRP) {
+ if (rsrc->num_bufqs_per_qgrp > IDPF_SINGLE_BUFQ_PER_RXQ_GRP) {
qi->bufq2_ena = IDPF_BUFQ2_ENA;
qi->rx_bufq2_id = cpu_to_le16(sets[1].bufq.q_id);
}
@@ -1909,16 +1551,16 @@ static void idpf_fill_rxq_config_chunk(const struct idpf_vport *vport,
/**
* idpf_fill_bufq_config_chunk - fill chunk describing the buffer queue
- * @vport: virtual port data structure
+ * @rsrc: pointer to queue and vector resources
* @q: buffer queue to be inserted into VC chunk
* @qi: pointer to the buffer containing the VC chunk
*/
-static void idpf_fill_bufq_config_chunk(const struct idpf_vport *vport,
+static void idpf_fill_bufq_config_chunk(const struct idpf_q_vec_rsrc *rsrc,
const struct idpf_buf_queue *q,
struct virtchnl2_rxq_info *qi)
{
qi->queue_id = cpu_to_le32(q->q_id);
- qi->model = cpu_to_le16(vport->rxq_model);
+ qi->model = cpu_to_le16(rsrc->rxq_model);
qi->type = cpu_to_le32(VIRTCHNL2_QUEUE_TYPE_RX_BUFFER);
qi->ring_len = cpu_to_le16(q->desc_count);
qi->dma_ring_addr = cpu_to_le64(q->dma);
@@ -1926,7 +1568,7 @@ static void idpf_fill_bufq_config_chunk(const struct idpf_vport *vport,
qi->rx_buffer_low_watermark = cpu_to_le16(q->rx_buffer_low_watermark);
qi->desc_ids = cpu_to_le64(VIRTCHNL2_RXDID_2_FLEX_SPLITQ_M);
qi->buffer_notif_stride = IDPF_RX_BUF_STRIDE;
- if (idpf_is_feature_ena(vport, NETIF_F_GRO_HW))
+ if (idpf_queue_has(RSC_EN, q))
qi->qflags = cpu_to_le16(VIRTCHNL2_RXQ_RSC);
if (idpf_queue_has(HSPLIT_EN, q)) {
@@ -1937,7 +1579,7 @@ static void idpf_fill_bufq_config_chunk(const struct idpf_vport *vport,
/**
* idpf_prepare_cfg_rxqs_msg - prepare message to configure selected Rx queues
- * @vport: virtual port data structure
+ * @vport_id: ID of virtual port queues are associated with
* @buf: buffer containing the message
* @pos: pointer to the first chunk describing the rx queue
* @num_chunks: number of chunks in the message
@@ -1947,13 +1589,12 @@ static void idpf_fill_bufq_config_chunk(const struct idpf_vport *vport,
*
* Return: the total size of the prepared message.
*/
-static u32 idpf_prepare_cfg_rxqs_msg(const struct idpf_vport *vport,
- void *buf, const void *pos,
+static u32 idpf_prepare_cfg_rxqs_msg(u32 vport_id, void *buf, const void *pos,
u32 num_chunks)
{
struct virtchnl2_config_rx_queues *crq = buf;
- crq->vport_id = cpu_to_le32(vport->vport_id);
+ crq->vport_id = cpu_to_le32(vport_id);
crq->num_qinfo = cpu_to_le16(num_chunks);
memcpy(crq->qinfo, pos, num_chunks * sizeof(*crq->qinfo));
@@ -1974,13 +1615,14 @@ static int idpf_send_config_rx_queue_set_msg(const struct idpf_queue_set *qs)
{
struct virtchnl2_rxq_info *qi __free(kfree) = NULL;
struct idpf_chunked_msg_params params = {
+ .vport_id = qs->vport_id,
.vc_op = VIRTCHNL2_OP_CONFIG_RX_QUEUES,
.prepare_msg = idpf_prepare_cfg_rxqs_msg,
.config_sz = sizeof(struct virtchnl2_config_rx_queues),
.chunk_sz = sizeof(*qi),
};
- qi = kcalloc(qs->num, sizeof(*qi), GFP_KERNEL);
+ qi = kzalloc_objs(*qi, qs->num);
if (!qi)
return -ENOMEM;
@@ -1988,36 +1630,40 @@ static int idpf_send_config_rx_queue_set_msg(const struct idpf_queue_set *qs)
for (u32 i = 0; i < qs->num; i++) {
if (qs->qs[i].type == VIRTCHNL2_QUEUE_TYPE_RX)
- idpf_fill_rxq_config_chunk(qs->vport, qs->qs[i].rxq,
+ idpf_fill_rxq_config_chunk(qs->qv_rsrc, qs->qs[i].rxq,
&qi[params.num_chunks++]);
else if (qs->qs[i].type == VIRTCHNL2_QUEUE_TYPE_RX_BUFFER)
- idpf_fill_bufq_config_chunk(qs->vport, qs->qs[i].bufq,
+ idpf_fill_bufq_config_chunk(qs->qv_rsrc, qs->qs[i].bufq,
&qi[params.num_chunks++]);
}
- return idpf_send_chunked_msg(qs->vport, &params);
+ return idpf_send_chunked_msg(qs->adapter, &params);
}
/**
* idpf_send_config_rx_queues_msg - send virtchnl config Rx queues message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
* Return: 0 on success, -errno on failure.
*/
-static int idpf_send_config_rx_queues_msg(struct idpf_vport *vport)
+static int idpf_send_config_rx_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id)
{
- bool splitq = idpf_is_queue_model_split(vport->rxq_model);
+ bool splitq = idpf_is_queue_model_split(rsrc->rxq_model);
struct idpf_queue_set *qs __free(kfree) = NULL;
- u32 totqs = vport->num_rxq + vport->num_bufq;
+ u32 totqs = rsrc->num_rxq + rsrc->num_bufq;
u32 k = 0;
- qs = idpf_alloc_queue_set(vport, totqs);
+ qs = idpf_alloc_queue_set(adapter, rsrc, vport_id, totqs);
if (!qs)
return -ENOMEM;
/* Populate the queue info buffer with all queue context info */
- for (u32 i = 0; i < vport->num_rxq_grp; i++) {
- const struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (u32 i = 0; i < rsrc->num_rxq_grp; i++) {
+ const struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u32 num_rxq;
if (!splitq) {
@@ -2025,7 +1671,7 @@ static int idpf_send_config_rx_queues_msg(struct idpf_vport *vport)
goto rxq;
}
- for (u32 j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (u32 j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_RX_BUFFER;
qs->qs[k++].bufq = &rx_qgrp->splitq.bufq_sets[j].bufq;
}
@@ -2054,7 +1700,7 @@ rxq:
/**
* idpf_prepare_ena_dis_qs_msg - prepare message to enable/disable selected
* queues
- * @vport: virtual port data structure
+ * @vport_id: ID of virtual port queues are associated with
* @buf: buffer containing the message
* @pos: pointer to the first chunk describing the queue
* @num_chunks: number of chunks in the message
@@ -2064,13 +1710,12 @@ rxq:
*
* Return: the total size of the prepared message.
*/
-static u32 idpf_prepare_ena_dis_qs_msg(const struct idpf_vport *vport,
- void *buf, const void *pos,
+static u32 idpf_prepare_ena_dis_qs_msg(u32 vport_id, void *buf, const void *pos,
u32 num_chunks)
{
struct virtchnl2_del_ena_dis_queues *eq = buf;
- eq->vport_id = cpu_to_le32(vport->vport_id);
+ eq->vport_id = cpu_to_le32(vport_id);
eq->chunks.num_chunks = cpu_to_le16(num_chunks);
memcpy(eq->chunks.chunks, pos,
num_chunks * sizeof(*eq->chunks.chunks));
@@ -2095,6 +1740,7 @@ static int idpf_send_ena_dis_queue_set_msg(const struct idpf_queue_set *qs,
{
struct virtchnl2_queue_chunk *qc __free(kfree) = NULL;
struct idpf_chunked_msg_params params = {
+ .vport_id = qs->vport_id,
.vc_op = en ? VIRTCHNL2_OP_ENABLE_QUEUES :
VIRTCHNL2_OP_DISABLE_QUEUES,
.prepare_msg = idpf_prepare_ena_dis_qs_msg,
@@ -2103,7 +1749,7 @@ static int idpf_send_ena_dis_queue_set_msg(const struct idpf_queue_set *qs,
.num_chunks = qs->num,
};
- qc = kcalloc(qs->num, sizeof(*qc), GFP_KERNEL);
+ qc = kzalloc_objs(*qc, qs->num);
if (!qc)
return -ENOMEM;
@@ -2136,34 +1782,38 @@ static int idpf_send_ena_dis_queue_set_msg(const struct idpf_queue_set *qs,
qc[i].start_queue_id = cpu_to_le32(qid);
}
- return idpf_send_chunked_msg(qs->vport, &params);
+ return idpf_send_chunked_msg(qs->adapter, &params);
}
/**
* idpf_send_ena_dis_queues_msg - send virtchnl enable or disable queues
* message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
* @en: whether to enable or disable queues
*
* Return: 0 on success, -errno on failure.
*/
-static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool en)
+static int idpf_send_ena_dis_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id, bool en)
{
struct idpf_queue_set *qs __free(kfree) = NULL;
u32 num_txq, num_q, k = 0;
bool split;
- num_txq = vport->num_txq + vport->num_complq;
- num_q = num_txq + vport->num_rxq + vport->num_bufq;
+ num_txq = rsrc->num_txq + rsrc->num_complq;
+ num_q = num_txq + rsrc->num_rxq + rsrc->num_bufq;
- qs = idpf_alloc_queue_set(vport, num_q);
+ qs = idpf_alloc_queue_set(adapter, rsrc, vport_id, num_q);
if (!qs)
return -ENOMEM;
- split = idpf_is_queue_model_split(vport->txq_model);
+ split = idpf_is_queue_model_split(rsrc->txq_model);
- for (u32 i = 0; i < vport->num_txq_grp; i++) {
- const struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (u32 i = 0; i < rsrc->num_txq_grp; i++) {
+ const struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
for (u32 j = 0; j < tx_qgrp->num_txq; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_TX;
@@ -2180,10 +1830,10 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool en)
if (k != num_txq)
return -EINVAL;
- split = idpf_is_queue_model_split(vport->rxq_model);
+ split = idpf_is_queue_model_split(rsrc->rxq_model);
- for (u32 i = 0; i < vport->num_rxq_grp; i++) {
- const struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (u32 i = 0; i < rsrc->num_rxq_grp; i++) {
+ const struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u32 num_rxq;
if (split)
@@ -2204,7 +1854,7 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool en)
if (!split)
continue;
- for (u32 j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (u32 j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_RX_BUFFER;
qs->qs[k++].bufq = &rx_qgrp->splitq.bufq_sets[j].bufq;
}
@@ -2219,7 +1869,7 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool en)
/**
* idpf_prep_map_unmap_queue_set_vector_msg - prepare message to map or unmap
* queue set to the interrupt vector
- * @vport: virtual port data structure
+ * @vport_id: ID of virtual port queues are associated with
* @buf: buffer containing the message
* @pos: pointer to the first chunk describing the vector mapping
* @num_chunks: number of chunks in the message
@@ -2230,13 +1880,12 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_vport *vport, bool en)
* Return: the total size of the prepared message.
*/
static u32
-idpf_prep_map_unmap_queue_set_vector_msg(const struct idpf_vport *vport,
- void *buf, const void *pos,
- u32 num_chunks)
+idpf_prep_map_unmap_queue_set_vector_msg(u32 vport_id, void *buf,
+ const void *pos, u32 num_chunks)
{
struct virtchnl2_queue_vector_maps *vqvm = buf;
- vqvm->vport_id = cpu_to_le32(vport->vport_id);
+ vqvm->vport_id = cpu_to_le32(vport_id);
vqvm->num_qv_maps = cpu_to_le16(num_chunks);
memcpy(vqvm->qv_maps, pos, num_chunks * sizeof(*vqvm->qv_maps));
@@ -2257,6 +1906,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
{
struct virtchnl2_queue_vector *vqv __free(kfree) = NULL;
struct idpf_chunked_msg_params params = {
+ .vport_id = qs->vport_id,
.vc_op = map ? VIRTCHNL2_OP_MAP_QUEUE_VECTOR :
VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR,
.prepare_msg = idpf_prep_map_unmap_queue_set_vector_msg,
@@ -2266,13 +1916,13 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
};
bool split;
- vqv = kcalloc(qs->num, sizeof(*vqv), GFP_KERNEL);
+ vqv = kzalloc_objs(*vqv, qs->num);
if (!vqv)
return -ENOMEM;
params.chunks = vqv;
- split = idpf_is_queue_model_split(qs->vport->txq_model);
+ split = idpf_is_queue_model_split(qs->qv_rsrc->txq_model);
for (u32 i = 0; i < qs->num; i++) {
const struct idpf_queue_ptr *q = &qs->qs[i];
@@ -2294,7 +1944,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
v_idx = vec->v_idx;
itr_idx = vec->rx_itr_idx;
} else {
- v_idx = qs->vport->noirq_v_idx;
+ v_idx = qs->qv_rsrc->noirq_v_idx;
itr_idx = VIRTCHNL2_ITR_IDX_0;
}
break;
@@ -2314,7 +1964,7 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
v_idx = vec->v_idx;
itr_idx = vec->tx_itr_idx;
} else {
- v_idx = qs->vport->noirq_v_idx;
+ v_idx = qs->qv_rsrc->noirq_v_idx;
itr_idx = VIRTCHNL2_ITR_IDX_1;
}
break;
@@ -2327,29 +1977,33 @@ idpf_send_map_unmap_queue_set_vector_msg(const struct idpf_queue_set *qs,
vqv[i].itr_idx = cpu_to_le32(itr_idx);
}
- return idpf_send_chunked_msg(qs->vport, &params);
+ return idpf_send_chunked_msg(qs->adapter, &params);
}
/**
* idpf_send_map_unmap_queue_vector_msg - send virtchnl map or unmap queue
* vector message
- * @vport: virtual port data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
* @map: true for map and false for unmap
*
* Return: 0 on success, -errno on failure.
*/
-int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map)
+int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id, bool map)
{
struct idpf_queue_set *qs __free(kfree) = NULL;
- u32 num_q = vport->num_txq + vport->num_rxq;
+ u32 num_q = rsrc->num_txq + rsrc->num_rxq;
u32 k = 0;
- qs = idpf_alloc_queue_set(vport, num_q);
+ qs = idpf_alloc_queue_set(adapter, rsrc, vport_id, num_q);
if (!qs)
return -ENOMEM;
- for (u32 i = 0; i < vport->num_txq_grp; i++) {
- const struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (u32 i = 0; i < rsrc->num_txq_grp; i++) {
+ const struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
for (u32 j = 0; j < tx_qgrp->num_txq; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_TX;
@@ -2357,14 +2011,14 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map)
}
}
- if (k != vport->num_txq)
+ if (k != rsrc->num_txq)
return -EINVAL;
- for (u32 i = 0; i < vport->num_rxq_grp; i++) {
- const struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (u32 i = 0; i < rsrc->num_rxq_grp; i++) {
+ const struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u32 num_rxq;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
num_rxq = rx_qgrp->splitq.num_rxq_sets;
else
num_rxq = rx_qgrp->singleq.num_rxq;
@@ -2372,7 +2026,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map)
for (u32 j = 0; j < num_rxq; j++) {
qs->qs[k].type = VIRTCHNL2_QUEUE_TYPE_RX;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
qs->qs[k++].rxq =
&rx_qgrp->splitq.rxq_sets[j]->rxq;
else
@@ -2448,7 +2102,9 @@ int idpf_send_config_queue_set_msg(const struct idpf_queue_set *qs)
*/
int idpf_send_enable_queues_msg(struct idpf_vport *vport)
{
- return idpf_send_ena_dis_queues_msg(vport, true);
+ return idpf_send_ena_dis_queues_msg(vport->adapter,
+ &vport->dflt_qv_rsrc,
+ vport->vport_id, true);
}
/**
@@ -2462,7 +2118,9 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport)
{
int err;
- err = idpf_send_ena_dis_queues_msg(vport, false);
+ err = idpf_send_ena_dis_queues_msg(vport->adapter,
+ &vport->dflt_qv_rsrc,
+ vport->vport_id, false);
if (err)
return err;
@@ -2477,148 +2135,143 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport)
* @num_chunks: number of chunks to copy
*/
static void idpf_convert_reg_to_queue_chunks(struct virtchnl2_queue_chunk *dchunks,
- struct virtchnl2_queue_reg_chunk *schunks,
+ struct idpf_queue_id_reg_chunk *schunks,
u16 num_chunks)
{
u16 i;
for (i = 0; i < num_chunks; i++) {
- dchunks[i].type = schunks[i].type;
- dchunks[i].start_queue_id = schunks[i].start_queue_id;
- dchunks[i].num_queues = schunks[i].num_queues;
+ dchunks[i].type = cpu_to_le32(schunks[i].type);
+ dchunks[i].start_queue_id = cpu_to_le32(schunks[i].start_queue_id);
+ dchunks[i].num_queues = cpu_to_le32(schunks[i].num_queues);
}
}
/**
* idpf_send_delete_queues_msg - send delete queues virtchnl message
- * @vport: Virtual port private data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @chunks: queue ids received over mailbox
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Will send delete queues virtchnl message. Return 0 on success, negative on
- * failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_delete_queues_msg(struct idpf_vport *vport)
+int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_queue_id_reg_info *chunks,
+ u32 vport_id)
{
- struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL;
- struct virtchnl2_create_vport *vport_params;
- struct virtchnl2_queue_reg_chunks *chunks;
- struct idpf_vc_xn_params xn_params = {};
- struct idpf_vport_config *vport_config;
- u16 vport_idx = vport->idx;
- ssize_t reply_sz;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DEL_QUEUES,
+ };
+ struct virtchnl2_del_ena_dis_queues *eq;
+ ssize_t buf_size;
u16 num_chunks;
- int buf_size;
-
- vport_config = vport->adapter->vport_config[vport_idx];
- if (vport_config->req_qs_chunks) {
- chunks = &vport_config->req_qs_chunks->chunks;
- } else {
- vport_params = vport->adapter->vport_params_recvd[vport_idx];
- chunks = &vport_params->chunks;
- }
+ int err;
- num_chunks = le16_to_cpu(chunks->num_chunks);
+ num_chunks = chunks->num_chunks;
buf_size = struct_size(eq, chunks.chunks, num_chunks);
eq = kzalloc(buf_size, GFP_KERNEL);
if (!eq)
return -ENOMEM;
- eq->vport_id = cpu_to_le32(vport->vport_id);
+ eq->vport_id = cpu_to_le32(vport_id);
eq->chunks.num_chunks = cpu_to_le16(num_chunks);
- idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->chunks,
+ idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->queue_chunks,
num_chunks);
- xn_params.vc_op = VIRTCHNL2_OP_DEL_QUEUES;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = eq;
- xn_params.send_buf.iov_len = buf_size;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, eq, buf_size);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
* idpf_send_config_queues_msg - Send config queues virtchnl message
- * @vport: Virtual port private data structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Will send config queues virtchnl message. Returns 0 on success, negative on
- * failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_config_queues_msg(struct idpf_vport *vport)
+int idpf_send_config_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id)
{
int err;
- err = idpf_send_config_tx_queues_msg(vport);
+ err = idpf_send_config_tx_queues_msg(adapter, rsrc, vport_id);
if (err)
return err;
- return idpf_send_config_rx_queues_msg(vport);
+ return idpf_send_config_rx_queues_msg(adapter, rsrc, vport_id);
}
/**
* idpf_send_add_queues_msg - Send virtchnl add queues message
- * @vport: Virtual port private data structure
- * @num_tx_q: number of transmit queues
- * @num_complq: number of transmit completion queues
- * @num_rx_q: number of receive queues
- * @num_rx_bufq: number of receive buffer queues
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_config: vport persistent structure to store the queue chunk info
+ * @rsrc: pointer to queue and vector resources
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Returns 0 on success, negative on failure. vport _MUST_ be const here as
- * we should not change any fields within vport itself in this function.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
- u16 num_complq, u16 num_rx_q, u16 num_rx_bufq)
+int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_vport_config *vport_config,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id)
{
- struct virtchnl2_add_queues *vc_msg __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
- struct idpf_vport_config *vport_config;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_ADD_QUEUES,
+ };
+ struct virtchnl2_add_queues *vc_msg;
struct virtchnl2_add_queues aq = {};
- u16 vport_idx = vport->idx;
- ssize_t reply_sz;
- int size;
+ size_t size;
+ int err;
- vc_msg = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!vc_msg)
- return -ENOMEM;
+ aq.vport_id = cpu_to_le32(vport_id);
+ aq.num_tx_q = cpu_to_le16(rsrc->num_txq);
+ aq.num_tx_complq = cpu_to_le16(rsrc->num_complq);
+ aq.num_rx_q = cpu_to_le16(rsrc->num_rxq);
+ aq.num_rx_bufq = cpu_to_le16(rsrc->num_bufq);
+
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &aq);
+ if (err)
+ return err;
- vport_config = vport->adapter->vport_config[vport_idx];
- kfree(vport_config->req_qs_chunks);
- vport_config->req_qs_chunks = NULL;
-
- aq.vport_id = cpu_to_le32(vport->vport_id);
- aq.num_tx_q = cpu_to_le16(num_tx_q);
- aq.num_tx_complq = cpu_to_le16(num_complq);
- aq.num_rx_q = cpu_to_le16(num_rx_q);
- aq.num_rx_bufq = cpu_to_le16(num_rx_bufq);
-
- xn_params.vc_op = VIRTCHNL2_OP_ADD_QUEUES;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &aq;
- xn_params.send_buf.iov_len = sizeof(aq);
- xn_params.recv_buf.iov_base = vc_msg;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ vc_msg = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*vc_msg)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
/* compare vc_msg num queues with vport num queues */
- if (le16_to_cpu(vc_msg->num_tx_q) != num_tx_q ||
- le16_to_cpu(vc_msg->num_rx_q) != num_rx_q ||
- le16_to_cpu(vc_msg->num_tx_complq) != num_complq ||
- le16_to_cpu(vc_msg->num_rx_bufq) != num_rx_bufq)
- return -EINVAL;
+ if (le16_to_cpu(vc_msg->num_tx_q) != rsrc->num_txq ||
+ le16_to_cpu(vc_msg->num_rx_q) != rsrc->num_rxq ||
+ le16_to_cpu(vc_msg->num_tx_complq) != rsrc->num_complq ||
+ le16_to_cpu(vc_msg->num_rx_bufq) != rsrc->num_bufq) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
size = struct_size(vc_msg, chunks.chunks,
le16_to_cpu(vc_msg->chunks.num_chunks));
- if (reply_sz < size)
- return -EIO;
+ if (xn_params.recv_mem.iov_len < size) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- vport_config->req_qs_chunks = kmemdup(vc_msg, size, GFP_KERNEL);
- if (!vport_config->req_qs_chunks)
- return -ENOMEM;
+ err = idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
- return 0;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
}
/**
@@ -2630,49 +2283,51 @@ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
*/
int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
{
- struct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_ALLOC_VECTORS,
+ };
+ struct virtchnl2_alloc_vectors *rcvd_vec;
struct virtchnl2_alloc_vectors ac = {};
- ssize_t reply_sz;
u16 num_vchunks;
- int size;
+ int size, err;
ac.num_vectors = cpu_to_le16(num_vectors);
- rcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcvd_vec)
- return -ENOMEM;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &ac);
+ if (err)
+ return err;
- xn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS;
- xn_params.send_buf.iov_base = &ac;
- xn_params.send_buf.iov_len = sizeof(ac);
- xn_params.recv_buf.iov_base = rcvd_vec;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ rcvd_vec = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*rcvd_vec)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks);
size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);
- if (reply_sz < size)
- return -EIO;
-
- if (size > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
+ if (xn_params.recv_mem.iov_len < size) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = kmemdup(rcvd_vec, size, GFP_KERNEL);
- if (!adapter->req_vec_chunks)
- return -ENOMEM;
+ if (!adapter->req_vec_chunks) {
+ err = -ENOMEM;
+ goto free_rx_buf;
+ }
if (le16_to_cpu(adapter->req_vec_chunks->num_vectors) < num_vectors) {
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = NULL;
- return -EINVAL;
+ err = -EINVAL;
}
- return 0;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
}
/**
@@ -2684,24 +2339,28 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
{
struct virtchnl2_alloc_vectors *ac = adapter->req_vec_chunks;
- struct virtchnl2_vector_chunks *vcs = &ac->vchunks;
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
- int buf_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DEALLOC_VECTORS,
+ };
+ struct virtchnl2_vector_chunks *vcs;
+ int buf_size, err;
- buf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs->num_vchunks));
+ buf_size = struct_size(&ac->vchunks, vchunks,
+ le16_to_cpu(ac->vchunks.num_vchunks));
+ vcs = kmemdup(&ac->vchunks, buf_size, GFP_KERNEL);
+ if (!vcs)
+ return -ENOMEM;
- xn_params.vc_op = VIRTCHNL2_OP_DEALLOC_VECTORS;
- xn_params.send_buf.iov_base = vcs;
- xn_params.send_buf.iov_len = buf_size;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, vcs, buf_size);
+ if (err)
+ return err;
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = NULL;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
return 0;
}
@@ -2725,223 +2384,170 @@ static int idpf_get_max_vfs(struct idpf_adapter *adapter)
*/
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)
{
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_SET_SRIOV_VFS,
+ };
struct virtchnl2_sriov_vfs_info svi = {};
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ int err;
svi.num_vfs = cpu_to_le16(num_vfs);
- xn_params.vc_op = VIRTCHNL2_OP_SET_SRIOV_VFS;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &svi;
- xn_params.send_buf.iov_len = sizeof(svi);
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- return reply_sz < 0 ? reply_sz : 0;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &svi);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return 0;
}
/**
* idpf_send_get_stats_msg - Send virtchnl get statistics message
- * @vport: vport to get stats for
+ * @np: netdev private structure
+ * @port_stats: structure to store the vport statistics
*
- * Returns 0 on success, negative on failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_get_stats_msg(struct idpf_vport *vport)
+int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,
+ struct idpf_port_stats *port_stats)
{
- struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_GET_STATS,
+ };
struct rtnl_link_stats64 *netstats = &np->netstats;
+ struct virtchnl2_vport_stats *stats_recv;
struct virtchnl2_vport_stats stats_msg = {};
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ int err;
/* Don't send get_stats message if the link is down */
if (!test_bit(IDPF_VPORT_UP, np->state))
return 0;
- stats_msg.vport_id = cpu_to_le32(vport->vport_id);
+ stats_msg.vport_id = cpu_to_le32(np->vport_id);
- xn_params.vc_op = VIRTCHNL2_OP_GET_STATS;
- xn_params.send_buf.iov_base = &stats_msg;
- xn_params.send_buf.iov_len = sizeof(stats_msg);
- xn_params.recv_buf = xn_params.send_buf;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ err = idpf_send_mb_msg_stack(np->adapter, &xn_params, &stats_msg);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len < sizeof(*stats_recv)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz < sizeof(stats_msg))
- return -EIO;
+ stats_recv = xn_params.recv_mem.iov_base;
spin_lock_bh(&np->stats_lock);
- netstats->rx_packets = le64_to_cpu(stats_msg.rx_unicast) +
- le64_to_cpu(stats_msg.rx_multicast) +
- le64_to_cpu(stats_msg.rx_broadcast);
- netstats->tx_packets = le64_to_cpu(stats_msg.tx_unicast) +
- le64_to_cpu(stats_msg.tx_multicast) +
- le64_to_cpu(stats_msg.tx_broadcast);
- netstats->rx_bytes = le64_to_cpu(stats_msg.rx_bytes);
- netstats->tx_bytes = le64_to_cpu(stats_msg.tx_bytes);
- netstats->rx_errors = le64_to_cpu(stats_msg.rx_errors);
- netstats->tx_errors = le64_to_cpu(stats_msg.tx_errors);
- netstats->rx_dropped = le64_to_cpu(stats_msg.rx_discards);
- netstats->tx_dropped = le64_to_cpu(stats_msg.tx_discards);
-
- vport->port_stats.vport_stats = stats_msg;
+ netstats->rx_packets = le64_to_cpu(stats_recv->rx_unicast) +
+ le64_to_cpu(stats_recv->rx_multicast) +
+ le64_to_cpu(stats_recv->rx_broadcast);
+ netstats->tx_packets = le64_to_cpu(stats_recv->tx_unicast) +
+ le64_to_cpu(stats_recv->tx_multicast) +
+ le64_to_cpu(stats_recv->tx_broadcast);
+ netstats->rx_bytes = le64_to_cpu(stats_recv->rx_bytes);
+ netstats->tx_bytes = le64_to_cpu(stats_recv->tx_bytes);
+ netstats->rx_errors = le64_to_cpu(stats_recv->rx_errors);
+ netstats->tx_errors = le64_to_cpu(stats_recv->tx_errors);
+ netstats->rx_dropped = le64_to_cpu(stats_recv->rx_discards);
+ netstats->tx_dropped = le64_to_cpu(stats_recv->tx_discards);
+
+ port_stats->vport_stats = *stats_recv;
spin_unlock_bh(&np->stats_lock);
- return 0;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
}
/**
- * idpf_send_get_set_rss_lut_msg - Send virtchnl get or set rss lut message
- * @vport: virtual port data structure
- * @get: flag to set or get rss look up table
+ * idpf_send_set_rss_lut_msg - Send virtchnl set RSS lut message
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rss_data: pointer to RSS key and lut info
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Returns 0 on success, negative on failure.
+ * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash
+ * is enabled, the LUT values stored in driver's soft copy will be used to setup
+ * the HW.
+ *
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id)
{
- struct virtchnl2_rss_lut *recv_rl __free(kfree) = NULL;
- struct virtchnl2_rss_lut *rl __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
- struct idpf_rss_data *rss_data;
- int buf_size, lut_buf_size;
- ssize_t reply_sz;
- int i;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_SET_RSS_LUT,
+ };
+ struct virtchnl2_rss_lut *rl;
+ struct idpf_vport *vport;
+ int buf_size, i, err;
+ bool rxhash_ena;
+
+ vport = idpf_vid_to_vport(adapter, vport_id);
+ if (!vport)
+ return -EINVAL;
+
+ rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH);
- rss_data =
- &vport->adapter->vport_config[vport->idx]->user_config.rss_data;
buf_size = struct_size(rl, lut, rss_data->rss_lut_size);
rl = kzalloc(buf_size, GFP_KERNEL);
if (!rl)
return -ENOMEM;
- rl->vport_id = cpu_to_le32(vport->vport_id);
-
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = rl;
- xn_params.send_buf.iov_len = buf_size;
-
- if (get) {
- recv_rl = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!recv_rl)
- return -ENOMEM;
- xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_LUT;
- xn_params.recv_buf.iov_base = recv_rl;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- } else {
- rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
- for (i = 0; i < rss_data->rss_lut_size; i++)
- rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]);
-
- xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT;
- }
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (!get)
- return 0;
- if (reply_sz < sizeof(struct virtchnl2_rss_lut))
- return -EIO;
-
- lut_buf_size = le16_to_cpu(recv_rl->lut_entries) * sizeof(u32);
- if (reply_sz < lut_buf_size)
- return -EIO;
-
- /* size didn't change, we can reuse existing lut buf */
- if (rss_data->rss_lut_size == le16_to_cpu(recv_rl->lut_entries))
- goto do_memcpy;
+ rl->vport_id = cpu_to_le32(vport_id);
+ rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
+ for (i = 0; i < rss_data->rss_lut_size; i++)
+ rl->lut[i] = rxhash_ena ? cpu_to_le32(rss_data->rss_lut[i]) : 0;
- rss_data->rss_lut_size = le16_to_cpu(recv_rl->lut_entries);
- kfree(rss_data->rss_lut);
-
- rss_data->rss_lut = kzalloc(lut_buf_size, GFP_KERNEL);
- if (!rss_data->rss_lut) {
- rss_data->rss_lut_size = 0;
- return -ENOMEM;
- }
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rl, buf_size);
+ if (err)
+ return err;
-do_memcpy:
- memcpy(rss_data->rss_lut, recv_rl->lut, rss_data->rss_lut_size);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
- * idpf_send_get_set_rss_key_msg - Send virtchnl get or set rss key message
- * @vport: virtual port data structure
- * @get: flag to set or get rss look up table
+ * idpf_send_set_rss_key_msg - Send virtchnl set RSS key message
+ * @adapter: adapter pointer used to send virtchnl message
+ * @rss_data: pointer to RSS key and lut info
+ * @vport_id: vport identifier used while preparing the virtchnl message
*
- * Returns 0 on success, negative on failure
+ * Return: 0 on success, negative on failure
*/
-int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get)
+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id)
{
- struct virtchnl2_rss_key *recv_rk __free(kfree) = NULL;
- struct virtchnl2_rss_key *rk __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
- struct idpf_rss_data *rss_data;
- ssize_t reply_sz;
- int i, buf_size;
- u16 key_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_SET_RSS_KEY,
+ };
+ struct virtchnl2_rss_key *rk;
+ int i, buf_size, err;
- rss_data =
- &vport->adapter->vport_config[vport->idx]->user_config.rss_data;
buf_size = struct_size(rk, key_flex, rss_data->rss_key_size);
rk = kzalloc(buf_size, GFP_KERNEL);
if (!rk)
return -ENOMEM;
- rk->vport_id = cpu_to_le32(vport->vport_id);
- xn_params.send_buf.iov_base = rk;
- xn_params.send_buf.iov_len = buf_size;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- if (get) {
- recv_rk = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!recv_rk)
- return -ENOMEM;
-
- xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_KEY;
- xn_params.recv_buf.iov_base = recv_rk;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- } else {
- rk->key_len = cpu_to_le16(rss_data->rss_key_size);
- for (i = 0; i < rss_data->rss_key_size; i++)
- rk->key_flex[i] = rss_data->rss_key[i];
-
- xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_KEY;
- }
+ rk->vport_id = cpu_to_le32(vport_id);
+ rk->key_len = cpu_to_le16(rss_data->rss_key_size);
+ for (i = 0; i < rss_data->rss_key_size; i++)
+ rk->key_flex[i] = rss_data->rss_key[i];
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (!get)
- return 0;
- if (reply_sz < sizeof(struct virtchnl2_rss_key))
- return -EIO;
-
- key_size = min_t(u16, NETDEV_RSS_KEY_LEN,
- le16_to_cpu(recv_rk->key_len));
- if (reply_sz < key_size)
- return -EIO;
-
- /* key len didn't change, reuse existing buf */
- if (rss_data->rss_key_size == key_size)
- goto do_memcpy;
-
- rss_data->rss_key_size = key_size;
- kfree(rss_data->rss_key);
- rss_data->rss_key = kzalloc(key_size, GFP_KERNEL);
- if (!rss_data->rss_key) {
- rss_data->rss_key_size = 0;
- return -ENOMEM;
- }
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rk, buf_size);
+ if (err)
+ return err;
-do_memcpy:
- memcpy(rss_data->rss_key, recv_rk->key_flex, rss_data->rss_key_size);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -2999,264 +2605,288 @@ static void idpf_finalize_ptype_lookup(struct libeth_rx_pt *ptype)
}
/**
+ * idpf_parse_protocol_ids - parse protocol IDs for a given packet type
+ * @ptype: packet type to parse
+ * @rx_pt: store the parsed packet type info into
+ */
+static void idpf_parse_protocol_ids(struct virtchnl2_ptype *ptype,
+ struct libeth_rx_pt *rx_pt)
+{
+ struct idpf_ptype_state pstate = {};
+
+ for (u32 j = 0; j < ptype->proto_id_count; j++) {
+ u16 id = le16_to_cpu(ptype->proto_id[j]);
+
+ switch (id) {
+ case VIRTCHNL2_PROTO_HDR_GRE:
+ if (pstate.tunnel_state == IDPF_PTYPE_TUNNEL_IP) {
+ rx_pt->tunnel_type =
+ LIBETH_RX_PT_TUNNEL_IP_GRENAT;
+ pstate.tunnel_state |=
+ IDPF_PTYPE_TUNNEL_IP_GRENAT;
+ }
+ break;
+ case VIRTCHNL2_PROTO_HDR_MAC:
+ rx_pt->outer_ip = LIBETH_RX_PT_OUTER_L2;
+ if (pstate.tunnel_state == IDPF_TUN_IP_GRE) {
+ rx_pt->tunnel_type =
+ LIBETH_RX_PT_TUNNEL_IP_GRENAT_MAC;
+ pstate.tunnel_state |=
+ IDPF_PTYPE_TUNNEL_IP_GRENAT_MAC;
+ }
+ break;
+ case VIRTCHNL2_PROTO_HDR_IPV4:
+ idpf_fill_ptype_lookup(rx_pt, &pstate, true, false);
+ break;
+ case VIRTCHNL2_PROTO_HDR_IPV6:
+ idpf_fill_ptype_lookup(rx_pt, &pstate, false, false);
+ break;
+ case VIRTCHNL2_PROTO_HDR_IPV4_FRAG:
+ idpf_fill_ptype_lookup(rx_pt, &pstate, true, true);
+ break;
+ case VIRTCHNL2_PROTO_HDR_IPV6_FRAG:
+ idpf_fill_ptype_lookup(rx_pt, &pstate, false, true);
+ break;
+ case VIRTCHNL2_PROTO_HDR_UDP:
+ rx_pt->inner_prot = LIBETH_RX_PT_INNER_UDP;
+ break;
+ case VIRTCHNL2_PROTO_HDR_TCP:
+ rx_pt->inner_prot = LIBETH_RX_PT_INNER_TCP;
+ break;
+ case VIRTCHNL2_PROTO_HDR_SCTP:
+ rx_pt->inner_prot = LIBETH_RX_PT_INNER_SCTP;
+ break;
+ case VIRTCHNL2_PROTO_HDR_ICMP:
+ rx_pt->inner_prot = LIBETH_RX_PT_INNER_ICMP;
+ break;
+ case VIRTCHNL2_PROTO_HDR_PAY:
+ rx_pt->payload_layer = LIBETH_RX_PT_PAYLOAD_L2;
+ break;
+ case VIRTCHNL2_PROTO_HDR_ICMPV6:
+ case VIRTCHNL2_PROTO_HDR_IPV6_EH:
+ case VIRTCHNL2_PROTO_HDR_PRE_MAC:
+ case VIRTCHNL2_PROTO_HDR_POST_MAC:
+ case VIRTCHNL2_PROTO_HDR_ETHERTYPE:
+ case VIRTCHNL2_PROTO_HDR_SVLAN:
+ case VIRTCHNL2_PROTO_HDR_CVLAN:
+ case VIRTCHNL2_PROTO_HDR_MPLS:
+ case VIRTCHNL2_PROTO_HDR_MMPLS:
+ case VIRTCHNL2_PROTO_HDR_PTP:
+ case VIRTCHNL2_PROTO_HDR_CTRL:
+ case VIRTCHNL2_PROTO_HDR_LLDP:
+ case VIRTCHNL2_PROTO_HDR_ARP:
+ case VIRTCHNL2_PROTO_HDR_ECP:
+ case VIRTCHNL2_PROTO_HDR_EAPOL:
+ case VIRTCHNL2_PROTO_HDR_PPPOD:
+ case VIRTCHNL2_PROTO_HDR_PPPOE:
+ case VIRTCHNL2_PROTO_HDR_IGMP:
+ case VIRTCHNL2_PROTO_HDR_AH:
+ case VIRTCHNL2_PROTO_HDR_ESP:
+ case VIRTCHNL2_PROTO_HDR_IKE:
+ case VIRTCHNL2_PROTO_HDR_NATT_KEEP:
+ case VIRTCHNL2_PROTO_HDR_L2TPV2:
+ case VIRTCHNL2_PROTO_HDR_L2TPV2_CONTROL:
+ case VIRTCHNL2_PROTO_HDR_L2TPV3:
+ case VIRTCHNL2_PROTO_HDR_GTP:
+ case VIRTCHNL2_PROTO_HDR_GTP_EH:
+ case VIRTCHNL2_PROTO_HDR_GTPCV2:
+ case VIRTCHNL2_PROTO_HDR_GTPC_TEID:
+ case VIRTCHNL2_PROTO_HDR_GTPU:
+ case VIRTCHNL2_PROTO_HDR_GTPU_UL:
+ case VIRTCHNL2_PROTO_HDR_GTPU_DL:
+ case VIRTCHNL2_PROTO_HDR_ECPRI:
+ case VIRTCHNL2_PROTO_HDR_VRRP:
+ case VIRTCHNL2_PROTO_HDR_OSPF:
+ case VIRTCHNL2_PROTO_HDR_TUN:
+ case VIRTCHNL2_PROTO_HDR_NVGRE:
+ case VIRTCHNL2_PROTO_HDR_VXLAN:
+ case VIRTCHNL2_PROTO_HDR_VXLAN_GPE:
+ case VIRTCHNL2_PROTO_HDR_GENEVE:
+ case VIRTCHNL2_PROTO_HDR_NSH:
+ case VIRTCHNL2_PROTO_HDR_QUIC:
+ case VIRTCHNL2_PROTO_HDR_PFCP:
+ case VIRTCHNL2_PROTO_HDR_PFCP_NODE:
+ case VIRTCHNL2_PROTO_HDR_PFCP_SESSION:
+ case VIRTCHNL2_PROTO_HDR_RTP:
+ case VIRTCHNL2_PROTO_HDR_NO_PROTO:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
* idpf_send_get_rx_ptype_msg - Send virtchnl for ptype info
- * @vport: virtual port data structure
+ * @adapter: driver specific private structure
*
- * Returns 0 on success, negative on failure.
+ * Return: 0 on success, negative on failure.
*/
-int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport)
+static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
{
- struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;
- struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;
- struct libeth_rx_pt *ptype_lkup __free(kfree) = NULL;
- int max_ptype, ptypes_recvd = 0, ptype_offset;
- struct idpf_adapter *adapter = vport->adapter;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_GET_PTYPE_INFO,
+ };
+ struct virtchnl2_get_ptype_info *get_ptype_info;
+ struct virtchnl2_get_ptype_info *ptype_info;
+ int err = 0, max_ptype = IDPF_RX_MAX_PTYPE;
+ int buf_size = sizeof(*get_ptype_info);
+ struct libeth_rx_pt *singleq_pt_lkup;
+ struct libeth_rx_pt *splitq_pt_lkup;
+ int ptypes_recvd = 0, ptype_offset;
u16 next_ptype_id = 0;
- ssize_t reply_sz;
- int i, j, k;
- if (vport->rx_ptype_lkup)
- return 0;
-
- if (idpf_is_queue_model_split(vport->rxq_model))
- max_ptype = IDPF_RX_MAX_PTYPE;
- else
- max_ptype = IDPF_RX_MAX_BASE_PTYPE;
-
- ptype_lkup = kcalloc(max_ptype, sizeof(*ptype_lkup), GFP_KERNEL);
- if (!ptype_lkup)
+ singleq_pt_lkup = kzalloc_objs(*singleq_pt_lkup, IDPF_RX_MAX_BASE_PTYPE);
+ if (!singleq_pt_lkup)
return -ENOMEM;
- get_ptype_info = kzalloc(sizeof(*get_ptype_info), GFP_KERNEL);
- if (!get_ptype_info)
- return -ENOMEM;
+ splitq_pt_lkup = kzalloc_objs(*splitq_pt_lkup, max_ptype);
+ if (!splitq_pt_lkup) {
+ err = -ENOMEM;
+ goto free_singleq;
+ }
- ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!ptype_info)
- return -ENOMEM;
+ while (next_ptype_id < max_ptype) {
+ u16 num_ptypes;
- xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;
- xn_params.send_buf.iov_base = get_ptype_info;
- xn_params.send_buf.iov_len = sizeof(*get_ptype_info);
- xn_params.recv_buf.iov_base = ptype_info;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ get_ptype_info = kzalloc(buf_size, GFP_KERNEL);
+ if (!get_ptype_info) {
+ err = -ENOMEM;
+ goto free_splitq;
+ }
- while (next_ptype_id < max_ptype) {
get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);
if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
- get_ptype_info->num_ptypes =
- cpu_to_le16(max_ptype - next_ptype_id);
+ num_ptypes = max_ptype - next_ptype_id;
else
- get_ptype_info->num_ptypes =
- cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);
-
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
-
+ num_ptypes = IDPF_RX_MAX_PTYPES_PER_BUF;
+
+ get_ptype_info->num_ptypes = cpu_to_le16(num_ptypes);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params,
+ get_ptype_info, buf_size);
+ if (err)
+ goto free_splitq;
+
+ ptype_info = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*ptype_info)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
- if (ptypes_recvd > max_ptype)
- return -EINVAL;
-
- next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
- le16_to_cpu(get_ptype_info->num_ptypes);
+ if (ptypes_recvd > max_ptype) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
+ next_ptype_id = next_ptype_id + num_ptypes;
ptype_offset = IDPF_RX_PTYPE_HDR_SZ;
- for (i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
- struct idpf_ptype_state pstate = { };
+ for (u16 i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
+ struct libeth_rx_pt rx_pt = {};
struct virtchnl2_ptype *ptype;
- u16 id;
+ u16 pt_10, pt_8;
ptype = (struct virtchnl2_ptype *)
((u8 *)ptype_info + ptype_offset);
+ if (xn_params.recv_mem.iov_len <
+ ptype_offset + sizeof(struct virtchnl2_ptype)) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
+
+ pt_10 = le16_to_cpu(ptype->ptype_id_10);
+ pt_8 = ptype->ptype_id_8;
ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
- if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
+ if (xn_params.recv_mem.iov_len < ptype_offset) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
/* 0xFFFF indicates end of ptypes */
- if (le16_to_cpu(ptype->ptype_id_10) ==
- IDPF_INVALID_PTYPE_ID)
+ if (pt_10 == IDPF_INVALID_PTYPE_ID)
goto out;
-
- if (idpf_is_queue_model_split(vport->rxq_model))
- k = le16_to_cpu(ptype->ptype_id_10);
- else
- k = ptype->ptype_id_8;
-
- for (j = 0; j < ptype->proto_id_count; j++) {
- id = le16_to_cpu(ptype->proto_id[j]);
- switch (id) {
- case VIRTCHNL2_PROTO_HDR_GRE:
- if (pstate.tunnel_state ==
- IDPF_PTYPE_TUNNEL_IP) {
- ptype_lkup[k].tunnel_type =
- LIBETH_RX_PT_TUNNEL_IP_GRENAT;
- pstate.tunnel_state |=
- IDPF_PTYPE_TUNNEL_IP_GRENAT;
- }
- break;
- case VIRTCHNL2_PROTO_HDR_MAC:
- ptype_lkup[k].outer_ip =
- LIBETH_RX_PT_OUTER_L2;
- if (pstate.tunnel_state ==
- IDPF_TUN_IP_GRE) {
- ptype_lkup[k].tunnel_type =
- LIBETH_RX_PT_TUNNEL_IP_GRENAT_MAC;
- pstate.tunnel_state |=
- IDPF_PTYPE_TUNNEL_IP_GRENAT_MAC;
- }
- break;
- case VIRTCHNL2_PROTO_HDR_IPV4:
- idpf_fill_ptype_lookup(&ptype_lkup[k],
- &pstate, true,
- false);
- break;
- case VIRTCHNL2_PROTO_HDR_IPV6:
- idpf_fill_ptype_lookup(&ptype_lkup[k],
- &pstate, false,
- false);
- break;
- case VIRTCHNL2_PROTO_HDR_IPV4_FRAG:
- idpf_fill_ptype_lookup(&ptype_lkup[k],
- &pstate, true,
- true);
- break;
- case VIRTCHNL2_PROTO_HDR_IPV6_FRAG:
- idpf_fill_ptype_lookup(&ptype_lkup[k],
- &pstate, false,
- true);
- break;
- case VIRTCHNL2_PROTO_HDR_UDP:
- ptype_lkup[k].inner_prot =
- LIBETH_RX_PT_INNER_UDP;
- break;
- case VIRTCHNL2_PROTO_HDR_TCP:
- ptype_lkup[k].inner_prot =
- LIBETH_RX_PT_INNER_TCP;
- break;
- case VIRTCHNL2_PROTO_HDR_SCTP:
- ptype_lkup[k].inner_prot =
- LIBETH_RX_PT_INNER_SCTP;
- break;
- case VIRTCHNL2_PROTO_HDR_ICMP:
- ptype_lkup[k].inner_prot =
- LIBETH_RX_PT_INNER_ICMP;
- break;
- case VIRTCHNL2_PROTO_HDR_PAY:
- ptype_lkup[k].payload_layer =
- LIBETH_RX_PT_PAYLOAD_L2;
- break;
- case VIRTCHNL2_PROTO_HDR_ICMPV6:
- case VIRTCHNL2_PROTO_HDR_IPV6_EH:
- case VIRTCHNL2_PROTO_HDR_PRE_MAC:
- case VIRTCHNL2_PROTO_HDR_POST_MAC:
- case VIRTCHNL2_PROTO_HDR_ETHERTYPE:
- case VIRTCHNL2_PROTO_HDR_SVLAN:
- case VIRTCHNL2_PROTO_HDR_CVLAN:
- case VIRTCHNL2_PROTO_HDR_MPLS:
- case VIRTCHNL2_PROTO_HDR_MMPLS:
- case VIRTCHNL2_PROTO_HDR_PTP:
- case VIRTCHNL2_PROTO_HDR_CTRL:
- case VIRTCHNL2_PROTO_HDR_LLDP:
- case VIRTCHNL2_PROTO_HDR_ARP:
- case VIRTCHNL2_PROTO_HDR_ECP:
- case VIRTCHNL2_PROTO_HDR_EAPOL:
- case VIRTCHNL2_PROTO_HDR_PPPOD:
- case VIRTCHNL2_PROTO_HDR_PPPOE:
- case VIRTCHNL2_PROTO_HDR_IGMP:
- case VIRTCHNL2_PROTO_HDR_AH:
- case VIRTCHNL2_PROTO_HDR_ESP:
- case VIRTCHNL2_PROTO_HDR_IKE:
- case VIRTCHNL2_PROTO_HDR_NATT_KEEP:
- case VIRTCHNL2_PROTO_HDR_L2TPV2:
- case VIRTCHNL2_PROTO_HDR_L2TPV2_CONTROL:
- case VIRTCHNL2_PROTO_HDR_L2TPV3:
- case VIRTCHNL2_PROTO_HDR_GTP:
- case VIRTCHNL2_PROTO_HDR_GTP_EH:
- case VIRTCHNL2_PROTO_HDR_GTPCV2:
- case VIRTCHNL2_PROTO_HDR_GTPC_TEID:
- case VIRTCHNL2_PROTO_HDR_GTPU:
- case VIRTCHNL2_PROTO_HDR_GTPU_UL:
- case VIRTCHNL2_PROTO_HDR_GTPU_DL:
- case VIRTCHNL2_PROTO_HDR_ECPRI:
- case VIRTCHNL2_PROTO_HDR_VRRP:
- case VIRTCHNL2_PROTO_HDR_OSPF:
- case VIRTCHNL2_PROTO_HDR_TUN:
- case VIRTCHNL2_PROTO_HDR_NVGRE:
- case VIRTCHNL2_PROTO_HDR_VXLAN:
- case VIRTCHNL2_PROTO_HDR_VXLAN_GPE:
- case VIRTCHNL2_PROTO_HDR_GENEVE:
- case VIRTCHNL2_PROTO_HDR_NSH:
- case VIRTCHNL2_PROTO_HDR_QUIC:
- case VIRTCHNL2_PROTO_HDR_PFCP:
- case VIRTCHNL2_PROTO_HDR_PFCP_NODE:
- case VIRTCHNL2_PROTO_HDR_PFCP_SESSION:
- case VIRTCHNL2_PROTO_HDR_RTP:
- case VIRTCHNL2_PROTO_HDR_NO_PROTO:
- break;
- default:
- break;
- }
+ if (pt_10 >= max_ptype) {
+ err = -EINVAL;
+ goto free_rx_buf;
}
- idpf_finalize_ptype_lookup(&ptype_lkup[k]);
+ idpf_parse_protocol_ids(ptype, &rx_pt);
+ idpf_finalize_ptype_lookup(&rx_pt);
+
+ /* For a given protocol ID stack, the ptype value might
+ * vary between ptype_id_10 and ptype_id_8. So store
+ * them separately for splitq and singleq. Also skip
+ * the repeated ptypes in case of singleq.
+ */
+ splitq_pt_lkup[pt_10] = rx_pt;
+ if (!singleq_pt_lkup[pt_8].outer_ip)
+ singleq_pt_lkup[pt_8] = rx_pt;
}
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ xn_params.recv_mem = (struct kvec) {};
}
out:
- vport->rx_ptype_lkup = no_free_ptr(ptype_lkup);
+ adapter->splitq_pt_lkup = splitq_pt_lkup;
+ adapter->singleq_pt_lkup = singleq_pt_lkup;
+ splitq_pt_lkup = NULL;
+ singleq_pt_lkup = NULL;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+free_splitq:
+ kfree(splitq_pt_lkup);
+free_singleq:
+ kfree(singleq_pt_lkup);
- return 0;
+ return err;
}
/**
- * idpf_send_ena_dis_loopback_msg - Send virtchnl enable/disable loopback
- * message
- * @vport: virtual port data structure
- *
- * Returns 0 on success, negative on failure.
+ * idpf_rel_rx_pt_lkup - release RX ptype lookup table
+ * @adapter: adapter pointer to get the lookup table
*/
-int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport)
+static void idpf_rel_rx_pt_lkup(struct idpf_adapter *adapter)
{
- struct idpf_vc_xn_params xn_params = {};
- struct virtchnl2_loopback loopback;
- ssize_t reply_sz;
-
- loopback.vport_id = cpu_to_le32(vport->vport_id);
- loopback.enable = idpf_is_feature_ena(vport, NETIF_F_LOOPBACK);
-
- xn_params.vc_op = VIRTCHNL2_OP_LOOPBACK;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &loopback;
- xn_params.send_buf.iov_len = sizeof(loopback);
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
+ kfree(adapter->splitq_pt_lkup);
+ adapter->splitq_pt_lkup = NULL;
- return reply_sz < 0 ? reply_sz : 0;
+ kfree(adapter->singleq_pt_lkup);
+ adapter->singleq_pt_lkup = NULL;
}
/**
- * idpf_find_ctlq - Given a type and id, find ctlq info
- * @hw: hardware struct
- * @type: type of ctrlq to find
- * @id: ctlq id to find
+ * idpf_send_ena_dis_loopback_msg - Send virtchnl enable/disable loopback
+ * message
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_id: vport identifier used while preparing the virtchnl message
+ * @loopback_ena: flag to enable or disable loopback
*
- * Returns pointer to found ctlq info struct, NULL otherwise.
+ * Return: 0 on success, negative on failure.
*/
-static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
- enum idpf_ctlq_type type, int id)
+int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
+ bool loopback_ena)
{
- struct idpf_ctlq_info *cq, *tmp;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_LOOPBACK,
+ };
+ struct virtchnl2_loopback loopback;
+ int err;
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- if (cq->q_id == id && cq->cq_type == type)
- return cq;
+ loopback.vport_id = cpu_to_le32(vport_id);
+ loopback.enable = loopback_ena;
- return NULL;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &loopback);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return 0;
}
/**
@@ -3267,42 +2897,49 @@ static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
*/
int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
{
- struct idpf_ctlq_create_info ctlq_info[] = {
+ struct libie_ctlq_ctx *ctx = &adapter->ctlq_ctx;
+ struct libie_ctlq_create_info ctlq_info[] = {
{
- .type = IDPF_CTLQ_TYPE_MAILBOX_TX,
- .id = IDPF_DFLT_MBX_ID,
+ .type = LIBIE_CTLQ_TYPE_TX,
+ .id = LIBIE_CTLQ_MBX_ID,
.len = IDPF_DFLT_MBX_Q_LEN,
- .buf_size = IDPF_CTLQ_MAX_BUF_LEN
},
{
- .type = IDPF_CTLQ_TYPE_MAILBOX_RX,
- .id = IDPF_DFLT_MBX_ID,
+ .type = LIBIE_CTLQ_TYPE_RX,
+ .id = LIBIE_CTLQ_MBX_ID,
.len = IDPF_DFLT_MBX_Q_LEN,
- .buf_size = IDPF_CTLQ_MAX_BUF_LEN
}
};
- struct idpf_hw *hw = &adapter->hw;
+ struct libie_ctlq_xn_init_params params = {
+ .num_qs = IDPF_NUM_DFLT_MBX_Q,
+ .cctlq_info = ctlq_info,
+ .ctx = ctx,
+ };
int err;
- adapter->dev_ops.reg_ops.ctlq_reg_init(adapter, ctlq_info);
+ adapter->dev_ops.reg_ops.ctlq_reg_init(&ctx->mmio_info,
+ params.cctlq_info);
- err = idpf_ctlq_init(hw, IDPF_NUM_DFLT_MBX_Q, ctlq_info);
+ err = libie_ctlq_xn_init(&params);
if (err)
return err;
- hw->asq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_TX,
- IDPF_DFLT_MBX_ID);
- hw->arq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_RX,
- IDPF_DFLT_MBX_ID);
-
- if (!hw->asq || !hw->arq) {
- idpf_ctlq_deinit(hw);
-
+ adapter->asq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_TX,
+ LIBIE_CTLQ_MBX_ID);
+ adapter->arq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_RX,
+ LIBIE_CTLQ_MBX_ID);
+ if (!adapter->asq || !adapter->arq) {
+ adapter->asq = NULL;
+ adapter->arq = NULL;
+ libie_ctlq_xn_deinit(params.xnm, ctx);
return -ENOENT;
}
+ adapter->xnm = params.xnm;
adapter->state = __IDPF_VER_CHECK;
+ queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
+
return 0;
}
@@ -3312,12 +2949,18 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
*/
void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter)
{
- if (adapter->hw.arq && adapter->hw.asq) {
- idpf_mb_clean(adapter);
- idpf_ctlq_deinit(&adapter->hw);
+ idpf_mb_intr_rel_irq(adapter);
+ cancel_delayed_work_sync(&adapter->mbx_task);
+
+ if (adapter->xnm) {
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ idpf_mb_clean(adapter->asq, true);
+ libie_ctlq_xn_deinit(adapter->xnm, &adapter->ctlq_ctx);
}
- adapter->hw.arq = NULL;
- adapter->hw.asq = NULL;
+
+ adapter->arq = NULL;
+ adapter->asq = NULL;
+ adapter->xnm = NULL;
}
/**
@@ -3330,8 +2973,6 @@ static void idpf_vport_params_buf_rel(struct idpf_adapter *adapter)
{
kfree(adapter->vport_params_recvd);
adapter->vport_params_recvd = NULL;
- kfree(adapter->vport_params_reqd);
- adapter->vport_params_reqd = NULL;
kfree(adapter->vport_ids);
adapter->vport_ids = NULL;
}
@@ -3346,17 +2987,10 @@ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter)
{
u16 num_max_vports = idpf_get_max_vports(adapter);
- adapter->vport_params_reqd = kcalloc(num_max_vports,
- sizeof(*adapter->vport_params_reqd),
- GFP_KERNEL);
- if (!adapter->vport_params_reqd)
- return -ENOMEM;
-
- adapter->vport_params_recvd = kcalloc(num_max_vports,
- sizeof(*adapter->vport_params_recvd),
- GFP_KERNEL);
+ adapter->vport_params_recvd = kzalloc_objs(*adapter->vport_params_recvd,
+ num_max_vports);
if (!adapter->vport_params_recvd)
- goto err_mem;
+ return -ENOMEM;
adapter->vport_ids = kcalloc(num_max_vports, sizeof(u32), GFP_KERNEL);
if (!adapter->vport_ids)
@@ -3365,9 +2999,8 @@ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter)
if (adapter->vport_config)
return 0;
- adapter->vport_config = kcalloc(num_max_vports,
- sizeof(*adapter->vport_config),
- GFP_KERNEL);
+ adapter->vport_config = kzalloc_objs(*adapter->vport_config,
+ num_max_vports);
if (!adapter->vport_config)
goto err_mem;
@@ -3398,15 +3031,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
u16 num_max_vports;
int err = 0;
- if (!adapter->vcxn_mngr) {
- adapter->vcxn_mngr = kzalloc(sizeof(*adapter->vcxn_mngr), GFP_KERNEL);
- if (!adapter->vcxn_mngr) {
- err = -ENOMEM;
- goto init_failed;
- }
- }
- idpf_vc_xn_init(adapter->vcxn_mngr);
-
while (adapter->state != __IDPF_INIT_SW) {
switch (adapter->state) {
case __IDPF_VER_CHECK:
@@ -3445,41 +3069,33 @@ restart:
}
if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_LAN_MEMORY_REGIONS)) {
- err = idpf_send_get_lan_memory_regions(adapter);
+ err = idpf_cfg_lan_memory_regions(adapter);
if (err) {
- dev_err(&adapter->pdev->dev, "Failed to get LAN memory regions: %d\n",
+ dev_err(&adapter->pdev->dev, "Failed to configure LAN memory regions: %d\n",
err);
return -EINVAL;
}
} else {
/* Fallback to mapping the remaining regions of the entire BAR */
- err = idpf_calc_remaining_mmio_regs(adapter);
+ err = idpf_map_remaining_mmio_regs(adapter);
if (err) {
- dev_err(&adapter->pdev->dev, "Failed to allocate BAR0 region(s): %d\n",
+ dev_err(&adapter->pdev->dev, "Failed to configure BAR0 region(s): %d\n",
err);
- return -ENOMEM;
+ return err;
}
}
- err = idpf_map_lan_mmio_regs(adapter);
- if (err) {
- dev_err(&adapter->pdev->dev, "Failed to map BAR0 region(s): %d\n",
- err);
- return -ENOMEM;
- }
-
pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter));
num_max_vports = idpf_get_max_vports(adapter);
- adapter->max_vports = num_max_vports;
- adapter->vports = kcalloc(num_max_vports, sizeof(*adapter->vports),
- GFP_KERNEL);
- if (!adapter->vports)
- return -ENOMEM;
+ adapter->vports = kzalloc_objs(*adapter->vports, num_max_vports);
+ if (!adapter->vports) {
+ err = -ENOMEM;
+ goto decfg_regions;
+ }
if (!adapter->netdevs) {
- adapter->netdevs = kcalloc(num_max_vports,
- sizeof(struct net_device *),
- GFP_KERNEL);
+ adapter->netdevs = kzalloc_objs(struct net_device *,
+ num_max_vports);
if (!adapter->netdevs) {
err = -ENOMEM;
goto err_netdev_alloc;
@@ -3493,6 +3109,12 @@ restart:
goto err_netdev_alloc;
}
+ /* Set max_vports only after vports, netdevs and vport_config buffers
+ * are allocated to make sure max_vport bound loops don't end up
+ * crashing, following allocation errors on init.
+ */
+ adapter->max_vports = num_max_vports;
+
/* Start the mailbox task before requesting vectors. This will ensure
* vector information response from mailbox is handled
*/
@@ -3508,6 +3130,13 @@ restart:
goto err_intr_req;
}
+ err = idpf_send_get_rx_ptype_msg(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "failed to get RX ptypes: %d\n",
+ err);
+ goto intr_rel;
+ }
+
err = idpf_ptp_init(adapter);
if (err)
pci_err(adapter->pdev, "PTP init failed, err=%pe\n",
@@ -3525,6 +3154,8 @@ restart:
return 0;
+intr_rel:
+ idpf_intr_rel(adapter);
err_intr_req:
cancel_delayed_work_sync(&adapter->serv_task);
cancel_delayed_work_sync(&adapter->mbx_task);
@@ -3532,6 +3163,8 @@ err_intr_req:
err_netdev_alloc:
kfree(adapter->vports);
adapter->vports = NULL;
+decfg_regions:
+ idpf_decfg_lan_memory_regions(adapter);
return err;
init_failed:
@@ -3549,8 +3182,7 @@ init_failed:
* the mailbox again
*/
adapter->state = __IDPF_VER_CHECK;
- if (adapter->vcxn_mngr)
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ libie_ctlq_xn_shutdown(adapter->xnm);
set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
msecs_to_jiffies(task_delay));
@@ -3573,15 +3205,16 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
/* Avoid transaction timeouts when called during reset */
remove_in_prog = test_bit(IDPF_REMOVE_IN_PROG, adapter->flags);
if (!remove_in_prog)
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ libie_ctlq_xn_shutdown(adapter->xnm);
idpf_ptp_release(adapter);
idpf_deinit_task(adapter);
- idpf_idc_deinit_core_aux_device(adapter->cdev_info);
+ idpf_idc_deinit_core_aux_device(adapter);
+ idpf_rel_rx_pt_lkup(adapter);
idpf_intr_rel(adapter);
if (remove_in_prog)
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ libie_ctlq_xn_shutdown(adapter->xnm);
cancel_delayed_work_sync(&adapter->serv_task);
cancel_delayed_work_sync(&adapter->mbx_task);
@@ -3591,31 +3224,34 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
kfree(adapter->vports);
adapter->vports = NULL;
+ idpf_decfg_lan_memory_regions(adapter);
clear_bit(IDPF_VC_CORE_INIT, adapter->flags);
}
/**
* idpf_vport_alloc_vec_indexes - Get relative vector indexes
* @vport: virtual port data struct
+ * @rsrc: pointer to queue and vector resources
*
* This function requests the vector information required for the vport and
* stores the vector indexes received from the 'global vector distribution'
* in the vport's queue vectors array.
*
- * Return 0 on success, error on failure
+ * Return: 0 on success, error on failure
*/
-int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
+int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc)
{
struct idpf_vector_info vec_info;
int num_alloc_vecs;
u32 req;
- vec_info.num_curr_vecs = vport->num_q_vectors;
+ vec_info.num_curr_vecs = rsrc->num_q_vectors;
if (vec_info.num_curr_vecs)
vec_info.num_curr_vecs += IDPF_RESERVED_VECS;
/* XDPSQs are all bound to the NOIRQ vector from IDPF_RESERVED_VECS */
- req = max(vport->num_txq - vport->num_xdp_txq, vport->num_rxq) +
+ req = max(rsrc->num_txq - vport->num_xdp_txq, rsrc->num_rxq) +
IDPF_RESERVED_VECS;
vec_info.num_req_vecs = req;
@@ -3623,7 +3259,7 @@ int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
vec_info.index = vport->idx;
num_alloc_vecs = idpf_req_rel_vector_indexes(vport->adapter,
- vport->q_vector_idxs,
+ rsrc->q_vector_idxs,
&vec_info);
if (num_alloc_vecs <= 0) {
dev_err(&vport->adapter->pdev->dev, "Vector distribution failed: %d\n",
@@ -3631,7 +3267,7 @@ int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
return -EINVAL;
}
- vport->num_q_vectors = num_alloc_vecs - IDPF_RESERVED_VECS;
+ rsrc->num_q_vectors = num_alloc_vecs - IDPF_RESERVED_VECS;
return 0;
}
@@ -3642,9 +3278,12 @@ int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
* @max_q: vport max queue info
*
* Will initialize vport with the info received through MB earlier
+ *
+ * Return: 0 on success, negative on failure.
*/
-void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
+int idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
{
+ struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct idpf_adapter *adapter = vport->adapter;
struct virtchnl2_create_vport *vport_msg;
struct idpf_vport_config *vport_config;
@@ -3658,13 +3297,18 @@ void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
rss_data = &vport_config->user_config.rss_data;
vport_msg = adapter->vport_params_recvd[idx];
+ err = idpf_vport_init_queue_reg_chunks(vport_config,
+ &vport_msg->chunks);
+ if (err)
+ return err;
+
vport_config->max_q.max_txq = max_q->max_txq;
vport_config->max_q.max_rxq = max_q->max_rxq;
vport_config->max_q.max_complq = max_q->max_complq;
vport_config->max_q.max_bufq = max_q->max_bufq;
- vport->txq_model = le16_to_cpu(vport_msg->txq_model);
- vport->rxq_model = le16_to_cpu(vport_msg->rxq_model);
+ rsrc->txq_model = le16_to_cpu(vport_msg->txq_model);
+ rsrc->rxq_model = le16_to_cpu(vport_msg->rxq_model);
vport->vport_type = le16_to_cpu(vport_msg->vport_type);
vport->vport_id = le32_to_cpu(vport_msg->vport_id);
@@ -3681,24 +3325,27 @@ void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
idpf_vport_set_hsplit(vport, ETHTOOL_TCP_DATA_SPLIT_ENABLED);
- idpf_vport_init_num_qs(vport, vport_msg);
- idpf_vport_calc_num_q_desc(vport);
- idpf_vport_calc_num_q_groups(vport);
- idpf_vport_alloc_vec_indexes(vport);
+ idpf_vport_init_num_qs(vport, vport_msg, rsrc);
+ idpf_vport_calc_num_q_desc(vport, rsrc);
+ idpf_vport_calc_num_q_groups(rsrc);
+ idpf_vport_alloc_vec_indexes(vport, rsrc);
vport->crc_enable = adapter->crc_enable;
if (!(vport_msg->vport_flags &
cpu_to_le16(VIRTCHNL2_VPORT_UPLINK_PORT)))
- return;
+ return 0;
err = idpf_ptp_get_vport_tstamps_caps(vport);
if (err) {
+ /* Do not error on timestamp failure */
pci_dbg(vport->adapter->pdev, "Tx timestamping not supported\n");
- return;
+ return 0;
}
INIT_WORK(&vport->tstamp_task, idpf_tstamp_task);
+
+ return 0;
}
/**
@@ -3757,21 +3404,21 @@ int idpf_get_vec_ids(struct idpf_adapter *adapter,
* Returns number of ids filled
*/
static int idpf_vport_get_queue_ids(u32 *qids, int num_qids, u16 q_type,
- struct virtchnl2_queue_reg_chunks *chunks)
+ struct idpf_queue_id_reg_info *chunks)
{
- u16 num_chunks = le16_to_cpu(chunks->num_chunks);
+ u16 num_chunks = chunks->num_chunks;
u32 num_q_id_filled = 0, i;
u32 start_q_id, num_q;
while (num_chunks--) {
- struct virtchnl2_queue_reg_chunk *chunk;
+ struct idpf_queue_id_reg_chunk *chunk;
- chunk = &chunks->chunks[num_chunks];
- if (le32_to_cpu(chunk->type) != q_type)
+ chunk = &chunks->queue_chunks[num_chunks];
+ if (chunk->type != q_type)
continue;
- num_q = le32_to_cpu(chunk->num_queues);
- start_q_id = le32_to_cpu(chunk->start_queue_id);
+ num_q = chunk->num_queues;
+ start_q_id = chunk->start_queue_id;
for (i = 0; i < num_q; i++) {
if ((num_q_id_filled + i) < num_qids) {
@@ -3790,6 +3437,7 @@ static int idpf_vport_get_queue_ids(u32 *qids, int num_qids, u16 q_type,
/**
* __idpf_vport_queue_ids_init - Initialize queue ids from Mailbox parameters
* @vport: virtual port for which the queues ids are initialized
+ * @rsrc: pointer to queue and vector resources
* @qids: queue ids
* @num_qids: number of queue ids
* @q_type: type of queue
@@ -3798,6 +3446,7 @@ static int idpf_vport_get_queue_ids(u32 *qids, int num_qids, u16 q_type,
* parameters. Returns number of queue ids initialized.
*/
static int __idpf_vport_queue_ids_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
const u32 *qids,
int num_qids,
u32 q_type)
@@ -3806,19 +3455,19 @@ static int __idpf_vport_queue_ids_init(struct idpf_vport *vport,
switch (q_type) {
case VIRTCHNL2_QUEUE_TYPE_TX:
- for (i = 0; i < vport->num_txq_grp; i++) {
- struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (i = 0; i < rsrc->num_txq_grp; i++) {
+ struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
for (j = 0; j < tx_qgrp->num_txq && k < num_qids; j++, k++)
tx_qgrp->txqs[j]->q_id = qids[k];
}
break;
case VIRTCHNL2_QUEUE_TYPE_RX:
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u16 num_rxq;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
num_rxq = rx_qgrp->splitq.num_rxq_sets;
else
num_rxq = rx_qgrp->singleq.num_rxq;
@@ -3826,7 +3475,7 @@ static int __idpf_vport_queue_ids_init(struct idpf_vport *vport,
for (j = 0; j < num_rxq && k < num_qids; j++, k++) {
struct idpf_rx_queue *q;
- if (idpf_is_queue_model_split(vport->rxq_model))
+ if (idpf_is_queue_model_split(rsrc->rxq_model))
q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
else
q = rx_qgrp->singleq.rxqs[j];
@@ -3835,16 +3484,16 @@ static int __idpf_vport_queue_ids_init(struct idpf_vport *vport,
}
break;
case VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION:
- for (i = 0; i < vport->num_txq_grp && k < num_qids; i++, k++) {
- struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
+ for (i = 0; i < rsrc->num_txq_grp && k < num_qids; i++, k++) {
+ struct idpf_txq_group *tx_qgrp = &rsrc->txq_grps[i];
tx_qgrp->complq->q_id = qids[k];
}
break;
case VIRTCHNL2_QUEUE_TYPE_RX_BUFFER:
- for (i = 0; i < vport->num_rxq_grp; i++) {
- struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
- u8 num_bufqs = vport->num_bufqs_per_qgrp;
+ for (i = 0; i < rsrc->num_rxq_grp; i++) {
+ struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
+ u8 num_bufqs = rsrc->num_bufqs_per_qgrp;
for (j = 0; j < num_bufqs && k < num_qids; j++, k++) {
struct idpf_buf_queue *q;
@@ -3864,30 +3513,21 @@ static int __idpf_vport_queue_ids_init(struct idpf_vport *vport,
/**
* idpf_vport_queue_ids_init - Initialize queue ids from Mailbox parameters
* @vport: virtual port for which the queues ids are initialized
+ * @rsrc: pointer to queue and vector resources
+ * @chunks: queue ids received over mailbox
*
* Will initialize all queue ids with ids received as mailbox parameters.
- * Returns 0 on success, negative if all the queues are not initialized.
+ *
+ * Return: 0 on success, negative if all the queues are not initialized.
*/
-int idpf_vport_queue_ids_init(struct idpf_vport *vport)
+int idpf_vport_queue_ids_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ struct idpf_queue_id_reg_info *chunks)
{
- struct virtchnl2_create_vport *vport_params;
- struct virtchnl2_queue_reg_chunks *chunks;
- struct idpf_vport_config *vport_config;
- u16 vport_idx = vport->idx;
int num_ids, err = 0;
u16 q_type;
u32 *qids;
- vport_config = vport->adapter->vport_config[vport_idx];
- if (vport_config->req_qs_chunks) {
- struct virtchnl2_add_queues *vc_aq =
- (struct virtchnl2_add_queues *)vport_config->req_qs_chunks;
- chunks = &vc_aq->chunks;
- } else {
- vport_params = vport->adapter->vport_params_recvd[vport_idx];
- chunks = &vport_params->chunks;
- }
-
qids = kcalloc(IDPF_MAX_QIDS, sizeof(u32), GFP_KERNEL);
if (!qids)
return -ENOMEM;
@@ -3895,13 +3535,13 @@ int idpf_vport_queue_ids_init(struct idpf_vport *vport)
num_ids = idpf_vport_get_queue_ids(qids, IDPF_MAX_QIDS,
VIRTCHNL2_QUEUE_TYPE_TX,
chunks);
- if (num_ids < vport->num_txq) {
+ if (num_ids < rsrc->num_txq) {
err = -EINVAL;
goto mem_rel;
}
- num_ids = __idpf_vport_queue_ids_init(vport, qids, num_ids,
+ num_ids = __idpf_vport_queue_ids_init(vport, rsrc, qids, num_ids,
VIRTCHNL2_QUEUE_TYPE_TX);
- if (num_ids < vport->num_txq) {
+ if (num_ids < rsrc->num_txq) {
err = -EINVAL;
goto mem_rel;
}
@@ -3909,44 +3549,46 @@ int idpf_vport_queue_ids_init(struct idpf_vport *vport)
num_ids = idpf_vport_get_queue_ids(qids, IDPF_MAX_QIDS,
VIRTCHNL2_QUEUE_TYPE_RX,
chunks);
- if (num_ids < vport->num_rxq) {
+ if (num_ids < rsrc->num_rxq) {
err = -EINVAL;
goto mem_rel;
}
- num_ids = __idpf_vport_queue_ids_init(vport, qids, num_ids,
+ num_ids = __idpf_vport_queue_ids_init(vport, rsrc, qids, num_ids,
VIRTCHNL2_QUEUE_TYPE_RX);
- if (num_ids < vport->num_rxq) {
+ if (num_ids < rsrc->num_rxq) {
err = -EINVAL;
goto mem_rel;
}
- if (!idpf_is_queue_model_split(vport->txq_model))
+ if (!idpf_is_queue_model_split(rsrc->txq_model))
goto check_rxq;
q_type = VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION;
num_ids = idpf_vport_get_queue_ids(qids, IDPF_MAX_QIDS, q_type, chunks);
- if (num_ids < vport->num_complq) {
+ if (num_ids < rsrc->num_complq) {
err = -EINVAL;
goto mem_rel;
}
- num_ids = __idpf_vport_queue_ids_init(vport, qids, num_ids, q_type);
- if (num_ids < vport->num_complq) {
+ num_ids = __idpf_vport_queue_ids_init(vport, rsrc, qids,
+ num_ids, q_type);
+ if (num_ids < rsrc->num_complq) {
err = -EINVAL;
goto mem_rel;
}
check_rxq:
- if (!idpf_is_queue_model_split(vport->rxq_model))
+ if (!idpf_is_queue_model_split(rsrc->rxq_model))
goto mem_rel;
q_type = VIRTCHNL2_QUEUE_TYPE_RX_BUFFER;
num_ids = idpf_vport_get_queue_ids(qids, IDPF_MAX_QIDS, q_type, chunks);
- if (num_ids < vport->num_bufq) {
+ if (num_ids < rsrc->num_bufq) {
err = -EINVAL;
goto mem_rel;
}
- num_ids = __idpf_vport_queue_ids_init(vport, qids, num_ids, q_type);
- if (num_ids < vport->num_bufq)
+ num_ids = __idpf_vport_queue_ids_init(vport, rsrc, qids,
+ num_ids, q_type);
+ if (num_ids < rsrc->num_bufq)
err = -EINVAL;
mem_rel:
@@ -3958,23 +3600,24 @@ mem_rel:
/**
* idpf_vport_adjust_qs - Adjust to new requested queues
* @vport: virtual port data struct
+ * @rsrc: pointer to queue and vector resources
*
* Renegotiate queues. Returns 0 on success, negative on failure.
*/
-int idpf_vport_adjust_qs(struct idpf_vport *vport)
+int idpf_vport_adjust_qs(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
{
struct virtchnl2_create_vport vport_msg;
int err;
- vport_msg.txq_model = cpu_to_le16(vport->txq_model);
- vport_msg.rxq_model = cpu_to_le16(vport->rxq_model);
+ vport_msg.txq_model = cpu_to_le16(rsrc->txq_model);
+ vport_msg.rxq_model = cpu_to_le16(rsrc->rxq_model);
err = idpf_vport_calc_total_qs(vport->adapter, vport->idx, &vport_msg,
NULL);
if (err)
return err;
- idpf_vport_init_num_qs(vport, &vport_msg);
- idpf_vport_calc_num_q_groups(vport);
+ idpf_vport_init_num_qs(vport, &vport_msg, rsrc);
+ idpf_vport_calc_num_q_groups(rsrc);
return 0;
}
@@ -4096,21 +3739,21 @@ u32 idpf_get_vport_id(struct idpf_vport *vport)
return le32_to_cpu(vport_msg->vport_id);
}
-static void idpf_set_mac_type(struct idpf_vport *vport,
+static void idpf_set_mac_type(const u8 *default_mac_addr,
struct virtchnl2_mac_addr *mac_addr)
{
bool is_primary;
- is_primary = ether_addr_equal(vport->default_mac_addr, mac_addr->addr);
+ is_primary = ether_addr_equal(default_mac_addr, mac_addr->addr);
mac_addr->type = is_primary ? VIRTCHNL2_MAC_ADDR_PRIMARY :
VIRTCHNL2_MAC_ADDR_EXTRA;
}
/**
* idpf_mac_filter_async_handler - Async callback for mac filters
- * @adapter: private data struct
- * @xn: transaction for message
- * @ctlq_msg: received message
+ * @ctx: controlq context structure
+ * @buff: response buffer pointer and size
+ * @status: async call return value
*
* In some scenarios driver can't sleep and wait for a reply (e.g.: stack is
* holding rtnl_lock) when adding a new mac filter. It puts us in a difficult
@@ -4118,13 +3761,14 @@ static void idpf_set_mac_type(struct idpf_vport *vport,
* ultimately do is remove it from our list of mac filters and report the
* error.
*/
-static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
- struct idpf_vc_xn *xn,
- const struct idpf_ctlq_msg *ctlq_msg)
+static void idpf_mac_filter_async_handler(void *ctx,
+ struct kvec *buff,
+ int status)
{
struct virtchnl2_mac_addr_list *ma_list;
struct idpf_vport_config *vport_config;
struct virtchnl2_mac_addr *mac_addr;
+ struct idpf_adapter *adapter = ctx;
struct idpf_mac_filter *f, *tmp;
struct list_head *ma_list_head;
struct idpf_vport *vport;
@@ -4132,18 +3776,18 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
int i;
/* if success we're done, we're only here if something bad happened */
- if (!ctlq_msg->cookie.mbx.chnl_retval)
- return 0;
+ if (!status || status == -ETIMEDOUT)
+ return;
+ ma_list = buff->iov_base;
/* make sure at least struct is there */
- if (xn->reply_sz < sizeof(*ma_list))
+ if (buff->iov_len < sizeof(*ma_list))
goto invalid_payload;
- ma_list = ctlq_msg->ctx.indirect.payload->va;
mac_addr = ma_list->mac_addr_list;
num_entries = le16_to_cpu(ma_list->num_mac_addr);
/* we should have received a buffer at least this big */
- if (xn->reply_sz < struct_size(ma_list, mac_addr_list, num_entries))
+ if (buff->iov_len < struct_size(ma_list, mac_addr_list, num_entries))
goto invalid_payload;
vport = idpf_vid_to_vport(adapter, le32_to_cpu(ma_list->vport_id));
@@ -4163,48 +3807,47 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
if (ether_addr_equal(mac_addr[i].addr, f->macaddr))
list_del(&f->list);
spin_unlock_bh(&vport_config->mac_filter_list_lock);
- dev_err_ratelimited(&adapter->pdev->dev, "Received error sending MAC filter request (op %d)\n",
- xn->vc_op);
-
- return 0;
+ dev_err_ratelimited(&adapter->pdev->dev, "Received error %d on sending MAC filter request\n",
+ status);
+ return;
invalid_payload:
- dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (op %d) (len %zd)\n",
- xn->vc_op, xn->reply_sz);
-
- return -EINVAL;
+ dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (len %zd)\n",
+ buff->iov_len);
}
/**
* idpf_add_del_mac_filters - Add/del mac filters
- * @vport: Virtual port data structure
- * @np: Netdev private structure
+ * @adapter: adapter pointer used to send virtchnl message
+ * @vport_config: persistent vport structure to get the MAC filter list
+ * @default_mac_addr: default MAC address to compare with
+ * @vport_id: vport identifier used while preparing the virtchnl message
* @add: Add or delete flag
* @async: Don't wait for return message
*
- * Returns 0 on success, error on failure.
+ * Return: 0 on success, error on failure.
**/
-int idpf_add_del_mac_filters(struct idpf_vport *vport,
- struct idpf_netdev_priv *np,
+int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
+ struct idpf_vport_config *vport_config,
+ const u8 *default_mac_addr, u32 vport_id,
bool add, bool async)
{
- struct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL;
struct virtchnl2_mac_addr *mac_addr __free(kfree) = NULL;
- struct idpf_adapter *adapter = np->adapter;
- struct idpf_vc_xn_params xn_params = {};
- struct idpf_vport_config *vport_config;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
+ VIRTCHNL2_OP_DEL_MAC_ADDR,
+ };
+ struct virtchnl2_mac_addr_list *ma_list;
u32 num_msgs, total_filters = 0;
struct idpf_mac_filter *f;
- ssize_t reply_sz;
- int i = 0, k;
+ int i = 0;
- xn_params.vc_op = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
- VIRTCHNL2_OP_DEL_MAC_ADDR;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.async = async;
- xn_params.async_handler = idpf_mac_filter_async_handler;
+ if (async) {
+ xn_params.resp_cb = idpf_mac_filter_async_handler;
+ xn_params.send_ctx = adapter;
+ }
- vport_config = adapter->vport_config[np->vport_idx];
spin_lock_bh(&vport_config->mac_filter_list_lock);
/* Find the number of newly added filters */
@@ -4223,8 +3866,8 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
}
/* Fill all the new filters into virtchannel message */
- mac_addr = kcalloc(total_filters, sizeof(struct virtchnl2_mac_addr),
- GFP_ATOMIC);
+ mac_addr = kzalloc_objs(struct virtchnl2_mac_addr, total_filters,
+ GFP_ATOMIC);
if (!mac_addr) {
spin_unlock_bh(&vport_config->mac_filter_list_lock);
@@ -4235,7 +3878,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
list) {
if (add && f->add) {
ether_addr_copy(mac_addr[i].addr, f->macaddr);
- idpf_set_mac_type(vport, &mac_addr[i]);
+ idpf_set_mac_type(default_mac_addr, &mac_addr[i]);
i++;
f->add = false;
if (i == total_filters)
@@ -4243,7 +3886,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
}
if (!add && f->remove) {
ether_addr_copy(mac_addr[i].addr, f->macaddr);
- idpf_set_mac_type(vport, &mac_addr[i]);
+ idpf_set_mac_type(default_mac_addr, &mac_addr[i]);
i++;
f->remove = false;
if (i == total_filters)
@@ -4258,32 +3901,31 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
*/
num_msgs = DIV_ROUND_UP(total_filters, IDPF_NUM_FILTERS_PER_MSG);
- for (i = 0, k = 0; i < num_msgs; i++) {
- u32 entries_size, buf_size, num_entries;
+ for (u32 i = 0, k = 0; i < num_msgs; i++) {
+ u32 entries_size, num_entries;
+ size_t buf_size;
+ int err;
num_entries = min_t(u32, total_filters,
IDPF_NUM_FILTERS_PER_MSG);
entries_size = sizeof(struct virtchnl2_mac_addr) * num_entries;
buf_size = struct_size(ma_list, mac_addr_list, num_entries);
- if (!ma_list || num_entries != IDPF_NUM_FILTERS_PER_MSG) {
- kfree(ma_list);
- ma_list = kzalloc(buf_size, GFP_ATOMIC);
- if (!ma_list)
- return -ENOMEM;
- } else {
- memset(ma_list, 0, buf_size);
- }
+ ma_list = kzalloc(buf_size, GFP_ATOMIC);
+ if (!ma_list)
+ return -ENOMEM;
- ma_list->vport_id = cpu_to_le32(np->vport_id);
+ ma_list->vport_id = cpu_to_le32(vport_id);
ma_list->num_mac_addr = cpu_to_le16(num_entries);
memcpy(ma_list->mac_addr_list, &mac_addr[k], entries_size);
- xn_params.send_buf.iov_base = ma_list;
- xn_params.send_buf.iov_len = buf_size;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, ma_list,
+ buf_size);
+ if (err)
+ return err;
+
+ if (!async)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
k += num_entries;
total_filters -= num_entries;
@@ -4293,6 +3935,26 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
}
/**
+ * idpf_promiscuous_async_handler - async callback for promiscuous mode
+ * @ctx: controlq context structure
+ * @buff: response buffer pointer and size
+ * @status: async call return value
+ *
+ * Nobody is waiting for the promiscuous virtchnl message response. Print
+ * an error message if something went wrong and return.
+ */
+static void idpf_promiscuous_async_handler(void *ctx,
+ struct kvec *buff,
+ int status)
+{
+ struct idpf_adapter *adapter = ctx;
+
+ if (status)
+ dev_err_ratelimited(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n",
+ status);
+}
+
+/**
* idpf_set_promiscuous - set promiscuous and send message to mailbox
* @adapter: Driver specific private structure
* @config_data: Vport specific config data
@@ -4306,9 +3968,13 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
struct idpf_vport_user_config_data *config_data,
u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE,
+ .resp_cb = idpf_promiscuous_async_handler,
+ .send_ctx = adapter,
+ };
struct virtchnl2_promisc_info vpi;
- ssize_t reply_sz;
u16 flags = 0;
if (test_bit(__IDPF_PROMISC_UC, config_data->user_flags))
@@ -4319,15 +3985,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
vpi.vport_id = cpu_to_le32(vport_id);
vpi.flags = cpu_to_le16(flags);
- xn_params.vc_op = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &vpi;
- xn_params.send_buf.iov_len = sizeof(vpi);
- /* setting promiscuous is only ever done asynchronously */
- xn_params.async = true;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-
- return reply_sz < 0 ? reply_sz : 0;
+ return idpf_send_mb_msg_stack(adapter, &xn_params, &vpi);
}
/**
@@ -4336,7 +3994,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
* @send_msg: message to send
* @msg_size: size of message to send
* @recv_msg: message to populate on reception of response
- * @recv_len: length of message copied into recv_msg or 0 on error
+ * @recv_len: on input, maximum response size; on success, actual response size
*
* Return: 0 on success or error code on failure.
*/
@@ -4345,26 +4003,39 @@ int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
u8 *recv_msg, u16 *recv_len)
{
struct idpf_adapter *adapter = pci_get_drvdata(cdev_info->pdev);
- struct idpf_vc_xn_params xn_params = { };
- ssize_t reply_sz;
- u16 recv_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_RDMA,
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ };
+ u8 on_stack_buf[LIBIE_CP_TX_COPYBREAK];
+ void *send_buf;
+ int err;
- if (!recv_msg || !recv_len || msg_size > IDPF_CTLQ_MAX_BUF_LEN)
+ if (!recv_msg || !recv_len || msg_size > LIBIE_CTLQ_MAX_BUF_LEN)
return -EINVAL;
- recv_size = min_t(u16, *recv_len, IDPF_CTLQ_MAX_BUF_LEN);
- *recv_len = 0;
- xn_params.vc_op = VIRTCHNL2_OP_RDMA;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = send_msg;
- xn_params.send_buf.iov_len = msg_size;
- xn_params.recv_buf.iov_base = recv_msg;
- xn_params.recv_buf.iov_len = recv_size;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- *recv_len = reply_sz;
+ if (!libie_cp_can_send_onstack(msg_size)) {
+ send_buf = kzalloc(msg_size, GFP_KERNEL);
+ if (!send_buf)
+ return -ENOMEM;
+ } else {
+ send_buf = on_stack_buf;
+ }
- return 0;
+ memcpy(send_buf, send_msg, msg_size);
+ err = idpf_send_mb_msg(adapter, &xn_params, send_buf, msg_size);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len > *recv_len) {
+ err = -EINVAL;
+ goto rel_buf;
+ }
+
+ *recv_len = xn_params.recv_mem.iov_len;
+ memcpy(recv_msg, xn_params.recv_mem.iov_base, *recv_len);
+rel_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
EXPORT_SYMBOL_GPL(idpf_idc_rdma_vc_send_sync);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index eac3d15daa42..5d27805ff40f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -4,107 +4,37 @@
#ifndef _IDPF_VIRTCHNL_H_
#define _IDPF_VIRTCHNL_H_
-#include "virtchnl2.h"
+#include <linux/net/intel/virtchnl2.h>
#define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC (60 * 1000)
-#define IDPF_VC_XN_IDX_M GENMASK(7, 0)
-#define IDPF_VC_XN_SALT_M GENMASK(15, 8)
-#define IDPF_VC_XN_RING_LEN U8_MAX
-
-/**
- * enum idpf_vc_xn_state - Virtchnl transaction status
- * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used
- * @IDPF_VC_XN_WAITING: expecting a reply, not yet received
- * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, buffer
- * updated
- * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there
- * was an error, buffer not updated
- * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down
- * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the
- * return context; a callback may be provided to handle
- * return
- */
-enum idpf_vc_xn_state {
- IDPF_VC_XN_IDLE = 1,
- IDPF_VC_XN_WAITING,
- IDPF_VC_XN_COMPLETED_SUCCESS,
- IDPF_VC_XN_COMPLETED_FAILED,
- IDPF_VC_XN_SHUTDOWN,
- IDPF_VC_XN_ASYNC,
-};
-
-struct idpf_vc_xn;
-/* Callback for asynchronous messages */
-typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
- const struct idpf_ctlq_msg *);
-
-/**
- * struct idpf_vc_xn - Data structure representing virtchnl transactions
- * @completed: virtchnl event loop uses that to signal when a reply is
- * available, uses kernel completion API
- * @state: virtchnl event loop stores the data below, protected by the
- * completion's lock.
- * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
- * truncated on its way to the receiver thread according to
- * reply_buf.iov_len.
- * @reply: Reference to the buffer(s) where the reply data should be written
- * to. May be 0-length (then NULL address permitted) if the reply data
- * should be ignored.
- * @async_handler: if sent asynchronously, a callback can be provided to handle
- * the reply when it's received
- * @vc_op: corresponding opcode sent with this transaction
- * @idx: index used as retrieval on reply receive, used for cookie
- * @salt: changed every message to make unique, used for cookie
- */
-struct idpf_vc_xn {
- struct completion completed;
- enum idpf_vc_xn_state state;
- size_t reply_sz;
- struct kvec reply;
- async_vc_cb async_handler;
- u32 vc_op;
- u8 idx;
- u8 salt;
-};
-
-/**
- * struct idpf_vc_xn_params - Parameters for executing transaction
- * @send_buf: kvec for send buffer
- * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length
- * @timeout_ms: timeout to wait for reply
- * @async: send message asynchronously, will not wait on completion
- * @async_handler: If sent asynchronously, optional callback handler. The user
- * must be careful when using async handlers as the memory for
- * the recv_buf _cannot_ be on stack if this is async.
- * @vc_op: virtchnl op to send
- */
-struct idpf_vc_xn_params {
- struct kvec send_buf;
- struct kvec recv_buf;
- int timeout_ms;
- bool async;
- async_vc_cb async_handler;
- u32 vc_op;
-};
struct idpf_adapter;
struct idpf_netdev_priv;
struct idpf_vec_regs;
struct idpf_vport;
struct idpf_vport_max_q;
+struct idpf_vport_config;
struct idpf_vport_user_config_data;
-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
- const struct idpf_vc_xn_params *params);
int idpf_init_dflt_mbx(struct idpf_adapter *adapter);
void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
int idpf_vc_core_init(struct idpf_adapter *adapter);
void idpf_vc_core_deinit(struct idpf_adapter *adapter);
-int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
- struct idpf_vec_regs *reg_vals);
-int idpf_queue_reg_init(struct idpf_vport *vport);
-int idpf_vport_queue_ids_init(struct idpf_vport *vport);
+int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
+ struct idpf_vec_regs *reg_vals, int num_vecs);
+int idpf_queue_reg_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ struct idpf_queue_id_reg_info *chunks);
+int idpf_vport_queue_ids_init(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc,
+ struct idpf_queue_id_reg_info *chunks);
+static inline void
+idpf_vport_deinit_queue_reg_chunks(struct idpf_vport_config *vport_cfg)
+{
+ kfree(vport_cfg->qid_reg_info.queue_chunks);
+ vport_cfg->qid_reg_info.queue_chunks = NULL;
+}
bool idpf_vport_is_cap_ena(struct idpf_vport *vport, u16 flag);
bool idpf_sideband_flow_type_ena(struct idpf_vport *vport, u32 flow_type);
@@ -112,9 +42,35 @@ bool idpf_sideband_action_ena(struct idpf_vport *vport,
struct ethtool_rx_flow_spec *fsp);
unsigned int idpf_fsteer_max_rules(struct idpf_vport *vport);
-int idpf_recv_mb_msg(struct idpf_adapter *adapter);
-int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
- u16 msg_size, u8 *msg, u16 cookie);
+void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_msg *ctlq_msg);
+int idpf_send_mb_msg(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size);
+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size);
+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter);
+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg);
+
+/**
+ * idpf_send_mb_msg_stack - send a mailbox message from an on-stack buffer
+ * @adapter: driver specific private structure
+ * @xn_params: Xn send parameters to fill
+ * @ptr: pointer to the on-stack message object to send
+ *
+ * Send size is deduced based on the pointer type.
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+#define idpf_send_mb_msg_stack(adapter, xn_params, ptr) \
+({ \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ static_assert(sizeof(*__ptr) <= LIBIE_CP_TX_COPYBREAK); \
+ idpf_send_mb_msg(adapter, xn_params, __ptr, sizeof(*__ptr)); \
+})
struct idpf_queue_ptr {
enum virtchnl2_queue_type type;
@@ -127,61 +83,79 @@ struct idpf_queue_ptr {
};
struct idpf_queue_set {
- struct idpf_vport *vport;
+ struct idpf_adapter *adapter;
+ struct idpf_q_vec_rsrc *qv_rsrc;
+ u32 vport_id;
u32 num;
struct idpf_queue_ptr qs[] __counted_by(num);
};
-struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_vport *vport, u32 num);
+struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id, u32 num);
int idpf_send_enable_queue_set_msg(const struct idpf_queue_set *qs);
int idpf_send_disable_queue_set_msg(const struct idpf_queue_set *qs);
int idpf_send_config_queue_set_msg(const struct idpf_queue_set *qs);
int idpf_send_disable_queues_msg(struct idpf_vport *vport);
-int idpf_send_config_queues_msg(struct idpf_vport *vport);
int idpf_send_enable_queues_msg(struct idpf_vport *vport);
+int idpf_send_config_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id);
-void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q);
+int idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q);
u32 idpf_get_vport_id(struct idpf_vport *vport);
int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
-int idpf_send_destroy_vport_msg(struct idpf_vport *vport);
-int idpf_send_enable_vport_msg(struct idpf_vport *vport);
-int idpf_send_disable_vport_msg(struct idpf_vport *vport);
+int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
+int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
+int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
-int idpf_vport_adjust_qs(struct idpf_vport *vport);
+int idpf_vport_adjust_qs(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
-int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
- u16 num_complq, u16 num_rx_q, u16 num_rx_bufq);
-int idpf_send_delete_queues_msg(struct idpf_vport *vport);
-
-int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport);
+int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_vport_config *vport_config,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id);
+int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
+ struct idpf_queue_id_reg_info *chunks,
+ u32 vport_id);
+
+int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
int idpf_get_vec_ids(struct idpf_adapter *adapter,
u16 *vecids, int num_vecids,
struct virtchnl2_vector_chunks *chunks);
int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors);
int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter);
-int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map);
-
-int idpf_add_del_mac_filters(struct idpf_vport *vport,
- struct idpf_netdev_priv *np,
+int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
+ struct idpf_q_vec_rsrc *rsrc,
+ u32 vport_id,
+ bool map);
+
+int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
+ struct idpf_vport_config *vport_config,
+ const u8 *default_mac_addr, u32 vport_id,
bool add, bool async);
int idpf_set_promiscuous(struct idpf_adapter *adapter,
struct idpf_vport_user_config_data *config_data,
u32 vport_id);
int idpf_check_supported_desc_ids(struct idpf_vport *vport);
-int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport);
-int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport);
-int idpf_send_get_stats_msg(struct idpf_vport *vport);
+int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
+ bool loopback_ena);
+int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,
+ struct idpf_port_stats *port_stats);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
-int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get);
-int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get);
-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr);
+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id);
+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id);
int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
u8 *send_msg, u16 msg_size,
u8 *recv_msg, u16 *recv_len);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
index 61cedb6f2854..14dba40a993f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
@@ -15,7 +15,6 @@
*/
int idpf_ptp_get_caps(struct idpf_adapter *adapter)
{
- struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg __free(kfree) = NULL;
struct virtchnl2_ptp_get_caps send_ptp_caps_msg = {
.caps = cpu_to_le32(VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME |
VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB |
@@ -24,34 +23,33 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB |
VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB)
};
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_CAPS,
- .send_buf.iov_base = &send_ptp_caps_msg,
- .send_buf.iov_len = sizeof(send_ptp_caps_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CAPS,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
struct virtchnl2_ptp_cross_time_reg_offsets cross_tstamp_offsets;
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
+ struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg;
struct idpf_ptp_secondary_mbx *scnd_mbx;
struct idpf_ptp *ptp = adapter->ptp;
enum idpf_ptp_access access_type;
u32 temp_offset;
- int reply_sz;
+ size_t reply_sz;
+ int err;
- recv_ptp_caps_msg = kzalloc(sizeof(struct virtchnl2_ptp_get_caps),
- GFP_KERNEL);
- if (!recv_ptp_caps_msg)
- return -ENOMEM;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &send_ptp_caps_msg);
+ if (err)
+ return err;
- xn_params.recv_buf.iov_base = recv_ptp_caps_msg;
- xn_params.recv_buf.iov_len = sizeof(*recv_ptp_caps_msg);
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz != sizeof(*recv_ptp_caps_msg)) {
+ err = -EIO;
+ goto free_resp;
+ }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- else if (reply_sz != sizeof(*recv_ptp_caps_msg))
- return -EIO;
+ recv_ptp_caps_msg = xn_params.recv_mem.iov_base;
ptp->caps = le32_to_cpu(recv_ptp_caps_msg->caps);
ptp->base_incval = le64_to_cpu(recv_ptp_caps_msg->base_incval);
@@ -77,19 +75,20 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
clock_offsets = recv_ptp_caps_msg->clk_offsets;
temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_l);
- ptp->dev_clk_regs.dev_clk_ns_l = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.dev_clk_ns_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_h);
- ptp->dev_clk_regs.dev_clk_ns_h = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.dev_clk_ns_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_l);
- ptp->dev_clk_regs.phy_clk_ns_l = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.phy_clk_ns_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_h);
- ptp->dev_clk_regs.phy_clk_ns_h = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.phy_clk_ns_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clock_offsets.cmd_sync_trigger);
- ptp->dev_clk_regs.cmd_sync = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.cmd_sync =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
cross_tstamp:
access_type = ptp->get_cross_tstamp_access;
@@ -99,48 +98,54 @@ cross_tstamp:
cross_tstamp_offsets = recv_ptp_caps_msg->cross_time_offsets;
temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_l);
- ptp->dev_clk_regs.sys_time_ns_l = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.sys_time_ns_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_h);
- ptp->dev_clk_regs.sys_time_ns_h = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.sys_time_ns_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(cross_tstamp_offsets.cmd_sync_trigger);
- ptp->dev_clk_regs.cmd_sync = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.cmd_sync =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
discipline_clock:
access_type = ptp->adj_dev_clk_time_access;
if (access_type != IDPF_PTP_DIRECT)
- return 0;
+ goto free_resp;
clk_adj_offsets = recv_ptp_caps_msg->clk_adj_offsets;
/* Device clock offsets */
temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_cmd_type);
- ptp->dev_clk_regs.cmd = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.cmd = libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_l);
- ptp->dev_clk_regs.incval_l = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.incval_l = libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_h);
- ptp->dev_clk_regs.incval_h = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.incval_h = libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_l);
- ptp->dev_clk_regs.shadj_l = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.shadj_l = libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_h);
- ptp->dev_clk_regs.shadj_h = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.shadj_h = libie_pci_get_mmio_addr(mmio, temp_offset);
/* PHY clock offsets */
temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_cmd_type);
- ptp->dev_clk_regs.phy_cmd = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.phy_cmd =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_l);
- ptp->dev_clk_regs.phy_incval_l = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.phy_incval_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_h);
- ptp->dev_clk_regs.phy_incval_h = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.phy_incval_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_l);
- ptp->dev_clk_regs.phy_shadj_l = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.phy_shadj_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_h);
- ptp->dev_clk_regs.phy_shadj_h = idpf_get_reg_addr(adapter, temp_offset);
+ ptp->dev_clk_regs.phy_shadj_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
- return 0;
+free_resp:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -155,28 +160,34 @@ discipline_clock:
int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
struct idpf_ptp_dev_timers *dev_clk_time)
{
+ struct virtchnl2_ptp_get_dev_clk_time *get_dev_clk_time_resp;
struct virtchnl2_ptp_get_dev_clk_time get_dev_clk_time_msg;
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
- .send_buf.iov_base = &get_dev_clk_time_msg,
- .send_buf.iov_len = sizeof(get_dev_clk_time_msg),
- .recv_buf.iov_base = &get_dev_clk_time_msg,
- .recv_buf.iov_len = sizeof(get_dev_clk_time_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ size_t reply_sz;
u64 dev_time;
+ int err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(get_dev_clk_time_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params,
+ &get_dev_clk_time_msg);
+ if (err)
+ return err;
- dev_time = le64_to_cpu(get_dev_clk_time_msg.dev_time_ns);
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz != sizeof(*get_dev_clk_time_resp)) {
+ err = -EIO;
+ goto free_resp;
+ }
+
+ get_dev_clk_time_resp = xn_params.recv_mem.iov_base;
+ dev_time = le64_to_cpu(get_dev_clk_time_resp->dev_time_ns);
dev_clk_time->dev_clk_time_ns = dev_time;
- return 0;
+free_resp:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -192,27 +203,29 @@ int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
struct idpf_ptp_dev_timers *cross_time)
{
- struct virtchnl2_ptp_get_cross_time cross_time_msg;
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
- .send_buf.iov_base = &cross_time_msg,
- .send_buf.iov_len = sizeof(cross_time_msg),
- .recv_buf.iov_base = &cross_time_msg,
- .recv_buf.iov_len = sizeof(cross_time_msg),
+ struct virtchnl2_ptp_get_cross_time cross_time_send, *cross_time_recv;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ int err = 0;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(cross_time_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &cross_time_send);
+ if (err)
+ return err;
- cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_msg.dev_time_ns);
- cross_time->sys_time_ns = le64_to_cpu(cross_time_msg.sys_time_ns);
+ if (xn_params.recv_mem.iov_len != sizeof(*cross_time_recv)) {
+ err = -EIO;
+ goto free_resp;
+ }
- return 0;
+ cross_time_recv = xn_params.recv_mem.iov_base;
+ cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_recv->dev_time_ns);
+ cross_time->sys_time_ns = le64_to_cpu(cross_time_recv->sys_time_ns);
+
+free_resp:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -229,23 +242,18 @@ int idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, u64 time)
struct virtchnl2_ptp_set_dev_clk_time set_dev_clk_time_msg = {
.dev_time_ns = cpu_to_le64(time),
};
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,
- .send_buf.iov_base = &set_dev_clk_time_msg,
- .send_buf.iov_len = sizeof(set_dev_clk_time_msg),
- .recv_buf.iov_base = &set_dev_clk_time_msg,
- .recv_buf.iov_len = sizeof(set_dev_clk_time_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ int err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(set_dev_clk_time_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params,
+ &set_dev_clk_time_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -262,23 +270,18 @@ int idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, s64 delta)
struct virtchnl2_ptp_adj_dev_clk_time adj_dev_clk_time_msg = {
.delta = cpu_to_le64(delta),
};
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,
- .send_buf.iov_base = &adj_dev_clk_time_msg,
- .send_buf.iov_len = sizeof(adj_dev_clk_time_msg),
- .recv_buf.iov_base = &adj_dev_clk_time_msg,
- .recv_buf.iov_len = sizeof(adj_dev_clk_time_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ int err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(adj_dev_clk_time_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params,
+ &adj_dev_clk_time_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -296,23 +299,18 @@ int idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, u64 incval)
struct virtchnl2_ptp_adj_dev_clk_fine adj_dev_clk_fine_msg = {
.incval = cpu_to_le64(incval),
};
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,
- .send_buf.iov_base = &adj_dev_clk_fine_msg,
- .send_buf.iov_len = sizeof(adj_dev_clk_fine_msg),
- .recv_buf.iov_base = &adj_dev_clk_fine_msg,
- .recv_buf.iov_len = sizeof(adj_dev_clk_fine_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ int err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(adj_dev_clk_fine_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params,
+ &adj_dev_clk_fine_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -331,18 +329,16 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
struct virtchnl2_ptp_tx_tstamp_latch_caps tx_tstamp_latch_caps;
struct idpf_ptp_vport_tx_tstamp_caps *tstamp_caps;
struct idpf_ptp_tx_tstamp *ptp_tx_tstamp, *tmp;
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,
- .send_buf.iov_base = &send_tx_tstamp_caps,
- .send_buf.iov_len = sizeof(send_tx_tstamp_caps),
- .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
enum idpf_ptp_access tstamp_access, get_dev_clk_access;
struct idpf_ptp *ptp = vport->adapter->ptp;
struct list_head *head;
- int err = 0, reply_sz;
+ size_t reply_sz;
u16 num_latches;
+ int err = 0;
u32 size;
if (!ptp)
@@ -354,19 +350,19 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
get_dev_clk_access == IDPF_PTP_NONE)
return -EOPNOTSUPP;
- rcv_tx_tstamp_caps = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcv_tx_tstamp_caps)
- return -ENOMEM;
-
send_tx_tstamp_caps.vport_id = cpu_to_le32(vport->vport_id);
- xn_params.recv_buf.iov_base = rcv_tx_tstamp_caps;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0) {
- err = reply_sz;
+ err = idpf_send_mb_msg_stack(vport->adapter, &xn_params,
+ &send_tx_tstamp_caps);
+ if (err)
+ return err;
+
+ rcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz < sizeof(*rcv_tx_tstamp_caps)) {
+ err = -EIO;
goto get_tstamp_caps_out;
}
-
num_latches = le16_to_cpu(rcv_tx_tstamp_caps->num_latches);
size = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);
if (reply_sz != size) {
@@ -395,7 +391,7 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
for (u16 i = 0; i < tstamp_caps->num_entries; i++) {
__le32 offset_l, offset_h;
- ptp_tx_tstamp = kzalloc(sizeof(*ptp_tx_tstamp), GFP_KERNEL);
+ ptp_tx_tstamp = kzalloc_obj(*ptp_tx_tstamp);
if (!ptp_tx_tstamp) {
err = -ENOMEM;
goto err_free_ptp_tx_stamp_list;
@@ -421,7 +417,7 @@ skip_offsets:
}
vport->tx_tstamp_caps = tstamp_caps;
- kfree(rcv_tx_tstamp_caps);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
return 0;
@@ -434,7 +430,7 @@ err_free_ptp_tx_stamp_list:
kfree(tstamp_caps);
get_tstamp_caps_out:
- kfree(rcv_tx_tstamp_caps);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
return err;
}
@@ -531,9 +527,9 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
/**
* idpf_ptp_get_tx_tstamp_async_handler - Async callback for getting Tx tstamps
- * @adapter: Driver specific private structure
- * @xn: transaction for message
- * @ctlq_msg: received message
+ * @ctx: adapter pointer
+ * @mem: address and size of the response
+ * @status: return value of the request
*
* Read the tstamps Tx tstamp values from a received message and put them
* directly to the skb. The number of timestamps to read is specified by
@@ -541,22 +537,26 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
*
* Return: 0 on success, -errno otherwise.
*/
-static int
-idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
- struct idpf_vc_xn *xn,
- const struct idpf_ctlq_msg *ctlq_msg)
+static void
+idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)
{
struct virtchnl2_ptp_get_vport_tx_tstamp_latches *recv_tx_tstamp_msg;
struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
struct virtchnl2_ptp_tx_tstamp_latch tstamp_latch;
struct idpf_ptp_tx_tstamp *tx_tstamp, *tmp;
struct idpf_vport *tstamp_vport = NULL;
+ struct idpf_adapter *adapter = ctx;
struct list_head *head;
u16 num_latches;
u32 vport_id;
- int err = 0;
- recv_tx_tstamp_msg = ctlq_msg->ctx.indirect.payload->va;
+ if (status)
+ return;
+
+ recv_tx_tstamp_msg = mem->iov_base;
+ if (mem->iov_len < sizeof(*recv_tx_tstamp_msg))
+ return;
+
vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);
idpf_for_each_vport(adapter, vport) {
@@ -570,10 +570,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
}
if (!tstamp_vport || !tstamp_vport->tx_tstamp_caps)
- return -EINVAL;
+ return;
tx_tstamp_caps = tstamp_vport->tx_tstamp_caps;
num_latches = le16_to_cpu(recv_tx_tstamp_msg->num_latches);
+ if (mem->iov_len < struct_size(recv_tx_tstamp_msg, tstamp_latches,
+ num_latches))
+ return;
spin_lock_bh(&tx_tstamp_caps->latches_lock);
head = &tx_tstamp_caps->latches_in_use;
@@ -584,13 +587,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
if (!tstamp_latch.valid)
continue;
- if (list_empty(head)) {
- err = -ENOBUFS;
+ if (list_empty(head))
goto unlock;
- }
list_for_each_entry_safe(tx_tstamp, tmp, head, list_member) {
if (tstamp_latch.index == tx_tstamp->idx) {
+ int err;
+
list_del(&tx_tstamp->list_member);
err = idpf_ptp_get_tstamp_value(tstamp_vport,
&tstamp_latch,
@@ -605,8 +608,6 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
unlock:
spin_unlock_bh(&tx_tstamp_caps->latches_lock);
-
- return err;
}
/**
@@ -622,15 +623,15 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
{
struct virtchnl2_ptp_get_vport_tx_tstamp_latches *send_tx_tstamp_msg;
struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
- .async = true,
- .async_handler = idpf_ptp_get_tx_tstamp_async_handler,
+ .resp_cb = idpf_ptp_get_tx_tstamp_async_handler,
+ .send_ctx = vport->adapter,
};
struct idpf_ptp_tx_tstamp *ptp_tx_tstamp;
- int reply_sz, size, msg_size;
struct list_head *head;
+ int size, msg_size;
bool state_upd;
u16 id = 0;
@@ -663,11 +664,7 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
msg_size = struct_size(send_tx_tstamp_msg, tstamp_latches, id);
send_tx_tstamp_msg->vport_id = cpu_to_le32(vport->vport_id);
send_tx_tstamp_msg->num_latches = cpu_to_le16(id);
- xn_params.send_buf.iov_base = send_tx_tstamp_msg;
- xn_params.send_buf.iov_len = msg_size;
-
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- kfree(send_tx_tstamp_msg);
- return min(reply_sz, 0);
+ return idpf_send_mb_msg_kfree(vport->adapter, &xn_params,
+ send_tx_tstamp_msg, msg_size);
}
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/drivers/net/ethernet/intel/idpf/virtchnl2.h
deleted file mode 100644
index 02ae447cc24a..000000000000
--- a/drivers/net/ethernet/intel/idpf/virtchnl2.h
+++ /dev/null
@@ -1,1813 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _VIRTCHNL2_H_
-#define _VIRTCHNL2_H_
-
-#include <linux/if_ether.h>
-
-/* All opcodes associated with virtchnl2 are prefixed with virtchnl2 or
- * VIRTCHNL2. Any future opcodes, offloads/capabilities, structures,
- * and defines must be prefixed with virtchnl2 or VIRTCHNL2 to avoid confusion.
- *
- * PF/VF uses the virtchnl2 interface defined in this header file to communicate
- * with device Control Plane (CP). Driver and the CP may run on different
- * platforms with different endianness. To avoid byte order discrepancies,
- * all the structures in this header follow little-endian format.
- *
- * This is an interface definition file where existing enums and their values
- * must remain unchanged over time, so we specify explicit values for all enums.
- */
-
-/* This macro is used to generate compilation errors if a structure
- * is not exactly the correct length.
- */
-#define VIRTCHNL2_CHECK_STRUCT_LEN(n, X) \
- static_assert((n) == sizeof(struct X))
-
-/* New major set of opcodes introduced and so leaving room for
- * old misc opcodes to be added in future. Also these opcodes may only
- * be used if both the PF and VF have successfully negotiated the
- * VIRTCHNL version as 2.0 during VIRTCHNL2_OP_VERSION exchange.
- */
-enum virtchnl2_op {
- VIRTCHNL2_OP_UNKNOWN = 0,
- VIRTCHNL2_OP_VERSION = 1,
- VIRTCHNL2_OP_GET_CAPS = 500,
- VIRTCHNL2_OP_CREATE_VPORT = 501,
- VIRTCHNL2_OP_DESTROY_VPORT = 502,
- VIRTCHNL2_OP_ENABLE_VPORT = 503,
- VIRTCHNL2_OP_DISABLE_VPORT = 504,
- VIRTCHNL2_OP_CONFIG_TX_QUEUES = 505,
- VIRTCHNL2_OP_CONFIG_RX_QUEUES = 506,
- VIRTCHNL2_OP_ENABLE_QUEUES = 507,
- VIRTCHNL2_OP_DISABLE_QUEUES = 508,
- VIRTCHNL2_OP_ADD_QUEUES = 509,
- VIRTCHNL2_OP_DEL_QUEUES = 510,
- VIRTCHNL2_OP_MAP_QUEUE_VECTOR = 511,
- VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR = 512,
- VIRTCHNL2_OP_GET_RSS_KEY = 513,
- VIRTCHNL2_OP_SET_RSS_KEY = 514,
- VIRTCHNL2_OP_GET_RSS_LUT = 515,
- VIRTCHNL2_OP_SET_RSS_LUT = 516,
- VIRTCHNL2_OP_GET_RSS_HASH = 517,
- VIRTCHNL2_OP_SET_RSS_HASH = 518,
- VIRTCHNL2_OP_SET_SRIOV_VFS = 519,
- VIRTCHNL2_OP_ALLOC_VECTORS = 520,
- VIRTCHNL2_OP_DEALLOC_VECTORS = 521,
- VIRTCHNL2_OP_EVENT = 522,
- VIRTCHNL2_OP_GET_STATS = 523,
- VIRTCHNL2_OP_RESET_VF = 524,
- VIRTCHNL2_OP_GET_EDT_CAPS = 525,
- VIRTCHNL2_OP_GET_PTYPE_INFO = 526,
- /* Opcode 527 and 528 are reserved for VIRTCHNL2_OP_GET_PTYPE_ID and
- * VIRTCHNL2_OP_GET_PTYPE_INFO_RAW.
- */
- VIRTCHNL2_OP_RDMA = 529,
- /* Opcodes 530 through 533 are reserved. */
- VIRTCHNL2_OP_LOOPBACK = 534,
- VIRTCHNL2_OP_ADD_MAC_ADDR = 535,
- VIRTCHNL2_OP_DEL_MAC_ADDR = 536,
- VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE = 537,
-
- /* TimeSync opcodes */
- VIRTCHNL2_OP_PTP_GET_CAPS = 541,
- VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP = 542,
- VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME = 543,
- VIRTCHNL2_OP_PTP_GET_CROSS_TIME = 544,
- VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME = 545,
- VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE = 546,
- VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME = 547,
- VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS = 548,
- VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS = 549,
- /* Opcode 550 is reserved */
- VIRTCHNL2_OP_ADD_FLOW_RULE = 551,
- VIRTCHNL2_OP_GET_FLOW_RULE = 552,
- VIRTCHNL2_OP_DEL_FLOW_RULE = 553,
-};
-
-/**
- * enum virtchnl2_vport_type - Type of virtual port.
- * @VIRTCHNL2_VPORT_TYPE_DEFAULT: Default virtual port type.
- */
-enum virtchnl2_vport_type {
- VIRTCHNL2_VPORT_TYPE_DEFAULT = 0,
-};
-
-/**
- * enum virtchnl2_queue_model - Type of queue model.
- * @VIRTCHNL2_QUEUE_MODEL_SINGLE: Single queue model.
- * @VIRTCHNL2_QUEUE_MODEL_SPLIT: Split queue model.
- *
- * In the single queue model, the same transmit descriptor queue is used by
- * software to post descriptors to hardware and by hardware to post completed
- * descriptors to software.
- * Likewise, the same receive descriptor queue is used by hardware to post
- * completions to software and by software to post buffers to hardware.
- *
- * In the split queue model, hardware uses transmit completion queues to post
- * descriptor/buffer completions to software, while software uses transmit
- * descriptor queues to post descriptors to hardware.
- * Likewise, hardware posts descriptor completions to the receive descriptor
- * queue, while software uses receive buffer queues to post buffers to hardware.
- */
-enum virtchnl2_queue_model {
- VIRTCHNL2_QUEUE_MODEL_SINGLE = 0,
- VIRTCHNL2_QUEUE_MODEL_SPLIT = 1,
-};
-
-/* Checksum offload capability flags */
-enum virtchnl2_cap_txrx_csum {
- VIRTCHNL2_CAP_TX_CSUM_L3_IPV4 = BIT(0),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_TCP = BIT(1),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_UDP = BIT(2),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_SCTP = BIT(3),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_TCP = BIT(4),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_UDP = BIT(5),
- VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_SCTP = BIT(6),
- VIRTCHNL2_CAP_TX_CSUM_GENERIC = BIT(7),
- VIRTCHNL2_CAP_RX_CSUM_L3_IPV4 = BIT(8),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_TCP = BIT(9),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_UDP = BIT(10),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_SCTP = BIT(11),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_TCP = BIT(12),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_UDP = BIT(13),
- VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_SCTP = BIT(14),
- VIRTCHNL2_CAP_RX_CSUM_GENERIC = BIT(15),
- VIRTCHNL2_CAP_TX_CSUM_L3_SINGLE_TUNNEL = BIT(16),
- VIRTCHNL2_CAP_TX_CSUM_L3_DOUBLE_TUNNEL = BIT(17),
- VIRTCHNL2_CAP_RX_CSUM_L3_SINGLE_TUNNEL = BIT(18),
- VIRTCHNL2_CAP_RX_CSUM_L3_DOUBLE_TUNNEL = BIT(19),
- VIRTCHNL2_CAP_TX_CSUM_L4_SINGLE_TUNNEL = BIT(20),
- VIRTCHNL2_CAP_TX_CSUM_L4_DOUBLE_TUNNEL = BIT(21),
- VIRTCHNL2_CAP_RX_CSUM_L4_SINGLE_TUNNEL = BIT(22),
- VIRTCHNL2_CAP_RX_CSUM_L4_DOUBLE_TUNNEL = BIT(23),
-};
-
-/* Segmentation offload capability flags */
-enum virtchnl2_cap_seg {
- VIRTCHNL2_CAP_SEG_IPV4_TCP = BIT(0),
- VIRTCHNL2_CAP_SEG_IPV4_UDP = BIT(1),
- VIRTCHNL2_CAP_SEG_IPV4_SCTP = BIT(2),
- VIRTCHNL2_CAP_SEG_IPV6_TCP = BIT(3),
- VIRTCHNL2_CAP_SEG_IPV6_UDP = BIT(4),
- VIRTCHNL2_CAP_SEG_IPV6_SCTP = BIT(5),
- VIRTCHNL2_CAP_SEG_GENERIC = BIT(6),
- VIRTCHNL2_CAP_SEG_TX_SINGLE_TUNNEL = BIT(7),
- VIRTCHNL2_CAP_SEG_TX_DOUBLE_TUNNEL = BIT(8),
-};
-
-/* Receive Side Scaling and Flow Steering Flow type capability flags */
-enum virtchnl2_flow_types {
- VIRTCHNL2_FLOW_IPV4_TCP = BIT(0),
- VIRTCHNL2_FLOW_IPV4_UDP = BIT(1),
- VIRTCHNL2_FLOW_IPV4_SCTP = BIT(2),
- VIRTCHNL2_FLOW_IPV4_OTHER = BIT(3),
- VIRTCHNL2_FLOW_IPV6_TCP = BIT(4),
- VIRTCHNL2_FLOW_IPV6_UDP = BIT(5),
- VIRTCHNL2_FLOW_IPV6_SCTP = BIT(6),
- VIRTCHNL2_FLOW_IPV6_OTHER = BIT(7),
- VIRTCHNL2_FLOW_IPV4_AH = BIT(8),
- VIRTCHNL2_FLOW_IPV4_ESP = BIT(9),
- VIRTCHNL2_FLOW_IPV4_AH_ESP = BIT(10),
- VIRTCHNL2_FLOW_IPV6_AH = BIT(11),
- VIRTCHNL2_FLOW_IPV6_ESP = BIT(12),
- VIRTCHNL2_FLOW_IPV6_AH_ESP = BIT(13),
-};
-
-/* Header split capability flags */
-enum virtchnl2_cap_rx_hsplit_at {
- /* for prepended metadata */
- VIRTCHNL2_CAP_RX_HSPLIT_AT_L2 = BIT(0),
- /* all VLANs go into header buffer */
- VIRTCHNL2_CAP_RX_HSPLIT_AT_L3 = BIT(1),
- VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V4 = BIT(2),
- VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V6 = BIT(3),
-};
-
-/* Receive Side Coalescing offload capability flags */
-enum virtchnl2_cap_rsc {
- VIRTCHNL2_CAP_RSC_IPV4_TCP = BIT(0),
- VIRTCHNL2_CAP_RSC_IPV4_SCTP = BIT(1),
- VIRTCHNL2_CAP_RSC_IPV6_TCP = BIT(2),
- VIRTCHNL2_CAP_RSC_IPV6_SCTP = BIT(3),
-};
-
-/* Other capability flags */
-enum virtchnl2_cap_other {
- VIRTCHNL2_CAP_RDMA = BIT_ULL(0),
- VIRTCHNL2_CAP_SRIOV = BIT_ULL(1),
- VIRTCHNL2_CAP_MACFILTER = BIT_ULL(2),
- /* Other capability 3 is available
- * Queue based scheduling using split queue model
- */
- VIRTCHNL2_CAP_SPLITQ_QSCHED = BIT_ULL(4),
- VIRTCHNL2_CAP_CRC = BIT_ULL(5),
- VIRTCHNL2_CAP_ADQ = BIT_ULL(6),
- VIRTCHNL2_CAP_WB_ON_ITR = BIT_ULL(7),
- VIRTCHNL2_CAP_PROMISC = BIT_ULL(8),
- VIRTCHNL2_CAP_LINK_SPEED = BIT_ULL(9),
- VIRTCHNL2_CAP_INLINE_IPSEC = BIT_ULL(10),
- VIRTCHNL2_CAP_LARGE_NUM_QUEUES = BIT_ULL(11),
- VIRTCHNL2_CAP_VLAN = BIT_ULL(12),
- VIRTCHNL2_CAP_PTP = BIT_ULL(13),
- /* EDT: Earliest Departure Time capability used for Timing Wheel */
- VIRTCHNL2_CAP_EDT = BIT_ULL(14),
- VIRTCHNL2_CAP_ADV_RSS = BIT_ULL(15),
- /* Other capability 16 is available */
- VIRTCHNL2_CAP_RX_FLEX_DESC = BIT_ULL(17),
- VIRTCHNL2_CAP_PTYPE = BIT_ULL(18),
- VIRTCHNL2_CAP_LOOPBACK = BIT_ULL(19),
- /* Other capability 20 is reserved */
- VIRTCHNL2_CAP_FLOW_STEER = BIT_ULL(21),
- VIRTCHNL2_CAP_LAN_MEMORY_REGIONS = BIT_ULL(22),
-
- /* this must be the last capability */
- VIRTCHNL2_CAP_OEM = BIT_ULL(63),
-};
-
-/**
- * enum virtchnl2_action_types - Available actions for sideband flow steering
- * @VIRTCHNL2_ACTION_DROP: Drop the packet
- * @VIRTCHNL2_ACTION_PASSTHRU: Forward the packet to the next classifier/stage
- * @VIRTCHNL2_ACTION_QUEUE: Forward the packet to a receive queue
- * @VIRTCHNL2_ACTION_Q_GROUP: Forward the packet to a receive queue group
- * @VIRTCHNL2_ACTION_MARK: Mark the packet with specific marker value
- * @VIRTCHNL2_ACTION_COUNT: Increment the corresponding counter
- */
-
-enum virtchnl2_action_types {
- VIRTCHNL2_ACTION_DROP = BIT(0),
- VIRTCHNL2_ACTION_PASSTHRU = BIT(1),
- VIRTCHNL2_ACTION_QUEUE = BIT(2),
- VIRTCHNL2_ACTION_Q_GROUP = BIT(3),
- VIRTCHNL2_ACTION_MARK = BIT(4),
- VIRTCHNL2_ACTION_COUNT = BIT(5),
-};
-
-/* underlying device type */
-enum virtchl2_device_type {
- VIRTCHNL2_MEV_DEVICE = 0,
-};
-
-/**
- * enum virtchnl2_txq_sched_mode - Transmit Queue Scheduling Modes.
- * @VIRTCHNL2_TXQ_SCHED_MODE_QUEUE: Queue mode is the legacy mode i.e. inorder
- * completions where descriptors and buffers
- * are completed at the same time.
- * @VIRTCHNL2_TXQ_SCHED_MODE_FLOW: Flow scheduling mode allows for out of order
- * packet processing where descriptors are
- * cleaned in order, but buffers can be
- * completed out of order.
- */
-enum virtchnl2_txq_sched_mode {
- VIRTCHNL2_TXQ_SCHED_MODE_QUEUE = 0,
- VIRTCHNL2_TXQ_SCHED_MODE_FLOW = 1,
-};
-
-/**
- * enum virtchnl2_rxq_flags - Receive Queue Feature flags.
- * @VIRTCHNL2_RXQ_RSC: Rx queue RSC flag.
- * @VIRTCHNL2_RXQ_HDR_SPLIT: Rx queue header split flag.
- * @VIRTCHNL2_RXQ_IMMEDIATE_WRITE_BACK: When set, packet descriptors are flushed
- * by hardware immediately after processing
- * each packet.
- * @VIRTCHNL2_RX_DESC_SIZE_16BYTE: Rx queue 16 byte descriptor size.
- * @VIRTCHNL2_RX_DESC_SIZE_32BYTE: Rx queue 32 byte descriptor size.
- */
-enum virtchnl2_rxq_flags {
- VIRTCHNL2_RXQ_RSC = BIT(0),
- VIRTCHNL2_RXQ_HDR_SPLIT = BIT(1),
- VIRTCHNL2_RXQ_IMMEDIATE_WRITE_BACK = BIT(2),
- VIRTCHNL2_RX_DESC_SIZE_16BYTE = BIT(3),
- VIRTCHNL2_RX_DESC_SIZE_32BYTE = BIT(4),
-};
-
-/* Type of RSS algorithm */
-enum virtchnl2_rss_alg {
- VIRTCHNL2_RSS_ALG_TOEPLITZ_ASYMMETRIC = 0,
- VIRTCHNL2_RSS_ALG_R_ASYMMETRIC = 1,
- VIRTCHNL2_RSS_ALG_TOEPLITZ_SYMMETRIC = 2,
- VIRTCHNL2_RSS_ALG_XOR_SYMMETRIC = 3,
-};
-
-/* Type of event */
-enum virtchnl2_event_codes {
- VIRTCHNL2_EVENT_UNKNOWN = 0,
- VIRTCHNL2_EVENT_LINK_CHANGE = 1,
- /* Event type 2, 3 are reserved */
-};
-
-/* Transmit and Receive queue types are valid in legacy as well as split queue
- * models. With Split Queue model, 2 additional types are introduced -
- * TX_COMPLETION and RX_BUFFER. In split queue model, receive corresponds to
- * the queue where hardware posts completions.
- */
-enum virtchnl2_queue_type {
- VIRTCHNL2_QUEUE_TYPE_TX = 0,
- VIRTCHNL2_QUEUE_TYPE_RX = 1,
- VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION = 2,
- VIRTCHNL2_QUEUE_TYPE_RX_BUFFER = 3,
- VIRTCHNL2_QUEUE_TYPE_CONFIG_TX = 4,
- VIRTCHNL2_QUEUE_TYPE_CONFIG_RX = 5,
- /* Queue types 6, 7, 8, 9 are reserved */
- VIRTCHNL2_QUEUE_TYPE_MBX_TX = 10,
- VIRTCHNL2_QUEUE_TYPE_MBX_RX = 11,
-};
-
-/* Interrupt throttling rate index */
-enum virtchnl2_itr_idx {
- VIRTCHNL2_ITR_IDX_0 = 0,
- VIRTCHNL2_ITR_IDX_1 = 1,
-};
-
-/**
- * enum virtchnl2_mac_addr_type - MAC address types.
- * @VIRTCHNL2_MAC_ADDR_PRIMARY: PF/VF driver should set this type for the
- * primary/device unicast MAC address filter for
- * VIRTCHNL2_OP_ADD_MAC_ADDR and
- * VIRTCHNL2_OP_DEL_MAC_ADDR. This allows for the
- * underlying control plane function to accurately
- * track the MAC address and for VM/function reset.
- *
- * @VIRTCHNL2_MAC_ADDR_EXTRA: PF/VF driver should set this type for any extra
- * unicast and/or multicast filters that are being
- * added/deleted via VIRTCHNL2_OP_ADD_MAC_ADDR or
- * VIRTCHNL2_OP_DEL_MAC_ADDR.
- */
-enum virtchnl2_mac_addr_type {
- VIRTCHNL2_MAC_ADDR_PRIMARY = 1,
- VIRTCHNL2_MAC_ADDR_EXTRA = 2,
-};
-
-/* Flags used for promiscuous mode */
-enum virtchnl2_promisc_flags {
- VIRTCHNL2_UNICAST_PROMISC = BIT(0),
- VIRTCHNL2_MULTICAST_PROMISC = BIT(1),
-};
-
-/* Protocol header type within a packet segment. A segment consists of one or
- * more protocol headers that make up a logical group of protocol headers. Each
- * logical group of protocol headers encapsulates or is encapsulated using/by
- * tunneling or encapsulation protocols for network virtualization.
- */
-enum virtchnl2_proto_hdr_type {
- /* VIRTCHNL2_PROTO_HDR_ANY is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_ANY = 0,
- VIRTCHNL2_PROTO_HDR_PRE_MAC = 1,
- /* VIRTCHNL2_PROTO_HDR_MAC is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_MAC = 2,
- VIRTCHNL2_PROTO_HDR_POST_MAC = 3,
- VIRTCHNL2_PROTO_HDR_ETHERTYPE = 4,
- VIRTCHNL2_PROTO_HDR_VLAN = 5,
- VIRTCHNL2_PROTO_HDR_SVLAN = 6,
- VIRTCHNL2_PROTO_HDR_CVLAN = 7,
- VIRTCHNL2_PROTO_HDR_MPLS = 8,
- VIRTCHNL2_PROTO_HDR_UMPLS = 9,
- VIRTCHNL2_PROTO_HDR_MMPLS = 10,
- VIRTCHNL2_PROTO_HDR_PTP = 11,
- VIRTCHNL2_PROTO_HDR_CTRL = 12,
- VIRTCHNL2_PROTO_HDR_LLDP = 13,
- VIRTCHNL2_PROTO_HDR_ARP = 14,
- VIRTCHNL2_PROTO_HDR_ECP = 15,
- VIRTCHNL2_PROTO_HDR_EAPOL = 16,
- VIRTCHNL2_PROTO_HDR_PPPOD = 17,
- VIRTCHNL2_PROTO_HDR_PPPOE = 18,
- /* VIRTCHNL2_PROTO_HDR_IPV4 is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_IPV4 = 19,
- /* IPv4 and IPv6 Fragment header types are only associated to
- * VIRTCHNL2_PROTO_HDR_IPV4 and VIRTCHNL2_PROTO_HDR_IPV6 respectively,
- * cannot be used independently.
- */
- /* VIRTCHNL2_PROTO_HDR_IPV4_FRAG is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_IPV4_FRAG = 20,
- /* VIRTCHNL2_PROTO_HDR_IPV6 is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_IPV6 = 21,
- /* VIRTCHNL2_PROTO_HDR_IPV6_FRAG is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_IPV6_FRAG = 22,
- VIRTCHNL2_PROTO_HDR_IPV6_EH = 23,
- /* VIRTCHNL2_PROTO_HDR_UDP is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_UDP = 24,
- /* VIRTCHNL2_PROTO_HDR_TCP is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_TCP = 25,
- /* VIRTCHNL2_PROTO_HDR_SCTP is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_SCTP = 26,
- /* VIRTCHNL2_PROTO_HDR_ICMP is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_ICMP = 27,
- /* VIRTCHNL2_PROTO_HDR_ICMPV6 is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_ICMPV6 = 28,
- VIRTCHNL2_PROTO_HDR_IGMP = 29,
- VIRTCHNL2_PROTO_HDR_AH = 30,
- VIRTCHNL2_PROTO_HDR_ESP = 31,
- VIRTCHNL2_PROTO_HDR_IKE = 32,
- VIRTCHNL2_PROTO_HDR_NATT_KEEP = 33,
- /* VIRTCHNL2_PROTO_HDR_PAY is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_PAY = 34,
- VIRTCHNL2_PROTO_HDR_L2TPV2 = 35,
- VIRTCHNL2_PROTO_HDR_L2TPV2_CONTROL = 36,
- VIRTCHNL2_PROTO_HDR_L2TPV3 = 37,
- VIRTCHNL2_PROTO_HDR_GTP = 38,
- VIRTCHNL2_PROTO_HDR_GTP_EH = 39,
- VIRTCHNL2_PROTO_HDR_GTPCV2 = 40,
- VIRTCHNL2_PROTO_HDR_GTPC_TEID = 41,
- VIRTCHNL2_PROTO_HDR_GTPU = 42,
- VIRTCHNL2_PROTO_HDR_GTPU_UL = 43,
- VIRTCHNL2_PROTO_HDR_GTPU_DL = 44,
- VIRTCHNL2_PROTO_HDR_ECPRI = 45,
- VIRTCHNL2_PROTO_HDR_VRRP = 46,
- VIRTCHNL2_PROTO_HDR_OSPF = 47,
- /* VIRTCHNL2_PROTO_HDR_TUN is a mandatory protocol id */
- VIRTCHNL2_PROTO_HDR_TUN = 48,
- VIRTCHNL2_PROTO_HDR_GRE = 49,
- VIRTCHNL2_PROTO_HDR_NVGRE = 50,
- VIRTCHNL2_PROTO_HDR_VXLAN = 51,
- VIRTCHNL2_PROTO_HDR_VXLAN_GPE = 52,
- VIRTCHNL2_PROTO_HDR_GENEVE = 53,
- VIRTCHNL2_PROTO_HDR_NSH = 54,
- VIRTCHNL2_PROTO_HDR_QUIC = 55,
- VIRTCHNL2_PROTO_HDR_PFCP = 56,
- VIRTCHNL2_PROTO_HDR_PFCP_NODE = 57,
- VIRTCHNL2_PROTO_HDR_PFCP_SESSION = 58,
- VIRTCHNL2_PROTO_HDR_RTP = 59,
- VIRTCHNL2_PROTO_HDR_ROCE = 60,
- VIRTCHNL2_PROTO_HDR_ROCEV1 = 61,
- VIRTCHNL2_PROTO_HDR_ROCEV2 = 62,
- /* Protocol ids up to 32767 are reserved.
- * 32768 - 65534 are used for user defined protocol ids.
- * VIRTCHNL2_PROTO_HDR_NO_PROTO is a mandatory protocol id.
- */
- VIRTCHNL2_PROTO_HDR_NO_PROTO = 65535,
-};
-
-enum virtchl2_version {
- VIRTCHNL2_VERSION_MINOR_0 = 0,
- VIRTCHNL2_VERSION_MAJOR_2 = 2,
-};
-
-/**
- * struct virtchnl2_edt_caps - Get EDT granularity and time horizon.
- * @tstamp_granularity_ns: Timestamp granularity in nanoseconds.
- * @time_horizon_ns: Total time window in nanoseconds.
- *
- * Associated with VIRTCHNL2_OP_GET_EDT_CAPS.
- */
-struct virtchnl2_edt_caps {
- __le64 tstamp_granularity_ns;
- __le64 time_horizon_ns;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_edt_caps);
-
-/**
- * struct virtchnl2_version_info - Version information.
- * @major: Major version.
- * @minor: Minor version.
- *
- * PF/VF posts its version number to the CP. CP responds with its version number
- * in the same format, along with a return code.
- * If there is a major version mismatch, then the PF/VF cannot operate.
- * If there is a minor version mismatch, then the PF/VF can operate but should
- * add a warning to the system log.
- *
- * This version opcode MUST always be specified as == 1, regardless of other
- * changes in the API. The CP must always respond to this message without
- * error regardless of version mismatch.
- *
- * Associated with VIRTCHNL2_OP_VERSION.
- */
-struct virtchnl2_version_info {
- __le32 major;
- __le32 minor;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_version_info);
-
-/**
- * struct virtchnl2_get_capabilities - Capabilities info.
- * @csum_caps: See enum virtchnl2_cap_txrx_csum.
- * @seg_caps: See enum virtchnl2_cap_seg.
- * @hsplit_caps: See enum virtchnl2_cap_rx_hsplit_at.
- * @rsc_caps: See enum virtchnl2_cap_rsc.
- * @rss_caps: See enum virtchnl2_flow_types.
- * @other_caps: See enum virtchnl2_cap_other.
- * @mailbox_dyn_ctl: DYN_CTL register offset and vector id for mailbox
- * provided by CP.
- * @mailbox_vector_id: Mailbox vector id.
- * @num_allocated_vectors: Maximum number of allocated vectors for the device.
- * @max_rx_q: Maximum number of supported Rx queues.
- * @max_tx_q: Maximum number of supported Tx queues.
- * @max_rx_bufq: Maximum number of supported buffer queues.
- * @max_tx_complq: Maximum number of supported completion queues.
- * @max_sriov_vfs: The PF sends the maximum VFs it is requesting. The CP
- * responds with the maximum VFs granted.
- * @max_vports: Maximum number of vports that can be supported.
- * @default_num_vports: Default number of vports driver should allocate on load.
- * @max_tx_hdr_size: Max header length hardware can parse/checksum, in bytes.
- * @max_sg_bufs_per_tx_pkt: Max number of scatter gather buffers that can be
- * sent per transmit packet without needing to be
- * linearized.
- * @pad: Padding.
- * @reserved: Reserved.
- * @device_type: See enum virtchl2_device_type.
- * @min_sso_packet_len: Min packet length supported by device for single
- * segment offload.
- * @max_hdr_buf_per_lso: Max number of header buffers that can be used for
- * an LSO.
- * @num_rdma_allocated_vectors: Maximum number of allocated RDMA vectors for
- * the device.
- * @pad1: Padding for future extensions.
- *
- * Dataplane driver sends this message to CP to negotiate capabilities and
- * provides a virtchnl2_get_capabilities structure with its desired
- * capabilities, max_sriov_vfs and num_allocated_vectors.
- * CP responds with a virtchnl2_get_capabilities structure updated
- * with allowed capabilities and the other fields as below.
- * If PF sets max_sriov_vfs as 0, CP will respond with max number of VFs
- * that can be created by this PF. For any other value 'n', CP responds
- * with max_sriov_vfs set to min(n, x) where x is the max number of VFs
- * allowed by CP's policy. max_sriov_vfs is not applicable for VFs.
- * If dataplane driver sets num_allocated_vectors as 0, CP will respond with 1
- * which is default vector associated with the default mailbox. For any other
- * value 'n', CP responds with a value <= n based on the CP's policy of
- * max number of vectors for a PF.
- * CP will respond with the vector ID of mailbox allocated to the PF in
- * mailbox_vector_id and the number of itr index registers in itr_idx_map.
- * It also responds with default number of vports that the dataplane driver
- * should comeup with in default_num_vports and maximum number of vports that
- * can be supported in max_vports.
- *
- * Associated with VIRTCHNL2_OP_GET_CAPS.
- */
-struct virtchnl2_get_capabilities {
- __le32 csum_caps;
- __le32 seg_caps;
- __le32 hsplit_caps;
- __le32 rsc_caps;
- __le64 rss_caps;
- __le64 other_caps;
- __le32 mailbox_dyn_ctl;
- __le16 mailbox_vector_id;
- __le16 num_allocated_vectors;
- __le16 max_rx_q;
- __le16 max_tx_q;
- __le16 max_rx_bufq;
- __le16 max_tx_complq;
- __le16 max_sriov_vfs;
- __le16 max_vports;
- __le16 default_num_vports;
- __le16 max_tx_hdr_size;
- u8 max_sg_bufs_per_tx_pkt;
- u8 pad[3];
- u8 reserved[4];
- __le32 device_type;
- u8 min_sso_packet_len;
- u8 max_hdr_buf_per_lso;
- __le16 num_rdma_allocated_vectors;
- u8 pad1[8];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(80, virtchnl2_get_capabilities);
-
-/**
- * struct virtchnl2_queue_reg_chunk - Single queue chunk.
- * @type: See enum virtchnl2_queue_type.
- * @start_queue_id: Start Queue ID.
- * @num_queues: Number of queues in the chunk.
- * @pad: Padding.
- * @qtail_reg_start: Queue tail register offset.
- * @qtail_reg_spacing: Queue tail register spacing.
- * @pad1: Padding for future extensions.
- */
-struct virtchnl2_queue_reg_chunk {
- __le32 type;
- __le32 start_queue_id;
- __le32 num_queues;
- __le32 pad;
- __le64 qtail_reg_start;
- __le32 qtail_reg_spacing;
- u8 pad1[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(32, virtchnl2_queue_reg_chunk);
-
-/**
- * struct virtchnl2_queue_reg_chunks - Specify several chunks of contiguous
- * queues.
- * @num_chunks: Number of chunks.
- * @pad: Padding.
- * @chunks: Chunks of queue info.
- */
-struct virtchnl2_queue_reg_chunks {
- __le16 num_chunks;
- u8 pad[6];
- struct virtchnl2_queue_reg_chunk chunks[] __counted_by_le(num_chunks);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_queue_reg_chunks);
-
-/**
- * enum virtchnl2_vport_flags - Vport flags that indicate vport capabilities.
- * @VIRTCHNL2_VPORT_UPLINK_PORT: Representatives of underlying physical ports
- * @VIRTCHNL2_VPORT_INLINE_FLOW_STEER: Inline flow steering enabled
- * @VIRTCHNL2_VPORT_INLINE_FLOW_STEER_RXQ: Inline flow steering enabled
- * with explicit Rx queue action
- * @VIRTCHNL2_VPORT_SIDEBAND_FLOW_STEER: Sideband flow steering enabled
- * @VIRTCHNL2_VPORT_ENABLE_RDMA: RDMA is enabled for this vport
- */
-enum virtchnl2_vport_flags {
- VIRTCHNL2_VPORT_UPLINK_PORT = BIT(0),
- VIRTCHNL2_VPORT_INLINE_FLOW_STEER = BIT(1),
- VIRTCHNL2_VPORT_INLINE_FLOW_STEER_RXQ = BIT(2),
- VIRTCHNL2_VPORT_SIDEBAND_FLOW_STEER = BIT(3),
- VIRTCHNL2_VPORT_ENABLE_RDMA = BIT(4),
-};
-
-/**
- * struct virtchnl2_create_vport - Create vport config info.
- * @vport_type: See enum virtchnl2_vport_type.
- * @txq_model: See virtchnl2_queue_model.
- * @rxq_model: See virtchnl2_queue_model.
- * @num_tx_q: Number of Tx queues.
- * @num_tx_complq: Valid only if txq_model is split queue.
- * @num_rx_q: Number of Rx queues.
- * @num_rx_bufq: Valid only if rxq_model is split queue.
- * @default_rx_q: Relative receive queue index to be used as default.
- * @vport_index: Used to align PF and CP in case of default multiple vports,
- * it is filled by the PF and CP returns the same value, to
- * enable the driver to support multiple asynchronous parallel
- * CREATE_VPORT requests and associate a response to a specific
- * request.
- * @max_mtu: Max MTU. CP populates this field on response.
- * @vport_id: Vport id. CP populates this field on response.
- * @default_mac_addr: Default MAC address.
- * @vport_flags: See enum virtchnl2_vport_flags.
- * @rx_desc_ids: See VIRTCHNL2_RX_DESC_IDS definitions.
- * @tx_desc_ids: See VIRTCHNL2_TX_DESC_IDS definitions.
- * @pad1: Padding.
- * @inline_flow_caps: Bit mask of supported inline-flow-steering
- * flow types (See enum virtchnl2_flow_types)
- * @sideband_flow_caps: Bit mask of supported sideband-flow-steering
- * flow types (See enum virtchnl2_flow_types)
- * @sideband_flow_actions: Bit mask of supported action types
- * for sideband flow steering (See enum virtchnl2_action_types)
- * @flow_steer_max_rules: Max rules allowed for inline and sideband
- * flow steering combined
- * @rss_algorithm: RSS algorithm.
- * @rss_key_size: RSS key size.
- * @rss_lut_size: RSS LUT size.
- * @rx_split_pos: See enum virtchnl2_cap_rx_hsplit_at.
- * @pad2: Padding.
- * @chunks: Chunks of contiguous queues.
- *
- * PF sends this message to CP to create a vport by filling in required
- * fields of virtchnl2_create_vport structure.
- * CP responds with the updated virtchnl2_create_vport structure containing the
- * necessary fields followed by chunks which in turn will have an array of
- * num_chunks entries of virtchnl2_queue_chunk structures.
- *
- * Associated with VIRTCHNL2_OP_CREATE_VPORT.
- */
-struct virtchnl2_create_vport {
- __le16 vport_type;
- __le16 txq_model;
- __le16 rxq_model;
- __le16 num_tx_q;
- __le16 num_tx_complq;
- __le16 num_rx_q;
- __le16 num_rx_bufq;
- __le16 default_rx_q;
- __le16 vport_index;
- /* CP populates the following fields on response */
- __le16 max_mtu;
- __le32 vport_id;
- u8 default_mac_addr[ETH_ALEN];
- __le16 vport_flags;
- __le64 rx_desc_ids;
- __le64 tx_desc_ids;
- u8 pad1[48];
- __le64 inline_flow_caps;
- __le64 sideband_flow_caps;
- __le32 sideband_flow_actions;
- __le32 flow_steer_max_rules;
- __le32 rss_algorithm;
- __le16 rss_key_size;
- __le16 rss_lut_size;
- __le32 rx_split_pos;
- u8 pad2[20];
- struct virtchnl2_queue_reg_chunks chunks;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(160, virtchnl2_create_vport);
-
-/**
- * struct virtchnl2_vport - Vport ID info.
- * @vport_id: Vport id.
- * @pad: Padding for future extensions.
- *
- * PF sends this message to CP to destroy, enable or disable a vport by filling
- * in the vport_id in virtchnl2_vport structure.
- * CP responds with the status of the requested operation.
- *
- * Associated with VIRTCHNL2_OP_DESTROY_VPORT, VIRTCHNL2_OP_ENABLE_VPORT,
- * VIRTCHNL2_OP_DISABLE_VPORT.
- */
-struct virtchnl2_vport {
- __le32 vport_id;
- u8 pad[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_vport);
-
-/**
- * struct virtchnl2_txq_info - Transmit queue config info
- * @dma_ring_addr: DMA address.
- * @type: See enum virtchnl2_queue_type.
- * @queue_id: Queue ID.
- * @relative_queue_id: Valid only if queue model is split and type is transmit
- * queue. Used in many to one mapping of transmit queues to
- * completion queue.
- * @model: See enum virtchnl2_queue_model.
- * @sched_mode: See enum virtchnl2_txq_sched_mode.
- * @qflags: TX queue feature flags.
- * @ring_len: Ring length.
- * @tx_compl_queue_id: Valid only if queue model is split and type is transmit
- * queue.
- * @peer_type: Valid only if queue type is VIRTCHNL2_QUEUE_TYPE_MAILBOX_TX
- * @peer_rx_queue_id: Valid only if queue type is CONFIG_TX and used to deliver
- * messages for the respective CONFIG_TX queue.
- * @pad: Padding.
- * @egress_pasid: Egress PASID info.
- * @egress_hdr_pasid: Egress HDR passid.
- * @egress_buf_pasid: Egress buf passid.
- * @pad1: Padding for future extensions.
- */
-struct virtchnl2_txq_info {
- __le64 dma_ring_addr;
- __le32 type;
- __le32 queue_id;
- __le16 relative_queue_id;
- __le16 model;
- __le16 sched_mode;
- __le16 qflags;
- __le16 ring_len;
- __le16 tx_compl_queue_id;
- __le16 peer_type;
- __le16 peer_rx_queue_id;
- u8 pad[4];
- __le32 egress_pasid;
- __le32 egress_hdr_pasid;
- __le32 egress_buf_pasid;
- u8 pad1[8];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(56, virtchnl2_txq_info);
-
-/**
- * struct virtchnl2_config_tx_queues - TX queue config.
- * @vport_id: Vport id.
- * @num_qinfo: Number of virtchnl2_txq_info structs.
- * @pad: Padding.
- * @qinfo: Tx queues config info.
- *
- * PF sends this message to set up parameters for one or more transmit queues.
- * This message contains an array of num_qinfo instances of virtchnl2_txq_info
- * structures. CP configures requested queues and returns a status code. If
- * num_qinfo specified is greater than the number of queues associated with the
- * vport, an error is returned and no queues are configured.
- *
- * Associated with VIRTCHNL2_OP_CONFIG_TX_QUEUES.
- */
-struct virtchnl2_config_tx_queues {
- __le32 vport_id;
- __le16 num_qinfo;
- u8 pad[10];
- struct virtchnl2_txq_info qinfo[] __counted_by_le(num_qinfo);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_config_tx_queues);
-
-/**
- * struct virtchnl2_rxq_info - Receive queue config info.
- * @desc_ids: See VIRTCHNL2_RX_DESC_IDS definitions.
- * @dma_ring_addr: See VIRTCHNL2_RX_DESC_IDS definitions.
- * @type: See enum virtchnl2_queue_type.
- * @queue_id: Queue id.
- * @model: See enum virtchnl2_queue_model.
- * @hdr_buffer_size: Header buffer size.
- * @data_buffer_size: Data buffer size.
- * @max_pkt_size: Max packet size.
- * @ring_len: Ring length.
- * @buffer_notif_stride: Buffer notification stride in units of 32-descriptors.
- * This field must be a power of 2.
- * @pad: Padding.
- * @dma_head_wb_addr: Applicable only for receive buffer queues.
- * @qflags: Applicable only for receive completion queues.
- * See enum virtchnl2_rxq_flags.
- * @rx_buffer_low_watermark: Rx buffer low watermark.
- * @rx_bufq1_id: Buffer queue index of the first buffer queue associated with
- * the Rx queue. Valid only in split queue model.
- * @rx_bufq2_id: Buffer queue index of the second buffer queue associated with
- * the Rx queue. Valid only in split queue model.
- * @bufq2_ena: It indicates if there is a second buffer, rx_bufq2_id is valid
- * only if this field is set.
- * @pad1: Padding.
- * @ingress_pasid: Ingress PASID.
- * @ingress_hdr_pasid: Ingress PASID header.
- * @ingress_buf_pasid: Ingress PASID buffer.
- * @pad2: Padding for future extensions.
- */
-struct virtchnl2_rxq_info {
- __le64 desc_ids;
- __le64 dma_ring_addr;
- __le32 type;
- __le32 queue_id;
- __le16 model;
- __le16 hdr_buffer_size;
- __le32 data_buffer_size;
- __le32 max_pkt_size;
- __le16 ring_len;
- u8 buffer_notif_stride;
- u8 pad;
- __le64 dma_head_wb_addr;
- __le16 qflags;
- __le16 rx_buffer_low_watermark;
- __le16 rx_bufq1_id;
- __le16 rx_bufq2_id;
- u8 bufq2_ena;
- u8 pad1[3];
- __le32 ingress_pasid;
- __le32 ingress_hdr_pasid;
- __le32 ingress_buf_pasid;
- u8 pad2[16];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(88, virtchnl2_rxq_info);
-
-/**
- * struct virtchnl2_config_rx_queues - Rx queues config.
- * @vport_id: Vport id.
- * @num_qinfo: Number of instances.
- * @pad: Padding.
- * @qinfo: Rx queues config info.
- *
- * PF sends this message to set up parameters for one or more receive queues.
- * This message contains an array of num_qinfo instances of virtchnl2_rxq_info
- * structures. CP configures requested queues and returns a status code.
- * If the number of queues specified is greater than the number of queues
- * associated with the vport, an error is returned and no queues are configured.
- *
- * Associated with VIRTCHNL2_OP_CONFIG_RX_QUEUES.
- */
-struct virtchnl2_config_rx_queues {
- __le32 vport_id;
- __le16 num_qinfo;
- u8 pad[18];
- struct virtchnl2_rxq_info qinfo[] __counted_by_le(num_qinfo);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_config_rx_queues);
-
-/**
- * struct virtchnl2_add_queues - data for VIRTCHNL2_OP_ADD_QUEUES.
- * @vport_id: Vport id.
- * @num_tx_q: Number of Tx qieues.
- * @num_tx_complq: Number of Tx completion queues.
- * @num_rx_q: Number of Rx queues.
- * @num_rx_bufq: Number of Rx buffer queues.
- * @pad: Padding.
- * @chunks: Chunks of contiguous queues.
- *
- * PF sends this message to request additional transmit/receive queues beyond
- * the ones that were assigned via CREATE_VPORT request. virtchnl2_add_queues
- * structure is used to specify the number of each type of queues.
- * CP responds with the same structure with the actual number of queues assigned
- * followed by num_chunks of virtchnl2_queue_chunk structures.
- *
- * Associated with VIRTCHNL2_OP_ADD_QUEUES.
- */
-struct virtchnl2_add_queues {
- __le32 vport_id;
- __le16 num_tx_q;
- __le16 num_tx_complq;
- __le16 num_rx_q;
- __le16 num_rx_bufq;
- u8 pad[4];
- struct virtchnl2_queue_reg_chunks chunks;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_add_queues);
-
-/**
- * struct virtchnl2_vector_chunk - Structure to specify a chunk of contiguous
- * interrupt vectors.
- * @start_vector_id: Start vector id.
- * @start_evv_id: Start EVV id.
- * @num_vectors: Number of vectors.
- * @pad: Padding.
- * @dynctl_reg_start: DYN_CTL register offset.
- * @dynctl_reg_spacing: register spacing between DYN_CTL registers of 2
- * consecutive vectors.
- * @itrn_reg_start: ITRN register offset.
- * @itrn_reg_spacing: Register spacing between dynctl registers of 2
- * consecutive vectors.
- * @itrn_index_spacing: Register spacing between itrn registers of the same
- * vector where n=0..2.
- * @pad1: Padding for future extensions.
- *
- * Register offsets and spacing provided by CP.
- * Dynamic control registers are used for enabling/disabling/re-enabling
- * interrupts and updating interrupt rates in the hotpath. Any changes
- * to interrupt rates in the dynamic control registers will be reflected
- * in the interrupt throttling rate registers.
- * itrn registers are used to update interrupt rates for specific
- * interrupt indices without modifying the state of the interrupt.
- */
-struct virtchnl2_vector_chunk {
- __le16 start_vector_id;
- __le16 start_evv_id;
- __le16 num_vectors;
- __le16 pad;
- __le32 dynctl_reg_start;
- __le32 dynctl_reg_spacing;
- __le32 itrn_reg_start;
- __le32 itrn_reg_spacing;
- __le32 itrn_index_spacing;
- u8 pad1[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(32, virtchnl2_vector_chunk);
-
-/**
- * struct virtchnl2_vector_chunks - chunks of contiguous interrupt vectors.
- * @num_vchunks: number of vector chunks.
- * @pad: Padding.
- * @vchunks: Chunks of contiguous vector info.
- *
- * PF sends virtchnl2_vector_chunks struct to specify the vectors it is giving
- * away. CP performs requested action and returns status.
- *
- * Associated with VIRTCHNL2_OP_DEALLOC_VECTORS.
- */
-struct virtchnl2_vector_chunks {
- __le16 num_vchunks;
- u8 pad[14];
- struct virtchnl2_vector_chunk vchunks[] __counted_by_le(num_vchunks);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_vector_chunks);
-
-/**
- * struct virtchnl2_alloc_vectors - vector allocation info.
- * @num_vectors: Number of vectors.
- * @pad: Padding.
- * @vchunks: Chunks of contiguous vector info.
- *
- * PF sends this message to request additional interrupt vectors beyond the
- * ones that were assigned via GET_CAPS request. virtchnl2_alloc_vectors
- * structure is used to specify the number of vectors requested. CP responds
- * with the same structure with the actual number of vectors assigned followed
- * by virtchnl2_vector_chunks structure identifying the vector ids.
- *
- * Associated with VIRTCHNL2_OP_ALLOC_VECTORS.
- */
-struct virtchnl2_alloc_vectors {
- __le16 num_vectors;
- u8 pad[14];
- struct virtchnl2_vector_chunks vchunks;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(32, virtchnl2_alloc_vectors);
-
-/**
- * struct virtchnl2_rss_lut - RSS LUT info.
- * @vport_id: Vport id.
- * @lut_entries_start: Start of LUT entries.
- * @lut_entries: Number of LUT entrties.
- * @pad: Padding.
- * @lut: RSS lookup table.
- *
- * PF sends this message to get or set RSS lookup table. Only supported if
- * both PF and CP drivers set the VIRTCHNL2_CAP_RSS bit during configuration
- * negotiation.
- *
- * Associated with VIRTCHNL2_OP_GET_RSS_LUT and VIRTCHNL2_OP_SET_RSS_LUT.
- */
-struct virtchnl2_rss_lut {
- __le32 vport_id;
- __le16 lut_entries_start;
- __le16 lut_entries;
- u8 pad[4];
- __le32 lut[] __counted_by_le(lut_entries);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(12, virtchnl2_rss_lut);
-
-/**
- * struct virtchnl2_rss_hash - RSS hash info.
- * @ptype_groups: Packet type groups bitmap.
- * @vport_id: Vport id.
- * @pad: Padding for future extensions.
- *
- * PF sends these messages to get and set the hash filter enable bits for RSS.
- * By default, the CP sets these to all possible traffic types that the
- * hardware supports. The PF can query this value if it wants to change the
- * traffic types that are hashed by the hardware.
- * Only supported if both PF and CP drivers set the VIRTCHNL2_CAP_RSS bit
- * during configuration negotiation.
- *
- * Associated with VIRTCHNL2_OP_GET_RSS_HASH and VIRTCHNL2_OP_SET_RSS_HASH
- */
-struct virtchnl2_rss_hash {
- __le64 ptype_groups;
- __le32 vport_id;
- u8 pad[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_rss_hash);
-
-/**
- * struct virtchnl2_sriov_vfs_info - VFs info.
- * @num_vfs: Number of VFs.
- * @pad: Padding for future extensions.
- *
- * This message is used to set number of SRIOV VFs to be created. The actual
- * allocation of resources for the VFs in terms of vport, queues and interrupts
- * is done by CP. When this call completes, the IDPF driver calls
- * pci_enable_sriov to let the OS instantiate the SRIOV PCIE devices.
- * The number of VFs set to 0 will destroy all the VFs of this function.
- *
- * Associated with VIRTCHNL2_OP_SET_SRIOV_VFS.
- */
-struct virtchnl2_sriov_vfs_info {
- __le16 num_vfs;
- __le16 pad;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(4, virtchnl2_sriov_vfs_info);
-
-/**
- * struct virtchnl2_ptype - Packet type info.
- * @ptype_id_10: 10-bit packet type.
- * @ptype_id_8: 8-bit packet type.
- * @proto_id_count: Number of protocol ids the packet supports, maximum of 32
- * protocol ids are supported.
- * @pad: Padding.
- * @proto_id: proto_id_count decides the allocation of protocol id array.
- * See enum virtchnl2_proto_hdr_type.
- *
- * Based on the descriptor type the PF supports, CP fills ptype_id_10 or
- * ptype_id_8 for flex and base descriptor respectively. If ptype_id_10 value
- * is set to 0xFFFF, PF should consider this ptype as dummy one and it is the
- * last ptype.
- */
-struct virtchnl2_ptype {
- __le16 ptype_id_10;
- u8 ptype_id_8;
- u8 proto_id_count;
- __le16 pad;
- __le16 proto_id[] __counted_by(proto_id_count);
-} __packed __aligned(2);
-VIRTCHNL2_CHECK_STRUCT_LEN(6, virtchnl2_ptype);
-
-/**
- * struct virtchnl2_get_ptype_info - Packet type info.
- * @start_ptype_id: Starting ptype ID.
- * @num_ptypes: Number of packet types from start_ptype_id.
- * @pad: Padding for future extensions.
- *
- * The total number of supported packet types is based on the descriptor type.
- * For the flex descriptor, it is 1024 (10-bit ptype), and for the base
- * descriptor, it is 256 (8-bit ptype). Send this message to the CP by
- * populating the 'start_ptype_id' and the 'num_ptypes'. CP responds with the
- * 'start_ptype_id', 'num_ptypes', and the array of ptype (virtchnl2_ptype) that
- * are added at the end of the 'virtchnl2_get_ptype_info' message (Note: There
- * is no specific field for the ptypes but are added at the end of the
- * ptype info message. PF/VF is expected to extract the ptypes accordingly.
- * Reason for doing this is because compiler doesn't allow nested flexible
- * array fields).
- *
- * If all the ptypes don't fit into one mailbox buffer, CP splits the
- * ptype info into multiple messages, where each message will have its own
- * 'start_ptype_id', 'num_ptypes', and the ptype array itself. When CP is done
- * updating all the ptype information extracted from the package (the number of
- * ptypes extracted might be less than what PF/VF expects), it will append a
- * dummy ptype (which has 'ptype_id_10' of 'struct virtchnl2_ptype' as 0xFFFF)
- * to the ptype array.
- *
- * PF/VF is expected to receive multiple VIRTCHNL2_OP_GET_PTYPE_INFO messages.
- *
- * Associated with VIRTCHNL2_OP_GET_PTYPE_INFO.
- */
-struct virtchnl2_get_ptype_info {
- __le16 start_ptype_id;
- __le16 num_ptypes;
- __le32 pad;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_get_ptype_info);
-
-/**
- * struct virtchnl2_vport_stats - Vport statistics.
- * @vport_id: Vport id.
- * @pad: Padding.
- * @rx_bytes: Received bytes.
- * @rx_unicast: Received unicast packets.
- * @rx_multicast: Received multicast packets.
- * @rx_broadcast: Received broadcast packets.
- * @rx_discards: Discarded packets on receive.
- * @rx_errors: Receive errors.
- * @rx_unknown_protocol: Unlnown protocol.
- * @tx_bytes: Transmitted bytes.
- * @tx_unicast: Transmitted unicast packets.
- * @tx_multicast: Transmitted multicast packets.
- * @tx_broadcast: Transmitted broadcast packets.
- * @tx_discards: Discarded packets on transmit.
- * @tx_errors: Transmit errors.
- * @rx_invalid_frame_length: Packets with invalid frame length.
- * @rx_overflow_drop: Packets dropped on buffer overflow.
- *
- * PF/VF sends this message to CP to get the update stats by specifying the
- * vport_id. CP responds with stats in struct virtchnl2_vport_stats.
- *
- * Associated with VIRTCHNL2_OP_GET_STATS.
- */
-struct virtchnl2_vport_stats {
- __le32 vport_id;
- u8 pad[4];
- __le64 rx_bytes;
- __le64 rx_unicast;
- __le64 rx_multicast;
- __le64 rx_broadcast;
- __le64 rx_discards;
- __le64 rx_errors;
- __le64 rx_unknown_protocol;
- __le64 tx_bytes;
- __le64 tx_unicast;
- __le64 tx_multicast;
- __le64 tx_broadcast;
- __le64 tx_discards;
- __le64 tx_errors;
- __le64 rx_invalid_frame_length;
- __le64 rx_overflow_drop;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(128, virtchnl2_vport_stats);
-
-/**
- * struct virtchnl2_event - Event info.
- * @event: Event opcode. See enum virtchnl2_event_codes.
- * @link_speed: Link_speed provided in Mbps.
- * @vport_id: Vport ID.
- * @link_status: Link status.
- * @pad: Padding.
- * @reserved: Reserved.
- *
- * CP sends this message to inform the PF/VF driver of events that may affect
- * it. No direct response is expected from the driver, though it may generate
- * other messages in response to this one.
- *
- * Associated with VIRTCHNL2_OP_EVENT.
- */
-struct virtchnl2_event {
- __le32 event;
- __le32 link_speed;
- __le32 vport_id;
- u8 link_status;
- u8 pad;
- __le16 reserved;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_event);
-
-/**
- * struct virtchnl2_rss_key - RSS key info.
- * @vport_id: Vport id.
- * @key_len: Length of RSS key.
- * @pad: Padding.
- * @key_flex: RSS hash key, packed bytes.
- * PF/VF sends this message to get or set RSS key. Only supported if both
- * PF/VF and CP drivers set the VIRTCHNL2_CAP_RSS bit during configuration
- * negotiation.
- *
- * Associated with VIRTCHNL2_OP_GET_RSS_KEY and VIRTCHNL2_OP_SET_RSS_KEY.
- */
-struct virtchnl2_rss_key {
- __le32 vport_id;
- __le16 key_len;
- u8 pad;
- u8 key_flex[] __counted_by_le(key_len);
-} __packed;
-VIRTCHNL2_CHECK_STRUCT_LEN(7, virtchnl2_rss_key);
-
-/**
- * struct virtchnl2_queue_chunk - chunk of contiguous queues
- * @type: See enum virtchnl2_queue_type.
- * @start_queue_id: Starting queue id.
- * @num_queues: Number of queues.
- * @pad: Padding for future extensions.
- */
-struct virtchnl2_queue_chunk {
- __le32 type;
- __le32 start_queue_id;
- __le32 num_queues;
- u8 pad[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_queue_chunk);
-
-/* struct virtchnl2_queue_chunks - chunks of contiguous queues
- * @num_chunks: Number of chunks.
- * @pad: Padding.
- * @chunks: Chunks of contiguous queues info.
- */
-struct virtchnl2_queue_chunks {
- __le16 num_chunks;
- u8 pad[6];
- struct virtchnl2_queue_chunk chunks[] __counted_by_le(num_chunks);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_queue_chunks);
-
-/**
- * struct virtchnl2_del_ena_dis_queues - Enable/disable queues info.
- * @vport_id: Vport id.
- * @pad: Padding.
- * @chunks: Chunks of contiguous queues info.
- *
- * PF sends these messages to enable, disable or delete queues specified in
- * chunks. PF sends virtchnl2_del_ena_dis_queues struct to specify the queues
- * to be enabled/disabled/deleted. Also applicable to single queue receive or
- * transmit. CP performs requested action and returns status.
- *
- * Associated with VIRTCHNL2_OP_ENABLE_QUEUES, VIRTCHNL2_OP_DISABLE_QUEUES and
- * VIRTCHNL2_OP_DISABLE_QUEUES.
- */
-struct virtchnl2_del_ena_dis_queues {
- __le32 vport_id;
- u8 pad[4];
- struct virtchnl2_queue_chunks chunks;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_del_ena_dis_queues);
-
-/**
- * struct virtchnl2_queue_vector - Queue to vector mapping.
- * @queue_id: Queue id.
- * @vector_id: Vector id.
- * @pad: Padding.
- * @itr_idx: See enum virtchnl2_itr_idx.
- * @queue_type: See enum virtchnl2_queue_type.
- * @pad1: Padding for future extensions.
- */
-struct virtchnl2_queue_vector {
- __le32 queue_id;
- __le16 vector_id;
- u8 pad[2];
- __le32 itr_idx;
- __le32 queue_type;
- u8 pad1[8];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_queue_vector);
-
-/**
- * struct virtchnl2_queue_vector_maps - Map/unmap queues info.
- * @vport_id: Vport id.
- * @num_qv_maps: Number of queue vector maps.
- * @pad: Padding.
- * @qv_maps: Queue to vector maps.
- *
- * PF sends this message to map or unmap queues to vectors and interrupt
- * throttling rate index registers. External data buffer contains
- * virtchnl2_queue_vector_maps structure that contains num_qv_maps of
- * virtchnl2_queue_vector structures. CP maps the requested queue vector maps
- * after validating the queue and vector ids and returns a status code.
- *
- * Associated with VIRTCHNL2_OP_MAP_QUEUE_VECTOR and
- * VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR.
- */
-struct virtchnl2_queue_vector_maps {
- __le32 vport_id;
- __le16 num_qv_maps;
- u8 pad[10];
- struct virtchnl2_queue_vector qv_maps[] __counted_by_le(num_qv_maps);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_queue_vector_maps);
-
-/**
- * struct virtchnl2_loopback - Loopback info.
- * @vport_id: Vport id.
- * @enable: Enable/disable.
- * @pad: Padding for future extensions.
- *
- * PF/VF sends this message to transition to/from the loopback state. Setting
- * the 'enable' to 1 enables the loopback state and setting 'enable' to 0
- * disables it. CP configures the state to loopback and returns status.
- *
- * Associated with VIRTCHNL2_OP_LOOPBACK.
- */
-struct virtchnl2_loopback {
- __le32 vport_id;
- u8 enable;
- u8 pad[3];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_loopback);
-
-/* struct virtchnl2_mac_addr - MAC address info.
- * @addr: MAC address.
- * @type: MAC type. See enum virtchnl2_mac_addr_type.
- * @pad: Padding for future extensions.
- */
-struct virtchnl2_mac_addr {
- u8 addr[ETH_ALEN];
- u8 type;
- u8 pad;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_mac_addr);
-
-/**
- * struct virtchnl2_mac_addr_list - List of MAC addresses.
- * @vport_id: Vport id.
- * @num_mac_addr: Number of MAC addresses.
- * @pad: Padding.
- * @mac_addr_list: List with MAC address info.
- *
- * PF/VF driver uses this structure to send list of MAC addresses to be
- * added/deleted to the CP where as CP performs the action and returns the
- * status.
- *
- * Associated with VIRTCHNL2_OP_ADD_MAC_ADDR and VIRTCHNL2_OP_DEL_MAC_ADDR.
- */
-struct virtchnl2_mac_addr_list {
- __le32 vport_id;
- __le16 num_mac_addr;
- u8 pad[2];
- struct virtchnl2_mac_addr mac_addr_list[] __counted_by_le(num_mac_addr);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_mac_addr_list);
-
-/**
- * struct virtchnl2_promisc_info - Promisc type info.
- * @vport_id: Vport id.
- * @flags: See enum virtchnl2_promisc_flags.
- * @pad: Padding for future extensions.
- *
- * PF/VF sends vport id and flags to the CP where as CP performs the action
- * and returns the status.
- *
- * Associated with VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE.
- */
-struct virtchnl2_promisc_info {
- __le32 vport_id;
- /* See VIRTCHNL2_PROMISC_FLAGS definitions */
- __le16 flags;
- u8 pad[2];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_promisc_info);
-
-/**
- * enum virtchnl2_ptp_caps - PTP capabilities
- * @VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME: direct access to get the time of
- * device clock
- * @VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB: mailbox access to get the time of
- * device clock
- * @VIRTCHNL2_CAP_PTP_GET_CROSS_TIME: direct access to cross timestamp
- * @VIRTCHNL2_CAP_PTP_GET_CROSS_TIME_MB: mailbox access to cross timestamp
- * @VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME: direct access to set the time of
- * device clock
- * @VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB: mailbox access to set the time of
- * device clock
- * @VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK: direct access to adjust the time of device
- * clock
- * @VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB: mailbox access to adjust the time of
- * device clock
- * @VIRTCHNL2_CAP_PTP_TX_TSTAMPS: direct access to the Tx timestamping
- * @VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB: mailbox access to the Tx timestamping
- *
- * PF/VF negotiates a set of supported PTP capabilities with the Control Plane.
- * There are two access methods - mailbox (_MB) and direct.
- * PTP capabilities enables Main Timer operations: get/set/adjust Main Timer,
- * cross timestamping and the Tx timestamping.
- */
-enum virtchnl2_ptp_caps {
- VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME = BIT(0),
- VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB = BIT(1),
- VIRTCHNL2_CAP_PTP_GET_CROSS_TIME = BIT(2),
- VIRTCHNL2_CAP_PTP_GET_CROSS_TIME_MB = BIT(3),
- VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME = BIT(4),
- VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB = BIT(5),
- VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK = BIT(6),
- VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB = BIT(7),
- VIRTCHNL2_CAP_PTP_TX_TSTAMPS = BIT(8),
- VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB = BIT(9),
-};
-
-/**
- * struct virtchnl2_ptp_clk_reg_offsets - Offsets of device and PHY clocks
- * registers.
- * @dev_clk_ns_l: Device clock low register offset
- * @dev_clk_ns_h: Device clock high register offset
- * @phy_clk_ns_l: PHY clock low register offset
- * @phy_clk_ns_h: PHY clock high register offset
- * @cmd_sync_trigger: The command sync trigger register offset
- * @pad: Padding for future extensions
- */
-struct virtchnl2_ptp_clk_reg_offsets {
- __le32 dev_clk_ns_l;
- __le32 dev_clk_ns_h;
- __le32 phy_clk_ns_l;
- __le32 phy_clk_ns_h;
- __le32 cmd_sync_trigger;
- u8 pad[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_ptp_clk_reg_offsets);
-
-/**
- * struct virtchnl2_ptp_cross_time_reg_offsets - Offsets of the device cross
- * time registers.
- * @sys_time_ns_l: System time low register offset
- * @sys_time_ns_h: System time high register offset
- * @cmd_sync_trigger: The command sync trigger register offset
- * @pad: Padding for future extensions
- */
-struct virtchnl2_ptp_cross_time_reg_offsets {
- __le32 sys_time_ns_l;
- __le32 sys_time_ns_h;
- __le32 cmd_sync_trigger;
- u8 pad[4];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_cross_time_reg_offsets);
-
-/**
- * struct virtchnl2_ptp_clk_adj_reg_offsets - Offsets of device and PHY clocks
- * adjustments registers.
- * @dev_clk_cmd_type: Device clock command type register offset
- * @dev_clk_incval_l: Device clock increment value low register offset
- * @dev_clk_incval_h: Device clock increment value high registers offset
- * @dev_clk_shadj_l: Device clock shadow adjust low register offset
- * @dev_clk_shadj_h: Device clock shadow adjust high register offset
- * @phy_clk_cmd_type: PHY timer command type register offset
- * @phy_clk_incval_l: PHY timer increment value low register offset
- * @phy_clk_incval_h: PHY timer increment value high register offset
- * @phy_clk_shadj_l: PHY timer shadow adjust low register offset
- * @phy_clk_shadj_h: PHY timer shadow adjust high register offset
- */
-struct virtchnl2_ptp_clk_adj_reg_offsets {
- __le32 dev_clk_cmd_type;
- __le32 dev_clk_incval_l;
- __le32 dev_clk_incval_h;
- __le32 dev_clk_shadj_l;
- __le32 dev_clk_shadj_h;
- __le32 phy_clk_cmd_type;
- __le32 phy_clk_incval_l;
- __le32 phy_clk_incval_h;
- __le32 phy_clk_shadj_l;
- __le32 phy_clk_shadj_h;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(40, virtchnl2_ptp_clk_adj_reg_offsets);
-
-/**
- * struct virtchnl2_ptp_tx_tstamp_latch_caps - PTP Tx timestamp latch
- * capabilities.
- * @tx_latch_reg_offset_l: Tx timestamp latch low register offset
- * @tx_latch_reg_offset_h: Tx timestamp latch high register offset
- * @index: Latch index provided to the Tx descriptor
- * @pad: Padding for future extensions
- */
-struct virtchnl2_ptp_tx_tstamp_latch_caps {
- __le32 tx_latch_reg_offset_l;
- __le32 tx_latch_reg_offset_h;
- u8 index;
- u8 pad[7];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_tx_tstamp_latch_caps);
-
-/**
- * struct virtchnl2_ptp_get_vport_tx_tstamp_caps - Structure that defines Tx
- * tstamp entries.
- * @vport_id: Vport number
- * @num_latches: Total number of latches
- * @tstamp_ns_lo_bit: First bit for nanosecond part of the timestamp
- * @tstamp_ns_hi_bit: Last bit for nanosecond part of the timestamp
- * @pad: Padding for future tstamp granularity extensions
- * @tstamp_latches: Capabilities of Tx timestamp entries
- *
- * PF/VF sends this message to negotiate the Tx timestamp latches for each
- * Vport.
- *
- * Associated with VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS.
- */
-struct virtchnl2_ptp_get_vport_tx_tstamp_caps {
- __le32 vport_id;
- __le16 num_latches;
- u8 tstamp_ns_lo_bit;
- u8 tstamp_ns_hi_bit;
- u8 pad[8];
-
- struct virtchnl2_ptp_tx_tstamp_latch_caps tstamp_latches[]
- __counted_by_le(num_latches);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_vport_tx_tstamp_caps);
-
-/**
- * struct virtchnl2_ptp_get_caps - Get PTP capabilities
- * @caps: PTP capability bitmap. See enum virtchnl2_ptp_caps
- * @max_adj: The maximum possible frequency adjustment
- * @base_incval: The default timer increment value
- * @peer_mbx_q_id: ID of the PTP Device Control daemon queue
- * @peer_id: Peer ID for PTP Device Control daemon
- * @secondary_mbx: Indicates to the driver that it should create a secondary
- * mailbox to inetract with control plane for PTP
- * @pad: Padding for future extensions
- * @clk_offsets: Main timer and PHY registers offsets
- * @cross_time_offsets: Cross time registers offsets
- * @clk_adj_offsets: Offsets needed to adjust the PHY and the main timer
- *
- * PF/VF sends this message to negotiate PTP capabilities. CP updates bitmap
- * with supported features and fulfills appropriate structures.
- * If HW uses primary MBX for PTP: secondary_mbx is set to false.
- * If HW uses secondary MBX for PTP: secondary_mbx is set to true.
- * Control plane has 2 MBX and the driver has 1 MBX, send to peer
- * driver may be used to send a message using valid ptp_peer_mb_q_id and
- * ptp_peer_id.
- * If HW does not use send to peer driver: secondary_mbx is no care field and
- * peer_mbx_q_id holds invalid value (0xFFFF).
- *
- * Associated with VIRTCHNL2_OP_PTP_GET_CAPS.
- */
-struct virtchnl2_ptp_get_caps {
- __le32 caps;
- __le32 max_adj;
- __le64 base_incval;
- __le16 peer_mbx_q_id;
- u8 peer_id;
- u8 secondary_mbx;
- u8 pad[4];
-
- struct virtchnl2_ptp_clk_reg_offsets clk_offsets;
- struct virtchnl2_ptp_cross_time_reg_offsets cross_time_offsets;
- struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(104, virtchnl2_ptp_get_caps);
-
-/**
- * struct virtchnl2_ptp_tx_tstamp_latch - Structure that describes tx tstamp
- * values, index and validity.
- * @tstamp: Timestamp value
- * @index: Timestamp index from which the value is read
- * @valid: Timestamp validity
- * @pad: Padding for future extensions
- */
-struct virtchnl2_ptp_tx_tstamp_latch {
- __le64 tstamp;
- u8 index;
- u8 valid;
- u8 pad[6];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_tx_tstamp_latch);
-
-/**
- * struct virtchnl2_ptp_get_vport_tx_tstamp_latches - Tx timestamp latches
- * associated with the vport.
- * @vport_id: Number of vport that requests the timestamp
- * @num_latches: Number of latches
- * @get_devtime_with_txtstmp: Flag to request device time along with Tx timestamp
- * @pad: Padding for future extensions
- * @device_time: device time if get_devtime_with_txtstmp was set in request
- * @tstamp_latches: PTP TX timestamp latch
- *
- * PF/VF sends this message to receive a specified number of timestamps
- * entries.
- *
- * Associated with VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP.
- */
-struct virtchnl2_ptp_get_vport_tx_tstamp_latches {
- __le32 vport_id;
- __le16 num_latches;
- u8 get_devtime_with_txtstmp;
- u8 pad[1];
- __le64 device_time;
-
- struct virtchnl2_ptp_tx_tstamp_latch tstamp_latches[]
- __counted_by_le(num_latches);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_vport_tx_tstamp_latches);
-
-/**
- * struct virtchnl2_ptp_get_dev_clk_time - Associated with message
- * VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME.
- * @dev_time_ns: Device clock time value in nanoseconds
- *
- * PF/VF sends this message to receive the time from the main timer.
- */
-struct virtchnl2_ptp_get_dev_clk_time {
- __le64 dev_time_ns;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_get_dev_clk_time);
-
-/**
- * struct virtchnl2_ptp_get_cross_time: Associated with message
- * VIRTCHNL2_OP_PTP_GET_CROSS_TIME.
- * @sys_time_ns: System counter value expressed in nanoseconds, read
- * synchronously with device time
- * @dev_time_ns: Device clock time value expressed in nanoseconds
- *
- * PF/VF sends this message to receive the cross time.
- */
-struct virtchnl2_ptp_get_cross_time {
- __le64 sys_time_ns;
- __le64 dev_time_ns;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_cross_time);
-
-/**
- * struct virtchnl2_ptp_set_dev_clk_time: Associated with message
- * VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME.
- * @dev_time_ns: Device time value expressed in nanoseconds to set
- *
- * PF/VF sends this message to set the time of the main timer.
- */
-struct virtchnl2_ptp_set_dev_clk_time {
- __le64 dev_time_ns;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_set_dev_clk_time);
-
-/**
- * struct virtchnl2_ptp_adj_dev_clk_fine: Associated with message
- * VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE.
- * @incval: Source timer increment value per clock cycle
- *
- * PF/VF sends this message to adjust the frequency of the main timer by the
- * indicated increment value.
- */
-struct virtchnl2_ptp_adj_dev_clk_fine {
- __le64 incval;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_adj_dev_clk_fine);
-
-/**
- * struct virtchnl2_ptp_adj_dev_clk_time: Associated with message
- * VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME.
- * @delta: Offset in nanoseconds to adjust the time by
- *
- * PF/VF sends this message to adjust the time of the main timer by the delta.
- */
-struct virtchnl2_ptp_adj_dev_clk_time {
- __le64 delta;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_adj_dev_clk_time);
-
-/**
- * struct virtchnl2_mem_region - MMIO memory region
- * @start_offset: starting offset of the MMIO memory region
- * @size: size of the MMIO memory region
- */
-struct virtchnl2_mem_region {
- __le64 start_offset;
- __le64 size;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_mem_region);
-
-/**
- * struct virtchnl2_get_lan_memory_regions - List of LAN MMIO memory regions
- * @num_memory_regions: number of memory regions
- * @pad: Padding
- * @mem_reg: List with memory region info
- *
- * PF/VF sends this message to learn what LAN MMIO memory regions it should map.
- */
-struct virtchnl2_get_lan_memory_regions {
- __le16 num_memory_regions;
- u8 pad[6];
- struct virtchnl2_mem_region mem_reg[];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_get_lan_memory_regions);
-
-#define VIRTCHNL2_MAX_NUM_PROTO_HDRS 4
-#define VIRTCHNL2_MAX_SIZE_RAW_PACKET 256
-#define VIRTCHNL2_MAX_NUM_ACTIONS 8
-
-/**
- * struct virtchnl2_proto_hdr - represent one protocol header
- * @hdr_type: See enum virtchnl2_proto_hdr_type
- * @pad: padding
- * @buffer_spec: binary buffer based on header type.
- * @buffer_mask: mask applied on buffer_spec.
- *
- * Structure to hold protocol headers based on hdr_type
- */
-struct virtchnl2_proto_hdr {
- __le32 hdr_type;
- u8 pad[4];
- u8 buffer_spec[64];
- u8 buffer_mask[64];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(136, virtchnl2_proto_hdr);
-
-/**
- * struct virtchnl2_proto_hdrs - struct to represent match criteria
- * @tunnel_level: specify where protocol header(s) start from.
- * must be 0 when sending a raw packet request.
- * 0 - from the outer layer
- * 1 - from the first inner layer
- * 2 - from the second inner layer
- * @pad: Padding bytes
- * @count: total number of protocol headers in proto_hdr. 0 for raw packet.
- * @proto_hdr: Array of protocol headers
- * @raw: struct holding raw packet buffer when count is 0
- */
-struct virtchnl2_proto_hdrs {
- u8 tunnel_level;
- u8 pad[3];
- __le32 count;
- union {
- struct virtchnl2_proto_hdr
- proto_hdr[VIRTCHNL2_MAX_NUM_PROTO_HDRS];
- struct {
- __le16 pkt_len;
- u8 spec[VIRTCHNL2_MAX_SIZE_RAW_PACKET];
- u8 mask[VIRTCHNL2_MAX_SIZE_RAW_PACKET];
- } raw;
- };
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(552, virtchnl2_proto_hdrs);
-
-/**
- * struct virtchnl2_rule_action - struct representing single action for a flow
- * @action_type: see enum virtchnl2_action_types
- * @act_conf: union representing action depending on action_type.
- * @act_conf.q_id: queue id to redirect the packets to.
- * @act_conf.q_grp_id: queue group id to redirect the packets to.
- * @act_conf.ctr_id: used for count action. If input value 0xFFFFFFFF control
- * plane assigns a new counter and returns the counter ID to
- * the driver. If input value is not 0xFFFFFFFF then it must
- * be an existing counter given to the driver for an earlier
- * flow. Then this flow will share the counter.
- * @act_conf.mark_id: Value used to mark the packets. Used for mark action.
- * @act_conf.reserved: Reserved for future use.
- */
-struct virtchnl2_rule_action {
- __le32 action_type;
- union {
- __le32 q_id;
- __le32 q_grp_id;
- __le32 ctr_id;
- __le32 mark_id;
- u8 reserved[8];
- } act_conf;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(12, virtchnl2_rule_action);
-
-/**
- * struct virtchnl2_rule_action_set - struct representing multiple actions
- * @count: number of valid actions in the action set of a rule
- * @actions: array of struct virtchnl2_rule_action
- */
-struct virtchnl2_rule_action_set {
- /* action count must be less than VIRTCHNL2_MAX_NUM_ACTIONS */
- __le32 count;
- struct virtchnl2_rule_action actions[VIRTCHNL2_MAX_NUM_ACTIONS];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(100, virtchnl2_rule_action_set);
-
-/**
- * struct virtchnl2_flow_rule - represent one flow steering rule
- * @proto_hdrs: array of protocol header buffers representing match criteria
- * @action_set: series of actions to be applied for given rule
- * @priority: rule priority.
- * @pad: padding for future extensions.
- */
-struct virtchnl2_flow_rule {
- struct virtchnl2_proto_hdrs proto_hdrs;
- struct virtchnl2_rule_action_set action_set;
- __le32 priority;
- u8 pad[8];
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(664, virtchnl2_flow_rule);
-
-enum virtchnl2_flow_rule_status {
- VIRTCHNL2_FLOW_RULE_SUCCESS = 1,
- VIRTCHNL2_FLOW_RULE_NORESOURCE = 2,
- VIRTCHNL2_FLOW_RULE_EXIST = 3,
- VIRTCHNL2_FLOW_RULE_TIMEOUT = 4,
- VIRTCHNL2_FLOW_RULE_FLOW_TYPE_NOT_SUPPORTED = 5,
- VIRTCHNL2_FLOW_RULE_MATCH_KEY_NOT_SUPPORTED = 6,
- VIRTCHNL2_FLOW_RULE_ACTION_NOT_SUPPORTED = 7,
- VIRTCHNL2_FLOW_RULE_ACTION_COMBINATION_INVALID = 8,
- VIRTCHNL2_FLOW_RULE_ACTION_DATA_INVALID = 9,
- VIRTCHNL2_FLOW_RULE_NOT_ADDED = 10,
-};
-
-/**
- * struct virtchnl2_flow_rule_info: structure representing single flow rule
- * @rule_id: rule_id associated with the flow_rule.
- * @rule_cfg: structure representing rule.
- * @status: status of rule programming. See enum virtchnl2_flow_rule_status.
- */
-struct virtchnl2_flow_rule_info {
- __le32 rule_id;
- struct virtchnl2_flow_rule rule_cfg;
- __le32 status;
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(672, virtchnl2_flow_rule_info);
-
-/**
- * struct virtchnl2_flow_rule_add_del - add/delete a flow steering rule
- * @vport_id: vport id for which the rule is to be added or deleted.
- * @count: Indicates number of rules to be added or deleted.
- * @rule_info: Array of flow rules to be added or deleted.
- *
- * For VIRTCHNL2_OP_FLOW_RULE_ADD, rule_info contains list of rules to be
- * added. If rule_id is 0xFFFFFFFF, then the rule is programmed and not cached.
- *
- * For VIRTCHNL2_OP_FLOW_RULE_DEL, there are two possibilities. The structure
- * can contain either array of rule_ids or array of match keys to be deleted.
- * When match keys are used the corresponding rule_ids must be 0xFFFFFFFF.
- *
- * status member of each rule indicates the result. Maximum of 6 rules can be
- * added or deleted using this method. Driver has to retry in case of any
- * failure of ADD or DEL opcode. CP doesn't retry in case of failure.
- */
-struct virtchnl2_flow_rule_add_del {
- __le32 vport_id;
- __le32 count;
- struct virtchnl2_flow_rule_info rule_info[] __counted_by_le(count);
-};
-VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_flow_rule_add_del);
-
-#endif /* _VIRTCHNL_2_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h b/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h
deleted file mode 100644
index f1b577f1c452..000000000000
--- a/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h
+++ /dev/null
@@ -1,451 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _VIRTCHNL2_LAN_DESC_H_
-#define _VIRTCHNL2_LAN_DESC_H_
-
-#include <linux/bits.h>
-
-/* This is an interface definition file where existing enums and their values
- * must remain unchanged over time, so we specify explicit values for all enums.
- */
-
-/* Transmit descriptor ID flags
- */
-enum virtchnl2_tx_desc_ids {
- VIRTCHNL2_TXDID_DATA = BIT(0),
- VIRTCHNL2_TXDID_CTX = BIT(1),
- /* TXDID bit 2 is reserved
- * TXDID bit 3 is free for future use
- * TXDID bit 4 is reserved
- */
- VIRTCHNL2_TXDID_FLEX_TSO_CTX = BIT(5),
- /* TXDID bit 6 is reserved */
- VIRTCHNL2_TXDID_FLEX_L2TAG1_L2TAG2 = BIT(7),
- /* TXDID bits 8 and 9 are free for future use
- * TXDID bit 10 is reserved
- * TXDID bit 11 is free for future use
- */
- VIRTCHNL2_TXDID_FLEX_FLOW_SCHED = BIT(12),
- /* TXDID bits 13 and 14 are free for future use */
- VIRTCHNL2_TXDID_DESC_DONE = BIT(15),
-};
-
-/* Receive descriptor IDs */
-enum virtchnl2_rx_desc_ids {
- VIRTCHNL2_RXDID_1_32B_BASE = 1,
- /* FLEX_SQ_NIC and FLEX_SPLITQ share desc ids because they can be
- * differentiated based on queue model; e.g. single queue model can
- * only use FLEX_SQ_NIC and split queue model can only use FLEX_SPLITQ
- * for DID 2.
- */
- VIRTCHNL2_RXDID_2_FLEX_SPLITQ = 2,
- VIRTCHNL2_RXDID_2_FLEX_SQ_NIC = VIRTCHNL2_RXDID_2_FLEX_SPLITQ,
- /* 3 through 6 are reserved */
- VIRTCHNL2_RXDID_7_HW_RSVD = 7,
- /* 8 through 15 are free */
-};
-
-/* Receive descriptor ID bitmasks */
-#define VIRTCHNL2_RXDID_M(bit) BIT_ULL(VIRTCHNL2_RXDID_##bit)
-
-enum virtchnl2_rx_desc_id_bitmasks {
- VIRTCHNL2_RXDID_1_32B_BASE_M = VIRTCHNL2_RXDID_M(1_32B_BASE),
- VIRTCHNL2_RXDID_2_FLEX_SPLITQ_M = VIRTCHNL2_RXDID_M(2_FLEX_SPLITQ),
- VIRTCHNL2_RXDID_2_FLEX_SQ_NIC_M = VIRTCHNL2_RXDID_M(2_FLEX_SQ_NIC),
- VIRTCHNL2_RXDID_7_HW_RSVD_M = VIRTCHNL2_RXDID_M(7_HW_RSVD),
-};
-
-/* For splitq virtchnl2_rx_flex_desc_adv_nic_3 desc members */
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_RXDID_M GENMASK(3, 0)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_UMBCAST_M GENMASK(7, 6)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_PTYPE_M GENMASK(9, 0)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_RAW_CSUM_INV_S 12
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_RAW_CSUM_INV_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_RAW_CSUM_INV_S)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_FF0_M GENMASK(15, 13)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_PBUF_M GENMASK(13, 0)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_S 14
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_S)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_BUFQ_ID_S 15
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_BUFQ_ID_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_BUFQ_ID_S)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_HDR_M GENMASK(9, 0)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_RSC_S 10
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_RSC_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_RSC_S)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_SPH_S 11
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_SPH_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_SPH_S)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_FF1_S 12
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_FF1_M GENMASK(14, 12)
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_MISS_S 15
-#define VIRTCHNL2_RX_FLEX_DESC_ADV_MISS_M \
- BIT_ULL(VIRTCHNL2_RX_FLEX_DESC_ADV_MISS_S)
-
-/* Bitmasks for splitq virtchnl2_rx_flex_desc_adv_nic_3 */
-enum virtchl2_rx_flex_desc_adv_status_error_0_qw1_bits {
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_DD_M = BIT(0),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_EOF_M = BIT(1),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_HBO_M = BIT(2),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_L3L4P_M = BIT(3),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XSUM_IPE_M = BIT(4),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XSUM_L4E_M = BIT(5),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XSUM_EIPE_M = BIT(6),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XSUM_EUDPE_M = BIT(7),
-};
-
-/* Bitmasks for splitq virtchnl2_rx_flex_desc_adv_nic_3 */
-enum virtchnl2_rx_flex_desc_adv_status_error_0_qw0_bits {
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_LPBK_M = BIT(0),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_IPV6EXADD_M = BIT(1),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_RXE_M = BIT(2),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_CRCP_M = BIT(3),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_RSS_VALID_M = BIT(4),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_L2TAG1P_M = BIT(5),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XTRMD0_VALID_M = BIT(6),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_XTRMD1_VALID_M = BIT(7),
-};
-
-/* Bitmasks for splitq virtchnl2_rx_flex_desc_adv_nic_3 */
-enum virtchnl2_rx_flex_desc_adv_status_error_1_bits {
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_RSVD_M = GENMASK(1, 0),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_ATRAEFAIL_M = BIT(2),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_L2TAG2P_M = BIT(3),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_XTRMD2_VALID_M = BIT(4),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_XTRMD3_VALID_M = BIT(5),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_XTRMD4_VALID_M = BIT(6),
- VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS1_XTRMD5_VALID_M = BIT(7),
-};
-
-/* For singleq (flex) virtchnl2_rx_flex_desc fields
- * For virtchnl2_rx_flex_desc.ptype_flex_flags0 member
- */
-#define VIRTCHNL2_RX_FLEX_DESC_PTYPE_M GENMASK(9, 0)
-
-/* For virtchnl2_rx_flex_desc.pkt_len member */
-#define VIRTCHNL2_RX_FLEX_DESC_PKT_LEN_M GENMASK(13, 0)
-
-/* Bitmasks for singleq (flex) virtchnl2_rx_flex_desc */
-enum virtchnl2_rx_flex_desc_status_error_0_bits {
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_DD_M = BIT(0),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_EOF_M = BIT(1),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_HBO_M = BIT(2),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_L3L4P_M = BIT(3),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XSUM_IPE_M = BIT(4),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XSUM_L4E_M = BIT(5),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XSUM_EIPE_M = BIT(6),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XSUM_EUDPE_M = BIT(7),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_LPBK_M = BIT(8),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_IPV6EXADD_M = BIT(9),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_RXE_M = BIT(10),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_CRCP_M = BIT(11),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_RSS_VALID_M = BIT(12),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_L2TAG1P_M = BIT(13),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XTRMD0_VALID_M = BIT(14),
- VIRTCHNL2_RX_FLEX_DESC_STATUS0_XTRMD1_VALID_M = BIT(15),
-};
-
-/* Bitmasks for singleq (flex) virtchnl2_rx_flex_desc */
-enum virtchnl2_rx_flex_desc_status_error_1_bits {
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_CPM_M = GENMASK(3, 0),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_NAT_M = BIT(4),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_CRYPTO_M = BIT(5),
- /* [10:6] reserved */
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_L2TAG2P_M = BIT(11),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_XTRMD2_VALID_M = BIT(12),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_XTRMD3_VALID_M = BIT(13),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_M = BIT(14),
- VIRTCHNL2_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_M = BIT(15),
-};
-
-/* For virtchnl2_rx_flex_desc.ts_low member */
-#define VIRTCHNL2_RX_FLEX_TSTAMP_VALID BIT(0)
-
-/* For singleq (non flex) virtchnl2_singleq_base_rx_desc legacy desc members */
-#define VIRTCHNL2_RX_BASE_DESC_QW1_LEN_PBUF_M GENMASK_ULL(51, 38)
-#define VIRTCHNL2_RX_BASE_DESC_QW1_PTYPE_M GENMASK_ULL(37, 30)
-#define VIRTCHNL2_RX_BASE_DESC_QW1_ERROR_M GENMASK_ULL(26, 19)
-#define VIRTCHNL2_RX_BASE_DESC_QW1_STATUS_M GENMASK_ULL(18, 0)
-
-/* Bitmasks for singleq (base) virtchnl2_rx_base_desc */
-enum virtchnl2_rx_base_desc_status_bits {
- VIRTCHNL2_RX_BASE_DESC_STATUS_DD_M = BIT(0),
- VIRTCHNL2_RX_BASE_DESC_STATUS_EOF_M = BIT(1),
- VIRTCHNL2_RX_BASE_DESC_STATUS_L2TAG1P_M = BIT(2),
- VIRTCHNL2_RX_BASE_DESC_STATUS_L3L4P_M = BIT(3),
- VIRTCHNL2_RX_BASE_DESC_STATUS_CRCP_M = BIT(4),
- VIRTCHNL2_RX_BASE_DESC_STATUS_RSVD_M = GENMASK(7, 5),
- VIRTCHNL2_RX_BASE_DESC_STATUS_EXT_UDP_0_M = BIT(8),
- VIRTCHNL2_RX_BASE_DESC_STATUS_UMBCAST_M = GENMASK(10, 9),
- VIRTCHNL2_RX_BASE_DESC_STATUS_FLM_M = BIT(11),
- VIRTCHNL2_RX_BASE_DESC_STATUS_FLTSTAT_M = GENMASK(13, 12),
- VIRTCHNL2_RX_BASE_DESC_STATUS_LPBK_M = BIT(14),
- VIRTCHNL2_RX_BASE_DESC_STATUS_IPV6EXADD_M = BIT(15),
- VIRTCHNL2_RX_BASE_DESC_STATUS_RSVD1_M = GENMASK(17, 16),
- VIRTCHNL2_RX_BASE_DESC_STATUS_INT_UDP_0_M = BIT(18),
-};
-
-/* Bitmasks for singleq (base) virtchnl2_rx_base_desc */
-enum virtchnl2_rx_base_desc_error_bits {
- VIRTCHNL2_RX_BASE_DESC_ERROR_RXE_M = BIT(0),
- VIRTCHNL2_RX_BASE_DESC_ERROR_ATRAEFAIL_M = BIT(1),
- VIRTCHNL2_RX_BASE_DESC_ERROR_HBO_M = BIT(2),
- VIRTCHNL2_RX_BASE_DESC_ERROR_L3L4E_M = GENMASK(5, 3),
- VIRTCHNL2_RX_BASE_DESC_ERROR_IPE_M = BIT(3),
- VIRTCHNL2_RX_BASE_DESC_ERROR_L4E_M = BIT(4),
- VIRTCHNL2_RX_BASE_DESC_ERROR_EIPE_M = BIT(5),
- VIRTCHNL2_RX_BASE_DESC_ERROR_OVERSIZE_M = BIT(6),
- VIRTCHNL2_RX_BASE_DESC_ERROR_PPRS_M = BIT(7),
-};
-
-/* Bitmasks for singleq (base) virtchnl2_rx_base_desc */
-#define VIRTCHNL2_RX_BASE_DESC_FLTSTAT_RSS_HASH_M GENMASK(13, 12)
-
-/**
- * struct virtchnl2_splitq_rx_buf_desc - SplitQ RX buffer descriptor format
- * @qword0: RX buffer struct.
- * @qword0.buf_id: Buffer identifier.
- * @qword0.rsvd0: Reserved.
- * @qword0.rsvd1: Reserved.
- * @pkt_addr: Packet buffer address.
- * @hdr_addr: Header buffer address.
- * @rsvd2: Rerserved.
- *
- * Receive Descriptors
- * SplitQ buffer
- * | 16| 0|
- * ----------------------------------------------------------------
- * | RSV | Buffer ID |
- * ----------------------------------------------------------------
- * | Rx packet buffer address |
- * ----------------------------------------------------------------
- * | Rx header buffer address |
- * ----------------------------------------------------------------
- * | RSV |
- * ----------------------------------------------------------------
- * | 0|
- */
-struct virtchnl2_splitq_rx_buf_desc {
- struct {
- __le16 buf_id;
- __le16 rsvd0;
- __le32 rsvd1;
- } qword0;
- __le64 pkt_addr;
- __le64 hdr_addr;
- __le64 rsvd2;
-};
-
-/**
- * struct virtchnl2_singleq_rx_buf_desc - SingleQ RX buffer descriptor format.
- * @pkt_addr: Packet buffer address.
- * @hdr_addr: Header buffer address.
- * @rsvd1: Reserved.
- * @rsvd2: Reserved.
- *
- * SingleQ buffer
- * | 0|
- * ----------------------------------------------------------------
- * | Rx packet buffer address |
- * ----------------------------------------------------------------
- * | Rx header buffer address |
- * ----------------------------------------------------------------
- * | RSV |
- * ----------------------------------------------------------------
- * | RSV |
- * ----------------------------------------------------------------
- * | 0|
- */
-struct virtchnl2_singleq_rx_buf_desc {
- __le64 pkt_addr;
- __le64 hdr_addr;
- __le64 rsvd1;
- __le64 rsvd2;
-};
-
-/**
- * struct virtchnl2_singleq_base_rx_desc - RX descriptor writeback format.
- * @qword0: First quad word struct.
- * @qword0.lo_dword: Lower dual word struct.
- * @qword0.lo_dword.mirroring_status: Mirrored packet status.
- * @qword0.lo_dword.l2tag1: Stripped L2 tag from the received packet.
- * @qword0.hi_dword: High dual word union.
- * @qword0.hi_dword.rss: RSS hash.
- * @qword0.hi_dword.fd_id: Flow director filter id.
- * @qword1: Second quad word struct.
- * @qword1.status_error_ptype_len: Status/error/PTYPE/length.
- * @qword2: Third quad word struct.
- * @qword2.ext_status: Extended status.
- * @qword2.rsvd: Reserved.
- * @qword2.l2tag2_1: Extracted L2 tag 2 from the packet.
- * @qword2.l2tag2_2: Reserved.
- * @qword3: Fourth quad word struct.
- * @qword3.reserved: Reserved.
- * @qword3.fd_id: Flow director filter id.
- *
- * Profile ID 0x1, SingleQ, base writeback format
- */
-struct virtchnl2_singleq_base_rx_desc {
- struct {
- struct {
- __le16 mirroring_status;
- __le16 l2tag1;
- } lo_dword;
- union {
- __le32 rss;
- __le32 fd_id;
- } hi_dword;
- } qword0;
- struct {
- __le64 status_error_ptype_len;
- } qword1;
- struct {
- __le16 ext_status;
- __le16 rsvd;
- __le16 l2tag2_1;
- __le16 l2tag2_2;
- } qword2;
- struct {
- __le32 reserved;
- __le32 fd_id;
- } qword3;
-};
-
-/**
- * struct virtchnl2_rx_flex_desc_nic - RX descriptor writeback format.
- *
- * @rxdid: Descriptor builder profile id.
- * @mir_id_umb_cast: umb_cast=[7:6], mirror=[5:0]
- * @ptype_flex_flags0: ff0=[15:10], ptype=[9:0]
- * @pkt_len: Packet length, [15:14] are reserved.
- * @hdr_len_sph_flex_flags1: ff1/ext=[15:12], sph=[11], header=[10:0].
- * @status_error0: Status/Error section 0.
- * @l2tag1: Stripped L2 tag from the received packet
- * @rss_hash: RSS hash.
- * @status_error1: Status/Error section 1.
- * @flexi_flags2: Flexible flags section 2.
- * @ts_low: Lower word of timestamp value.
- * @l2tag2_1st: First L2TAG2.
- * @l2tag2_2nd: Second L2TAG2.
- * @flow_id: Flow id.
- * @flex_ts: Timestamp and flexible flow id union.
- * @flex_ts.ts_high: Timestamp higher word of the timestamp value.
- * @flex_ts.flex.rsvd: Reserved.
- * @flex_ts.flex.flow_id_ipv6: IPv6 flow id.
- *
- * Profile ID 0x2, SingleQ, flex writeback format
- */
-struct virtchnl2_rx_flex_desc_nic {
- /* Qword 0 */
- u8 rxdid;
- u8 mir_id_umb_cast;
- __le16 ptype_flex_flags0;
- __le16 pkt_len;
- __le16 hdr_len_sph_flex_flags1;
- /* Qword 1 */
- __le16 status_error0;
- __le16 l2tag1;
- __le32 rss_hash;
- /* Qword 2 */
- __le16 status_error1;
- u8 flexi_flags2;
- u8 ts_low;
- __le16 l2tag2_1st;
- __le16 l2tag2_2nd;
- /* Qword 3 */
- __le32 flow_id;
- union {
- struct {
- __le16 rsvd;
- __le16 flow_id_ipv6;
- } flex;
- __le32 ts_high;
- } flex_ts;
-};
-
-/**
- * struct virtchnl2_rx_flex_desc_adv_nic_3 - RX descriptor writeback format.
- * @rxdid_ucast: ucast=[7:6], rsvd=[5:4], profile_id=[3:0].
- * @status_err0_qw0: Status/Error section 0 in quad word 0.
- * @ptype_err_fflags0: ff0=[15:12], udp_len_err=[11], ip_hdr_err=[10],
- * ptype=[9:0].
- * @pktlen_gen_bufq_id: bufq_id=[15] only in splitq, gen=[14] only in splitq,
- * plen=[13:0].
- * @hdrlen_flags: miss_prepend=[15], trunc_mirr=[14], int_udp_0=[13],
- * ext_udp0=[12], sph=[11] only in splitq, rsc=[10]
- * only in splitq, header=[9:0].
- * @status_err0_qw1: Status/Error section 0 in quad word 1.
- * @status_err1: Status/Error section 1.
- * @fflags1: Flexible flags section 1.
- * @ts_low: Lower word of timestamp value.
- * @buf_id: Buffer identifier. Only in splitq mode.
- * @misc: Union.
- * @misc.raw_cs: Raw checksum.
- * @misc.l2tag1: Stripped L2 tag from the received packet
- * @misc.rscseglen:
- * @hash1: Lower bits of Rx hash value.
- * @ff2_mirrid_hash2: Union.
- * @ff2_mirrid_hash2.fflags2: Flexible flags section 2.
- * @ff2_mirrid_hash2.mirrorid: Mirror id.
- * @ff2_mirrid_hash2.rscseglen: RSC segment length.
- * @hash3: Upper bits of Rx hash value.
- * @l2tag2: Extracted L2 tag 2 from the packet.
- * @fmd4: Flexible metadata container 4.
- * @l2tag1: Stripped L2 tag from the received packet
- * @fmd6: Flexible metadata container 6.
- * @ts_high: Timestamp higher word of the timestamp value.
- *
- * Profile ID 0x2, SplitQ, flex writeback format
- *
- * Flex-field 0: BufferID
- * Flex-field 1: Raw checksum/L2TAG1/RSC Seg Len (determined by HW)
- * Flex-field 2: Hash[15:0]
- * Flex-flags 2: Hash[23:16]
- * Flex-field 3: L2TAG2
- * Flex-field 5: L2TAG1
- * Flex-field 7: Timestamp (upper 32 bits)
- */
-struct virtchnl2_rx_flex_desc_adv_nic_3 {
- /* Qword 0 */
- u8 rxdid_ucast;
- u8 status_err0_qw0;
- __le16 ptype_err_fflags0;
- __le16 pktlen_gen_bufq_id;
- __le16 hdrlen_flags;
- /* Qword 1 */
- u8 status_err0_qw1;
- u8 status_err1;
- u8 fflags1;
- u8 ts_low;
- __le16 buf_id;
- union {
- __le16 raw_cs;
- __le16 l2tag1;
- __le16 rscseglen;
- } misc;
- /* Qword 2 */
- __le16 hash1;
- union {
- u8 fflags2;
- u8 mirrorid;
- u8 hash2;
- } ff2_mirrid_hash2;
- u8 hash3;
- __le16 l2tag2;
- __le16 fmd4;
- /* Qword 3 */
- __le16 l2tag1;
- __le16 fmd6;
- __le32 ts_high;
-};
-
-/* Common union for accessing descriptor format structs */
-union virtchnl2_rx_desc {
- struct virtchnl2_singleq_base_rx_desc base_wb;
- struct virtchnl2_rx_flex_desc_nic flex_nic_wb;
- struct virtchnl2_rx_flex_desc_adv_nic_3 flex_adv_nic_3_wb;
-};
-
-#endif /* _VIRTCHNL_LAN_DESC_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c
index 958d16f87424..cbccd4546768 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.c
+++ b/drivers/net/ethernet/intel/idpf/xdp.c
@@ -2,21 +2,22 @@
/* Copyright (C) 2025 Intel Corporation */
#include "idpf.h"
+#include "idpf_ptp.h"
#include "idpf_virtchnl.h"
#include "xdp.h"
#include "xsk.h"
-static int idpf_rxq_for_each(const struct idpf_vport *vport,
+static int idpf_rxq_for_each(const struct idpf_q_vec_rsrc *rsrc,
int (*fn)(struct idpf_rx_queue *rxq, void *arg),
void *arg)
{
- bool splitq = idpf_is_queue_model_split(vport->rxq_model);
+ bool splitq = idpf_is_queue_model_split(rsrc->rxq_model);
- if (!vport->rxq_grps)
+ if (!rsrc->rxq_grps)
return -ENETDOWN;
- for (u32 i = 0; i < vport->num_rxq_grp; i++) {
- const struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ for (u32 i = 0; i < rsrc->num_rxq_grp; i++) {
+ const struct idpf_rxq_group *rx_qgrp = &rsrc->rxq_grps[i];
u32 num_rxq;
if (splitq)
@@ -45,15 +46,23 @@ static int idpf_rxq_for_each(const struct idpf_vport *vport,
static int __idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq, void *arg)
{
const struct idpf_vport *vport = rxq->q_vector->vport;
- bool split = idpf_is_queue_model_split(vport->rxq_model);
+ const struct idpf_q_vec_rsrc *rsrc;
+ u32 frag_size = 0;
+ bool split;
int err;
+ if (idpf_queue_has(XSK, rxq))
+ frag_size = rxq->bufq_sets[0].bufq.truesize;
+
err = __xdp_rxq_info_reg(&rxq->xdp_rxq, vport->netdev, rxq->idx,
rxq->q_vector->napi.napi_id,
- rxq->rx_buf_size);
+ frag_size);
if (err)
return err;
+ rsrc = &vport->dflt_qv_rsrc;
+ split = idpf_is_queue_model_split(rsrc->rxq_model);
+
if (idpf_queue_has(XSK, rxq)) {
err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
@@ -70,7 +79,7 @@ static int __idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq, void *arg)
if (!split)
return 0;
- rxq->xdpsqs = &vport->txqs[vport->xdp_txq_offset];
+ rxq->xdpsqs = &vport->txqs[rsrc->xdp_txq_offset];
rxq->num_xdp_txq = vport->num_xdp_txq;
return 0;
@@ -86,9 +95,9 @@ int idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq)
return __idpf_xdp_rxq_info_init(rxq, NULL);
}
-int idpf_xdp_rxq_info_init_all(const struct idpf_vport *vport)
+int idpf_xdp_rxq_info_init_all(const struct idpf_q_vec_rsrc *rsrc)
{
- return idpf_rxq_for_each(vport, __idpf_xdp_rxq_info_init, NULL);
+ return idpf_rxq_for_each(rsrc, __idpf_xdp_rxq_info_init, NULL);
}
static int __idpf_xdp_rxq_info_deinit(struct idpf_rx_queue *rxq, void *arg)
@@ -111,10 +120,10 @@ void idpf_xdp_rxq_info_deinit(struct idpf_rx_queue *rxq, u32 model)
__idpf_xdp_rxq_info_deinit(rxq, (void *)(size_t)model);
}
-void idpf_xdp_rxq_info_deinit_all(const struct idpf_vport *vport)
+void idpf_xdp_rxq_info_deinit_all(const struct idpf_q_vec_rsrc *rsrc)
{
- idpf_rxq_for_each(vport, __idpf_xdp_rxq_info_deinit,
- (void *)(size_t)vport->rxq_model);
+ idpf_rxq_for_each(rsrc, __idpf_xdp_rxq_info_deinit,
+ (void *)(size_t)rsrc->rxq_model);
}
static int idpf_xdp_rxq_assign_prog(struct idpf_rx_queue *rxq, void *arg)
@@ -132,10 +141,10 @@ static int idpf_xdp_rxq_assign_prog(struct idpf_rx_queue *rxq, void *arg)
return 0;
}
-void idpf_xdp_copy_prog_to_rqs(const struct idpf_vport *vport,
+void idpf_xdp_copy_prog_to_rqs(const struct idpf_q_vec_rsrc *rsrc,
struct bpf_prog *xdp_prog)
{
- idpf_rxq_for_each(vport, idpf_xdp_rxq_assign_prog, xdp_prog);
+ idpf_rxq_for_each(rsrc, idpf_xdp_rxq_assign_prog, xdp_prog);
}
static void idpf_xdp_tx_timer(struct work_struct *work);
@@ -149,7 +158,7 @@ int idpf_xdpsqs_get(const struct idpf_vport *vport)
if (!idpf_xdp_enabled(vport))
return 0;
- timers = kvcalloc(vport->num_xdp_txq, sizeof(*timers), GFP_KERNEL);
+ timers = kvzalloc_objs(*timers, vport->num_xdp_txq);
if (!timers)
return -ENOMEM;
@@ -165,7 +174,7 @@ int idpf_xdpsqs_get(const struct idpf_vport *vport)
}
dev = vport->netdev;
- sqs = vport->xdp_txq_offset;
+ sqs = vport->dflt_qv_rsrc.xdp_txq_offset;
for (u32 i = sqs; i < vport->num_txq; i++) {
struct idpf_tx_queue *xdpsq = vport->txqs[i];
@@ -202,7 +211,7 @@ void idpf_xdpsqs_put(const struct idpf_vport *vport)
return;
dev = vport->netdev;
- sqs = vport->xdp_txq_offset;
+ sqs = vport->dflt_qv_rsrc.xdp_txq_offset;
for (u32 i = sqs; i < vport->num_txq; i++) {
struct idpf_tx_queue *xdpsq = vport->txqs[i];
@@ -358,12 +367,15 @@ int idpf_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
{
const struct idpf_netdev_priv *np = netdev_priv(dev);
const struct idpf_vport *vport = np->vport;
+ u32 xdp_txq_offset;
if (unlikely(!netif_carrier_ok(dev) || !vport->link_up))
return -ENETDOWN;
+ xdp_txq_offset = vport->dflt_qv_rsrc.xdp_txq_offset;
+
return libeth_xdp_xmit_do_bulk(dev, n, frames, flags,
- &vport->txqs[vport->xdp_txq_offset],
+ &vport->txqs[xdp_txq_offset],
vport->num_xdp_txq,
idpf_xdp_xmit_flush_bulk,
idpf_xdp_tx_finalize);
@@ -391,13 +403,43 @@ static int idpf_xdpmo_rx_hash(const struct xdp_md *ctx, u32 *hash,
pt);
}
+static int idpf_xdpmo_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp)
+{
+ const struct libeth_xdp_buff *xdp = (typeof(xdp))ctx;
+ struct idpf_xdp_rx_desc desc __uninitialized;
+ const struct idpf_rx_queue *rxq;
+ u64 cached_time, ts_ns;
+ u32 ts_high;
+
+ rxq = libeth_xdp_buff_to_rq(xdp, typeof(*rxq), xdp_rxq);
+
+ if (!idpf_queue_has(PTP, rxq))
+ return -ENODATA;
+
+ idpf_xdp_get_qw1(&desc, xdp->desc);
+
+ if (!(idpf_xdp_rx_ts_low(&desc) & VIRTCHNL2_RX_FLEX_TSTAMP_VALID))
+ return -ENODATA;
+
+ cached_time = READ_ONCE(rxq->cached_phc_time);
+
+ idpf_xdp_get_qw3(&desc, xdp->desc);
+
+ ts_high = idpf_xdp_rx_ts_high(&desc);
+ ts_ns = idpf_ptp_tstamp_extend_32b_to_64b(cached_time, ts_high);
+
+ *timestamp = ts_ns;
+ return 0;
+}
+
static const struct xdp_metadata_ops idpf_xdpmo = {
.xmo_rx_hash = idpf_xdpmo_rx_hash,
+ .xmo_rx_timestamp = idpf_xdpmo_rx_timestamp,
};
void idpf_xdp_set_features(const struct idpf_vport *vport)
{
- if (!idpf_is_queue_model_split(vport->rxq_model))
+ if (!idpf_is_queue_model_split(vport->dflt_qv_rsrc.rxq_model))
return;
libeth_xdp_set_features_noredir(vport->netdev, &idpf_xdpmo,
@@ -409,6 +451,7 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport,
const struct netdev_bpf *xdp)
{
const struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
+ const struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct bpf_prog *old, *prog = xdp->prog;
struct idpf_vport_config *cfg;
int ret;
@@ -419,7 +462,7 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport,
!test_bit(IDPF_VPORT_REG_NETDEV, cfg->flags) ||
!!vport->xdp_prog == !!prog) {
if (test_bit(IDPF_VPORT_UP, np->state))
- idpf_xdp_copy_prog_to_rqs(vport, prog);
+ idpf_xdp_copy_prog_to_rqs(rsrc, prog);
old = xchg(&vport->xdp_prog, prog);
if (old)
@@ -464,7 +507,7 @@ int idpf_xdp(struct net_device *dev, struct netdev_bpf *xdp)
idpf_vport_ctrl_lock(dev);
vport = idpf_netdev_to_vport(dev);
- if (!idpf_is_queue_model_split(vport->txq_model))
+ if (!idpf_is_queue_model_split(vport->dflt_qv_rsrc.txq_model))
goto notsupp;
switch (xdp->command) {
diff --git a/drivers/net/ethernet/intel/idpf/xdp.h b/drivers/net/ethernet/intel/idpf/xdp.h
index 479f5ef3c604..63e56f7d43e0 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.h
+++ b/drivers/net/ethernet/intel/idpf/xdp.h
@@ -9,10 +9,10 @@
#include "idpf_txrx.h"
int idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq);
-int idpf_xdp_rxq_info_init_all(const struct idpf_vport *vport);
+int idpf_xdp_rxq_info_init_all(const struct idpf_q_vec_rsrc *rsrc);
void idpf_xdp_rxq_info_deinit(struct idpf_rx_queue *rxq, u32 model);
-void idpf_xdp_rxq_info_deinit_all(const struct idpf_vport *vport);
-void idpf_xdp_copy_prog_to_rqs(const struct idpf_vport *vport,
+void idpf_xdp_rxq_info_deinit_all(const struct idpf_q_vec_rsrc *rsrc);
+void idpf_xdp_copy_prog_to_rqs(const struct idpf_q_vec_rsrc *rsrc,
struct bpf_prog *xdp_prog);
int idpf_xdpsqs_get(const struct idpf_vport *vport);
@@ -112,11 +112,13 @@ struct idpf_xdp_rx_desc {
aligned_u64 qw1;
#define IDPF_XDP_RX_BUF GENMASK_ULL(47, 32)
#define IDPF_XDP_RX_EOP BIT_ULL(1)
+#define IDPF_XDP_RX_TS_LOW GENMASK_ULL(31, 24)
aligned_u64 qw2;
#define IDPF_XDP_RX_HASH GENMASK_ULL(31, 0)
aligned_u64 qw3;
+#define IDPF_XDP_RX_TS_HIGH GENMASK_ULL(63, 32)
} __aligned(4 * sizeof(u64));
static_assert(sizeof(struct idpf_xdp_rx_desc) ==
sizeof(struct virtchnl2_rx_flex_desc_adv_nic_3));
@@ -128,6 +130,8 @@ static_assert(sizeof(struct idpf_xdp_rx_desc) ==
#define idpf_xdp_rx_buf(desc) FIELD_GET(IDPF_XDP_RX_BUF, (desc)->qw1)
#define idpf_xdp_rx_eop(desc) !!((desc)->qw1 & IDPF_XDP_RX_EOP)
#define idpf_xdp_rx_hash(desc) FIELD_GET(IDPF_XDP_RX_HASH, (desc)->qw2)
+#define idpf_xdp_rx_ts_low(desc) FIELD_GET(IDPF_XDP_RX_TS_LOW, (desc)->qw1)
+#define idpf_xdp_rx_ts_high(desc) FIELD_GET(IDPF_XDP_RX_TS_HIGH, (desc)->qw3)
static inline void
idpf_xdp_get_qw0(struct idpf_xdp_rx_desc *desc,
@@ -149,6 +153,9 @@ idpf_xdp_get_qw1(struct idpf_xdp_rx_desc *desc,
desc->qw1 = ((const typeof(desc))rxd)->qw1;
#else
desc->qw1 = ((u64)le16_to_cpu(rxd->buf_id) << 32) |
+ ((u64)rxd->ts_low << 24) |
+ ((u64)rxd->fflags1 << 16) |
+ ((u64)rxd->status_err1 << 8) |
rxd->status_err0_qw1;
#endif
}
@@ -166,6 +173,19 @@ idpf_xdp_get_qw2(struct idpf_xdp_rx_desc *desc,
#endif
}
+static inline void
+idpf_xdp_get_qw3(struct idpf_xdp_rx_desc *desc,
+ const struct virtchnl2_rx_flex_desc_adv_nic_3 *rxd)
+{
+#ifdef __LIBETH_WORD_ACCESS
+ desc->qw3 = ((const typeof(desc))rxd)->qw3;
+#else
+ desc->qw3 = ((u64)le32_to_cpu(rxd->ts_high) << 32) |
+ ((u64)le16_to_cpu(rxd->fmd6) << 16) |
+ le16_to_cpu(rxd->l2tag1);
+#endif
+}
+
void idpf_xdp_set_features(const struct idpf_vport *vport);
int idpf_xdp(struct net_device *dev, struct netdev_bpf *xdp);
diff --git a/drivers/net/ethernet/intel/idpf/xsk.c b/drivers/net/ethernet/intel/idpf/xsk.c
index fd2cc43ab43c..d95d3efdfd36 100644
--- a/drivers/net/ethernet/intel/idpf/xsk.c
+++ b/drivers/net/ethernet/intel/idpf/xsk.c
@@ -26,13 +26,14 @@ static void idpf_xsk_setup_rxq(const struct idpf_vport *vport,
static void idpf_xsk_setup_bufq(const struct idpf_vport *vport,
struct idpf_buf_queue *bufq)
{
+ const struct idpf_q_vec_rsrc *rsrc = &vport->dflt_qv_rsrc;
struct xsk_buff_pool *pool;
u32 qid = U32_MAX;
- for (u32 i = 0; i < vport->num_rxq_grp; i++) {
- const struct idpf_rxq_group *grp = &vport->rxq_grps[i];
+ for (u32 i = 0; i < rsrc->num_rxq_grp; i++) {
+ const struct idpf_rxq_group *grp = &rsrc->rxq_grps[i];
- for (u32 j = 0; j < vport->num_bufqs_per_qgrp; j++) {
+ for (u32 j = 0; j < rsrc->num_bufqs_per_qgrp; j++) {
if (&grp->splitq.bufq_sets[j].bufq == bufq) {
qid = grp->splitq.rxq_sets[0]->rxq.idx;
goto setup;
@@ -61,7 +62,7 @@ static void idpf_xsk_setup_txq(const struct idpf_vport *vport,
if (!idpf_queue_has(XDP, txq))
return;
- qid = txq->idx - vport->xdp_txq_offset;
+ qid = txq->idx - vport->dflt_qv_rsrc.xdp_txq_offset;
pool = xsk_get_pool_from_qid(vport->netdev, qid);
if (!pool || !pool->dev)
@@ -86,7 +87,8 @@ static void idpf_xsk_setup_complq(const struct idpf_vport *vport,
if (!idpf_queue_has(XDP, complq))
return;
- qid = complq->txq_grp->txqs[0]->idx - vport->xdp_txq_offset;
+ qid = complq->txq_grp->txqs[0]->idx -
+ vport->dflt_qv_rsrc.xdp_txq_offset;
pool = xsk_get_pool_from_qid(vport->netdev, qid);
if (!pool || !pool->dev)
@@ -401,6 +403,7 @@ int idpf_xskfq_init(struct idpf_buf_queue *bufq)
bufq->pending = fq.pending;
bufq->thresh = fq.thresh;
bufq->rx_buf_size = fq.buf_len;
+ bufq->truesize = fq.truesize;
if (!idpf_xskfq_refill(bufq))
netdev_err(bufq->pool->netdev,
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 63ec253ac788..9e696d55e512 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -87,6 +87,27 @@ union e1000_adv_rx_desc {
} wb; /* writeback */
};
+#define E1000_RSS_TYPE_NO_HASH 0
+#define E1000_RSS_TYPE_HASH_TCP_IPV4 1
+#define E1000_RSS_TYPE_HASH_IPV4 2
+#define E1000_RSS_TYPE_HASH_TCP_IPV6 3
+#define E1000_RSS_TYPE_HASH_IPV6_EX 4
+#define E1000_RSS_TYPE_HASH_IPV6 5
+#define E1000_RSS_TYPE_HASH_TCP_IPV6_EX 6
+#define E1000_RSS_TYPE_HASH_UDP_IPV4 7
+#define E1000_RSS_TYPE_HASH_UDP_IPV6 8
+#define E1000_RSS_TYPE_HASH_UDP_IPV6_EX 9
+
+#define E1000_RSS_TYPE_MASK GENMASK(3, 0)
+
+#define E1000_RSS_L4_TYPES_MASK \
+ (BIT(E1000_RSS_TYPE_HASH_TCP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6_EX) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6_EX))
+
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index fa028928482f..7e6f9aa2d57b 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -442,7 +442,7 @@
/* Interrupt Cause Set */
#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
-#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */
+#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Asserted */
/* Extended Interrupt Cause Set */
/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index 9db29b231d6a..784f9a7bcbed 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -756,11 +756,7 @@ static s32 __igb_access_xmdio_reg(struct e1000_hw *hw, u16 address,
return ret_val;
/* Recalibrate the device back to 0 */
- ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
- if (ret_val)
- return ret_val;
-
- return ret_val;
+ return hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
}
/**
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index fa3dfafd2bb1..2bcce6eef0c7 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1581,7 +1581,7 @@ out:
* igb_validate_mdi_setting - Verify MDI/MDIx settings
* @hw: pointer to the HW structure
*
- * Verify that when not using auto-negotitation that MDI/MDIx is correctly
+ * Verify that when not using auto-negotiation that MDI/MDIx is correctly
* set, which is forced to MDI mode only.
**/
s32 igb_validate_mdi_setting(struct e1000_hw *hw)
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index 178e60ec71d4..9e44527f5eea 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -30,7 +30,7 @@
/* Indicates that VF is still clear to send requests */
#define E1000_VT_MSGTYPE_CTS 0x20000000
#define E1000_VT_MSGINFO_SHIFT 16
-/* bits 23:16 are used for exra info for certain messages */
+/* bits 23:16 are used for extra info for certain messages */
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_RESET 0x01 /* VF requests reset */
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index c8638502c2be..cf4e5d0e9417 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -405,7 +405,7 @@ out:
* Writes data to EEPROM at offset using SPI interface.
*
* If e1000_update_nvm_checksum is not called after this function , the
- * EEPROM will most likley contain an invalid checksum.
+ * EEPROM will most likely contain an invalid checksum.
**/
s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0fff1df81b7b..8c9b02058cec 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -495,6 +495,7 @@ struct hwmon_buff {
#define IGB_N_PEROUT 2
#define IGB_N_SDP 4
#define IGB_RETA_SIZE 128
+#define IGB_RSS_KEY_SIZE 40
enum igb_filter_match_flags {
IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
@@ -655,6 +656,7 @@ struct igb_adapter {
struct i2c_client *i2c_client;
u32 rss_indir_tbl_init;
u8 rss_indir_tbl[IGB_RETA_SIZE];
+ u8 rss_key[IGB_RSS_KEY_SIZE];
unsigned long link_check_timeout;
int copper_tries;
@@ -735,6 +737,7 @@ void igb_down(struct igb_adapter *);
void igb_reinit_locked(struct igb_adapter *);
void igb_reset(struct igb_adapter *);
int igb_reinit_queues(struct igb_adapter *);
+void igb_write_rss_key(struct igb_adapter *adapter);
void igb_write_rss_indir_tbl(struct igb_adapter *);
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
int igb_setup_tx_resources(struct igb_ring *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index b507576b28b2..65014a54a6d1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2919,7 +2919,7 @@ static int igb_add_ethtool_nfc_entry(struct igb_adapter *adapter,
if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW)
return -EINVAL;
- input = kzalloc(sizeof(*input), GFP_KERNEL);
+ input = kzalloc_obj(*input);
if (!input)
return -ENOMEM;
@@ -3019,6 +3019,27 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
+/**
+ * igb_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igb_write_rss_key(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ ASSERT_RTNL();
+
+ for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
+ u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+
+ wr32(E1000_RSSRK(i), val);
+ }
+}
+
static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -3276,10 +3297,12 @@ static int igb_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+ if (rxfh->indir)
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -3319,6 +3342,11 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
}
+static u32 igb_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGB_RSS_KEY_SIZE;
+}
+
static int igb_set_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
@@ -3329,35 +3357,39 @@ static int igb_set_rxfh(struct net_device *netdev,
u32 num_queues;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- switch (hw->mac.type) {
- case e1000_82576:
- /* 82576 supports 2 RSS queues for SR-IOV */
- if (adapter->vfs_allocated_count)
- num_queues = 2;
- break;
- default:
- break;
- }
+ switch (hw->mac.type) {
+ case e1000_82576:
+ /* 82576 supports 2 RSS queues for SR-IOV */
+ if (adapter->vfs_allocated_count)
+ num_queues = 2;
+ break;
+ default:
+ break;
+ }
+
+ /* Verify user input. */
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- /* Verify user input. */
- for (i = 0; i < IGB_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
- for (i = 0; i < IGB_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ igb_write_rss_indir_tbl(adapter);
+ }
- igb_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igb_write_rss_key(adapter);
+ }
return 0;
}
@@ -3483,6 +3515,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_module_eeprom = igb_get_module_eeprom,
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
.get_rxfh = igb_get_rxfh,
+ .get_rxfh_key_size = igb_get_rxfh_key_size,
.set_rxfh = igb_set_rxfh,
.get_rxfh_fields = igb_get_rxfh_fields,
.set_rxfh_fields = igb_set_rxfh_fields,
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index dbea37269d2c..d4a897a8c82c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -63,40 +63,40 @@ static const struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_FLASHLESS), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES_FLASHLESS), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_FLASHLESS), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES_FLASHLESS), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), .driver_data = board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), .driver_data = board_82575 },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
@@ -2203,9 +2203,8 @@ void igb_down(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igb_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igb_set_queue_napi(adapter, i, NULL);
}
}
@@ -2711,7 +2710,7 @@ static int igb_configure_clsflower(struct igb_adapter *adapter,
return -EINVAL;
}
- filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ filter = kzalloc_obj(*filter);
if (!filter)
return -ENOMEM;
@@ -3775,8 +3774,8 @@ static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs, bool reinit)
} else
adapter->vfs_allocated_count = num_vfs;
- adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
- sizeof(struct vf_data_storage), GFP_KERNEL);
+ adapter->vf_data = kzalloc_objs(struct vf_data_storage,
+ adapter->vfs_allocated_count);
/* if allocation failed then we do not support SR-IOV */
if (!adapter->vf_data) {
@@ -3794,9 +3793,8 @@ static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs, bool reinit)
(1 + IGB_PF_MAC_FILTERS_RESERVED +
adapter->vfs_allocated_count);
- adapter->vf_mac_list = kcalloc(num_vf_mac_filters,
- sizeof(struct vf_mac_filter),
- GFP_KERNEL);
+ adapter->vf_mac_list = kzalloc_objs(struct vf_mac_filter,
+ num_vf_mac_filters);
mac_list = adapter->vf_mac_list;
INIT_LIST_HEAD(&adapter->vf_macs.l);
@@ -4050,6 +4048,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGB_DEFAULT_TXD;
adapter->rx_ring_count = IGB_DEFAULT_RXD;
@@ -4091,9 +4092,8 @@ static int igb_sw_init(struct igb_adapter *adapter)
/* Assume MSI-X interrupts, will be checked during IRQ allocation */
adapter->flags |= IGB_FLAG_HAS_MSIX;
- adapter->mac_table = kcalloc(hw->mac.rar_entry_count,
- sizeof(struct igb_mac_addr),
- GFP_KERNEL);
+ adapter->mac_table = kzalloc_objs(struct igb_mac_addr,
+ hw->mac.rar_entry_count);
if (!adapter->mac_table)
return -ENOMEM;
@@ -4525,11 +4525,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(E1000_RSSRK(j), rss_key[j]);
+ igb_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -7160,7 +7157,7 @@ static irqreturn_t igb_msix_ring(int irq, void *data)
/* Write the ITR value calculated from the previous interrupt. */
igb_write_itr(q_vector);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -8201,7 +8198,7 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
if (icr & E1000_ICR_TS)
igb_tsync_interrupt(adapter);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -8247,7 +8244,7 @@ static irqreturn_t igb_intr(int irq, void *data)
if (icr & E1000_ICR_TS)
igb_tsync_interrupt(adapter);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -8823,10 +8820,19 @@ static inline void igb_rx_hash(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
- if (ring->netdev->features & NETIF_F_RXHASH)
- skb_set_hash(skb,
- le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
- PKT_HASH_TYPE_L3);
+ u16 rss_type;
+
+ if (!(ring->netdev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.pkt_info) &
+ E1000_RSS_TYPE_MASK;
+ if (!rss_type)
+ return;
+
+ skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ (E1000_RSS_L4_TYPES_MASK & BIT(rss_type)) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
/**
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index bd85d02ecadd..638d8242b66b 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -1500,12 +1500,13 @@ void igb_ptp_reset(struct igb_adapter *adapter)
/* Re-initialize the timer. */
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
- struct timespec64 ts = ktime_to_timespec64(ktime_get_real());
+ struct timespec64 ts;
+ ktime_get_real_ts64(&ts);
igb_ptp_write_i210(adapter, &ts);
} else {
timecounter_init(&adapter->tc, &adapter->cc,
- ktime_to_ns(ktime_get_real()));
+ ktime_get_real_ns());
}
out:
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
diff --git a/drivers/net/ethernet/intel/igb/igb_xsk.c b/drivers/net/ethernet/intel/igb/igb_xsk.c
index 30ce5fbb5b77..ce4a7b58cad2 100644
--- a/drivers/net/ethernet/intel/igb/igb_xsk.c
+++ b/drivers/net/ethernet/intel/igb/igb_xsk.c
@@ -524,6 +524,16 @@ bool igb_xmit_zc(struct igb_ring *tx_ring, struct xsk_buff_pool *xsk_pool)
return nb_pkts < budget;
}
+static u32 igb_sw_irq_prep(struct igb_q_vector *q_vector)
+{
+ u32 eics = 0;
+
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
+}
+
int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
{
struct igb_adapter *adapter = netdev_priv(dev);
@@ -542,20 +552,32 @@ int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
ring = adapter->tx_ring[qid];
- if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
- return -ENETDOWN;
-
if (!READ_ONCE(ring->xsk_pool))
return -EINVAL;
- if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
+ if (flags & XDP_WAKEUP_TX) {
+ if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
+ return -ENETDOWN;
+
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (flags & XDP_WAKEUP_RX) {
+ /* If IGB_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the TX path, making this RX call a NOP
+ */
+ ring = adapter->rx_ring[qid];
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics) {
/* Cause software interrupt */
- if (adapter->flags & IGB_FLAG_HAS_MSIX) {
- eics |= ring->q_vector->eims_value;
+ if (adapter->flags & IGB_FLAG_HAS_MSIX)
wr32(E1000_EICS, eics);
- } else {
+ else
wr32(E1000_ICS, E1000_ICS_RXDMT0);
- }
}
return 0;
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index ac57212ab02b..c686ee120a14 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -1017,8 +1017,7 @@ static void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter)
int i;
/* we allocate 3 vectors, 1 for Tx, 1 for Rx, one for PF messages */
- adapter->msix_entries = kcalloc(3, sizeof(struct msix_entry),
- GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, 3);
if (adapter->msix_entries) {
for (i = 0; i < 3; i++)
adapter->msix_entries[i].entry = i;
@@ -1098,11 +1097,11 @@ static int igbvf_alloc_queues(struct igbvf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- adapter->tx_ring = kzalloc(sizeof(struct igbvf_ring), GFP_KERNEL);
+ adapter->tx_ring = kzalloc_obj(struct igbvf_ring);
if (!adapter->tx_ring)
return -ENOMEM;
- adapter->rx_ring = kzalloc(sizeof(struct igbvf_ring), GFP_KERNEL);
+ adapter->rx_ring = kzalloc_obj(struct igbvf_ring);
if (!adapter->rx_ring) {
kfree(adapter->tx_ring);
return -ENOMEM;
@@ -2191,8 +2190,6 @@ dma_error:
buffer_info->time_stamp = 0;
buffer_info->length = 0;
buffer_info->mapped_as_page = false;
- if (count)
- count--;
/* clear timestamp and dma mappings for remaining portion of packet */
while (count--) {
@@ -2938,8 +2935,8 @@ static const struct pci_error_handlers igbvf_err_handler = {
};
static const struct pci_device_id igbvf_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), board_vf },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_VF), board_i350_vf },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), .driver_data = board_vf },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_VF), .driver_data = board_i350_vf },
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, igbvf_pci_tbl);
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index a427f05814c1..17f213cc93e4 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -30,6 +30,7 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_ETYPE_FILTER 8
#define IGC_RETA_SIZE 128
+#define IGC_RSS_KEY_SIZE 40
/* SDP support */
#define IGC_N_EXTTS 2
@@ -302,6 +303,7 @@ struct igc_adapter {
unsigned int nfc_rule_count;
u8 rss_indir_tbl[IGC_RETA_SIZE];
+ u8 rss_key[IGC_RSS_KEY_SIZE];
unsigned long link_check_timeout;
struct igc_info ei;
@@ -326,6 +328,7 @@ struct igc_adapter {
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
ktime_t ptp_reset_start; /* Reset time in clock mono */
struct system_time_snapshot snapshot;
+ clockid_t snapshot_clock_id;
struct mutex ptm_lock; /* Only allow one PTM transaction at a time */
char fw_version[32];
@@ -360,6 +363,7 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
const u32 max_rss_queues);
int igc_reinit_queues(struct igc_adapter *adapter);
+void igc_write_rss_key(struct igc_adapter *adapter);
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
@@ -781,6 +785,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void igc_ptp_tx_hang(struct igc_adapter *adapter);
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter,
+ u16 queue_id);
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c
index 1613b562d17c..ab9120a3127f 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.c
+++ b/drivers/net/ethernet/intel/igc/igc_base.c
@@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw)
u32 ctrl;
ctrl = rd32(IGC_CTRL);
- ctrl |= IGC_CTRL_SLU;
- ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
- wr32(IGC_CTRL, ctrl);
-
- ret_val = igc_setup_copper_link(hw);
+ ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX |
+ IGC_CTRL_SPEED_MASK | IGC_CTRL_FD);
+
+ if (hw->mac.autoneg_enabled) {
+ ctrl |= IGC_CTRL_SLU;
+ wr32(IGC_CTRL, ctrl);
+ ret_val = igc_setup_copper_link(hw);
+ } else {
+ ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX;
+
+ switch (hw->mac.forced_speed_duplex) {
+ case IGC_FORCED_10H:
+ ctrl |= IGC_CTRL_SPEED_10;
+ break;
+ case IGC_FORCED_10F:
+ ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD;
+ break;
+ case IGC_FORCED_100H:
+ ctrl |= IGC_CTRL_SPEED_100;
+ break;
+ case IGC_FORCED_100F:
+ ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD;
+ break;
+ default:
+ return -IGC_ERR_CONFIG;
+ }
+ wr32(IGC_CTRL, ctrl);
+ ret_val = igc_setup_copper_link(hw);
+ }
return ret_val;
}
@@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = {
.reset = igc_phy_hw_reset,
.read_reg = igc_read_phy_reg_gpy,
.write_reg = igc_write_phy_reg_gpy,
+ .force_speed_duplex = igc_force_speed_duplex,
};
const struct igc_info igc_base_info = {
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index 498ba1522ca4..3f504751c2d9 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -129,10 +129,13 @@
#define IGC_ERR_SWFW_SYNC 13
/* Device Control */
+#define IGC_CTRL_FD BIT(0) /* Full Duplex */
#define IGC_CTRL_RST 0x04000000 /* Global reset */
-
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define IGC_CTRL_SPEED_MASK GENMASK(10, 8)
+#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0)
+#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1)
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
@@ -443,9 +446,10 @@
#define IGC_TXPBSIZE_DEFAULT ( \
IGC_TXPB0SIZE(20) | IGC_TXPB1SIZE(0) | IGC_TXPB2SIZE(0) | \
IGC_TXPB3SIZE(0) | IGC_OS2BMCPBSIZE(4))
+/* TSN value following I225/I226 SW User Manual Section 7.5.4 */
#define IGC_TXPBSIZE_TSN ( \
- IGC_TXPB0SIZE(7) | IGC_TXPB1SIZE(7) | IGC_TXPB2SIZE(7) | \
- IGC_TXPB3SIZE(7) | IGC_OS2BMCPBSIZE(4))
+ IGC_TXPB0SIZE(5) | IGC_TXPB1SIZE(5) | IGC_TXPB2SIZE(5) | \
+ IGC_TXPB3SIZE(5) | IGC_OS2BMCPBSIZE(4))
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */
@@ -672,6 +676,10 @@
#define IGC_GEN_POLL_TIMEOUT 1920
/* PHY Control Register */
+#define MII_CR_SPEED_MASK (BIT(6) | BIT(13))
+#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */
+#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */
+#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full Duplex */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
diff --git a/drivers/net/ethernet/intel/igc/igc_diag.c b/drivers/net/ethernet/intel/igc/igc_diag.c
index a43d7244ee70..031561fdce49 100644
--- a/drivers/net/ethernet/intel/igc/igc_diag.c
+++ b/drivers/net/ethernet/intel/igc/igc_diag.c
@@ -172,7 +172,7 @@ bool igc_link_test(struct igc_adapter *adapter, u64 *data)
*data = 0;
- /* add delay to give enough time for autonegotioation to finish */
+ /* add delay to give enough time for autonegotiation to finish */
ssleep(5);
link_up = igc_has_link(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index e94c1922b97a..89fe2788a565 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1395,7 +1395,7 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
return -EINVAL;
}
- rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ rule = kzalloc_obj(*rule);
if (!rule)
return -ENOMEM;
@@ -1460,6 +1460,26 @@ static int igc_ethtool_set_rxnfc(struct net_device *dev,
}
}
+/**
+ * igc_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the IGC_RSSRK registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igc_write_rss_key(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 val;
+ int i;
+
+ for (i = 0; i < IGC_RSS_KEY_SIZE / 4; i++) {
+ val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+ wr32(IGC_RSSRK(i), val);
+ }
+}
+
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
@@ -1482,6 +1502,11 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
}
}
+static u32 igc_ethtool_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGC_RSS_KEY_SIZE;
+}
+
static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
{
return IGC_RETA_SIZE;
@@ -1494,10 +1519,13 @@ static int igc_ethtool_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->indir)
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -1511,24 +1539,28 @@ static int igc_ethtool_set_rxfh(struct net_device *netdev,
int i;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- /* Verify user input. */
- for (i = 0; i < IGC_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
+
+ igc_write_rss_indir_tbl(adapter);
+ }
- igc_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igc_write_rss_key(adapter);
+ }
return 0;
}
@@ -1565,8 +1597,8 @@ static int igc_ethtool_set_channels(struct net_device *netdev,
if (ch->other_count != NON_Q_VECTORS)
return -EINVAL;
- /* Do not allow channel reconfiguration when mqprio is enabled */
- if (adapter->strict_priority_enable)
+ /* Do not allow channel reconfiguration when any TSN qdisc is enabled */
+ if (adapter->flags & IGC_FLAG_TSN_ANY_ENABLED)
return -EINVAL;
/* Verify the number of channels doesn't exceed hw limits */
@@ -1914,44 +1946,58 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
- /* advertising link modes */
- if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
- if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
- if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
-
/* set autoneg settings */
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+ if (hw->mac.autoneg_enabled) {
+ ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+ cmd->base.autoneg = AUTONEG_ENABLE;
+
+ /* advertising link modes only apply when autoneg is on */
+ if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 10baseT_Half);
+ if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 10baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 100baseT_Half);
+ if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 100baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 1000baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 2500baseT_Full);
+
+ /* Set pause flow control advertising */
+ switch (hw->fc.requested_mode) {
+ case igc_fc_full:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Pause);
+ break;
+ case igc_fc_rx_pause:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Pause);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Asym_Pause);
+ break;
+ case igc_fc_tx_pause:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Asym_Pause);
+ break;
+ default:
+ break;
+ }
+ } else {
+ cmd->base.autoneg = AUTONEG_DISABLE;
+ }
- /* Set pause flow control settings */
+ /* Pause is always supported */
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
- switch (hw->fc.requested_mode) {
- case igc_fc_full:
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
- break;
- case igc_fc_rx_pause:
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Asym_Pause);
- break;
- case igc_fc_tx_pause:
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Asym_Pause);
- break;
- default:
- break;
- }
-
status = pm_runtime_suspended(&adapter->pdev->dev) ?
0 : rd32(IGC_STATUS);
@@ -1983,7 +2029,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
cmd->base.duplex = DUPLEX_UNKNOWN;
}
cmd->base.speed = speed;
- cmd->base.autoneg = AUTONEG_ENABLE;
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if (hw->phy.media_type == igc_media_type_copper)
@@ -2000,37 +2045,50 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
return 0;
}
-static int
-igc_ethtool_set_link_ksettings(struct net_device *netdev,
- const struct ethtool_link_ksettings *cmd)
+/**
+ * igc_handle_autoneg_disabled - Configure forced speed/duplex settings
+ * @adapter: private driver structure
+ * @speed: requested speed (must be SPEED_10 or SPEED_100)
+ * @duplex: requested duplex
+ *
+ * Records forced speed/duplex when autoneg is disabled.
+ * Caller must validate speed before calling this function.
+ */
+static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, u32 speed,
+ u8 duplex)
{
- struct igc_adapter *adapter = netdev_priv(netdev);
- struct net_device *dev = adapter->netdev;
- struct igc_hw *hw = &adapter->hw;
- u16 advertised = 0;
+ struct igc_mac_info *mac = &adapter->hw.mac;
- /* When adapter in resetting mode, autoneg/speed/duplex
- * cannot be changed
- */
- if (igc_check_reset_block(hw)) {
- netdev_err(dev, "Cannot change link characteristics when reset is active\n");
- return -EINVAL;
+ switch (speed) {
+ case SPEED_10:
+ mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
+ IGC_FORCED_10F : IGC_FORCED_10H;
+ break;
+ case SPEED_100:
+ mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
+ IGC_FORCED_100F : IGC_FORCED_100H;
+ break;
+ default:
+ WARN_ONCE(1, "Unsupported speed %u\n", speed);
+ return;
}
- /* MDI setting is only allowed when autoneg enabled because
- * some hardware doesn't allow MDI setting when speed or
- * duplex is forced.
- */
- if (cmd->base.eth_tp_mdix_ctrl) {
- if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
- cmd->base.autoneg != AUTONEG_ENABLE) {
- netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
- return -EINVAL;
- }
- }
+ mac->autoneg_enabled = false;
+}
- while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
- usleep_range(1000, 2000);
+/**
+ * igc_handle_autoneg_enabled - Configure autonegotiation advertisement
+ * @adapter: private driver structure
+ * @cmd: ethtool link ksettings from user
+ *
+ * Records advertised speeds and flow control settings when autoneg
+ * is enabled.
+ */
+static void igc_handle_autoneg_enabled(struct igc_adapter *adapter,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u16 advertised = 0;
if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
2500baseT_Full))
@@ -2056,14 +2114,66 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
10baseT_Half))
advertised |= ADVERTISE_10_HALF;
- if (cmd->base.autoneg == AUTONEG_ENABLE) {
- hw->phy.autoneg_advertised = advertised;
- if (adapter->fc_autoneg)
- hw->fc.requested_mode = igc_fc_default;
- } else {
- netdev_info(dev, "Force mode currently not supported\n");
+ hw->mac.autoneg_enabled = true;
+ hw->phy.autoneg_advertised = advertised;
+ if (adapter->fc_autoneg)
+ hw->fc.requested_mode = igc_fc_default;
+}
+
+static int
+igc_ethtool_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct net_device *dev = adapter->netdev;
+ struct igc_hw *hw = &adapter->hw;
+
+ /* When adapter in resetting mode, autoneg/speed/duplex
+ * cannot be changed
+ */
+ if (igc_check_reset_block(hw)) {
+ netdev_err(dev, "Cannot change link characteristics when reset is active\n");
+ return -EINVAL;
+ }
+
+ if (cmd->base.autoneg != AUTONEG_ENABLE &&
+ cmd->base.autoneg != AUTONEG_DISABLE) {
+ netdev_info(dev, "Unsupported autoneg setting\n");
+ return -EINVAL;
+ }
+
+ /* MDI setting is only allowed when autoneg enabled because
+ * some hardware doesn't allow MDI setting when speed or
+ * duplex is forced.
+ */
+ if (cmd->base.eth_tp_mdix_ctrl) {
+ if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
+ cmd->base.autoneg != AUTONEG_ENABLE) {
+ netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
+ return -EINVAL;
+ }
}
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ if (cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) {
+ netdev_info(dev, "Unsupported speed for forced link\n");
+ return -EINVAL;
+ }
+ if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) {
+ netdev_info(dev, "Duplex must be half or full for forced link\n");
+ return -EINVAL;
+ }
+ }
+
+ while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
+ usleep_range(1000, 2000);
+
+ if (cmd->base.autoneg == AUTONEG_ENABLE)
+ igc_handle_autoneg_enabled(adapter, cmd);
+ else
+ igc_handle_autoneg_disabled(adapter, cmd->base.speed,
+ cmd->base.duplex);
+
/* MDI-X => 2; MDI => 1; Auto => 3 */
if (cmd->base.eth_tp_mdix_ctrl) {
/* fix up the value for auto (3 => 0) as zero is mapped
@@ -2175,6 +2285,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
.get_rxnfc = igc_ethtool_get_rxnfc,
.set_rxnfc = igc_ethtool_set_rxnfc,
.get_rx_ring_count = igc_ethtool_get_rx_ring_count,
+ .get_rxfh_key_size = igc_ethtool_get_rxfh_key_size,
.get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size,
.get_rxfh = igc_ethtool_get_rxfh,
.set_rxfh = igc_ethtool_set_rxfh,
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h
index be8a49a86d09..62aaee55668a 100644
--- a/drivers/net/ethernet/intel/igc/igc_hw.h
+++ b/drivers/net/ethernet/intel/igc/igc_hw.h
@@ -73,6 +73,13 @@ struct igc_info {
extern const struct igc_info igc_base_info;
+enum igc_forced_speed_duplex {
+ IGC_FORCED_10H,
+ IGC_FORCED_10F,
+ IGC_FORCED_100H,
+ IGC_FORCED_100F,
+};
+
struct igc_mac_info {
struct igc_mac_operations ops;
@@ -92,8 +99,9 @@ struct igc_mac_info {
bool asf_firmware_present;
bool arc_subsystem_valid;
- bool autoneg_failed;
bool get_link_status;
+ bool autoneg_enabled;
+ enum igc_forced_speed_duplex forced_speed_duplex;
};
struct igc_nvm_operations {
diff --git a/drivers/net/ethernet/intel/igc/igc_leds.c b/drivers/net/ethernet/intel/igc/igc_leds.c
index 3929b25b6ae6..fdb9692516e8 100644
--- a/drivers/net/ethernet/intel/igc/igc_leds.c
+++ b/drivers/net/ethernet/intel/igc/igc_leds.c
@@ -268,7 +268,7 @@ int igc_led_setup(struct igc_adapter *adapter)
mutex_init(&adapter->led_mutex);
- leds = kcalloc(IGC_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
+ leds = kzalloc_objs(*leds, IGC_NUM_LEDS);
if (!leds)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
index 7ac6637f8db7..d6f3f6618469 100644
--- a/drivers/net/ethernet/intel/igc/igc_mac.c
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -438,26 +438,23 @@ void igc_config_collision_dist(struct igc_hw *hw)
* Checks the status of auto-negotiation after link up to ensure that the
* speed and duplex were not forced. If the link needed to be forced, then
* flow control needs to be forced also. If auto-negotiation is enabled
- * and did not fail, then we configure flow control based on our link
- * partner.
+ * then we configure flow control based on our link partner.
*/
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
{
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
- struct igc_mac_info *mac = &hw->mac;
u16 speed, duplex;
s32 ret_val = 0;
- /* Check for the case where we have fiber media and auto-neg failed
- * so we had to force link. In this case, we need to force the
- * configuration of the MAC to match the "fc" parameter.
+ /* Without autoneg, flow control capability is not exchanged with the
+ * link partner. IEEE 802.3 prohibits flow control in half-duplex mode.
*/
- if (mac->autoneg_failed)
- ret_val = igc_force_mac_fc(hw);
+ if (!hw->mac.autoneg_enabled) {
+ if (hw->mac.forced_speed_duplex == IGC_FORCED_10H ||
+ hw->mac.forced_speed_duplex == IGC_FORCED_100H)
+ hw->fc.current_mode = igc_fc_none;
- if (ret_val) {
- hw_dbg("Error forcing flow control settings\n");
- goto out;
+ goto force_fc;
}
/* In auto-neg, we need to check and see if Auto-Neg has completed,
@@ -472,15 +469,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
- goto out;
+ return ret_val;
}
/* The AutoNeg process has completed, so we now need to
@@ -492,11 +489,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
if (ret_val)
- goto out;
+ return ret_val;
/* Two bits in the Auto Negotiation Advertisement Register
* (Address 4) and two bits in the Auto Negotiation Base
* Page Ability Register (Address 5) determine flow control
@@ -612,7 +609,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
if (ret_val) {
hw_dbg("Error getting link speed and duplex\n");
- goto out;
+ return ret_val;
}
if (duplex == HALF_DUPLEX)
@@ -621,13 +618,13 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
/* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
*/
+force_fc:
ret_val = igc_force_mac_fc(hw);
if (ret_val) {
hw_dbg("Error forcing flow control settings\n");
- goto out;
+ return ret_val;
}
-out:
return ret_val;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 7aafa60ba0c8..1fb5f3cbe93c 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -47,24 +47,24 @@ static const struct igc_info *igc_info_tbl[] = {
};
static const struct pci_device_id igc_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_I), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I220_V), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_K), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_K2), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_K), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LMVP), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LMVP), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_IT), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LM), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_V), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_IT), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I221_V), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_BLANK_NVM), board_base },
- { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_BLANK_NVM), board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_I), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I220_V), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_K), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_K2), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_K), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LMVP), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LMVP), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_IT), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LM), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_V), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_IT), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I221_V), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_BLANK_NVM), .driver_data = board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_BLANK_NVM), .driver_data = board_base },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
@@ -264,6 +264,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
/* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
+
+ /* Clear any lingering XSK TX timestamp requests */
+ if (test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags)) {
+ struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
+
+ igc_ptp_clear_xsk_tx_tstamp_queue(adapter, tx_ring->queue_index);
+ }
}
/**
@@ -778,11 +785,8 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
struct igc_hw *hw = &adapter->hw;
u32 j, num_rx_queues;
u32 mrqc, rxcsum;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(IGC_RSSRK(j), rss_key[j]);
+ igc_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -1730,11 +1734,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
- if (skb->len < 17) {
- if (skb_padto(skb, 17))
- return NETDEV_TX_OK;
- skb->len = 17;
- }
+ if (skb_put_padto(skb, 17))
+ return NETDEV_TX_OK;
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
}
@@ -1793,7 +1794,7 @@ static const enum pkt_hash_types igc_rss_type_table[IGC_RSS_TYPE_MAX_TABLE] = {
[IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = PKT_HASH_TYPE_L4,
[10] = PKT_HASH_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */
[11] = PKT_HASH_TYPE_NONE, /* keep array sized for SW bit-mask */
- [12] = PKT_HASH_TYPE_NONE, /* to handle future HW revisons */
+ [12] = PKT_HASH_TYPE_NONE, /* to handle future HW revisions */
[13] = PKT_HASH_TYPE_NONE,
[14] = PKT_HASH_TYPE_NONE,
[15] = PKT_HASH_TYPE_NONE,
@@ -2645,7 +2646,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
}
if (igc_fpe_is_pmac_enabled(adapter) &&
- igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf)) {
+ igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf + pkt_offset)) {
/* Advance the ring next-to-clean */
igc_is_non_eop(rx_ring, rx_desc);
cleaned_count++;
@@ -3070,7 +3071,8 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
olinfo_status = xdp_desc.len << IGC_ADVTXD_PAYLEN_SHIFT;
dma = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
- meta = xsk_buff_get_metadata(pool, xdp_desc.addr);
+ meta = xsk_buff_get_metadata(pool, xdp_desc.addr,
+ xdp_desc.options);
xsk_buff_raw_dma_sync_for_device(pool, dma, xdp_desc.len);
bi = &ring->tx_buffer_info[ntu];
@@ -3078,7 +3080,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
meta_req.tx_buffer = bi;
meta_req.meta = meta;
meta_req.used_desc = 0;
- xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops,
+ xsk_tx_metadata_request(pool, &meta, &igc_xsk_tx_metadata_ops,
&meta_req);
/* xsk_tx_metadata_request() may have updated next_to_use */
@@ -4633,8 +4635,7 @@ static void igc_set_interrupt_capability(struct igc_adapter *adapter,
/* add 1 vector for link status interrupts */
numvecs++;
- adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
- GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, numvecs);
if (!adapter->msix_entries)
return;
@@ -4863,8 +4864,7 @@ static int igc_alloc_q_vector(struct igc_adapter *adapter,
/* allocate q_vector and rings */
q_vector = adapter->q_vector[v_idx];
if (!q_vector)
- q_vector = kzalloc(struct_size(q_vector, ring, ring_count),
- GFP_KERNEL);
+ q_vector = kzalloc_flex(*q_vector, ring, ring_count);
else
memset(q_vector, 0, struct_size(q_vector, ring, ring_count));
if (!q_vector)
@@ -5046,6 +5046,9 @@ static int igc_sw_init(struct igc_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGC_DEFAULT_TXD;
adapter->rx_ring_count = IGC_DEFAULT_RXD;
@@ -5350,9 +5353,8 @@ void igc_down(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igc_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igc_set_queue_napi(adapter, i, NULL);
}
}
@@ -5686,7 +5688,7 @@ static irqreturn_t igc_msix_ring(int irq, void *data)
/* Write the ITR value calculated from the previous interrupt. */
igc_write_itr(q_vector);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -6057,7 +6059,7 @@ static irqreturn_t igc_intr_msi(int irq, void *data)
if (icr & IGC_ICR_TS)
igc_tsync_interrupt(adapter);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -6103,7 +6105,7 @@ static irqreturn_t igc_intr(int irq, void *data)
if (icr & IGC_ICR_TS)
igc_tsync_interrupt(adapter);
- napi_schedule(&q_vector->napi);
+ napi_schedule_irqoff(&q_vector->napi);
return IRQ_HANDLED;
}
@@ -6908,28 +6910,29 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
-static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
- struct igc_q_vector *q_vector)
+static u32 igc_sw_irq_prep(struct igc_q_vector *q_vector)
{
- struct igc_hw *hw = &adapter->hw;
u32 eics = 0;
- eics |= q_vector->eims_value;
- wr32(IGC_EICS, eics);
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
}
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
{
struct igc_adapter *adapter = netdev_priv(dev);
- struct igc_q_vector *q_vector;
+ struct igc_hw *hw = &adapter->hw;
struct igc_ring *ring;
+ u32 eics = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return -ENETDOWN;
if (!igc_xdp_is_enabled(adapter))
return -ENXIO;
-
+ /* Check if queue_id is valid. Tx and Rx queue numbers are always same */
if (queue_id >= adapter->num_rx_queues)
return -EINVAL;
@@ -6938,9 +6941,22 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
if (!ring->xsk_pool)
return -ENXIO;
- q_vector = adapter->q_vector[queue_id];
- if (!napi_if_scheduled_mark_missed(&q_vector->napi))
- igc_trigger_rxtxq_interrupt(adapter, q_vector);
+ if (flags & XDP_WAKEUP_RX)
+ eics |= igc_sw_irq_prep(ring->q_vector);
+
+ if (flags & XDP_WAKEUP_TX) {
+ /* If IGC_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the RX path, making this TX call a NOP
+ */
+ ring = adapter->tx_ring[queue_id];
+ eics |= igc_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics)
+ /* Cause software interrupt */
+ wr32(IGC_EICS, eics);
return 0;
}
@@ -7023,7 +7039,7 @@ static enum xdp_rss_hash_type igc_xdp_rss_type[IGC_RSS_TYPE_MAX_TABLE] = {
[IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_UDP_EX,
[10] = XDP_RSS_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */
[11] = XDP_RSS_TYPE_NONE, /* keep array sized for SW bit-mask */
- [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisons */
+ [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisions */
[13] = XDP_RSS_TYPE_NONE,
[14] = XDP_RSS_TYPE_NONE,
[15] = XDP_RSS_TYPE_NONE,
@@ -7125,7 +7141,7 @@ static int igc_probe(struct pci_dev *pdev,
if (err)
goto err_pci_reg;
- err = pci_enable_ptm(pdev, NULL);
+ err = pci_enable_ptm(pdev);
if (err < 0)
dev_info(&pdev->dev, "PCIe PTM not supported by PCIe bus/controller\n");
@@ -7282,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev,
/* Initialize link properties that are user-changeable */
adapter->fc_autoneg = true;
hw->phy.autoneg_advertised = 0xaf;
-
+ hw->mac.autoneg_enabled = true;
hw->fc.requested_mode = igc_fc_default;
hw->fc.current_mode = igc_fc_default;
@@ -7570,11 +7586,13 @@ static int __igc_resume(struct device *dev, bool rpm)
err = __igc_open(netdev, true);
if (!rpm)
rtnl_unlock();
- if (!err)
- netif_device_attach(netdev);
+ if (err)
+ return err;
}
- return err;
+ netif_device_attach(netdev);
+
+ return 0;
}
static int igc_resume(struct device *dev)
@@ -7759,6 +7777,11 @@ int igc_reinit_queues(struct igc_adapter *adapter)
if (netif_running(netdev))
err = igc_open(netdev);
+ if (!err) {
+ /* Restore default IEEE 802.1Qbv schedule after queue reinit */
+ igc_tsn_clear_schedule(adapter);
+ }
+
return err;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
index 6c4d204aecfa..b758a7e0f013 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.c
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw)
s32 ret_val = 0;
bool link;
- /* Setup autoneg and flow control advertisement and perform
- * autonegotiation.
- */
- ret_val = igc_copper_link_autoneg(hw);
- if (ret_val)
- goto out;
+ if (hw->mac.autoneg_enabled) {
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = igc_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg("Error Forcing Speed/Duplex\n");
+ goto out;
+ }
+ }
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
@@ -667,11 +675,7 @@ static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
return ret_val;
/* Recalibrate the device back to 0 */
- ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
- if (ret_val)
- return ret_val;
-
- return ret_val;
+ return hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
}
/**
@@ -778,3 +782,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw)
return gphy_version;
}
+
+/**
+ * igc_force_speed_duplex - Force PHY speed and duplex settings
+ * @hw: pointer to the HW structure
+ *
+ * Programs the GPY PHY control register to disable autonegotiation
+ * and force the speed/duplex indicated by hw->mac.forced_speed_duplex.
+ */
+s32 igc_force_speed_duplex(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u16 phy_ctrl;
+ s32 ret_val;
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN |
+ MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+
+ switch (hw->mac.forced_speed_duplex) {
+ case IGC_FORCED_10H:
+ phy_ctrl |= MII_CR_SPEED_10;
+ break;
+ case IGC_FORCED_10F:
+ phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN;
+ break;
+ case IGC_FORCED_100H:
+ phy_ctrl |= MII_CR_SPEED_100;
+ break;
+ case IGC_FORCED_100F:
+ phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN;
+ break;
+ default:
+ return -IGC_ERR_CONFIG;
+ }
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ hw->mac.get_link_status = true;
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h
index 832a7e359f18..d37a89174826 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.h
+++ b/drivers/net/ethernet/intel/igc/igc_phy.h
@@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw);
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);
u16 igc_read_phy_fw_version(struct igc_hw *hw);
+s32 igc_force_speed_duplex(struct igc_hw *hw);
#endif
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index b7b46d863bee..b40aba9ab685 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -550,7 +550,8 @@ static void igc_ptp_free_tx_buffer(struct igc_adapter *adapter,
tstamp->buffer_type = 0;
/* Trigger txrx interrupt for transmit completion */
- igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index, 0);
+ igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
+ XDP_WAKEUP_TX);
return;
}
@@ -576,6 +577,39 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
+/**
+ * igc_ptp_clear_xsk_tx_tstamp_queue - Clear pending XSK TX timestamps for a queue
+ * @adapter: Board private structure
+ * @queue_id: TX queue index to clear timestamps for
+ *
+ * Iterates over all TX timestamp registers and releases any pending
+ * timestamp requests associated with the given TX queue. This is
+ * called when an XDP pool is being disabled to ensure no stale
+ * timestamp references remain.
+ */
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter, u16 queue_id)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
+
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+ if (tstamp->buffer_type != IGC_TX_BUFFER_TYPE_XSK)
+ continue;
+ if (tstamp->xsk_queue_index != queue_id)
+ continue;
+ if (!tstamp->xsk_tx_buffer)
+ continue;
+
+ igc_ptp_free_tx_buffer(adapter, tstamp);
+ }
+
+ spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
+}
+
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
@@ -774,36 +808,43 @@ static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
+ u32 txstmpl_old;
u64 regval;
u32 mask;
int i;
+ /* Establish baseline of TXSTMPL_0 before checking TXTT_0.
+ * This baseline is used to detect if a new timestamp arrives in
+ * register 0 during the hardware bug workaround below.
+ */
+ txstmpl_old = rd32(IGC_TXSTMPL);
+
mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
if (mask & IGC_TSYNCTXCTL_TXTT_0) {
regval = rd32(IGC_TXSTMPL);
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
} else {
- /* There's a bug in the hardware that could cause
- * missing interrupts for TX timestamping. The issue
- * is that for new interrupts to be triggered, the
- * IGC_TXSTMPH_0 register must be read.
+ /* TXTT_0 not set - register 0 has no new timestamp initially.
+ *
+ * Hardware bug: Future timestamp interrupts won't fire unless
+ * TXSTMPH_0 is read, even if the timestamp was captured in
+ * registers 1-3.
*
- * To avoid discarding a valid timestamp that just
- * happened at the "wrong" time, we need to confirm
- * that there was no timestamp captured, we do that by
- * assuming that no two timestamps in sequence have
- * the same nanosecond value.
+ * Workaround: Read TXSTMPH_0 here to enable future interrupts.
+ * However, this read clears TXTT_0. If a timestamp arrives in
+ * register 0 after checking TXTT_0 but before this read, it
+ * would be lost.
*
- * So, we read the "low" register, read the "high"
- * register (to latch a new timestamp) and read the
- * "low" register again, if "old" and "new" versions
- * of the "low" register are different, a valid
- * timestamp was captured, we can read the "high"
- * register again.
+ * To detect this race: We saved a baseline read of TXSTMPL_0
+ * before TXTT_0 check. After performing the workaround read of
+ * TXSTMPH_0, we read TXSTMPL_0 again. Since consecutive
+ * timestamps never share the same nanosecond value, a change
+ * between the baseline and new TXSTMPL_0 indicates a timestamp
+ * arrived during the race window. If so, read the complete
+ * timestamp.
*/
- u32 txstmpl_old, txstmpl_new;
+ u32 txstmpl_new;
- txstmpl_old = rd32(IGC_TXSTMPL);
rd32(IGC_TXSTMPH);
txstmpl_new = rd32(IGC_TXSTMPL);
@@ -818,7 +859,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
done:
/* Now that the problematic first register was handled, we can
- * use retrieve the timestamps from the other registers
+ * retrieve the timestamps from the other registers
* (starting from '1') with less complications.
*/
for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
@@ -1008,7 +1049,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device,
*/
do {
/* Get a snapshot of system clocks to use as historic value. */
- ktime_get_snapshot(&adapter->snapshot);
+ ktime_get_snapshot_id(adapter->snapshot_clock_id, &adapter->snapshot);
igc_ptm_trigger(hw);
@@ -1062,6 +1103,8 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
/* This blocks until any in progress PTM transactions complete */
mutex_lock(&adapter->ptm_lock);
+ adapter->snapshot_clock_id = cts->clock_id;
+
ret = get_device_system_crosststamp(igc_phc_get_syncdevicetime,
adapter, &adapter->snapshot, cts);
mutex_unlock(&adapter->ptm_lock);
diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c
index 8a110145bfee..d23a45a34fa3 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.c
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
@@ -34,6 +34,7 @@ static int igc_fpe_init_smd_frame(struct igc_ring *ring,
return -ENOMEM;
}
+ buffer->type = IGC_TX_BUFFER_TYPE_SKB;
buffer->skb = skb;
buffer->protocol = 0;
buffer->bytecount = skb->len;
@@ -109,10 +110,16 @@ static int igc_fpe_xmit_smd_frame(struct igc_adapter *adapter,
__netif_tx_lock(nq, cpu);
err = igc_fpe_init_tx_descriptor(ring, skb, type);
- igc_flush_tx_descriptors(ring);
+ if (err)
+ goto err_free_skb_any;
+ igc_flush_tx_descriptors(ring);
__netif_tx_unlock(nq);
+ return 0;
+err_free_skb_any:
+ __netif_tx_unlock(nq);
+ dev_kfree_skb_any(skb);
return err;
}
@@ -175,14 +182,16 @@ static u32 igc_fpe_map_preempt_tc_to_queue(const struct igc_adapter *adapter,
struct net_device *dev = adapter->netdev;
u32 i, queue = 0;
- for (i = 0; i < dev->num_tc; i++) {
+ for (i = 0; i < netdev_get_num_tc(dev); i++) {
+ struct netdev_tc_txq res;
u32 offset, count;
if (!(preemptible_tcs & BIT(i)))
continue;
- offset = dev->tc_to_txq[i].offset;
- count = dev->tc_to_txq[i].count;
+ res.combined = READ_ONCE(dev->tc_to_txq[i].combined);
+ offset = res.offset;
+ count = res.count;
queue |= GENMASK(offset + count - 1, offset);
}
diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
new file mode 100644
index 000000000000..0a48b3bb7bc2
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2025 Intel Corporation
+
+config IXD
+ tristate "Intel(R) Control Plane Function Support"
+ depends on PCI_MSI
+ select LIBIE_CP
+ select LIBIE_PCI
+ select NET_DEVLINK
+ help
+ This driver supports Intel(R) Control Plane PCI Function
+ of Intel E2100 and later IPUs and FNICs.
+ It facilitates a centralized control over multiple IDPF PFs/VFs/SFs
+ exposed by the same card.
diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
new file mode 100644
index 000000000000..03760a2580b9
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2025 Intel Corporation
+
+# Intel(R) Control Plane Function Linux Driver
+
+obj-$(CONFIG_IXD) += ixd.o
+
+ixd-y := ixd_main.o
+ixd-y += ixd_ctlq.o
+ixd-y += ixd_dev.o
+ixd-y += ixd_devlink.o
+ixd-y += ixd_lib.o
+ixd-y += ixd_virtchnl.o
diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
new file mode 100644
index 000000000000..2a09ccba13d5
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_H_
+#define _IXD_H_
+
+#include <linux/net/intel/libie/controlq.h>
+
+#define IXD_INIT_TASK_DELAY_JIFFIES msecs_to_jiffies(500)
+
+/**
+ * struct ixd_adapter - Data structure representing a CPF
+ * @cp_ctx: Control plane communication context
+ * @init_task: Delayed initialization after reset
+ * @init_task.init_work: Delayed initialization work
+ * @init_task.reset_retries: How many times to check, whether reset is completed
+ * @init_task.vc_retries: Number of retries to establish mailbox communication
+ * @init_task.success: init_work completion status
+ * @mbx_task: Control queue Rx handling
+ * @xnm: virtchnl transaction manager
+ * @asq: Send control queue info
+ * @arq: Receive control queue info
+ * @vc_ver: Negotiated virtchnl version
+ * @vc_ver.major: Negotiated major virtchnl version
+ * @vc_ver.minor: Negotiated minor virtchnl version
+ * @caps: Negotiated virtchnl capabilities
+ */
+struct ixd_adapter {
+ struct libie_ctlq_ctx cp_ctx;
+ struct {
+ struct delayed_work init_work;
+ u8 reset_retries;
+ u8 vc_retries;
+ bool success;
+ } init_task;
+ struct delayed_work mbx_task;
+ struct libie_ctlq_xn_manager *xnm;
+ struct libie_ctlq_info *asq;
+ struct libie_ctlq_info *arq;
+ struct {
+ u32 major;
+ u32 minor;
+ } vc_ver;
+ struct virtchnl2_get_capabilities caps;
+};
+
+/**
+ * ixd_to_dev - Get the corresponding device struct from an adapter
+ * @adapter: PCI device driver-specific private data
+ *
+ * Return: struct device corresponding to the given adapter
+ */
+static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)
+{
+ return &adapter->cp_ctx.mmio_info.pdev->dev;
+}
+
+void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
+ struct libie_ctlq_reg *ctlq_reg_tx,
+ struct libie_ctlq_reg *ctlq_reg_rx);
+void ixd_trigger_reset(struct ixd_adapter *adapter);
+bool ixd_check_reset_complete(struct ixd_adapter *adapter);
+void ixd_init_task(struct work_struct *work);
+int ixd_init_dflt_mbx(struct ixd_adapter *adapter);
+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);
+
+#endif /* _IXD_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
new file mode 100644
index 000000000000..8712e10c8c50
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_virtchnl.h"
+
+#define IXD_CTLQ_RX_TASK_DELAY_JIFFIES msecs_to_jiffies(300)
+
+/**
+ * ixd_ctlq_clean_sq - Clean the send control queue after sending the message
+ * @adapter: The adapter that sent the messages
+ * @force: Clean regardless of send status
+ *
+ * Free the libie send resources after sending the message and handling
+ * the response.
+ */
+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force)
+{
+ libie_ctlq_xn_send_clean(adapter->asq, kfree, force);
+}
+
+/**
+ * ixd_ctlq_init_sparams - Initialize control queue send parameters
+ * @adapter: The adapter with initialized mailbox
+ * @sparams: Parameters to initialize
+ * @msg_buf: DMA-mappable pointer to the message being sent
+ * @msg_size: Message size
+ */
+static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,
+ struct libie_ctlq_xn_send_params *sparams,
+ void *msg_buf, size_t msg_size)
+{
+ *sparams = (struct libie_ctlq_xn_send_params) {
+ .rel_tx_buf = kfree,
+ .xnm = adapter->xnm,
+ .ctlq = adapter->asq,
+ .timeout_ms = IXD_CTLQ_TIMEOUT,
+ .send_buf = (struct kvec) {
+ .iov_base = msg_buf,
+ .iov_len = msg_size,
+ },
+ };
+}
+
+/**
+ * ixd_ctlq_do_req - Perform a standard virtchnl request
+ * @adapter: The adapter with initialized mailbox
+ * @req: virtchnl request description
+ *
+ * Return: %0 if a message was sent and received a response
+ * that was successfully handled by the custom callback,
+ * negative error otherwise.
+ */
+int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
+{
+ u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] __aligned_largest = {};
+ struct libie_ctlq_xn_send_params send_params = {};
+ struct kvec *recv_mem;
+ void *send_buff;
+ int err;
+
+ send_buff = libie_cp_can_send_onstack(req->send_size) ?
+ &onstack_send_buff : kzalloc(req->send_size, GFP_KERNEL);
+ if (!send_buff)
+ return -ENOMEM;
+
+ ixd_ctlq_init_sparams(adapter, &send_params, send_buff,
+ req->send_size);
+
+ send_params.chnl_opcode = req->opcode;
+
+ if (req->send_buff_init)
+ req->send_buff_init(adapter, send_buff, req->ctx);
+
+ ixd_ctlq_clean_sq(adapter, false);
+ err = libie_ctlq_xn_send(&send_params);
+ if (err)
+ return err;
+
+ recv_mem = &send_params.recv_mem;
+ if (req->recv_process)
+ err = req->recv_process(adapter, recv_mem->iov_base,
+ recv_mem->iov_len, req->ctx);
+
+ libie_ctlq_release_rx_buf(recv_mem);
+
+ return err;
+}
+
+/**
+ * ixd_ctlq_handle_msg - Default control queue message handler
+ * @ctx: Control plane communication context
+ * @msg: Message received
+ */
+static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_msg *msg)
+{
+ struct ixd_adapter *adapter = pci_get_drvdata(ctx->mmio_info.pdev);
+
+ if (ixd_vc_can_handle_msg(msg))
+ ixd_vc_recv_event_msg(adapter, msg);
+ else
+ dev_dbg_ratelimited(ixd_to_dev(adapter),
+ "Received an unsupported opcode 0x%x from the CP\n",
+ msg->chnl_opcode);
+
+ libie_ctlq_release_rx_buf(&msg->recv_mem);
+}
+
+/**
+ * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically
+ * @adapter: The adapter with initialized mailbox
+ */
+static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)
+{
+ struct libie_ctlq_xn_recv_params xn_params = {
+ .xnm = adapter->xnm,
+ .ctlq = adapter->arq,
+ .ctlq_msg_handler = ixd_ctlq_handle_msg,
+ .budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
+ };
+
+ libie_ctlq_xn_recv(&xn_params);
+}
+
+/**
+ * ixd_ctlq_rx_task - Periodically check for mailbox responses and events
+ * @work: work handle
+ */
+void ixd_ctlq_rx_task(struct work_struct *work)
+{
+ struct ixd_adapter *adapter;
+
+ adapter = container_of(work, struct ixd_adapter, mbx_task.work);
+
+ queue_delayed_work(system_dfl_wq, &adapter->mbx_task,
+ IXD_CTLQ_RX_TASK_DELAY_JIFFIES);
+
+ ixd_ctlq_recv_mb_msg(adapter);
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.h b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
new file mode 100644
index 000000000000..8839f9f8f6d5
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_CTLQ_H_
+#define _IXD_CTLQ_H_
+
+#include <linux/net/intel/virtchnl2.h>
+
+#define IXD_CTLQ_TIMEOUT 2000
+
+/**
+ * struct ixd_ctlq_req - Standard virtchnl request description
+ * @opcode: protocol opcode, only virtchnl2 is needed for now
+ * @send_size: required length of the send buffer
+ * @send_buff_init: function to initialize the allocated send buffer
+ * @recv_process: function to handle the CP response
+ * @ctx: additional context for callbacks
+ */
+struct ixd_ctlq_req {
+ enum virtchnl2_op opcode;
+ size_t send_size;
+ void (*send_buff_init)(struct ixd_adapter *adapter, void *send_buff,
+ void *ctx);
+ int (*recv_process)(struct ixd_adapter *adapter, void *recv_buff,
+ size_t recv_size, void *ctx);
+ void *ctx;
+};
+
+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force);
+int ixd_ctlq_do_req(struct ixd_adapter *adapter,
+ const struct ixd_ctlq_req *req);
+void ixd_ctlq_rx_task(struct work_struct *work);
+
+#endif /* _IXD_CTLQ_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_dev.c b/drivers/net/ethernet/intel/ixd/ixd_dev.c
new file mode 100644
index 000000000000..cdd5477cc1f4
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_dev.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_lan_regs.h"
+
+/**
+ * ixd_ctlq_reg_init - Initialize default mailbox registers
+ * @adapter: PCI device driver-specific private data
+ * @ctlq_reg_tx: Transmit queue registers info to be filled
+ * @ctlq_reg_rx: Receive queue registers info to be filled
+ */
+void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
+ struct libie_ctlq_reg *ctlq_reg_tx,
+ struct libie_ctlq_reg *ctlq_reg_rx)
+{
+ struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+ *ctlq_reg_tx = (struct libie_ctlq_reg) {
+ .head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQH),
+ .tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQT),
+ .len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQLEN),
+ .addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAH),
+ .addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAL),
+ .len_mask = PF_FW_ATQLEN_ATQLEN_M,
+ .len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M,
+ .head_mask = PF_FW_ATQH_ATQH_M,
+ };
+
+ *ctlq_reg_rx = (struct libie_ctlq_reg) {
+ .head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQH),
+ .tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQT),
+ .len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQLEN),
+ .addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAH),
+ .addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAL),
+ .len_mask = PF_FW_ARQLEN_ARQLEN_M,
+ .len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M,
+ .head_mask = PF_FW_ARQH_ARQH_M,
+ };
+}
+
+static const struct ixd_reset_reg ixd_reset_reg = {
+ .rstat = PFGEN_RSTAT,
+ .rstat_m = PFGEN_RSTAT_PFR_STATE_M,
+ .rstat_ok_v = 0b01,
+ .rtrigger = PFGEN_CTRL,
+ .rtrigger_m = PFGEN_CTRL_PFSWR,
+};
+
+/**
+ * ixd_trigger_reset - Trigger PFR reset
+ * @adapter: the device with mapped reset register
+ */
+void ixd_trigger_reset(struct ixd_adapter *adapter)
+{
+ void __iomem *addr;
+ u32 reg_val;
+
+ addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
+ ixd_reset_reg.rtrigger);
+ reg_val = readl(addr);
+ writel(reg_val | ixd_reset_reg.rtrigger_m, addr);
+}
+
+/**
+ * ixd_check_reset_complete - Check if the PFR reset is completed
+ * @adapter: CPF being reset
+ *
+ * Return: %true if the register read indicates reset has been finished,
+ * %false otherwise
+ */
+bool ixd_check_reset_complete(struct ixd_adapter *adapter)
+{
+ u32 reg_val, reset_status;
+ void __iomem *addr;
+
+ addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
+ ixd_reset_reg.rstat);
+ reg_val = readl(addr);
+ reset_status = reg_val & ixd_reset_reg.rstat_m;
+
+ /* 0xFFFFFFFF might be read if the other side hasn't cleared
+ * the register for us yet.
+ */
+ if (reg_val != GENMASK(31, 0) &&
+ reset_status == ixd_reset_reg.rstat_ok_v)
+ return true;
+
+ return false;
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.c b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
new file mode 100644
index 000000000000..828132db8323
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025, Intel Corporation. */
+
+#include "ixd.h"
+#include "ixd_devlink.h"
+
+#define IXD_DEVLINK_INFO_LEN 128
+
+/**
+ * ixd_fill_dsn - Get the serial number for the ixd device
+ * @adapter: adapter to query
+ * @buf: storage buffer for the info request
+ */
+static void ixd_fill_dsn(struct ixd_adapter *adapter, char *buf)
+{
+ u8 dsn[8];
+
+ /* Copy the DSN into an array in Big Endian format */
+ put_unaligned_be64(pci_get_dsn(adapter->cp_ctx.mmio_info.pdev), dsn);
+
+ snprintf(buf, IXD_DEVLINK_INFO_LEN, "%8phD", dsn);
+}
+
+/**
+ * ixd_fill_device_name - Get the name of the underlying hardware
+ * @adapter: adapter to query
+ * @buf: storage buffer for the info request
+ * @buf_size: size of the storage buffer
+ */
+static void ixd_fill_device_name(struct ixd_adapter *adapter, char *buf,
+ size_t buf_size)
+{
+ if (adapter->caps.device_type == cpu_to_le32(VIRTCHNL2_MEV_DEVICE))
+ snprintf(buf, buf_size, "%s", "MEV");
+ else
+ snprintf(buf, buf_size, "%s", "UNKNOWN");
+}
+
+/**
+ * ixd_devlink_info_get - .info_get devlink handler
+ * @devlink: devlink instance structure
+ * @req: the devlink info request
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .info_get operation. Reports information about the
+ * device.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+static int ixd_devlink_info_get(struct devlink *devlink,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct ixd_adapter *adapter = devlink_priv(devlink);
+ char buf[IXD_DEVLINK_INFO_LEN];
+ int err;
+
+ ixd_fill_dsn(adapter, buf);
+ err = devlink_info_serial_number_put(req, buf);
+ if (err)
+ return err;
+
+ ixd_fill_device_name(adapter, buf, IXD_DEVLINK_INFO_LEN);
+ err = devlink_info_version_fixed_put(req, "device.type", buf);
+ if (err)
+ return err;
+
+ snprintf(buf, sizeof(buf), "%u.%u",
+ adapter->vc_ver.major, adapter->vc_ver.minor);
+
+ return devlink_info_version_running_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
+ buf);
+}
+
+static const struct devlink_ops ixd_devlink_ops = {
+ .info_get = ixd_devlink_info_get,
+};
+
+/**
+ * ixd_adapter_alloc - Allocate devlink and return adapter pointer
+ * @dev: the device to allocate for
+ *
+ * Allocate a devlink instance for this device and return the private area as
+ * the adapter structure.
+ *
+ * Return: adapter structure on success, NULL on failure
+ */
+struct ixd_adapter *ixd_adapter_alloc(struct device *dev)
+{
+ struct devlink *devlink;
+
+ devlink = devlink_alloc(&ixd_devlink_ops, sizeof(struct ixd_adapter),
+ dev);
+ if (!devlink)
+ return NULL;
+
+ return devlink_priv(devlink);
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.h b/drivers/net/ethernet/intel/ixd/ixd_devlink.h
new file mode 100644
index 000000000000..b23a1b37aebc
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2025, Intel Corporation. */
+
+#ifndef _IXD_DEVLINK_H_
+#define _IXD_DEVLINK_H_
+
+#include <net/devlink.h>
+
+#include "ixd.h"
+
+struct ixd_adapter *ixd_adapter_alloc(struct device *dev);
+
+/**
+ * ixd_devlink_free - teardown the devlink
+ * @adapter: the adapter structure to free
+ *
+ */
+static inline void ixd_devlink_free(struct ixd_adapter *adapter)
+{
+ struct devlink *devlink = priv_to_devlink(adapter);
+
+ devlink_free(devlink);
+}
+
+/**
+ * ixd_devlink_unregister - Unregister devlink for this adapter.
+ * @adapter: the adapter structure to cleanup
+ *
+ * Init task must be completed or cancelled beforehand.
+ */
+static inline void ixd_devlink_unregister(struct ixd_adapter *adapter)
+{
+ if (!adapter->init_task.success)
+ return;
+
+ devlink_unregister(priv_to_devlink(adapter));
+}
+
+/**
+ * ixd_devlink_register - Register devlink interface for this adapter
+ * @adapter: pointer to ixd adapter structure to be associated with devlink
+ *
+ * Register the devlink instance associated with this adapter
+ */
+static inline void ixd_devlink_register(struct ixd_adapter *adapter)
+{
+ devlink_register(priv_to_devlink(adapter));
+}
+
+#endif /* _IXD_DEVLINK_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
new file mode 100644
index 000000000000..58e58c75981b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_LAN_REGS_H_
+#define _IXD_LAN_REGS_H_
+
+/* Control Plane Function PCI ID */
+#define IXD_DEV_ID_CPF 0x1efe
+
+/* Control Queue (Mailbox) */
+#define PF_FW_MBX_REG_LEN 4096
+#define PF_FW_MBX 0x08400000
+
+#define PF_FW_ARQBAL (PF_FW_MBX)
+#define PF_FW_ARQBAH (PF_FW_MBX + 0x4)
+#define PF_FW_ARQLEN (PF_FW_MBX + 0x8)
+#define PF_FW_ARQLEN_ARQLEN_M GENMASK(12, 0)
+#define PF_FW_ARQLEN_ARQENABLE_S 31
+#define PF_FW_ARQLEN_ARQENABLE_M BIT(PF_FW_ARQLEN_ARQENABLE_S)
+#define PF_FW_ARQH_ARQH_M GENMASK(12, 0)
+#define PF_FW_ARQH (PF_FW_MBX + 0xC)
+#define PF_FW_ARQT (PF_FW_MBX + 0x10)
+
+#define PF_FW_ATQBAL (PF_FW_MBX + 0x14)
+#define PF_FW_ATQBAH (PF_FW_MBX + 0x18)
+#define PF_FW_ATQLEN (PF_FW_MBX + 0x1C)
+#define PF_FW_ATQLEN_ATQLEN_M GENMASK(9, 0)
+#define PF_FW_ATQLEN_ATQENABLE_S 31
+#define PF_FW_ATQLEN_ATQENABLE_M BIT(PF_FW_ATQLEN_ATQENABLE_S)
+#define PF_FW_ATQH_ATQH_M GENMASK(9, 0)
+#define PF_FW_ATQH (PF_FW_MBX + 0x20)
+#define PF_FW_ATQT (PF_FW_MBX + 0x24)
+
+/* Reset registers */
+#define PFGEN_RTRIG_REG_LEN 2048
+#define PFGEN_RTRIG 0x08407000 /* Device resets */
+#define PFGEN_RSTAT 0x08407008 /* PFR status */
+#define PFGEN_RSTAT_PFR_STATE_M GENMASK(1, 0)
+#define PFGEN_CTRL 0x0840700C /* PFR trigger */
+#define PFGEN_CTRL_PFSWR BIT(0)
+
+/**
+ * struct ixd_bar_region - BAR region description
+ * @offset: BAR region offset
+ * @size: BAR region size
+ */
+struct ixd_bar_region {
+ resource_size_t offset;
+ resource_size_t size;
+};
+
+/**
+ * struct ixd_reset_reg - structure for reset registers
+ * @rstat: offset of status in register
+ * @rstat_m: status mask
+ * @rstat_ok_v: value that indicates PFR completed status
+ * @rtrigger: offset of reset trigger in register
+ * @rtrigger_m: reset trigger mask
+ */
+struct ixd_reset_reg {
+ u32 rstat;
+ u32 rstat_m;
+ u32 rstat_ok_v;
+ u32 rtrigger;
+ u32 rtrigger_m;
+};
+
+#endif /* _IXD_LAN_REGS_H_ */
diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
new file mode 100644
index 000000000000..8311f7590666
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_devlink.h"
+#include "ixd_virtchnl.h"
+
+#define IXD_DFLT_MBX_Q_LEN 64
+
+/**
+ * ixd_init_ctlq_create_info - Initialize control queue info for creation
+ * @info: destination
+ * @type: type of the queue to create
+ * @ctlq_reg: register assigned to the control queue
+ */
+static void ixd_init_ctlq_create_info(struct libie_ctlq_create_info *info,
+ enum libie_ctlq_type type,
+ const struct libie_ctlq_reg *ctlq_reg)
+{
+ *info = (struct libie_ctlq_create_info) {
+ .type = type,
+ .id = -1,
+ .reg = *ctlq_reg,
+ .len = IXD_DFLT_MBX_Q_LEN,
+ };
+}
+
+/**
+ * ixd_init_libie_xn_params - Initialize xn transaction manager creation info
+ * @params: destination
+ * @adapter: adapter info struct
+ * @ctlqs: list of the managed queues to create
+ * @num_queues: length of the queue list
+ */
+static void ixd_init_libie_xn_params(struct libie_ctlq_xn_init_params *params,
+ struct ixd_adapter *adapter,
+ struct libie_ctlq_create_info *ctlqs,
+ uint num_queues)
+{
+ *params = (struct libie_ctlq_xn_init_params){
+ .cctlq_info = ctlqs,
+ .ctx = &adapter->cp_ctx,
+ .num_qs = num_queues,
+ };
+}
+
+/**
+ * ixd_adapter_fill_dflt_ctlqs - Find default control queues and store them
+ * @adapter: adapter info struct
+ */
+static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
+{
+ adapter->arq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_RX,
+ LIBIE_CTLQ_MBX_ID);
+ adapter->asq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_TX,
+ LIBIE_CTLQ_MBX_ID);
+}
+
+/**
+ * ixd_deinit_dflt_mbx - Deinitialize default mailbox
+ * @adapter: adapter info struct
+ */
+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
+{
+ cancel_delayed_work_sync(&adapter->mbx_task);
+
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
+
+ if (adapter->asq)
+ ixd_ctlq_clean_sq(adapter, true);
+
+ if (adapter->xnm)
+ libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
+
+ adapter->arq = NULL;
+ adapter->asq = NULL;
+ adapter->xnm = NULL;
+}
+
+/**
+ * ixd_init_dflt_mbx - Setup default mailbox parameters and make request
+ * @adapter: adapter info struct
+ *
+ * Return: %0 on success, negative errno code on failure
+ */
+int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
+{
+ struct libie_ctlq_create_info ctlqs_info[2];
+ struct libie_ctlq_xn_init_params xn_params;
+ struct libie_ctlq_reg ctlq_reg_tx;
+ struct libie_ctlq_reg ctlq_reg_rx;
+ int err;
+
+ ixd_ctlq_reg_init(adapter, &ctlq_reg_tx, &ctlq_reg_rx);
+ ixd_init_ctlq_create_info(&ctlqs_info[0], LIBIE_CTLQ_TYPE_TX,
+ &ctlq_reg_tx);
+ ixd_init_ctlq_create_info(&ctlqs_info[1], LIBIE_CTLQ_TYPE_RX,
+ &ctlq_reg_rx);
+ ixd_init_libie_xn_params(&xn_params, adapter, ctlqs_info,
+ ARRAY_SIZE(ctlqs_info));
+ err = libie_ctlq_xn_init(&xn_params);
+ if (err)
+ return err;
+ adapter->xnm = xn_params.xnm;
+
+ ixd_adapter_fill_dflt_ctlqs(adapter);
+
+ if (!adapter->asq || !adapter->arq) {
+ ixd_deinit_dflt_mbx(adapter);
+ return -ENOENT;
+ }
+
+ queue_delayed_work(system_dfl_wq, &adapter->mbx_task, 0);
+
+ return 0;
+}
+
+/**
+ * ixd_init_task - Initialize after reset
+ * @work: init work struct
+ */
+void ixd_init_task(struct work_struct *work)
+{
+ struct ixd_adapter *adapter;
+ int err;
+
+ adapter = container_of(work, struct ixd_adapter,
+ init_task.init_work.work);
+
+ if (!ixd_check_reset_complete(adapter)) {
+ if (++adapter->init_task.reset_retries < 10)
+ queue_delayed_work(system_dfl_wq,
+ &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+ else
+ dev_err(ixd_to_dev(adapter),
+ "Device reset failed. The driver was unable to contact the device's firmware. Check that the FW is running.\n");
+ return;
+ }
+
+ adapter->init_task.reset_retries = 0;
+ err = ixd_init_dflt_mbx(adapter);
+ if (err) {
+ dev_err(ixd_to_dev(adapter),
+ "Failed to initialize the default mailbox: %pe\n",
+ ERR_PTR(err));
+ return;
+ }
+
+ err = ixd_vc_dev_init(adapter);
+ if (!err) {
+ adapter->init_task.vc_retries = 0;
+ adapter->init_task.success = true;
+ ixd_devlink_register(adapter);
+ return;
+ }
+
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ ixd_trigger_reset(adapter);
+ ixd_deinit_dflt_mbx(adapter);
+ if (++adapter->init_task.vc_retries > 5 ||
+ (err != -ETIMEDOUT && err != -EAGAIN && err != -EBUSY)) {
+ dev_err(ixd_to_dev(adapter),
+ "Failed to establish mailbox communication with the hardware: %pe\n",
+ ERR_PTR(err));
+ return;
+ }
+
+ queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
new file mode 100644
index 000000000000..5db992d4f9fb
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_lan_regs.h"
+#include "ixd_devlink.h"
+
+MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
+MODULE_IMPORT_NS("LIBIE_CP");
+MODULE_IMPORT_NS("LIBIE_PCI");
+MODULE_LICENSE("GPL");
+
+/**
+ * ixd_remove - remove a CPF PCI device
+ * @pdev: PCI device being removed
+ */
+static void ixd_remove(struct pci_dev *pdev)
+{
+ struct ixd_adapter *adapter = pci_get_drvdata(pdev);
+
+ /* Do not mix removal with (re)initialization */
+ cancel_delayed_work_sync(&adapter->init_task.init_work);
+
+ ixd_devlink_unregister(adapter);
+
+ /* Leave the device clean on exit */
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ ixd_trigger_reset(adapter);
+ ixd_deinit_dflt_mbx(adapter);
+
+ libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
+ ixd_devlink_free(adapter);
+}
+
+/**
+ * ixd_shutdown - shut down a CPF PCI device
+ * @pdev: PCI device being shut down
+ */
+static void ixd_shutdown(struct pci_dev *pdev)
+{
+ ixd_remove(pdev);
+
+ if (system_state == SYSTEM_POWER_OFF)
+ pci_set_power_state(pdev, PCI_D3hot);
+}
+
+/**
+ * ixd_iomap_regions - iomap PCI BARs
+ * @adapter: adapter to map memory regions for
+ *
+ * Returns: %0 on success, negative on failure
+ */
+static int ixd_iomap_regions(struct ixd_adapter *adapter)
+{
+ const struct ixd_bar_region regions[] = {
+ {
+ .offset = PFGEN_RTRIG,
+ .size = PFGEN_RTRIG_REG_LEN,
+ },
+ {
+ .offset = PF_FW_MBX,
+ .size = PF_FW_MBX_REG_LEN,
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(regions); i++) {
+ struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+ bool map_ok;
+
+ map_ok = libie_pci_map_mmio_region(mmio_info,
+ regions[i].offset,
+ regions[i].size);
+ if (!map_ok) {
+ dev_err(ixd_to_dev(adapter),
+ "Failed to map PCI device MMIO region\n");
+
+ libie_pci_unmap_all_mmio_regions(mmio_info);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ixd_probe - probe a CPF PCI device
+ * @pdev: corresponding PCI device
+ * @ent: entry in ixd_pci_tbl
+ *
+ * Returns: %0 on success, negative errno code on failure
+ */
+static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct ixd_adapter *adapter;
+ int err;
+
+ adapter = ixd_adapter_alloc(&pdev->dev);
+ if (!adapter)
+ return -ENOMEM;
+
+ adapter->cp_ctx.mmio_info.pdev = pdev;
+ INIT_LIST_HEAD(&adapter->cp_ctx.mmio_info.mmio_list);
+
+ err = libie_pci_init_dev(pdev);
+ if (err)
+ goto free_adapter;
+
+ pci_set_drvdata(pdev, adapter);
+
+ err = ixd_iomap_regions(adapter);
+ if (err)
+ goto free_adapter;
+
+ INIT_DELAYED_WORK(&adapter->init_task.init_work,
+ ixd_init_task);
+ INIT_DELAYED_WORK(&adapter->mbx_task, ixd_ctlq_rx_task);
+
+ ixd_trigger_reset(adapter);
+ queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+
+ return 0;
+
+free_adapter:
+ ixd_devlink_free(adapter);
+ return err;
+}
+
+static const struct pci_device_id ixd_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, IXD_DEV_ID_CPF) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, ixd_pci_tbl);
+
+static struct pci_driver ixd_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ixd_pci_tbl,
+ .probe = ixd_probe,
+ .remove = ixd_remove,
+ .shutdown = ixd_shutdown,
+};
+module_pci_driver(ixd_driver);
diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
new file mode 100644
index 000000000000..fc3b6d2e28c5
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_virtchnl.h"
+
+/**
+ * ixd_vc_recv_event_msg - Handle virtchnl event message
+ * @adapter: The adapter handling the message
+ * @ctlq_msg: Message received
+ */
+void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
+ struct libie_ctlq_msg *ctlq_msg)
+{
+ int payload_size = ctlq_msg->data_len;
+ struct virtchnl2_event *v2e;
+
+ if (payload_size < sizeof(*v2e)) {
+ dev_warn_ratelimited(ixd_to_dev(adapter),
+ "Failed to receive valid payload for event msg (op 0x%X len %u)\n",
+ ctlq_msg->chnl_opcode,
+ payload_size);
+ return;
+ }
+
+ v2e = (struct virtchnl2_event *)ctlq_msg->recv_mem.iov_base;
+
+ dev_dbg(ixd_to_dev(adapter), "Got event 0x%X from the CP\n",
+ le32_to_cpu(v2e->event));
+}
+
+/**
+ * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code
+ * @ctlq_msg: Message received
+ *
+ * Return: %true if virtchnl code can handle the event, %false otherwise
+ */
+bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg)
+{
+ return ctlq_msg->chnl_opcode == VIRTCHNL2_OP_EVENT;
+}
+
+/**
+ * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response
+ * @adapter: The adapter for which the capabilities are being updated
+ * @recv_buff: Buffer containing the response
+ * @recv_size: Response buffer size
+ * @ctx: unused
+ *
+ * Return: %0 if the response format is correct and was handled as expected,
+ * negative error otherwise.
+ */
+static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,
+ size_t recv_size, void *ctx)
+{
+ if (recv_size < sizeof(adapter->caps))
+ return -EBADMSG;
+
+ adapter->caps = *(typeof(adapter->caps) *)recv_buff;
+
+ return 0;
+}
+
+/**
+ * ixd_req_vc_caps - Request and save device capability
+ * @adapter: The adapter to get the capabilities for
+ *
+ * Return: success or error if sending the get capability message fails
+ */
+static int ixd_req_vc_caps(struct ixd_adapter *adapter)
+{
+ const struct ixd_ctlq_req req = {
+ .opcode = VIRTCHNL2_OP_GET_CAPS,
+ .send_size = sizeof(struct virtchnl2_get_capabilities),
+ .ctx = NULL,
+ .send_buff_init = NULL,
+ .recv_process = ixd_handle_caps,
+ };
+
+ return ixd_ctlq_do_req(adapter, &req);
+}
+
+/**
+ * ixd_get_vc_ver - Get version info from adapter
+ *
+ * Return: filled in virtchannel2 version info, ready for sending
+ */
+static struct virtchnl2_version_info ixd_get_vc_ver(void)
+{
+ return (struct virtchnl2_version_info) {
+ .major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2),
+ .minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0),
+ };
+}
+
+static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff,
+ void *ctx)
+{
+ *(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver();
+}
+
+/**
+ * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response
+ * @adapter: The adapter for which the version is being updated
+ * @recv_buff: Buffer containing the response
+ * @recv_size: Response buffer size
+ * @ctx: Unused
+ *
+ * Return: %0 if the response format is correct and was handled as expected,
+ * negative error otherwise.
+ */
+static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff,
+ size_t recv_size, void *ctx)
+{
+ struct virtchnl2_version_info need_ver = ixd_get_vc_ver();
+ struct virtchnl2_version_info *recv_ver;
+
+ if (recv_size < sizeof(need_ver))
+ return -EBADMSG;
+
+ recv_ver = recv_buff;
+ if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major) ||
+ le32_to_cpu(need_ver.minor) != le32_to_cpu(recv_ver->minor))
+ dev_warn(ixd_to_dev(adapter),
+ "Virtchnl version does not match (expected %u.%u, received %u.%u)\n",
+ le32_to_cpu(need_ver.major),
+ le32_to_cpu(need_ver.minor),
+ le32_to_cpu(recv_ver->major),
+ le32_to_cpu(recv_ver->minor));
+
+ if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major)) {
+ dev_err(ixd_to_dev(adapter),
+ "Device initialization failed due to virtchnl major version mismatch\n");
+ return -EOPNOTSUPP;
+ }
+
+ adapter->vc_ver.major = le32_to_cpu(recv_ver->major);
+ adapter->vc_ver.minor = le32_to_cpu(recv_ver->minor);
+
+ return 0;
+}
+
+/**
+ * ixd_req_vc_version - Request and save Virtchannel2 version
+ * @adapter: The adapter to get the version for
+ *
+ * Return: success or error if sending fails or the response was not as expected
+ */
+static int ixd_req_vc_version(struct ixd_adapter *adapter)
+{
+ const struct ixd_ctlq_req req = {
+ .opcode = VIRTCHNL2_OP_VERSION,
+ .send_size = sizeof(struct virtchnl2_version_info),
+ .ctx = NULL,
+ .send_buff_init = ixd_fill_vc_ver,
+ .recv_process = ixd_handle_vc_ver,
+ };
+
+ return ixd_ctlq_do_req(adapter, &req);
+}
+
+/**
+ * ixd_vc_dev_init - virtchnl device core initialization
+ * @adapter: device information
+ *
+ * Return: %0 on success or error if any step of the initialization fails
+ */
+int ixd_vc_dev_init(struct ixd_adapter *adapter)
+{
+ int err;
+
+ err = ixd_req_vc_version(adapter);
+ if (err) {
+ dev_warn(ixd_to_dev(adapter),
+ "Getting virtchnl version failed, error=%pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ err = ixd_req_vc_caps(adapter);
+ if (err) {
+ dev_warn(ixd_to_dev(adapter),
+ "Getting virtchnl capabilities failed, error=%pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ return err;
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
new file mode 100644
index 000000000000..1a53da8b545c
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_VIRTCHNL_H_
+#define _IXD_VIRTCHNL_H_
+
+int ixd_vc_dev_init(struct ixd_adapter *adapter);
+bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg);
+void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
+ struct libie_ctlq_msg *ctlq_msg);
+
+#endif /* _IXD_VIRTCHNL_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
index d227f4d2a2d1..cf8908b82f8a 100644
--- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
@@ -318,7 +318,7 @@ static int ixgbe_devlink_info_get(struct devlink *devlink,
struct ixgbe_info_ctx *ctx;
int err;
- ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kmalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -474,7 +474,7 @@ static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink,
adapter->flags2 &= ~(IXGBE_FLAG2_API_MISMATCH |
IXGBE_FLAG2_FW_ROLLBACK);
- return 0;
+ return ixgbe_refresh_fw_version(adapter);
}
static const struct devlink_ops ixgbe_devlink_ops = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index dce4936708eb..9b8217523fd2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -322,10 +322,11 @@ enum ixgbe_ring_state_t {
__IXGBE_HANG_CHECK_ARMED,
__IXGBE_TX_XDP_RING,
__IXGBE_TX_DISABLED,
+ __IXGBE_RING_STATE_NBITS, /* must be last */
};
#define ring_uses_build_skb(ring) \
- test_bit(__IXGBE_RX_BUILD_SKB_ENABLED, &(ring)->state)
+ test_bit(__IXGBE_RX_BUILD_SKB_ENABLED, (ring)->state)
struct ixgbe_fwd_adapter {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -336,23 +337,23 @@ struct ixgbe_fwd_adapter {
};
#define check_for_tx_hang(ring) \
- test_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+ test_bit(__IXGBE_TX_DETECT_HANG, (ring)->state)
#define set_check_for_tx_hang(ring) \
- set_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+ set_bit(__IXGBE_TX_DETECT_HANG, (ring)->state)
#define clear_check_for_tx_hang(ring) \
- clear_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
+ clear_bit(__IXGBE_TX_DETECT_HANG, (ring)->state)
#define ring_is_rsc_enabled(ring) \
- test_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
+ test_bit(__IXGBE_RX_RSC_ENABLED, (ring)->state)
#define set_ring_rsc_enabled(ring) \
- set_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
+ set_bit(__IXGBE_RX_RSC_ENABLED, (ring)->state)
#define clear_ring_rsc_enabled(ring) \
- clear_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
+ clear_bit(__IXGBE_RX_RSC_ENABLED, (ring)->state)
#define ring_is_xdp(ring) \
- test_bit(__IXGBE_TX_XDP_RING, &(ring)->state)
+ test_bit(__IXGBE_TX_XDP_RING, (ring)->state)
#define set_ring_xdp(ring) \
- set_bit(__IXGBE_TX_XDP_RING, &(ring)->state)
+ set_bit(__IXGBE_TX_XDP_RING, (ring)->state)
#define clear_ring_xdp(ring) \
- clear_bit(__IXGBE_TX_XDP_RING, &(ring)->state)
+ clear_bit(__IXGBE_TX_XDP_RING, (ring)->state)
struct ixgbe_ring {
struct ixgbe_ring *next; /* pointer to next ring in q_vector */
struct ixgbe_q_vector *q_vector; /* backpointer to host q_vector */
@@ -364,7 +365,7 @@ struct ixgbe_ring {
struct ixgbe_tx_buffer *tx_buffer_info;
struct ixgbe_rx_buffer *rx_buffer_info;
};
- unsigned long state;
+ DECLARE_BITMAP(state, __IXGBE_RING_STATE_NBITS);
u8 __iomem *tail;
dma_addr_t dma; /* phys. address of descriptor ring */
unsigned int size; /* length in bytes */
@@ -453,7 +454,7 @@ struct ixgbe_ring_feature {
*/
static inline unsigned int ixgbe_rx_bufsz(struct ixgbe_ring *ring)
{
- if (test_bit(__IXGBE_RX_3K_BUFFER, &ring->state))
+ if (test_bit(__IXGBE_RX_3K_BUFFER, ring->state))
return IXGBE_RXBUFFER_3K;
#if (PAGE_SIZE < 8192)
if (ring_uses_build_skb(ring))
@@ -465,7 +466,7 @@ static inline unsigned int ixgbe_rx_bufsz(struct ixgbe_ring *ring)
static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
{
#if (PAGE_SIZE < 8192)
- if (test_bit(__IXGBE_RX_3K_BUFFER, &ring->state))
+ if (test_bit(__IXGBE_RX_3K_BUFFER, ring->state))
return 1;
#endif
return 0;
@@ -973,7 +974,7 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
u16 subdevice_id);
void ixgbe_set_fw_version_e610(struct ixgbe_adapter *adapter);
-void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
+int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
#ifdef CONFIG_PCI_IOV
void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter);
#endif
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 3069b583fd81..89c7fed7b8fc 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -342,6 +342,13 @@ static int ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
return 0;
}
+ if (hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1) {
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ *autoneg = false;
+ return 0;
+ }
+
/*
* Determine link capabilities based on the stored value of AUTOC,
* which represents EEPROM defaults. If AUTOC value has not been
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index 3dd5a16a14df..382d097e4b11 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -516,8 +516,7 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
return -EINVAL;
if (!adapter->ixgbe_ieee_ets) {
- adapter->ixgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets),
- GFP_KERNEL);
+ adapter->ixgbe_ieee_ets = kmalloc_obj(struct ieee_ets);
if (!adapter->ixgbe_ieee_ets)
return -ENOMEM;
@@ -593,8 +592,7 @@ static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev,
return -EINVAL;
if (!adapter->ixgbe_ieee_pfc) {
- adapter->ixgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc),
- GFP_KERNEL);
+ adapter->ixgbe_ieee_pfc = kmalloc_obj(struct ieee_pfc);
if (!adapter->ixgbe_ieee_pfc)
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index c2f8189a0738..4d8ae5b56145 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -142,20 +142,14 @@ static int ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw,
IXGBE_PF_HICR);
/* Read sync Admin Command response */
- if ((hicr & IXGBE_PF_HICR_SV)) {
- for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+ if ((hicr & IXGBE_PF_HICR_SV))
+ for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++)
raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA(i));
- raw_desc[i] = raw_desc[i];
- }
- }
/* Read async Admin Command response */
- if ((hicr & IXGBE_PF_HICR_EV) && !(hicr & IXGBE_PF_HICR_C)) {
- for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+ if ((hicr & IXGBE_PF_HICR_EV) && !(hicr & IXGBE_PF_HICR_C))
+ for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++)
raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA_2(i));
- raw_desc[i] = raw_desc[i];
- }
- }
/* Handle timeout and invalid state of HICR register */
if (hicr & IXGBE_PF_HICR_C)
@@ -628,6 +622,9 @@ static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw,
(phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0;
break;
}
+ case LIBIE_AQC_CAPS_EEE:
+ caps->eee_support = (u8)number;
+ break;
default:
/* Not one of the recognized common capabilities */
return false;
@@ -1073,6 +1070,7 @@ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
cfg->link_fec_opt = caps->link_fec_options;
cfg->module_compliance_enforcement =
caps->module_compliance_enforcement;
+ cfg->eee_entry_delay = caps->eee_entry_delay;
}
/**
@@ -1093,11 +1091,16 @@ int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
{
struct ixgbe_aci_cmd_set_phy_cfg *cmd;
struct libie_aq_desc desc;
+ bool use_buff_eee_field;
+ u16 buf_size;
int err;
if (!cfg)
return -EINVAL;
+ /* If FW supports EEE, we have to use buffer with EEE field. */
+ use_buff_eee_field = hw->dev_caps.common_cap.eee_support;
+
cmd = libie_aq_raw(&desc);
/* Ensure that only valid bits of cfg->caps can be turned on. */
cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
@@ -1106,7 +1109,17 @@ int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
cmd->lport_num = hw->bus.func;
desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD);
- err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
+ if (use_buff_eee_field)
+ buf_size = sizeof(*cfg);
+ else
+ /* Buffer w/o eee_entry_delay field is 2B smaller. */
+ buf_size = sizeof(*cfg) - sizeof(u16);
+
+ err = ixgbe_aci_send_cmd(hw, &desc, cfg, buf_size);
+
+ /* 1.40 config format is compatible with pre-1.40, just extends
+ * it at the end.
+ */
if (!err)
hw->phy.curr_user_phy_cfg = *cfg;
@@ -1285,7 +1298,7 @@ int ixgbe_update_link_info(struct ixgbe_hw *hw)
if (!(li->link_info & IXGBE_ACI_MEDIA_AVAILABLE))
return 0;
- pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
+ pcaps = kzalloc_obj(*pcaps);
if (!pcaps)
return -ENOMEM;
@@ -1386,6 +1399,7 @@ int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
li->topo_media_conflict = link_data.topo_media_conflict;
li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
IXGBE_ACI_CFG_PACING_TYPE_M);
+ li->eee_status = link_data.eee_status;
/* Update fc info. */
tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
@@ -1980,15 +1994,59 @@ int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
/* Set PHY ID */
memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
- hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
- IXGBE_LINK_SPEED_100_FULL |
- IXGBE_LINK_SPEED_1GB_FULL;
+ /* E610 supports EEE only for speeds above 1G */
+ if (hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
+ hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_2_5GB_FULL;
+ else
+ hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_2_5GB_FULL |
+ IXGBE_LINK_SPEED_5GB_FULL |
+ IXGBE_LINK_SPEED_10GB_FULL;
+
hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
return 0;
}
/**
+ * ixgbe_setup_eee_e610 - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ * @enable_eee: boolean flag to enable EEE
+ *
+ * Enable/disable EEE based on @enable_eee.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_eee_e610(struct ixgbe_hw *hw, bool enable_eee)
+{
+ struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = {};
+ struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = {};
+ u16 eee_cap = 0;
+ int err;
+
+ err = ixgbe_aci_get_phy_caps(hw, false,
+ IXGBE_ACI_REPORT_ACTIVE_CFG, &phy_caps);
+ if (err)
+ return err;
+
+ ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
+ phy_cfg.caps |= (IXGBE_ACI_PHY_ENA_LINK |
+ IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT);
+
+ if (enable_eee) {
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T;
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_5GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_5GBASE_T;
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_10GBASE_T;
+ }
+
+ phy_cfg.eee_cap = cpu_to_le16(eee_cap);
+
+ return ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+}
+
+/**
* ixgbe_identify_module_e610 - Identify SFP module type
* @hw: pointer to hardware structure
*
@@ -4001,6 +4059,7 @@ static const struct ixgbe_mac_operations mac_ops_e610 = {
.fw_rollback_mode = ixgbe_fw_rollback_mode_e610,
.get_nvm_ver = ixgbe_get_active_nvm_ver,
.get_link_capabilities = ixgbe_get_link_capabilities_e610,
+ .setup_eee = ixgbe_setup_eee_e610,
.get_bus_info = ixgbe_get_bus_info_generic,
.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540,
.release_swfw_sync = ixgbe_release_swfw_sync_X540,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 11916b979d28..2cb76a3d30ae 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -55,6 +55,7 @@ int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw);
int ixgbe_identify_phy_e610(struct ixgbe_hw *hw);
int ixgbe_identify_module_e610(struct ixgbe_hw *hw);
int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw);
+int ixgbe_setup_eee_e610(struct ixgbe_hw *hw, bool enable_eee);
int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
int ixgbe_init_eeprom_params_e610(struct ixgbe_hw *hw);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 2ad81f687a84..36e43b5e88d1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -12,6 +12,7 @@
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
+#include <linux/string_choices.h>
#include <linux/uaccess.h>
#include "ixgbe.h"
@@ -351,6 +352,8 @@ static int ixgbe_get_link_ksettings(struct net_device *netdev,
case ixgbe_sfp_type_1g_lx_core1:
case ixgbe_sfp_type_1g_bx_core0:
case ixgbe_sfp_type_1g_bx_core1:
+ case ixgbe_sfp_type_10g_bx_core0:
+ case ixgbe_sfp_type_10g_bx_core1:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
@@ -1153,12 +1156,17 @@ err:
return ret_val;
}
-void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
+int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ err = ixgbe_get_flash_data(hw);
+ if (err)
+ return err;
- ixgbe_get_flash_data(hw);
ixgbe_set_fw_version_e610(adapter);
+ return 0;
}
static void ixgbe_get_drvinfo(struct net_device *netdev,
@@ -1166,10 +1174,6 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
- /* need to refresh info for e610 in case fw reloads in runtime */
- if (adapter->hw.mac.type == ixgbe_mac_e610)
- ixgbe_refresh_fw_version(adapter);
-
strscpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
strscpy(drvinfo->fw_version, adapter->eeprom_id,
@@ -2979,7 +2983,7 @@ static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
return -EINVAL;
}
- input = kzalloc(sizeof(*input), GFP_ATOMIC);
+ input = kzalloc_obj(*input, GFP_ATOMIC);
if (!input)
return -ENOMEM;
@@ -3537,7 +3541,8 @@ static const struct {
{ IXGBE_LINK_SPEED_10_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT },
{ IXGBE_LINK_SPEED_100_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT },
{ IXGBE_LINK_SPEED_1GB_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
- { IXGBE_LINK_SPEED_2_5GB_FULL, ETHTOOL_LINK_MODE_2500baseX_Full_BIT },
+ { IXGBE_LINK_SPEED_2_5GB_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT },
+ { IXGBE_LINK_SPEED_5GB_FULL, ETHTOOL_LINK_MODE_5000baseT_Full_BIT },
{ IXGBE_LINK_SPEED_10GB_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT },
};
@@ -3553,6 +3558,165 @@ static const struct {
{ FW_PHY_ACT_UD_2_10G_KR_EEE, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
};
+static int ixgbe_validate_keee(struct net_device *netdev,
+ struct ethtool_keee *keee_requested)
+{
+ struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ struct ethtool_keee keee_stored = {};
+ int err;
+
+ if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
+ return -EOPNOTSUPP;
+
+ err = netdev->ethtool_ops->get_eee(netdev, &keee_stored);
+ if (err)
+ return err;
+
+ if (keee_stored.tx_lpi_enabled != keee_requested->tx_lpi_enabled) {
+ e_err(drv, "Setting EEE tx-lpi is not supported\n");
+ return -EINVAL;
+ }
+
+ if (keee_stored.tx_lpi_timer != keee_requested->tx_lpi_timer) {
+ e_err(drv,
+ "Setting EEE Tx LPI timer is not supported\n");
+ return -EINVAL;
+ }
+
+ if (!linkmode_equal(keee_stored.advertised,
+ keee_requested->advertised)) {
+ e_err(drv,
+ "Setting EEE advertised speeds is not supported\n");
+ return -EINVAL;
+ }
+
+ /* -EALREADY here is for internal use only, must be converted into
+ * early bail out with 0 by caller
+ */
+ if (keee_stored.eee_enabled == keee_requested->eee_enabled)
+ return -EALREADY;
+
+ return 0;
+}
+
+/**
+ * ixgbe_is_eee_link_speed_supported_e610 - Check if EEE can be enabled
+ * @adapter: pointer to the adapter struct
+ *
+ * Check whether current link configuration is capable of enabling EEE feature.
+ *
+ * E610 specific function - for other adapters supporting EEE there might be
+ * no such limitation.
+ *
+ * Return: true if EEE can be enabled, false otherwise.
+ */
+static bool
+ixgbe_is_eee_link_speed_supported_e610(struct ixgbe_adapter *adapter)
+{
+ switch (adapter->link_speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ case IXGBE_LINK_SPEED_2_5GB_FULL:
+ case IXGBE_LINK_SPEED_5GB_FULL:
+ return true;
+ case IXGBE_LINK_SPEED_100_FULL:
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ e_dev_info("Energy Efficient Ethernet (EEE) feature is not supported on link speeds equal to or below 1Gbps. EEE is supported on speeds above 1Gbps.\n");
+ fallthrough;
+ default:
+ return false;
+ }
+}
+
+static int ixgbe_get_eee_e610(struct net_device *netdev,
+ struct ethtool_keee *kedata)
+{
+ struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_link_status link;
+ int err;
+
+ linkmode_zero(kedata->lp_advertised);
+ linkmode_zero(kedata->supported);
+ linkmode_zero(kedata->advertised);
+
+ err = ixgbe_aci_get_link_info(hw, true, &link);
+ if (err)
+ return err;
+
+ err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
+ &pcaps);
+ if (err)
+ return err;
+
+ kedata->eee_active = link.eee_status & IXGBE_ACI_LINK_EEE_ACTIVE;
+ kedata->eee_enabled = link.eee_status & IXGBE_ACI_LINK_EEE_ENABLED;
+
+ /* for E610 devices EEE enablement implies TX LPI enablement */
+ kedata->tx_lpi_enabled = kedata->eee_enabled;
+
+ if (kedata->eee_enabled)
+ kedata->tx_lpi_timer = le16_to_cpu(pcaps.eee_entry_delay);
+
+ for (int i = 0; i < ARRAY_SIZE(ixgbe_ls_map); i++) {
+ if (hw->phy.eee_speeds_supported &
+ ixgbe_ls_map[i].mac_speed)
+ linkmode_set_bit(ixgbe_ls_map[i].link_mode,
+ kedata->supported);
+
+ if (hw->phy.eee_speeds_advertised &
+ ixgbe_ls_map[i].mac_speed)
+ linkmode_set_bit(ixgbe_ls_map[i].link_mode,
+ kedata->advertised);
+ }
+
+ return 0;
+}
+
+static int ixgbe_set_eee_e610(struct net_device *netdev,
+ struct ethtool_keee *kedata)
+{
+ struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ err = ixgbe_validate_keee(netdev, kedata);
+
+ if (err == -EALREADY) {
+ return 0;
+ } else if (err) {
+ if (err == -EOPNOTSUPP)
+ e_dev_info("Energy Efficient Ethernet (EEE) feature is currently not supported on this device, please update the device NVM to the latest and try again\n");
+ return err;
+ }
+
+ if (!(ixgbe_is_eee_link_speed_supported_e610(adapter)) &&
+ kedata->eee_enabled)
+ return -EOPNOTSUPP;
+
+ hw->phy.eee_speeds_advertised = kedata->eee_enabled ?
+ hw->phy.eee_speeds_supported : 0;
+
+ err = hw->mac.ops.setup_eee(hw, kedata->eee_enabled);
+ if (err) {
+ e_dev_err("Setting EEE %s failed.\n",
+ str_on_off(kedata->eee_enabled));
+ return err;
+ }
+
+ if (kedata->eee_enabled)
+ adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
+ else
+ adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
+
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
+ else
+ ixgbe_reset(adapter);
+
+ return 0;
+}
+
static int
ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata)
{
@@ -3611,53 +3775,28 @@ static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata)
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- struct ethtool_keee eee_data;
int ret_val;
- if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
- return -EOPNOTSUPP;
-
- memset(&eee_data, 0, sizeof(struct ethtool_keee));
-
- ret_val = ixgbe_get_eee(netdev, &eee_data);
- if (ret_val)
+ ret_val = ixgbe_validate_keee(netdev, edata);
+ if (ret_val == -EALREADY)
+ return 0;
+ else if (ret_val)
return ret_val;
- if (eee_data.eee_enabled && !edata->eee_enabled) {
- if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) {
- e_err(drv, "Setting EEE tx-lpi is not supported\n");
- return -EINVAL;
- }
-
- if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) {
- e_err(drv,
- "Setting EEE Tx LPI timer is not supported\n");
- return -EINVAL;
- }
-
- if (!linkmode_equal(eee_data.advertised, edata->advertised)) {
- e_err(drv,
- "Setting EEE advertised speeds is not supported\n");
- return -EINVAL;
- }
+ if (edata->eee_enabled) {
+ adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
+ hw->phy.eee_speeds_advertised =
+ hw->phy.eee_speeds_supported;
+ } else {
+ adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
+ hw->phy.eee_speeds_advertised = 0;
}
- if (eee_data.eee_enabled != edata->eee_enabled) {
- if (edata->eee_enabled) {
- adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
- hw->phy.eee_speeds_advertised =
- hw->phy.eee_speeds_supported;
- } else {
- adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
- hw->phy.eee_speeds_advertised = 0;
- }
-
- /* reset link */
- if (netif_running(netdev))
- ixgbe_reinit_locked(adapter);
- else
- ixgbe_reset(adapter);
- }
+ /* reset link */
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
+ else
+ ixgbe_reset(adapter);
return 0;
}
@@ -3804,8 +3943,8 @@ static const struct ethtool_ops ixgbe_ethtool_ops_e610 = {
.set_rxfh = ixgbe_set_rxfh,
.get_rxfh_fields = ixgbe_get_rxfh_fields,
.set_rxfh_fields = ixgbe_set_rxfh_fields,
- .get_eee = ixgbe_get_eee,
- .set_eee = ixgbe_set_eee,
+ .get_eee = ixgbe_get_eee_e610,
+ .set_eee = ixgbe_set_eee_e610,
.get_channels = ixgbe_get_channels,
.set_channels = ixgbe_set_channels,
.get_priv_flags = ixgbe_get_priv_flags,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c
index e5479fc07a07..ffceaef8502f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c
@@ -516,7 +516,7 @@ int ixgbe_get_pending_updates(struct ixgbe_adapter *adapter, u8 *pending,
struct ixgbe_hw *hw = &adapter->hw;
int err;
- dev_caps = kzalloc(sizeof(*dev_caps), GFP_KERNEL);
+ dev_caps = kzalloc_obj(*dev_caps);
if (!dev_caps)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
index d1f4073b36f9..bd397b3d7dea 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -904,7 +904,7 @@ int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
goto err_out;
}
- xs = kzalloc(sizeof(*xs), GFP_ATOMIC);
+ xs = kzalloc_obj(*xs, GFP_ATOMIC);
if (unlikely(!xs)) {
err = -ENOMEM;
goto err_out;
@@ -1233,7 +1233,7 @@ void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
if (t_dis || r_dis)
return;
- ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL);
+ ipsec = kzalloc_obj(*ipsec);
if (!ipsec)
goto err1;
hash_init(ipsec->rx_sa_list);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index a1d04914fbbc..1db4bd5cc2ba 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -768,9 +768,7 @@ static int ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter)
*/
vector_threshold = MIN_MSIX_COUNT;
- adapter->msix_entries = kcalloc(vectors,
- sizeof(struct msix_entry),
- GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, vectors);
if (!adapter->msix_entries)
return -ENOMEM;
@@ -859,8 +857,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
q_vector = kzalloc_node(struct_size(q_vector, ring, ring_count),
GFP_KERNEL, node);
if (!q_vector)
- q_vector = kzalloc(struct_size(q_vector, ring, ring_count),
- GFP_KERNEL);
+ q_vector = kzalloc_flex(*q_vector, ring, ring_count);
if (!q_vector)
return -ENOMEM;
@@ -979,7 +976,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
* can be marked as checksum errors.
*/
if (adapter->hw.mac.type == ixgbe_mac_82599EB)
- set_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, &ring->state);
+ set_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, ring->state);
#ifdef IXGBE_FCOE
if (adapter->netdev->fcoe_mtu) {
@@ -987,7 +984,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
f = &adapter->ring_feature[RING_F_FCOE];
if ((rxr_idx >= f->offset) &&
(rxr_idx < f->offset + f->indices))
- set_bit(__IXGBE_RX_FCOE, &ring->state);
+ set_bit(__IXGBE_RX_FCOE, ring->state);
}
#endif /* IXGBE_FCOE */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 034618e79169..f91856498eb2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -88,60 +88,60 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id ixgbe_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX), board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KR), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_QSFP_SF_QP), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T), board_X550},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T1), board_X550},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KX4), board_X550EM_x},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_XFI), board_X550EM_x},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR), board_X550EM_x},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), board_X550EM_x},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP), board_X550EM_x},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_1G_T), board_x550em_x_fw},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR_L), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII_L), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_10G_T), board_x550em_a},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), board_x550em_a },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T), board_x550em_a_fw },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L), board_x550em_a_fw },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_BACKPLANE), board_e610},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SFP), board_e610},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_10G_T), board_e610},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_2_5G_T), board_e610},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SGMII), board_e610},
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX), .driver_data = board_82598 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KR), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), .driver_data = board_X540 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_QSFP_SF_QP), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), .driver_data = board_82599 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), .driver_data = board_X540 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T), .driver_data = board_X550 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T1), .driver_data = board_X550 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KX4), .driver_data = board_X550EM_x },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_XFI), .driver_data = board_X550EM_x },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR), .driver_data = board_X550EM_x },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), .driver_data = board_X550EM_x },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP), .driver_data = board_X550EM_x },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_1G_T), .driver_data = board_x550em_x_fw },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR_L), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII_L), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_10G_T), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), .driver_data = board_x550em_a },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T), .driver_data = board_x550em_a_fw },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L), .driver_data = board_x550em_a_fw },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_BACKPLANE), .driver_data = board_e610 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SFP), .driver_data = board_e610 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_10G_T), .driver_data = board_e610 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_2_5G_T), .driver_data = board_e610 },
+ { PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SGMII), .driver_data = board_e610 },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
@@ -968,7 +968,7 @@ static void ixgbe_update_xoff_rx_lfc(struct ixgbe_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++)
clear_bit(__IXGBE_HANG_CHECK_ARMED,
- &adapter->tx_ring[i]->state);
+ adapter->tx_ring[i]->state);
}
static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter)
@@ -1011,7 +1011,7 @@ static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter)
tc = tx_ring->dcb_tc;
if (xoff[tc])
- clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, tx_ring->state);
}
for (i = 0; i < adapter->num_xdp_queues; i++) {
@@ -1019,7 +1019,7 @@ static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter)
tc = xdp_ring->dcb_tc;
if (xoff[tc])
- clear_bit(__IXGBE_HANG_CHECK_ARMED, &xdp_ring->state);
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, xdp_ring->state);
}
}
@@ -1103,11 +1103,11 @@ static bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
if (tx_done_old == tx_done && tx_pending)
/* make sure it is true for two checks in a row */
return test_and_set_bit(__IXGBE_HANG_CHECK_ARMED,
- &tx_ring->state);
+ tx_ring->state);
/* update completed stats and continue */
tx_ring->tx_stats.tx_done_old = tx_done;
/* reset the countdown */
- clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, tx_ring->state);
return false;
}
@@ -1660,7 +1660,7 @@ static inline bool ixgbe_rx_is_fcoe(struct ixgbe_ring *ring,
{
__le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
- return test_bit(__IXGBE_RX_FCOE, &ring->state) &&
+ return test_bit(__IXGBE_RX_FCOE, ring->state) &&
((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_ETQF_MASK)) ==
(cpu_to_le16(IXGBE_ETQF_FILTER_FCOE <<
IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT)));
@@ -1708,7 +1708,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
* checksum errors.
*/
if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_UDP)) &&
- test_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, &ring->state))
+ test_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, ring->state))
return;
ring->rx_stats.csum_err++;
@@ -3526,7 +3526,7 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
for (i = 0; i < adapter->num_tx_queues; i++) {
struct ixgbe_ring *ring = adapter->tx_ring[i];
if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &ring->state))
+ ring->state))
reinit_count++;
}
if (reinit_count) {
@@ -3952,13 +3952,14 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
ring->atr_sample_rate = adapter->atr_sample_rate;
ring->atr_count = 0;
- set_bit(__IXGBE_TX_FDIR_INIT_DONE, &ring->state);
+ set_bit(__IXGBE_TX_FDIR_INIT_DONE, ring->state);
} else {
ring->atr_sample_rate = 0;
}
/* initialize XPS */
- if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, &ring->state)) {
+ if (!ring_is_xdp(ring) &&
+ !test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, ring->state)) {
struct ixgbe_q_vector *q_vector = ring->q_vector;
if (q_vector)
@@ -3967,7 +3968,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
ring->queue_index);
}
- clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ clear_bit(__IXGBE_HANG_CHECK_ARMED, ring->state);
/* reinitialize tx_buffer_info */
memset(ring->tx_buffer_info, 0,
@@ -4173,7 +4174,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
else
srrctl |= xsk_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
- } else if (test_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state)) {
+ } else if (test_bit(__IXGBE_RX_3K_BUFFER, rx_ring->state)) {
srrctl |= IXGBE_RXBUFFER_3K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
} else {
srrctl |= IXGBE_RXBUFFER_2K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
@@ -4558,7 +4559,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
* higher than the MTU of the PF.
*/
if (ring_uses_build_skb(ring) &&
- !test_bit(__IXGBE_RX_3K_BUFFER, &ring->state))
+ !test_bit(__IXGBE_RX_3K_BUFFER, ring->state))
rxdctl |= IXGBE_MAX_2K_FRAME_BUILD_SKB |
IXGBE_RXDCTL_RLPML_EN;
#endif
@@ -4733,27 +4734,27 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
rx_ring = adapter->rx_ring[i];
clear_ring_rsc_enabled(rx_ring);
- clear_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state);
- clear_bit(__IXGBE_RX_BUILD_SKB_ENABLED, &rx_ring->state);
+ clear_bit(__IXGBE_RX_3K_BUFFER, rx_ring->state);
+ clear_bit(__IXGBE_RX_BUILD_SKB_ENABLED, rx_ring->state);
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
set_ring_rsc_enabled(rx_ring);
- if (test_bit(__IXGBE_RX_FCOE, &rx_ring->state))
- set_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state);
+ if (test_bit(__IXGBE_RX_FCOE, rx_ring->state))
+ set_bit(__IXGBE_RX_3K_BUFFER, rx_ring->state);
if (adapter->flags2 & IXGBE_FLAG2_RX_LEGACY)
continue;
- set_bit(__IXGBE_RX_BUILD_SKB_ENABLED, &rx_ring->state);
+ set_bit(__IXGBE_RX_BUILD_SKB_ENABLED, rx_ring->state);
#if (PAGE_SIZE < 8192)
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
- set_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state);
+ set_bit(__IXGBE_RX_3K_BUFFER, rx_ring->state);
if (IXGBE_2K_TOO_SMALL_WITH_PADDING ||
(max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)))
- set_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state);
+ set_bit(__IXGBE_RX_3K_BUFFER, rx_ring->state);
#endif
}
}
@@ -6289,6 +6290,16 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
msleep(2000);
ixgbe_up(adapter);
+
+ /* E610 has no FW event to notify all PFs of an EMPR reset, so
+ * refresh the FW version here to pick up any new FW version after
+ * a hardware reset (e.g. EMPR triggered by another PF's devlink
+ * reload). ixgbe_refresh_fw_version() updates both hw->flash and
+ * adapter->eeprom_id so ethtool -i reports the correct string.
+ */
+ if (adapter->hw.mac.type == ixgbe_mac_e610)
+ (void)ixgbe_refresh_fw_version(adapter);
+
clear_bit(__IXGBE_RESETTING, &adapter->state);
}
@@ -6748,6 +6759,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/**
* ixgbe_set_eee_capable - helper function to determine EEE support on X550
+ * and E610
* @adapter: board private structure
*/
static void ixgbe_set_eee_capable(struct ixgbe_adapter *adapter)
@@ -6764,6 +6776,20 @@ static void ixgbe_set_eee_capable(struct ixgbe_adapter *adapter)
break;
adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
break;
+ case IXGBE_DEV_ID_E610_BACKPLANE:
+ case IXGBE_DEV_ID_E610_SFP:
+ case IXGBE_DEV_ID_E610_10G_T:
+ case IXGBE_DEV_ID_E610_2_5G_T:
+ if (hw->dev_caps.common_cap.eee_support &&
+ hw->phy.eee_speeds_supported) {
+ adapter->flags2 |= IXGBE_FLAG2_EEE_CAPABLE;
+ /* For E610 adapters EEE should be enabled by default
+ * if the feature is supported by FW.
+ */
+ adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
+ break;
+ }
+ fallthrough;
default:
adapter->flags2 &= ~IXGBE_FLAG2_EEE_CAPABLE;
adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
@@ -6895,8 +6921,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
#endif /* IXGBE_FCOE */
/* initialize static ixgbe jump table entries */
- adapter->jump_tables[0] = kzalloc(sizeof(*adapter->jump_tables[0]),
- GFP_KERNEL);
+ adapter->jump_tables[0] = kzalloc_obj(*adapter->jump_tables[0]);
if (!adapter->jump_tables[0])
return -ENOMEM;
adapter->jump_tables[0]->mat = ixgbe_ipv4_fields;
@@ -6904,9 +6929,8 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
for (i = 1; i < IXGBE_MAX_LINK_HANDLE; i++)
adapter->jump_tables[i] = NULL;
- adapter->mac_table = kcalloc(hw->mac.num_rar_entries,
- sizeof(struct ixgbe_mac_addr),
- GFP_KERNEL);
+ adapter->mac_table = kzalloc_objs(struct ixgbe_mac_addr,
+ hw->mac.num_rar_entries);
if (!adapter->mac_table)
return -ENOMEM;
@@ -7946,10 +7970,10 @@ static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter)
if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
for (i = 0; i < adapter->num_tx_queues; i++)
set_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &(adapter->tx_ring[i]->state));
+ adapter->tx_ring[i]->state);
for (i = 0; i < adapter->num_xdp_queues; i++)
set_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &adapter->xdp_ring[i]->state);
+ adapter->xdp_ring[i]->state);
/* re-enable flow director interrupts */
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
} else {
@@ -8074,6 +8098,7 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u32 link_speed = adapter->link_speed;
+ struct ethtool_keee keee = {};
const char *speed_str;
bool flow_rx, flow_tx;
@@ -8114,6 +8139,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
ixgbe_ptp_start_cyclecounter(adapter);
+ netdev->ethtool_ops->get_eee(netdev, &keee);
+
switch (link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
speed_str = "10 Gbps";
@@ -8137,10 +8164,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
speed_str = "unknown speed";
break;
}
- e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", speed_str,
+ e_info(drv, "NIC Link is Up %s, Flow Control: %s, EEE: %s\n", speed_str,
((flow_rx && flow_tx) ? "RX/TX" :
(flow_rx ? "RX" :
- (flow_tx ? "TX" : "None"))));
+ (flow_tx ? "TX" : "None"))),
+ str_on_off(keee.eee_enabled));
netif_carrier_on(netdev);
ixgbe_check_vf_rate_limit(adapter);
@@ -9245,10 +9273,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
if (sb_dev) {
u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
struct net_device *vdev = sb_dev;
+ struct netdev_tc_txq res;
- txq = vdev->tc_to_txq[tc].offset;
- txq += reciprocal_scale(skb_get_hash(skb),
- vdev->tc_to_txq[tc].count);
+ res.combined = READ_ONCE(vdev->tc_to_txq[tc].combined);
+ txq = res.offset;
+ txq += reciprocal_scale(skb_get_hash(skb), res.count);
return txq;
}
@@ -9490,7 +9519,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
ixgbe_tx_csum(tx_ring, first, &ipsec_tx);
/* add the ATR filter if ATR is on */
- if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
+ if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, tx_ring->state))
ixgbe_atr(tx_ring, first);
#ifdef IXGBE_FCOE
@@ -9530,7 +9559,7 @@ static netdev_tx_t __ixgbe_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
tx_ring = ring ? ring : adapter->tx_ring[skb_get_queue_mapping(skb)];
- if (unlikely(test_bit(__IXGBE_TX_DISABLED, &tx_ring->state)))
+ if (unlikely(test_bit(__IXGBE_TX_DISABLED, tx_ring->state)))
return NETDEV_TX_BUSY;
return ixgbe_xmit_frame_ring(skb, adapter, tx_ring);
@@ -10273,15 +10302,15 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
(__force u32)cls->knode.sel->offmask)
return err;
- jump = kzalloc(sizeof(*jump), GFP_KERNEL);
+ jump = kzalloc_obj(*jump);
if (!jump)
return -ENOMEM;
- input = kzalloc(sizeof(*input), GFP_KERNEL);
+ input = kzalloc_obj(*input);
if (!input) {
err = -ENOMEM;
goto free_jump;
}
- mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ mask = kzalloc_obj(*mask);
if (!mask) {
err = -ENOMEM;
goto free_input;
@@ -10305,10 +10334,10 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
return 0;
}
- input = kzalloc(sizeof(*input), GFP_KERNEL);
+ input = kzalloc_obj(*input);
if (!input)
return -ENOMEM;
- mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ mask = kzalloc_obj(*mask);
if (!mask) {
err = -ENOMEM;
goto free_input;
@@ -10786,7 +10815,7 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
return ERR_PTR(-ENOMEM);
}
- accel = kzalloc(sizeof(*accel), GFP_KERNEL);
+ accel = kzalloc_obj(*accel);
if (!accel)
return ERR_PTR(-ENOMEM);
@@ -11015,7 +11044,7 @@ static int ixgbe_xdp_xmit(struct net_device *dev, int n,
if (unlikely(!ring))
return -ENXIO;
- if (unlikely(test_bit(__IXGBE_TX_DISABLED, &ring->state)))
+ if (unlikely(test_bit(__IXGBE_TX_DISABLED, ring->state)))
return -ENXIO;
if (static_branch_unlikely(&ixgbe_xdp_locking_key))
@@ -11121,7 +11150,7 @@ static void ixgbe_disable_txr_hw(struct ixgbe_adapter *adapter,
static void ixgbe_disable_txr(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring)
{
- set_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
+ set_bit(__IXGBE_TX_DISABLED, tx_ring->state);
ixgbe_disable_txr_hw(adapter, tx_ring);
}
@@ -11275,9 +11304,9 @@ void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
ixgbe_configure_tx_ring(adapter, xdp_ring);
ixgbe_configure_rx_ring(adapter, rx_ring);
- clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
+ clear_bit(__IXGBE_TX_DISABLED, tx_ring->state);
if (xdp_ring)
- clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state);
+ clear_bit(__IXGBE_TX_DISABLED, xdp_ring->state);
/* Rx/Tx/XDP Tx share the same napi context. */
napi_enable(&rx_ring->q_vector->napi);
@@ -11468,20 +11497,17 @@ static void ixgbe_set_fw_version(struct ixgbe_adapter *adapter)
*/
static int ixgbe_recovery_probe(struct ixgbe_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct ixgbe_hw *hw = &adapter->hw;
- bool disable_dev;
int err = -EIO;
if (hw->mac.type != ixgbe_mac_e610)
- goto clean_up_probe;
+ return err;
ixgbe_get_hw_control(adapter);
- mutex_init(&hw->aci.lock);
err = ixgbe_get_flash_data(&adapter->hw);
if (err)
- goto shutdown_aci;
+ goto err_release_hw_control;
timer_setup(&adapter->service_timer, ixgbe_service_timer, 0);
INIT_WORK(&adapter->service_task, ixgbe_recovery_service_task);
@@ -11504,16 +11530,8 @@ static int ixgbe_recovery_probe(struct ixgbe_adapter *adapter)
devl_unlock(adapter->devlink);
return 0;
-shutdown_aci:
- mutex_destroy(&adapter->hw.aci.lock);
+err_release_hw_control:
ixgbe_release_hw_control(adapter);
-clean_up_probe:
- disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
- free_netdev(netdev);
- devlink_free(adapter->devlink);
- pci_release_mem_regions(pdev);
- if (disable_dev)
- pci_disable_device(pdev);
return err;
}
@@ -11655,8 +11673,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_sw_init;
- if (ixgbe_check_fw_error(adapter))
- return ixgbe_recovery_probe(adapter);
+ if (ixgbe_check_fw_error(adapter)) {
+ err = ixgbe_recovery_probe(adapter);
+ if (err)
+ goto err_sw_init;
+
+ return 0;
+ }
if (adapter->hw.mac.type == ixgbe_mac_e610) {
err = ixgbe_get_caps(&adapter->hw);
@@ -12001,6 +12024,13 @@ skip_sriov:
if (err)
goto err_netdev;
+ if (hw->mac.type == ixgbe_mac_e610 &&
+ (adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) {
+ bool eee_enable = adapter->flags2 & IXGBE_FLAG2_EEE_ENABLED;
+
+ hw->mac.ops.setup_eee(hw, eee_enable);
+ }
+
ixgbe_devlink_init_regions(adapter);
devl_register(adapter->devlink);
devl_unlock(adapter->devlink);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 2449e4cf2679..ab733e73927d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -1534,8 +1534,10 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
struct ixgbe_adapter *adapter = hw->back;
u8 oui_bytes[3] = {0, 0, 0};
u8 bitrate_nominal = 0;
+ u8 sm_length_100m = 0;
u8 comp_codes_10g = 0;
u8 comp_codes_1g = 0;
+ u8 sm_length_km = 0;
u16 enforce_sfp = 0;
u32 vendor_oui = 0;
u8 identifier = 0;
@@ -1678,6 +1680,33 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
else
hw->phy.sfp_type =
ixgbe_sfp_type_1g_bx_core1;
+ /* Support Ethernet 10G-BX, checking the Bit Rate
+ * Nominal Value as per SFF-8472 to be 12.5 Gb/s (67h) and
+ * Single Mode fibre with at least 1km link length
+ */
+ } else if ((!comp_codes_10g) && (bitrate_nominal == 0x67) &&
+ (!(cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)) &&
+ (!(cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE))) {
+ status = hw->phy.ops.read_i2c_eeprom(hw,
+ IXGBE_SFF_SM_LENGTH_KM,
+ &sm_length_km);
+ if (status != 0)
+ goto err_read_i2c_eeprom;
+ status = hw->phy.ops.read_i2c_eeprom(hw,
+ IXGBE_SFF_SM_LENGTH_100M,
+ &sm_length_100m);
+ if (status != 0)
+ goto err_read_i2c_eeprom;
+ if (sm_length_km > 0 || sm_length_100m >= 10) {
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_10g_bx_core0;
+ else
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_10g_bx_core1;
+ } else {
+ hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+ }
} else {
hw->phy.sfp_type = ixgbe_sfp_type_unknown;
}
@@ -1768,7 +1797,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
- hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
return -EOPNOTSUPP;
}
@@ -1786,7 +1817,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
- hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) {
/* Make sure we're a supported PHY type */
if (hw->phy.type == ixgbe_phy_sfp_intel)
return 0;
@@ -2016,20 +2049,22 @@ int ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
return -EOPNOTSUPP;
/*
- * Limiting active cables and 1G Phys must be initialized as
+ * Limiting active cables, 10G BX and 1G Phys must be initialized as
* SR modules
*/
if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
- sfp_type == ixgbe_sfp_type_1g_bx_core0)
+ sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
+ sfp_type == ixgbe_sfp_type_10g_bx_core0)
sfp_type = ixgbe_sfp_type_srlr_core0;
else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
- sfp_type == ixgbe_sfp_type_1g_bx_core1)
+ sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+ sfp_type == ixgbe_sfp_type_10g_bx_core1)
sfp_type = ixgbe_sfp_type_srlr_core1;
/* Read offset to PHY init contents */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 81179c60af4e..039ba4b6c120 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -32,6 +32,8 @@
#define IXGBE_SFF_QSFP_1GBE_COMP 0x86
#define IXGBE_SFF_QSFP_CABLE_LENGTH 0x92
#define IXGBE_SFF_QSFP_DEVICE_TECH 0x93
+#define IXGBE_SFF_SM_LENGTH_KM 0xE
+#define IXGBE_SFF_SM_LENGTH_100M 0xF
/* Bitmasks */
#define IXGBE_SFF_DA_PASSIVE_CABLE 0x4
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index ee133d6749b3..431d77da15a5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -37,8 +37,7 @@ static inline void ixgbe_alloc_vf_macvlans(struct ixgbe_adapter *adapter,
if (!num_vf_macvlans)
return;
- mv_list = kcalloc(num_vf_macvlans, sizeof(struct vf_macvlans),
- GFP_KERNEL);
+ mv_list = kzalloc_objs(struct vf_macvlans, num_vf_macvlans);
if (mv_list) {
for (i = 0; i < num_vf_macvlans; i++) {
mv_list[i].vf = -1;
@@ -65,8 +64,7 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
IXGBE_FLAG_VMDQ_ENABLED;
/* Allocate memory for per VF control structures */
- adapter->vfinfo = kcalloc(num_vfs, sizeof(struct vf_data_storage),
- GFP_KERNEL);
+ adapter->vfinfo = kzalloc_objs(struct vf_data_storage, num_vfs);
if (!adapter->vfinfo)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index b1bfeb21537a..a461b6542f96 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -2798,6 +2798,7 @@ struct ixgbe_hic_hdr2_rsp {
};
union ixgbe_hic_hdr2 {
+ u32 buf[1];
struct ixgbe_hic_hdr2_req req;
struct ixgbe_hic_hdr2_rsp rsp;
};
@@ -3286,6 +3287,8 @@ enum ixgbe_sfp_type {
ixgbe_sfp_type_1g_lx_core1 = 14,
ixgbe_sfp_type_1g_bx_core0 = 15,
ixgbe_sfp_type_1g_bx_core1 = 16,
+ ixgbe_sfp_type_10g_bx_core0 = 17,
+ ixgbe_sfp_type_10g_bx_core1 = 18,
ixgbe_sfp_type_not_present = 0xFFFE,
ixgbe_sfp_type_unknown = 0xFFFF
@@ -3522,6 +3525,7 @@ struct ixgbe_mac_operations {
int (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
bool *);
void (*set_rate_select_speed)(struct ixgbe_hw *, ixgbe_link_speed);
+ int (*setup_eee)(struct ixgbe_hw *hw, bool enable_eee);
/* Packet Buffer Manipulation */
void (*set_rxpba)(struct ixgbe_hw *, int, u32, int);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
index ff8d640a50b1..959cacecae49 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -323,10 +323,8 @@ struct ixgbe_aci_cmd_get_phy_caps_data {
#define IXGBE_ACI_PHY_EEE_EN_100BASE_TX BIT(0)
#define IXGBE_ACI_PHY_EEE_EN_1000BASE_T BIT(1)
#define IXGBE_ACI_PHY_EEE_EN_10GBASE_T BIT(2)
-#define IXGBE_ACI_PHY_EEE_EN_1000BASE_KX BIT(3)
-#define IXGBE_ACI_PHY_EEE_EN_10GBASE_KR BIT(4)
-#define IXGBE_ACI_PHY_EEE_EN_25GBASE_KR BIT(5)
-#define IXGBE_ACI_PHY_EEE_EN_10BASE_T BIT(11)
+#define IXGBE_ACI_PHY_EEE_EN_5GBASE_T BIT(11)
+#define IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T BIT(12)
__le16 eeer_value;
u8 phy_id_oui[4]; /* PHY/Module ID connected on the port */
u8 phy_fw_ver[8];
@@ -356,7 +354,9 @@ struct ixgbe_aci_cmd_get_phy_caps_data {
#define IXGBE_ACI_MOD_TYPE_BYTE2_SFP_PLUS 0xA0
#define IXGBE_ACI_MOD_TYPE_BYTE2_QSFP_PLUS 0x86
u8 qualified_module_count;
- u8 rsvd2[7]; /* Bytes 47:41 reserved */
+ u8 rsvd2;
+ __le16 eee_entry_delay;
+ u8 rsvd3[4];
#define IXGBE_ACI_QUAL_MOD_COUNT_MAX 16
struct {
u8 v_oui[3];
@@ -382,6 +382,15 @@ struct ixgbe_aci_cmd_set_phy_cfg_data {
__le64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
__le64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
u8 caps;
+ u8 low_power_ctrl_an;
+ __le16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
+ __le16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
+ u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
+ u8 module_compliance_enforcement;
+ __le16 eee_entry_delay;
+} __packed;
+
+/* Set PHY config capabilities (@caps) defines */
#define IXGBE_ACI_PHY_ENA_VALID_MASK 0xef
#define IXGBE_ACI_PHY_ENA_TX_PAUSE_ABILITY BIT(0)
#define IXGBE_ACI_PHY_ENA_RX_PAUSE_ABILITY BIT(1)
@@ -390,12 +399,6 @@ struct ixgbe_aci_cmd_set_phy_cfg_data {
#define IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT BIT(5)
#define IXGBE_ACI_PHY_ENA_LESM BIT(6)
#define IXGBE_ACI_PHY_ENA_AUTO_FEC BIT(7)
- u8 low_power_ctrl_an;
- __le16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
- __le16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
- u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
- u8 module_compliance_enforcement;
-};
/* Restart AN command data structure (direct 0x0605)
* Also used for response, with only the lport_num field present.
@@ -509,8 +512,9 @@ struct ixgbe_aci_cmd_get_link_status_data {
#define IXGBE_ACI_LINK_SPEED_200GB BIT(11)
#define IXGBE_ACI_LINK_SPEED_UNKNOWN BIT(15)
__le16 reserved3;
- u8 ext_fec_status;
-#define IXGBE_ACI_LINK_RS_272_FEC_EN BIT(0) /* RS 272 FEC enabled */
+ u8 eee_status;
+#define IXGBE_ACI_LINK_EEE_ENABLED BIT(2)
+#define IXGBE_ACI_LINK_EEE_ACTIVE BIT(3)
u8 reserved4;
__le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */
__le64 phy_type_high; /* Use values from ICE_PHY_TYPE_HIGH_* */
@@ -812,6 +816,7 @@ struct ixgbe_link_status {
* of ixgbe_aci_get_phy_caps structure
*/
u8 module_type[IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE];
+ u8 eee_status;
};
/* Common HW capabilities for SW use */
@@ -891,6 +896,7 @@ struct ixgbe_hw_caps {
u8 apm_wol_support;
u8 acpi_prog_mthd;
u8 proxy_support;
+ u8 eee_support;
bool nvm_update_pending_nvm;
bool nvm_update_pending_orom;
bool nvm_update_pending_netlist;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index 76d2fa3ef518..4a0ccbf448a2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1228,7 +1228,7 @@ static int ixgbe_update_flash_X550(struct ixgbe_hw *hw)
buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
buffer.req.checksum = FW_DEFAULT_CHECKSUM;
- status = ixgbe_host_interface_command(hw, &buffer, sizeof(buffer),
+ status = ixgbe_host_interface_command(hw, buffer.buf, sizeof(buffer),
IXGBE_HI_COMMAND_TIMEOUT, false);
return status;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
index 7b941505a9d0..89f96c463f02 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -524,7 +524,7 @@ int ixgbe_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
ring = adapter->xdp_ring[qid];
- if (test_bit(__IXGBE_TX_DISABLED, &ring->state))
+ if (test_bit(__IXGBE_TX_DISABLED, ring->state))
return -ENETDOWN;
if (!ring->xsk_pool)
diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
index fce35924ff8b..076fd0a24858 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
@@ -628,7 +628,7 @@ void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter)
return;
}
- ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL);
+ ipsec = kzalloc_obj(*ipsec);
if (!ipsec)
goto err1;
hash_init(ipsec->rx_sa_list);
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index d5ce20f47def..7ce46b4b4821 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -64,20 +64,43 @@ static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id ixgbevf_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF), board_82599_vf },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF_HV), board_82599_vf_hv },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF), board_X540_vf },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF_HV), board_X540_vf_hv },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF), board_X550_vf },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF_HV), board_X550_vf_hv },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF), board_X550EM_x_vf },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF_HV), board_X550EM_x_vf_hv},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_VF), board_x550em_a_vf },
- {PCI_VDEVICE_SUB(INTEL, IXGBE_DEV_ID_E610_VF, PCI_ANY_ID,
- IXGBE_SUBDEV_ID_E610_VF_HV), board_e610_vf_hv},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_VF), board_e610_vf},
+ {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF),
+ .driver_data = board_82599_vf,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF_HV),
+ .driver_data = board_82599_vf_hv,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF),
+ .driver_data = board_X540_vf,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF_HV),
+ .driver_data = board_X540_vf_hv,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF),
+ .driver_data = board_X550_vf,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF_HV),
+ .driver_data = board_X550_vf_hv,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF),
+ .driver_data = board_X550EM_x_vf,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF_HV),
+ .driver_data = board_X550EM_x_vf_hv
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_VF),
+ .driver_data = board_x550em_a_vf,
+ }, {
+ PCI_VDEVICE_SUB(INTEL, IXGBE_DEV_ID_E610_VF,
+ PCI_ANY_ID, IXGBE_SUBDEV_ID_E610_VF_HV),
+ .driver_data = board_e610_vf_hv,
+ }, {
+ PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_VF),
+ .driver_data = board_e610_vf,
+ },
/* required last entry */
- {0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl);
@@ -1221,6 +1244,7 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
ether_addr_equal(rx_ring->netdev->dev_addr,
eth_hdr(skb)->h_source)) {
dev_kfree_skb_irq(skb);
+ skb = NULL;
continue;
}
@@ -2716,8 +2740,7 @@ static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
v_budget = min_t(int, v_budget, num_online_cpus());
v_budget += NON_Q_VECTORS;
- adapter->msix_entries = kcalloc(v_budget,
- sizeof(struct msix_entry), GFP_KERNEL);
+ adapter->msix_entries = kzalloc_objs(struct msix_entry, v_budget);
if (!adapter->msix_entries)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index 74d320879513..f6df86d124b9 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -709,6 +709,12 @@ static int ixgbevf_negotiate_features_vf(struct ixgbe_hw *hw, u32 *pf_features)
return err;
}
+static int ixgbevf_hv_negotiate_features_vf(struct ixgbe_hw *hw,
+ u32 *pf_features)
+{
+ return -EOPNOTSUPP;
+}
+
/**
* ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
* @hw: pointer to the HW structure
@@ -852,7 +858,8 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
if (!mac->get_link_status)
goto out;
- if (hw->mac.type == ixgbe_mac_e610_vf) {
+ if (hw->mac.type == ixgbe_mac_e610_vf &&
+ hw->api_version >= ixgbe_mbox_api_16) {
ret_val = ixgbevf_get_pf_link_state(hw, speed, link_up);
if (ret_val)
goto out;
@@ -1141,6 +1148,7 @@ static const struct ixgbe_mac_operations ixgbevf_hv_mac_ops = {
.setup_link = ixgbevf_setup_mac_link_vf,
.check_link = ixgbevf_hv_check_mac_link_vf,
.negotiate_api_version = ixgbevf_hv_negotiate_api_version_vf,
+ .negotiate_features = ixgbevf_hv_negotiate_features_vf,
.set_rar = ixgbevf_hv_set_rar_vf,
.update_mc_addr_list = ixgbevf_hv_update_mc_addr_list_vf,
.update_xcast_mode = ixgbevf_hv_update_xcast_mode,
diff --git a/drivers/net/ethernet/intel/libeth/rx.c b/drivers/net/ethernet/intel/libeth/rx.c
index 62521a1f4ec9..0c1a565a1b3a 100644
--- a/drivers/net/ethernet/intel/libeth/rx.c
+++ b/drivers/net/ethernet/intel/libeth/rx.c
@@ -145,25 +145,29 @@ static bool libeth_rx_page_pool_params_zc(struct libeth_fq *fq,
/**
* libeth_rx_fq_create - create a PP with the default libeth settings
* @fq: buffer queue struct to fill
- * @napi: &napi_struct covering this PP (no usage outside its poll loops)
+ * @napi_dev: &napi_struct for NAPI (data) queues, &device for others
*
* Return: %0 on success, -%errno on failure.
*/
-int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi)
+int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev)
{
+ struct napi_struct *napi = fq->no_napi ? NULL : napi_dev;
struct page_pool_params pp = {
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
.order = LIBETH_RX_PAGE_ORDER,
.pool_size = fq->count,
.nid = fq->nid,
- .dev = napi->dev->dev.parent,
- .netdev = napi->dev,
+ .dev = napi ? napi->dev->dev.parent : napi_dev,
+ .netdev = napi ? napi->dev : NULL,
.napi = napi,
};
struct libeth_fqe *fqes;
struct page_pool *pool;
int ret;
+ if (!pp.netdev && fq->type == LIBETH_FQE_MTU)
+ return -EINVAL;
+
pp.dma_dir = fq->xdp ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
if (!fq->hsplit)
diff --git a/drivers/net/ethernet/intel/libeth/xsk.c b/drivers/net/ethernet/intel/libeth/xsk.c
index 846e902e31b6..4882951d5c9c 100644
--- a/drivers/net/ethernet/intel/libeth/xsk.c
+++ b/drivers/net/ethernet/intel/libeth/xsk.c
@@ -167,6 +167,7 @@ int libeth_xskfq_create(struct libeth_xskfq *fq)
fq->pending = fq->count;
fq->thresh = libeth_xdp_queue_threshold(fq->count);
fq->buf_len = xsk_pool_get_rx_frame_size(fq->pool);
+ fq->truesize = xsk_pool_get_rx_frag_step(fq->pool);
return 0;
}
diff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig
index 70831c7e336e..9c5fdebb6766 100644
--- a/drivers/net/ethernet/intel/libie/Kconfig
+++ b/drivers/net/ethernet/intel/libie/Kconfig
@@ -15,6 +15,14 @@ config LIBIE_ADMINQ
Helper functions used by Intel Ethernet drivers for administration
queue command interface (aka adminq).
+config LIBIE_CP
+ tristate
+ select LIBETH
+ select LIBIE_PCI
+ help
+ Common helper routines to communicate with the device Control Plane
+ using virtchnl2 or related mailbox protocols.
+
config LIBIE_FWLOG
tristate
select LIBIE_ADMINQ
@@ -23,3 +31,9 @@ config LIBIE_FWLOG
for it. Firmware logging is using admin queue interface to communicate
with the device. Debugfs is a user interface used to config logging
and dump all collected logs.
+
+config LIBIE_PCI
+ tristate
+ help
+ Helper functions for management of PCI resources belonging
+ to networking devices.
diff --git a/drivers/net/ethernet/intel/libie/Makefile b/drivers/net/ethernet/intel/libie/Makefile
index db57fc6780ea..3065aa057798 100644
--- a/drivers/net/ethernet/intel/libie/Makefile
+++ b/drivers/net/ethernet/intel/libie/Makefile
@@ -9,6 +9,14 @@ obj-$(CONFIG_LIBIE_ADMINQ) += libie_adminq.o
libie_adminq-y := adminq.o
+obj-$(CONFIG_LIBIE_CP) += libie_cp.o
+
+libie_cp-y := controlq.o
+
obj-$(CONFIG_LIBIE_FWLOG) += libie_fwlog.o
libie_fwlog-y := fwlog.o
+
+obj-$(CONFIG_LIBIE_PCI) += libie_pci.o
+
+libie_pci-y := pci.o
diff --git a/drivers/net/ethernet/intel/libie/controlq.c b/drivers/net/ethernet/intel/libie/controlq.c
new file mode 100644
index 000000000000..6214fc036ce5
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/controlq.c
@@ -0,0 +1,1294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/bitfield.h>
+#include <net/libeth/rx.h>
+
+#include <linux/net/intel/libie/controlq.h>
+
+#define LIBIE_CTLQ_DESC_QWORD0(sz) \
+ (LIBIE_CTLQ_DESC_FLAG_BUF | \
+ LIBIE_CTLQ_DESC_FLAG_RD | \
+ FIELD_PREP(LIBIE_CTLQ_DESC_DATA_LEN, sz))
+
+/**
+ * libie_ctlq_free_fq - free fill queue resources, including buffers
+ * @ctlq: Rx control queue whose resources need to be freed
+ */
+static void libie_ctlq_free_fq(struct libie_ctlq_info *ctlq)
+{
+ struct libeth_fq fq = {
+ .fqes = ctlq->rx_fqes,
+ .pp = ctlq->pp,
+ };
+
+ for (u32 ntc = ctlq->next_to_clean; ntc != ctlq->next_to_post; ) {
+ page_pool_put_full_netmem(fq.pp, fq.fqes[ntc].netmem, false);
+
+ if (++ntc >= ctlq->ring_len)
+ ntc = 0;
+ }
+
+ libeth_rx_fq_destroy(&fq);
+}
+
+/**
+ * libie_ctlq_init_fq - initialize fill queue for an Rx controlq
+ * @ctlq: control queue that needs Rx buffer allocation
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+static int libie_ctlq_init_fq(struct libie_ctlq_info *ctlq)
+{
+ struct libeth_fq fq = {
+ .count = ctlq->ring_len,
+ .truesize = LIBIE_CTLQ_MAX_BUF_LEN,
+ .nid = NUMA_NO_NODE,
+ .type = LIBETH_FQE_SHORT,
+ .hsplit = true,
+ .no_napi = true,
+ };
+ int err;
+
+ err = libeth_rx_fq_create(&fq, ctlq->dev);
+ if (err)
+ return err;
+
+ ctlq->pp = fq.pp;
+ ctlq->rx_fqes = fq.fqes;
+ ctlq->truesize = fq.truesize;
+
+ return 0;
+}
+
+/**
+ * libie_ctlq_prep_rx_desc - prepare the descriptor with a new address
+ * @desc: descriptor to (re)initialize
+ * @addr: physical address to put into descriptor
+ * @mem_truesize: size of the accessible memory
+ */
+static void libie_ctlq_prep_rx_desc(struct libie_ctlq_desc *desc,
+ dma_addr_t addr, u32 mem_truesize)
+{
+ u64 qword;
+
+ qword = LIBIE_CTLQ_DESC_QWORD0(mem_truesize);
+ desc->qword0 = cpu_to_le64(qword);
+
+ qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
+ upper_32_bits(addr)) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
+ lower_32_bits(addr));
+ desc->qword3 = cpu_to_le64(qword);
+}
+
+/**
+ * libie_ctlq_post_rx_buffs - post buffers to descriptor ring
+ * @ctlq: control queue that requires Rx descriptor ring to be initialized with
+ * new Rx buffers
+ *
+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
+ * and libie_ctlq_recv() for each queue are either serialized
+ * or used under ctlq->lock.
+ *
+ * Return: %0 on success, -%ENOMEM if any buffer could not be allocated
+ */
+int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq)
+{
+ u32 ntp = ctlq->next_to_post, ntc = ctlq->next_to_clean, num_to_post;
+ const struct libeth_fq_fp fq = {
+ .pp = ctlq->pp,
+ .fqes = ctlq->rx_fqes,
+ .truesize = ctlq->truesize,
+ .count = ctlq->ring_len,
+ };
+ int ret = 0;
+
+ num_to_post = (ntc > ntp ? 0 : ctlq->ring_len) + ntc - ntp - 1;
+
+ while (num_to_post--) {
+ dma_addr_t addr;
+
+ ctlq->descs[ntp] = (struct libie_ctlq_desc) {};
+
+ addr = libeth_rx_alloc(&fq, ntp);
+ if (unlikely(addr == DMA_MAPPING_ERROR)) {
+ ret = -ENOMEM;
+ goto post_bufs;
+ }
+
+ libie_ctlq_prep_rx_desc(&ctlq->descs[ntp], addr, fq.truesize);
+
+ if (unlikely(++ntp == ctlq->ring_len))
+ ntp = 0;
+ }
+
+post_bufs:
+ if (likely(ctlq->next_to_post != ntp)) {
+ ctlq->next_to_post = ntp;
+
+ dma_wmb();
+ writel(ntp, ctlq->reg.tail);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_post_rx_buffs, "LIBIE_CP");
+
+/**
+ * libie_ctlq_free_tx_msgs - Free Tx control queue messages
+ * @ctlq: Tx control queue being destroyed
+ * @num_msgs: number of messages allocated so far
+ */
+static void libie_ctlq_free_tx_msgs(struct libie_ctlq_info *ctlq,
+ u32 num_msgs)
+{
+ for (u32 i = 0; i < num_msgs; i++)
+ kfree(ctlq->tx_msg[i]);
+
+ kvfree(ctlq->tx_msg);
+}
+
+/**
+ * libie_ctlq_alloc_tx_msgs - Allocate Tx control queue messages
+ * @ctlq: Tx control queue being created
+ *
+ * Return: %0 on success, -%ENOMEM on allocation error
+ */
+static int libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info *ctlq)
+{
+ ctlq->tx_msg = kvzalloc_objs(*ctlq->tx_msg, ctlq->ring_len);
+ if (!ctlq->tx_msg)
+ return -ENOMEM;
+
+ for (u32 i = 0; i < ctlq->ring_len; i++) {
+ ctlq->tx_msg[i] = kzalloc_obj(*ctlq->tx_msg[i]);
+ if (!ctlq->tx_msg[i]) {
+ libie_ctlq_free_tx_msgs(ctlq, i);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * libie_cp_free_desc_mem - free the previously allocated descriptor DMA memory
+ * @dev: device information
+ * @mem: DMA memory information
+ */
+static void libie_cp_free_desc_mem(struct device *dev,
+ struct libie_cp_dma_mem *mem)
+{
+ dma_free_coherent(dev, mem->size, mem->va, mem->pa);
+ mem->va = NULL;
+}
+
+/**
+ * libie_ctlq_dealloc_ring_res - free memory allocated for control queue
+ * @ctlq: control queue that requires its ring memory to be freed
+ *
+ * Free the memory used by the ring, buffers and other related structures.
+ */
+static void libie_ctlq_dealloc_ring_res(struct libie_ctlq_info *ctlq)
+{
+ struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
+
+ if (ctlq->type == LIBIE_CTLQ_TYPE_TX)
+ libie_ctlq_free_tx_msgs(ctlq, ctlq->ring_len);
+ else
+ libie_ctlq_free_fq(ctlq);
+
+ libie_cp_free_desc_mem(ctlq->dev, dma);
+}
+
+/**
+ * libie_cp_alloc_desc_mem - allocate DMA memory for descriptor ring
+ * @dev: device information
+ * @mem: memory for DMA information to be stored
+ * @size: size of the memory to allocate
+ *
+ * Return: virtual address of DMA memory or NULL.
+ */
+static void *libie_cp_alloc_desc_mem(struct device *dev,
+ struct libie_cp_dma_mem *mem, u32 size)
+{
+ size = LARGEST_ALIGN(size);
+
+ mem->va = dma_alloc_coherent(dev, size, &mem->pa, GFP_KERNEL);
+ mem->size = size;
+ mem->direction = DMA_BIDIRECTIONAL;
+
+ return mem->va;
+}
+
+/**
+ * libie_ctlq_alloc_queue_res - allocate memory for descriptor ring and bufs
+ * @ctlq: control queue that requires its ring resources to be allocated
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+static int libie_ctlq_alloc_queue_res(struct libie_ctlq_info *ctlq)
+{
+ size_t size = array_size(ctlq->ring_len, sizeof(*ctlq->descs));
+ struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
+ int err = -ENOMEM;
+
+ if (!libie_cp_alloc_desc_mem(ctlq->dev, dma, size))
+ return -ENOMEM;
+
+ ctlq->descs = dma->va;
+
+ if (ctlq->type == LIBIE_CTLQ_TYPE_TX) {
+ if (libie_ctlq_alloc_tx_msgs(ctlq))
+ goto free_dma_mem;
+ } else {
+ err = libie_ctlq_init_fq(ctlq);
+ if (err)
+ goto free_dma_mem;
+
+ err = libie_ctlq_post_rx_buffs(ctlq);
+ if (err) {
+ libie_ctlq_free_fq(ctlq);
+ goto free_dma_mem;
+ }
+ }
+
+ return 0;
+
+free_dma_mem:
+ libie_cp_free_desc_mem(ctlq->dev, dma);
+
+ return err;
+}
+
+/**
+ * libie_ctlq_init_regs - Initialize control queue registers
+ * @ctlq: control queue that needs to be initialized
+ *
+ * Initialize registers. The caller is expected to have already initialized the
+ * descriptor ring memory and buffer memory.
+ */
+static void libie_ctlq_init_regs(struct libie_ctlq_info *ctlq)
+{
+ u32 dword;
+
+ if (ctlq->type == LIBIE_CTLQ_TYPE_RX)
+ writel(ctlq->ring_len - 1, ctlq->reg.tail);
+ else
+ writel(0, ctlq->reg.tail);
+
+ writel(0, ctlq->reg.head);
+ writel(lower_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_low);
+ writel(upper_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_high);
+
+ dword = FIELD_PREP(LIBIE_CTLQ_MBX_ATQ_LEN, ctlq->ring_len) |
+ ctlq->reg.len_ena_mask;
+ writel(dword, ctlq->reg.len);
+}
+
+/**
+ * libie_find_ctlq - find the controlq for the given id and type
+ * @ctx: libie CP context information
+ * @type: type of controlq to find
+ * @id: controlq id to find
+ *
+ * Return: control queue info pointer on success, NULL on failure
+ */
+struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,
+ enum libie_ctlq_type type,
+ int id)
+{
+ struct libie_ctlq_info *cq;
+
+ guard(spinlock)(&ctx->ctlqs_lock);
+
+ list_for_each_entry(cq, &ctx->ctlqs, list)
+ if (cq->qid == id && cq->type == type)
+ return cq;
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(libie_find_ctlq, "LIBIE_CP");
+
+/**
+ * libie_ctlq_add - add one control queue
+ * @ctx: libie CP context information
+ * @qinfo: information required for queue creation
+ *
+ * Allocate and initialize a control queue and add it to the control queue list.
+ * libie_ctlq_init() must be called prior to any calls to libie_ctlq_add.
+ *
+ * Return: added control queue info pointer on success, error pointer on failure
+ */
+static struct libie_ctlq_info *
+libie_ctlq_add(struct libie_ctlq_ctx *ctx,
+ const struct libie_ctlq_create_info *qinfo)
+{
+ struct libie_ctlq_info *ctlq;
+ int err;
+
+ if (qinfo->id != LIBIE_CTLQ_MBX_ID)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (qinfo->len > FIELD_MAX(LIBIE_CTLQ_MBX_ATQ_LEN) || !qinfo->len)
+ return ERR_PTR(-EINVAL);
+
+ ctlq = kvzalloc_obj(*ctlq);
+ if (!ctlq)
+ return ERR_PTR(-ENOMEM);
+
+ ctlq->type = qinfo->type;
+ ctlq->qid = qinfo->id;
+ ctlq->ring_len = qinfo->len;
+ ctlq->dev = &ctx->mmio_info.pdev->dev;
+ ctlq->reg = qinfo->reg;
+
+ err = libie_ctlq_alloc_queue_res(ctlq);
+ if (err) {
+ kvfree(ctlq);
+ return ERR_PTR(err);
+ }
+
+ libie_ctlq_init_regs(ctlq);
+
+ spin_lock_init(&ctlq->lock);
+
+ scoped_guard(spinlock, &ctx->ctlqs_lock)
+ list_add(&ctlq->list, &ctx->ctlqs);
+
+ return ctlq;
+}
+
+/**
+ * libie_ctlq_remove - deallocate and remove specified control queue
+ * @ctx: libie CP context information
+ * @ctlq: specific control queue that needs to be removed
+ */
+static void libie_ctlq_remove(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_info *ctlq)
+{
+ scoped_guard(spinlock, &ctx->ctlqs_lock)
+ list_del(&ctlq->list);
+
+ libie_ctlq_dealloc_ring_res(ctlq);
+ kvfree(ctlq);
+}
+
+/**
+ * libie_ctlq_init - main initialization routine for all control queues
+ * @ctx: libie CP context information
+ * @qinfo: array of structs containing info for each queue to be initialized
+ * @numq: number of queues to initialize
+ *
+ * This initializes queue list and adds any number and any type of control
+ * queues. This is an all or nothing routine; if one fails, all previously
+ * allocated queues will be destroyed.
+ *
+ * Please note that any control queue send/receive functions are not
+ * softirq/NAPI safe, and therefore API can be used in process context only.
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+int libie_ctlq_init(struct libie_ctlq_ctx *ctx,
+ const struct libie_ctlq_create_info *qinfo,
+ u32 numq)
+{
+ INIT_LIST_HEAD(&ctx->ctlqs);
+ spin_lock_init(&ctx->ctlqs_lock);
+
+ for (u32 i = 0; i < numq; i++) {
+ struct libie_ctlq_info *ctlq;
+
+ ctlq = libie_ctlq_add(ctx, &qinfo[i]);
+ if (IS_ERR(ctlq)) {
+ libie_ctlq_deinit(ctx);
+ return PTR_ERR(ctlq);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_init, "LIBIE_CP");
+
+/**
+ * libie_ctlq_deinit - destroy all control queues
+ * @ctx: libie CP context information
+ */
+void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx)
+{
+ struct libie_ctlq_info *ctlq, *tmp;
+
+ list_for_each_entry_safe(ctlq, tmp, &ctx->ctlqs, list)
+ libie_ctlq_remove(ctx, ctlq);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_deinit, "LIBIE_CP");
+
+/**
+ * libie_ctlq_tx_desc_from_msg - initialize a Tx descriptor from a message
+ * @desc: descriptor to be initialized
+ * @msg: filled control queue message
+ */
+static void libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc *desc,
+ const struct libie_ctlq_msg *msg)
+{
+ const struct libie_cp_dma_mem *dma = &msg->send_mem;
+ u64 qword;
+
+ qword = FIELD_PREP(LIBIE_CTLQ_DESC_FLAGS, msg->flags) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_INFRA_OPCODE, msg->opcode) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_PFID_VFID, msg->func_id);
+ desc->qword0 = cpu_to_le64(qword);
+
+ qword = FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE,
+ msg->chnl_opcode) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL,
+ msg->chnl_retval);
+ desc->qword1 = cpu_to_le64(qword);
+
+ qword = FIELD_PREP(LIBIE_CTLQ_DESC_MSG_PARAM0, msg->param0) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_SW_COOKIE,
+ msg->sw_cookie) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS,
+ msg->virt_flags);
+ desc->qword2 = cpu_to_le64(qword);
+
+ if (likely(msg->data_len)) {
+ desc->qword0 |=
+ cpu_to_le64(LIBIE_CTLQ_DESC_QWORD0(msg->data_len));
+ qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
+ upper_32_bits(dma->pa)) |
+ FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
+ lower_32_bits(dma->pa));
+ } else {
+ qword = msg->addr_param;
+ }
+
+ desc->qword3 = cpu_to_le64(qword);
+}
+
+/**
+ * libie_ctlq_send_desc_avail - get number of free descriptors on a Tx ctlq
+ * @ctlq: specific control queue which is going be used for sending messages
+ *
+ * The caller must hold ctlq->lock. Any dependent sending must be done
+ * in the same critical section.
+ *
+ * Return: number of available descriptors/messages on a given control queue.
+ */
+u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq)
+{
+ u32 ntu = ctlq->next_to_use, ntc = ctlq->next_to_clean;
+
+ lockdep_assert_held(&ctlq->lock);
+
+ return (ntc > ntu ? 0 : ctlq->ring_len) + ntc - ntu - 1;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_desc_avail, "LIBIE_CP");
+
+/**
+ * libie_ctlq_send - send a message to Control Plane or Peer
+ * @ctlq: specific control queue which is used for sending a message
+ * @num_q_msg: number of messages present to send on @ctlq,
+ * positive and no greater than the number of available descriptors
+ *
+ * The caller must fill in @num_q_msg Tx messages starting at ntu beforehand.
+ *
+ * The caller must hold ctlq->lock. The intended pattern is to first check
+ * the number of descriptors available, then fill in the messages and perform
+ * send within a single critical section.
+ */
+void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg)
+{
+ u32 ntu = ctlq->next_to_use;
+
+ lockdep_assert_held(&ctlq->lock);
+
+ for (int i = 0; i < num_q_msg; i++) {
+ struct libie_ctlq_msg *msg = ctlq->tx_msg[ntu];
+ struct libie_ctlq_desc *desc;
+
+ desc = &ctlq->descs[ntu];
+ libie_ctlq_tx_desc_from_msg(desc, msg);
+
+ if (unlikely(++ntu == ctlq->ring_len))
+ ntu = 0;
+ }
+ dma_wmb();
+ writel(ntu, ctlq->reg.tail);
+ ctlq->next_to_use = ntu;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send, "LIBIE_CP");
+
+/**
+ * libie_ctlq_send_clean - cleanup the send control queue message buffers
+ * @params: information for handling of Tx completions
+ *
+ * Cleanup the send buffers for the given control queue, if force is set, then
+ * clear all the outstanding send messages irrespective of their send status,
+ * until a zero-length message is encountered, which is either a message that
+ * is already cleared, or a VF reset message, which is always last.
+ * Force should be used during deinit or reset.
+ *
+ * Return: number of send buffers cleaned.
+ */
+u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params)
+{
+ struct libie_ctlq_info *ctlq = params->ctlq;
+ u32 ntc, i;
+
+ spin_lock(&ctlq->lock);
+ ntc = ctlq->next_to_clean;
+
+ for (i = 0; i < params->num_msgs; i++) {
+ struct libie_ctlq_msg *msg = ctlq->tx_msg[ntc];
+ struct libie_ctlq_desc *desc;
+ u64 qword;
+
+ desc = &ctlq->descs[ntc];
+ qword = le64_to_cpu(desc->qword0);
+
+ if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword) &&
+ !(unlikely(params->force) && msg->data_len))
+ break;
+
+ /* This cannot be reordered and lock is taken, so no barriers */
+ desc->qword0 = 0;
+
+ params->rel_dma_mem(params->rel_ctx, &msg->send_mem);
+ memset(msg, 0, sizeof(*msg));
+
+ if (unlikely(++ntc == ctlq->ring_len))
+ ntc = 0;
+ }
+
+ ctlq->next_to_clean = ntc;
+ spin_unlock(&ctlq->lock);
+
+ return i;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_clean, "LIBIE_CP");
+
+/**
+ * libie_ctlq_fill_rx_msg - fill in a message from Rx descriptor and buffer
+ * @msg: message to be filled in
+ * @desc: received descriptor
+ * @rx_buf: fill queue buffer associated with the descriptor
+ */
+static void libie_ctlq_fill_rx_msg(struct libie_ctlq_msg *msg,
+ const struct libie_ctlq_desc *desc,
+ struct libeth_fqe *rx_buf)
+{
+ u64 qword = le64_to_cpu(desc->qword0);
+
+ msg->flags = FIELD_GET(LIBIE_CTLQ_DESC_FLAGS, qword);
+ msg->opcode = FIELD_GET(LIBIE_CTLQ_DESC_INFRA_OPCODE, qword);
+ msg->data_len = FIELD_GET(LIBIE_CTLQ_DESC_DATA_LEN, qword);
+ msg->hw_retval = FIELD_GET(LIBIE_CTLQ_DESC_HW_RETVAL, qword);
+
+ qword = le64_to_cpu(desc->qword1);
+ msg->chnl_opcode =
+ FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE, qword);
+ msg->chnl_retval =
+ FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL, qword);
+
+ qword = le64_to_cpu(desc->qword2);
+ msg->param0 =
+ FIELD_GET(LIBIE_CTLQ_DESC_MSG_PARAM0, qword);
+ msg->sw_cookie =
+ FIELD_GET(LIBIE_CTLQ_DESC_SW_COOKIE, qword);
+ msg->virt_flags =
+ FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS, qword);
+
+ if (likely(msg->data_len)) {
+ if (unlikely(msg->data_len > LIBIE_CTLQ_MAX_BUF_LEN)) {
+ msg->data_len = LIBIE_CTLQ_MAX_BUF_LEN;
+ msg->chnl_retval = U32_MAX;
+ }
+ msg->recv_mem = (struct kvec) {
+ .iov_base = netmem_address(rx_buf->netmem) +
+ rx_buf->offset,
+ .iov_len = msg->data_len,
+ };
+ libeth_rx_sync_for_cpu(rx_buf, msg->data_len);
+ } else {
+ msg->recv_mem = (struct kvec) {};
+ msg->addr_param = le64_to_cpu(desc->qword3);
+ page_pool_put_full_netmem(netmem_get_pp(rx_buf->netmem),
+ rx_buf->netmem, false);
+ }
+}
+
+/**
+ * libie_ctlq_recv - receive control queue messages
+ * @ctlq: control queue that needs to processed for receive
+ * @msg: array of received control queue messages on this q;
+ * needs to be pre-allocated by caller for as many messages as requested
+ * @num_q_msg: number of messages that can be stored in msg buffer,
+ * no greater than number of posted buffers
+ *
+ * Caller is expected to return buffers via libie_ctlq_release_rx_buf().
+ *
+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
+ * and libie_ctlq_recv() for each queue are either serialized
+ * or used under ctlq->lock.
+ *
+ * Return: number of messages received
+ */
+u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
+ u32 num_q_msg)
+{
+ u32 ntc, i;
+
+ ntc = ctlq->next_to_clean;
+
+ for (i = 0; i < num_q_msg; i++) {
+ struct libie_ctlq_desc *desc = &ctlq->descs[ntc];
+ struct libeth_fqe *rx_buf = &ctlq->rx_fqes[ntc];
+ u64 qword;
+
+ qword = le64_to_cpu(desc->qword0);
+ if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword))
+ break;
+
+ dma_rmb();
+
+ libie_ctlq_fill_rx_msg(&msg[i], desc, rx_buf);
+ desc->qword0 = 0;
+
+ if (unlikely(++ntc == ctlq->ring_len))
+ ntc = 0;
+ }
+
+ ctlq->next_to_clean = ntc;
+
+ return i;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_recv, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_pop_free - get a free Xn entry from the free list
+ * @xnm: Xn transaction manager
+ *
+ * Retrieve a free Xn entry from the free list.
+ *
+ * Return: valid Xn entry pointer or NULL if there are no free Xn entries.
+ */
+static struct libie_ctlq_xn *
+libie_ctlq_xn_pop_free(struct libie_ctlq_xn_manager *xnm)
+{
+ struct libie_ctlq_xn *xn;
+ u32 free_idx;
+
+ guard(spinlock)(&xnm->free_xns_bm_lock);
+
+ if (unlikely(xnm->shutdown))
+ return NULL;
+
+ for_each_set_bit(free_idx, xnm->free_xns_bm,
+ LIBIE_CTLQ_MAX_XN_ENTRIES) {
+ xn = &xnm->ring[free_idx];
+
+ /* Torn read of the physical address is possible, the worst case
+ * scenario is a transient spurious skip. If the physical
+ * address is dirty in any way, reuse is already safe.
+ */
+ if (xn->tx_msg &&
+ data_race(xn->tx_msg->send_mem.pa) == xn->small_dma_mem.pa)
+ continue;
+
+ clear_bit(free_idx, xnm->free_xns_bm);
+
+ return xn;
+ }
+
+ return NULL;
+}
+
+/**
+ * __libie_ctlq_xn_push_free - unsafely push an xn entry into the free list
+ * @xnm: Xn transaction manager
+ * @xn: xn entry to be added into the free list
+ *
+ * Return: whether xnm destruction can be triggered by the caller
+ */
+static bool __libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
+ struct libie_ctlq_xn *xn)
+{
+ xn->cookie++;
+ set_bit(xn->index, xnm->free_xns_bm);
+
+ if (unlikely(xnm->shutdown) &&
+ bitmap_full(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES))
+ return true;
+
+ return false;
+}
+
+/**
+ * libie_ctlq_xn_push_free - push a Xn entry into the free list
+ * @xnm: Xn transaction manager
+ * @xn: xn entry to be added into the free list, not locked
+ *
+ * Safely add a used Xn entry back to the free list.
+ */
+static void libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
+ struct libie_ctlq_xn *xn)
+{
+ bool can_destroy;
+
+ scoped_guard(spinlock, &xnm->free_xns_bm_lock)
+ can_destroy = __libie_ctlq_xn_push_free(xnm, xn);
+
+ if (can_destroy)
+ complete(&xnm->can_destroy);
+}
+
+/**
+ * libie_ctlq_xn_deinit_dma - free the DMA memory allocated for send messages
+ * @xnm: pointer to the transaction manager
+ * @num_entries: number of Xn entries to free the DMA for
+ */
+static void libie_ctlq_xn_deinit_dma(struct libie_ctlq_xn_manager *xnm,
+ u32 num_entries)
+{
+ for (u32 i = 0; i < num_entries; i++) {
+ struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+ dma_pool_free(xnm->small_buff_pool, xn->small_dma_mem.va,
+ xn->small_dma_mem.pa);
+ }
+
+ dma_pool_destroy(xnm->small_buff_pool);
+}
+
+/**
+ * libie_ctlq_xn_init_dma - pre-allocate DMA memory for send messages that use
+ * stack variables
+ * @dev: device pointer
+ * @xnm: pointer to transaction manager
+ *
+ * Return: %0 on success or error if memory allocation fails
+ */
+static int libie_ctlq_xn_init_dma(struct device *dev,
+ struct libie_ctlq_xn_manager *xnm)
+{
+ u32 i;
+
+ xnm->small_buff_pool =
+ dma_pool_create("libie_ctlq_xn_tx", dev, LIBIE_CP_TX_COPYBREAK,
+ LIBIE_CP_TX_COPYBREAK, 0);
+ if (!xnm->small_buff_pool)
+ return -ENOMEM;
+
+ for (i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
+ struct libie_cp_dma_mem *mem = &xnm->ring[i].small_dma_mem;
+
+ mem->va = dma_pool_zalloc(xnm->small_buff_pool, GFP_KERNEL,
+ &mem->pa);
+ if (!mem->va)
+ goto dealloc_dma;
+
+ mem->direction = DMA_BIDIRECTIONAL;
+ mem->size = LIBIE_CP_TX_COPYBREAK;
+ }
+
+ return 0;
+
+dealloc_dma:
+ libie_ctlq_xn_deinit_dma(xnm, i);
+
+ return -ENOMEM;
+}
+
+/**
+ * libie_ctlq_xn_process_recv - process Xn data in receive message
+ * @params: Xn receive param information to handle a receive message
+ * @ctlq_msg: received control queue message
+ *
+ * Process a control queue receive message and send a complete event
+ * notification.
+ *
+ * Return: true if a message has been processed, false otherwise.
+ */
+static bool
+libie_ctlq_xn_process_recv(struct libie_ctlq_xn_recv_params *params,
+ struct libie_ctlq_msg *ctlq_msg)
+{
+ struct libie_ctlq_xn_manager *xnm = params->xnm;
+ struct libie_ctlq_xn *xn;
+ u16 msg_cookie, xn_index;
+ struct kvec *response;
+ int status;
+ u16 data;
+
+ data = ctlq_msg->sw_cookie;
+ xn_index = FIELD_GET(LIBIE_CTLQ_XN_INDEX_M, data);
+ msg_cookie = FIELD_GET(LIBIE_CTLQ_XN_COOKIE_M, data);
+ status = ctlq_msg->chnl_retval ? -EFAULT : 0;
+
+ xn = &xnm->ring[xn_index];
+ spin_lock(&xn->xn_lock);
+ if (ctlq_msg->chnl_opcode != xn->virtchnl_opcode ||
+ msg_cookie != xn->cookie) {
+ spin_unlock(&xn->xn_lock);
+ return false;
+ }
+
+ if (xn->state != LIBIE_CTLQ_XN_ASYNC &&
+ xn->state != LIBIE_CTLQ_XN_WAITING) {
+ spin_unlock(&xn->xn_lock);
+ return false;
+ }
+
+ response = &ctlq_msg->recv_mem;
+ if (xn->state == LIBIE_CTLQ_XN_ASYNC) {
+ xn->resp_cb(xn->send_ctx, response, status);
+ libie_ctlq_release_rx_buf(response);
+ xn->state = LIBIE_CTLQ_XN_IDLE;
+ spin_unlock(&xn->xn_lock);
+ libie_ctlq_xn_push_free(xnm, xn);
+
+ return true;
+ }
+
+ xn->recv_mem = *response;
+ xn->state = status ? LIBIE_CTLQ_XN_COMPLETED_FAILED :
+ LIBIE_CTLQ_XN_COMPLETED_SUCCESS;
+
+ complete(&xn->cmd_completion_event);
+ spin_unlock(&xn->xn_lock);
+
+ return true;
+}
+
+/**
+ * libie_xn_check_async_timeout - Check for asynchronous message timeouts
+ * @xnm: Xn transaction manager
+ *
+ * Call the corresponding callback to notify the caller about the timeout.
+ * Iterates free_xns_bm locklessly, potential races are caught under
+ * xn->xn_lock.
+ */
+static void libie_xn_check_async_timeout(struct libie_ctlq_xn_manager *xnm)
+{
+ u32 idx;
+
+ for_each_clear_bit(idx, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
+ struct libie_ctlq_xn *xn = &xnm->ring[idx];
+ u64 timeout_ms;
+
+ spin_lock(&xn->xn_lock);
+
+ timeout_ms = ktime_ms_delta(ktime_get(), xn->timestamp);
+ if (xn->state != LIBIE_CTLQ_XN_ASYNC ||
+ timeout_ms < xn->timeout_ms) {
+ spin_unlock(&xn->xn_lock);
+ continue;
+ }
+
+ xn->resp_cb(xn->send_ctx, NULL, -ETIMEDOUT);
+ xn->state = LIBIE_CTLQ_XN_IDLE;
+ spin_unlock(&xn->xn_lock);
+ libie_ctlq_xn_push_free(xnm, xn);
+ }
+}
+
+/**
+ * libie_ctlq_xn_recv - process control queue receive message
+ * @params: Xn receive param information to handle a receive message
+ *
+ * Process a receive message and update the receive queue buffer.
+ * Also terminates async transactions for which it failed to receive a response
+ * within a given timeframe.
+ * Function is intended to be called periodically from a single task.
+ *
+ * Return: remaining budget.
+ */
+u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params)
+{
+ struct libie_ctlq_msg ctlq_msg;
+ u32 budget = params->budget;
+
+ while (budget && libie_ctlq_recv(params->ctlq, &ctlq_msg, 1)) {
+ budget--;
+ if (!libie_ctlq_xn_process_recv(params, &ctlq_msg))
+ params->ctlq_msg_handler(params->xnm->ctx, &ctlq_msg);
+ }
+
+ libie_ctlq_post_rx_buffs(params->ctlq);
+ libie_xn_check_async_timeout(params->xnm);
+
+ return budget;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_recv, "LIBIE_CP");
+
+/**
+ * libie_cp_map_dma_mem - map a given virtual address for DMA
+ * @dev: device information
+ * @va: virtual address to be mapped
+ * @size: size of the memory
+ * @direction: DMA direction either from/to device
+ * @dma_mem: memory for DMA information to be stored
+ *
+ * Return: true on success, false on DMA map failure.
+ */
+static bool libie_cp_map_dma_mem(struct device *dev, void *va, size_t size,
+ int direction,
+ struct libie_cp_dma_mem *dma_mem)
+{
+ dma_mem->pa = dma_map_single(dev, va, size, direction);
+
+ return dma_mapping_error(dev, dma_mem->pa) ? false : true;
+}
+
+/**
+ * libie_cp_unmap_dma_mem - unmap previously mapped DMA address
+ * @dev: device information
+ * @dma_mem: DMA memory information
+ */
+static void libie_cp_unmap_dma_mem(struct device *dev,
+ const struct libie_cp_dma_mem *dma_mem)
+{
+ dma_unmap_single(dev, dma_mem->pa, dma_mem->size,
+ dma_mem->direction);
+}
+
+/**
+ * libie_ctlq_xn_process_send - process and send a control queue message
+ * @params: Xn send param information for sending a control queue message
+ * @xn: Assigned Xn entry for tracking the control queue message
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+static
+int libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params *params,
+ struct libie_ctlq_xn *xn)
+{
+ size_t buf_len = params->send_buf.iov_len;
+ struct device *dev = params->ctlq->dev;
+ void *buf = params->send_buf.iov_base;
+ struct libie_cp_dma_mem *dma_mem;
+ u16 cookie;
+
+ if (!buf || !buf_len)
+ return -EOPNOTSUPP;
+
+ if (libie_cp_can_send_onstack(buf_len)) {
+ dma_mem = &xn->small_dma_mem;
+ memcpy(dma_mem->va, buf, buf_len);
+ } else {
+ dma_mem = &xn->send_dma_mem;
+ dma_mem->va = buf;
+ dma_mem->size = buf_len;
+ dma_mem->direction = DMA_TO_DEVICE;
+
+ if (!libie_cp_map_dma_mem(dev, buf, buf_len, DMA_TO_DEVICE,
+ dma_mem))
+ return -ENOMEM;
+ }
+
+ cookie = FIELD_PREP(LIBIE_CTLQ_XN_COOKIE_M, xn->cookie) |
+ FIELD_PREP(LIBIE_CTLQ_XN_INDEX_M, xn->index);
+
+ scoped_guard(spinlock, &params->ctlq->lock) {
+ struct libie_ctlq_info *ctlq = params->ctlq;
+ struct libie_ctlq_msg *ctlq_msg;
+
+ if (!libie_ctlq_send_desc_avail(ctlq)) {
+ if (!libie_cp_can_send_onstack(buf_len))
+ libie_cp_unmap_dma_mem(dev, dma_mem);
+
+ return -EBUSY;
+ }
+
+ ctlq_msg = ctlq->tx_msg[ctlq->next_to_use];
+ xn->tx_msg = dma_mem == &xn->small_dma_mem ? ctlq_msg : NULL;
+ if (params->ctlq_msg)
+ *ctlq_msg = *params->ctlq_msg;
+ else
+ /* Unused ctlq messages are already zeroed */
+ ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_CP;
+
+ ctlq_msg->sw_cookie = cookie;
+ ctlq_msg->send_mem = *dma_mem;
+ ctlq_msg->data_len = buf_len;
+ ctlq_msg->chnl_opcode = params->chnl_opcode;
+ libie_ctlq_send(params->ctlq, 1);
+ }
+
+ return 0;
+}
+
+/**
+ * libie_ctlq_xn_send - send a control queue message, initiating a transaction
+ * @params: Xn send param information for sending a control queue message
+ *
+ * Send a control queue (mailbox or config) message.
+ * Based on the params value, the call can be completed synchronously or
+ * asynchronously.
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params)
+{
+ bool free_send = !libie_cp_can_send_onstack(params->send_buf.iov_len);
+ struct libie_ctlq_xn *xn;
+ int ret;
+
+ if (params->send_buf.iov_len > LIBIE_CTLQ_MAX_BUF_LEN) {
+ ret = -EINVAL;
+ goto free_buf;
+ }
+
+ xn = libie_ctlq_xn_pop_free(params->xnm);
+ /* no free transactions available */
+ if (unlikely(!xn)) {
+ ret = -EAGAIN;
+ goto free_buf;
+ }
+
+ spin_lock(&xn->xn_lock);
+ if (xn->state == LIBIE_CTLQ_XN_SHUTDOWN) {
+ ret = -ENXIO;
+ goto unlock_xn;
+ }
+
+ xn->state = params->resp_cb ? LIBIE_CTLQ_XN_ASYNC :
+ LIBIE_CTLQ_XN_WAITING;
+ xn->virtchnl_opcode = params->chnl_opcode;
+
+ if (params->resp_cb) {
+ xn->send_ctx = params->send_ctx;
+ xn->resp_cb = params->resp_cb;
+ xn->timeout_ms = params->timeout_ms;
+ xn->timestamp = ktime_get();
+ }
+
+ ret = libie_ctlq_xn_process_send(params, xn);
+ if (ret)
+ goto release_xn;
+ else
+ free_send = false;
+
+ spin_unlock(&xn->xn_lock);
+
+ if (params->resp_cb)
+ return 0;
+
+ wait_for_completion_timeout(&xn->cmd_completion_event,
+ msecs_to_jiffies(params->timeout_ms));
+
+ spin_lock(&xn->xn_lock);
+ switch (xn->state) {
+ case LIBIE_CTLQ_XN_WAITING:
+ ret = -ETIMEDOUT;
+ break;
+ case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
+ params->recv_mem = xn->recv_mem;
+ break;
+ default:
+ ret = -EBADMSG;
+ break;
+ }
+
+ /* Free the receive buffer in case of failure. On timeout, receive
+ * buffer is not allocated.
+ */
+ if (ret && ret != -ETIMEDOUT)
+ libie_ctlq_release_rx_buf(&xn->recv_mem);
+
+release_xn:
+ xn->state = LIBIE_CTLQ_XN_IDLE;
+ reinit_completion(&xn->cmd_completion_event);
+unlock_xn:
+ spin_unlock(&xn->xn_lock);
+ libie_ctlq_xn_push_free(params->xnm, xn);
+free_buf:
+ if (free_send)
+ params->rel_tx_buf(params->send_buf.iov_base);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send, "LIBIE_CP");
+
+/**
+ * struct libie_ctlq_xn_rel_tx_ctx - context needed to release xn Tx message
+ * @dev: device for which DMA was mapped
+ * @rel_tx_buf: freeing function for non-small buffers
+ */
+struct libie_ctlq_xn_rel_tx_ctx {
+ struct device *dev;
+ void (*rel_tx_buf)(const void *buf_va);
+};
+
+/**
+ * libie_ctlq_xn_rel_tx_buf - release xn-controlled Tx message buffer
+ * @ctx: context, namely DMA device and freeing function
+ * @dma_mem: DMA memory to reclaim/unmap
+ */
+static void libie_ctlq_xn_rel_tx_buf(const void *ctx,
+ struct libie_cp_dma_mem *dma_mem)
+{
+ const struct libie_ctlq_xn_rel_tx_ctx *rel_ctx = ctx;
+
+ if (!libie_cp_can_send_onstack(dma_mem->size)) {
+ libie_cp_unmap_dma_mem(rel_ctx->dev, dma_mem);
+ rel_ctx->rel_tx_buf(dma_mem->va);
+ }
+}
+
+/**
+ * libie_ctlq_xn_send_clean - clean xn-controlled Tx messages
+ * @ctlq: control queue to clean
+ * @rel_tx_buf: driver callback to free the buffer
+ * @force: clean regardless of DD
+ *
+ * Return: number of completed/released messages.
+ */
+u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,
+ void (*rel_tx_buf)(const void *buf_va),
+ bool force)
+{
+ struct libie_ctlq_xn_rel_tx_ctx rel_ctx = {
+ .dev = ctlq->dev,
+ .rel_tx_buf = rel_tx_buf,
+ };
+ struct libie_ctlq_clean_params params = {
+ .ctlq = ctlq,
+ .force = force,
+ .num_msgs = ctlq->ring_len,
+ .rel_ctx = &rel_ctx,
+ .rel_dma_mem = libie_ctlq_xn_rel_tx_buf,
+ };
+
+ return libie_ctlq_send_clean(&params);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send_clean, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_shutdown - terminate control queue transactions
+ * @xnm: pointer to the transaction manager
+ *
+ * Synchronously terminate existing transactions and stop accepting new ones.
+ * Async transactions are discarded without invoking resp_cb.
+ */
+void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm)
+{
+ bool must_wait = false;
+ u32 i;
+
+ /* Should be no new clear bits after this */
+ spin_lock(&xnm->free_xns_bm_lock);
+ xnm->shutdown = true;
+
+ for_each_clear_bit(i, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
+ struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+ spin_lock(&xn->xn_lock);
+
+ switch (xn->state) {
+ /* if an idle xn is not free, it is about to be either
+ * freed or initialized, prevent the latter and wait
+ */
+ case LIBIE_CTLQ_XN_IDLE:
+ xn->state = LIBIE_CTLQ_XN_SHUTDOWN;
+ fallthrough;
+ /* waiting thread possibly needs a push to return the xn,
+ * transaction will be reported as timed out
+ */
+ case LIBIE_CTLQ_XN_WAITING:
+ complete(&xn->cmd_completion_event);
+ fallthrough;
+ /* these states will return the xn soon */
+ case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
+ case LIBIE_CTLQ_XN_COMPLETED_FAILED:
+ case LIBIE_CTLQ_XN_SHUTDOWN:
+ must_wait = true;
+ break;
+ /* no thread should reference async xns at this point */
+ case LIBIE_CTLQ_XN_ASYNC:
+ xn->state = LIBIE_CTLQ_XN_IDLE;
+ __libie_ctlq_xn_push_free(xnm, xn);
+ break;
+ }
+
+ spin_unlock(&xn->xn_lock);
+ }
+
+ spin_unlock(&xnm->free_xns_bm_lock);
+
+ if (must_wait)
+ wait_for_completion(&xnm->can_destroy);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_shutdown, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
+ * @xnm: pointer to the transaction manager
+ * @ctx: libie CP context information
+ *
+ * Rx processing must be stopped beforehand via cancelling tasks.
+ * Tx processing must be stopped beforehand via libie_ctlq_xn_shutdown(),
+ * all buffers must be force-cleaned from the send queue.
+ */
+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
+ struct libie_ctlq_ctx *ctx)
+{
+ libie_ctlq_xn_deinit_dma(xnm, LIBIE_CTLQ_MAX_XN_ENTRIES);
+ kvfree(xnm);
+ libie_ctlq_deinit(ctx);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_init - initialize the Xn transaction manager
+ * @params: Xn init param information for allocating Xn manager resources
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params)
+{
+ struct libie_ctlq_xn_manager *xnm;
+ int ret;
+
+ ret = libie_ctlq_init(params->ctx, params->cctlq_info, params->num_qs);
+ if (ret)
+ return ret;
+
+ xnm = kvzalloc_obj(*xnm);
+ if (!xnm)
+ goto ctlq_deinit;
+
+ ret = libie_ctlq_xn_init_dma(&params->ctx->mmio_info.pdev->dev, xnm);
+ if (ret)
+ goto free_xnm;
+
+ spin_lock_init(&xnm->free_xns_bm_lock);
+ init_completion(&xnm->can_destroy);
+ bitmap_fill(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);
+
+ for (u32 i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
+ struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+ xn->index = i;
+ init_completion(&xn->cmd_completion_event);
+ spin_lock_init(&xn->xn_lock);
+ }
+ xnm->ctx = params->ctx;
+ params->xnm = xnm;
+
+ return 0;
+
+free_xnm:
+ kvfree(xnm);
+ctlq_deinit:
+ libie_ctlq_deinit(params->ctx);
+
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_init, "LIBIE_CP");
+
+MODULE_DESCRIPTION("Control Plane communication API");
+MODULE_IMPORT_NS("LIBETH");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/intel/libie/fwlog.c b/drivers/net/ethernet/intel/libie/fwlog.c
index f39cc11cb7c5..96bba57c8a5b 100644
--- a/drivers/net/ethernet/intel/libie/fwlog.c
+++ b/drivers/net/ethernet/intel/libie/fwlog.c
@@ -153,7 +153,7 @@ static void libie_fwlog_realloc_rings(struct libie_fwlog *fwlog, int index)
* old rings and buffers. that way if we don't have enough
* memory then we at least have what we had before
*/
- ring.rings = kcalloc(ring_size, sizeof(*ring.rings), GFP_KERNEL);
+ ring.rings = kzalloc_objs(*ring.rings, ring_size);
if (!ring.rings)
return;
@@ -208,7 +208,7 @@ libie_aq_fwlog_set(struct libie_fwlog *fwlog,
int status;
int i;
- fw_modules = kcalloc(num_entries, sizeof(*fw_modules), GFP_KERNEL);
+ fw_modules = kzalloc_objs(*fw_modules, num_entries);
if (!fw_modules)
return -ENOMEM;
@@ -433,17 +433,21 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
if (module < 0) {
dev_info(dev, "unknown module\n");
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
cnt = sscanf(cmd_buf, "%s", user_val);
- if (cnt != 1)
- return -EINVAL;
+ if (cnt != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
if (log_level < 0) {
dev_info(dev, "unknown log level '%s'\n", user_val);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
@@ -458,6 +462,9 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
fwlog->cfg.module_entries[i].log_level = log_level;
}
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtos16(user_val, 0, &nr_messages);
- if (ret)
- return ret;
+ if (ret) {
+ count = ret;
+ goto free_cmd_buf;
+ }
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
fwlog->cfg.log_resolution = nr_messages;
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtobool(user_val, &enable);
if (ret)
@@ -624,6 +641,8 @@ enable_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
index = sysfs_match_string(libie_fwlog_log_size, user_val);
if (index < 0) {
@@ -712,6 +733,8 @@ log_size_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
@@ -838,8 +861,7 @@ static void libie_debugfs_fwlog_init(struct libie_fwlog *fwlog,
/* allocate space for this first because if it fails then we don't
* need to unwind
*/
- fw_modules = kcalloc(LIBIE_NR_FW_LOG_MODULES, sizeof(*fw_modules),
- GFP_KERNEL);
+ fw_modules = kzalloc_objs(*fw_modules, LIBIE_NR_FW_LOG_MODULES);
if (!fw_modules)
return;
@@ -978,7 +1000,7 @@ static void libie_fwlog_set_supported(struct libie_fwlog *fwlog)
fwlog->supported = false;
- cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ cfg = kzalloc_obj(*cfg);
if (!cfg)
return;
@@ -1013,9 +1035,8 @@ int libie_fwlog_init(struct libie_fwlog *fwlog, struct libie_fwlog_api *api)
if (status)
return status;
- fwlog->ring.rings = kcalloc(LIBIE_FWLOG_RING_SIZE_DFLT,
- sizeof(*fwlog->ring.rings),
- GFP_KERNEL);
+ fwlog->ring.rings = kzalloc_objs(*fwlog->ring.rings,
+ LIBIE_FWLOG_RING_SIZE_DFLT);
if (!fwlog->ring.rings) {
dev_warn(&fwlog->pdev->dev, "Unable to allocate memory for FW log rings\n");
return -ENOMEM;
@@ -1051,6 +1072,10 @@ void libie_fwlog_deinit(struct libie_fwlog *fwlog)
{
int status;
+ /* if FW logging isn't supported it means no configuration was done */
+ if (!libie_fwlog_supported(fwlog))
+ return;
+
/* make sure FW logging is disabled to not put the FW in a weird state
* for the next driver load
*/
diff --git a/drivers/net/ethernet/intel/libie/pci.c b/drivers/net/ethernet/intel/libie/pci.c
new file mode 100644
index 000000000000..b756c1186ce9
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/pci.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/net/intel/libie/pci.h>
+
+/**
+ * libie_find_mmio_region - find MMIO region containing a range
+ * @mmio_list: list that contains MMIO region info
+ * @offset: range start offset
+ * @size: range size
+ * @bar_idx: BAR index containing the range to search
+ *
+ * MMIO regions mappings are traversed from oldest to newest.
+ *
+ * Return: pointer to a MMIO region overlapping with the range in any way or
+ * NULL if no such region is mapped.
+ */
+static struct libie_pci_mmio_region *
+libie_find_mmio_region(const struct list_head *mmio_list,
+ resource_size_t offset, resource_size_t size,
+ int bar_idx)
+{
+ resource_size_t end_offset = offset + size;
+ struct libie_pci_mmio_region *mr;
+
+ list_for_each_entry(mr, mmio_list, list) {
+ resource_size_t mr_end = mr->offset + mr->size;
+ resource_size_t mr_start = mr->offset;
+
+ if (mr->bar_idx != bar_idx)
+ continue;
+ if (offset < mr_end && end_offset > mr_start)
+ return mr;
+ }
+
+ return NULL;
+}
+
+/**
+ * __libie_pci_get_mmio_addr - get the MMIO virtual address
+ * @mmio_info: contains list of MMIO regions
+ * @offset: register offset to find
+ * @num_args: number of additional arguments present
+ * @...: optional BAR index (0 by default)
+ *
+ * This function finds the virtual address of a register offset by iterating
+ * through the non-linear MMIO regions that are mapped by the driver.
+ *
+ * The list is traversed oldest to newest, so accessing an older mapping
+ * via this function while deleting a newer one is allowed.
+ *
+ * Return: valid MMIO virtual address or NULL.
+ */
+void __iomem *__libie_pci_get_mmio_addr(struct libie_mmio_info *mmio_info,
+ resource_size_t offset,
+ int num_args, ...)
+{
+ struct libie_pci_mmio_region *mr;
+ int bar_idx = 0;
+ va_list args;
+
+ if (num_args) {
+ va_start(args, num_args);
+ bar_idx = va_arg(args, int);
+ va_end(args);
+ }
+
+ list_for_each_entry(mr, &mmio_info->mmio_list, list)
+ if (bar_idx == mr->bar_idx && offset >= mr->offset &&
+ offset < mr->offset + mr->size) {
+ offset -= mr->offset;
+
+ return mr->addr + offset;
+ }
+
+ WARN_ONCE(true, "Access to an unmapped MMIO region (BAR%d, offset %pa)",
+ bar_idx, &offset);
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(__libie_pci_get_mmio_addr, "LIBIE_PCI");
+
+/**
+ * __libie_pci_map_mmio_region - map PCI device MMIO region
+ * @mmio_info: struct to store the mapped MMIO region
+ * @offset: MMIO region start offset
+ * @size: MMIO region size
+ * @num_args: number of additional arguments present
+ * @...: optional BAR index (0 by default)
+ *
+ * Return: true if the requested address range is accessible through
+ * new or existing mapping, false otherwise.
+ */
+bool __libie_pci_map_mmio_region(struct libie_mmio_info *mmio_info,
+ resource_size_t offset,
+ resource_size_t size, int num_args, ...)
+{
+ struct pci_dev *pdev = mmio_info->pdev;
+ struct libie_pci_mmio_region *mr;
+ resource_size_t end_offset;
+ void __iomem *va;
+ int bar_idx = 0;
+ va_list args;
+
+ if (num_args) {
+ va_start(args, num_args);
+ bar_idx = va_arg(args, int);
+ va_end(args);
+ }
+
+ if (bar_idx >= PCI_STD_NUM_BARS || bar_idx < 0 ||
+ !pci_resource_is_mem(pdev, bar_idx))
+ return false;
+
+ /* pci_iomap_range() silently maps less
+ * if the requested length is too big
+ */
+ if (!size || check_add_overflow(offset, size, &end_offset) ||
+ end_offset > pci_resource_len(pdev, bar_idx))
+ return false;
+
+ mr = libie_find_mmio_region(&mmio_info->mmio_list, offset, size,
+ bar_idx);
+ if (mr) {
+ pci_warn(pdev,
+ "Mapping of BAR%u (offset=%llu, size=%llu) intersecting region (offset=%llu, size=%llu) already exists\n",
+ bar_idx, (unsigned long long)mr->offset,
+ (unsigned long long)mr->size,
+ (unsigned long long)offset, (unsigned long long)size);
+ return mr->offset <= offset &&
+ mr->offset + mr->size >= end_offset;
+ }
+
+ va = pci_iomap_range(mmio_info->pdev, bar_idx, offset, size);
+ if (!va) {
+ pci_err(pdev, "Failed to map BAR%u region\n", bar_idx);
+ return false;
+ }
+
+ mr = kvzalloc_obj(*mr);
+ if (!mr) {
+ pci_iounmap(pdev, va);
+ return false;
+ }
+
+ mr->addr = va;
+ mr->offset = offset;
+ mr->size = size;
+ mr->bar_idx = bar_idx;
+
+ list_add_tail(&mr->list, &mmio_info->mmio_list);
+
+ return true;
+}
+EXPORT_SYMBOL_NS_GPL(__libie_pci_map_mmio_region, "LIBIE_PCI");
+
+/**
+ * libie_pci_unmap_fltr_regs - unmap selected PCI device MMIO regions
+ * @mmio_info: contains list of MMIO regions to unmap
+ * @fltr: returns true, if region is to be unmapped
+ */
+void libie_pci_unmap_fltr_regs(struct libie_mmio_info *mmio_info,
+ bool (*fltr)(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg))
+{
+ struct libie_pci_mmio_region *mr, *tmp;
+
+ list_for_each_entry_safe(mr, tmp, &mmio_info->mmio_list, list) {
+ if (!fltr(mmio_info, mr))
+ continue;
+ list_del(&mr->list);
+ pci_iounmap(mmio_info->pdev, mr->addr);
+ kvfree(mr);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_fltr_regs, "LIBIE_PCI");
+
+/**
+ * libie_pci_unmap_all_mmio_regions - unmap all PCI device MMIO regions
+ * @mmio_info: contains list of MMIO regions to unmap
+ */
+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info)
+{
+ struct libie_pci_mmio_region *mr, *tmp;
+
+ list_for_each_entry_safe(mr, tmp, &mmio_info->mmio_list, list) {
+ list_del(&mr->list);
+ pci_iounmap(mmio_info->pdev, mr->addr);
+ kvfree(mr);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_all_mmio_regions, "LIBIE_PCI");
+
+/**
+ * libie_pci_init_dev - enable and configure the device
+ * @pdev: PCI device information
+ *
+ * Enable the device, request memory regions, set 64-bit DMA mask
+ * and coherent DMA mask, and enable bus-mastering
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_pci_init_dev(struct pci_dev *pdev)
+{
+ int err;
+
+ err = pcim_enable_device(pdev);
+ if (err)
+ return err;
+
+ for (int bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+ err = pcim_request_region(pdev, bar, pci_name(pdev));
+ if (err)
+ return err;
+ }
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_init_dev, "LIBIE_PCI");
+
+MODULE_DESCRIPTION("Common Ethernet PCI library");
+MODULE_LICENSE("GPL");