diff options
Diffstat (limited to 'drivers/net/ethernet/intel')
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, ®); + 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, ®); + 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, ©); + + 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, ©); + + 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(¶ms->atqbal_wq.lock, flags); + spin_lock_irq(¶ms->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(¶ms->atqbal_wq.lock, flags); + spin_unlock_irq(¶ms->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(¶ms->atqbal_wq.lock, flags); + spin_unlock_irq(¶ms->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(¶ms->atqbal_wq.lock, flags); + spin_unlock_irq(¶ms->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(¶ms->atqbal_wq.lock); - return err; - } - spin_unlock_irq(¶ms->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(¶ms->atqbal_wq.lock); - return err; - } - spin_unlock_irq(¶ms->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, ÷r); + 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 = ®_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 = ®_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 = ¶ms->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 = ∩︀ - 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, ¶ms); + return idpf_send_chunked_msg(qs->adapter, ¶ms); } /** * 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, ¶ms); + return idpf_send_chunked_msg(qs->adapter, ¶ms); } /** * 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, ¶ms); + return idpf_send_chunked_msg(qs->adapter, ¶ms); } /** * 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, ¶ms); + return idpf_send_chunked_msg(qs->adapter, ¶ms); } /** * 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 = ∾ - 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(¶ms); 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, ¶ms->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(¶ms); +} +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(¶ms->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"); |
