diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice')
73 files changed, 7056 insertions, 5849 deletions
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 9e0d9f710441..5b2c666496e7 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -42,18 +42,19 @@ ice-y := ice_main.o \ ice_ethtool.o \ ice_repr.o \ ice_tc_lib.o \ - ice_fwlog.o \ ice_debugfs.o \ ice_adapter.o ice-$(CONFIG_PCI_IOV) += \ ice_sriov.o \ - ice_virtchnl.o \ - ice_virtchnl_allowlist.o \ - ice_virtchnl_fdir.o \ + virt/allowlist.o \ + virt/fdir.o \ + virt/queues.o \ + virt/virtchnl.o \ + virt/rss.o \ 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-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o ice_tspll.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 4af60e2f37df..fb2de521731a 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -293,7 +293,7 @@ static int ice_devlink_info_get(struct devlink *devlink, err = ice_discover_dev_caps(hw, &ctx->dev_caps); if (err) { dev_dbg(dev, "Failed to discover device capabilities, status %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Unable to discover device capabilities"); goto out_free_ctx; } @@ -302,7 +302,7 @@ static int ice_devlink_info_get(struct devlink *devlink, err = ice_get_inactive_orom_ver(hw, &ctx->pending_orom); if (err) { dev_dbg(dev, "Unable to read inactive Option ROM version data, status %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); /* disable display of pending Option ROM */ ctx->dev_caps.common_cap.nvm_update_pending_orom = false; @@ -313,7 +313,7 @@ static int ice_devlink_info_get(struct devlink *devlink, err = ice_get_inactive_nvm_ver(hw, &ctx->pending_nvm); if (err) { dev_dbg(dev, "Unable to read inactive NVM version data, status %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); /* disable display of pending Option ROM */ ctx->dev_caps.common_cap.nvm_update_pending_nvm = false; @@ -324,7 +324,7 @@ static int ice_devlink_info_get(struct devlink *devlink, err = ice_get_inactive_netlist_ver(hw, &ctx->pending_netlist); if (err) { dev_dbg(dev, "Unable to read inactive Netlist version data, status %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); /* disable display of pending Option ROM */ ctx->dev_caps.common_cap.nvm_update_pending_netlist = false; @@ -440,7 +440,7 @@ ice_devlink_reload_empr_start(struct ice_pf *pf, err = ice_aq_nvm_update_empr(hw); if (err) { dev_err(dev, "Failed to trigger EMP device reset to reload firmware, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to trigger EMP device reset to reload firmware"); return err; } diff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c index 19c3d37aa768..8e9a8a8178d4 100644 --- a/drivers/net/ethernet/intel/ice/devlink/health.c +++ b/drivers/net/ethernet/intel/ice/devlink/health.c @@ -204,7 +204,7 @@ static void ice_config_health_events(struct ice_pf *pf, bool enable) if (ret) dev_err(ice_pf_to_dev(pf), "Failed to %s firmware health events, err %d aq_err %s\n", str_enable_disable(enable), ret, - ice_aq_str(pf->hw.adminq.sq_last_status)); + libie_aq_str(pf->hw.adminq.sq_last_status)); } /** @@ -217,10 +217,12 @@ static void ice_config_health_events(struct ice_pf *pf, bool enable) void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info *event) { const struct ice_aqc_health_status_elem *health_info; + const struct ice_aqc_get_health_status *cmd; u16 count; health_info = (struct ice_aqc_health_status_elem *)event->msg_buf; - count = le16_to_cpu(event->desc.params.get_health_status.health_status_count); + cmd = libie_aq_raw(&event->desc); + count = le16_to_cpu(cmd->health_status_count); if (count > (event->buf_len / sizeof(*health_info))) { dev_err(ice_pf_to_dev(pf), "Received a health status event with invalid element count\n"); @@ -448,9 +450,8 @@ ice_init_devlink_rep(struct ice_pf *pf, { struct devlink *devlink = priv_to_devlink(pf); struct devlink_health_reporter *rep; - const u64 graceful_period = 0; - rep = devl_health_reporter_create(devlink, ops, graceful_period, pf); + rep = devl_health_reporter_create(devlink, ops, pf); if (IS_ERR(rep)) { struct device *dev = ice_pf_to_dev(pf); diff --git a/drivers/net/ethernet/intel/ice/devlink/port.c b/drivers/net/ethernet/intel/ice/devlink/port.c index 767419a67fef..63fb36fc4b3d 100644 --- a/drivers/net/ethernet/intel/ice/devlink/port.c +++ b/drivers/net/ethernet/intel/ice/devlink/port.c @@ -30,6 +30,8 @@ static const char *ice_devlink_port_opt_speed_str(u8 speed) return "10"; case ICE_AQC_PORT_OPT_MAX_LANE_25G: return "25"; + case ICE_AQC_PORT_OPT_MAX_LANE_40G: + return "40"; case ICE_AQC_PORT_OPT_MAX_LANE_50G: return "50"; case ICE_AQC_PORT_OPT_MAX_LANE_100G: diff --git a/drivers/net/ethernet/intel/ice/devlink/port.h b/drivers/net/ethernet/intel/ice/devlink/port.h index d60efc340945..e89ddd60eeac 100644 --- a/drivers/net/ethernet/intel/ice/devlink/port.h +++ b/drivers/net/ethernet/intel/ice/devlink/port.h @@ -11,7 +11,7 @@ * struct ice_dynamic_port - Track dynamically added devlink port instance * @hw_addr: the HW address for this port * @active: true if the port has been activated - * @attached: true it the prot is attached + * @attached: true if the prot is attached * @devlink_port: the associated devlink port structure * @pf: pointer to the PF private structure * @vsi: the VSI associated with this port diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index ddd0ad68185b..22b8323ff0d0 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -67,6 +67,7 @@ #include "ice_sriov.h" #include "ice_vf_mbx.h" #include "ice_ptp.h" +#include "ice_tspll.h" #include "ice_fdir.h" #include "ice_xsk.h" #include "ice_arfs.h" @@ -83,7 +84,11 @@ #define ICE_BAR0 0 #define ICE_REQ_DESC_MULTIPLE 32 #define ICE_MIN_NUM_DESC 64 -#define ICE_MAX_NUM_DESC 8160 +#define ICE_MAX_NUM_DESC_E810 8160 +#define ICE_MAX_NUM_DESC_E830 8096 +#define ICE_MAX_NUM_DESC_BY_MAC(hw) ((hw)->mac_type == ICE_MAC_E830 ? \ + ICE_MAX_NUM_DESC_E830 : \ + ICE_MAX_NUM_DESC_E810) #define ICE_DFLT_MIN_RX_DESC 512 #define ICE_DFLT_NUM_TX_DESC 256 #define ICE_DFLT_NUM_RX_DESC 2048 @@ -199,9 +204,11 @@ enum ice_feature { ICE_F_SMA_CTRL, ICE_F_CGU, ICE_F_GNSS, + ICE_F_TXTIME, ICE_F_GCS, ICE_F_ROCE_LAG, ICE_F_SRIOV_LAG, + ICE_F_SRIOV_AA_LAG, ICE_F_MBX_LIMIT, ICE_F_MAX }; @@ -509,6 +516,7 @@ enum ice_pf_flags { ICE_FLAG_LINK_LENIENT_MODE_ENA, ICE_FLAG_PLUG_AUX_DEV, ICE_FLAG_UNPLUG_AUX_DEV, + ICE_FLAG_AUX_DEV_CREATED, ICE_FLAG_MTU_CHANGED, ICE_FLAG_GNSS, /* GNSS successfully initialized */ ICE_FLAG_DPLL, /* SyncE/PTP dplls initialized */ @@ -565,9 +573,6 @@ struct ice_pf { struct ice_sw *first_sw; /* first switch created by firmware */ u16 eswitch_mode; /* current mode of eswitch */ struct dentry *ice_debugfs_pf; - struct dentry *ice_debugfs_pf_fwlog; - /* keep track of all the dentrys for FW log modules */ - struct dentry **ice_debugfs_pf_fwlog_modules; struct ice_vfs vfs; DECLARE_BITMAP(features, ICE_F_MAX); DECLARE_BITMAP(state, ICE_STATE_NBITS); @@ -575,6 +580,7 @@ struct ice_pf { DECLARE_BITMAP(misc_thread, ICE_MISC_THREAD_NBITS); unsigned long *avail_txqs; /* bitmap to track PF Tx queue usage */ unsigned long *avail_rxqs; /* bitmap to track PF Rx queue usage */ + unsigned long *txtime_txqs; /* bitmap to track PF Tx Time queue */ unsigned long serv_tmr_period; unsigned long serv_tmr_prev; struct timer_list serv_tmr; @@ -614,6 +620,7 @@ struct ice_pf { u16 globr_count; /* Global reset count */ u16 empr_count; /* EMP reset count */ u16 pfr_count; /* PF reset count */ + u32 link_down_events; u8 wol_ena : 1; /* software state of WoL */ u32 wakeup_reason; /* last wakeup reason */ @@ -748,6 +755,31 @@ static inline void ice_set_ring_xdp(struct ice_tx_ring *ring) } /** + * ice_is_txtime_ena - check if Tx Time is enabled on the Tx ring + * @ring: pointer to Tx ring + * + * Return: true if the Tx ring has Tx Time enabled, false otherwise. + */ +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; + + return test_bit(ring->q_index, pf->txtime_txqs); +} + +/** + * ice_is_txtime_cfg - check if Tx Time is configured on the Tx ring + * @ring: pointer to Tx ring + * + * Return: true if the Tx ring is configured for Tx ring, false otherwise. + */ +static inline bool ice_is_txtime_cfg(const struct ice_tx_ring *ring) +{ + return !!(ring->flags & ICE_TX_FLAGS_TXTIME); +} + +/** * ice_get_xp_from_qid - get ZC XSK buffer pool bound to a queue ID * @vsi: pointer to VSI * @qid: index of a queue to look at XSK buff pool presence @@ -904,11 +936,10 @@ static inline bool ice_is_adq_active(struct ice_pf *pf) return false; } -void ice_debugfs_fwlog_init(struct ice_pf *pf); +int ice_debugfs_pf_init(struct ice_pf *pf); void ice_debugfs_pf_deinit(struct ice_pf *pf); void ice_debugfs_init(void); void ice_debugfs_exit(void); -void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module); bool netif_is_ice(const struct net_device *dev); int ice_vsi_setup_tx_rings(struct ice_vsi *vsi); @@ -958,7 +989,6 @@ int ice_plug_aux_dev(struct ice_pf *pf); void ice_unplug_aux_dev(struct ice_pf *pf); int ice_init_rdma(struct ice_pf *pf); void ice_deinit_rdma(struct ice_pf *pf); -const char *ice_aq_str(enum ice_aq_err aq_err); bool ice_is_wol_supported(struct ice_hw *hw); void ice_fdir_del_all_fltrs(struct ice_vsi *vsi); int diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c index 66e070095d1b..b53561c34708 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.c +++ b/drivers/net/ethernet/intel/ice/ice_adapter.c @@ -13,16 +13,45 @@ static DEFINE_XARRAY(ice_adapters); static DEFINE_MUTEX(ice_adapters_mutex); -static unsigned long ice_adapter_index(u64 dsn) +#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63) + +#define ICE_ADAPTER_INDEX_E825C \ + (ICE_DEV_ID_E825C_BACKPLANE | ICE_ADAPTER_FIXED_INDEX) + +static u64 ice_adapter_index(struct pci_dev *pdev) { + switch (pdev->device) { + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + /* E825C devices have multiple NACs which are connected to the + * same clock source, and which must share the same + * ice_adapter structure. We can't use the serial number since + * each NAC has its own NVM generated with its own unique + * Device Serial Number. Instead, rely on the embedded nature + * of the E825C devices, and use a fixed index. This relies on + * the fact that all E825C physical functions in a given + * system are part of the same overall device. + */ + return ICE_ADAPTER_INDEX_E825C; + default: + return pci_get_dsn(pdev) & ~ICE_ADAPTER_FIXED_INDEX; + } +} + +static unsigned long ice_adapter_xa_index(struct pci_dev *pdev) +{ + u64 index = ice_adapter_index(pdev); + #if BITS_PER_LONG == 64 - return dsn; + return index; #else - return (u32)dsn ^ (u32)(dsn >> 32); + return (u32)index ^ (u32)(index >> 32); #endif } -static struct ice_adapter *ice_adapter_new(u64 dsn) +static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev) { struct ice_adapter *adapter; @@ -30,8 +59,9 @@ static struct ice_adapter *ice_adapter_new(u64 dsn) if (!adapter) return NULL; - adapter->device_serial_number = dsn; + adapter->index = ice_adapter_index(pdev); spin_lock_init(&adapter->ptp_gltsyn_time_lock); + spin_lock_init(&adapter->txq_ctx_lock); refcount_set(&adapter->refcount, 1); mutex_init(&adapter->ports.lock); @@ -63,24 +93,23 @@ static void ice_adapter_free(struct ice_adapter *adapter) */ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) { - u64 dsn = pci_get_dsn(pdev); struct ice_adapter *adapter; unsigned long index; int err; - index = ice_adapter_index(dsn); + index = ice_adapter_xa_index(pdev); scoped_guard(mutex, &ice_adapters_mutex) { err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL); if (err == -EBUSY) { adapter = xa_load(&ice_adapters, index); refcount_inc(&adapter->refcount); - WARN_ON_ONCE(adapter->device_serial_number != dsn); + WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev)); return adapter; } if (err) return ERR_PTR(err); - adapter = ice_adapter_new(dsn); + adapter = ice_adapter_new(pdev); if (!adapter) return ERR_PTR(-ENOMEM); xa_store(&ice_adapters, index, adapter, GFP_KERNEL); @@ -99,11 +128,10 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) */ void ice_adapter_put(struct pci_dev *pdev) { - u64 dsn = pci_get_dsn(pdev); struct ice_adapter *adapter; unsigned long index; - index = ice_adapter_index(dsn); + index = ice_adapter_xa_index(pdev); scoped_guard(mutex, &ice_adapters_mutex) { adapter = xa_load(&ice_adapters, index); if (WARN_ON(!adapter)) diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h index ac15c0d2bc1a..e95266c7f20b 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.h +++ b/drivers/net/ethernet/intel/ice/ice_adapter.h @@ -27,21 +27,24 @@ struct ice_port_list { /** * struct ice_adapter - PCI adapter resources shared across PFs + * @refcount: Reference count. struct ice_pf objects hold the references. * @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME * register of the PTP clock. - * @refcount: Reference count. struct ice_pf objects hold the references. + * @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register * @ctrl_pf: Control PF of the adapter * @ports: Ports list - * @device_serial_number: DSN cached for collision detection on 32bit systems + * @index: 64-bit index cached for collision detection on 32bit systems */ struct ice_adapter { refcount_t refcount; /* For access to the GLTSYN_TIME register */ spinlock_t ptp_gltsyn_time_lock; + /* For access to GLCOMM_QTX_CNTX_CTL register */ + spinlock_t txq_ctx_lock; struct ice_pf *ctrl_pf; struct ice_port_list ports; - u64 device_serial_number; + u64 index; }; struct ice_adapter *ice_adapter_get(struct pci_dev *pdev); diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index bdee499f991a..859e9c66f3e7 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -4,6 +4,8 @@ #ifndef _ICE_ADMINQ_CMD_H_ #define _ICE_ADMINQ_CMD_H_ +#include <linux/net/intel/libie/adminq.h> + /* This header file defines the Admin Queue commands, error codes and * descriptor format. It is shared between Firmware and Software. */ @@ -14,42 +16,26 @@ #define ICE_RXQ_CTX_SIZE_DWORDS 8 #define ICE_RXQ_CTX_SZ (ICE_RXQ_CTX_SIZE_DWORDS * sizeof(u32)) -#define ICE_TXQ_CTX_SZ 22 typedef struct __packed { u8 buf[ICE_RXQ_CTX_SZ]; } ice_rxq_ctx_buf_t; + +/* The Tx queue context is 40 bytes, and includes some internal state. The + * Admin Queue buffers don't include the internal state, so only include the + * first 22 bytes of the context. + */ +#define ICE_TXQ_CTX_SZ 22 + typedef struct __packed { u8 buf[ICE_TXQ_CTX_SZ]; } ice_txq_ctx_buf_t; -struct ice_aqc_generic { - __le32 param0; - __le32 param1; - __le32 addr_high; - __le32 addr_low; -}; +#define ICE_TXQ_CTX_FULL_SIZE_DWORDS 10 +#define ICE_TXQ_CTX_FULL_SZ \ + (ICE_TXQ_CTX_FULL_SIZE_DWORDS * sizeof(u32)) -/* Get version (direct 0x0001) */ -struct ice_aqc_get_ver { - __le32 rom_ver; - __le32 fw_build; - u8 fw_branch; - u8 fw_major; - u8 fw_minor; - u8 fw_patch; - u8 api_branch; - u8 api_major; - u8 api_minor; - u8 api_patch; -}; - -/* Send driver version (indirect 0x0002) */ -struct ice_aqc_driver_ver { - u8 major_ver; - u8 minor_ver; - u8 build_ver; - u8 subbuild_ver; - u8 reserved[4]; - __le32 addr_high; - __le32 addr_low; -}; +typedef struct __packed { u8 buf[ICE_TXQ_CTX_FULL_SZ]; } ice_txq_ctx_buf_full_t; + +#define ICE_TXTIME_CTX_SZ 25 + +typedef struct __packed { u8 buf[ICE_TXTIME_CTX_SZ]; } ice_txtime_ctx_buf_t; /* Queue Shutdown (direct 0x0003) */ struct ice_aqc_q_shutdown { @@ -58,94 +44,6 @@ struct ice_aqc_q_shutdown { u8 reserved[15]; }; -/* Request resource ownership (direct 0x0008) - * Release resource ownership (direct 0x0009) - */ -struct ice_aqc_req_res { - __le16 res_id; -#define ICE_AQC_RES_ID_NVM 1 -#define ICE_AQC_RES_ID_SDP 2 -#define ICE_AQC_RES_ID_CHNG_LOCK 3 -#define ICE_AQC_RES_ID_GLBL_LOCK 4 - __le16 access_type; -#define ICE_AQC_RES_ACCESS_READ 1 -#define ICE_AQC_RES_ACCESS_WRITE 2 - - /* Upon successful completion, FW writes this value and driver is - * expected to release resource before timeout. This value is provided - * in milliseconds. - */ - __le32 timeout; -#define ICE_AQ_RES_NVM_READ_DFLT_TIMEOUT_MS 3000 -#define ICE_AQ_RES_NVM_WRITE_DFLT_TIMEOUT_MS 180000 -#define ICE_AQ_RES_CHNG_LOCK_DFLT_TIMEOUT_MS 1000 -#define ICE_AQ_RES_GLBL_LOCK_DFLT_TIMEOUT_MS 3000 - /* For SDP: pin ID of the SDP */ - __le32 res_number; - /* Status is only used for ICE_AQC_RES_ID_GLBL_LOCK */ - __le16 status; -#define ICE_AQ_RES_GLBL_SUCCESS 0 -#define ICE_AQ_RES_GLBL_IN_PROG 1 -#define ICE_AQ_RES_GLBL_DONE 2 - u8 reserved[2]; -}; - -/* Get function capabilities (indirect 0x000A) - * Get device capabilities (indirect 0x000B) - */ -struct ice_aqc_list_caps { - u8 cmd_flags; - u8 pf_index; - u8 reserved[2]; - __le32 count; - __le32 addr_high; - __le32 addr_low; -}; - -/* Device/Function buffer entry, repeated per reported capability */ -struct ice_aqc_list_caps_elem { - __le16 cap; -#define ICE_AQC_CAPS_VALID_FUNCTIONS 0x0005 -#define ICE_AQC_CAPS_SRIOV 0x0012 -#define ICE_AQC_CAPS_VF 0x0013 -#define ICE_AQC_CAPS_VSI 0x0017 -#define ICE_AQC_CAPS_DCB 0x0018 -#define ICE_AQC_CAPS_RSS 0x0040 -#define ICE_AQC_CAPS_RXQS 0x0041 -#define ICE_AQC_CAPS_TXQS 0x0042 -#define ICE_AQC_CAPS_MSIX 0x0043 -#define ICE_AQC_CAPS_FD 0x0045 -#define ICE_AQC_CAPS_1588 0x0046 -#define ICE_AQC_CAPS_MAX_MTU 0x0047 -#define ICE_AQC_CAPS_NVM_VER 0x0048 -#define ICE_AQC_CAPS_PENDING_NVM_VER 0x0049 -#define ICE_AQC_CAPS_OROM_VER 0x004A -#define ICE_AQC_CAPS_PENDING_OROM_VER 0x004B -#define ICE_AQC_CAPS_NET_VER 0x004C -#define ICE_AQC_CAPS_PENDING_NET_VER 0x004D -#define ICE_AQC_CAPS_RDMA 0x0051 -#define ICE_AQC_CAPS_SENSOR_READING 0x0067 -#define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076 -#define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077 -#define ICE_AQC_CAPS_NVM_MGMT 0x0080 -#define ICE_AQC_CAPS_TX_SCHED_TOPO_COMP_MODE 0x0085 -#define ICE_AQC_CAPS_NAC_TOPOLOGY 0x0087 -#define ICE_AQC_CAPS_FW_LAG_SUPPORT 0x0092 -#define ICE_AQC_BIT_ROCEV2_LAG 0x01 -#define ICE_AQC_BIT_SRIOV_LAG 0x02 - - u8 major_ver; - u8 minor_ver; - /* Number of resources described by this capability */ - __le32 number; - /* Only meaningful for some types of resources */ - __le32 logical_id; - /* Only meaningful for some types of resources */ - __le32 phys_id; - __le64 rsvd1; - __le64 rsvd2; -}; - /* Manage MAC address, read command - indirect (0x0107) * This struct is also used for the response */ @@ -1672,6 +1570,7 @@ struct ice_aqc_get_port_options_elem { #define ICE_AQC_PORT_OPT_MAX_LANE_50G 6 #define ICE_AQC_PORT_OPT_MAX_LANE_100G 7 #define ICE_AQC_PORT_OPT_MAX_LANE_200G 8 +#define ICE_AQC_PORT_OPT_MAX_LANE_40G 9 u8 global_scid[2]; u8 phy_scid[2]; @@ -2165,6 +2064,10 @@ struct ice_aqc_cfg_txqs { #define ICE_AQC_Q_CFG_SRC_PRT_M 0x7 #define ICE_AQC_Q_CFG_DST_PRT_S 3 #define ICE_AQC_Q_CFG_DST_PRT_M (0x7 << ICE_AQC_Q_CFG_DST_PRT_S) +#define ICE_AQC_Q_CFG_MODE_M GENMASK(7, 6) +#define ICE_AQC_Q_CFG_MODE_SAME_PF 0x0 +#define ICE_AQC_Q_CFG_MODE_GIVE_OWN 0x1 +#define ICE_AQC_Q_CFG_MODE_KEEP_OWN 0x2 u8 time_out; #define ICE_AQC_Q_CFG_TIMEOUT_S 2 #define ICE_AQC_Q_CFG_TIMEOUT_M (0x1F << ICE_AQC_Q_CFG_TIMEOUT_S) @@ -2218,6 +2121,34 @@ struct ice_aqc_add_rdma_qset_data { struct ice_aqc_add_tx_rdma_qset_entry rdma_qsets[]; }; +/* Set Tx Time LAN Queue (indirect 0x0C35) */ +struct ice_aqc_set_txtimeqs { + __le16 q_id; + __le16 q_amount; + u8 reserved[4]; + __le32 addr_high; + __le32 addr_low; +}; + +/* This is the descriptor of each queue entry for the Set Tx Time Queue + * command (0x0C35). Only used within struct ice_aqc_set_txtime_qgrp. + */ +struct ice_aqc_set_txtimeqs_perq { + u8 reserved[4]; + ice_txtime_ctx_buf_t txtime_ctx; + u8 reserved1[3]; +}; + +/* The format of the command buffer for Set Tx Time Queue (0x0C35) + * is an array of the following structs. Please note that the length of + * each struct ice_aqc_set_txtime_qgrp is variable due to the variable + * number of queues in each group! + */ +struct ice_aqc_set_txtime_qgrp { + u8 reserved[8]; + struct ice_aqc_set_txtimeqs_perq txtimeqs[]; +}; + /* Download Package (indirect 0x0C40) */ /* Also used for Update Package (indirect 0x0C41 and 0x0C42) */ struct ice_aqc_download_pkg { @@ -2272,6 +2203,22 @@ struct ice_aqc_get_pkg_info_resp { struct ice_aqc_get_pkg_info pkg_info[]; }; +#define ICE_CGU_INPUT_PHASE_OFFSET_BYTES 6 + +struct ice_cgu_input_measure { + u8 phase_offset[ICE_CGU_INPUT_PHASE_OFFSET_BYTES]; + __le32 freq; +} __packed __aligned(sizeof(__le16)); + +#define ICE_AQC_GET_CGU_IN_MEAS_DPLL_IDX_M ICE_M(0xf, 0) + +/* Get CGU input measure command response data structure (indirect 0x0C59) */ +struct ice_aqc_get_cgu_input_measure { + u8 dpll_idx_opt; + u8 length; + u8 rsvd[6]; +}; + #define ICE_AQC_GET_CGU_MAX_PHASE_ADJ GENMASK(30, 0) /* Get CGU abilities command response data structure (indirect 0x0C61) */ @@ -2288,6 +2235,8 @@ struct ice_aqc_get_cgu_abilities { u8 rsvd[3]; }; +#define ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN BIT(7) + /* Set CGU input config (direct 0x0C62) */ struct ice_aqc_set_cgu_input_config { u8 input_idx; @@ -2482,42 +2431,6 @@ struct ice_aqc_event_lan_overflow { u8 reserved[8]; }; -enum ice_aqc_fw_logging_mod { - ICE_AQC_FW_LOG_ID_GENERAL = 0, - ICE_AQC_FW_LOG_ID_CTRL, - ICE_AQC_FW_LOG_ID_LINK, - ICE_AQC_FW_LOG_ID_LINK_TOPO, - ICE_AQC_FW_LOG_ID_DNL, - ICE_AQC_FW_LOG_ID_I2C, - ICE_AQC_FW_LOG_ID_SDP, - ICE_AQC_FW_LOG_ID_MDIO, - ICE_AQC_FW_LOG_ID_ADMINQ, - ICE_AQC_FW_LOG_ID_HDMA, - ICE_AQC_FW_LOG_ID_LLDP, - ICE_AQC_FW_LOG_ID_DCBX, - ICE_AQC_FW_LOG_ID_DCB, - ICE_AQC_FW_LOG_ID_XLR, - ICE_AQC_FW_LOG_ID_NVM, - ICE_AQC_FW_LOG_ID_AUTH, - ICE_AQC_FW_LOG_ID_VPD, - ICE_AQC_FW_LOG_ID_IOSF, - ICE_AQC_FW_LOG_ID_PARSER, - ICE_AQC_FW_LOG_ID_SW, - ICE_AQC_FW_LOG_ID_SCHEDULER, - ICE_AQC_FW_LOG_ID_TXQ, - ICE_AQC_FW_LOG_ID_RSVD, - ICE_AQC_FW_LOG_ID_POST, - ICE_AQC_FW_LOG_ID_WATCHDOG, - ICE_AQC_FW_LOG_ID_TASK_DISPATCH, - ICE_AQC_FW_LOG_ID_MNG, - ICE_AQC_FW_LOG_ID_SYNCE, - ICE_AQC_FW_LOG_ID_HEALTH, - ICE_AQC_FW_LOG_ID_TSDRV, - ICE_AQC_FW_LOG_ID_PFREG, - ICE_AQC_FW_LOG_ID_MDLVER, - ICE_AQC_FW_LOG_ID_MAX, -}; - enum ice_aqc_health_status_mask { ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK = BIT(0), ICE_AQC_HEALTH_STATUS_SET_ALL_PF_MASK = BIT(1), @@ -2599,193 +2512,6 @@ struct ice_aqc_health_status_elem { __le32 internal_data2; }; -/* Set FW Logging configuration (indirect 0xFF30) - * Register for FW Logging (indirect 0xFF31) - * Query FW Logging (indirect 0xFF32) - * FW Log Event (indirect 0xFF33) - */ -struct ice_aqc_fw_log { - u8 cmd_flags; -#define ICE_AQC_FW_LOG_CONF_UART_EN BIT(0) -#define ICE_AQC_FW_LOG_CONF_AQ_EN BIT(1) -#define ICE_AQC_FW_LOG_QUERY_REGISTERED BIT(2) -#define ICE_AQC_FW_LOG_CONF_SET_VALID BIT(3) -#define ICE_AQC_FW_LOG_AQ_REGISTER BIT(0) -#define ICE_AQC_FW_LOG_AQ_QUERY BIT(2) - - u8 rsp_flag; - __le16 fw_rt_msb; - union { - struct { - __le32 fw_rt_lsb; - } sync; - struct { - __le16 log_resolution; -#define ICE_AQC_FW_LOG_MIN_RESOLUTION (1) -#define ICE_AQC_FW_LOG_MAX_RESOLUTION (128) - - __le16 mdl_cnt; - } cfg; - } ops; - __le32 addr_high; - __le32 addr_low; -}; - -/* Response Buffer for: - * Set Firmware Logging Configuration (0xFF30) - * Query FW Logging (0xFF32) - */ -struct ice_aqc_fw_log_cfg_resp { - __le16 module_identifier; - u8 log_level; - u8 rsvd0; -}; - -/** - * struct ice_aq_desc - Admin Queue (AQ) descriptor - * @flags: ICE_AQ_FLAG_* flags - * @opcode: AQ command opcode - * @datalen: length in bytes of indirect/external data buffer - * @retval: return value from firmware - * @cookie_high: opaque data high-half - * @cookie_low: opaque data low-half - * @params: command-specific parameters - * - * Descriptor format for commands the driver posts on the Admin Transmit Queue - * (ATQ). The firmware writes back onto the command descriptor and returns - * the result of the command. Asynchronous events that are not an immediate - * result of the command are written to the Admin Receive Queue (ARQ) using - * the same descriptor format. Descriptors are in little-endian notation with - * 32-bit words. - */ -struct ice_aq_desc { - __le16 flags; - __le16 opcode; - __le16 datalen; - __le16 retval; - __le32 cookie_high; - __le32 cookie_low; - union { - u8 raw[16]; - struct ice_aqc_generic generic; - struct ice_aqc_get_ver get_ver; - struct ice_aqc_driver_ver driver_ver; - struct ice_aqc_q_shutdown q_shutdown; - struct ice_aqc_req_res res_owner; - struct ice_aqc_manage_mac_read mac_read; - struct ice_aqc_manage_mac_write mac_write; - struct ice_aqc_clear_pxe clear_pxe; - struct ice_aqc_list_caps get_cap; - struct ice_aqc_get_phy_caps get_phy; - struct ice_aqc_set_phy_cfg set_phy; - struct ice_aqc_restart_an restart_an; - struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out; - struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out; - struct ice_aqc_get_sensor_reading get_sensor_reading; - struct ice_aqc_get_sensor_reading_resp get_sensor_reading_resp; - struct ice_aqc_gpio read_write_gpio; - struct ice_aqc_sff_eeprom read_write_sff_param; - struct ice_aqc_set_port_id_led set_port_id_led; - struct ice_aqc_get_port_options get_port_options; - struct ice_aqc_set_port_option set_port_option; - struct ice_aqc_get_sw_cfg get_sw_conf; - struct ice_aqc_set_port_params set_port_params; - struct ice_aqc_sw_rules sw_rules; - struct ice_aqc_add_get_recipe add_get_recipe; - struct ice_aqc_recipe_to_profile recipe_to_profile; - struct ice_aqc_get_topo get_topo; - struct ice_aqc_sched_elem_cmd sched_elem_cmd; - struct ice_aqc_query_txsched_res query_sched_res; - struct ice_aqc_query_port_ets port_ets; - struct ice_aqc_rl_profile rl_profile; - struct ice_aqc_nvm nvm; - struct ice_aqc_nvm_checksum nvm_checksum; - struct ice_aqc_nvm_pkg_data pkg_data; - struct ice_aqc_nvm_pass_comp_tbl pass_comp_tbl; - struct ice_aqc_pf_vf_msg virt; - struct ice_aqc_set_query_pfc_mode set_query_pfc_mode; - struct ice_aqc_lldp_get_mib lldp_get_mib; - struct ice_aqc_lldp_set_mib_change lldp_set_event; - struct ice_aqc_lldp_stop lldp_stop; - struct ice_aqc_lldp_start lldp_start; - struct ice_aqc_lldp_set_local_mib lldp_set_mib; - struct ice_aqc_lldp_stop_start_specific_agent lldp_agent_ctrl; - struct ice_aqc_lldp_filter_ctrl lldp_filter_ctrl; - struct ice_aqc_get_set_rss_lut get_set_rss_lut; - struct ice_aqc_get_set_rss_key get_set_rss_key; - struct ice_aqc_neigh_dev_req neigh_dev; - struct ice_aqc_add_txqs add_txqs; - struct ice_aqc_dis_txqs dis_txqs; - struct ice_aqc_cfg_txqs cfg_txqs; - struct ice_aqc_add_rdma_qset add_rdma_qset; - struct ice_aqc_add_get_update_free_vsi vsi_cmd; - struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res; - struct ice_aqc_download_pkg download_pkg; - struct ice_aqc_set_cgu_input_config set_cgu_input_config; - struct ice_aqc_get_cgu_input_config get_cgu_input_config; - struct ice_aqc_set_cgu_output_config set_cgu_output_config; - struct ice_aqc_get_cgu_output_config get_cgu_output_config; - struct ice_aqc_get_cgu_dpll_status get_cgu_dpll_status; - struct ice_aqc_set_cgu_dpll_config set_cgu_dpll_config; - struct ice_aqc_set_cgu_ref_prio set_cgu_ref_prio; - struct ice_aqc_get_cgu_ref_prio get_cgu_ref_prio; - struct ice_aqc_get_cgu_info get_cgu_info; - struct ice_aqc_driver_shared_params drv_shared_params; - struct ice_aqc_fw_log fw_log; - struct ice_aqc_set_mac_lb set_mac_lb; - struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; - struct ice_aqc_set_mac_cfg set_mac_cfg; - struct ice_aqc_set_event_mask set_event_mask; - struct ice_aqc_get_link_status get_link_status; - struct ice_aqc_event_lan_overflow lan_overflow; - struct ice_aqc_get_link_topo get_link_topo; - struct ice_aqc_set_health_status_cfg set_health_status_cfg; - struct ice_aqc_get_health_status get_health_status; - struct ice_aqc_dnl_call_command dnl_call; - struct ice_aqc_i2c read_write_i2c; - struct ice_aqc_read_i2c_resp read_i2c_resp; - struct ice_aqc_get_set_tx_topo get_set_tx_topo; - } params; -}; - -/* FW defined boundary for a large buffer, 4k >= Large buffer > 512 bytes */ -#define ICE_AQ_LG_BUF 512 - -#define ICE_AQ_FLAG_DD_S 0 -#define ICE_AQ_FLAG_CMP_S 1 -#define ICE_AQ_FLAG_ERR_S 2 -#define ICE_AQ_FLAG_LB_S 9 -#define ICE_AQ_FLAG_RD_S 10 -#define ICE_AQ_FLAG_BUF_S 12 -#define ICE_AQ_FLAG_SI_S 13 - -#define ICE_AQ_FLAG_DD BIT(ICE_AQ_FLAG_DD_S) /* 0x1 */ -#define ICE_AQ_FLAG_CMP BIT(ICE_AQ_FLAG_CMP_S) /* 0x2 */ -#define ICE_AQ_FLAG_ERR BIT(ICE_AQ_FLAG_ERR_S) /* 0x4 */ -#define ICE_AQ_FLAG_LB BIT(ICE_AQ_FLAG_LB_S) /* 0x200 */ -#define ICE_AQ_FLAG_RD BIT(ICE_AQ_FLAG_RD_S) /* 0x400 */ -#define ICE_AQ_FLAG_BUF BIT(ICE_AQ_FLAG_BUF_S) /* 0x1000 */ -#define ICE_AQ_FLAG_SI BIT(ICE_AQ_FLAG_SI_S) /* 0x2000 */ - -/* error codes */ -enum ice_aq_err { - ICE_AQ_RC_OK = 0, /* Success */ - ICE_AQ_RC_EPERM = 1, /* Operation not permitted */ - ICE_AQ_RC_ENOENT = 2, /* No such element */ - ICE_AQ_RC_ENOMEM = 9, /* Out of memory */ - ICE_AQ_RC_EBUSY = 12, /* Device or resource busy */ - ICE_AQ_RC_EEXIST = 13, /* Object already exists */ - ICE_AQ_RC_EINVAL = 14, /* Invalid argument */ - ICE_AQ_RC_ENOSPC = 16, /* No space left or allocation failure */ - ICE_AQ_RC_ENOSYS = 17, /* Function not implemented */ - ICE_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */ - ICE_AQ_RC_ENOSEC = 24, /* Missing security manifest */ - ICE_AQ_RC_EBADSIG = 25, /* Bad RSA signature */ - ICE_AQ_RC_ESVN = 26, /* SVN number prohibits this package */ - ICE_AQ_RC_EBADMAN = 27, /* Manifest hash mismatch */ - ICE_AQ_RC_EBADBUF = 28, /* Buffer hash mismatches manifest */ -}; - /* Admin Queue command opcodes */ enum ice_adminq_opc { /* AQ commands */ @@ -2920,6 +2646,9 @@ enum ice_adminq_opc { ice_aqc_opc_cfg_txqs = 0x0C32, ice_aqc_opc_add_rdma_qset = 0x0C33, + /* Tx Time queue commands */ + ice_aqc_opc_set_txtimeqs = 0x0C35, + /* package commands */ ice_aqc_opc_download_pkg = 0x0C40, ice_aqc_opc_upload_section = 0x0C41, @@ -2927,6 +2656,7 @@ enum ice_adminq_opc { ice_aqc_opc_get_pkg_info_list = 0x0C43, /* 1588/SyncE commands/events */ + ice_aqc_opc_get_cgu_input_measure = 0x0C59, ice_aqc_opc_get_cgu_abilities = 0x0C61, ice_aqc_opc_set_cgu_input_config = 0x0C62, ice_aqc_opc_get_cgu_input_config = 0x0C63, diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 6db4ad8fc70b..2d35a278c555 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -242,7 +242,8 @@ static void ice_cfg_itr_gran(struct ice_hw *hw) * @ring: ring to get the absolute queue index * @tc: traffic class number */ -static u16 ice_calc_txq_handle(struct ice_vsi *vsi, struct ice_tx_ring *ring, u8 tc) +static u16 +ice_calc_txq_handle(const struct ice_vsi *vsi, struct ice_tx_ring *ring, u8 tc) { WARN_ONCE(ice_ring_is_xdp(ring) && tc, "XDP ring can't belong to TC other than 0\n"); @@ -250,7 +251,7 @@ static u16 ice_calc_txq_handle(struct ice_vsi *vsi, struct ice_tx_ring *ring, u8 return ring->q_index - ring->ch->base_q; /* Idea here for calculation is that we subtract the number of queue - * count from TC that ring belongs to from it's absolute queue index + * count from TC that ring belongs to from its absolute queue index * and as a result we get the queue's index within TC. */ return ring->q_index - vsi->tc_cfg.tc_info[tc].qoffset; @@ -278,30 +279,20 @@ static void ice_cfg_xps_tx_ring(struct ice_tx_ring *ring) } /** - * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance - * @ring: The Tx ring to configure - * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized - * @pf_q: queue index in the PF space + * ice_set_txq_ctx_vmvf - set queue context VM/VF type and number by VSI type + * @ring: the Tx ring to configure + * @vmvf_type: VM/VF type + * @vmvf_num: VM/VF number * - * Configure the Tx descriptor ring in TLAN context. + * Return: 0 on success and a negative value on error. */ -static void -ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) +static int +ice_set_txq_ctx_vmvf(struct ice_tx_ring *ring, u8 *vmvf_type, u16 *vmvf_num) { struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; - - tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; - - tlan_ctx->port_num = vsi->port_info->lport; - - /* Transmit Queue Length */ - tlan_ctx->qlen = ring->count; - - ice_set_cgd_num(tlan_ctx, ring->dcb_tc); + struct ice_hw *hw; - /* PF number */ - tlan_ctx->pf_num = hw->pf_id; + hw = &vsi->back->hw; /* queue belongs to a specific VSI type * VF / VM index should be programmed per vmvf_type setting: @@ -314,21 +305,60 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf case ICE_VSI_CTRL: case ICE_VSI_PF: if (ring->ch) - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ; + *vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ; else - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; + *vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; break; case ICE_VSI_VF: /* Firmware expects vmvf_num to be absolute VF ID */ - tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf->vf_id; - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF; + *vmvf_num = hw->func_caps.vf_base_id + vsi->vf->vf_id; + *vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF; break; case ICE_VSI_SF: - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ; + *vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ; break; default: - return; + dev_info(ice_pf_to_dev(vsi->back), + "Unable to set VMVF type for VSI type %d\n", + vsi->type); + return -EINVAL; } + return 0; +} + +/** + * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance + * @ring: the Tx ring to configure + * @tlan_ctx: pointer to the Tx LAN queue context structure to be initialized + * @pf_q: queue index in the PF space + * + * Configure the Tx descriptor ring in TLAN context. + * + * Return: 0 on success and a negative value on error. + */ +static int +ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) +{ + struct ice_vsi *vsi = ring->vsi; + struct ice_hw *hw; + int err; + + hw = &vsi->back->hw; + tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; + tlan_ctx->port_num = vsi->port_info->lport; + + /* Transmit Queue Length */ + tlan_ctx->qlen = ring->count; + + ice_set_cgd_num(tlan_ctx, ring->dcb_tc); + + /* PF number */ + tlan_ctx->pf_num = hw->pf_id; + + err = ice_set_txq_ctx_vmvf(ring, &tlan_ctx->vmvf_type, + &tlan_ctx->vmvf_num); + if (err) + return err; /* make sure the context is associated with the right VSI */ if (ring->ch) @@ -355,6 +385,80 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf * 1: Legacy Host Interface */ tlan_ctx->legacy_int = ICE_TX_LEGACY; + + return 0; +} + +/** + * ice_setup_txtime_ctx - setup a struct ice_txtime_ctx instance + * @ring: the tstamp ring to configure + * @txtime_ctx: pointer to the Tx time queue context structure to be initialized + * + * Return: 0 on success and a negative value on error. + */ +static int +ice_setup_txtime_ctx(const struct ice_tstamp_ring *ring, + struct ice_txtime_ctx *txtime_ctx) +{ + struct ice_tx_ring *tx_ring = ring->tx_ring; + struct ice_vsi *vsi = tx_ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + int err; + + txtime_ctx->base = ring->dma >> ICE_TXTIME_CTX_BASE_S; + + /* Tx time Queue Length */ + txtime_ctx->qlen = ring->count; + txtime_ctx->txtime_ena_q = 1; + + /* PF number */ + txtime_ctx->pf_num = hw->pf_id; + + err = ice_set_txq_ctx_vmvf(tx_ring, &txtime_ctx->vmvf_type, + &txtime_ctx->vmvf_num); + if (err) + return err; + + /* make sure the context is associated with the right VSI */ + if (tx_ring->ch) + txtime_ctx->src_vsi = tx_ring->ch->vsi_num; + else + txtime_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx); + + txtime_ctx->ts_res = ICE_TXTIME_CTX_RESOLUTION_128NS; + txtime_ctx->drbell_mode_32 = ICE_TXTIME_CTX_DRBELL_MODE_32; + txtime_ctx->ts_fetch_prof_id = ICE_TXTIME_CTX_FETCH_PROF_ID_0; + + return 0; +} + +/** + * ice_calc_ts_ring_count - calculate the number of Tx time stamp descriptors + * @tx_ring: Tx ring to calculate the count for + * + * Return: the number of Tx time stamp descriptors. + */ +u16 ice_calc_ts_ring_count(struct ice_tx_ring *tx_ring) +{ + u16 prof = ICE_TXTIME_CTX_FETCH_PROF_ID_0; + struct ice_vsi *vsi = tx_ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + u16 max_fetch_desc = 0, fetch, i; + u32 reg; + + for (i = 0; i < ICE_TXTIME_FETCH_PROFILE_CNT; i++) { + reg = rd32(hw, E830_GLTXTIME_FETCH_PROFILE(prof, 0)); + fetch = FIELD_GET(E830_GLTXTIME_FETCH_PROFILE_FETCH_TS_DESC_M, + reg); + max_fetch_desc = max(fetch, max_fetch_desc); + } + + if (!max_fetch_desc) + max_fetch_desc = ICE_TXTIME_FETCH_TS_DESC_DFLT; + + max_fetch_desc = ALIGN(max_fetch_desc, ICE_REQ_DESC_MULTIPLE); + + return tx_ring->count + max_fetch_desc; } /** @@ -623,7 +727,10 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) return 0; } - ice_alloc_rx_bufs(ring, num_bufs); + if (ring->vsi->type == ICE_VSI_CTRL) + ice_init_ctrl_rx_descs(ring, num_bufs); + else + ice_alloc_rx_bufs(ring, num_bufs); return 0; } @@ -879,13 +986,49 @@ void ice_vsi_free_q_vectors(struct ice_vsi *vsi) } /** + * ice_cfg_tstamp - Configure Tx time stamp queue + * @tx_ring: Tx ring to be configured with timestamping + * + * Return: 0 on success and a negative value on error. + */ +static int +ice_cfg_tstamp(struct ice_tx_ring *tx_ring) +{ + DEFINE_RAW_FLEX(struct ice_aqc_set_txtime_qgrp, txtime_qg_buf, + txtimeqs, 1); + u8 txtime_buf_len = struct_size(txtime_qg_buf, txtimeqs, 1); + struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; + struct ice_txtime_ctx txtime_ctx = {}; + struct ice_vsi *vsi = tx_ring->vsi; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u16 pf_q = tx_ring->reg_idx; + int err; + + err = ice_setup_txtime_ctx(tstamp_ring, &txtime_ctx); + if (err) { + dev_err(ice_pf_to_dev(pf), "Failed to setup Tx time queue context for queue %d, error: %d\n", + pf_q, err); + return err; + } + ice_pack_txtime_ctx(&txtime_ctx, + &txtime_qg_buf->txtimeqs[0].txtime_ctx); + + tstamp_ring->tail = hw->hw_addr + E830_GLQTX_TXTIME_DBELL_LSB(pf_q); + return ice_aq_set_txtimeq(hw, pf_q, 1, txtime_qg_buf, + txtime_buf_len, NULL); +} + +/** * ice_vsi_cfg_txq - Configure single Tx queue * @vsi: the VSI that queue belongs to * @ring: Tx ring to be configured * @qg_buf: queue group buffer + * + * Return: 0 on success and a negative value on error. */ static int -ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, +ice_vsi_cfg_txq(const struct ice_vsi *vsi, struct ice_tx_ring *ring, struct ice_aqc_add_tx_qgrp *qg_buf) { u8 buf_len = struct_size(qg_buf, txqs, 1); @@ -894,15 +1037,20 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, struct ice_channel *ch = ring->ch; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; + u32 pf_q, vsi_idx; int status; - u16 pf_q; u8 tc; /* Configure XPS */ ice_cfg_xps_tx_ring(ring); pf_q = ring->reg_idx; - ice_setup_tx_ctx(ring, &tlan_ctx, pf_q); + status = ice_setup_tx_ctx(ring, &tlan_ctx, pf_q); + if (status) { + dev_err(ice_pf_to_dev(pf), "Failed to setup Tx context for queue %d, error: %d\n", + pf_q, status); + return status; + } /* copy context contents into the qg_buf */ qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); ice_pack_txq_ctx(&tlan_ctx, &qg_buf->txqs[0].txq_ctx); @@ -922,14 +1070,15 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, */ ring->q_handle = ice_calc_txq_handle(vsi, ring, tc); - if (ch) - status = ice_ena_vsi_txq(vsi->port_info, ch->ch_vsi->idx, 0, - ring->q_handle, 1, qg_buf, buf_len, - NULL); - else - status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, - ring->q_handle, 1, qg_buf, buf_len, - NULL); + if (ch) { + tc = 0; + vsi_idx = ch->ch_vsi->idx; + } else { + vsi_idx = vsi->idx; + } + + status = ice_ena_vsi_txq(vsi->port_info, vsi_idx, tc, ring->q_handle, + 1, qg_buf, buf_len, NULL); if (status) { dev_err(ice_pf_to_dev(pf), "Failed to set LAN Tx queue context, error: %d\n", status); @@ -944,7 +1093,32 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring, if (pf_q == le16_to_cpu(txq->txq_id)) ring->txq_teid = le32_to_cpu(txq->q_teid); + if (ice_is_txtime_ena(ring)) { + status = ice_alloc_setup_tstamp_ring(ring); + if (status) { + dev_err(ice_pf_to_dev(pf), + "Failed to allocate Tx timestamp ring, error: %d\n", + status); + goto err_setup_tstamp; + } + + status = ice_cfg_tstamp(ring); + if (status) { + dev_err(ice_pf_to_dev(pf), "Failed to set Tx Time queue context, error: %d\n", + status); + goto err_cfg_tstamp; + } + } return 0; + +err_cfg_tstamp: + ice_free_tx_tstamp_ring(ring); +err_setup_tstamp: + ice_dis_vsi_txq(vsi->port_info, vsi_idx, tc, 1, &ring->q_handle, + &ring->reg_idx, &ring->txq_teid, ICE_NO_RESET, + tlan_ctx.vmvf_num, NULL); + + return status; } int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings, @@ -1203,3 +1377,148 @@ ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring, txq_meta->tc = tc; } } + +/** + * ice_qp_reset_stats - Resets all stats for rings of given index + * @vsi: VSI that contains rings of interest + * @q_idx: ring index in array + */ +static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx) +{ + struct ice_vsi_stats *vsi_stat; + struct ice_pf *pf; + + pf = vsi->back; + if (!pf->vsi_stats) + return; + + vsi_stat = pf->vsi_stats[vsi->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->tx_ring_stats[q_idx]->stats, 0, + sizeof(vsi_stat->tx_ring_stats[q_idx]->stats)); + if (vsi->xdp_rings) + memset(&vsi->xdp_rings[q_idx]->ring_stats->stats, 0, + sizeof(vsi->xdp_rings[q_idx]->ring_stats->stats)); +} + +/** + * ice_qp_clean_rings - Cleans all the rings of a given index + * @vsi: VSI that contains rings of interest + * @q_idx: ring index in array + */ +static void ice_qp_clean_rings(struct ice_vsi *vsi, u16 q_idx) +{ + ice_clean_tx_ring(vsi->tx_rings[q_idx]); + if (vsi->xdp_rings) + ice_clean_tx_ring(vsi->xdp_rings[q_idx]); + ice_clean_rx_ring(vsi->rx_rings[q_idx]); +} + +/** + * ice_qp_dis - Disables a queue pair + * @vsi: VSI of interest + * @q_idx: ring index in array + * + * Returns 0 on success, negative on failure. + */ +int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) +{ + struct ice_txq_meta txq_meta = { }; + struct ice_q_vector *q_vector; + struct ice_tx_ring *tx_ring; + struct ice_rx_ring *rx_ring; + int fail = 0; + int err; + + if (q_idx >= vsi->num_rxq || q_idx >= vsi->num_txq) + return -EINVAL; + + tx_ring = vsi->tx_rings[q_idx]; + rx_ring = vsi->rx_rings[q_idx]; + q_vector = rx_ring->q_vector; + + synchronize_net(); + netif_carrier_off(vsi->netdev); + netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); + + ice_qvec_dis_irq(vsi, rx_ring, q_vector); + ice_qvec_toggle_napi(vsi, q_vector, false); + + ice_fill_txq_meta(vsi, tx_ring, &txq_meta); + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, tx_ring, &txq_meta); + if (!fail) + fail = err; + if (vsi->xdp_rings) { + struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_idx]; + + memset(&txq_meta, 0, sizeof(txq_meta)); + ice_fill_txq_meta(vsi, xdp_ring, &txq_meta); + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, xdp_ring, + &txq_meta); + if (!fail) + fail = err; + } + + ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, false); + ice_qp_clean_rings(vsi, q_idx); + ice_qp_reset_stats(vsi, q_idx); + + return fail; +} + +/** + * ice_qp_ena - Enables a queue pair + * @vsi: VSI of interest + * @q_idx: ring index in array + * + * Returns 0 on success, negative on failure. + */ +int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) +{ + struct ice_q_vector *q_vector; + int fail = 0; + bool link_up; + int err; + + err = ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx); + if (!fail) + fail = err; + + if (ice_is_xdp_ena_vsi(vsi)) { + struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_idx]; + + err = ice_vsi_cfg_single_txq(vsi, vsi->xdp_rings, q_idx); + if (!fail) + fail = err; + ice_set_ring_xdp(xdp_ring); + ice_tx_xsk_pool(vsi, q_idx); + } + + err = ice_vsi_cfg_single_rxq(vsi, q_idx); + if (!fail) + fail = err; + + q_vector = vsi->rx_rings[q_idx]->q_vector; + ice_qvec_cfg_msix(vsi, q_vector, q_idx); + + err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_idx, true); + if (!fail) + fail = err; + + ice_qvec_toggle_napi(vsi, q_vector, true); + ice_qvec_ena_irq(vsi, q_vector); + + /* make sure NAPI sees updated ice_{t,x}_ring::xsk_pool */ + synchronize_net(); + ice_get_link_status(vsi->port_info, &link_up); + if (link_up) { + netif_tx_start_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); + netif_carrier_on(vsi->netdev); + } + + return fail; +} diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h index b711bc921928..d28294247599 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.h +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -32,4 +32,7 @@ ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, void ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring, struct ice_txq_meta *txq_meta); +int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx); +int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx); +u16 ice_calc_ts_ring_count(struct ice_tx_ring *tx_ring); #endif /* _ICE_BASE_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_cgu_regs.h b/drivers/net/ethernet/intel/ice/ice_cgu_regs.h deleted file mode 100644 index 10d9d74f3545..000000000000 --- a/drivers/net/ethernet/intel/ice/ice_cgu_regs.h +++ /dev/null @@ -1,181 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018-2021, Intel Corporation. */ - -#ifndef _ICE_CGU_REGS_H_ -#define _ICE_CGU_REGS_H_ - -#define NAC_CGU_DWORD9 0x24 -union nac_cgu_dword9 { - struct { - u32 time_ref_freq_sel : 3; - u32 clk_eref1_en : 1; - u32 clk_eref0_en : 1; - u32 time_ref_en : 1; - u32 time_sync_en : 1; - u32 one_pps_out_en : 1; - u32 clk_ref_synce_en : 1; - u32 clk_synce1_en : 1; - u32 clk_synce0_en : 1; - u32 net_clk_ref1_en : 1; - u32 net_clk_ref0_en : 1; - u32 clk_synce1_amp : 2; - u32 misc6 : 1; - u32 clk_synce0_amp : 2; - u32 one_pps_out_amp : 2; - u32 misc24 : 12; - }; - u32 val; -}; - -#define NAC_CGU_DWORD16_E825C 0x40 -union nac_cgu_dword16_e825c { - struct { - u32 synce_remndr : 6; - u32 synce_phlmt_en : 1; - u32 misc13 : 17; - u32 tspll_ck_refclkfreq : 8; - }; - u32 val; -}; - -#define NAC_CGU_DWORD19 0x4c -union nac_cgu_dword19 { - struct { - u32 tspll_fbdiv_intgr : 8; - u32 fdpll_ulck_thr : 5; - u32 misc15 : 3; - u32 tspll_ndivratio : 4; - u32 tspll_iref_ndivratio : 3; - u32 misc19 : 1; - u32 japll_ndivratio : 4; - u32 japll_iref_ndivratio : 3; - u32 misc27 : 1; - }; - u32 val; -}; - -#define NAC_CGU_DWORD22 0x58 -union nac_cgu_dword22 { - struct { - u32 fdpll_frac_div_out_nc : 2; - u32 fdpll_lock_int_for : 1; - u32 synce_hdov_int_for : 1; - u32 synce_lock_int_for : 1; - u32 fdpll_phlead_slip_nc : 1; - u32 fdpll_acc1_ovfl_nc : 1; - u32 fdpll_acc2_ovfl_nc : 1; - u32 synce_status_nc : 6; - u32 fdpll_acc1f_ovfl : 1; - u32 misc18 : 1; - u32 fdpllclk_div : 4; - u32 time1588clk_div : 4; - u32 synceclk_div : 4; - u32 synceclk_sel_div2 : 1; - u32 fdpllclk_sel_div2 : 1; - u32 time1588clk_sel_div2 : 1; - u32 misc3 : 1; - }; - u32 val; -}; - -#define NAC_CGU_DWORD23_E825C 0x5C -union nac_cgu_dword23_e825c { - struct { - u32 cgupll_fbdiv_intgr : 10; - u32 ux56pll_fbdiv_intgr : 10; - u32 misc20 : 4; - u32 ts_pll_enable : 1; - u32 time_sync_tspll_align_sel : 1; - u32 ext_synce_sel : 1; - u32 ref1588_ck_div : 4; - u32 time_ref_sel : 1; - - }; - u32 val; -}; - -#define NAC_CGU_DWORD24 0x60 -union nac_cgu_dword24 { - struct { - u32 tspll_fbdiv_frac : 22; - u32 misc20 : 2; - u32 ts_pll_enable : 1; - u32 time_sync_tspll_align_sel : 1; - u32 ext_synce_sel : 1; - u32 ref1588_ck_div : 4; - u32 time_ref_sel : 1; - }; - u32 val; -}; - -#define TSPLL_CNTR_BIST_SETTINGS 0x344 -union tspll_cntr_bist_settings { - struct { - u32 i_irefgen_settling_time_cntr_7_0 : 8; - u32 i_irefgen_settling_time_ro_standby_1_0 : 2; - u32 reserved195 : 5; - u32 i_plllock_sel_0 : 1; - u32 i_plllock_sel_1 : 1; - u32 i_plllock_cnt_6_0 : 7; - u32 i_plllock_cnt_10_7 : 4; - u32 reserved200 : 4; - }; - u32 val; -}; - -#define TSPLL_RO_BWM_LF 0x370 -union tspll_ro_bwm_lf { - struct { - u32 bw_freqov_high_cri_7_0 : 8; - u32 bw_freqov_high_cri_9_8 : 2; - u32 biascaldone_cri : 1; - u32 plllock_gain_tran_cri : 1; - u32 plllock_true_lock_cri : 1; - u32 pllunlock_flag_cri : 1; - u32 afcerr_cri : 1; - u32 afcdone_cri : 1; - u32 feedfwrdgain_cal_cri_7_0 : 8; - u32 m2fbdivmod_cri_7_0 : 8; - }; - u32 val; -}; - -#define TSPLL_RO_LOCK_E825C 0x3f0 -union tspll_ro_lock_e825c { - struct { - u32 bw_freqov_high_cri_7_0 : 8; - u32 bw_freqov_high_cri_9_8 : 2; - u32 reserved455 : 1; - u32 plllock_gain_tran_cri : 1; - u32 plllock_true_lock_cri : 1; - u32 pllunlock_flag_cri : 1; - u32 afcerr_cri : 1; - u32 afcdone_cri : 1; - u32 feedfwrdgain_cal_cri_7_0 : 8; - u32 reserved462 : 8; - }; - u32 val; -}; - -#define TSPLL_BW_TDC_E825C 0x31c -union tspll_bw_tdc_e825c { - struct { - u32 i_tdc_offset_lock_1_0 : 2; - u32 i_bbthresh1_2_0 : 3; - u32 i_bbthresh2_2_0 : 3; - u32 i_tdcsel_1_0 : 2; - u32 i_tdcovccorr_en_h : 1; - u32 i_divretimeren : 1; - u32 i_bw_ampmeas_window : 1; - u32 i_bw_lowerbound_2_0 : 3; - u32 i_bw_upperbound_2_0 : 3; - u32 i_bw_mode_1_0 : 2; - u32 i_ft_mode_sel_2_0 : 3; - u32 i_bwphase_4_0 : 5; - u32 i_plllock_sel_1_0 : 2; - u32 i_afc_divratio : 1; - }; - u32 val; -}; - -#endif /* _ICE_CGU_REGS_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 4fedf0181c4e..2250426ec91b 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -171,6 +171,15 @@ static int ice_set_mac_type(struct ice_hw *hw) case ICE_DEV_ID_E830_XXV_QSFP: case ICE_DEV_ID_E830C_SFP: case ICE_DEV_ID_E830_XXV_SFP: + case ICE_DEV_ID_E835CC_BACKPLANE: + case ICE_DEV_ID_E835CC_QSFP56: + case ICE_DEV_ID_E835CC_SFP: + case ICE_DEV_ID_E835C_BACKPLANE: + case ICE_DEV_ID_E835C_QSFP: + case ICE_DEV_ID_E835C_SFP: + case ICE_DEV_ID_E835_L_BACKPLANE: + case ICE_DEV_ID_E835_L_QSFP: + case ICE_DEV_ID_E835_L_SFP: hw->mac_type = ICE_MAC_E830; break; default: @@ -239,7 +248,7 @@ static bool ice_is_pf_c827(struct ice_hw *hw) */ int ice_clear_pf_cfg(struct ice_hw *hw) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pf_cfg); @@ -267,12 +276,12 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size, { struct ice_aqc_manage_mac_read_resp *resp; struct ice_aqc_manage_mac_read *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; u16 flags; u8 i; - cmd = &desc.params.mac_read; + cmd = libie_aq_raw(&desc); if (buf_size < sizeof(*resp)) return -EINVAL; @@ -321,12 +330,12 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, { struct ice_aqc_get_phy_caps *cmd; u16 pcaps_size = sizeof(*pcaps); - struct ice_aq_desc desc; + struct libie_aq_desc desc; const char *prefix; struct ice_hw *hw; int status; - cmd = &desc.params.get_phy; + cmd = libie_aq_raw(&desc); if (!pcaps || (report_mode & ~ICE_AQC_REPORT_MODE_M) || !pi) return -EINVAL; @@ -415,9 +424,9 @@ ice_aq_get_link_topo_handle(struct ice_port_info *pi, u8 node_type, struct ice_sq_cd *cd) { struct ice_aqc_get_link_topo *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.get_link_topo; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); @@ -445,19 +454,20 @@ int ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, u8 *node_part_number, u16 *node_handle) { - struct ice_aq_desc desc; + struct ice_aqc_get_link_topo *resp; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); - desc.params.get_link_topo = *cmd; + resp = libie_aq_raw(&desc); + *resp = *cmd; if (ice_aq_send_cmd(hw, &desc, NULL, 0, NULL)) return -EINTR; if (node_handle) - *node_handle = - le16_to_cpu(desc.params.get_link_topo.addr.handle); + *node_handle = le16_to_cpu(resp->addr.handle); if (node_part_number) - *node_part_number = desc.params.get_link_topo.node_part_num; + *node_part_number = resp->node_part_num; return 0; } @@ -680,8 +690,8 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, struct ice_link_status *li_old, *li; enum ice_media_type *hw_media_type; struct ice_fc_info *hw_fc_info; + struct libie_aq_desc desc; bool tx_pause, rx_pause; - struct ice_aq_desc desc; struct ice_hw *hw; u16 cmd_flags; int status; @@ -696,7 +706,7 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_status); cmd_flags = (ena_lse) ? ICE_AQ_LSE_ENA : ICE_AQ_LSE_DIS; - resp = &desc.params.get_link_status; + resp = libie_aq_raw(&desc); resp->cmd_flags = cpu_to_le16(cmd_flags); resp->lport_num = pi->lport; @@ -825,9 +835,9 @@ int ice_aq_set_mac_cfg(struct ice_hw *hw, u16 max_frame_size, struct ice_sq_cd *cd) { struct ice_aqc_set_mac_cfg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.set_mac_cfg; + cmd = libie_aq_raw(&desc); if (max_frame_size == 0) return -EINVAL; @@ -974,6 +984,37 @@ static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout) return -ETIMEDOUT; } +static int __fwlog_send_cmd(void *priv, struct libie_aq_desc *desc, void *buf, + u16 size) +{ + struct ice_hw *hw = priv; + + return ice_aq_send_cmd(hw, desc, buf, size, NULL); +} + +static int __fwlog_init(struct ice_hw *hw) +{ + struct ice_pf *pf = hw->back; + struct libie_fwlog_api api = { + .pdev = pf->pdev, + .send_cmd = __fwlog_send_cmd, + .priv = hw, + }; + int err; + + /* only support fw log commands on PF 0 */ + if (hw->bus.func) + return -EINVAL; + + err = ice_debugfs_pf_init(pf); + if (err) + return err; + + api.debugfs_root = pf->ice_debugfs_pf; + + return libie_fwlog_init(&hw->fwlog, &api); +} + /** * ice_init_hw - main hardware initialization routine * @hw: pointer to the hardware structure @@ -1002,7 +1043,7 @@ int ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_cqinit; - status = ice_fwlog_init(hw); + status = __fwlog_init(hw); if (status) ice_debug(hw, ICE_DBG_FW_LOG, "Error initializing FW logging: %d\n", status); @@ -1149,6 +1190,16 @@ err_unroll_cqinit: return status; } +static void __fwlog_deinit(struct ice_hw *hw) +{ + /* only support fw log commands on PF 0 */ + if (hw->bus.func) + return; + + ice_debugfs_pf_deinit(hw->back); + libie_fwlog_deinit(&hw->fwlog); +} + /** * ice_deinit_hw - unroll initialization operations done by ice_init_hw * @hw: pointer to the hardware structure @@ -1167,8 +1218,7 @@ void ice_deinit_hw(struct ice_hw *hw) ice_free_seg(hw); ice_free_hw_tbls(hw); mutex_destroy(&hw->tnl_lock); - - ice_fwlog_deinit(hw); + __fwlog_deinit(hw); ice_destroy_all_ctrlq(hw); /* Clear VSI contexts if not already cleared */ @@ -1342,6 +1392,26 @@ static void ice_copy_rxq_ctx_to_hw(struct ice_hw *hw, } } +/** + * ice_copy_rxq_ctx_from_hw - Copy packed Rx Queue context from HW registers + * @hw: pointer to the hardware structure + * @rxq_ctx: pointer to the packed Rx queue context + * @rxq_index: the index of the Rx queue + */ +static void ice_copy_rxq_ctx_from_hw(struct ice_hw *hw, + ice_rxq_ctx_buf_t *rxq_ctx, + u32 rxq_index) +{ + u32 *ctx = (u32 *)rxq_ctx; + + /* Copy each dword separately from HW */ + for (int i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++, ctx++) { + *ctx = rd32(hw, QRX_CONTEXT(i, rxq_index)); + + ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i, *ctx); + } +} + #define ICE_CTX_STORE(struct_name, struct_field, width, lsb) \ PACKED_FIELD((lsb) + (width) - 1, (lsb), struct struct_name, struct_field) @@ -1386,6 +1456,21 @@ static void ice_pack_rxq_ctx(const struct ice_rlan_ctx *ctx, } /** + * ice_unpack_rxq_ctx - Unpack Rx queue context from a HW buffer + * @buf: the HW buffer to unpack from + * @ctx: the Rx queue context to unpack + * + * Unpack the Rx queue context from the HW buffer into the CPU-friendly + * structure. + */ +static void ice_unpack_rxq_ctx(const ice_rxq_ctx_buf_t *buf, + struct ice_rlan_ctx *ctx) +{ + unpack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields, + QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST); +} + +/** * ice_write_rxq_ctx - Write Rx Queue context to hardware * @hw: pointer to the hardware structure * @rlan_ctx: pointer to the unpacked Rx queue context @@ -1410,6 +1495,31 @@ int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, return 0; } +/** + * ice_read_rxq_ctx - Read Rx queue context from HW + * @hw: pointer to the hardware structure + * @rlan_ctx: pointer to the Rx queue context + * @rxq_index: the index of the Rx queue + * + * Read the Rx queue context from the hardware registers, and unpack it into + * the sparse Rx queue context structure. + * + * Returns: 0 on success, or -EINVAL if the Rx queue index is invalid. + */ +int ice_read_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, + u32 rxq_index) +{ + ice_rxq_ctx_buf_t buf = {}; + + if (rxq_index > QRX_CTRL_MAX_INDEX) + return -EINVAL; + + ice_copy_rxq_ctx_from_hw(hw, &buf, rxq_index); + ice_unpack_rxq_ctx(&buf, rlan_ctx); + + return 0; +} + /* LAN Tx Queue Context */ static const struct packed_field_u8 ice_tlan_ctx_fields[] = { /* Field Width LSB */ @@ -1443,12 +1553,12 @@ static const struct packed_field_u8 ice_tlan_ctx_fields[] = { }; /** - * ice_pack_txq_ctx - Pack Tx queue context into a HW buffer + * ice_pack_txq_ctx - Pack Tx queue context into Admin Queue buffer * @ctx: the Tx queue context to pack - * @buf: the HW buffer to pack into + * @buf: the Admin Queue HW buffer to pack into * * Pack the Tx queue context from the CPU-friendly unpacked buffer into its - * bit-packed HW layout. + * bit-packed Admin Queue layout. */ void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf) { @@ -1456,6 +1566,211 @@ void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf) QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST); } +/** + * ice_pack_txq_ctx_full - Pack Tx queue context into a HW buffer + * @ctx: the Tx queue context to pack + * @buf: the HW buffer to pack into + * + * Pack the Tx queue context from the CPU-friendly unpacked buffer into its + * bit-packed HW layout, including the internal data portion. + */ +static void ice_pack_txq_ctx_full(const struct ice_tlan_ctx *ctx, + ice_txq_ctx_buf_full_t *buf) +{ + pack_fields(buf, sizeof(*buf), ctx, ice_tlan_ctx_fields, + QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST); +} + +/** + * ice_unpack_txq_ctx_full - Unpack Tx queue context from a HW buffer + * @buf: the HW buffer to unpack from + * @ctx: the Tx queue context to unpack + * + * Unpack the Tx queue context from the HW buffer (including the full internal + * state) into the CPU-friendly structure. + */ +static void ice_unpack_txq_ctx_full(const ice_txq_ctx_buf_full_t *buf, + struct ice_tlan_ctx *ctx) +{ + unpack_fields(buf, sizeof(*buf), ctx, ice_tlan_ctx_fields, + QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST); +} + +/** + * ice_copy_txq_ctx_from_hw - Copy Tx Queue context from HW registers + * @hw: pointer to the hardware structure + * @txq_ctx: pointer to the packed Tx queue context, including internal state + * @txq_index: the index of the Tx queue + * + * Copy Tx Queue context from HW register space to dense structure + */ +static void ice_copy_txq_ctx_from_hw(struct ice_hw *hw, + ice_txq_ctx_buf_full_t *txq_ctx, + u32 txq_index) +{ + struct ice_pf *pf = container_of(hw, struct ice_pf, hw); + u32 *ctx = (u32 *)txq_ctx; + u32 txq_base, reg; + + /* Get Tx queue base within card space */ + txq_base = rd32(hw, PFLAN_TX_QALLOC(hw->pf_id)); + txq_base = FIELD_GET(PFLAN_TX_QALLOC_FIRSTQ_M, txq_base); + + reg = FIELD_PREP(GLCOMM_QTX_CNTX_CTL_CMD_M, + GLCOMM_QTX_CNTX_CTL_CMD_READ) | + FIELD_PREP(GLCOMM_QTX_CNTX_CTL_QUEUE_ID_M, + txq_base + txq_index) | + GLCOMM_QTX_CNTX_CTL_CMD_EXEC_M; + + /* Prevent other PFs on the same adapter from accessing the Tx queue + * context interface concurrently. + */ + spin_lock(&pf->adapter->txq_ctx_lock); + + wr32(hw, GLCOMM_QTX_CNTX_CTL, reg); + ice_flush(hw); + + /* Copy each dword separately from HW */ + for (int i = 0; i < ICE_TXQ_CTX_FULL_SIZE_DWORDS; i++, ctx++) { + *ctx = rd32(hw, GLCOMM_QTX_CNTX_DATA(i)); + + ice_debug(hw, ICE_DBG_QCTX, "qtxdata[%d]: %08X\n", i, *ctx); + } + + spin_unlock(&pf->adapter->txq_ctx_lock); +} + +/** + * ice_copy_txq_ctx_to_hw - Copy Tx Queue context into HW registers + * @hw: pointer to the hardware structure + * @txq_ctx: pointer to the packed Tx queue context, including internal state + * @txq_index: the index of the Tx queue + */ +static void ice_copy_txq_ctx_to_hw(struct ice_hw *hw, + const ice_txq_ctx_buf_full_t *txq_ctx, + u32 txq_index) +{ + struct ice_pf *pf = container_of(hw, struct ice_pf, hw); + u32 txq_base, reg; + + /* Get Tx queue base within card space */ + txq_base = rd32(hw, PFLAN_TX_QALLOC(hw->pf_id)); + txq_base = FIELD_GET(PFLAN_TX_QALLOC_FIRSTQ_M, txq_base); + + reg = FIELD_PREP(GLCOMM_QTX_CNTX_CTL_CMD_M, + GLCOMM_QTX_CNTX_CTL_CMD_WRITE_NO_DYN) | + FIELD_PREP(GLCOMM_QTX_CNTX_CTL_QUEUE_ID_M, + txq_base + txq_index) | + GLCOMM_QTX_CNTX_CTL_CMD_EXEC_M; + + /* Prevent other PFs on the same adapter from accessing the Tx queue + * context interface concurrently. + */ + spin_lock(&pf->adapter->txq_ctx_lock); + + /* Copy each dword separately to HW */ + for (int i = 0; i < ICE_TXQ_CTX_FULL_SIZE_DWORDS; i++) { + u32 ctx = ((const u32 *)txq_ctx)[i]; + + wr32(hw, GLCOMM_QTX_CNTX_DATA(i), ctx); + + ice_debug(hw, ICE_DBG_QCTX, "qtxdata[%d]: %08X\n", i, ctx); + } + + wr32(hw, GLCOMM_QTX_CNTX_CTL, reg); + ice_flush(hw); + + spin_unlock(&pf->adapter->txq_ctx_lock); +} + +/** + * ice_read_txq_ctx - Read Tx queue context from HW + * @hw: pointer to the hardware structure + * @tlan_ctx: pointer to the Tx queue context + * @txq_index: the index of the Tx queue + * + * Read the Tx queue context from the HW registers, then unpack it into the + * ice_tlan_ctx structure for use. + * + * Returns: 0 on success, or -EINVAL on an invalid Tx queue index. + */ +int ice_read_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx, + u32 txq_index) +{ + ice_txq_ctx_buf_full_t buf = {}; + + if (txq_index > QTX_COMM_HEAD_MAX_INDEX) + return -EINVAL; + + ice_copy_txq_ctx_from_hw(hw, &buf, txq_index); + ice_unpack_txq_ctx_full(&buf, tlan_ctx); + + return 0; +} + +/** + * ice_write_txq_ctx - Write Tx queue context to HW + * @hw: pointer to the hardware structure + * @tlan_ctx: pointer to the Tx queue context + * @txq_index: the index of the Tx queue + * + * Pack the Tx queue context into the dense HW layout, then write it into the + * HW registers. + * + * Returns: 0 on success, or -EINVAL on an invalid Tx queue index. + */ +int ice_write_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx, + u32 txq_index) +{ + ice_txq_ctx_buf_full_t buf = {}; + + if (txq_index > QTX_COMM_HEAD_MAX_INDEX) + return -EINVAL; + + ice_pack_txq_ctx_full(tlan_ctx, &buf); + ice_copy_txq_ctx_to_hw(hw, &buf, txq_index); + + return 0; +} + +/* Tx time Queue Context */ +static const struct packed_field_u8 ice_txtime_ctx_fields[] = { + /* Field Width LSB */ + ICE_CTX_STORE(ice_txtime_ctx, base, 57, 0), + ICE_CTX_STORE(ice_txtime_ctx, pf_num, 3, 57), + ICE_CTX_STORE(ice_txtime_ctx, vmvf_num, 10, 60), + ICE_CTX_STORE(ice_txtime_ctx, vmvf_type, 2, 70), + ICE_CTX_STORE(ice_txtime_ctx, src_vsi, 10, 72), + ICE_CTX_STORE(ice_txtime_ctx, cpuid, 8, 82), + ICE_CTX_STORE(ice_txtime_ctx, tphrd_desc, 1, 90), + ICE_CTX_STORE(ice_txtime_ctx, qlen, 13, 91), + ICE_CTX_STORE(ice_txtime_ctx, timer_num, 1, 104), + ICE_CTX_STORE(ice_txtime_ctx, txtime_ena_q, 1, 105), + ICE_CTX_STORE(ice_txtime_ctx, drbell_mode_32, 1, 106), + ICE_CTX_STORE(ice_txtime_ctx, ts_res, 4, 107), + ICE_CTX_STORE(ice_txtime_ctx, ts_round_type, 2, 111), + ICE_CTX_STORE(ice_txtime_ctx, ts_pacing_slot, 3, 113), + ICE_CTX_STORE(ice_txtime_ctx, merging_ena, 1, 116), + ICE_CTX_STORE(ice_txtime_ctx, ts_fetch_prof_id, 4, 117), + ICE_CTX_STORE(ice_txtime_ctx, ts_fetch_cache_line_aln_thld, 4, 121), + ICE_CTX_STORE(ice_txtime_ctx, tx_pipe_delay_mode, 1, 125), +}; + +/** + * ice_pack_txtime_ctx - pack Tx time queue context into a HW buffer + * @ctx: the Tx time queue context to pack + * @buf: the HW buffer to pack into + * + * Pack the Tx time queue context from the CPU-friendly unpacked buffer into + * its bit-packed HW layout. + */ +void ice_pack_txtime_ctx(const struct ice_txtime_ctx *ctx, + ice_txtime_ctx_buf_t *buf) +{ + pack_fields(buf, sizeof(*buf), ctx, ice_txtime_ctx_fields, + QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST); +} + /* Sideband Queue command wrappers */ /** @@ -1471,7 +1786,7 @@ ice_sbq_send_cmd(struct ice_hw *hw, struct ice_sbq_cmd_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd) { return ice_sq_send_cmd(hw, ice_get_sbq(hw), - (struct ice_aq_desc *)desc, buf, buf_size, cd); + (struct libie_aq_desc *)desc, buf, buf_size, cd); } /** @@ -1556,10 +1871,10 @@ static bool ice_should_retry_sq_send_cmd(u16 opcode) */ static int ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq, - struct ice_aq_desc *desc, void *buf, u16 buf_size, + struct libie_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd) { - struct ice_aq_desc desc_cpy; + struct libie_aq_desc desc_cpy; bool is_cmd_for_retry; u8 idx = 0; u16 opcode; @@ -1580,7 +1895,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq, status = ice_sq_send_cmd(hw, cq, desc, buf, buf_size, cd); if (!is_cmd_for_retry || !status || - hw->adminq.sq_last_status != ICE_AQ_RC_EBUSY) + hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY) break; memcpy(desc, &desc_cpy, sizeof(desc_cpy)); @@ -1603,10 +1918,10 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq, * Helper function to send FW Admin Queue commands to the FW Admin Queue. */ int -ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf, +ice_aq_send_cmd(struct ice_hw *hw, struct libie_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd) { - struct ice_aqc_req_res *cmd = &desc->params.res_owner; + struct libie_aqc_req_res *cmd = libie_aq_raw(desc); bool lock_acquired = false; int status; @@ -1637,7 +1952,7 @@ ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf, case ice_aqc_opc_get_recipe_to_profile: break; case ice_aqc_opc_release_res: - if (le16_to_cpu(cmd->res_id) == ICE_AQC_RES_ID_GLBL_LOCK) + if (le16_to_cpu(cmd->res_id) == LIBIE_AQC_RES_ID_GLBL_LOCK) break; fallthrough; default: @@ -1662,8 +1977,8 @@ ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf, */ int ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd) { - struct ice_aqc_get_ver *resp; - struct ice_aq_desc desc; + struct libie_aqc_get_ver *resp; + struct libie_aq_desc desc; int status; resp = &desc.params.get_ver; @@ -1699,8 +2014,8 @@ int ice_aq_send_driver_ver(struct ice_hw *hw, struct ice_driver_ver *dv, struct ice_sq_cd *cd) { - struct ice_aqc_driver_ver *cmd; - struct ice_aq_desc desc; + struct libie_aqc_driver_ver *cmd; + struct libie_aq_desc desc; u16 len; cmd = &desc.params.driver_ver; @@ -1710,7 +2025,7 @@ ice_aq_send_driver_ver(struct ice_hw *hw, struct ice_driver_ver *dv, ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_driver_ver); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->major_ver = dv->major_ver; cmd->minor_ver = dv->minor_ver; cmd->build_ver = dv->build_ver; @@ -1735,9 +2050,9 @@ ice_aq_send_driver_ver(struct ice_hw *hw, struct ice_driver_ver *dv, int ice_aq_q_shutdown(struct ice_hw *hw, bool unloading) { struct ice_aqc_q_shutdown *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.q_shutdown; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_q_shutdown); @@ -1778,8 +2093,8 @@ ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res, enum ice_aq_res_access_type access, u8 sdp_number, u32 *timeout, struct ice_sq_cd *cd) { - struct ice_aqc_req_res *cmd_resp; - struct ice_aq_desc desc; + struct libie_aqc_req_res *cmd_resp; + struct libie_aq_desc desc; int status; cmd_resp = &desc.params.res_owner; @@ -1801,20 +2116,20 @@ ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res, /* Global config lock response utilizes an additional status field. * * If the Global config lock resource is held by some other driver, the - * command completes with ICE_AQ_RES_GLBL_IN_PROG in the status field + * command completes with LIBIE_AQ_RES_GLBL_IN_PROG in the status field * and the timeout field indicates the maximum time the current owner * of the resource has to free it. */ if (res == ICE_GLOBAL_CFG_LOCK_RES_ID) { - if (le16_to_cpu(cmd_resp->status) == ICE_AQ_RES_GLBL_SUCCESS) { + if (le16_to_cpu(cmd_resp->status) == LIBIE_AQ_RES_GLBL_SUCCESS) { *timeout = le32_to_cpu(cmd_resp->timeout); return 0; } else if (le16_to_cpu(cmd_resp->status) == - ICE_AQ_RES_GLBL_IN_PROG) { + LIBIE_AQ_RES_GLBL_IN_PROG) { *timeout = le32_to_cpu(cmd_resp->timeout); return -EIO; } else if (le16_to_cpu(cmd_resp->status) == - ICE_AQ_RES_GLBL_DONE) { + LIBIE_AQ_RES_GLBL_DONE) { return -EALREADY; } @@ -1827,7 +2142,7 @@ ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res, * with a busy return value and the timeout field indicates the maximum * time the current owner of the resource has to free it. */ - if (!status || hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) + if (!status || hw->adminq.sq_last_status == LIBIE_AQ_RC_EBUSY) *timeout = le32_to_cpu(cmd_resp->timeout); return status; @@ -1846,8 +2161,8 @@ static int ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8 sdp_number, struct ice_sq_cd *cd) { - struct ice_aqc_req_res *cmd; - struct ice_aq_desc desc; + struct libie_aqc_req_res *cmd; + struct libie_aq_desc desc; cmd = &desc.params.res_owner; @@ -1956,16 +2271,16 @@ int ice_aq_alloc_free_res(struct ice_hw *hw, enum ice_adminq_opc opc) { struct ice_aqc_alloc_free_res_cmd *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.sw_res_ctrl; + cmd = libie_aq_raw(&desc); if (!buf || buf_size < flex_array_size(buf, elem, 1)) return -EINVAL; ice_fill_dflt_direct_cmd_desc(&desc, opc); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->num_entries = cpu_to_le16(1); @@ -2079,7 +2394,7 @@ static u32 ice_get_num_per_func(struct ice_hw *hw, u32 max) */ static bool ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, - struct ice_aqc_list_caps_elem *elem, const char *prefix) + struct libie_aqc_list_caps_elem *elem, const char *prefix) { u32 logical_id = le32_to_cpu(elem->logical_id); u32 phys_id = le32_to_cpu(elem->phys_id); @@ -2088,17 +2403,17 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, bool found = true; switch (cap) { - case ICE_AQC_CAPS_VALID_FUNCTIONS: + case LIBIE_AQC_CAPS_VALID_FUNCTIONS: caps->valid_functions = number; ice_debug(hw, ICE_DBG_INIT, "%s: valid_functions (bitmap) = %d\n", prefix, caps->valid_functions); break; - case ICE_AQC_CAPS_SRIOV: + case LIBIE_AQC_CAPS_SRIOV: caps->sr_iov_1_1 = (number == 1); ice_debug(hw, ICE_DBG_INIT, "%s: sr_iov_1_1 = %d\n", prefix, caps->sr_iov_1_1); break; - case ICE_AQC_CAPS_DCB: + case LIBIE_AQC_CAPS_DCB: caps->dcb = (number == 1); caps->active_tc_bitmap = logical_id; caps->maxtc = phys_id; @@ -2107,7 +2422,7 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, caps->active_tc_bitmap); ice_debug(hw, ICE_DBG_INIT, "%s: maxtc = %d\n", prefix, caps->maxtc); break; - case ICE_AQC_CAPS_RSS: + case LIBIE_AQC_CAPS_RSS: caps->rss_table_size = number; caps->rss_table_entry_width = logical_id; ice_debug(hw, ICE_DBG_INIT, "%s: rss_table_size = %d\n", prefix, @@ -2115,7 +2430,7 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, ice_debug(hw, ICE_DBG_INIT, "%s: rss_table_entry_width = %d\n", prefix, caps->rss_table_entry_width); break; - case ICE_AQC_CAPS_RXQS: + case LIBIE_AQC_CAPS_RXQS: caps->num_rxq = number; caps->rxq_first_id = phys_id; ice_debug(hw, ICE_DBG_INIT, "%s: num_rxq = %d\n", prefix, @@ -2123,7 +2438,7 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, ice_debug(hw, ICE_DBG_INIT, "%s: rxq_first_id = %d\n", prefix, caps->rxq_first_id); break; - case ICE_AQC_CAPS_TXQS: + case LIBIE_AQC_CAPS_TXQS: caps->num_txq = number; caps->txq_first_id = phys_id; ice_debug(hw, ICE_DBG_INIT, "%s: num_txq = %d\n", prefix, @@ -2131,7 +2446,7 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, ice_debug(hw, ICE_DBG_INIT, "%s: txq_first_id = %d\n", prefix, caps->txq_first_id); break; - case ICE_AQC_CAPS_MSIX: + case LIBIE_AQC_CAPS_MSIX: caps->num_msix_vectors = number; caps->msix_vector_first_id = phys_id; ice_debug(hw, ICE_DBG_INIT, "%s: num_msix_vectors = %d\n", prefix, @@ -2139,56 +2454,59 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps, ice_debug(hw, ICE_DBG_INIT, "%s: msix_vector_first_id = %d\n", prefix, caps->msix_vector_first_id); break; - case ICE_AQC_CAPS_PENDING_NVM_VER: + case LIBIE_AQC_CAPS_PENDING_NVM_VER: caps->nvm_update_pending_nvm = true; ice_debug(hw, ICE_DBG_INIT, "%s: update_pending_nvm\n", prefix); break; - case ICE_AQC_CAPS_PENDING_OROM_VER: + case LIBIE_AQC_CAPS_PENDING_OROM_VER: caps->nvm_update_pending_orom = true; ice_debug(hw, ICE_DBG_INIT, "%s: update_pending_orom\n", prefix); break; - case ICE_AQC_CAPS_PENDING_NET_VER: + case LIBIE_AQC_CAPS_PENDING_NET_VER: caps->nvm_update_pending_netlist = true; ice_debug(hw, ICE_DBG_INIT, "%s: update_pending_netlist\n", prefix); break; - case ICE_AQC_CAPS_NVM_MGMT: + case LIBIE_AQC_CAPS_NVM_MGMT: caps->nvm_unified_update = (number & ICE_NVM_MGMT_UNIFIED_UPD_SUPPORT) ? true : false; ice_debug(hw, ICE_DBG_INIT, "%s: nvm_unified_update = %d\n", prefix, caps->nvm_unified_update); break; - case ICE_AQC_CAPS_RDMA: + case LIBIE_AQC_CAPS_RDMA: if (IS_ENABLED(CONFIG_INFINIBAND_IRDMA)) caps->rdma = (number == 1); ice_debug(hw, ICE_DBG_INIT, "%s: rdma = %d\n", prefix, caps->rdma); break; - case ICE_AQC_CAPS_MAX_MTU: + case LIBIE_AQC_CAPS_MAX_MTU: caps->max_mtu = number; ice_debug(hw, ICE_DBG_INIT, "%s: max_mtu = %d\n", prefix, caps->max_mtu); break; - case ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE: + case LIBIE_AQC_CAPS_PCIE_RESET_AVOIDANCE: caps->pcie_reset_avoidance = (number > 0); ice_debug(hw, ICE_DBG_INIT, "%s: pcie_reset_avoidance = %d\n", prefix, caps->pcie_reset_avoidance); break; - case ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT: + case LIBIE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT: caps->reset_restrict_support = (number == 1); ice_debug(hw, ICE_DBG_INIT, "%s: reset_restrict_support = %d\n", prefix, caps->reset_restrict_support); break; - case ICE_AQC_CAPS_FW_LAG_SUPPORT: - caps->roce_lag = !!(number & ICE_AQC_BIT_ROCEV2_LAG); + case LIBIE_AQC_CAPS_FW_LAG_SUPPORT: + caps->roce_lag = number & LIBIE_AQC_BIT_ROCEV2_LAG; ice_debug(hw, ICE_DBG_INIT, "%s: roce_lag = %u\n", prefix, caps->roce_lag); - caps->sriov_lag = !!(number & ICE_AQC_BIT_SRIOV_LAG); + caps->sriov_lag = number & LIBIE_AQC_BIT_SRIOV_LAG; ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n", prefix, caps->sriov_lag); + caps->sriov_aa_lag = number & LIBIE_AQC_BIT_SRIOV_AA_LAG; + ice_debug(hw, ICE_DBG_INIT, "%s: sriov_aa_lag = %u\n", + prefix, caps->sriov_aa_lag); break; - case ICE_AQC_CAPS_TX_SCHED_TOPO_COMP_MODE: + case LIBIE_AQC_CAPS_TX_SCHED_TOPO_COMP_MODE: caps->tx_sched_topo_comp_mode_en = (number == 1); break; default: @@ -2242,7 +2560,7 @@ ice_recalc_port_limited_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps) */ static void ice_parse_vf_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { u32 logical_id = le32_to_cpu(cap->logical_id); u32 number = le32_to_cpu(cap->number); @@ -2265,7 +2583,7 @@ ice_parse_vf_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, */ static void ice_parse_vsi_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { func_p->guar_num_vsi = ice_get_num_per_func(hw, ICE_MAX_VSI); ice_debug(hw, ICE_DBG_INIT, "func caps: guar_num_vsi (fw) = %d\n", @@ -2284,7 +2602,7 @@ ice_parse_vsi_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, */ static void ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { struct ice_ts_func_info *info = &func_p->ts_func_info; u32 number = le32_to_cpu(cap->number); @@ -2301,12 +2619,12 @@ ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, info->clk_freq = FIELD_GET(ICE_TS_CLK_FREQ_M, number); info->clk_src = ((number & ICE_TS_CLK_SRC_M) != 0); } else { - info->clk_freq = ICE_TIME_REF_FREQ_156_250; - info->clk_src = ICE_CLK_SRC_TCXO; + info->clk_freq = ICE_TSPLL_FREQ_156_250; + info->clk_src = ICE_CLK_SRC_TIME_REF; } - if (info->clk_freq < NUM_ICE_TIME_REF_FREQ) { - info->time_ref = (enum ice_time_ref_freq)info->clk_freq; + if (info->clk_freq < NUM_ICE_TSPLL_FREQ) { + info->time_ref = (enum ice_tspll_freq)info->clk_freq; } else { /* Unknown clock frequency, so assume a (probably incorrect) * default to avoid out-of-bounds look ups of frequency @@ -2314,7 +2632,7 @@ ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, */ ice_debug(hw, ICE_DBG_INIT, "1588 func caps: unknown clock frequency %u\n", info->clk_freq); - info->time_ref = ICE_TIME_REF_FREQ_25_000; + info->time_ref = ICE_TSPLL_FREQ_25_000; } ice_debug(hw, ICE_DBG_INIT, "func caps: ieee_1588 = %u\n", @@ -2383,7 +2701,7 @@ static void ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, void *buf, u32 cap_count) { - struct ice_aqc_list_caps_elem *cap_resp; + struct libie_aqc_list_caps_elem *cap_resp; u32 i; cap_resp = buf; @@ -2398,16 +2716,16 @@ ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, &cap_resp[i], "func caps"); switch (cap) { - case ICE_AQC_CAPS_VF: + case LIBIE_AQC_CAPS_VF: ice_parse_vf_func_caps(hw, func_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_VSI: + case LIBIE_AQC_CAPS_VSI: ice_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_1588: + case LIBIE_AQC_CAPS_1588: ice_parse_1588_func_caps(hw, func_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_FD: + case LIBIE_AQC_CAPS_FD: ice_parse_fdir_func_caps(hw, func_p); break; default: @@ -2451,7 +2769,7 @@ static int ice_func_id_to_logical_id(u32 active_function_bitmap, u8 pf_id) */ static void ice_parse_valid_functions_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { u32 number = le32_to_cpu(cap->number); @@ -2472,7 +2790,7 @@ ice_parse_valid_functions_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_vf_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { u32 number = le32_to_cpu(cap->number); @@ -2491,7 +2809,7 @@ ice_parse_vf_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_vsi_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { u32 number = le32_to_cpu(cap->number); @@ -2510,7 +2828,7 @@ ice_parse_vsi_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { struct ice_ts_dev_info *info = &dev_p->ts_dev_info; u32 logical_id = le32_to_cpu(cap->logical_id); @@ -2571,7 +2889,7 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { u32 number = le32_to_cpu(cap->number); @@ -2591,7 +2909,7 @@ ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_sensor_reading_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { dev_p->supported_sensors = le32_to_cpu(cap->number); @@ -2610,7 +2928,7 @@ ice_parse_sensor_reading_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, */ static void ice_parse_nac_topo_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, - struct ice_aqc_list_caps_elem *cap) + struct libie_aqc_list_caps_elem *cap) { dev_p->nac_topo.mode = le32_to_cpu(cap->number); dev_p->nac_topo.id = le32_to_cpu(cap->phys_id) & ICE_NAC_TOPO_ID_M; @@ -2646,7 +2964,7 @@ static void ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, void *buf, u32 cap_count) { - struct ice_aqc_list_caps_elem *cap_resp; + struct libie_aqc_list_caps_elem *cap_resp; u32 i; cap_resp = buf; @@ -2661,25 +2979,25 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, &cap_resp[i], "dev caps"); switch (cap) { - case ICE_AQC_CAPS_VALID_FUNCTIONS: + case LIBIE_AQC_CAPS_VALID_FUNCTIONS: ice_parse_valid_functions_cap(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_VF: + case LIBIE_AQC_CAPS_VF: ice_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_VSI: + case LIBIE_AQC_CAPS_VSI: ice_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_1588: + case LIBIE_AQC_CAPS_1588: ice_parse_1588_dev_caps(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_FD: + case LIBIE_AQC_CAPS_FD: ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_SENSOR_READING: + case LIBIE_AQC_CAPS_SENSOR_READING: ice_parse_sensor_reading_cap(hw, dev_p, &cap_resp[i]); break; - case ICE_AQC_CAPS_NAC_TOPOLOGY: + case LIBIE_AQC_CAPS_NAC_TOPOLOGY: ice_parse_nac_topo_dev_caps(hw, dev_p, &cap_resp[i]); break; default: @@ -2799,8 +3117,8 @@ int ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, enum ice_adminq_opc opc, struct ice_sq_cd *cd) { - struct ice_aqc_list_caps *cmd; - struct ice_aq_desc desc; + struct libie_aqc_list_caps *cmd; + struct libie_aq_desc desc; int status; cmd = &desc.params.get_cap; @@ -2841,7 +3159,7 @@ ice_discover_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_caps) * device will return, we can simply send a 4KB buffer, the maximum * possible size that firmware can return. */ - cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct ice_aqc_list_caps_elem); + cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct libie_aqc_list_caps_elem); status = ice_aq_list_caps(hw, cbuf, ICE_AQ_MAX_BUF_LEN, &cap_count, ice_aqc_opc_list_dev_caps, NULL); @@ -2875,7 +3193,7 @@ ice_discover_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_caps) * device will return, we can simply send a 4KB buffer, the maximum * possible size that firmware can return. */ - cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct ice_aqc_list_caps_elem); + cap_count = ICE_AQ_MAX_BUF_LEN / sizeof(struct libie_aqc_list_caps_elem); status = ice_aq_list_caps(hw, cbuf, ICE_AQ_MAX_BUF_LEN, &cap_count, ice_aqc_opc_list_func_caps, NULL); @@ -2984,9 +3302,9 @@ ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, struct ice_sq_cd *cd) { struct ice_aqc_manage_mac_write *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.mac_write; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_manage_mac_write); cmd->flags = flags; @@ -3003,10 +3321,12 @@ ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, */ static int ice_aq_clear_pxe_mode(struct ice_hw *hw) { - struct ice_aq_desc desc; + struct ice_aqc_clear_pxe *cmd; + struct libie_aq_desc desc; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_pxe_mode); - desc.params.clear_pxe.rx_cnt = ICE_AQC_CLEAR_PXE_RX_CNT; + cmd->rx_cnt = ICE_AQC_CLEAR_PXE_RX_CNT; return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); } @@ -3039,10 +3359,10 @@ ice_aq_set_port_params(struct ice_port_info *pi, bool double_vlan, { struct ice_aqc_set_port_params *cmd; struct ice_hw *hw = pi->hw; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 cmd_flags = 0; - cmd = &desc.params.set_port_params; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_params); if (double_vlan) @@ -3279,7 +3599,8 @@ int ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct ice_aqc_set_phy_cfg *cmd; + struct libie_aq_desc desc; int status; if (!cfg) @@ -3294,8 +3615,9 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi, } ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg); - desc.params.set_phy.lport_num = pi->lport; - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + cmd = libie_aq_raw(&desc); + cmd->lport_num = pi->lport; + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); ice_debug(hw, ICE_DBG_LINK, "set phy cfg\n"); ice_debug(hw, ICE_DBG_LINK, " phy_type_low = 0x%llx\n", @@ -3311,7 +3633,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi, cfg->link_fec_opt); status = ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd); - if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE) + if (hw->adminq.sq_last_status == LIBIE_AQ_RC_EMODE) status = 0; if (!status) @@ -3368,17 +3690,17 @@ int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code, { struct ice_aqc_dnl_call_command *cmd; struct ice_aqc_dnl_call buf = {}; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int err; buf.sto.txrx_equa_reqs.data_in = cpu_to_le16(data_in); buf.sto.txrx_equa_reqs.op_code_serdes_sel = cpu_to_le16(op_code | (serdes_num & 0xF)); - cmd = &desc.params.dnl_call; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dnl_call); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_BUF | - ICE_AQ_FLAG_RD | - ICE_AQ_FLAG_SI); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_BUF | + LIBIE_AQ_FLAG_RD | + LIBIE_AQ_FLAG_SI); desc.datalen = cpu_to_le16(sizeof(struct ice_aqc_dnl_call)); cmd->activity_id = cpu_to_le16(ICE_AQC_ACT_ID_DNL); @@ -3416,7 +3738,7 @@ static const u32 fec_reg[][ICE_FEC_MAX] = { int ice_aq_get_fec_stats(struct ice_hw *hw, u16 pcs_quad, u16 pcs_port, enum ice_fec_stats_types fec_type, u32 *output) { - u16 flag = (ICE_AQ_FLAG_RD | ICE_AQ_FLAG_BUF | ICE_AQ_FLAG_SI); + u16 flag = (LIBIE_AQ_FLAG_RD | LIBIE_AQ_FLAG_BUF | LIBIE_AQ_FLAG_SI); struct ice_sbq_msg_input msg = {}; u32 receiver_id, reg_offset; int err; @@ -3839,9 +4161,9 @@ ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, struct ice_sq_cd *cd) { struct ice_aqc_restart_an *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.restart_an; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_restart_an); @@ -3869,9 +4191,9 @@ ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask, struct ice_sq_cd *cd) { struct ice_aqc_set_event_mask *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.set_event_mask; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_event_mask); @@ -3893,9 +4215,9 @@ int ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd) { struct ice_aqc_set_mac_lb *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.set_mac_lb; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_mac_lb); if (ena_lpbk) @@ -3918,9 +4240,9 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode, { struct ice_aqc_set_port_id_led *cmd; struct ice_hw *hw = pi->hw; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.set_port_id_led; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_id_led); @@ -3956,7 +4278,7 @@ ice_aq_get_port_options(struct ice_hw *hw, u8 *pending_option_idx, bool *pending_option_valid) { struct ice_aqc_get_port_options *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; u8 i; @@ -3964,7 +4286,7 @@ ice_aq_get_port_options(struct ice_hw *hw, if (*option_count < ICE_AQC_PORT_OPT_COUNT_M) return -EINVAL; - cmd = &desc.params.get_port_options; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_port_options); if (lport_valid) @@ -4030,12 +4352,12 @@ ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid, u8 new_option) { struct ice_aqc_set_port_option *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (new_option > ICE_AQC_PORT_OPT_COUNT_M) return -EINVAL; - cmd = &desc.params.set_port_option; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_option); if (lport_valid) @@ -4080,7 +4402,7 @@ int ice_get_phy_lane_number(struct ice_hw *hw) speed = options[active_idx].max_lane_speed; /* If we don't get speed for this lane, it's unoccupied */ - if (speed > ICE_AQC_PORT_OPT_MAX_LANE_200G) + if (speed > ICE_AQC_PORT_OPT_MAX_LANE_40G) continue; if (hw->pf_id == lport) { @@ -4121,7 +4443,7 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr, bool write, struct ice_sq_cd *cd) { struct ice_aqc_sff_eeprom *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 i2c_bus_addr; int status; @@ -4129,8 +4451,8 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr, return -EINVAL; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_sff_eeprom); - cmd = &desc.params.read_write_sff_param; - desc.flags = cpu_to_le16(ICE_AQ_FLAG_RD); + cmd = libie_aq_raw(&desc); + desc.flags = cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->lport_num = (u8)(lport & 0xff); cmd->lport_num_valid = (u8)((lport >> 8) & 0x01); i2c_bus_addr = FIELD_PREP(ICE_AQC_SFF_I2CBUS_7BIT_M, bus_addr >> 1) | @@ -4190,7 +4512,7 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, struct ice_aqc_get_set_rss_lut *desc_params; enum ice_aqc_lut_flags flags; enum ice_lut_size lut_size; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u8 *lut = params->lut; @@ -4206,9 +4528,9 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, opcode = set ? ice_aqc_opc_set_rss_lut : ice_aqc_opc_get_rss_lut; ice_fill_dflt_direct_cmd_desc(&desc, opcode); if (set) - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); - desc_params = &desc.params.get_set_rss_lut; + desc_params = libie_aq_raw(&desc); vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); desc_params->vsi_id = cpu_to_le16(vsi_id | ICE_AQC_RSS_VSI_VALID); @@ -4263,16 +4585,16 @@ __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id, { struct ice_aqc_get_set_rss_key *desc_params; u16 key_size = sizeof(*key); - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (set) { ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_key); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); } else { ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_key); } - desc_params = &desc.params.get_set_rss_key; + desc_params = libie_aq_raw(&desc); desc_params->vsi_id = cpu_to_le16(vsi_id | ICE_AQC_RSS_VSI_VALID); return ice_aq_send_cmd(hw, &desc, key, key_size, NULL); @@ -4344,10 +4666,10 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps, { struct ice_aqc_add_tx_qgrp *list; struct ice_aqc_add_txqs *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 i, sum_size = 0; - cmd = &desc.params.add_txqs; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_txqs); @@ -4366,7 +4688,7 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps, if (buf_size != sum_size) return -EINVAL; - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->num_qgrps = num_qgrps; @@ -4393,12 +4715,12 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, { struct ice_aqc_dis_txq_item *item; struct ice_aqc_dis_txqs *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 vmvf_and_timeout; u16 i, sz = 0; int status; - cmd = &desc.params.dis_txqs; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dis_txqs); /* qg_list can be NULL only in VM/VF reset flow */ @@ -4439,7 +4761,7 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, /* set RD bit to indicate that command buffer is provided by the driver * and it needs to be read by the firmware */ - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); for (i = 0, item = qg_list; i < num_qgrps; i++) { u16 item_size = struct_size(item, q_id, item->num_qs); @@ -4471,40 +4793,42 @@ do_aq: } /** - * ice_aq_cfg_lan_txq + * ice_aq_cfg_lan_txq - send AQ command 0x0C32 to FW * @hw: pointer to the hardware structure * @buf: buffer for command * @buf_size: size of buffer in bytes * @num_qs: number of queues being configured * @oldport: origination lport * @newport: destination lport + * @mode: cmd_type for move to use * @cd: pointer to command details structure or NULL * * Move/Configure LAN Tx queue (0x0C32) * - * There is a better AQ command to use for moving nodes, so only coding - * this one for configuring the node. + * Return: Zero on success, associated error code on failure. */ int ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf, u16 buf_size, u16 num_qs, u8 oldport, u8 newport, - struct ice_sq_cd *cd) + u8 mode, struct ice_sq_cd *cd) { struct ice_aqc_cfg_txqs *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.cfg_txqs; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_cfg_txqs); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); if (!buf) return -EINVAL; - cmd->cmd_type = ICE_AQC_Q_CFG_TC_CHNG; + cmd->cmd_type = mode; cmd->num_qs = num_qs; cmd->port_num_chng = (oldport & ICE_AQC_Q_CFG_SRC_PRT_M); cmd->port_num_chng |= FIELD_PREP(ICE_AQC_Q_CFG_DST_PRT_M, newport); + cmd->port_num_chng |= FIELD_PREP(ICE_AQC_Q_CFG_MODE_M, + ICE_AQC_Q_CFG_MODE_KEEP_OWN); cmd->time_out = FIELD_PREP(ICE_AQC_Q_CFG_TIMEOUT_M, 5); cmd->blocked_cgds = 0; @@ -4532,10 +4856,10 @@ ice_aq_add_rdma_qsets(struct ice_hw *hw, u8 num_qset_grps, { struct ice_aqc_add_rdma_qset_data *list; struct ice_aqc_add_rdma_qset *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 i, sum_size = 0; - cmd = &desc.params.add_rdma_qset; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_rdma_qset); @@ -4553,13 +4877,53 @@ ice_aq_add_rdma_qsets(struct ice_hw *hw, u8 num_qset_grps, if (buf_size != sum_size) return -EINVAL; - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->num_qset_grps = num_qset_grps; return ice_aq_send_cmd(hw, &desc, qset_list, buf_size, cd); } +/** + * ice_aq_set_txtimeq - set Tx time queues + * @hw: pointer to the hardware structure + * @txtimeq: first Tx time queue id to configure + * @q_count: number of queues to configure + * @txtime_qg: queue group to be set + * @buf_size: size of buffer for indirect command + * @cd: pointer to command details structure or NULL + * + * Set Tx Time queue (0x0C35) + * Return: 0 on success or negative value on failure. + */ +int +ice_aq_set_txtimeq(struct ice_hw *hw, u16 txtimeq, u8 q_count, + struct ice_aqc_set_txtime_qgrp *txtime_qg, u16 buf_size, + struct ice_sq_cd *cd) +{ + struct ice_aqc_set_txtimeqs *cmd; + struct libie_aq_desc desc; + u16 size; + + if (!txtime_qg || txtimeq > ICE_TXTIME_MAX_QUEUE || + q_count < 1 || q_count > ICE_SET_TXTIME_MAX_Q_AMOUNT) + return -EINVAL; + + size = struct_size(txtime_qg, txtimeqs, q_count); + if (buf_size != size) + return -EINVAL; + + cmd = libie_aq_raw(&desc); + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_txtimeqs); + + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); + + cmd->q_id = cpu_to_le16(txtimeq); + cmd->q_amount = cpu_to_le16(q_count); + return ice_aq_send_cmd(hw, &desc, txtime_qg, buf_size, cd); +} + /* End of FW Admin Queue command wrappers */ /** @@ -4971,6 +5335,32 @@ ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid, } /** + * ice_aq_get_cgu_input_pin_measure - get input pin signal measurements + * @hw: pointer to the HW struct + * @dpll_idx: index of dpll to be measured + * @meas: array to be filled with results + * @meas_num: max number of results array can hold + * + * Get CGU measurements (0x0C59) of phase and frequency offsets for input + * pins on given dpll. + * + * Return: 0 on success or negative value on failure. + */ +int ice_aq_get_cgu_input_pin_measure(struct ice_hw *hw, u8 dpll_idx, + struct ice_cgu_input_measure *meas, + u16 meas_num) +{ + struct ice_aqc_get_cgu_input_measure *cmd; + struct libie_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_measure); + cmd = libie_aq_raw(&desc); + cmd->dpll_idx_opt = dpll_idx & ICE_AQC_GET_CGU_IN_MEAS_DPLL_IDX_M; + + return ice_aq_send_cmd(hw, &desc, meas, meas_num * sizeof(*meas), NULL); +} + +/** * ice_aq_get_cgu_abilities - get cgu abilities * @hw: pointer to the HW struct * @abilities: CGU abilities @@ -4982,7 +5372,7 @@ int ice_aq_get_cgu_abilities(struct ice_hw *hw, struct ice_aqc_get_cgu_abilities *abilities) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_abilities); return ice_aq_send_cmd(hw, &desc, abilities, sizeof(*abilities), NULL); @@ -5005,10 +5395,10 @@ ice_aq_set_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 flags1, u8 flags2, u32 freq, s32 phase_delay) { struct ice_aqc_set_cgu_input_config *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_input_config); - cmd = &desc.params.set_cgu_input_config; + cmd = libie_aq_raw(&desc); cmd->input_idx = input_idx; cmd->flags1 = flags1; cmd->flags2 = flags2; @@ -5037,11 +5427,11 @@ ice_aq_get_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 *status, u8 *type, u8 *flags1, u8 *flags2, u32 *freq, s32 *phase_delay) { struct ice_aqc_get_cgu_input_config *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int ret; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_config); - cmd = &desc.params.get_cgu_input_config; + cmd = libie_aq_raw(&desc); cmd->input_idx = input_idx; ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); @@ -5080,10 +5470,10 @@ ice_aq_set_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 flags, u8 src_sel, u32 freq, s32 phase_delay) { struct ice_aqc_set_cgu_output_config *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_output_config); - cmd = &desc.params.set_cgu_output_config; + cmd = libie_aq_raw(&desc); cmd->output_idx = output_idx; cmd->flags = flags; cmd->src_sel = src_sel; @@ -5110,11 +5500,11 @@ ice_aq_get_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 *flags, u8 *src_sel, u32 *freq, u32 *src_freq) { struct ice_aqc_get_cgu_output_config *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int ret; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_output_config); - cmd = &desc.params.get_cgu_output_config; + cmd = libie_aq_raw(&desc); cmd->output_idx = output_idx; ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); @@ -5151,11 +5541,11 @@ ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state, u8 *eec_mode) { struct ice_aqc_get_cgu_dpll_status *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_dpll_status); - cmd = &desc.params.get_cgu_dpll_status; + cmd = libie_aq_raw(&desc); cmd->dpll_num = dpll_num; status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); @@ -5189,10 +5579,10 @@ ice_aq_set_cgu_dpll_config(struct ice_hw *hw, u8 dpll_num, u8 ref_state, u8 config, u8 eec_mode) { struct ice_aqc_set_cgu_dpll_config *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_dpll_config); - cmd = &desc.params.set_cgu_dpll_config; + cmd = libie_aq_raw(&desc); cmd->dpll_num = dpll_num; cmd->ref_state = ref_state; cmd->config = config; @@ -5216,10 +5606,10 @@ ice_aq_set_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, u8 ref_priority) { struct ice_aqc_set_cgu_ref_prio *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_ref_prio); - cmd = &desc.params.set_cgu_ref_prio; + cmd = libie_aq_raw(&desc); cmd->dpll_num = dpll_num; cmd->ref_idx = ref_idx; cmd->ref_priority = ref_priority; @@ -5242,11 +5632,11 @@ ice_aq_get_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, u8 *ref_prio) { struct ice_aqc_get_cgu_ref_prio *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_ref_prio); - cmd = &desc.params.get_cgu_ref_prio; + cmd = libie_aq_raw(&desc); cmd->dpll_num = dpll_num; cmd->ref_idx = ref_idx; @@ -5272,11 +5662,11 @@ ice_aq_get_cgu_info(struct ice_hw *hw, u32 *cgu_id, u32 *cgu_cfg_ver, u32 *cgu_fw_ver) { struct ice_aqc_get_cgu_info *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_info); - cmd = &desc.params.get_cgu_info; + cmd = libie_aq_raw(&desc); status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); if (!status) { @@ -5303,11 +5693,11 @@ ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, u32 *freq) { struct ice_aqc_set_phy_rec_clk_out *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_rec_clk_out); - cmd = &desc.params.set_phy_rec_clk_out; + cmd = libie_aq_raw(&desc); cmd->phy_output = phy_output; cmd->port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; cmd->flags = enable & ICE_AQC_SET_PHY_REC_CLK_OUT_OUT_EN; @@ -5336,11 +5726,11 @@ ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num, u8 *flags, u16 *node_handle) { struct ice_aqc_get_phy_rec_clk_out *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_phy_rec_clk_out); - cmd = &desc.params.get_phy_rec_clk_out; + cmd = libie_aq_raw(&desc); cmd->phy_output = *phy_output; status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); @@ -5368,11 +5758,11 @@ int ice_aq_get_sensor_reading(struct ice_hw *hw, struct ice_aqc_get_sensor_reading_resp *data) { struct ice_aqc_get_sensor_reading *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sensor_reading); - cmd = &desc.params.get_sensor_reading; + cmd = libie_aq_raw(&desc); #define ICE_INTERNAL_TEMP_SENSOR_FORMAT 0 #define ICE_INTERNAL_TEMP_SENSOR 0 cmd->sensor = ICE_INTERNAL_TEMP_SENSOR; @@ -5380,7 +5770,7 @@ int ice_aq_get_sensor_reading(struct ice_hw *hw, status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); if (!status) - memcpy(data, &desc.params.get_sensor_reading_resp, + memcpy(data, &desc.params.raw, sizeof(*data)); return status; @@ -5577,13 +5967,13 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, u16 bus_addr, __le16 addr, u8 params, u8 *data, struct ice_sq_cd *cd) { - struct ice_aq_desc desc = { 0 }; + struct libie_aq_desc desc = { 0 }; struct ice_aqc_i2c *cmd; u8 data_size; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_read_i2c); - cmd = &desc.params.read_write_i2c; + cmd = libie_aq_raw(&desc); if (!data) return -EINVAL; @@ -5600,7 +5990,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, struct ice_aqc_read_i2c_resp *resp; u8 i; - resp = &desc.params.read_i2c_resp; + resp = libie_aq_raw(&desc); for (i = 0; i < data_size; i++) { *data = resp->i2c_data[i]; data++; @@ -5632,12 +6022,12 @@ ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, u16 bus_addr, __le16 addr, u8 params, const u8 *data, struct ice_sq_cd *cd) { - struct ice_aq_desc desc = { 0 }; + struct libie_aq_desc desc = { 0 }; struct ice_aqc_i2c *cmd; u8 data_size; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_write_i2c); - cmd = &desc.params.read_write_i2c; + cmd = libie_aq_raw(&desc); data_size = FIELD_GET(ICE_AQC_I2C_DATA_SIZE_M, params); @@ -5669,7 +6059,7 @@ ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, int ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) { struct ice_aqc_get_link_topo *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int err; u8 idx; @@ -5692,7 +6082,7 @@ int ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) /* If handle was not detected read it from the netlist */ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); - cmd = &desc.params.get_link_topo; + cmd = libie_aq_raw(&desc); cmd->addr.topo_params.node_type_ctx = ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL; cmd->addr.topo_params.index = idx; @@ -5702,13 +6092,12 @@ int ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) return -ENXIO; /* Verify if we found the right IO expander type */ - if (desc.params.get_link_topo.node_part_num != - ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) + if (cmd->node_part_num != ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) return -ENXIO; /* If present save the handle and return it */ hw->io_expander_handle = - le16_to_cpu(desc.params.get_link_topo.addr.handle); + le16_to_cpu(cmd->addr.handle); *pca9575_handle = hw->io_expander_handle; return 0; @@ -5759,11 +6148,11 @@ int ice_aq_set_gpio(struct ice_hw *hw, u16 gpio_ctrl_handle, u8 pin_idx, bool value, struct ice_sq_cd *cd) { + struct libie_aq_desc desc; struct ice_aqc_gpio *cmd; - struct ice_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_gpio); - cmd = &desc.params.read_write_gpio; + cmd = libie_aq_raw(&desc); cmd->gpio_ctrl_handle = cpu_to_le16(gpio_ctrl_handle); cmd->gpio_num = pin_idx; cmd->gpio_val = value ? 1 : 0; @@ -5786,12 +6175,12 @@ int ice_aq_get_gpio(struct ice_hw *hw, u16 gpio_ctrl_handle, u8 pin_idx, bool *value, struct ice_sq_cd *cd) { + struct libie_aq_desc desc; struct ice_aqc_gpio *cmd; - struct ice_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_gpio); - cmd = &desc.params.read_write_gpio; + cmd = libie_aq_raw(&desc); cmd->gpio_ctrl_handle = cpu_to_le16(gpio_ctrl_handle); cmd->gpio_num = pin_idx; @@ -5954,9 +6343,9 @@ bool ice_is_fw_health_report_supported(struct ice_hw *hw) int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source) { struct ice_aqc_set_health_status_cfg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.set_health_status_cfg; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_health_status_cfg); @@ -5980,16 +6369,16 @@ ice_aq_set_lldp_mib(struct ice_hw *hw, u8 mib_type, void *buf, u16 buf_size, struct ice_sq_cd *cd) { struct ice_aqc_lldp_set_local_mib *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.lldp_set_mib; + cmd = libie_aq_raw(&desc); if (buf_size == 0 || !buf) return -EINVAL; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_local_mib); - desc.flags |= cpu_to_le16((u16)ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_RD); desc.datalen = cpu_to_le16(buf_size); cmd->type = mib_type; @@ -6025,12 +6414,12 @@ bool ice_fw_supports_lldp_fltr_ctrl(struct ice_hw *hw) int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add) { struct ice_aqc_lldp_filter_ctrl *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (vsi->type != ICE_VSI_PF || !ice_fw_supports_lldp_fltr_ctrl(hw)) return -EOPNOTSUPP; - cmd = &desc.params.lldp_filter_ctrl; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_filter_ctrl); @@ -6050,7 +6439,7 @@ int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add) */ int ice_lldp_execute_pending_mib(struct ice_hw *hw) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_execute_pending_mib); @@ -6106,3 +6495,64 @@ u32 ice_get_link_speed(u16 index) return ice_aq_to_link_speed[index]; } + +/** + * ice_read_cgu_reg - Read a CGU register + * @hw: Pointer to the HW struct + * @addr: Register address to read + * @val: Storage for register value read + * + * Read the contents of a register of the Clock Generation Unit. Only + * applicable to E82X devices. + * + * Return: 0 on success, other error codes when failed to read from CGU. + */ +int ice_read_cgu_reg(struct ice_hw *hw, u32 addr, u32 *val) +{ + struct ice_sbq_msg_input cgu_msg = { + .opcode = ice_sbq_msg_rd, + .dest_dev = ice_sbq_dev_cgu, + .msg_addr_low = addr + }; + int err; + + err = ice_sbq_rw_reg(hw, &cgu_msg, LIBIE_AQ_FLAG_RD); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", + addr, err); + return err; + } + + *val = cgu_msg.data; + + return 0; +} + +/** + * ice_write_cgu_reg - Write a CGU register + * @hw: Pointer to the HW struct + * @addr: Register address to write + * @val: Value to write into the register + * + * Write the specified value to a register of the Clock Generation Unit. Only + * applicable to E82X devices. + * + * Return: 0 on success, other error codes when failed to write to CGU. + */ +int ice_write_cgu_reg(struct ice_hw *hw, u32 addr, u32 val) +{ + struct ice_sbq_msg_input cgu_msg = { + .opcode = ice_sbq_msg_wr, + .dest_dev = ice_sbq_dev_cgu, + .msg_addr_low = addr, + .data = val + }; + int err; + + err = ice_sbq_rw_reg(hw, &cgu_msg, LIBIE_AQ_FLAG_RD); + if (err) + ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", + addr, err); + + return err; +} diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 64c530b39191..e700ac0dc347 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -39,6 +39,47 @@ #define FEC_RECEIVER_ID_PCS0 (0x33 << FEC_RECV_ID_SHIFT) #define FEC_RECEIVER_ID_PCS1 (0x34 << FEC_RECV_ID_SHIFT) +#define ICE_CGU_R9 0x24 +#define ICE_CGU_R9_TIME_REF_FREQ_SEL GENMASK(2, 0) +#define ICE_CGU_R9_CLK_EREF0_EN BIT(4) +#define ICE_CGU_R9_TIME_REF_EN BIT(5) +#define ICE_CGU_R9_TIME_SYNC_EN BIT(6) +#define ICE_CGU_R9_ONE_PPS_OUT_EN BIT(7) +#define ICE_CGU_R9_ONE_PPS_OUT_AMP GENMASK(19, 18) + +#define ICE_CGU_R16 0x40 +#define ICE_CGU_R16_TSPLL_CK_REFCLKFREQ GENMASK(31, 24) + +#define ICE_CGU_R19 0x4C +#define ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X GENMASK(7, 0) +#define ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825 GENMASK(9, 0) +#define ICE_CGU_R19_TSPLL_NDIVRATIO GENMASK(19, 16) + +#define ICE_CGU_R22 0x58 +#define ICE_CGU_R22_TIME1588CLK_DIV GENMASK(23, 20) +#define ICE_CGU_R22_TIME1588CLK_DIV2 BIT(30) + +#define ICE_CGU_R23 0x5C +#define ICE_CGU_R24 0x60 +#define ICE_CGU_R24_FBDIV_FRAC GENMASK(21, 0) +#define ICE_CGU_R23_R24_TSPLL_ENABLE BIT(24) +#define ICE_CGU_R23_R24_REF1588_CK_DIV GENMASK(30, 27) +#define ICE_CGU_R23_R24_TIME_REF_SEL BIT(31) + +#define ICE_CGU_BW_TDC 0x31C +#define ICE_CGU_BW_TDC_PLLLOCK_SEL GENMASK(30, 29) + +#define ICE_CGU_RO_LOCK 0x3F0 +#define ICE_CGU_RO_LOCK_TRUE_LOCK BIT(12) +#define ICE_CGU_RO_LOCK_UNLOCK BIT(13) + +#define ICE_CGU_CNTR_BIST 0x344 +#define ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 BIT(15) +#define ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1 BIT(16) + +#define ICE_CGU_RO_BWM_LF 0x370 +#define ICE_CGU_RO_BWM_LF_TRUE_LOCK BIT(12) + int ice_init_hw(struct ice_hw *hw); void ice_deinit_hw(struct ice_hw *hw); int ice_check_reset(struct ice_hw *hw); @@ -68,7 +109,7 @@ bool ice_is_sbq_supported(struct ice_hw *hw); struct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw); int ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, - struct ice_aq_desc *desc, void *buf, u16 buf_size, + struct libie_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd); void ice_clear_pxe_mode(struct ice_hw *hw); int ice_get_caps(struct ice_hw *hw); @@ -77,6 +118,12 @@ void ice_set_safe_mode_caps(struct ice_hw *hw); int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, u32 rxq_index); +int ice_read_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, + u32 rxq_index); +int ice_read_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx, + u32 txq_index); +int ice_write_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx, + u32 txq_index); int ice_aq_get_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *get_params); @@ -91,14 +138,14 @@ ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle, bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq); int ice_aq_q_shutdown(struct ice_hw *hw, bool unloading); -void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode); +void ice_fill_dflt_direct_cmd_desc(struct libie_aq_desc *desc, u16 opcode); void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf); extern struct mutex ice_global_cfg_lock_sw; int -ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, +ice_aq_send_cmd(struct ice_hw *hw, struct libie_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd); int ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd); @@ -223,12 +270,21 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle, int ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf, u16 buf_size, u16 num_qs, u8 oldport, u8 newport, - struct ice_sq_cd *cd); + u8 mode, struct ice_sq_cd *cd); int ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle); void ice_replay_post(struct ice_hw *hw); struct ice_q_ctx * ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle); +int +ice_aq_set_txtimeq(struct ice_hw *hw, u16 txtimeq, u8 q_count, + struct ice_aqc_set_txtime_qgrp *txtime_qg, + u16 buf_size, struct ice_sq_cd *cd); +void ice_pack_txtime_ctx(const struct ice_txtime_ctx *ctx, + ice_txtime_ctx_buf_t *buf); int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in, u16 flag); +int ice_aq_get_cgu_input_pin_measure(struct ice_hw *hw, u8 dpll_idx, + struct ice_cgu_input_measure *meas, + u16 meas_num); int ice_aq_get_cgu_abilities(struct ice_hw *hw, struct ice_aqc_get_cgu_abilities *abilities); @@ -303,4 +359,6 @@ ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, int ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle); int ice_read_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data); bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw); +int ice_read_cgu_reg(struct ice_hw *hw, u32 addr, u32 *val); +int ice_write_cgu_reg(struct ice_hw *hw, u32 addr, u32 val); #endif /* _ICE_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index e3959ad442a2..dcb837cadd18 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -90,7 +90,7 @@ bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq) static int ice_alloc_ctrlq_sq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) { - size_t size = cq->num_sq_entries * sizeof(struct ice_aq_desc); + size_t size = cq->num_sq_entries * sizeof(struct libie_aq_desc); cq->sq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, &cq->sq.desc_buf.pa, @@ -110,7 +110,7 @@ ice_alloc_ctrlq_sq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) static int ice_alloc_ctrlq_rq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) { - size_t size = cq->num_rq_entries * sizeof(struct ice_aq_desc); + size_t size = cq->num_rq_entries * sizeof(struct libie_aq_desc); cq->rq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, &cq->rq.desc_buf.pa, @@ -159,7 +159,7 @@ ice_alloc_rq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) /* allocate the mapped buffers */ for (i = 0; i < cq->num_rq_entries; i++) { - struct ice_aq_desc *desc; + struct libie_aq_desc *desc; struct ice_dma_mem *bi; bi = &cq->rq.r.rq_bi[i]; @@ -173,9 +173,9 @@ ice_alloc_rq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) /* now configure the descriptors for use */ desc = ICE_CTL_Q_DESC(cq->rq, i); - desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); - if (cq->rq_buf_size > ICE_AQ_LG_BUF) - desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); + desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_BUF); + if (cq->rq_buf_size > LIBIE_AQ_LG_BUF) + desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_LB); desc->opcode = 0; /* This is in accordance with control queue design, there is no * register for buffer size configuration @@ -858,7 +858,7 @@ static u16 ice_clean_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) { struct ice_ctl_q_ring *sq = &cq->sq; u16 ntc = sq->next_to_clean; - struct ice_aq_desc *desc; + struct libie_aq_desc *desc; desc = ICE_CTL_Q_DESC(*sq, ntc); @@ -912,7 +912,7 @@ static const char *ice_ctl_q_str(enum ice_ctl_q qtype) static void ice_debug_cq(struct ice_hw *hw, struct ice_ctl_q_info *cq, void *desc, void *buf, u16 buf_len, bool response) { - struct ice_aq_desc *cq_desc = desc; + struct libie_aq_desc *cq_desc = desc; u16 datalen, flags; if (!IS_ENABLED(CONFIG_DYNAMIC_DEBUG) && @@ -939,7 +939,8 @@ static void ice_debug_cq(struct ice_hw *hw, struct ice_ctl_q_info *cq, * by the DD and/or CMP flag set or a command with the RD flag set. */ if (buf && cq_desc->datalen && - (flags & (ICE_AQ_FLAG_DD | ICE_AQ_FLAG_CMP | ICE_AQ_FLAG_RD))) { + (flags & (LIBIE_AQ_FLAG_DD | LIBIE_AQ_FLAG_CMP | + LIBIE_AQ_FLAG_RD))) { char prefix[] = KBUILD_MODNAME " 0x12341234 0x12341234 "; sprintf(prefix, KBUILD_MODNAME " 0x%08X 0x%08X ", @@ -992,11 +993,11 @@ static bool ice_sq_done(struct ice_hw *hw, struct ice_ctl_q_info *cq) */ int ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, - struct ice_aq_desc *desc, void *buf, u16 buf_size, + struct libie_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd) { struct ice_dma_mem *dma_buf = NULL; - struct ice_aq_desc *desc_on_ring; + struct libie_aq_desc *desc_on_ring; bool cmd_completed = false; int status = 0; u16 retval = 0; @@ -1007,7 +1008,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, return -EBUSY; mutex_lock(&cq->sq_lock); - cq->sq_last_status = ICE_AQ_RC_OK; + cq->sq_last_status = LIBIE_AQ_RC_OK; if (!cq->sq.count) { ice_debug(hw, ICE_DBG_AQ_MSG, "Control Send queue not initialized.\n"); @@ -1028,9 +1029,9 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, goto sq_send_command_error; } - desc->flags |= cpu_to_le16(ICE_AQ_FLAG_BUF); - if (buf_size > ICE_AQ_LG_BUF) - desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); + desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_BUF); + if (buf_size > LIBIE_AQ_LG_BUF) + desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_LB); } val = rd32(hw, cq->sq.head); @@ -1112,9 +1113,9 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, retval &= 0xff; } cmd_completed = true; - if (!status && retval != ICE_AQ_RC_OK) + if (!status && retval != LIBIE_AQ_RC_OK) status = -EIO; - cq->sq_last_status = (enum ice_aq_err)retval; + cq->sq_last_status = (enum libie_aq_err)retval; } ice_debug(hw, ICE_DBG_AQ_MSG, "ATQ: desc and buffer writeback:\n"); @@ -1149,12 +1150,12 @@ sq_send_command_error: * * Fill the desc with default values */ -void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode) +void ice_fill_dflt_direct_cmd_desc(struct libie_aq_desc *desc, u16 opcode) { /* zero out the desc */ memset(desc, 0, sizeof(*desc)); desc->opcode = cpu_to_le16(opcode); - desc->flags = cpu_to_le16(ICE_AQ_FLAG_SI); + desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_SI); } /** @@ -1172,9 +1173,9 @@ int ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, struct ice_rq_event_info *e, u16 *pending) { + enum libie_aq_err rq_last_status; u16 ntc = cq->rq.next_to_clean; - enum ice_aq_err rq_last_status; - struct ice_aq_desc *desc; + struct libie_aq_desc *desc; struct ice_dma_mem *bi; int ret_code = 0; u16 desc_idx; @@ -1207,9 +1208,9 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, desc = ICE_CTL_Q_DESC(cq->rq, ntc); desc_idx = ntc; - rq_last_status = (enum ice_aq_err)le16_to_cpu(desc->retval); + rq_last_status = (enum libie_aq_err)le16_to_cpu(desc->retval); flags = le16_to_cpu(desc->flags); - if (flags & ICE_AQ_FLAG_ERR) { + if (flags & LIBIE_AQ_FLAG_ERR) { ret_code = -EIO; ice_debug(hw, ICE_DBG_AQ_MSG, "Control Receive Queue Event 0x%04X received with error 0x%X\n", le16_to_cpu(desc->opcode), rq_last_status); @@ -1230,9 +1231,9 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, bi = &cq->rq.r.rq_bi[ntc]; memset(desc, 0, sizeof(*desc)); - desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); - if (cq->rq_buf_size > ICE_AQ_LG_BUF) - desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); + desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_BUF); + if (cq->rq_buf_size > LIBIE_AQ_LG_BUF) + desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_LB); desc->datalen = cpu_to_le16(bi->size); desc->params.generic.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); desc->params.generic.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index ca97b7365a1b..788040dd662e 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -12,7 +12,7 @@ #define ICE_SBQ_MAX_BUF_LEN 512 #define ICE_CTL_Q_DESC(R, i) \ - (&(((struct ice_aq_desc *)((R).desc_buf.va))[i])) + (&(((struct libie_aq_desc *)((R).desc_buf.va))[i])) #define ICE_CTL_Q_DESC_UNUSED(R) \ ((u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ @@ -76,12 +76,12 @@ struct ice_ctl_q_ring { /* sq transaction details */ struct ice_sq_cd { - struct ice_aq_desc *wb_desc; + struct libie_aq_desc *wb_desc; }; /* rq event information */ struct ice_rq_event_info { - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 msg_len; u16 buf_len; u8 *msg_buf; @@ -96,7 +96,7 @@ struct ice_ctl_q_info { u16 num_sq_entries; /* send queue depth */ u16 rq_buf_size; /* receive queue buffer size */ u16 sq_buf_size; /* send queue buffer size */ - enum ice_aq_err sq_last_status; /* last status on send queue */ + enum libie_aq_err sq_last_status; /* last status on send queue */ struct mutex sq_lock; /* Send queue lock */ struct mutex rq_lock; /* Receive queue lock */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.c b/drivers/net/ethernet/intel/ice/ice_dcb.c index 64737fc62306..abea84f14658 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb.c @@ -24,10 +24,10 @@ ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf, struct ice_sq_cd *cd) { struct ice_aqc_lldp_get_mib *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.lldp_get_mib; + cmd = libie_aq_raw(&desc); if (buf_size == 0 || !buf) return -EINVAL; @@ -64,9 +64,9 @@ ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update, struct ice_sq_cd *cd) { struct ice_aqc_lldp_set_mib_change *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.lldp_set_event; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change); @@ -95,9 +95,9 @@ ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist, struct ice_sq_cd *cd) { struct ice_aqc_lldp_stop *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.lldp_stop; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop); @@ -121,9 +121,9 @@ ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist, int ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd) { struct ice_aqc_lldp_start *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.lldp_start; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_start); @@ -677,11 +677,11 @@ ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent, bool *dcbx_agent_status, struct ice_sq_cd *cd) { struct ice_aqc_lldp_stop_start_specific_agent *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 opcode; int status; - cmd = &desc.params.lldp_agent_ctrl; + cmd = libie_aq_raw(&desc); opcode = ice_aqc_opc_lldp_stop_start_specific_agent; @@ -714,7 +714,7 @@ ice_aq_get_cee_dcb_cfg(struct ice_hw *hw, struct ice_aqc_get_cee_dcb_cfg_resp *buff, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg); @@ -733,13 +733,13 @@ ice_aq_get_cee_dcb_cfg(struct ice_hw *hw, int ice_aq_set_pfc_mode(struct ice_hw *hw, u8 pfc_mode, struct ice_sq_cd *cd) { struct ice_aqc_set_query_pfc_mode *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; if (pfc_mode > ICE_AQC_PFC_DSCP_BASED_PFC) return -EINVAL; - cmd = &desc.params.set_query_pfc_mode; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_pfc_mode); @@ -914,7 +914,7 @@ static int ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode) ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE, ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg); /* Don't treat ENOENT as an error for Remote MIBs */ - if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) + if (pi->hw->adminq.sq_last_status == LIBIE_AQ_RC_ENOENT) ret = 0; out: @@ -941,7 +941,7 @@ int ice_get_dcb_cfg(struct ice_port_info *pi) /* CEE mode */ ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE); ice_cee_to_dcb_cfg(&cee_cfg, pi); - } else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) { + } else if (pi->hw->adminq.sq_last_status == LIBIE_AQ_RC_ENOENT) { /* CEE mode not enabled try querying IEEE data */ dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE; @@ -965,7 +965,7 @@ void ice_get_dcb_cfg_from_mib_change(struct ice_port_info *pi, struct ice_aqc_lldp_get_mib *mib; u8 change_type, dcbx_mode; - mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw; + mib = libie_aq_raw(&event->desc); change_type = FIELD_GET(ICE_AQ_LLDP_MIB_TYPE_M, mib->type); if (change_type == ICE_AQ_LLDP_MIB_REMOTE) @@ -1537,12 +1537,12 @@ ice_aq_query_port_ets(struct ice_port_info *pi, struct ice_sq_cd *cd) { struct ice_aqc_query_port_ets *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; if (!pi) return -EINVAL; - cmd = &desc.params.port_ets; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets); cmd->port_teid = pi->root->info.node_teid; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 533eb8930aa8..9fc8681cc58e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -1020,7 +1020,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, } pi = pf->hw.port_info; - mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw; + mib = libie_aq_raw(&event->desc); /* Ignore if event is not for Nearest Bridge */ mib_type = FIELD_GET(ICE_AQ_LLDP_BRID_TYPE_M, mib->type); diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c index 351824dc3c62..3b2d9c436979 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.c +++ b/drivers/net/ethernet/intel/ice/ice_ddp.c @@ -1101,16 +1101,16 @@ struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) return &bld->buf; } -static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err) +static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum libie_aq_err aq_err) { switch (aq_err) { - case ICE_AQ_RC_ENOSEC: - case ICE_AQ_RC_EBADSIG: + case LIBIE_AQ_RC_ENOSEC: + case LIBIE_AQ_RC_EBADSIG: return ICE_DDP_PKG_FILE_SIGNATURE_INVALID; - case ICE_AQ_RC_ESVN: + case LIBIE_AQ_RC_ESVN: return ICE_DDP_PKG_FILE_REVISION_TOO_LOW; - case ICE_AQ_RC_EBADMAN: - case ICE_AQ_RC_EBADBUF: + case LIBIE_AQ_RC_EBADMAN: + case LIBIE_AQ_RC_EBADBUF: return ICE_DDP_PKG_LOAD_ERROR; default: return ICE_DDP_PKG_ERR; @@ -1180,7 +1180,7 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u32 *error_info, struct ice_sq_cd *cd) { struct ice_aqc_download_pkg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; if (error_offset) @@ -1188,9 +1188,9 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, if (error_info) *error_info = 0; - cmd = &desc.params.download_pkg; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); if (last_buf) cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; @@ -1259,7 +1259,7 @@ static enum ice_ddp_state ice_ddp_send_hunk(struct ice_ddp_send_ctx *ctx, struct ice_buf_hdr *prev_hunk = ctx->hdr; struct ice_hw *hw = ctx->hw; bool prev_was_last = !hunk; - enum ice_aq_err aq_err; + enum libie_aq_err aq_err; u32 offset, info; int attempt, err; @@ -1278,7 +1278,8 @@ static enum ice_ddp_state ice_ddp_send_hunk(struct ice_ddp_send_ctx *ctx, prev_was_last, &offset, &info, NULL); aq_err = hw->adminq.sq_last_status; - if (aq_err != ICE_AQ_RC_ENOSEC && aq_err != ICE_AQ_RC_EBADSIG) + if (aq_err != LIBIE_AQ_RC_ENOSEC && + aq_err != LIBIE_AQ_RC_EBADSIG) break; } @@ -1537,7 +1538,7 @@ ice_post_dwnld_pkg_actions(struct ice_hw *hw) static enum ice_ddp_state ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) { - enum ice_aq_err aq_err = hw->adminq.sq_last_status; + enum libie_aq_err aq_err = hw->adminq.sq_last_status; enum ice_ddp_state state = ICE_DDP_PKG_ERR; struct ice_ddp_send_ctx ctx = { .hw = hw }; int status; @@ -1687,7 +1688,7 @@ static int ice_aq_get_pkg_info_list(struct ice_hw *hw, struct ice_aqc_get_pkg_info_resp *pkg_info, u16 buf_size, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list); @@ -1711,7 +1712,7 @@ static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u32 *error_info, struct ice_sq_cd *cd) { struct ice_aqc_download_pkg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; if (error_offset) @@ -1719,9 +1720,9 @@ static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, if (error_info) *error_info = 0; - cmd = &desc.params.download_pkg; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); if (last_buf) cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; @@ -1753,10 +1754,10 @@ static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd); } @@ -2335,10 +2336,10 @@ ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, struct ice_sq_cd *cd, u8 *flags, bool set) { struct ice_aqc_get_set_tx_topo *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.get_set_tx_topo; + cmd = libie_aq_raw(&desc); if (set) { ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_tx_topo); cmd->set_flags = ICE_AQC_TX_TOPO_FLAGS_ISSUED; @@ -2347,14 +2348,14 @@ ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, cmd->set_flags |= ICE_AQC_TX_TOPO_FLAGS_SRC_RAM | ICE_AQC_TX_TOPO_FLAGS_LOAD_NEW; - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); } else { ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_tx_topo); cmd->get_flags = ICE_AQC_TX_TOPO_GET_RAM; if (hw->mac_type == ICE_MAC_E810 || hw->mac_type == ICE_MAC_GENERIC) - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); } status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); @@ -2362,7 +2363,7 @@ ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, return status; /* read the return flag values (first byte) for get operation */ if (!set && flags) - *flags = desc.params.get_set_tx_topo.set_flags; + *flags = cmd->set_flags; return 0; } @@ -2376,7 +2377,13 @@ ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, * The function will apply the new Tx topology from the package buffer * if available. * - * Return: zero when update was successful, negative values otherwise. + * Return: + * * 0 - Successfully applied topology configuration. + * * -EBUSY - Failed to acquire global configuration lock. + * * -EEXIST - Topology configuration has already been applied. + * * -EIO - Unable to apply topology configuration. + * * -ENODEV - Failed to re-initialize device after applying configuration. + * * Other negative error codes indicate unexpected failures. */ int ice_cfg_tx_topo(struct ice_hw *hw, const void *buf, u32 len) { @@ -2409,7 +2416,7 @@ int ice_cfg_tx_topo(struct ice_hw *hw, const void *buf, u32 len) if (status) { ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n"); - return status; + return -EIO; } /* Is default topology already applied ? */ @@ -2496,31 +2503,45 @@ update_topo: ICE_GLOBAL_CFG_LOCK_TIMEOUT); if (status) { ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n"); - return status; + return -EBUSY; } /* Check if reset was triggered already. */ reg = rd32(hw, GLGEN_RSTAT); if (reg & GLGEN_RSTAT_DEVSTATE_M) { - /* Reset is in progress, re-init the HW again */ ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. Layer topology might be applied already\n"); ice_check_reset(hw); - return 0; + /* Reset is in progress, re-init the HW again */ + goto reinit_hw; } /* Set new topology */ status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true); if (status) { - ice_debug(hw, ICE_DBG_INIT, "Failed setting Tx topology\n"); - return status; + ice_debug(hw, ICE_DBG_INIT, "Failed to set Tx topology, status %pe\n", + ERR_PTR(status)); + /* only report -EIO here as the caller checks the error value + * and reports an informational error message informing that + * the driver failed to program Tx topology. + */ + status = -EIO; } - /* New topology is updated, delay 1 second before issuing the CORER */ + /* Even if Tx topology config failed, we need to CORE reset here to + * clear the global configuration lock. Delay 1 second to allow + * hardware to settle then issue a CORER + */ msleep(1000); ice_reset(hw, ICE_RESET_CORER); - /* CORER will clear the global lock, so no explicit call - * required for release. - */ + ice_check_reset(hw); + +reinit_hw: + /* Since we triggered a CORER, re-initialize hardware */ + ice_deinit_hw(hw); + if (ice_init_hw(hw)) { + ice_debug(hw, ICE_DBG_INIT, "Failed to re-init hardware after setting Tx topology\n"); + return -ENODEV; + } - return 0; + return status; } diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c index cb71eca6a85b..f450250fc827 100644 --- a/drivers/net/ethernet/intel/ice/ice_debugfs.c +++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c @@ -1,647 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022, Intel Corporation. */ -#include <linux/fs.h> #include <linux/debugfs.h> -#include <linux/random.h> -#include <linux/vmalloc.h> #include "ice.h" static struct dentry *ice_debugfs_root; -/* create a define that has an extra module that doesn't really exist. this - * is so we can add a module 'all' to easily enable/disable all the modules - */ -#define ICE_NR_FW_LOG_MODULES (ICE_AQC_FW_LOG_ID_MAX + 1) - -/* the ordering in this array is important. it matches the ordering of the - * values in the FW so the index is the same value as in ice_aqc_fw_logging_mod - */ -static const char * const ice_fwlog_module_string[] = { - "general", - "ctrl", - "link", - "link_topo", - "dnl", - "i2c", - "sdp", - "mdio", - "adminq", - "hdma", - "lldp", - "dcbx", - "dcb", - "xlr", - "nvm", - "auth", - "vpd", - "iosf", - "parser", - "sw", - "scheduler", - "txq", - "rsvd", - "post", - "watchdog", - "task_dispatch", - "mng", - "synce", - "health", - "tsdrv", - "pfreg", - "mdlver", - "all", -}; - -/* the ordering in this array is important. it matches the ordering of the - * values in the FW so the index is the same value as in ice_fwlog_level - */ -static const char * const ice_fwlog_level_string[] = { - "none", - "error", - "warning", - "normal", - "verbose", -}; - -static const char * const ice_fwlog_log_size[] = { - "128K", - "256K", - "512K", - "1M", - "2M", -}; - -/** - * ice_fwlog_print_module_cfg - print current FW logging module configuration - * @hw: pointer to the HW structure - * @module: module to print - * @s: the seq file to put data into - */ -static void -ice_fwlog_print_module_cfg(struct ice_hw *hw, int module, struct seq_file *s) -{ - struct ice_fwlog_cfg *cfg = &hw->fwlog_cfg; - struct ice_fwlog_module_entry *entry; - - if (module != ICE_AQC_FW_LOG_ID_MAX) { - entry = &cfg->module_entries[module]; - - seq_printf(s, "\tModule: %s, Log Level: %s\n", - ice_fwlog_module_string[entry->module_id], - ice_fwlog_level_string[entry->log_level]); - } else { - int i; - - for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) { - entry = &cfg->module_entries[i]; - - seq_printf(s, "\tModule: %s, Log Level: %s\n", - ice_fwlog_module_string[entry->module_id], - ice_fwlog_level_string[entry->log_level]); - } - } -} - -static int ice_find_module_by_dentry(struct ice_pf *pf, struct dentry *d) -{ - int i, module; - - module = -1; - /* find the module based on the dentry */ - for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) { - if (d == pf->ice_debugfs_pf_fwlog_modules[i]) { - module = i; - break; - } - } - - return module; -} - -/** - * ice_debugfs_module_show - read from 'module' file - * @s: the opened file - * @v: pointer to the offset - */ -static int ice_debugfs_module_show(struct seq_file *s, void *v) -{ - const struct file *filp = s->file; - struct dentry *dentry; - struct ice_pf *pf; - int module; - - dentry = file_dentry(filp); - pf = s->private; - - module = ice_find_module_by_dentry(pf, dentry); - if (module < 0) { - dev_info(ice_pf_to_dev(pf), "unknown module\n"); - return -EINVAL; - } - - ice_fwlog_print_module_cfg(&pf->hw, module, s); - - return 0; -} - -static int ice_debugfs_module_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, ice_debugfs_module_show, inode->i_private); -} - -/** - * ice_debugfs_module_write - write into 'module' file - * @filp: the opened file - * @buf: where to find the user's data - * @count: the length of the user's data - * @ppos: file position offset - */ -static ssize_t -ice_debugfs_module_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ice_pf *pf = file_inode(filp)->i_private; - struct dentry *dentry = file_dentry(filp); - struct device *dev = ice_pf_to_dev(pf); - char user_val[16], *cmd_buf; - int module, log_level, cnt; - - /* don't allow partial writes or invalid input */ - if (*ppos != 0 || count > 8) - return -EINVAL; - - cmd_buf = memdup_user_nul(buf, count); - if (IS_ERR(cmd_buf)) - return PTR_ERR(cmd_buf); - - module = ice_find_module_by_dentry(pf, dentry); - if (module < 0) { - dev_info(dev, "unknown module\n"); - return -EINVAL; - } - - cnt = sscanf(cmd_buf, "%s", user_val); - if (cnt != 1) - return -EINVAL; - - log_level = sysfs_match_string(ice_fwlog_level_string, user_val); - if (log_level < 0) { - dev_info(dev, "unknown log level '%s'\n", user_val); - return -EINVAL; - } - - if (module != ICE_AQC_FW_LOG_ID_MAX) { - ice_pf_fwlog_update_module(pf, log_level, module); - } else { - /* the module 'all' is a shortcut so that we can set - * all of the modules to the same level quickly - */ - int i; - - for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) - ice_pf_fwlog_update_module(pf, log_level, i); - } - - return count; -} - -static const struct file_operations ice_debugfs_module_fops = { - .owner = THIS_MODULE, - .open = ice_debugfs_module_open, - .read = seq_read, - .release = single_release, - .write = ice_debugfs_module_write, -}; - -/** - * ice_debugfs_nr_messages_read - read from 'nr_messages' file - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - */ -static ssize_t ice_debugfs_nr_messages_read(struct file *filp, - char __user *buffer, size_t count, - loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct ice_hw *hw = &pf->hw; - char buff[32] = {}; - - snprintf(buff, sizeof(buff), "%d\n", - hw->fwlog_cfg.log_resolution); - - return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff)); -} - -/** - * ice_debugfs_nr_messages_write - write into 'nr_messages' file - * @filp: the opened file - * @buf: where to find the user's data - * @count: the length of the user's data - * @ppos: file position offset - */ -static ssize_t -ice_debugfs_nr_messages_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct device *dev = ice_pf_to_dev(pf); - struct ice_hw *hw = &pf->hw; - char user_val[8], *cmd_buf; - s16 nr_messages; - ssize_t ret; - - /* don't allow partial writes or invalid input */ - if (*ppos != 0 || count > 4) - return -EINVAL; - - cmd_buf = memdup_user_nul(buf, count); - if (IS_ERR(cmd_buf)) - return PTR_ERR(cmd_buf); - - ret = sscanf(cmd_buf, "%s", user_val); - if (ret != 1) - return -EINVAL; - - ret = kstrtos16(user_val, 0, &nr_messages); - if (ret) - return ret; - - if (nr_messages < ICE_AQC_FW_LOG_MIN_RESOLUTION || - nr_messages > ICE_AQC_FW_LOG_MAX_RESOLUTION) { - dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n", - nr_messages, ICE_AQC_FW_LOG_MIN_RESOLUTION, - ICE_AQC_FW_LOG_MAX_RESOLUTION); - return -EINVAL; - } - - hw->fwlog_cfg.log_resolution = nr_messages; - - return count; -} - -static const struct file_operations ice_debugfs_nr_messages_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ice_debugfs_nr_messages_read, - .write = ice_debugfs_nr_messages_write, -}; - -/** - * ice_debugfs_enable_read - read from 'enable' file - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - */ -static ssize_t ice_debugfs_enable_read(struct file *filp, - char __user *buffer, size_t count, - loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct ice_hw *hw = &pf->hw; - char buff[32] = {}; - - snprintf(buff, sizeof(buff), "%u\n", - (u16)(hw->fwlog_cfg.options & - ICE_FWLOG_OPTION_IS_REGISTERED) >> 3); - - return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff)); -} - -/** - * ice_debugfs_enable_write - write into 'enable' file - * @filp: the opened file - * @buf: where to find the user's data - * @count: the length of the user's data - * @ppos: file position offset - */ -static ssize_t -ice_debugfs_enable_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct ice_hw *hw = &pf->hw; - char user_val[8], *cmd_buf; - bool enable; - ssize_t ret; - - /* don't allow partial writes or invalid input */ - if (*ppos != 0 || count > 2) - return -EINVAL; - - cmd_buf = memdup_user_nul(buf, count); - if (IS_ERR(cmd_buf)) - return PTR_ERR(cmd_buf); - - ret = sscanf(cmd_buf, "%s", user_val); - if (ret != 1) - return -EINVAL; - - ret = kstrtobool(user_val, &enable); - if (ret) - goto enable_write_error; - - if (enable) - hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_ARQ_ENA; - else - hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA; - - ret = ice_fwlog_set(hw, &hw->fwlog_cfg); - if (ret) - goto enable_write_error; - - if (enable) - ret = ice_fwlog_register(hw); - else - ret = ice_fwlog_unregister(hw); - - if (ret) - goto enable_write_error; - - /* if we get here, nothing went wrong; return count since we didn't - * really write anything - */ - ret = (ssize_t)count; - -enable_write_error: - /* This function always consumes all of the written input, or produces - * an error. Check and enforce this. Otherwise, the write operation - * won't complete properly. - */ - if (WARN_ON(ret != (ssize_t)count && ret >= 0)) - ret = -EIO; - - return ret; -} - -static const struct file_operations ice_debugfs_enable_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ice_debugfs_enable_read, - .write = ice_debugfs_enable_write, -}; - -/** - * ice_debugfs_log_size_read - read from 'log_size' file - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - */ -static ssize_t ice_debugfs_log_size_read(struct file *filp, - char __user *buffer, size_t count, - loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct ice_hw *hw = &pf->hw; - char buff[32] = {}; - int index; - - index = hw->fwlog_ring.index; - snprintf(buff, sizeof(buff), "%s\n", ice_fwlog_log_size[index]); - - return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff)); -} - -/** - * ice_debugfs_log_size_write - write into 'log_size' file - * @filp: the opened file - * @buf: where to find the user's data - * @count: the length of the user's data - * @ppos: file position offset - */ -static ssize_t -ice_debugfs_log_size_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct device *dev = ice_pf_to_dev(pf); - struct ice_hw *hw = &pf->hw; - char user_val[8], *cmd_buf; - ssize_t ret; - int index; - - /* don't allow partial writes or invalid input */ - if (*ppos != 0 || count > 5) - return -EINVAL; - - cmd_buf = memdup_user_nul(buf, count); - if (IS_ERR(cmd_buf)) - return PTR_ERR(cmd_buf); - - ret = sscanf(cmd_buf, "%s", user_val); - if (ret != 1) - return -EINVAL; - - index = sysfs_match_string(ice_fwlog_log_size, user_val); - if (index < 0) { - dev_info(dev, "Invalid log size '%s'. The value must be one of 128K, 256K, 512K, 1M, 2M\n", - user_val); - ret = -EINVAL; - goto log_size_write_error; - } else if (hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED) { - dev_info(dev, "FW logging is currently running. Please disable FW logging to change log_size\n"); - ret = -EINVAL; - goto log_size_write_error; - } - - /* free all the buffers and the tracking info and resize */ - ice_fwlog_realloc_rings(hw, index); - - /* if we get here, nothing went wrong; return count since we didn't - * really write anything - */ - ret = (ssize_t)count; - -log_size_write_error: - /* This function always consumes all of the written input, or produces - * an error. Check and enforce this. Otherwise, the write operation - * won't complete properly. - */ - if (WARN_ON(ret != (ssize_t)count && ret >= 0)) - ret = -EIO; - - return ret; -} - -static const struct file_operations ice_debugfs_log_size_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ice_debugfs_log_size_read, - .write = ice_debugfs_log_size_write, -}; - -/** - * ice_debugfs_data_read - read from 'data' file - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - */ -static ssize_t ice_debugfs_data_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct ice_hw *hw = &pf->hw; - int data_copied = 0; - bool done = false; - - if (ice_fwlog_ring_empty(&hw->fwlog_ring)) - return 0; - - while (!ice_fwlog_ring_empty(&hw->fwlog_ring) && !done) { - struct ice_fwlog_data *log; - u16 cur_buf_len; - - log = &hw->fwlog_ring.rings[hw->fwlog_ring.head]; - cur_buf_len = log->data_size; - if (cur_buf_len >= count) { - done = true; - continue; - } - - if (copy_to_user(buffer, log->data, cur_buf_len)) { - /* if there is an error then bail and return whatever - * the driver has copied so far - */ - done = true; - continue; - } - - data_copied += cur_buf_len; - buffer += cur_buf_len; - count -= cur_buf_len; - *ppos += cur_buf_len; - ice_fwlog_ring_increment(&hw->fwlog_ring.head, - hw->fwlog_ring.size); - } - - return data_copied; -} - -/** - * ice_debugfs_data_write - write into 'data' file - * @filp: the opened file - * @buf: where to find the user's data - * @count: the length of the user's data - * @ppos: file position offset - */ -static ssize_t -ice_debugfs_data_write(struct file *filp, const char __user *buf, size_t count, - loff_t *ppos) -{ - struct ice_pf *pf = filp->private_data; - struct device *dev = ice_pf_to_dev(pf); - struct ice_hw *hw = &pf->hw; - ssize_t ret; - - /* don't allow partial writes */ - if (*ppos != 0) - return 0; - - /* any value is allowed to clear the buffer so no need to even look at - * what the value is - */ - if (!(hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED)) { - hw->fwlog_ring.head = 0; - hw->fwlog_ring.tail = 0; - } else { - dev_info(dev, "Can't clear FW log data while FW log running\n"); - ret = -EINVAL; - goto nr_buffs_write_error; - } - - /* if we get here, nothing went wrong; return count since we didn't - * really write anything - */ - ret = (ssize_t)count; - -nr_buffs_write_error: - /* This function always consumes all of the written input, or produces - * an error. Check and enforce this. Otherwise, the write operation - * won't complete properly. - */ - if (WARN_ON(ret != (ssize_t)count && ret >= 0)) - ret = -EIO; - - return ret; -} - -static const struct file_operations ice_debugfs_data_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ice_debugfs_data_read, - .write = ice_debugfs_data_write, -}; - -/** - * ice_debugfs_fwlog_init - setup the debugfs directory - * @pf: the ice that is starting up - */ -void ice_debugfs_fwlog_init(struct ice_pf *pf) +int ice_debugfs_pf_init(struct ice_pf *pf) { const char *name = pci_name(pf->pdev); - struct dentry *fw_modules_dir; - struct dentry **fw_modules; - int i; - - /* only support fw log commands on PF 0 */ - if (pf->hw.bus.func) - return; - - /* allocate space for this first because if it fails then we don't - * need to unwind - */ - fw_modules = kcalloc(ICE_NR_FW_LOG_MODULES, sizeof(*fw_modules), - GFP_KERNEL); - if (!fw_modules) - return; pf->ice_debugfs_pf = debugfs_create_dir(name, ice_debugfs_root); if (IS_ERR(pf->ice_debugfs_pf)) - goto err_create_module_files; - - pf->ice_debugfs_pf_fwlog = debugfs_create_dir("fwlog", - pf->ice_debugfs_pf); - if (IS_ERR(pf->ice_debugfs_pf_fwlog)) - goto err_create_module_files; + return PTR_ERR(pf->ice_debugfs_pf); - fw_modules_dir = debugfs_create_dir("modules", - pf->ice_debugfs_pf_fwlog); - if (IS_ERR(fw_modules_dir)) - goto err_create_module_files; - - for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) { - fw_modules[i] = debugfs_create_file(ice_fwlog_module_string[i], - 0600, fw_modules_dir, pf, - &ice_debugfs_module_fops); - if (IS_ERR(fw_modules[i])) - goto err_create_module_files; - } - - debugfs_create_file("nr_messages", 0600, - pf->ice_debugfs_pf_fwlog, pf, - &ice_debugfs_nr_messages_fops); - - pf->ice_debugfs_pf_fwlog_modules = fw_modules; - - debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog, - pf, &ice_debugfs_enable_fops); - - debugfs_create_file("log_size", 0600, pf->ice_debugfs_pf_fwlog, - pf, &ice_debugfs_log_size_fops); - - debugfs_create_file("data", 0600, pf->ice_debugfs_pf_fwlog, - pf, &ice_debugfs_data_fops); - - return; - -err_create_module_files: - debugfs_remove_recursive(pf->ice_debugfs_pf_fwlog); - kfree(fw_modules); + return 0; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h index 34fd604132f5..bd4e66df0372 100644 --- a/drivers/net/ethernet/intel/ice/ice_devids.h +++ b/drivers/net/ethernet/intel/ice/ice_devids.h @@ -6,6 +6,24 @@ /* Device IDs */ #define ICE_DEV_ID_E822_SI_DFLT 0x1888 +/* Intel(R) Ethernet Controller E835-CC for backplane */ +#define ICE_DEV_ID_E835CC_BACKPLANE 0x1248 +/* Intel(R) Ethernet Controller E835-CC for QSFP */ +#define ICE_DEV_ID_E835CC_QSFP56 0x1249 +/* Intel(R) Ethernet Controller E835-CC for SFP */ +#define ICE_DEV_ID_E835CC_SFP 0x124A +/* Intel(R) Ethernet Controller E835-C for backplane */ +#define ICE_DEV_ID_E835C_BACKPLANE 0x1261 +/* Intel(R) Ethernet Controller E835-C for QSFP */ +#define ICE_DEV_ID_E835C_QSFP 0x1262 +/* Intel(R) Ethernet Controller E835-C for SFP */ +#define ICE_DEV_ID_E835C_SFP 0x1263 +/* Intel(R) Ethernet Controller E835-L for backplane */ +#define ICE_DEV_ID_E835_L_BACKPLANE 0x1265 +/* Intel(R) Ethernet Controller E835-L for QSFP */ +#define ICE_DEV_ID_E835_L_QSFP 0x1266 +/* Intel(R) Ethernet Controller E835-L for SFP */ +#define ICE_DEV_ID_E835_L_SFP 0x1267 /* Intel(R) Ethernet Connection E823-L for backplane */ #define ICE_DEV_ID_E823L_BACKPLANE 0x124C /* Intel(R) Ethernet Connection E823-L for SFP */ diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index bce3ad6ca2a6..53b54e395a2e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -11,6 +11,43 @@ #define ICE_DPLL_RCLK_NUM_PER_PF 1 #define ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT 25 #define ICE_DPLL_PIN_GEN_RCLK_FREQ 1953125 +#define ICE_DPLL_PIN_PRIO_OUTPUT 0xff +#define ICE_DPLL_INPUT_REF_NUM 10 +#define ICE_DPLL_PHASE_OFFSET_PERIOD 2 +#define ICE_DPLL_SW_PIN_INPUT_BASE_SFP 4 +#define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP 6 +#define ICE_DPLL_SW_PIN_OUTPUT_BASE 0 + +#define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \ + (ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx)) + +#define ICE_DPLL_PIN_SW_1_INPUT_ABS_IDX \ + (ICE_DPLL_PIN_SW_INPUT_ABS(ICE_DPLL_PIN_SW_1_IDX)) + +#define ICE_DPLL_PIN_SW_2_INPUT_ABS_IDX \ + (ICE_DPLL_PIN_SW_INPUT_ABS(ICE_DPLL_PIN_SW_2_IDX)) + +#define ICE_DPLL_PIN_SW_OUTPUT_ABS(out_idx) \ + (ICE_DPLL_SW_PIN_OUTPUT_BASE + (out_idx)) + +#define ICE_DPLL_PIN_SW_1_OUTPUT_ABS_IDX \ + (ICE_DPLL_PIN_SW_OUTPUT_ABS(ICE_DPLL_PIN_SW_1_IDX)) + +#define ICE_DPLL_PIN_SW_2_OUTPUT_ABS_IDX \ + (ICE_DPLL_PIN_SW_OUTPUT_ABS(ICE_DPLL_PIN_SW_2_IDX)) + +#define ICE_SR_PFA_DPLL_DEFAULTS 0x152 +#define ICE_DPLL_PFA_REF_SYNC_TYPE 0x2420 +#define ICE_DPLL_PFA_REF_SYNC_TYPE2 0x2424 +#define ICE_DPLL_PFA_END 0xFFFF +#define ICE_DPLL_PFA_HEADER_LEN 4 +#define ICE_DPLL_PFA_ENTRY_LEN 3 +#define ICE_DPLL_PFA_MAILBOX_REF_SYNC_PIN_S 4 +#define ICE_DPLL_PFA_MASK_OFFSET 1 +#define ICE_DPLL_PFA_VALUE_OFFSET 2 + +#define ICE_DPLL_E810C_SFP_NC_PINS 2 +#define ICE_DPLL_E810C_SFP_NC_START 4 /** * enum ice_dpll_pin_type - enumerate ice pin types: @@ -18,25 +55,61 @@ * @ICE_DPLL_PIN_TYPE_INPUT: input pin * @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 */ enum ice_dpll_pin_type { ICE_DPLL_PIN_INVALID, ICE_DPLL_PIN_TYPE_INPUT, ICE_DPLL_PIN_TYPE_OUTPUT, ICE_DPLL_PIN_TYPE_RCLK_INPUT, + ICE_DPLL_PIN_TYPE_SOFTWARE, }; static const char * const pin_type_name[] = { [ICE_DPLL_PIN_TYPE_INPUT] = "input", [ICE_DPLL_PIN_TYPE_OUTPUT] = "output", [ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input", + [ICE_DPLL_PIN_TYPE_SOFTWARE] = "software", }; +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 struct dpll_pin_frequency ice_esync_range[] = { DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ), }; /** + * ice_dpll_is_sw_pin - check if given pin shall be controlled by SW + * @pf: private board structure + * @index: index of a pin as understood by FW + * @input: true for input, false for output + * + * Check if the pin shall be controlled by SW - instead of providing raw access + * for pin control. For E810 NIC with dpll there is additional MUX-related logic + * between SMA/U.FL pins/connectors and dpll device, best to give user access + * with series of wrapper functions as from user perspective they convey single + * functionality rather then separated pins. + * + * Return: + * * true - pin controlled by SW + * * false - pin not controlled by SW + */ +static bool ice_dpll_is_sw_pin(struct ice_pf *pf, u8 index, bool input) +{ + if (input && pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) + index -= ICE_DPLL_SW_PIN_INPUT_BASE_QSFP - + ICE_DPLL_SW_PIN_INPUT_BASE_SFP; + + if ((input && (index == ICE_DPLL_PIN_SW_1_INPUT_ABS_IDX || + index == ICE_DPLL_PIN_SW_2_INPUT_ABS_IDX)) || + (!input && (index == ICE_DPLL_PIN_SW_1_OUTPUT_ABS_IDX || + index == ICE_DPLL_PIN_SW_2_OUTPUT_ABS_IDX))) + return true; + return false; +} + +/** * ice_dpll_is_reset - check if reset is in progress * @pf: private board structure * @extack: error reporting @@ -97,7 +170,7 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to set pin freq:%u on pin:%u", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), freq, pin->idx); return ret; } @@ -280,6 +353,87 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, } /** + * ice_dpll_sw_pin_frequency_set - callback to set frequency of SW pin + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: on success holds pin's frequency + * @extack: error reporting + * + * Calls set frequency command for corresponding and active input/output pin. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error pin not active or couldn't get from hw + */ +static int +ice_dpll_sw_pin_frequency_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 frequency, struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *sma = pin_priv; + int ret; + + if (!sma->active) { + NL_SET_ERR_MSG(extack, "pin is not active"); + return -EINVAL; + } + if (sma->direction == DPLL_PIN_DIRECTION_INPUT) + ret = ice_dpll_input_frequency_set(NULL, sma->input, dpll, + dpll_priv, frequency, + extack); + else + ret = ice_dpll_output_frequency_set(NULL, sma->output, dpll, + dpll_priv, frequency, + extack); + + return ret; +} + +/** + * ice_dpll_sw_pin_frequency_get - callback for get frequency of SW pin + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: on success holds pin's frequency + * @extack: error reporting + * + * Calls get frequency command for corresponding active input/output. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error pin not active or couldn't get from hw + */ +static int +ice_dpll_sw_pin_frequency_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *sma = pin_priv; + int ret; + + if (!sma->active) { + *frequency = 0; + return 0; + } + if (sma->direction == DPLL_PIN_DIRECTION_INPUT) { + ret = ice_dpll_input_frequency_get(NULL, sma->input, dpll, + dpll_priv, frequency, + extack); + } else { + ret = ice_dpll_output_frequency_get(NULL, sma->output, dpll, + dpll_priv, frequency, + extack); + } + + return ret; +} + +/** * ice_dpll_pin_enable - enable a pin on dplls * @hw: board private hw structure * @pin: pointer to a pin @@ -323,7 +477,7 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, if (ret) NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to enable %s pin:%u", - ret, ice_aq_str(hw->adminq.sq_last_status), + ret, libie_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); return ret; @@ -368,13 +522,74 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, if (ret) NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to disable %s pin:%u", - ret, ice_aq_str(hw->adminq.sq_last_status), + ret, libie_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); return ret; } /** + * ice_dpll_sw_pins_update - update status of all SW pins + * @pf: private board struct + * + * Determine and update pin struct fields (direction/active) of their current + * values for all the SW controlled pins. + * + * Context: Call with pf->dplls.lock held + * Return: + * * 0 - OK + * * negative - error + */ +static int +ice_dpll_sw_pins_update(struct ice_pf *pf) +{ + struct ice_dplls *d = &pf->dplls; + struct ice_dpll_pin *p; + u8 data = 0; + int ret; + + ret = ice_read_sma_ctrl(&pf->hw, &data); + if (ret) + return ret; + /* no change since last check */ + if (d->sma_data == data) + return 0; + + /* + * SMA1/U.FL1 vs SMA2/U.FL2 are using different bit scheme to decide + * on their direction and if are active + */ + p = &d->sma[ICE_DPLL_PIN_SW_1_IDX]; + p->active = true; + p->direction = DPLL_PIN_DIRECTION_INPUT; + if (data & ICE_SMA1_DIR_EN) { + p->direction = DPLL_PIN_DIRECTION_OUTPUT; + if (data & ICE_SMA1_TX_EN) + p->active = false; + } + + p = &d->sma[ICE_DPLL_PIN_SW_2_IDX]; + p->active = true; + p->direction = DPLL_PIN_DIRECTION_INPUT; + if ((data & ICE_SMA2_INACTIVE_MASK) == ICE_SMA2_INACTIVE_MASK) + p->active = false; + else if (data & ICE_SMA2_DIR_EN) + p->direction = DPLL_PIN_DIRECTION_OUTPUT; + + p = &d->ufl[ICE_DPLL_PIN_SW_1_IDX]; + if (!(data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN))) + p->active = true; + else + p->active = false; + + p = &d->ufl[ICE_DPLL_PIN_SW_2_IDX]; + p->active = (data & ICE_SMA2_DIR_EN) && !(data & ICE_SMA2_UFL2_RX_DIS); + d->sma_data = data; + + return 0; +} + +/** * ice_dpll_pin_state_update - update pin's state * @pf: private board struct * @pin: structure with pin attributes to be updated @@ -471,6 +686,11 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, DPLL_PIN_STATE_DISCONNECTED; } break; + case ICE_DPLL_PIN_TYPE_SOFTWARE: + ret = ice_dpll_sw_pins_update(pf); + if (ret) + goto err; + break; default: return -EINVAL; } @@ -481,13 +701,13 @@ err: NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to update %s pin:%u", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), pin_type_name[pin_type], pin->idx); else dev_err_ratelimited(ice_pf_to_dev(pf), "err:%d %s failed to update %s pin:%u\n", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), pin_type_name[pin_type], pin->idx); return ret; } @@ -520,7 +740,7 @@ ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to set pin prio:%u on pin:%u", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), prio, pin->idx); else dpll->input_prio[pin->idx] = prio; @@ -588,6 +808,67 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, } /** + * ice_dpll_phase_offset_monitor_set - set phase offset monitor state + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: feature state to be set + * @extack: error reporting + * + * Dpll subsystem callback. Enable/disable phase offset monitor feature of dpll. + * + * Context: Acquires and releases pf->dplls.lock + * Return: 0 - success + */ +static int ice_dpll_phase_offset_monitor_set(const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_feature_state state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = d->pf; + + mutex_lock(&pf->dplls.lock); + if (state == DPLL_FEATURE_STATE_ENABLE) + d->phase_offset_monitor_period = ICE_DPLL_PHASE_OFFSET_PERIOD; + else + d->phase_offset_monitor_period = 0; + mutex_unlock(&pf->dplls.lock); + + return 0; +} + +/** + * ice_dpll_phase_offset_monitor_get - get phase offset monitor state + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: on success holds current state of phase offset monitor + * @extack: error reporting + * + * Dpll subsystem callback. Provides current state of phase offset monitor + * features on dpll device. + * + * Context: Acquires and releases pf->dplls.lock + * Return: 0 - success + */ +static int ice_dpll_phase_offset_monitor_get(const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_feature_state *state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = d->pf; + + mutex_lock(&pf->dplls.lock); + if (d->phase_offset_monitor_period) + *state = DPLL_FEATURE_STATE_ENABLE; + else + *state = DPLL_FEATURE_STATE_DISABLE; + mutex_unlock(&pf->dplls.lock); + + return 0; +} + +/** * ice_dpll_pin_state_set - set pin's state on dpll * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration @@ -793,6 +1074,270 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, } /** + * ice_dpll_sma_direction_set - set direction of SMA pin + * @p: pointer to a pin + * @direction: requested direction of the pin + * @extack: error reporting + * + * Wrapper for dpll subsystem callback. Set direction of a SMA pin. + * + * Context: Call with pf->dplls.lock held + * Return: + * * 0 - success + * * negative - failed to get state + */ +static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) +{ + u8 data; + int ret; + + if (p->direction == direction && p->active) + return 0; + ret = ice_read_sma_ctrl(&p->pf->hw, &data); + if (ret) + return ret; + + switch (p->idx) { + case ICE_DPLL_PIN_SW_1_IDX: + data &= ~ICE_SMA1_MASK; + if (direction == DPLL_PIN_DIRECTION_OUTPUT) + data |= ICE_SMA1_DIR_EN; + break; + case ICE_DPLL_PIN_SW_2_IDX: + if (direction == DPLL_PIN_DIRECTION_INPUT) { + data &= ~ICE_SMA2_DIR_EN; + } else { + data &= ~ICE_SMA2_TX_EN; + data |= ICE_SMA2_DIR_EN; + } + break; + default: + return -EINVAL; + } + ret = ice_write_sma_ctrl(&p->pf->hw, data); + if (!ret) + ret = ice_dpll_pin_state_update(p->pf, p, + ICE_DPLL_PIN_TYPE_SOFTWARE, + extack); + + return ret; +} + +/** + * ice_dpll_ufl_pin_state_set - set U.FL pin state on dpll device + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: requested state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Set the state of a pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_ufl_pin_state_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, *target; + struct ice_dpll *d = dpll_priv; + enum ice_dpll_pin_type type; + struct ice_pf *pf = p->pf; + struct ice_hw *hw; + bool enable; + u8 data; + int ret; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + hw = &pf->hw; + ret = ice_read_sma_ctrl(hw, &data); + if (ret) + goto unlock; + + ret = -EINVAL; + switch (p->idx) { + case ICE_DPLL_PIN_SW_1_IDX: + if (state == DPLL_PIN_STATE_CONNECTED) { + data &= ~ICE_SMA1_MASK; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + data |= ICE_SMA1_TX_EN; + enable = false; + } else { + goto unlock; + } + target = p->output; + type = ICE_DPLL_PIN_TYPE_OUTPUT; + break; + case ICE_DPLL_PIN_SW_2_IDX: + if (state == DPLL_PIN_STATE_SELECTABLE) { + data |= ICE_SMA2_DIR_EN; + data &= ~ICE_SMA2_UFL2_RX_DIS; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + data |= ICE_SMA2_UFL2_RX_DIS; + enable = false; + } else { + goto unlock; + } + target = p->input; + type = ICE_DPLL_PIN_TYPE_INPUT; + break; + default: + goto unlock; + } + + ret = ice_write_sma_ctrl(hw, data); + if (ret) + goto unlock; + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOFTWARE, + extack); + if (ret) + goto unlock; + + if (enable) + ret = ice_dpll_pin_enable(hw, target, d->dpll_idx, type, extack); + else + ret = ice_dpll_pin_disable(hw, target, type, extack); + if (!ret) + ret = ice_dpll_pin_state_update(pf, target, type, extack); + +unlock: + mutex_unlock(&pf->dplls.lock); + + return ret; +} + +/** + * ice_dpll_sw_pin_state_get - get SW pin state + * @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 state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Check state of a SW pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_pin_state_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_dpll *d = dpll_priv; + struct ice_pf *pf = p->pf; + int ret = 0; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + mutex_lock(&pf->dplls.lock); + if (!p->active) { + *state = DPLL_PIN_STATE_DISCONNECTED; + goto unlock; + } + + if (p->direction == DPLL_PIN_DIRECTION_INPUT) { + ret = ice_dpll_pin_state_update(pf, p->input, + ICE_DPLL_PIN_TYPE_INPUT, + extack); + if (ret) + goto unlock; + *state = p->input->state[d->dpll_idx]; + } else { + ret = ice_dpll_pin_state_update(pf, p->output, + ICE_DPLL_PIN_TYPE_OUTPUT, + extack); + if (ret) + goto unlock; + *state = p->output->state[d->dpll_idx]; + } +unlock: + mutex_unlock(&pf->dplls.lock); + + return ret; +} + +/** + * ice_dpll_sma_pin_state_set - set SMA pin state on dpll device + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: requested state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Set state of a pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - failed to get state + */ +static int +ice_dpll_sma_pin_state_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 *sma = pin_priv, *target; + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = sma->pf; + enum ice_dpll_pin_type type; + bool enable; + int ret; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + if (!sma->active) { + ret = ice_dpll_sma_direction_set(sma, sma->direction, extack); + if (ret) + goto unlock; + } + if (sma->direction == DPLL_PIN_DIRECTION_INPUT) { + enable = state == DPLL_PIN_STATE_SELECTABLE; + target = sma->input; + type = ICE_DPLL_PIN_TYPE_INPUT; + } else { + enable = state == DPLL_PIN_STATE_CONNECTED; + target = sma->output; + type = ICE_DPLL_PIN_TYPE_OUTPUT; + } + + if (enable) + ret = ice_dpll_pin_enable(&pf->hw, target, d->dpll_idx, type, + extack); + else + ret = ice_dpll_pin_disable(&pf->hw, target, type, extack); + if (!ret) + ret = ice_dpll_pin_state_update(pf, target, type, extack); + +unlock: + mutex_unlock(&pf->dplls.lock); + + return ret; +} + +/** * ice_dpll_input_prio_get - get dpll's input prio * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration @@ -860,6 +1405,47 @@ ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv, return ret; } +static int +ice_dpll_sw_input_prio_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 *prio, struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = d->pf; + + mutex_lock(&pf->dplls.lock); + if (p->input && p->direction == DPLL_PIN_DIRECTION_INPUT) + *prio = d->input_prio[p->input->idx]; + else + *prio = ICE_DPLL_PIN_PRIO_OUTPUT; + mutex_unlock(&pf->dplls.lock); + + return 0; +} + +static int +ice_dpll_sw_input_prio_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 prio, struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = d->pf; + int ret; + + if (!p->input || p->direction != DPLL_PIN_DIRECTION_INPUT) + return -EINVAL; + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + ret = ice_dpll_hw_input_prio_set(pf, d, p->input, prio, extack); + mutex_unlock(&pf->dplls.lock); + + return ret; +} + /** * ice_dpll_input_direction - callback for get input pin direction * @pin: pointer to a pin @@ -911,6 +1497,76 @@ ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv, } /** + * ice_dpll_pin_sma_direction_set - callback for set SMA pin direction + * @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 + * @direction: requested pin direction + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting direction of a SMA pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; + int ret; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + + mutex_lock(&pf->dplls.lock); + ret = ice_dpll_sma_direction_set(p, direction, extack); + mutex_unlock(&pf->dplls.lock); + + return ret; +} + +/** + * ice_dpll_pin_sw_direction_get - callback for get SW pin direction + * @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 + * @direction: on success holds pin direction + * @extack: error reporting + * + * Dpll subsystem callback. Handler for getting direction of a SMA pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_pin_sw_direction_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction *direction, + 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); + *direction = p->direction; + mutex_unlock(&pf->dplls.lock); + + return 0; +} + +/** * ice_dpll_pin_phase_adjust_get - callback for get pin phase adjust value * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration @@ -1006,7 +1662,7 @@ ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to set pin phase_adjust:%d for pin:%u on dpll:%u", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), phase_adjust, p->idx, d->dpll_idx); return ret; @@ -1024,7 +1680,7 @@ ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, * Dpll subsystem callback. Wraps a handler for setting phase adjust on input * pin. * - * Context: Calls a function which acquires pf->dplls.lock + * Context: Calls a function which acquires and releases pf->dplls.lock * Return: * * 0 - success * * negative - error @@ -1068,6 +1724,82 @@ ice_dpll_output_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, ICE_DPLL_PIN_TYPE_OUTPUT); } +/** + * ice_dpll_sw_phase_adjust_get - callback for get SW pin phase adjust + * @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 + * @phase_adjust: on success holds phase adjust value + * @extack: error reporting + * + * Dpll subsystem callback. Wraps a handler for getting phase adjust on sw + * pin. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_phase_adjust_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + s32 *phase_adjust, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + if (p->direction == DPLL_PIN_DIRECTION_INPUT) + return ice_dpll_pin_phase_adjust_get(p->input->pin, p->input, + dpll, dpll_priv, + phase_adjust, extack); + else + return ice_dpll_pin_phase_adjust_get(p->output->pin, p->output, + dpll, dpll_priv, + phase_adjust, extack); +} + +/** + * ice_dpll_sw_phase_adjust_set - callback for set SW pin phase adjust value + * @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 + * @phase_adjust: phase_adjust to be set + * @extack: error reporting + * + * Dpll subsystem callback. Wraps a handler for setting phase adjust on output + * pin. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + s32 phase_adjust, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + if (!p->active) { + NL_SET_ERR_MSG(extack, "pin is not active"); + return -EINVAL; + } + if (p->direction == DPLL_PIN_DIRECTION_INPUT) + return ice_dpll_pin_phase_adjust_set(p->input->pin, p->input, + dpll, dpll_priv, + phase_adjust, extack, + ICE_DPLL_PIN_TYPE_INPUT); + else + return ice_dpll_pin_phase_adjust_set(p->output->pin, p->output, + dpll, dpll_priv, + phase_adjust, extack, + ICE_DPLL_PIN_TYPE_OUTPUT); +} + #define ICE_DPLL_PHASE_OFFSET_DIVIDER 100 #define ICE_DPLL_PHASE_OFFSET_FACTOR \ (DPLL_PHASE_OFFSET_DIVIDER / ICE_DPLL_PHASE_OFFSET_DIVIDER) @@ -1093,12 +1825,16 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, s64 *phase_offset, struct netlink_ext_ack *extack) { + struct ice_dpll_pin *p = pin_priv; struct ice_dpll *d = dpll_priv; struct ice_pf *pf = d->pf; mutex_lock(&pf->dplls.lock); - if (d->active_input == pin) + if (d->active_input == pin || (p->input && + 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; else *phase_offset = 0; mutex_unlock(&pf->dplls.lock); @@ -1315,6 +2051,219 @@ ice_dpll_input_esync_get(const struct dpll_pin *pin, void *pin_priv, } /** + * ice_dpll_sw_esync_set - callback for setting embedded sync on SW 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 + * @freq: requested embedded sync frequency + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting embedded sync frequency value + * on SW pin. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_esync_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 freq, struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + if (!p->active) { + NL_SET_ERR_MSG(extack, "pin is not active"); + return -EINVAL; + } + if (p->direction == DPLL_PIN_DIRECTION_INPUT) + return ice_dpll_input_esync_set(p->input->pin, p->input, dpll, + dpll_priv, freq, extack); + else + return ice_dpll_output_esync_set(p->output->pin, p->output, + dpll, dpll_priv, freq, extack); +} + +/** + * ice_dpll_sw_esync_get - callback for getting embedded sync on SW 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 + * @esync: on success holds embedded sync frequency and properties + * @extack: error reporting + * + * Dpll subsystem callback. Handler for getting embedded sync frequency value + * of SW pin. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_esync_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + struct dpll_pin_esync *esync, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + if (p->direction == DPLL_PIN_DIRECTION_INPUT) + return ice_dpll_input_esync_get(p->input->pin, p->input, dpll, + dpll_priv, esync, extack); + else + return ice_dpll_output_esync_get(p->output->pin, p->output, + dpll, dpll_priv, esync, + extack); +} + +/* + * ice_dpll_input_ref_sync_set - callback for setting reference sync feature + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @ref_pin: pin pointer for reference sync pair + * @ref_pin_priv: private data pointer of ref_pin + * @state: requested state for reference sync for pin pair + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting reference sync frequency + * feature for input pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_input_ref_sync_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *ref_pin, void *ref_pin_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; + u8 flags_en = 0; + int ret; + + if (ice_dpll_is_reset(pf, extack)) + return -EBUSY; + mutex_lock(&pf->dplls.lock); + + if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN) + flags_en = ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; + if (state == DPLL_PIN_STATE_CONNECTED) + flags_en |= ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN; + ret = ice_aq_set_input_pin_cfg(&pf->hw, p->idx, 0, flags_en, 0, 0); + if (!ret) + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_INPUT, + extack); + mutex_unlock(&pf->dplls.lock); + + return ret; +} + +/** + * ice_dpll_input_ref_sync_get - callback for getting reference sync config + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @ref_pin: pin pointer for reference sync pair + * @ref_pin_priv: private data pointer of ref_pin + * @state: on success holds reference sync state for pin pair + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting reference sync frequency + * feature for input pin. + * + * Context: Acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_input_ref_sync_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *ref_pin, void *ref_pin_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 (p->flags[0] & ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN) + *state = DPLL_PIN_STATE_CONNECTED; + else + *state = DPLL_PIN_STATE_DISCONNECTED; + mutex_unlock(&pf->dplls.lock); + + return 0; +} + +/* + * ice_dpll_sw_input_ref_sync_set - callback for setting reference sync feature + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @ref_pin: pin pointer for reference sync pair + * @ref_pin_priv: private data pointer of ref_pin + * @state: requested state for reference sync for pin pair + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting reference sync + * feature for input pins. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_input_ref_sync_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *ref_pin, + void *ref_pin_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + return ice_dpll_input_ref_sync_set(pin, p->input, ref_pin, ref_pin_priv, + state, extack); +} + +/** + * ice_dpll_sw_input_ref_sync_get - callback for getting reference sync config + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @ref_pin: pin pointer for reference sync pair + * @ref_pin_priv: private data pointer of ref_pin + * @state: on success holds reference sync state for pin pair + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting reference sync feature for + * input pins. + * + * Context: Calls a function which acquires and releases pf->dplls.lock + * Return: + * * 0 - success + * * negative - error + */ +static int +ice_dpll_sw_input_ref_sync_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *ref_pin, + void *ref_pin_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + struct ice_dpll_pin *p = pin_priv; + + return ice_dpll_input_ref_sync_get(pin, p->input, ref_pin, ref_pin_priv, + state, extack); +} + +/** * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration @@ -1364,7 +2313,7 @@ ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, NL_SET_ERR_MSG_FMT(extack, "err:%d %s failed to set pin state:%u for pin:%u on parent:%u", ret, - ice_aq_str(pf->hw.adminq.sq_last_status), + libie_aq_str(pf->hw.adminq.sq_last_status), state, p->idx, parent->idx); unlock: mutex_unlock(&pf->dplls.lock); @@ -1427,6 +2376,37 @@ static const struct dpll_pin_ops ice_dpll_rclk_ops = { .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, + .direction_get = ice_dpll_pin_sw_direction_get, + .direction_set = ice_dpll_pin_sma_direction_set, + .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, + .phase_adjust_get = ice_dpll_sw_phase_adjust_get, + .phase_adjust_set = ice_dpll_sw_phase_adjust_set, + .phase_offset_get = ice_dpll_phase_offset_get, + .esync_set = ice_dpll_sw_esync_set, + .esync_get = ice_dpll_sw_esync_get, + .ref_sync_set = ice_dpll_sw_input_ref_sync_set, + .ref_sync_get = ice_dpll_sw_input_ref_sync_get, +}; + +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, + .frequency_get = ice_dpll_sw_pin_frequency_get, + .frequency_set = ice_dpll_sw_pin_frequency_set, + .esync_set = ice_dpll_sw_esync_set, + .esync_get = ice_dpll_sw_esync_get, + .phase_adjust_get = ice_dpll_sw_phase_adjust_get, + .phase_adjust_set = ice_dpll_sw_phase_adjust_set, + .phase_offset_get = ice_dpll_phase_offset_get, +}; + static const struct dpll_pin_ops ice_dpll_input_ops = { .frequency_get = ice_dpll_input_frequency_get, .frequency_set = ice_dpll_input_frequency_set, @@ -1440,6 +2420,8 @@ static const struct dpll_pin_ops ice_dpll_input_ops = { .phase_offset_get = ice_dpll_phase_offset_get, .esync_set = ice_dpll_input_esync_set, .esync_get = ice_dpll_input_esync_get, + .ref_sync_set = ice_dpll_input_ref_sync_set, + .ref_sync_get = ice_dpll_input_ref_sync_get, }; static const struct dpll_pin_ops ice_dpll_output_ops = { @@ -1459,6 +2441,13 @@ static const struct dpll_device_ops ice_dpll_ops = { .mode_get = ice_dpll_mode_get, }; +static const struct dpll_device_ops ice_dpll_pom_ops = { + .lock_status_get = ice_dpll_lock_status_get, + .mode_get = ice_dpll_mode_get, + .phase_offset_monitor_set = ice_dpll_phase_offset_monitor_set, + .phase_offset_monitor_get = ice_dpll_phase_offset_monitor_get, +}; + /** * ice_generate_clock_id - generates unique clock_id for registering dpll. * @pf: board private structure @@ -1504,6 +2493,110 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) } /** + * ice_dpll_is_pps_phase_monitor - check if dpll capable of phase offset monitor + * @pf: pf private structure + * + * Check if firmware is capable of supporting admin command to provide + * phase offset monitoring on all the input pins on PPS dpll. + * + * Returns: + * * true - PPS dpll phase offset monitoring is supported + * * false - PPS dpll phase offset monitoring is not supported + */ +static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) +{ + struct ice_cgu_input_measure meas[ICE_DPLL_INPUT_REF_NUM]; + int 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_ESRCH) + return false; + + return true; +} + +/** + * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes + * @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 + * + * Iterate over array of pins and call dpll subsystem pin notify if + * corresponding pin index within bitmask is set. + * + * Context: Must be called while pf->dplls.lock is released. + */ +static void ice_dpll_pins_notify_mask(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); +} + +/** + * ice_dpll_pps_update_phase_offsets - update phase offset measurements + * @pf: pf private structure + * @phase_offset_pins_updated: returns mask of updated input pin indexes + * + * Read phase offset measurements for PPS dpll device and store values in + * input pins array. On success phase_offset_pins_updated - fills bitmask of + * updated input pin indexes, pins shall be notified. + * + * Context: Shall be called with pf->dplls.lock being locked. + * Returns: + * * 0 - success or no data available + * * negative - AQ failure + */ +static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf, + u32 *phase_offset_pins_updated) +{ + struct ice_cgu_input_measure meas[ICE_DPLL_INPUT_REF_NUM]; + struct ice_dpll_pin *p; + s64 phase_offset, tmp; + int i, j, ret; + + *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) { + return 0; + } else if (ret) { + dev_err(ice_pf_to_dev(pf), + "failed to get input pin measurements dpll=%d, ret=%d %s\n", + DPLL_TYPE_PPS, ret, + libie_aq_str(pf->hw.adminq.sq_last_status)); + return ret; + } + for (i = 0; i < pf->dplls.num_inputs; i++) { + p = &pf->dplls.inputs[i]; + phase_offset = 0; + for (j = 0; j < ICE_CGU_INPUT_PHASE_OFFSET_BYTES; j++) { + tmp = meas[i].phase_offset[j]; +#ifdef __LITTLE_ENDIAN + phase_offset += tmp << 8 * j; +#else + phase_offset += tmp << 8 * + (ICE_CGU_INPUT_PHASE_OFFSET_BYTES - 1 - j); +#endif + } + phase_offset = sign_extend64(phase_offset, 47); + if (p->phase_offset != phase_offset) { + dev_dbg(ice_pf_to_dev(pf), + "phase offset changed for pin:%d old:%llx, new:%llx\n", + p->idx, p->phase_offset, phase_offset); + p->phase_offset = phase_offset; + *phase_offset_pins_updated |= (1 << i); + } + } + + return 0; +} + +/** * ice_dpll_update_state - update dpll state * @pf: pf private structure * @d: pointer to queried dpll device @@ -1534,7 +2627,7 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) dev_err(ice_pf_to_dev(pf), "update dpll=%d state failed, ret=%d %s\n", d->dpll_idx, ret, - ice_aq_str(pf->hw.adminq.sq_last_status)); + libie_aq_str(pf->hw.adminq.sq_last_status)); return ret; } if (init) { @@ -1589,14 +2682,19 @@ static void ice_dpll_periodic_work(struct kthread_work *work) struct ice_pf *pf = container_of(d, struct ice_pf, dplls); struct ice_dpll *de = &pf->dplls.eec; struct ice_dpll *dp = &pf->dplls.pps; + u32 phase_offset_ntf = 0; int ret = 0; if (ice_is_reset_in_progress(pf->state)) goto resched; mutex_lock(&pf->dplls.lock); + d->periodic_counter++; ret = ice_dpll_update_state(pf, de, false); if (!ret) ret = ice_dpll_update_state(pf, dp, false); + if (!ret && dp->phase_offset_monitor_period && + d->periodic_counter % dp->phase_offset_monitor_period == 0) + ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf); if (ret) { d->cgu_state_acq_err_num++; /* stop rescheduling this worker */ @@ -1611,6 +2709,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work) mutex_unlock(&pf->dplls.lock); ice_dpll_notify_changes(de); ice_dpll_notify_changes(dp); + if (phase_offset_ntf) + ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, + phase_offset_ntf); resched: /* Run twice a second or reschedule if update failed */ @@ -1620,6 +2721,88 @@ resched: } /** + * ice_dpll_init_ref_sync_inputs - initialize reference sync pin pairs + * @pf: pf private structure + * + * Read DPLL TLV capabilities and initialize reference sync pin pairs in + * dpll subsystem. + * + * Return: + * * 0 - success or nothing to do (no ref-sync tlv are present) + * * negative - AQ failure + */ +static int ice_dpll_init_ref_sync_inputs(struct ice_pf *pf) +{ + struct ice_dpll_pin *inputs = pf->dplls.inputs; + struct ice_hw *hw = &pf->hw; + u16 addr, len, end, hdr; + int ret; + + ret = ice_get_pfa_module_tlv(hw, &hdr, &len, ICE_SR_PFA_DPLL_DEFAULTS); + if (ret) { + dev_err(ice_pf_to_dev(pf), + "Failed to read PFA dpll defaults TLV ret=%d\n", ret); + return ret; + } + end = hdr + len; + + for (addr = hdr + ICE_DPLL_PFA_HEADER_LEN; addr < end; + addr += ICE_DPLL_PFA_ENTRY_LEN) { + unsigned long bit, ul_mask, offset; + u16 pin, mask, buf; + bool valid = false; + + ret = ice_read_sr_word(hw, addr, &buf); + if (ret) + return ret; + + switch (buf) { + case ICE_DPLL_PFA_REF_SYNC_TYPE: + case ICE_DPLL_PFA_REF_SYNC_TYPE2: + { + u16 mask_addr = addr + ICE_DPLL_PFA_MASK_OFFSET; + u16 val_addr = addr + ICE_DPLL_PFA_VALUE_OFFSET; + + ret = ice_read_sr_word(hw, mask_addr, &mask); + if (ret) + return ret; + ret = ice_read_sr_word(hw, val_addr, &pin); + if (ret) + return ret; + if (buf == ICE_DPLL_PFA_REF_SYNC_TYPE) + pin >>= ICE_DPLL_PFA_MAILBOX_REF_SYNC_PIN_S; + valid = true; + break; + } + case ICE_DPLL_PFA_END: + addr = end; + break; + default: + continue; + } + if (!valid) + continue; + + ul_mask = mask; + offset = 0; + for_each_set_bit(bit, &ul_mask, BITS_PER_TYPE(u16)) { + int i, j; + + if (hw->device_id == ICE_DEV_ID_E810C_SFP && + pin > ICE_DPLL_E810C_SFP_NC_START) + offset = -ICE_DPLL_E810C_SFP_NC_PINS; + i = pin + offset; + j = bit + offset; + if (i < 0 || j < 0) + return -ERANGE; + inputs[i].ref_sync = j; + } + } + + return 0; +} + +/** * ice_dpll_release_pins - release pins resources from dpll subsystem * @pins: pointer to pins array * @count: number of pins @@ -1689,7 +2872,38 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, int i; for (i = 0; i < count; i++) - dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); + if (!pins[i].hidden) + dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); +} + +/** + * ice_dpll_pin_ref_sync_register - register reference sync pins + * @pins: pointer to pins array + * @count: number of pins + * + * Register reference sync pins in dpll subsystem. + * + * Return: + * * 0 - success + * * negative - registration failure reason + */ +static int +ice_dpll_pin_ref_sync_register(struct ice_dpll_pin *pins, int count) +{ + int ret, i; + + for (i = 0; i < count; i++) { + if (!pins[i].hidden && pins[i].ref_sync) { + int j = pins[i].ref_sync; + + ret = dpll_pin_ref_sync_pair_add(pins[i].pin, + pins[j].pin); + if (ret) + return ret; + } + } + + return 0; } /** @@ -1712,16 +2926,19 @@ ice_dpll_register_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, int ret, i; for (i = 0; i < count; i++) { - ret = dpll_pin_register(dpll, pins[i].pin, ops, &pins[i]); - if (ret) - goto unregister_pins; + if (!pins[i].hidden) { + ret = dpll_pin_register(dpll, pins[i].pin, ops, &pins[i]); + if (ret) + goto unregister_pins; + } } return 0; unregister_pins: while (--i >= 0) - dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); + if (!pins[i].hidden) + dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); return ret; } @@ -1909,6 +3126,18 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) ice_dpll_unregister_pins(de->dpll, outputs, &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_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_PIN_SW_NUM, + &ice_dpll_pin_sma_ops, + pf->dplls.pps.dpll, + pf->dplls.eec.dpll); + } } } @@ -1926,8 +3155,7 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) */ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) { - u32 rclk_idx; - int ret; + int ret, count; ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0, pf->dplls.num_inputs, @@ -1935,23 +3163,64 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) 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, - pf->dplls.num_inputs, + count, pf->dplls.num_outputs, &ice_dpll_output_ops, pf->dplls.eec.dpll, pf->dplls.pps.dpll); if (ret) goto deinit_inputs; + count += pf->dplls.num_outputs; + if (!pf->dplls.generic) { + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.sma, + count, + ICE_DPLL_PIN_SW_NUM, + &ice_dpll_pin_sma_ops, + pf->dplls.eec.dpll, + pf->dplls.pps.dpll); + if (ret) + goto deinit_outputs; + count += ICE_DPLL_PIN_SW_NUM; + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.ufl, + count, + ICE_DPLL_PIN_SW_NUM, + &ice_dpll_pin_ufl_ops, + pf->dplls.eec.dpll, + pf->dplls.pps.dpll); + if (ret) + goto deinit_sma; + count += ICE_DPLL_PIN_SW_NUM; + } + ret = ice_dpll_pin_ref_sync_register(pf->dplls.inputs, + pf->dplls.num_inputs); + if (ret) + goto deinit_ufl; + ret = ice_dpll_pin_ref_sync_register(pf->dplls.sma, + ICE_DPLL_PIN_SW_NUM); + if (ret) + goto deinit_ufl; + } else { + count += pf->dplls.num_outputs + 2 * ICE_DPLL_PIN_SW_NUM; } - rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; - ret = ice_dpll_init_rclk_pins(pf, &pf->dplls.rclk, rclk_idx, + ret = ice_dpll_init_rclk_pins(pf, &pf->dplls.rclk, count + pf->hw.pf_id, &ice_dpll_rclk_ops); if (ret) - goto deinit_outputs; + 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); +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); deinit_outputs: ice_dpll_deinit_direct_pins(cgu, pf->dplls.outputs, pf->dplls.num_outputs, @@ -1977,7 +3246,7 @@ static void ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu) { if (cgu) - dpll_device_unregister(d->dpll, &ice_dpll_ops, d); + dpll_device_unregister(d->dpll, d->ops, d); dpll_device_put(d->dpll); } @@ -2011,12 +3280,17 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, } d->pf = pf; if (cgu) { + 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); - ret = dpll_device_register(d->dpll, type, &ice_dpll_ops, d); + ret = dpll_device_register(d->dpll, type, ops, d); if (ret) { dpll_device_put(d->dpll); return ret; } + d->ops = ops; } return 0; @@ -2184,8 +3458,10 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, default: return -EINVAL; } - if (num_pins != ice_cgu_get_num_pins(hw, input)) + if (num_pins != ice_cgu_get_num_pins(hw, input)) { + pf->dplls.generic = true; return ice_dpll_init_info_pins_generic(pf, input); + } for (i = 0; i < num_pins; i++) { caps = 0; @@ -2203,10 +3479,14 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, return ret; caps |= (DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE); + if (ice_dpll_is_sw_pin(pf, i, true)) + pins[i].hidden = true; } else { ret = ice_cgu_get_output_pin_state_caps(hw, i, &caps); if (ret) return ret; + if (ice_dpll_is_sw_pin(pf, i, false)) + pins[i].hidden = true; } ice_dpll_phase_range_set(&pins[i].prop.phase_range, phase_adj_max); @@ -2219,6 +3499,8 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, pins[i].prop.freq_supported_num = freq_supp_num; pins[i].pf = pf; } + if (input) + ret = ice_dpll_init_ref_sync_inputs(pf); return ret; } @@ -2246,6 +3528,91 @@ static int ice_dpll_init_info_rclk_pin(struct ice_pf *pf) } /** + * ice_dpll_init_info_sw_pins - initializes software controlled pin information + * @pf: board private structure + * + * Init information for software controlled pins, cache them in + * pf->dplls.sma and pf->dplls.ufl. + * + * Return: + * * 0 - success + * * negative - init failure reason + */ +static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) +{ + u8 freq_supp_num, pin_abs_idx, input_idx_offset = 0; + struct ice_dplls *d = &pf->dplls; + struct ice_dpll_pin *pin; + u32 phase_adj_max, caps; + int i, ret; + + if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) + input_idx_offset = ICE_E810_RCLK_PINS_NUM; + phase_adj_max = max(d->input_phase_adj_max, d->output_phase_adj_max); + caps = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + for (i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { + pin = &d->sma[i]; + pin->idx = i; + pin->prop.type = DPLL_PIN_TYPE_EXT; + pin_abs_idx = ICE_DPLL_PIN_SW_INPUT_ABS(i) + input_idx_offset; + pin->prop.freq_supported = + ice_cgu_get_pin_freq_supp(&pf->hw, pin_abs_idx, + true, &freq_supp_num); + pin->prop.freq_supported_num = freq_supp_num; + pin->prop.capabilities = + (DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE | + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | + caps); + pin->pf = pf; + pin->prop.board_label = ice_dpll_sw_pin_sma[i]; + pin->input = &d->inputs[pin_abs_idx]; + if (pin->input->ref_sync) + pin->ref_sync = pin->input->ref_sync - pin_abs_idx; + pin->output = &d->outputs[ICE_DPLL_PIN_SW_OUTPUT_ABS(i)]; + ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); + } + for (i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { + pin = &d->ufl[i]; + pin->idx = i; + pin->prop.type = DPLL_PIN_TYPE_EXT; + pin->prop.capabilities = caps; + pin->pf = pf; + pin->prop.board_label = ice_dpll_sw_pin_ufl[i]; + if (i == ICE_DPLL_PIN_SW_1_IDX) { + pin->direction = DPLL_PIN_DIRECTION_OUTPUT; + pin_abs_idx = ICE_DPLL_PIN_SW_OUTPUT_ABS(i); + pin->prop.freq_supported = + ice_cgu_get_pin_freq_supp(&pf->hw, pin_abs_idx, + false, + &freq_supp_num); + pin->prop.freq_supported_num = freq_supp_num; + pin->input = NULL; + pin->output = &d->outputs[pin_abs_idx]; + } else if (i == ICE_DPLL_PIN_SW_2_IDX) { + pin->direction = DPLL_PIN_DIRECTION_INPUT; + pin_abs_idx = ICE_DPLL_PIN_SW_INPUT_ABS(i) + + input_idx_offset; + pin->output = NULL; + pin->input = &d->inputs[pin_abs_idx]; + pin->prop.freq_supported = + ice_cgu_get_pin_freq_supp(&pf->hw, pin_abs_idx, + true, &freq_supp_num); + pin->prop.freq_supported_num = freq_supp_num; + pin->prop.capabilities = + (DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | + caps); + } + ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); + } + ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, + NULL); + if (ret) + return ret; + + return 0; +} + +/** * ice_dpll_init_pins_info - init pins info wrapper * @pf: board private structure * @pin_type: type of pins being initialized @@ -2265,6 +3632,8 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) 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); + case ICE_DPLL_PIN_TYPE_SOFTWARE: + return ice_dpll_init_info_sw_pins(pf); default: return -EINVAL; } @@ -2309,7 +3678,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) if (ret) { dev_err(ice_pf_to_dev(pf), "err:%d %s failed to read cgu abilities\n", - ret, ice_aq_str(hw->adminq.sq_last_status)); + ret, libie_aq_str(hw->adminq.sq_last_status)); return ret; } @@ -2351,6 +3720,9 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT); if (ret) goto deinit_info; + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_SOFTWARE); + if (ret) + goto deinit_info; } ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index c320f1bf7d6d..c0da03384ce9 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -8,6 +8,18 @@ #define ICE_DPLL_RCLK_NUM_MAX 4 +/** + * enum ice_dpll_pin_sw - enumerate ice software pin indices: + * @ICE_DPLL_PIN_SW_1_IDX: index of first SW pin + * @ICE_DPLL_PIN_SW_2_IDX: index of second SW pin + * @ICE_DPLL_PIN_SW_NUM: number of SW pins in pair + */ +enum ice_dpll_pin_sw { + ICE_DPLL_PIN_SW_1_IDX, + ICE_DPLL_PIN_SW_2_IDX, + ICE_DPLL_PIN_SW_NUM +}; + /** ice_dpll_pin - store info about pins * @pin: dpll pin structure * @pf: pointer to pf, which has registered the dpll_pin @@ -19,6 +31,8 @@ * @prop: pin properties * @freq: current frequency of a pin * @phase_adjust: current phase adjust value + * @phase_offset: monitored phase offset value + * @ref_sync: store id of reference sync pin */ struct ice_dpll_pin { struct dpll_pin *pin; @@ -31,7 +45,14 @@ struct ice_dpll_pin { struct dpll_pin_properties prop; u32 freq; s32 phase_adjust; + struct ice_dpll_pin *input; + struct ice_dpll_pin *output; + enum dpll_pin_direction direction; + s64 phase_offset; u8 status; + u8 ref_sync; + bool active; + bool hidden; }; /** ice_dpll - store info required for DPLL control @@ -47,8 +68,10 @@ struct ice_dpll_pin { * @input_prio: priorities of each input * @dpll_state: current dpll sync state * @prev_dpll_state: last dpll sync state + * @phase_offset_monitor_period: period for phase offset monitor read frequency * @active_input: pointer to active input pin * @prev_input: pointer to previous active input pin + * @ops: holds the registered ops */ struct ice_dpll { struct dpll_device *dpll; @@ -64,8 +87,10 @@ struct ice_dpll { enum dpll_lock_status dpll_state; enum dpll_lock_status prev_dpll_state; enum dpll_mode mode; + u32 phase_offset_monitor_period; struct dpll_pin *active_input; struct dpll_pin *prev_input; + const struct dpll_device_ops *ops; }; /** ice_dplls - store info required for CCU (clock controlling unit) @@ -84,6 +109,7 @@ struct ice_dpll { * @clock_id: clock_id of dplls * @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 */ struct ice_dplls { struct kthread_worker *kworker; @@ -93,14 +119,19 @@ struct ice_dplls { struct ice_dpll pps; 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; u8 num_inputs; u8 num_outputs; - int cgu_state_acq_err_num; + u8 sma_data; u8 base_rclk_idx; + int cgu_state_acq_err_num; u64 clock_id; s32 input_phase_adj_max; s32 output_phase_adj_max; + u32 periodic_counter; + bool generic; }; #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index bbf9e6fd315b..dc131779d426 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -667,7 +667,8 @@ static int ice_get_port_topology(struct ice_hw *hw, u8 lport, if (max_speed == ICE_AQC_PORT_OPT_MAX_LANE_100G) port_topology->serdes_lane_count = 4; - else if (max_speed == ICE_AQC_PORT_OPT_MAX_LANE_50G) + else if (max_speed == ICE_AQC_PORT_OPT_MAX_LANE_50G || + max_speed == ICE_AQC_PORT_OPT_MAX_LANE_40G) port_topology->serdes_lane_count = 2; else port_topology->serdes_lane_count = 1; @@ -836,6 +837,15 @@ static void ice_set_msglevel(struct net_device *netdev, u32 data) #endif /* !CONFIG_DYNAMIC_DEBUG */ } +static void ice_get_link_ext_stats(struct net_device *netdev, + struct ethtool_link_ext_stats *stats) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; + + stats->link_down_events = pf->link_down_events; +} + static int ice_get_eeprom_len(struct net_device *netdev) { struct ice_netdev_priv *np = netdev_priv(netdev); @@ -869,7 +879,7 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, ret = ice_acquire_nvm(hw, ICE_RES_READ); if (ret) { dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %s\n", - ret, ice_aq_str(hw->adminq.sq_last_status)); + ret, libie_aq_str(hw->adminq.sq_last_status)); goto out; } @@ -877,7 +887,7 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, false); if (ret) { dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n", - ret, ice_aq_str(hw->adminq.sq_last_status)); + ret, libie_aq_str(hw->adminq.sq_last_status)); goto release; } @@ -2788,14 +2798,7 @@ done: return err; } -/** - * ice_parse_hdrs - parses headers from RSS hash input - * @nfc: ethtool rxnfc command - * - * This function parses the rxnfc command and returns intended - * header types for RSS configuration - */ -static u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc) +static u32 ice_parse_hdrs(const struct ethtool_rxfh_fields *nfc) { u32 hdrs = ICE_FLOW_SEG_HDR_NONE; @@ -2860,15 +2863,7 @@ static u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc) return hdrs; } -/** - * ice_parse_hash_flds - parses hash fields from RSS hash input - * @nfc: ethtool rxnfc command - * @symm: true if Symmetric Topelitz is set - * - * This function parses the rxnfc command and returns intended - * hash fields for RSS configuration - */ -static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc, bool symm) +static u64 ice_parse_hash_flds(const struct ethtool_rxfh_fields *nfc, bool symm) { u64 hfld = ICE_HASH_INVALID; @@ -2965,16 +2960,13 @@ static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc, bool symm) return hfld; } -/** - * ice_set_rss_hash_opt - Enable/Disable flow types for RSS hash - * @vsi: the VSI being configured - * @nfc: ethtool rxnfc command - * - * Returns Success if the flow input set is supported. - */ static int -ice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) +ice_set_rxfh_fields(struct net_device *netdev, + const struct ethtool_rxfh_fields *nfc, + struct netlink_ext_ack *extack) { + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; struct ice_rss_hash_cfg cfg; struct device *dev; @@ -3020,14 +3012,11 @@ ice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) return 0; } -/** - * ice_get_rss_hash_opt - Retrieve hash fields for a given flow-type - * @vsi: the VSI being configured - * @nfc: ethtool rxnfc command - */ -static void -ice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) +static int +ice_get_rxfh_fields(struct net_device *netdev, struct ethtool_rxfh_fields *nfc) { + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; struct device *dev; u64 hash_flds; @@ -3040,21 +3029,21 @@ ice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) if (ice_is_safe_mode(pf)) { dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", vsi->vsi_num); - return; + return 0; } hdrs = ice_parse_hdrs(nfc); if (hdrs == ICE_FLOW_SEG_HDR_NONE) { dev_dbg(dev, "Header type is not valid, vsi num = %d\n", vsi->vsi_num); - return; + return 0; } hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs, &symm); if (hash_flds == ICE_HASH_INVALID) { dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n", vsi->vsi_num); - return; + return 0; } if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_SA || @@ -3081,6 +3070,8 @@ ice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) hash_flds & ICE_FLOW_HASH_FLD_GTPU_UP_TEID || hash_flds & ICE_FLOW_HASH_FLD_GTPU_DWN_TEID) nfc->data |= (u64)RXH_GTP_TEID; + + return 0; } /** @@ -3100,8 +3091,6 @@ static int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) return ice_add_fdir_ethtool(vsi, cmd); case ETHTOOL_SRXCLSRLDEL: return ice_del_fdir_ethtool(vsi, cmd); - case ETHTOOL_SRXFH: - return ice_set_rss_hash_opt(vsi, cmd); default: break; } @@ -3144,10 +3133,6 @@ ice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, case ETHTOOL_GRXCLSRLALL: ret = ice_get_fdir_fltr_ids(hw, cmd, (u32 *)rule_locs); break; - case ETHTOOL_GRXFH: - ice_get_rss_hash_opt(vsi, cmd); - ret = 0; - break; default: break; } @@ -3162,9 +3147,11 @@ ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; + struct ice_hw *hw; - ring->rx_max_pending = ICE_MAX_NUM_DESC; - ring->tx_max_pending = ICE_MAX_NUM_DESC; + hw = &vsi->back->hw; + ring->rx_max_pending = ICE_MAX_NUM_DESC_BY_MAC(hw); + ring->tx_max_pending = ICE_MAX_NUM_DESC_BY_MAC(hw); if (vsi->tx_rings && vsi->rx_rings) { ring->rx_pending = vsi->rx_rings[0]->count; ring->tx_pending = vsi->tx_rings[0]->count; @@ -3192,15 +3179,16 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; int i, timeout = 50, err = 0; + struct ice_hw *hw = &pf->hw; u16 new_rx_cnt, new_tx_cnt; - if (ring->tx_pending > ICE_MAX_NUM_DESC || + if (ring->tx_pending > ICE_MAX_NUM_DESC_BY_MAC(hw) || ring->tx_pending < ICE_MIN_NUM_DESC || - ring->rx_pending > ICE_MAX_NUM_DESC || + ring->rx_pending > ICE_MAX_NUM_DESC_BY_MAC(hw) || ring->rx_pending < ICE_MIN_NUM_DESC) { netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n", ring->tx_pending, ring->rx_pending, - ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, + ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC_BY_MAC(hw), ICE_REQ_DESC_MULTIPLE); return -EINVAL; } @@ -3273,6 +3261,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, tx_rings[i].count = new_tx_cnt; tx_rings[i].desc = NULL; tx_rings[i].tx_buf = NULL; + tx_rings[i].tstamp_ring = NULL; tx_rings[i].tx_tstamps = &pf->ptp.port.tx; err = ice_setup_tx_ring(&tx_rings[i]); if (err) { @@ -3557,15 +3546,15 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) if (aq_failures & 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, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; } else if (aq_failures & 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, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; } else if (aq_failures & 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, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; } @@ -3607,11 +3596,10 @@ static int ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) { struct ice_netdev_priv *np = netdev_priv(netdev); - u32 rss_context = rxfh->rss_context; struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; u16 qcount, offset; - int err, num_tc, i; + int err, i; u8 *lut; if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { @@ -3619,24 +3607,8 @@ ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) return -EOPNOTSUPP; } - if (rss_context && !ice_is_adq_active(pf)) { - netdev_err(netdev, "RSS context cannot be non-zero when ADQ is not configured.\n"); - return -EINVAL; - } - - qcount = vsi->mqprio_qopt.qopt.count[rss_context]; - offset = vsi->mqprio_qopt.qopt.offset[rss_context]; - - if (rss_context && ice_is_adq_active(pf)) { - num_tc = vsi->mqprio_qopt.qopt.num_tc; - if (rss_context >= num_tc) { - netdev_err(netdev, "RSS context:%d > num_tc:%d\n", - rss_context, num_tc); - return -EINVAL; - } - /* Use channel VSI of given TC */ - vsi = vsi->tc_map_vsi[rss_context]; - } + qcount = vsi->mqprio_qopt.qopt.count[0]; + offset = vsi->mqprio_qopt.qopt.offset[0]; rxfh->hfunc = ETH_RSS_HASH_TOP; if (vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ) @@ -3696,9 +3668,6 @@ ice_set_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh, rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; - if (rxfh->rss_context) - return -EOPNOTSUPP; - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { /* RSS not supported return error here */ netdev_warn(netdev, "RSS is not configured on this VSI!\n"); @@ -3896,7 +3865,7 @@ static int ice_vsi_set_dflt_rss_lut(struct ice_vsi *vsi, int req_rss_size) err = ice_set_rss_lut(vsi, lut, vsi->rss_table_size); if (err) dev_err(dev, "Cannot set RSS lut, err %d aq_err %s\n", err, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); kfree(lut); return err; @@ -4655,10 +4624,12 @@ static int ice_get_port_fec_stats(struct ice_hw *hw, u16 pcs_quad, u16 pcs_port, * ice_get_fec_stats - returns FEC correctable, uncorrectable stats per netdev * @netdev: network interface device structure * @fec_stats: buffer to hold FEC statistics for given port + * @hist: buffer to put FEC histogram statistics for given port * */ static void ice_get_fec_stats(struct net_device *netdev, - struct ethtool_fec_stats *fec_stats) + struct ethtool_fec_stats *fec_stats, + struct ethtool_fec_hist *hist) { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_port_topology port_topology; @@ -4766,12 +4737,10 @@ static int ice_repr_ethtool_reset(struct net_device *dev, u32 *flags) } static const struct ethtool_ops ice_ethtool_ops = { - .cap_rss_ctx_supported = true, .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_USE_ADAPTIVE | ETHTOOL_COALESCE_RX_USECS_HIGH, .supported_input_xfrm = RXH_XFRM_SYM_XOR, - .rxfh_per_ctx_key = true, .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings, .get_fec_stats = ice_get_fec_stats, @@ -4784,6 +4753,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .set_msglevel = ice_set_msglevel, .self_test = ice_self_test, .get_link = ethtool_op_get_link, + .get_link_ext_stats = ice_get_link_ext_stats, .get_eeprom_len = ice_get_eeprom_len, .get_eeprom = ice_get_eeprom, .get_coalesce = ice_get_coalesce, @@ -4806,6 +4776,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_rxfh_indir_size = ice_get_rxfh_indir_size, .get_rxfh = ice_get_rxfh, .set_rxfh = ice_set_rxfh, + .get_rxfh_fields = ice_get_rxfh_fields, + .set_rxfh_fields = ice_set_rxfh_fields, .get_channels = ice_get_channels, .set_channels = ice_set_channels, .get_ts_info = ice_get_ts_info, diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c index ed95072ca6e3..363ae79a3620 100644 --- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c +++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c @@ -3043,16 +3043,16 @@ ice_disable_fd_swap(struct ice_hw *hw, u8 prof_id) * the ID value used here. */ int -ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[], - const struct ice_ptype_attributes *attr, u16 attr_cnt, - struct ice_fv_word *es, u16 *masks, bool symm, bool fd_swap) +ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, + unsigned long *ptypes, const struct ice_ptype_attributes *attr, + u16 attr_cnt, struct ice_fv_word *es, u16 *masks, bool symm, + bool fd_swap) { - u32 bytes = DIV_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE); DECLARE_BITMAP(ptgs_used, ICE_XLT1_CNT); struct ice_prof_map *prof; - u8 byte = 0; - u8 prof_id; int status; + u8 prof_id; + u16 ptype; bitmap_zero(ptgs_used, ICE_XLT1_CNT); @@ -3102,57 +3102,35 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[], prof->context = 0; /* build list of ptgs */ - while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) { - u8 bit; + for_each_set_bit(ptype, ptypes, ICE_FLOW_PTYPE_MAX) { + u8 ptg; - if (!ptypes[byte]) { - bytes--; - byte++; + /* The package should place all ptypes in a non-zero + * PTG, so the following call should never fail. + */ + if (ice_ptg_find_ptype(hw, blk, ptype, &ptg)) continue; - } - /* Examine 8 bits per byte */ - for_each_set_bit(bit, (unsigned long *)&ptypes[byte], - BITS_PER_BYTE) { - u16 ptype; - u8 ptg; - - ptype = byte * BITS_PER_BYTE + bit; - - /* The package should place all ptypes in a non-zero - * PTG, so the following call should never fail. - */ - if (ice_ptg_find_ptype(hw, blk, ptype, &ptg)) - continue; + /* If PTG is already added, skip and continue */ + if (test_bit(ptg, ptgs_used)) + continue; - /* If PTG is already added, skip and continue */ - if (test_bit(ptg, ptgs_used)) - continue; + set_bit(ptg, ptgs_used); + /* Check to see there are any attributes for this ptype, and + * add them if found. + */ + status = ice_add_prof_attrib(prof, ptg, ptype, attr, attr_cnt); + if (status == -ENOSPC) + break; + if (status) { + /* This is simple a ptype/PTG with no attribute */ + prof->ptg[prof->ptg_cnt] = ptg; + prof->attr[prof->ptg_cnt].flags = 0; + prof->attr[prof->ptg_cnt].mask = 0; - __set_bit(ptg, ptgs_used); - /* Check to see there are any attributes for - * this PTYPE, and add them if found. - */ - status = ice_add_prof_attrib(prof, ptg, ptype, - attr, attr_cnt); - if (status == -ENOSPC) + if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE) break; - if (status) { - /* This is simple a PTYPE/PTG with no - * attribute - */ - prof->ptg[prof->ptg_cnt] = ptg; - prof->attr[prof->ptg_cnt].flags = 0; - prof->attr[prof->ptg_cnt].mask = 0; - - if (++prof->ptg_cnt >= - ICE_MAX_PTG_PER_PROFILE) - break; - } } - - bytes--; - byte++; } list_add(&prof->list, &hw->blk[blk].es.prof_map); diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h index 28b0897adf32..ee5d9f9c9d53 100644 --- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h +++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h @@ -39,9 +39,10 @@ bool ice_hw_ptype_ena(struct ice_hw *hw, u16 ptype); /* XLT2/VSI group functions */ int -ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[], - const struct ice_ptype_attributes *attr, u16 attr_cnt, - struct ice_fv_word *es, u16 *masks, bool symm, bool fd_swap); +ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, + unsigned long *ptypes, const struct ice_ptype_attributes *attr, + u16 attr_cnt, struct ice_fv_word *es, u16 *masks, bool symm, + bool fd_swap); struct ice_prof_map * ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id); int diff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c index d97b751052f2..6d5c939dc8a5 100644 --- a/drivers/net/ethernet/intel/ice/ice_flow.c +++ b/drivers/net/ethernet/intel/ice/ice_flow.c @@ -1421,7 +1421,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk, } /* Add a HW profile for this flow profile */ - status = ice_add_prof(hw, blk, prof_id, (u8 *)params->ptypes, + status = ice_add_prof(hw, blk, prof_id, params->ptypes, params->attr, params->attr_cnt, params->es, params->mask, symm, true); if (status) { @@ -1617,7 +1617,7 @@ ice_flow_set_parser_prof(struct ice_hw *hw, u16 dest_vsi, u16 fdir_vsi, break; } - status = ice_add_prof(hw, blk, id, (u8 *)prof->ptypes, + status = ice_add_prof(hw, blk, id, prof->ptypes, params->attr, params->attr_cnt, params->es, params->mask, false, false); if (status) @@ -2573,38 +2573,38 @@ ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, * convert its values to their appropriate flow L3, L4 values. */ #define ICE_FLOW_AVF_RSS_IPV4_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV4)) #define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP)) #define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_UDP)) #define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \ (ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \ - ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) + ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP)) #define ICE_FLOW_AVF_RSS_IPV6_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV6)) #define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_UDP)) #define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \ - (BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP)) + (BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP)) #define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \ (ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \ - ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) + ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP)) /** * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver * @hw: pointer to the hardware structure * @vsi: VF's VSI - * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure + * @avf_hash: hash bit fields (LIBIE_FILTER_PCTYPE_*) to configure * * This function will take the hash bitmap provided by the AVF driver via a * message, convert it to ICE-compatible values, and configure RSS flow @@ -2621,8 +2621,7 @@ int ice_add_avf_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi, u64 avf_hash) return -EINVAL; vsi_handle = vsi->idx; - if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID || - !ice_is_vsi_valid(hw, vsi_handle)) + if (!avf_hash || !ice_is_vsi_valid(hw, vsi_handle)) return -EINVAL; /* Make sure no unsupported bits are specified */ @@ -2658,11 +2657,11 @@ int ice_add_avf_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi, u64 avf_hash) ICE_FLOW_HASH_UDP_PORT; hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS; } else if (hash_flds & - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) { + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP)) { rss_hash = ICE_FLOW_HASH_IPV4 | ICE_FLOW_HASH_SCTP_PORT; hash_flds &= - ~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP); + ~BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP); } } else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) { if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) { @@ -2679,11 +2678,11 @@ int ice_add_avf_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi, u64 avf_hash) ICE_FLOW_HASH_UDP_PORT; hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS; } else if (hash_flds & - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) { + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP)) { rss_hash = ICE_FLOW_HASH_IPV6 | ICE_FLOW_HASH_SCTP_PORT; hash_flds &= - ~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP); + ~BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP); } } diff --git a/drivers/net/ethernet/intel/ice/ice_flow.h b/drivers/net/ethernet/intel/ice/ice_flow.h index 6cb7bb879c98..52f906d89eca 100644 --- a/drivers/net/ethernet/intel/ice/ice_flow.h +++ b/drivers/net/ethernet/intel/ice/ice_flow.h @@ -4,6 +4,8 @@ #ifndef _ICE_FLOW_H_ #define _ICE_FLOW_H_ +#include <linux/net/intel/libie/pctype.h> + #include "ice_flex_type.h" #include "ice_parser.h" @@ -264,57 +266,27 @@ enum ice_flow_field { #define ICE_FLOW_HASH_FLD_GTPU_DWN_TEID \ BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_DWN_TEID) -/* Flow headers and fields for AVF support */ -enum ice_flow_avf_hdr_field { - /* Values 0 - 28 are reserved for future use */ - ICE_AVF_FLOW_FIELD_INVALID = 0, - ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP = 29, - ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP, - ICE_AVF_FLOW_FIELD_IPV4_UDP, - ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK, - ICE_AVF_FLOW_FIELD_IPV4_TCP, - ICE_AVF_FLOW_FIELD_IPV4_SCTP, - ICE_AVF_FLOW_FIELD_IPV4_OTHER, - ICE_AVF_FLOW_FIELD_FRAG_IPV4, - /* Values 37-38 are reserved */ - ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP = 39, - ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP, - ICE_AVF_FLOW_FIELD_IPV6_UDP, - ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK, - ICE_AVF_FLOW_FIELD_IPV6_TCP, - ICE_AVF_FLOW_FIELD_IPV6_SCTP, - ICE_AVF_FLOW_FIELD_IPV6_OTHER, - ICE_AVF_FLOW_FIELD_FRAG_IPV6, - ICE_AVF_FLOW_FIELD_RSVD47, - ICE_AVF_FLOW_FIELD_FCOE_OX, - ICE_AVF_FLOW_FIELD_FCOE_RX, - ICE_AVF_FLOW_FIELD_FCOE_OTHER, - /* Values 51-62 are reserved */ - ICE_AVF_FLOW_FIELD_L2_PAYLOAD = 63, - ICE_AVF_FLOW_FIELD_MAX -}; - /* Supported RSS offloads This macro is defined to support - * VIRTCHNL_OP_GET_RSS_HENA_CAPS ops. PF driver sends the RSS hardware + * VIRTCHNL_OP_GET_RSS_HASHCFG_CAPS ops. PF driver sends the RSS hardware * capabilities to the caller of this ops. */ -#define ICE_DEFAULT_RSS_HENA ( \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \ - BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP)) +#define ICE_DEFAULT_RSS_HASHCFG ( \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ + BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) enum ice_rss_cfg_hdr_type { ICE_RSS_OUTER_HEADERS, /* take outer headers as inputset. */ diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c index 70c201f569ce..d86db081579f 100644 --- a/drivers/net/ethernet/intel/ice/ice_fw_update.c +++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c @@ -68,7 +68,7 @@ ice_send_package_data(struct pldmfw *context, const u8 *data, u16 length) if (status) { dev_err(dev, "Failed to send record package data to firmware, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to record package data to firmware"); return -EIO; } @@ -257,7 +257,7 @@ ice_send_component_table(struct pldmfw *context, struct pldmfw_component *compon if (status) { dev_err(dev, "Failed to transfer component table to firmware, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to transfer component table to firmware"); return -EIO; } @@ -299,7 +299,8 @@ int ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, struct device *dev = ice_pf_to_dev(pf); struct ice_aq_task task = {}; struct ice_hw *hw = &pf->hw; - struct ice_aq_desc *desc; + struct libie_aq_desc *desc; + struct ice_aqc_nvm *cmd; u32 completion_offset; int err; @@ -313,7 +314,7 @@ int ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, if (err) { dev_err(dev, "Failed to flash module 0x%02x with block of size %u at offset %u, err %d aq_err %s\n", module, block_size, offset, err, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to program flash module"); return -EIO; } @@ -333,11 +334,12 @@ int ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, } desc = &task.event.desc; - completion_module = le16_to_cpu(desc->params.nvm.module_typeid); + cmd = libie_aq_raw(desc); + completion_module = le16_to_cpu(cmd->module_typeid); completion_retval = le16_to_cpu(desc->retval); - completion_offset = le16_to_cpu(desc->params.nvm.offset_low); - completion_offset |= desc->params.nvm.offset_high << 16; + completion_offset = le16_to_cpu(cmd->offset_low); + completion_offset |= cmd->offset_high << 16; if (completion_module != module) { dev_err(dev, "Unexpected module_typeid in write completion: got 0x%x, expected 0x%x\n", @@ -356,7 +358,7 @@ int ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, if (completion_retval) { dev_err(dev, "Firmware failed to flash module 0x%02x with block of size %u at offset %u, err %s\n", module, block_size, offset, - ice_aq_str((enum ice_aq_err)completion_retval)); + libie_aq_str((enum libie_aq_err)completion_retval)); NL_SET_ERR_MSG_MOD(extack, "Firmware failed to program flash module"); return -EIO; } @@ -369,7 +371,7 @@ int ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, */ if (reset_level && last_cmd && module == ICE_SR_1ST_NVM_BANK_PTR) { if (hw->dev_caps.common_cap.pcie_reset_avoidance) { - *reset_level = desc->params.nvm.cmd_flags & + *reset_level = cmd->cmd_flags & ICE_AQC_NVM_RESET_LVL_M; dev_dbg(dev, "Firmware reported required reset level as %u\n", *reset_level); @@ -487,7 +489,8 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, struct device *dev = ice_pf_to_dev(pf); struct ice_aq_task task = {}; struct ice_hw *hw = &pf->hw; - struct ice_aq_desc *desc; + struct libie_aq_desc *desc; + struct ice_aqc_nvm *cmd; struct devlink *devlink; int err; @@ -503,7 +506,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, if (err) { dev_err(dev, "Failed to erase %s (module 0x%02x), err %d aq_err %s\n", component, module, err, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to erase flash module"); err = -EIO; goto out_notify_devlink; @@ -518,7 +521,8 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, } desc = &task.event.desc; - completion_module = le16_to_cpu(desc->params.nvm.module_typeid); + cmd = libie_aq_raw(desc); + completion_module = le16_to_cpu(cmd->module_typeid); completion_retval = le16_to_cpu(desc->retval); if (completion_module != module) { @@ -532,7 +536,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, if (completion_retval) { dev_err(dev, "Firmware failed to erase %s (module 0x02%x), aq_err %s\n", component, module, - ice_aq_str((enum ice_aq_err)completion_retval)); + libie_aq_str((enum libie_aq_err)completion_retval)); NL_SET_ERR_MSG_MOD(extack, "Firmware failed to erase flash"); err = -EIO; goto out_notify_devlink; @@ -579,7 +583,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags, err = ice_nvm_write_activate(hw, activate_flags, &response_flags); if (err) { dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to switch active flash banks"); return -EIO; } @@ -611,7 +615,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags, completion_retval = le16_to_cpu(task.event.desc.retval); if (completion_retval) { dev_err(dev, "Firmware failed to switch active flash banks aq_err %s\n", - ice_aq_str((enum ice_aq_err)completion_retval)); + libie_aq_str((enum libie_aq_err)completion_retval)); NL_SET_ERR_MSG_MOD(extack, "Firmware failed to switch active flash banks"); return -EIO; } @@ -949,7 +953,7 @@ ice_cancel_pending_update(struct ice_pf *pf, const char *component, err = ice_acquire_nvm(hw, ICE_RES_WRITE); if (err) { dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock"); return err; } @@ -1042,7 +1046,7 @@ int ice_devlink_flash_update(struct devlink *devlink, err = ice_acquire_nvm(hw, ICE_RES_WRITE); if (err) { dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock"); return err; } diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.c b/drivers/net/ethernet/intel/ice/ice_fwlog.c deleted file mode 100644 index 4fd15387a7e5..000000000000 --- a/drivers/net/ethernet/intel/ice/ice_fwlog.c +++ /dev/null @@ -1,472 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2022, Intel Corporation. */ - -#include <linux/vmalloc.h> -#include "ice.h" -#include "ice_common.h" -#include "ice_fwlog.h" - -bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings) -{ - u16 head, tail; - - head = rings->head; - tail = rings->tail; - - if (head < tail && (tail - head == (rings->size - 1))) - return true; - else if (head > tail && (tail == (head - 1))) - return true; - - return false; -} - -bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings) -{ - return rings->head == rings->tail; -} - -void ice_fwlog_ring_increment(u16 *item, u16 size) -{ - *item = (*item + 1) & (size - 1); -} - -static int ice_fwlog_alloc_ring_buffs(struct ice_fwlog_ring *rings) -{ - int i, nr_bytes; - u8 *mem; - - nr_bytes = rings->size * ICE_AQ_MAX_BUF_LEN; - mem = vzalloc(nr_bytes); - if (!mem) - return -ENOMEM; - - for (i = 0; i < rings->size; i++) { - struct ice_fwlog_data *ring = &rings->rings[i]; - - ring->data_size = ICE_AQ_MAX_BUF_LEN; - ring->data = mem; - mem += ICE_AQ_MAX_BUF_LEN; - } - - return 0; -} - -static void ice_fwlog_free_ring_buffs(struct ice_fwlog_ring *rings) -{ - int i; - - for (i = 0; i < rings->size; i++) { - struct ice_fwlog_data *ring = &rings->rings[i]; - - /* the first ring is the base memory for the whole range so - * free it - */ - if (!i) - vfree(ring->data); - - ring->data = NULL; - ring->data_size = 0; - } -} - -#define ICE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n)) -/** - * ice_fwlog_realloc_rings - reallocate the FW log rings - * @hw: pointer to the HW structure - * @index: the new index to use to allocate memory for the log data - * - */ -void ice_fwlog_realloc_rings(struct ice_hw *hw, int index) -{ - struct ice_fwlog_ring ring; - int status, ring_size; - - /* convert the number of bytes into a number of 4K buffers. externally - * the driver presents the interface to the FW log data as a number of - * bytes because that's easy for users to understand. internally the - * driver uses a ring of buffers because the driver doesn't know where - * the beginning and end of any line of log data is so the driver has - * to overwrite data as complete blocks. when the data is returned to - * the user the driver knows that the data is correct and the FW log - * can be correctly parsed by the tools - */ - ring_size = ICE_FWLOG_INDEX_TO_BYTES(index) / ICE_AQ_MAX_BUF_LEN; - if (ring_size == hw->fwlog_ring.size) - return; - - /* allocate space for the new rings and buffers then release the - * 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); - if (!ring.rings) - return; - - ring.size = ring_size; - - status = ice_fwlog_alloc_ring_buffs(&ring); - if (status) { - dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n"); - ice_fwlog_free_ring_buffs(&ring); - kfree(ring.rings); - return; - } - - ice_fwlog_free_ring_buffs(&hw->fwlog_ring); - kfree(hw->fwlog_ring.rings); - - hw->fwlog_ring.rings = ring.rings; - hw->fwlog_ring.size = ring.size; - hw->fwlog_ring.index = index; - hw->fwlog_ring.head = 0; - hw->fwlog_ring.tail = 0; -} - -/** - * ice_fwlog_init - Initialize FW logging configuration - * @hw: pointer to the HW structure - * - * This function should be called on driver initialization during - * ice_init_hw(). - */ -int ice_fwlog_init(struct ice_hw *hw) -{ - /* only support fw log commands on PF 0 */ - if (hw->bus.func) - return -EINVAL; - - ice_fwlog_set_supported(hw); - - if (ice_fwlog_supported(hw)) { - int status; - - /* read the current config from the FW and store it */ - status = ice_fwlog_get(hw, &hw->fwlog_cfg); - if (status) - return status; - - hw->fwlog_ring.rings = kcalloc(ICE_FWLOG_RING_SIZE_DFLT, - sizeof(*hw->fwlog_ring.rings), - GFP_KERNEL); - if (!hw->fwlog_ring.rings) { - dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log rings\n"); - return -ENOMEM; - } - - hw->fwlog_ring.size = ICE_FWLOG_RING_SIZE_DFLT; - hw->fwlog_ring.index = ICE_FWLOG_RING_SIZE_INDEX_DFLT; - - status = ice_fwlog_alloc_ring_buffs(&hw->fwlog_ring); - if (status) { - dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n"); - ice_fwlog_free_ring_buffs(&hw->fwlog_ring); - kfree(hw->fwlog_ring.rings); - return status; - } - - ice_debugfs_fwlog_init(hw->back); - } else { - dev_warn(ice_hw_to_dev(hw), "FW logging is not supported in this NVM image. Please update the NVM to get FW log support\n"); - } - - return 0; -} - -/** - * ice_fwlog_deinit - unroll FW logging configuration - * @hw: pointer to the HW structure - * - * This function should be called in ice_deinit_hw(). - */ -void ice_fwlog_deinit(struct ice_hw *hw) -{ - struct ice_pf *pf = hw->back; - int status; - - /* only support fw log commands on PF 0 */ - if (hw->bus.func) - return; - - ice_debugfs_pf_deinit(hw->back); - - /* make sure FW logging is disabled to not put the FW in a weird state - * for the next driver load - */ - hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA; - status = ice_fwlog_set(hw, &hw->fwlog_cfg); - if (status) - dev_warn(ice_hw_to_dev(hw), "Unable to turn off FW logging, status: %d\n", - status); - - kfree(pf->ice_debugfs_pf_fwlog_modules); - - pf->ice_debugfs_pf_fwlog_modules = NULL; - - status = ice_fwlog_unregister(hw); - if (status) - dev_warn(ice_hw_to_dev(hw), "Unable to unregister FW logging, status: %d\n", - status); - - if (hw->fwlog_ring.rings) { - ice_fwlog_free_ring_buffs(&hw->fwlog_ring); - kfree(hw->fwlog_ring.rings); - } -} - -/** - * ice_fwlog_supported - Cached for whether FW supports FW logging or not - * @hw: pointer to the HW structure - * - * This will always return false if called before ice_init_hw(), so it must be - * called after ice_init_hw(). - */ -bool ice_fwlog_supported(struct ice_hw *hw) -{ - return hw->fwlog_supported; -} - -/** - * ice_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30) - * @hw: pointer to the HW structure - * @entries: entries to configure - * @num_entries: number of @entries - * @options: options from ice_fwlog_cfg->options structure - * @log_resolution: logging resolution - */ -static int -ice_aq_fwlog_set(struct ice_hw *hw, struct ice_fwlog_module_entry *entries, - u16 num_entries, u16 options, u16 log_resolution) -{ - struct ice_aqc_fw_log_cfg_resp *fw_modules; - struct ice_aqc_fw_log *cmd; - struct ice_aq_desc desc; - int status; - int i; - - fw_modules = kcalloc(num_entries, sizeof(*fw_modules), GFP_KERNEL); - if (!fw_modules) - return -ENOMEM; - - for (i = 0; i < num_entries; i++) { - fw_modules[i].module_identifier = - cpu_to_le16(entries[i].module_id); - fw_modules[i].log_level = entries[i].log_level; - } - - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_config); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); - - cmd = &desc.params.fw_log; - - cmd->cmd_flags = ICE_AQC_FW_LOG_CONF_SET_VALID; - cmd->ops.cfg.log_resolution = cpu_to_le16(log_resolution); - cmd->ops.cfg.mdl_cnt = cpu_to_le16(num_entries); - - if (options & ICE_FWLOG_OPTION_ARQ_ENA) - cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_AQ_EN; - if (options & ICE_FWLOG_OPTION_UART_ENA) - cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_UART_EN; - - status = ice_aq_send_cmd(hw, &desc, fw_modules, - sizeof(*fw_modules) * num_entries, - NULL); - - kfree(fw_modules); - - return status; -} - -/** - * ice_fwlog_set - Set the firmware logging settings - * @hw: pointer to the HW structure - * @cfg: config used to set firmware logging - * - * This function should be called whenever the driver needs to set the firmware - * logging configuration. It can be called on initialization, reset, or during - * runtime. - * - * If the PF wishes to receive FW logging then it must register via - * ice_fwlog_register. Note, that ice_fwlog_register does not need to be called - * for init. - */ -int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg) -{ - if (!ice_fwlog_supported(hw)) - return -EOPNOTSUPP; - - return ice_aq_fwlog_set(hw, cfg->module_entries, - ICE_AQC_FW_LOG_ID_MAX, cfg->options, - cfg->log_resolution); -} - -/** - * ice_aq_fwlog_get - Get the current firmware logging configuration (0xFF32) - * @hw: pointer to the HW structure - * @cfg: firmware logging configuration to populate - */ -static int ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg) -{ - struct ice_aqc_fw_log_cfg_resp *fw_modules; - struct ice_aqc_fw_log *cmd; - struct ice_aq_desc desc; - u16 module_id_cnt; - int status; - void *buf; - int i; - - memset(cfg, 0, sizeof(*cfg)); - - buf = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_query); - cmd = &desc.params.fw_log; - - cmd->cmd_flags = ICE_AQC_FW_LOG_AQ_QUERY; - - status = ice_aq_send_cmd(hw, &desc, buf, ICE_AQ_MAX_BUF_LEN, NULL); - if (status) { - ice_debug(hw, ICE_DBG_FW_LOG, "Failed to get FW log configuration\n"); - goto status_out; - } - - module_id_cnt = le16_to_cpu(cmd->ops.cfg.mdl_cnt); - if (module_id_cnt < ICE_AQC_FW_LOG_ID_MAX) { - ice_debug(hw, ICE_DBG_FW_LOG, "FW returned less than the expected number of FW log module IDs\n"); - } else if (module_id_cnt > ICE_AQC_FW_LOG_ID_MAX) { - ice_debug(hw, ICE_DBG_FW_LOG, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n", - ICE_AQC_FW_LOG_ID_MAX); - module_id_cnt = ICE_AQC_FW_LOG_ID_MAX; - } - - cfg->log_resolution = le16_to_cpu(cmd->ops.cfg.log_resolution); - if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_AQ_EN) - cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA; - if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN) - cfg->options |= ICE_FWLOG_OPTION_UART_ENA; - if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED) - cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED; - - fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf; - - for (i = 0; i < module_id_cnt; i++) { - struct ice_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i]; - - cfg->module_entries[i].module_id = - le16_to_cpu(fw_module->module_identifier); - cfg->module_entries[i].log_level = fw_module->log_level; - } - -status_out: - kfree(buf); - return status; -} - -/** - * ice_fwlog_get - Get the firmware logging settings - * @hw: pointer to the HW structure - * @cfg: config to populate based on current firmware logging settings - */ -int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg) -{ - if (!ice_fwlog_supported(hw)) - return -EOPNOTSUPP; - - return ice_aq_fwlog_get(hw, cfg); -} - -/** - * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31) - * @hw: pointer to the HW structure - * @reg: true to register and false to unregister - */ -static int ice_aq_fwlog_register(struct ice_hw *hw, bool reg) -{ - struct ice_aq_desc desc; - - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register); - - if (reg) - desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER; - - return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); -} - -/** - * ice_fwlog_register - Register the PF for firmware logging - * @hw: pointer to the HW structure - * - * After this call the PF will start to receive firmware logging based on the - * configuration set in ice_fwlog_set. - */ -int ice_fwlog_register(struct ice_hw *hw) -{ - int status; - - if (!ice_fwlog_supported(hw)) - return -EOPNOTSUPP; - - status = ice_aq_fwlog_register(hw, true); - if (status) - ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n"); - else - hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED; - - return status; -} - -/** - * ice_fwlog_unregister - Unregister the PF from firmware logging - * @hw: pointer to the HW structure - */ -int ice_fwlog_unregister(struct ice_hw *hw) -{ - int status; - - if (!ice_fwlog_supported(hw)) - return -EOPNOTSUPP; - - status = ice_aq_fwlog_register(hw, false); - if (status) - ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n"); - else - hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED; - - return status; -} - -/** - * ice_fwlog_set_supported - Set if FW logging is supported by FW - * @hw: pointer to the HW struct - * - * If FW returns success to the ice_aq_fwlog_get call then it supports FW - * logging, else it doesn't. Set the fwlog_supported flag accordingly. - * - * This function is only meant to be called during driver init to determine if - * the FW support FW logging. - */ -void ice_fwlog_set_supported(struct ice_hw *hw) -{ - struct ice_fwlog_cfg *cfg; - int status; - - hw->fwlog_supported = false; - - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) - return; - - /* don't call ice_fwlog_get() because that would check to see if FW - * logging is supported which is what the driver is determining now - */ - status = ice_aq_fwlog_get(hw, cfg); - if (status) - ice_debug(hw, ICE_DBG_FW_LOG, "ice_aq_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n", - status); - else - hw->fwlog_supported = true; - - kfree(cfg); -} diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.h b/drivers/net/ethernet/intel/ice/ice_fwlog.h deleted file mode 100644 index 287e71fa4b86..000000000000 --- a/drivers/net/ethernet/intel/ice/ice_fwlog.h +++ /dev/null @@ -1,79 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2022, Intel Corporation. */ - -#ifndef _ICE_FWLOG_H_ -#define _ICE_FWLOG_H_ -#include "ice_adminq_cmd.h" - -struct ice_hw; - -/* Only a single log level should be set and all log levels under the set value - * are enabled, e.g. if log level is set to ICE_FW_LOG_LEVEL_VERBOSE, then all - * other log levels are included (except ICE_FW_LOG_LEVEL_NONE) - */ -enum ice_fwlog_level { - ICE_FWLOG_LEVEL_NONE = 0, - ICE_FWLOG_LEVEL_ERROR = 1, - ICE_FWLOG_LEVEL_WARNING = 2, - ICE_FWLOG_LEVEL_NORMAL = 3, - ICE_FWLOG_LEVEL_VERBOSE = 4, - ICE_FWLOG_LEVEL_INVALID, /* all values >= this entry are invalid */ -}; - -struct ice_fwlog_module_entry { - /* module ID for the corresponding firmware logging event */ - u16 module_id; - /* verbosity level for the module_id */ - u8 log_level; -}; - -struct ice_fwlog_cfg { - /* list of modules for configuring log level */ - struct ice_fwlog_module_entry module_entries[ICE_AQC_FW_LOG_ID_MAX]; - /* options used to configure firmware logging */ - u16 options; -#define ICE_FWLOG_OPTION_ARQ_ENA BIT(0) -#define ICE_FWLOG_OPTION_UART_ENA BIT(1) - /* set before calling ice_fwlog_init() so the PF registers for firmware - * logging on initialization - */ -#define ICE_FWLOG_OPTION_REGISTER_ON_INIT BIT(2) - /* set in the ice_fwlog_get() response if the PF is registered for FW - * logging events over ARQ - */ -#define ICE_FWLOG_OPTION_IS_REGISTERED BIT(3) - - /* minimum number of log events sent per Admin Receive Queue event */ - u16 log_resolution; -}; - -struct ice_fwlog_data { - u16 data_size; - u8 *data; -}; - -struct ice_fwlog_ring { - struct ice_fwlog_data *rings; - u16 index; - u16 size; - u16 head; - u16 tail; -}; - -#define ICE_FWLOG_RING_SIZE_INDEX_DFLT 3 -#define ICE_FWLOG_RING_SIZE_DFLT 256 -#define ICE_FWLOG_RING_SIZE_MAX 512 - -bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings); -bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings); -void ice_fwlog_ring_increment(u16 *item, u16 size); -void ice_fwlog_set_supported(struct ice_hw *hw); -bool ice_fwlog_supported(struct ice_hw *hw); -int ice_fwlog_init(struct ice_hw *hw); -void ice_fwlog_deinit(struct ice_hw *hw); -int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg); -int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg); -int ice_fwlog_register(struct ice_hw *hw); -int ice_fwlog_unregister(struct ice_hw *hw); -void ice_fwlog_realloc_rings(struct ice_hw *hw, int index); -#endif /* _ICE_FWLOG_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index aa4bfbcf85d2..082ad33c53dc 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -16,8 +16,10 @@ #define GLCOMM_QUANTA_PROF_MAX_DESC_M ICE_M(0x3F, 24) #define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4)) #define QTX_COMM_HEAD(_DBQM) (0x000E0000 + ((_DBQM) * 4)) +#define QTX_COMM_HEAD_MAX_INDEX 16383 #define QTX_COMM_HEAD_HEAD_S 0 #define QTX_COMM_HEAD_HEAD_M ICE_M(0x1FFF, 0) +#define E830_GLQTX_TXTIME_DBELL_LSB(_DBQM) (0x002E0000 + ((_DBQM) * 8)) #define PF_FW_ARQBAH 0x00080180 #define PF_FW_ARQBAL 0x00080080 #define PF_FW_ARQH 0x00080380 @@ -272,6 +274,8 @@ #define VPINT_ALLOC_PCI_VALID_M BIT(31) #define VPINT_MBX_CTL(_VSI) (0x0016A000 + ((_VSI) * 4)) #define VPINT_MBX_CTL_CAUSE_ENA_M BIT(30) +#define PFLAN_TX_QALLOC(_PF) (0x001D2580 + ((_PF) * 4)) +#define PFLAN_TX_QALLOC_FIRSTQ_M GENMASK(13, 0) #define GLLAN_RCTL_0 0x002941F8 #define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4)) #define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4)) @@ -376,6 +380,15 @@ #define GLNVM_ULD_POR_DONE_1_M BIT(8) #define GLNVM_ULD_PCIER_DONE_2_M BIT(9) #define GLNVM_ULD_PE_DONE_M BIT(10) +#define GLCOMM_QTX_CNTX_CTL 0x002D2DC8 +#define GLCOMM_QTX_CNTX_CTL_QUEUE_ID_M GENMASK(13, 0) +#define GLCOMM_QTX_CNTX_CTL_CMD_M GENMASK(18, 16) +#define GLCOMM_QTX_CNTX_CTL_CMD_READ 0 +#define GLCOMM_QTX_CNTX_CTL_CMD_WRITE 1 +#define GLCOMM_QTX_CNTX_CTL_CMD_RESET 3 +#define GLCOMM_QTX_CNTX_CTL_CMD_WRITE_NO_DYN 4 +#define GLCOMM_QTX_CNTX_CTL_CMD_EXEC_M BIT(19) +#define GLCOMM_QTX_CNTX_DATA(_i) (0x002D2D40 + ((_i) * 4)) #define GLPCI_CNF2 0x000BE004 #define GLPCI_CNF2_CACHELINE_SIZE_M BIT(1) #define PF_FUNC_RID 0x0009E880 @@ -559,6 +572,8 @@ #define E830_PFPTM_SEM_BUSY_M BIT(0) #define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4)) #define VFINT_DYN_CTLN_CLEARPBA_M BIT(1) +#define E830_GLTXTIME_FETCH_PROFILE(_i, _j) (0x002D3500 + ((_i) * 4 + (_j) * 64)) +#define E830_GLTXTIME_FETCH_PROFILE_FETCH_TS_DESC_M ICE_M(0x1FF, 0) #define E830_MBX_PF_IN_FLIGHT_VF_MSGS_THRESH 0x00234000 #define E830_MBX_VF_DEC_TRIG(_VF) (0x00233800 + (_VF) * 4) #define E830_MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT(_VF) (0x00233000 + (_VF) * 4) diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c index 6ab53e430f91..420d45c2558b 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -336,6 +336,7 @@ int ice_plug_aux_dev(struct ice_pf *pf) mutex_lock(&pf->adev_mutex); cdev->adev = adev; mutex_unlock(&pf->adev_mutex); + set_bit(ICE_FLAG_AUX_DEV_CREATED, pf->flags); return 0; } @@ -347,15 +348,16 @@ void ice_unplug_aux_dev(struct ice_pf *pf) { struct auxiliary_device *adev; + if (!test_and_clear_bit(ICE_FLAG_AUX_DEV_CREATED, pf->flags)) + return; + mutex_lock(&pf->adev_mutex); adev = pf->cdev_info->adev; pf->cdev_info->adev = NULL; mutex_unlock(&pf->adev_mutex); - if (adev) { - auxiliary_device_delete(adev); - auxiliary_device_uninit(adev); - } + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index d132eb477551..aebf8e08a297 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -10,12 +10,17 @@ #define ICE_LAG_RES_SHARED BIT(14) #define ICE_LAG_RES_VALID BIT(15) -#define LACP_TRAIN_PKT_LEN 16 -static const u8 lacp_train_pkt[LACP_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0x88, 0x09, 0, 0 }; +#define ICE_TRAIN_PKT_LEN 16 +static const u8 lacp_train_pkt[ICE_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0x88, 0x09, 0, 0 }; +static const u8 act_act_train_pkt[ICE_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }; #define ICE_RECIPE_LEN 64 +#define ICE_LAG_SRIOV_CP_RECIPE 10 + static const u8 ice_dflt_vsi_rcp[ICE_RECIPE_LEN] = { 0x05, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x85, 0, 0x01, 0, 0, 0, 0xff, 0xff, 0x08, 0, 0, 0, 0, 0, 0, 0, @@ -46,10 +51,10 @@ static void ice_lag_set_primary(struct ice_lag *lag) } /** - * ice_lag_set_backup - set PF LAG state to Backup + * ice_lag_set_bkup - set PF LAG state to Backup * @lag: LAG info struct */ -static void ice_lag_set_backup(struct ice_lag *lag) +static void ice_lag_set_bkup(struct ice_lag *lag) { struct ice_pf *pf = lag->pf; @@ -99,6 +104,28 @@ static bool netif_is_same_ice(struct ice_pf *pf, struct net_device *netdev) } /** + * ice_lag_config_eswitch - configure eswitch to work with LAG + * @lag: lag info struct + * @netdev: active network interface device struct + * + * Updates all port representors in eswitch to use @netdev for Tx. + * + * Configures the netdev to keep dst metadata (also used in representor Tx). + * This is required for an uplink without switchdev mode configured. + */ +static void ice_lag_config_eswitch(struct ice_lag *lag, + struct net_device *netdev) +{ + struct ice_repr *repr; + unsigned long id; + + xa_for_each(&lag->pf->eswitch.reprs, id, repr) + repr->dst->u.port_info.lower_dev = netdev; + + netif_keep_dst(netdev); +} + +/** * ice_netdev_to_lag - return pointer to associated lag struct from netdev * @netdev: pointer to net_device struct to query */ @@ -210,13 +237,12 @@ ice_lag_cfg_fltr(struct ice_lag *lag, u32 act, u16 recipe_id, u16 *rule_idx, u8 direction, bool add) { struct ice_sw_rule_lkup_rx_tx *s_rule; + struct ice_hw *hw = &lag->pf->hw; u16 s_rule_sz, vsi_num; - struct ice_hw *hw; u8 *eth_hdr; u32 opc; int err; - hw = &lag->pf->hw; vsi_num = ice_get_hw_vsi_num(hw, 0); s_rule_sz = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule); @@ -314,26 +340,15 @@ ice_lag_cfg_drop_fltr(struct ice_lag *lag, bool add) } /** - * ice_lag_cfg_pf_fltrs - set filters up for new active port + * ice_lag_cfg_pf_fltrs_act_bkup - set filters up for new active port * @lag: local interfaces lag struct - * @ptr: opaque data containing notifier event + * @bonding_info: netdev event bonding info */ static void -ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) +ice_lag_cfg_pf_fltrs_act_bkup(struct ice_lag *lag, + struct netdev_bonding_info *bonding_info) { - struct netdev_notifier_bonding_info *info; - struct netdev_bonding_info *bonding_info; - struct net_device *event_netdev; - struct device *dev; - - event_netdev = netdev_notifier_info_to_dev(ptr); - /* not for this netdev */ - if (event_netdev != lag->netdev) - return; - - info = (struct netdev_notifier_bonding_info *)ptr; - bonding_info = &info->bonding_info; - dev = ice_pf_to_dev(lag->pf); + struct device *dev = ice_pf_to_dev(lag->pf); /* interface not active - remove old default VSI rule */ if (bonding_info->slave.state && lag->pf_rx_rule_id) { @@ -354,6 +369,105 @@ ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) } /** + * ice_lag_cfg_lp_fltr - configure lport filters + * @lag: local interface's lag struct + * @add: add or remove rule + * @cp: control packet only or general PF lport rule + */ +static void +ice_lag_cfg_lp_fltr(struct ice_lag *lag, bool add, bool cp) +{ + struct ice_sw_rule_lkup_rx_tx *s_rule; + struct ice_vsi *vsi = lag->pf->vsi[0]; + u16 buf_len, opc; + + buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, ICE_TRAIN_PKT_LEN); + s_rule = kzalloc(buf_len, GFP_KERNEL); + if (!s_rule) { + netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n"); + return; + } + + if (add) { + if (cp) { + s_rule->recipe_id = + cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); + memcpy(s_rule->hdr_data, lacp_train_pkt, + ICE_TRAIN_PKT_LEN); + } else { + s_rule->recipe_id = cpu_to_le16(lag->act_act_recipe); + memcpy(s_rule->hdr_data, act_act_train_pkt, + ICE_TRAIN_PKT_LEN); + } + + s_rule->src = cpu_to_le16(vsi->port_info->lport); + s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI | + ICE_SINGLE_ACT_LAN_ENABLE | + ICE_SINGLE_ACT_VALID_BIT | + FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, + vsi->vsi_num)); + s_rule->hdr_len = cpu_to_le16(ICE_TRAIN_PKT_LEN); + s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); + opc = ice_aqc_opc_add_sw_rules; + } else { + opc = ice_aqc_opc_remove_sw_rules; + if (cp) + s_rule->index = cpu_to_le16(lag->cp_rule_idx); + else + s_rule->index = cpu_to_le16(lag->act_act_rule_idx); + } + if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) { + netdev_warn(lag->netdev, "Error %s %s rule for aggregate\n", + add ? "ADDING" : "REMOVING", + cp ? "CONTROL PACKET" : "LPORT"); + goto err_cp_free; + } + + if (add) { + if (cp) + lag->cp_rule_idx = le16_to_cpu(s_rule->index); + else + lag->act_act_rule_idx = le16_to_cpu(s_rule->index); + } else { + if (cp) + lag->cp_rule_idx = 0; + else + lag->act_act_rule_idx = 0; + } + +err_cp_free: + kfree(s_rule); +} + +/** + * ice_lag_cfg_pf_fltrs - set filters up for PF traffic + * @lag: local interfaces lag struct + * @ptr: opaque data containing notifier event + */ +static void +ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) +{ + struct netdev_notifier_bonding_info *info = ptr; + struct netdev_bonding_info *bonding_info; + struct net_device *event_netdev; + + event_netdev = netdev_notifier_info_to_dev(ptr); + if (event_netdev != lag->netdev) + return; + + bonding_info = &info->bonding_info; + + if (lag->bond_aa) { + if (lag->need_fltr_cfg) { + ice_lag_cfg_lp_fltr(lag, true, false); + lag->need_fltr_cfg = false; + } + } else { + ice_lag_cfg_pf_fltrs_act_bkup(lag, bonding_info); + } +} + +/** * ice_display_lag_info - print LAG info * @lag: LAG info struct */ @@ -402,12 +516,11 @@ static u16 ice_lag_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf, u16 vsi_num, u16 numq, u8 tc) { + struct ice_pf *pf = hw->back; struct ice_q_ctx *q_ctx; u16 qid, count = 0; - struct ice_pf *pf; int i; - pf = hw->back; for (i = 0; i < numq; i++) { q_ctx = ice_get_lan_q_ctx(hw, vsi_num, tc, i); if (!q_ctx) { @@ -577,7 +690,7 @@ ice_lag_move_vf_node_tc(struct ice_lag *lag, u8 oldport, u8 newport, } if (ice_aq_cfg_lan_txq(&lag->pf->hw, qbuf, qbuf_size, valq, oldport, - newport, NULL)) { + newport, ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG failover\n"); goto qbuf_err; } @@ -677,54 +790,6 @@ ice_lag_move_single_vf_nodes(struct ice_lag *lag, u8 oldport, u8 newport, } /** - * ice_lag_move_new_vf_nodes - Move Tx scheduling nodes for a VF if required - * @vf: the VF to move Tx nodes for - * - * Called just after configuring new VF queues. Check whether the VF Tx - * scheduling nodes need to be updated to fail over to the active port. If so, - * move them now. - */ -void ice_lag_move_new_vf_nodes(struct ice_vf *vf) -{ - struct ice_lag_netdev_list ndlist; - u8 pri_port, act_port; - struct ice_lag *lag; - struct ice_vsi *vsi; - struct ice_pf *pf; - - vsi = ice_get_vf_vsi(vf); - - if (WARN_ON(!vsi)) - return; - - if (WARN_ON(vsi->type != ICE_VSI_VF)) - return; - - pf = vf->pf; - lag = pf->lag; - - mutex_lock(&pf->lag_mutex); - if (!lag->bonded) - goto new_vf_unlock; - - pri_port = pf->hw.port_info->lport; - act_port = lag->active_port; - - if (lag->upper_netdev) - ice_lag_build_netdev_list(lag, &ndlist); - - if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG) && - lag->bonded && lag->primary && pri_port != act_port && - !list_empty(lag->netdev_head)) - ice_lag_move_single_vf_nodes(lag, pri_port, act_port, vsi->idx); - - ice_lag_destroy_netdev_list(lag, &ndlist); - -new_vf_unlock: - mutex_unlock(&pf->lag_mutex); -} - -/** * ice_lag_move_vf_nodes - move Tx scheduling nodes for all VFs to new port * @lag: lag info struct * @oldport: lport of previous interface @@ -767,59 +832,60 @@ void ice_lag_move_vf_nodes_cfg(struct ice_lag *lag, u8 src_prt, u8 dst_prt) ice_lag_destroy_netdev_list(lag, &ndlist); } -#define ICE_LAG_SRIOV_CP_RECIPE 10 -#define ICE_LAG_SRIOV_TRAIN_PKT_LEN 16 - /** - * ice_lag_cfg_cp_fltr - configure filter for control packets - * @lag: local interface's lag struct - * @add: add or remove rule + * ice_lag_prepare_vf_reset - helper to adjust vf lag for reset + * @lag: lag struct for interface that owns VF + * + * Context: must be called with the lag_mutex lock held. + * + * Return: active lport value or ICE_LAG_INVALID_PORT if nothing moved. */ -static void -ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) +u8 ice_lag_prepare_vf_reset(struct ice_lag *lag) { - struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; - struct ice_vsi *vsi; - u16 buf_len, opc; - - vsi = lag->pf->vsi[0]; - - buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, - ICE_LAG_SRIOV_TRAIN_PKT_LEN); - s_rule = kzalloc(buf_len, GFP_KERNEL); - if (!s_rule) { - netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n"); - return; - } - - if (add) { - s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); - s_rule->recipe_id = cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE); - s_rule->src = cpu_to_le16(vsi->port_info->lport); - s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI | - ICE_SINGLE_ACT_LAN_ENABLE | - ICE_SINGLE_ACT_VALID_BIT | - FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi->vsi_num)); - s_rule->hdr_len = cpu_to_le16(ICE_LAG_SRIOV_TRAIN_PKT_LEN); - memcpy(s_rule->hdr_data, lacp_train_pkt, LACP_TRAIN_PKT_LEN); - opc = ice_aqc_opc_add_sw_rules; - } else { - opc = ice_aqc_opc_remove_sw_rules; - s_rule->index = cpu_to_le16(lag->cp_rule_idx); - } - if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) { - netdev_warn(lag->netdev, "Error %s CP rule for fail-over\n", - add ? "ADDING" : "REMOVING"); - goto cp_free; + u8 pri_prt, act_prt; + + if (lag && lag->bonded && lag->primary && lag->upper_netdev) { + if (!lag->bond_aa) { + pri_prt = lag->pf->hw.port_info->lport; + act_prt = lag->active_port; + if (act_prt != pri_prt && + act_prt != ICE_LAG_INVALID_PORT) { + ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); + return act_prt; + } + } else { + if (lag->port_bitmap & ICE_LAGS_M) { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, NULL); + lag->port_bitmap |= ICE_LAGS_M; + } + } } - if (add) - lag->cp_rule_idx = le16_to_cpu(s_rule->index); - else - lag->cp_rule_idx = 0; + return ICE_LAG_INVALID_PORT; +} -cp_free: - kfree(s_rule); +/** + * ice_lag_complete_vf_reset - helper for lag after reset + * @lag: lag struct for primary interface + * @act_prt: which port should be active for lag + * + * Context: must be called while holding the lag_mutex. + */ +void ice_lag_complete_vf_reset(struct ice_lag *lag, u8 act_prt) +{ + u8 pri_prt; + + if (lag && lag->bonded && lag->primary) { + if (!lag->bond_aa) { + pri_prt = lag->pf->hw.port_info->lport; + if (act_prt != ICE_LAG_INVALID_PORT) + ice_lag_move_vf_nodes_cfg(lag, pri_prt, + act_prt); + } else { + ice_lag_aa_failover(lag, ICE_LAGS_IDX, NULL); + } + } } /** @@ -831,13 +897,12 @@ cp_free: */ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_bonding_info *info; + struct netdev_notifier_bonding_info *info = ptr; struct netdev_bonding_info *bonding_info; struct net_device *event_netdev; const char *lag_netdev_name; event_netdev = netdev_notifier_info_to_dev(ptr); - info = ptr; lag_netdev_name = netdev_name(lag->netdev); bonding_info = &info->bonding_info; @@ -855,7 +920,7 @@ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) } if (bonding_info->slave.state) - ice_lag_set_backup(lag); + ice_lag_set_bkup(lag); else ice_lag_set_primary(lag); @@ -864,6 +929,295 @@ lag_out: } /** + * ice_lag_aa_qbuf_recfg - fill a single queue buffer for recfg cmd + * @hw: HW struct that contains the queue context + * @qbuf: pointer to single queue buffer + * @vsi_num: index of the VF VSI in PF space + * @qnum: queue index + * + * Return: Zero on success, error code on failure. + */ +static int +ice_lag_aa_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf, + u16 vsi_num, int qnum) +{ + struct ice_pf *pf = hw->back; + struct ice_q_ctx *q_ctx; + u16 q_id; + + q_ctx = ice_get_lan_q_ctx(hw, vsi_num, 0, qnum); + if (!q_ctx) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d no Q context\n", qnum); + return -ENOENT; + } + + if (q_ctx->q_teid == ICE_INVAL_TEID) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d INVAL TEID\n", qnum); + return -EINVAL; + } + + if (q_ctx->q_handle == ICE_INVAL_Q_HANDLE) { + dev_dbg(ice_hw_to_dev(hw), "LAG queue %d INVAL Q HANDLE\n", qnum); + return -EINVAL; + } + + q_id = pf->vsi[vsi_num]->txq_map[q_ctx->q_handle]; + qbuf->queue_info[0].q_handle = cpu_to_le16(q_id); + qbuf->queue_info[0].tc = 0; + qbuf->queue_info[0].q_teid = cpu_to_le32(q_ctx->q_teid); + + return 0; +} + +/** + * ice_lag_aa_move_vf_qs - Move some/all VF queues to destination + * @lag: primary interface's lag struct + * @dest: index of destination port + * @vsi_num: index of VF VSI in PF space + * @all: if true move all queues to destination + * @odd: VF wide q indicator for odd/even + * @e_pf: PF struct for the event interface + * + * the parameter "all" is to control whether we are splitting the queues + * between two interfaces or moving them all to the destination interface + */ +static void ice_lag_aa_move_vf_qs(struct ice_lag *lag, u8 dest, u16 vsi_num, + bool all, bool *odd, struct ice_pf *e_pf) +{ + DEFINE_RAW_FLEX(struct ice_aqc_cfg_txqs_buf, qbuf, queue_info, 1); + struct ice_hw *old_hw, *new_hw, *pri_hw, *sec_hw; + struct device *dev = ice_pf_to_dev(lag->pf); + struct ice_vsi_ctx *pv_ctx, *sv_ctx; + struct ice_lag_netdev_list ndlist; + u16 num_q, qbuf_size, sec_vsi_num; + u8 pri_lport, sec_lport; + u32 pvf_teid, svf_teid; + u16 vf_id; + + vf_id = lag->pf->vsi[vsi_num]->vf->vf_id; + /* If sec_vf[] not defined, then no second interface to share with */ + if (lag->sec_vf[vf_id]) + sec_vsi_num = lag->sec_vf[vf_id]->idx; + else + return; + + pri_lport = lag->bond_lport_pri; + sec_lport = lag->bond_lport_sec; + + if (pri_lport == ICE_LAG_INVALID_PORT || + sec_lport == ICE_LAG_INVALID_PORT) + return; + + if (!e_pf) + ice_lag_build_netdev_list(lag, &ndlist); + + pri_hw = &lag->pf->hw; + if (e_pf && lag->pf != e_pf) + sec_hw = &e_pf->hw; + else + sec_hw = ice_lag_find_hw_by_lport(lag, sec_lport); + + if (!pri_hw || !sec_hw) + return; + + if (dest == ICE_LAGP_IDX) { + struct ice_vsi *vsi; + + vsi = ice_get_main_vsi(lag->pf); + if (!vsi) + return; + + old_hw = sec_hw; + new_hw = pri_hw; + ice_lag_config_eswitch(lag, vsi->netdev); + } else { + struct ice_pf *sec_pf = sec_hw->back; + struct ice_vsi *vsi; + + vsi = ice_get_main_vsi(sec_pf); + if (!vsi) + return; + + old_hw = pri_hw; + new_hw = sec_hw; + ice_lag_config_eswitch(lag, vsi->netdev); + } + + pv_ctx = ice_get_vsi_ctx(pri_hw, vsi_num); + if (!pv_ctx) { + dev_warn(dev, "Unable to locate primary VSI %d context for LAG failover\n", + vsi_num); + return; + } + + sv_ctx = ice_get_vsi_ctx(sec_hw, sec_vsi_num); + if (!sv_ctx) { + dev_warn(dev, "Unable to locate secondary VSI %d context for LAG failover\n", + vsi_num); + return; + } + + num_q = pv_ctx->num_lan_q_entries[0]; + qbuf_size = __struct_size(qbuf); + + /* Suspend traffic for primary VSI VF */ + pvf_teid = le32_to_cpu(pv_ctx->sched.vsi_node[0]->info.node_teid); + ice_sched_suspend_resume_elems(pri_hw, 1, &pvf_teid, true); + + /* Suspend traffic for secondary VSI VF */ + svf_teid = le32_to_cpu(sv_ctx->sched.vsi_node[0]->info.node_teid); + ice_sched_suspend_resume_elems(sec_hw, 1, &svf_teid, true); + + for (int i = 0; i < num_q; i++) { + struct ice_sched_node *n_prt, *q_node, *parent; + struct ice_port_info *pi, *new_pi; + struct ice_vsi_ctx *src_ctx; + struct ice_sched_node *p; + struct ice_q_ctx *q_ctx; + u16 dst_vsi_num; + + pi = old_hw->port_info; + new_pi = new_hw->port_info; + + *odd = !(*odd); + if ((dest == ICE_LAGP_IDX && *odd && !all) || + (dest == ICE_LAGS_IDX && !(*odd) && !all) || + lag->q_home[vf_id][i] == dest) + continue; + + if (dest == ICE_LAGP_IDX) + dst_vsi_num = vsi_num; + else + dst_vsi_num = sec_vsi_num; + + n_prt = ice_sched_get_free_qparent(new_hw->port_info, + dst_vsi_num, 0, + ICE_SCHED_NODE_OWNER_LAN); + if (!n_prt) + continue; + + q_ctx = ice_get_lan_q_ctx(pri_hw, vsi_num, 0, i); + if (!q_ctx) + continue; + + if (dest == ICE_LAGP_IDX) + src_ctx = sv_ctx; + else + src_ctx = pv_ctx; + + q_node = ice_sched_find_node_by_teid(src_ctx->sched.vsi_node[0], + q_ctx->q_teid); + if (!q_node) + continue; + + qbuf->src_parent_teid = q_node->info.parent_teid; + qbuf->dst_parent_teid = n_prt->info.node_teid; + + /* Move the node in the HW/FW */ + if (ice_lag_aa_qbuf_recfg(pri_hw, qbuf, vsi_num, i)) + continue; + + if (dest == ICE_LAGP_IDX) + ice_aq_cfg_lan_txq(pri_hw, qbuf, qbuf_size, 1, + sec_lport, pri_lport, + ICE_AQC_Q_CFG_MOVE_TC_CHNG, + NULL); + else + ice_aq_cfg_lan_txq(pri_hw, qbuf, qbuf_size, 1, + pri_lport, sec_lport, + ICE_AQC_Q_CFG_MOVE_TC_CHNG, + NULL); + + /* Move the node in the SW */ + parent = q_node->parent; + if (!parent) + continue; + + for (int n = 0; n < parent->num_children; n++) { + int j; + + if (parent->children[n] != q_node) + continue; + + for (j = n + 1; j < parent->num_children; + j++) { + parent->children[j - 1] = + parent->children[j]; + } + parent->children[j] = NULL; + parent->num_children--; + break; + } + + p = pi->sib_head[0][q_node->tx_sched_layer]; + while (p) { + if (p->sibling == q_node) { + p->sibling = q_node->sibling; + break; + } + p = p->sibling; + } + + if (pi->sib_head[0][q_node->tx_sched_layer] == q_node) + pi->sib_head[0][q_node->tx_sched_layer] = + q_node->sibling; + + q_node->parent = n_prt; + q_node->info.parent_teid = n_prt->info.node_teid; + q_node->sibling = NULL; + p = new_pi->sib_head[0][q_node->tx_sched_layer]; + if (p) { + while (p) { + if (!p->sibling) { + p->sibling = q_node; + break; + } + p = p->sibling; + } + } else { + new_pi->sib_head[0][q_node->tx_sched_layer] = + q_node; + } + + n_prt->children[n_prt->num_children++] = q_node; + lag->q_home[vf_id][i] = dest; + } + + ice_sched_suspend_resume_elems(pri_hw, 1, &pvf_teid, false); + ice_sched_suspend_resume_elems(sec_hw, 1, &svf_teid, false); + + if (!e_pf) + ice_lag_destroy_netdev_list(lag, &ndlist); +} + +/** + * ice_lag_aa_failover - move VF queues in A/A mode + * @lag: primary lag struct + * @dest: index of destination port + * @e_pf: PF struct for event port + */ +void ice_lag_aa_failover(struct ice_lag *lag, u8 dest, struct ice_pf *e_pf) +{ + bool odd = true, all = false; + int i; + + /* Primary can be a target if down (cleanup), but secondary can't */ + if (dest == ICE_LAGS_IDX && !(lag->port_bitmap & ICE_LAGS_M)) + return; + + /* Move all queues to a destination if only one port is active, + * or no ports are active and dest is primary. + */ + if ((lag->port_bitmap ^ (ICE_LAGP_M | ICE_LAGS_M)) || + (!lag->port_bitmap && dest == ICE_LAGP_IDX)) + all = true; + + ice_for_each_vsi(lag->pf, i) + if (lag->pf->vsi[i] && lag->pf->vsi[i]->type == ICE_VSI_VF) + ice_lag_aa_move_vf_qs(lag, dest, i, all, &odd, e_pf); +} + +/** * ice_lag_reclaim_vf_tc - move scheduling nodes back to primary interface * @lag: primary interface lag struct * @src_hw: HW struct current node location @@ -879,13 +1233,12 @@ ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num, u16 numq, valq, num_moved, qbuf_size; u16 buf_size = __struct_size(buf); struct ice_aqc_cfg_txqs_buf *qbuf; + struct ice_hw *hw = &lag->pf->hw; struct ice_sched_node *n_prt; __le32 teid, parent_teid; struct ice_vsi_ctx *ctx; - struct ice_hw *hw; u32 tmp_teid; - hw = &lag->pf->hw; ctx = ice_get_vsi_ctx(hw, vsi_num); if (!ctx) { dev_warn(dev, "Unable to locate VSI context for LAG reclaim\n"); @@ -926,7 +1279,7 @@ ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num, if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq, src_hw->port_info->lport, hw->port_info->lport, - NULL)) { + ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG failover\n"); goto reclaim_qerr; } @@ -997,36 +1350,15 @@ static void ice_lag_link(struct ice_lag *lag) lag->bonded = true; lag->role = ICE_LAG_UNSET; + lag->need_fltr_cfg = true; netdev_info(lag->netdev, "Shared SR-IOV resources in bond are active\n"); } /** - * ice_lag_config_eswitch - configure eswitch to work with LAG - * @lag: lag info struct - * @netdev: active network interface device struct - * - * Updates all port representors in eswitch to use @netdev for Tx. - * - * Configures the netdev to keep dst metadata (also used in representor Tx). - * This is required for an uplink without switchdev mode configured. - */ -static void ice_lag_config_eswitch(struct ice_lag *lag, - struct net_device *netdev) -{ - struct ice_repr *repr; - unsigned long id; - - xa_for_each(&lag->pf->eswitch.reprs, id, repr) - repr->dst->u.port_info.lower_dev = netdev; - - netif_keep_dst(netdev); -} - -/** - * ice_lag_unlink - handle unlink event + * ice_lag_act_bkup_unlink - handle unlink event for A/B bond * @lag: LAG info struct */ -static void ice_lag_unlink(struct ice_lag *lag) +static void ice_lag_act_bkup_unlink(struct ice_lag *lag) { u8 pri_port, act_port, loc_port; struct ice_pf *pf = lag->pf; @@ -1062,10 +1394,32 @@ static void ice_lag_unlink(struct ice_lag *lag) } } } +} - lag->bonded = false; - lag->role = ICE_LAG_NONE; - lag->upper_netdev = NULL; +/** + * ice_lag_aa_unlink - handle unlink event for Active-Active bond + * @lag: LAG info struct + */ +static void ice_lag_aa_unlink(struct ice_lag *lag) +{ + struct ice_lag *pri_lag; + + if (lag->primary) { + pri_lag = lag; + lag->port_bitmap &= ~ICE_LAGP_M; + } else { + pri_lag = ice_lag_find_primary(lag); + if (pri_lag) + pri_lag->port_bitmap &= ICE_LAGS_M; + } + + if (pri_lag) { + ice_lag_aa_failover(pri_lag, ICE_LAGP_IDX, lag->pf); + if (lag->primary) + pri_lag->bond_lport_pri = ICE_LAG_INVALID_PORT; + else + pri_lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + } } /** @@ -1081,10 +1435,20 @@ static void ice_lag_link_unlink(struct ice_lag *lag, void *ptr) if (netdev != lag->netdev) return; - if (info->linking) + if (info->linking) { ice_lag_link(lag); - else - ice_lag_unlink(lag); + } else { + if (lag->bond_aa) + ice_lag_aa_unlink(lag); + else + ice_lag_act_bkup_unlink(lag); + + lag->bonded = false; + lag->role = ICE_LAG_NONE; + lag->upper_netdev = NULL; + lag->bond_aa = false; + lag->need_fltr_cfg = false; + } } /** @@ -1102,7 +1466,7 @@ ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag, { struct ice_aqc_alloc_free_res_elem *buf; struct ice_aqc_set_port_params *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 buf_len, swid; int status, i; @@ -1150,7 +1514,7 @@ ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag, else swid = local_lag->pf->hw.port_info->sw_id; - cmd = &desc.params.set_port_params; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_params); cmd->swid = cpu_to_le16(ICE_AQC_PORT_SWID_VALID | swid); @@ -1182,11 +1546,8 @@ ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag, */ static void ice_lag_primary_swid(struct ice_lag *lag, bool link) { - struct ice_hw *hw; - u16 swid; - - hw = &lag->pf->hw; - swid = hw->port_info->sw_id; + struct ice_hw *hw = &lag->pf->hw; + u16 swid = hw->port_info->sw_id; if (ice_share_res(hw, ICE_AQC_RES_TYPE_SWID, link, swid)) dev_warn(ice_pf_to_dev(lag->pf), "Failure to set primary interface shared status\n"); @@ -1199,12 +1560,10 @@ static void ice_lag_primary_swid(struct ice_lag *lag, bool link) */ static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { - u16 num_vsi, rule_buf_sz, vsi_list_id, event_vsi_num, prim_vsi_idx; - struct ice_sw_rule_vsi_list *s_rule = NULL; + u16 rule_buf_sz, vsi_list_id, event_vsi_num, prim_vsi_idx, num_vsi = 1; + struct ice_sw_rule_vsi_list *s_rule; struct device *dev; - num_vsi = 1; - dev = ice_pf_to_dev(lag->pf); event_vsi_num = event_pf->vsi[0]->vsi_num; prim_vsi_idx = lag->pf->vsi[0]->idx; @@ -1240,12 +1599,10 @@ static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) */ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { - u16 num_vsi, vsi_num, vsi_idx, rule_buf_sz, vsi_list_id; - struct ice_sw_rule_vsi_list *s_rule = NULL; + u16 vsi_num, vsi_idx, rule_buf_sz, vsi_list_id, num_vsi = 1; + struct ice_sw_rule_vsi_list *s_rule; struct device *dev; - num_vsi = 1; - dev = ice_pf_to_dev(lag->pf); vsi_num = event_pf->vsi[0]->vsi_num; vsi_idx = lag->pf->vsi[0]->idx; @@ -1293,6 +1650,11 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) ice_set_feature_support(pf, ICE_F_SRIOV_LAG); else ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); + + if (caps->sriov_aa_lag && ice_pkg_has_lport_extract(&pf->hw)) + ice_set_feature_support(pf, ICE_F_SRIOV_AA_LAG); + else + ice_clear_feature_support(pf, ICE_F_SRIOV_AA_LAG); } /** @@ -1302,11 +1664,10 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) */ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct ice_lag *primary_lag; struct net_device *netdev; - info = ptr; netdev = netdev_notifier_info_to_dev(ptr); /* not for this netdev */ @@ -1327,6 +1688,9 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) /* Configure primary's SWID to be shared */ ice_lag_primary_swid(lag, true); primary_lag = lag; + lag->bond_lport_pri = lag->pf->hw.port_info->lport; + lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + lag->port_bitmap = 0; } else { u16 swid; @@ -1336,16 +1700,29 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) swid = primary_lag->pf->hw.port_info->sw_id; ice_lag_set_swid(swid, lag, true); ice_lag_add_prune_list(primary_lag, lag->pf); - ice_lag_cfg_drop_fltr(lag, true); + primary_lag->bond_lport_sec = + lag->pf->hw.port_info->lport; } /* add filter for primary control packets */ - ice_lag_cfg_cp_fltr(lag, true); + ice_lag_cfg_lp_fltr(lag, true, true); } else { if (!primary_lag && lag->primary) primary_lag = lag; + if (primary_lag) { + for (int i = 0; i < ICE_MAX_SRIOV_VFS; i++) { + if (primary_lag->sec_vf[i]) { + ice_vsi_release(primary_lag->sec_vf[i]); + primary_lag->sec_vf[i] = NULL; + } + } + } + if (!lag->primary) { ice_lag_set_swid(0, lag, false); + if (primary_lag) + primary_lag->bond_lport_sec = + ICE_LAG_INVALID_PORT; } else { if (primary_lag && lag->primary) { ice_lag_primary_swid(lag, false); @@ -1353,7 +1730,7 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) } } /* remove filter for control packets */ - ice_lag_cfg_cp_fltr(lag, false); + ice_lag_cfg_lp_fltr(lag, false, !lag->bond_aa); } } @@ -1366,7 +1743,7 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) */ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct ice_hw *prim_hw, *active_hw; struct net_device *event_netdev; struct ice_pf *pf; @@ -1379,19 +1756,34 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) if (!netif_is_same_ice(lag->pf, event_netdev)) return; + if (info->upper_dev != lag->upper_netdev) + return; + + if (info->linking) + return; + pf = lag->pf; prim_hw = &pf->hw; prim_port = prim_hw->port_info->lport; - info = (struct netdev_notifier_changeupper_info *)ptr; - if (info->upper_dev != lag->upper_netdev) - return; - - if (!info->linking) { - /* Since there are only two interfaces allowed in SRIOV+LAG, if - * one port is leaving, then nodes need to be on primary - * interface. - */ + /* Since there are only two interfaces allowed in SRIOV+LAG, if + * one port is leaving, then nodes need to be on primary + * interface. + */ + if (lag->bond_aa) { + struct ice_netdev_priv *e_ndp; + struct ice_pf *e_pf; + + e_ndp = netdev_priv(event_netdev); + e_pf = e_ndp->vsi->back; + + if (lag->bond_lport_pri != ICE_LAG_INVALID_PORT && + lag->port_bitmap & ICE_LAGS_M) { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, e_pf); + lag->bond_lport_sec = ICE_LAG_INVALID_PORT; + } + } else { if (prim_port != lag->active_port && lag->active_port != ICE_LAG_INVALID_PORT) { active_hw = ice_lag_find_hw_by_lport(lag, @@ -1403,45 +1795,32 @@ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) } /** - * ice_lag_monitor_active - main PF keep track of which port is active + * ice_lag_monitor_act_bkup - keep track of which port is active in A/B LAG * @lag: lag info struct - * @ptr: opaque data containing notifier event + * @b_info: bonding info + * @event_netdev: net_device got target netdev * * This function is for the primary PF to monitor changes in which port is * active and handle changes for SRIOV VF functionality */ -static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) +static void ice_lag_monitor_act_bkup(struct ice_lag *lag, + struct netdev_bonding_info *b_info, + struct net_device *event_netdev) { - struct net_device *event_netdev, *event_upper; - struct netdev_notifier_bonding_info *info; - struct netdev_bonding_info *bonding_info; struct ice_netdev_priv *event_np; struct ice_pf *pf, *event_pf; u8 prim_port, event_port; - if (!lag->primary) - return; - pf = lag->pf; if (!pf) return; - event_netdev = netdev_notifier_info_to_dev(ptr); - rcu_read_lock(); - event_upper = netdev_master_upper_dev_get_rcu(event_netdev); - rcu_read_unlock(); - if (!netif_is_ice(event_netdev) || event_upper != lag->upper_netdev) - return; - event_np = netdev_priv(event_netdev); event_pf = event_np->vsi->back; event_port = event_pf->hw.port_info->lport; prim_port = pf->hw.port_info->lport; - info = (struct netdev_notifier_bonding_info *)ptr; - bonding_info = &info->bonding_info; - - if (!bonding_info->slave.state) { + if (!b_info->slave.state) { /* if no port is currently active, then nodes and filters exist * on primary port, check if we need to move them */ @@ -1478,6 +1857,128 @@ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) } /** + * ice_lag_aa_clear_spoof - adjust the placeholder VSI spoofing for A/A LAG + * @vsi: placeholder VSI to adjust + */ +static void ice_lag_aa_clear_spoof(struct ice_vsi *vsi) +{ + ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof); +} + +/** + * ice_lag_monitor_act_act - Keep track of active ports in A/A LAG + * @lag: lag struct for primary interface + * @b_info: bonding_info for event + * @event_netdev: net_device for target netdev + */ +static void ice_lag_monitor_act_act(struct ice_lag *lag, + struct netdev_bonding_info *b_info, + struct net_device *event_netdev) +{ + struct ice_netdev_priv *event_np; + u8 prim_port, event_port; + struct ice_pf *event_pf; + + event_np = netdev_priv(event_netdev); + event_pf = event_np->vsi->back; + event_port = event_pf->hw.port_info->lport; + prim_port = lag->pf->hw.port_info->lport; + + if (b_info->slave.link == BOND_LINK_UP) { + /* Port is coming up */ + if (prim_port == event_port) { + /* Processing event for primary interface */ + if (lag->bond_lport_pri == ICE_LAG_INVALID_PORT) + return; + + if (!(lag->port_bitmap & ICE_LAGP_M)) { + /* Primary port was not marked up before, move + * some|all VF queues to it and mark as up + */ + lag->port_bitmap |= ICE_LAGP_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, event_pf); + } + } else { + if (lag->bond_lport_sec == ICE_LAG_INVALID_PORT) + return; + + /* Create placeholder VSIs on secondary PF. + * The placeholder is necessary so that we have + * an element that represents the VF on the secondary + * interface's scheduling tree. This will be a tree + * root for scheduling nodes when they are moved to + * the secondary interface. + */ + if (!lag->sec_vf[0]) { + struct ice_vsi_cfg_params params = {}; + struct ice_vsi *nvsi; + struct ice_vf *vf; + unsigned int bkt; + + params.type = ICE_VSI_VF; + params.port_info = event_pf->hw.port_info; + params.flags = ICE_VSI_FLAG_INIT; + + ice_for_each_vf(lag->pf, bkt, vf) { + params.vf = vf; + nvsi = ice_vsi_setup(event_pf, + ¶ms); + ice_lag_aa_clear_spoof(nvsi); + lag->sec_vf[vf->vf_id] = nvsi; + } + } + + if (!(lag->port_bitmap & ICE_LAGS_M)) { + /* Secondary port was not marked up before, + * move some|all VF queues to it and mark as up + */ + lag->port_bitmap |= ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGS_IDX, event_pf); + } + } + } else { + /* Port is going down */ + if (prim_port == event_port) { + lag->port_bitmap &= ~ICE_LAGP_M; + ice_lag_aa_failover(lag, ICE_LAGS_IDX, event_pf); + } else { + lag->port_bitmap &= ~ICE_LAGS_M; + ice_lag_aa_failover(lag, ICE_LAGP_IDX, event_pf); + } + } +} + +/** + * ice_lag_monitor_info - Calls relevant A/A or A/B monitoring function + * @lag: lag info struct + * @ptr: opaque data containing notifier event + * + * This function is for the primary PF to monitor changes in which port is + * active and handle changes for SRIOV VF functionality + */ +static void ice_lag_monitor_info(struct ice_lag *lag, void *ptr) +{ + struct netdev_notifier_bonding_info *info = ptr; + struct net_device *event_netdev, *event_upper; + struct netdev_bonding_info *bonding_info; + + if (!lag->primary) + return; + + event_netdev = netdev_notifier_info_to_dev(ptr); + bonding_info = &info->bonding_info; + rcu_read_lock(); + event_upper = netdev_master_upper_dev_get_rcu(event_netdev); + rcu_read_unlock(); + if (!netif_is_ice(event_netdev) || event_upper != lag->upper_netdev) + return; + + if (lag->bond_aa) + ice_lag_monitor_act_act(lag, bonding_info, event_netdev); + else + ice_lag_monitor_act_bkup(lag, bonding_info, event_netdev); +} +/** * ice_lag_chk_comp - evaluate bonded interface for feature support * @lag: lag info struct * @ptr: opaque data for netdev event info @@ -1485,13 +1986,21 @@ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) static bool ice_lag_chk_comp(struct ice_lag *lag, void *ptr) { + struct netdev_notifier_bonding_info *info = ptr; struct net_device *event_netdev, *event_upper; - struct netdev_notifier_bonding_info *info; struct netdev_bonding_info *bonding_info; struct list_head *tmp; struct device *dev; int count = 0; + /* All members need to know if bond A/A or A/B */ + bonding_info = &info->bonding_info; + lag->bond_mode = bonding_info->master.bond_mode; + if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) + lag->bond_aa = true; + else + lag->bond_aa = false; + if (!lag->primary) return true; @@ -1512,13 +2021,9 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr) return false; } - info = (struct netdev_notifier_bonding_info *)ptr; - bonding_info = &info->bonding_info; - lag->bond_mode = bonding_info->master.bond_mode; - if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) { - dev_info(dev, "Bond Mode not ACTIVE-BACKUP - VF LAG disabled\n"); + if (lag->bond_aa && !ice_is_feature_supported(lag->pf, + ICE_F_SRIOV_AA_LAG)) return false; - } list_for_each(tmp, lag->netdev_head) { struct ice_dcbx_cfg *dcb_cfg, *peer_dcb_cfg; @@ -1622,10 +2127,9 @@ ice_lag_unregister(struct ice_lag *lag, struct net_device *event_netdev) static void ice_lag_monitor_rdma(struct ice_lag *lag, void *ptr) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; struct net_device *netdev; - info = ptr; netdev = netdev_notifier_info_to_dev(ptr); if (netdev != lag->netdev) @@ -1673,12 +2177,30 @@ static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr) */ static void ice_lag_disable_sriov_bond(struct ice_lag *lag) { - struct ice_netdev_priv *np; - struct ice_pf *pf; + struct ice_netdev_priv *np = netdev_priv(lag->netdev); + struct ice_pf *pf = np->vsi->back; - np = netdev_priv(lag->netdev); - pf = np->vsi->back; ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); + ice_clear_feature_support(pf, ICE_F_SRIOV_AA_LAG); +} + +/** + * ice_lag_preset_drop_fltr - preset drop filter for A/B bonds + * @lag: local lag struct + * @ptr: opaque data containing event + * + * Sets the initial drop filter for secondary interface in an + * active-backup bond + */ +static void ice_lag_preset_drop_fltr(struct ice_lag *lag, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + + if (netdev != lag->netdev || lag->primary || !lag->need_fltr_cfg) + return; + + ice_lag_cfg_drop_fltr(lag, true); + lag->need_fltr_cfg = false; } /** @@ -1719,10 +2241,12 @@ static void ice_lag_process_event(struct work_struct *work) ice_lag_unregister(lag_work->lag, netdev); goto lag_cleanup; } - ice_lag_monitor_active(lag_work->lag, - &lag_work->info.bonding_info); ice_lag_cfg_pf_fltrs(lag_work->lag, &lag_work->info.bonding_info); + ice_lag_preset_drop_fltr(lag_work->lag, + &lag_work->info.bonding_info); + ice_lag_monitor_info(lag_work->lag, + &lag_work->info.bonding_info); } ice_lag_info_event(lag_work->lag, &lag_work->info.bonding_info); break; @@ -1795,9 +2319,8 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event, lag_work->lag = lag; lag_work->event = event; if (event == NETDEV_CHANGEUPPER) { - struct netdev_notifier_changeupper_info *info; + struct netdev_notifier_changeupper_info *info = ptr; - info = ptr; upper_netdev = info->upper_dev; } else { upper_netdev = netdev_master_upper_dev_get(netdev); @@ -1847,10 +2370,8 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event, */ static int ice_register_lag_handler(struct ice_lag *lag) { + struct notifier_block *notif_blk = &lag->notif_block; struct device *dev = ice_pf_to_dev(lag->pf); - struct notifier_block *notif_blk; - - notif_blk = &lag->notif_block; if (!notif_blk->notifier_call) { notif_blk->notifier_call = ice_lag_event_handler; @@ -1870,10 +2391,9 @@ static int ice_register_lag_handler(struct ice_lag *lag) */ static void ice_unregister_lag_handler(struct ice_lag *lag) { + struct notifier_block *notif_blk = &lag->notif_block; struct device *dev = ice_pf_to_dev(lag->pf); - struct notifier_block *notif_blk; - notif_blk = &lag->notif_block; if (notif_blk->notifier_call) { unregister_netdevice_notifier(notif_blk); dev_dbg(dev, "LAG event handler unregistered\n"); @@ -1935,13 +2455,12 @@ ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw, u16 numq, valq, num_moved, qbuf_size; u16 buf_size = __struct_size(buf); struct ice_aqc_cfg_txqs_buf *qbuf; + struct ice_hw *hw = &lag->pf->hw; struct ice_sched_node *n_prt; __le32 teid, parent_teid; struct ice_vsi_ctx *ctx; - struct ice_hw *hw; u32 tmp_teid; - hw = &lag->pf->hw; ctx = ice_get_vsi_ctx(hw, vsi_num); if (!ctx) { dev_warn(dev, "LAG rebuild failed after reset due to VSI Context failure\n"); @@ -1978,7 +2497,8 @@ ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw, } if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq, hw->port_info->lport, - dest_hw->port_info->lport, NULL)) { + dest_hw->port_info->lport, + ICE_AQC_Q_CFG_TC_CHNG, NULL)) { dev_warn(dev, "Failure to configure queues for LAG reset rebuild\n"); goto sync_qerr; } @@ -2074,9 +2594,13 @@ int ice_init_lag(struct ice_pf *pf) lag->netdev = vsi->netdev; lag->role = ICE_LAG_NONE; lag->active_port = ICE_LAG_INVALID_PORT; + lag->port_bitmap = 0x0; lag->bonded = false; + lag->bond_aa = false; + lag->need_fltr_cfg = false; lag->upper_netdev = NULL; lag->notif_block.notifier_call = NULL; + memset(lag->sec_vf, 0, sizeof(lag->sec_vf)); err = ice_register_lag_handler(lag); if (err) { @@ -2094,6 +2618,11 @@ int ice_init_lag(struct ice_pf *pf) if (err) goto free_rcp_res; + err = ice_create_lag_recipe(&pf->hw, &lag->act_act_recipe, + ice_lport_rcp, 1); + if (err) + goto free_lport_res; + /* associate recipes to profiles */ for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) { err = ice_aq_get_recipe_to_profile(&pf->hw, n, @@ -2103,7 +2632,8 @@ int ice_init_lag(struct ice_pf *pf) if (recipe_bits & BIT(ICE_SW_LKUP_DFLT)) { recipe_bits |= BIT(lag->pf_recipe) | - BIT(lag->lport_recipe); + BIT(lag->lport_recipe) | + BIT(lag->act_act_recipe); ice_aq_map_recipe_to_profile(&pf->hw, n, recipe_bits, NULL); } @@ -2114,9 +2644,13 @@ int ice_init_lag(struct ice_pf *pf) dev_dbg(dev, "INIT LAG complete\n"); return 0; +free_lport_res: + ice_free_hw_res(&pf->hw, ICE_AQC_RES_TYPE_RECIPE, 1, + &lag->lport_recipe); + free_rcp_res: ice_free_hw_res(&pf->hw, ICE_AQC_RES_TYPE_RECIPE, 1, - &pf->lag->pf_recipe); + &lag->pf_recipe); lag_error: kfree(lag); pf->lag = NULL; @@ -2132,9 +2666,7 @@ lag_error: */ void ice_deinit_lag(struct ice_pf *pf) { - struct ice_lag *lag; - - lag = pf->lag; + struct ice_lag *lag = pf->lag; if (!lag) return; @@ -2203,11 +2735,15 @@ void ice_lag_rebuild(struct ice_pf *pf) ice_lag_move_vf_nodes_sync(prim_lag, &pf->hw); } - ice_lag_cfg_cp_fltr(lag, true); + if (!lag->bond_aa) { + ice_lag_cfg_lp_fltr(lag, true, true); + if (lag->pf_rx_rule_id) + if (ice_lag_cfg_dflt_fltr(lag, true)) + dev_err(ice_pf_to_dev(pf), "Error adding default VSI rule in rebuild\n"); + } else { + ice_lag_cfg_lp_fltr(lag, true, false); + } - if (lag->pf_rx_rule_id) - if (ice_lag_cfg_dflt_fltr(lag, true)) - dev_err(ice_pf_to_dev(pf), "Error adding default VSI rule in rebuild\n"); ice_clear_rdma_cap(pf); lag_rebuild_out: diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h index bab2c83142a1..f77ebcd61042 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.h +++ b/drivers/net/ethernet/intel/ice/ice_lag.h @@ -14,7 +14,11 @@ enum ice_lag_role { ICE_LAG_UNSET }; -#define ICE_LAG_INVALID_PORT 0xFF +#define ICE_LAG_INVALID_PORT 0xFF +#define ICE_LAGP_IDX 0 +#define ICE_LAGS_IDX 1 +#define ICE_LAGP_M 0x1 +#define ICE_LAGS_M 0x2 #define ICE_LAG_RESET_RETRIES 5 #define ICE_SW_DEFAULT_PROFILE 0 @@ -41,12 +45,26 @@ struct ice_lag { u8 active_port; /* lport value for the current active port */ u8 bonded:1; /* currently bonded */ u8 primary:1; /* this is primary */ + u8 bond_aa:1; /* is this bond active-active */ + u8 need_fltr_cfg:1; /* fltrs for A/A bond still need to be make */ + u8 port_bitmap:2; /* bitmap of active ports */ + u8 bond_lport_pri; /* lport values for primary PF */ + u8 bond_lport_sec; /* lport values for secondary PF */ + + /* q_home keeps track of which interface the q is currently on */ + u8 q_home[ICE_MAX_SRIOV_VFS][ICE_MAX_RSS_QS_PER_VF]; + + /* placeholder VSI for hanging VF queues from on secondary interface */ + struct ice_vsi *sec_vf[ICE_MAX_SRIOV_VFS]; + u16 pf_recipe; u16 lport_recipe; + u16 act_act_recipe; u16 pf_rx_rule_id; u16 pf_tx_rule_id; u16 cp_rule_idx; u16 lport_rule_idx; + u16 act_act_rule_idx; u8 role; }; @@ -64,10 +82,12 @@ struct ice_lag_work { } info; }; -void ice_lag_move_new_vf_nodes(struct ice_vf *vf); +void ice_lag_aa_failover(struct ice_lag *lag, u8 dest, struct ice_pf *e_pf); int ice_init_lag(struct ice_pf *pf); void ice_deinit_lag(struct ice_pf *pf); void ice_lag_rebuild(struct ice_pf *pf); bool ice_lag_is_switchdev_running(struct ice_pf *pf); void ice_lag_move_vf_nodes_cfg(struct ice_lag *lag, u8 src_prt, u8 dst_prt); +u8 ice_lag_prepare_vf_reset(struct ice_lag *lag); +void ice_lag_complete_vf_reset(struct ice_lag *lag, u8 act_prt); #endif /* _ICE_LAG_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index 77ba26538b07..10c312d49e05 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -569,4 +569,45 @@ struct ice_tlan_ctx { u8 pkt_shaper_prof_idx; }; +#define ICE_TXTIME_TX_DESC_IDX_M GENMASK(12, 0) +#define ICE_TXTIME_STAMP_M GENMASK(31, 13) + +/* Tx time stamp descriptor */ +struct ice_ts_desc { + __le32 tx_desc_idx_tstamp; +}; + +#define ICE_TS_DESC(R, i) (&(((struct ice_ts_desc *)((R)->desc))[i])) + +#define ICE_TXTIME_MAX_QUEUE 2047 +#define ICE_SET_TXTIME_MAX_Q_AMOUNT 127 +#define ICE_TXTIME_FETCH_TS_DESC_DFLT 8 +#define ICE_TXTIME_FETCH_PROFILE_CNT 16 + +/* Tx Time queue context data */ +struct ice_txtime_ctx { +#define ICE_TXTIME_CTX_BASE_S 7 + u64 base; /* base is defined in 128-byte units */ + u8 pf_num; + u16 vmvf_num; + u8 vmvf_type; + u16 src_vsi; + u8 cpuid; + u8 tphrd_desc; + u16 qlen; + u8 timer_num; + u8 txtime_ena_q; + u8 drbell_mode_32; +#define ICE_TXTIME_CTX_DRBELL_MODE_32 1 + u8 ts_res; +#define ICE_TXTIME_CTX_RESOLUTION_128NS 7 + u8 ts_round_type; + u8 ts_pacing_slot; +#define ICE_TXTIME_CTX_FETCH_PROF_ID_0 0 + u8 merging_ena; + u8 ts_fetch_prof_id; + u8 ts_fetch_cache_line_aln_thld; + u8 tx_pipe_delay_mode; +}; + #endif /* _ICE_LAN_TX_RX_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 03bb16191237..4479c824561e 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -484,8 +484,7 @@ static irqreturn_t ice_msix_clean_ctrl_vsi(int __always_unused irq, void *data) if (!q_vector->tx.tx_ring) return IRQ_HANDLED; -#define FDIR_RX_DESC_CLEAN_BUDGET 64 - ice_clean_rx_irq(q_vector->rx.rx_ring, FDIR_RX_DESC_CLEAN_BUDGET); + ice_clean_ctrl_rx_irq(q_vector->rx.rx_ring); ice_clean_ctrl_tx_irq(q_vector->tx.tx_ring); return IRQ_HANDLED; @@ -1579,7 +1578,7 @@ static void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi) return; } - status = ice_add_avf_rss_cfg(&pf->hw, vsi, ICE_DEFAULT_RSS_HENA); + status = ice_add_avf_rss_cfg(&pf->hw, vsi, ICE_DEFAULT_RSS_HASHCFG); if (status) dev_dbg(dev, "ice_add_avf_rss_cfg failed for vsi = %d, error = %d\n", vsi->vsi_num, status); @@ -3200,7 +3199,7 @@ void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc) if (!netdev) return; - /* CHNL VSI doesn't have it's own netdev, hence, no netdev_tc */ + /* CHNL VSI doesn't have its own netdev, hence, no netdev_tc */ if (vsi->type == ICE_VSI_CHNL) return; @@ -3737,20 +3736,20 @@ int ice_set_link(struct ice_vsi *vsi, bool ena) status = ice_aq_set_link_restart_an(pi, ena, NULL); - /* if link is owned by manageability, FW will return ICE_AQ_RC_EMODE. + /* 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 * a success code. Return an error if FW returns an error code other - * than ICE_AQ_RC_EMODE + * than LIBIE_AQ_RC_EMODE */ if (status == -EIO) { - if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE) + if (hw->adminq.sq_last_status == LIBIE_AQ_RC_EMODE) dev_dbg(dev, "can't set link to %s, err %d aq_err %s. not fatal, continuing\n", (ena ? "ON" : "OFF"), status, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); } else if (status) { dev_err(dev, "can't set link to %s, err %d aq_err %s\n", (ena ? "ON" : "OFF"), status, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); return status; } @@ -3951,6 +3950,7 @@ void ice_init_feature_support(struct ice_pf *pf) 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); + ice_set_feature_support(pf, ICE_F_TXTIME); } } @@ -4021,3 +4021,38 @@ ice_vsi_update_local_lb(struct ice_vsi *vsi, bool set) vsi->info = ctx.info; return 0; } + +/** + * ice_vsi_update_l2tsel - update l2tsel field for all Rx rings on this VSI + * @vsi: VSI used to update l2tsel on + * @l2tsel: l2tsel setting requested + * + * Use the l2tsel setting to update all of the Rx queue context bits for l2tsel. + * This will modify which descriptor field the first offloaded VLAN will be + * stripped into. + */ +void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel) +{ + struct ice_hw *hw = &vsi->back->hw; + u32 l2tsel_bit; + int i; + + if (l2tsel == ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND) + l2tsel_bit = 0; + else + l2tsel_bit = BIT(ICE_L2TSEL_BIT_OFFSET); + + for (i = 0; i < vsi->alloc_rxq; i++) { + u16 pfq = vsi->rxq_map[i]; + u32 qrx_context_offset; + u32 regval; + + qrx_context_offset = + QRX_CONTEXT(ICE_L2TSEL_QRX_CONTEXT_REG_IDX, pfq); + + regval = rd32(hw, qrx_context_offset); + regval &= ~BIT(ICE_L2TSEL_BIT_OFFSET); + regval |= l2tsel_bit; + wr32(hw, qrx_context_offset, regval); + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 654516c5fc3e..2cb1eb98b9da 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -11,6 +11,13 @@ #define ICE_VSI_FLAG_INIT BIT(0) #define ICE_VSI_FLAG_NO_INIT 0 +#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX 3 +#define ICE_L2TSEL_BIT_OFFSET 23 +enum ice_l2tsel { + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND, + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1, +}; + const char *ice_vsi_type_str(enum ice_vsi_type vsi_type); bool ice_pf_state_is_nominal(struct ice_pf *pf); @@ -116,4 +123,5 @@ void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f); void ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f); void ice_init_feature_support(struct ice_pf *pf); bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi); +void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel); #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0a11b4281092..86f5859e88ef 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -38,6 +38,8 @@ static const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation."; MODULE_DESCRIPTION(DRV_SUMMARY); MODULE_IMPORT_NS("LIBIE"); +MODULE_IMPORT_NS("LIBIE_ADMINQ"); +MODULE_IMPORT_NS("LIBIE_FWLOG"); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(ICE_DDP_PKG_FILE); @@ -379,7 +381,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) * should go into promiscuous mode. There should be some * space reserved for promiscuous filters. */ - if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOSPC && + if (hw->adminq.sq_last_status == LIBIE_AQ_RC_ENOSPC && !test_and_set_bit(ICE_FLTR_OVERFLOW_PROMISC, vsi->state)) { promisc_forced_on = true; @@ -1119,7 +1121,7 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, if (status) dev_dbg(dev, "Failed to update link status on port %d, err %d aq_err %s\n", pi->lport, status, - ice_aq_str(pi->hw->adminq.sq_last_status)); + libie_aq_str(pi->hw->adminq.sq_last_status)); ice_check_link_cfg_err(pf, pi->phy.link_info.link_cfg_err); @@ -1144,6 +1146,9 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, if (link_up == old_link && link_speed == old_link_speed) return 0; + if (!link_up && old_link) + pf->link_down_events++; + ice_ptp_link_change(pf, link_up); if (ice_is_dcb_active(pf)) { @@ -1247,32 +1252,6 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event) } /** - * ice_get_fwlog_data - copy the FW log data from ARQ event - * @pf: PF that the FW log event is associated with - * @event: event structure containing FW log data - */ -static void -ice_get_fwlog_data(struct ice_pf *pf, struct ice_rq_event_info *event) -{ - struct ice_fwlog_data *fwlog; - struct ice_hw *hw = &pf->hw; - - fwlog = &hw->fwlog_ring.rings[hw->fwlog_ring.tail]; - - memset(fwlog->data, 0, PAGE_SIZE); - fwlog->data_size = le16_to_cpu(event->desc.datalen); - - memcpy(fwlog->data, event->msg_buf, fwlog->data_size); - ice_fwlog_ring_increment(&hw->fwlog_ring.tail, hw->fwlog_ring.size); - - if (ice_fwlog_ring_full(&hw->fwlog_ring)) { - /* the rings are full so bump the head to create room */ - ice_fwlog_ring_increment(&hw->fwlog_ring.head, - hw->fwlog_ring.size); - } -} - -/** * ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware * @pf: pointer to the PF private structure * @task: intermediate helper storage and identifier for waiting @@ -1562,7 +1541,8 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) } break; case ice_aqc_opc_fw_logs_event: - ice_get_fwlog_data(pf, &event); + libie_get_fwlog_data(&hw->fwlog, event.msg_buf, + le16_to_cpu(event.desc.datalen)); break; case ice_aqc_opc_lldp_set_mib_change: ice_dcb_process_lldp_set_mib_change(pf, &event); @@ -3172,12 +3152,14 @@ static irqreturn_t ice_ll_ts_intr(int __always_unused irq, void *data) hw = &pf->hw; tx = &pf->ptp.port.tx; spin_lock_irqsave(&tx->lock, flags); - ice_ptp_complete_tx_single_tstamp(tx); + if (tx->init) { + ice_ptp_complete_tx_single_tstamp(tx); - idx = find_next_bit_wrap(tx->in_use, tx->len, - tx->last_ll_ts_idx_read + 1); - if (idx != tx->len) - ice_ptp_req_tx_single_tstamp(tx, idx); + idx = find_next_bit_wrap(tx->in_use, tx->len, + tx->last_ll_ts_idx_read + 1); + if (idx != tx->len) + ice_ptp_req_tx_single_tstamp(tx, idx); + } spin_unlock_irqrestore(&tx->lock, flags); val = GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M | @@ -3987,6 +3969,11 @@ static void ice_deinit_pf(struct ice_pf *pf) pf->avail_rxqs = NULL; } + if (pf->txtime_txqs) { + bitmap_free(pf->txtime_txqs); + pf->txtime_txqs = NULL; + } + if (pf->ptp.clock) ptp_clock_unregister(pf->ptp.clock); @@ -4080,6 +4067,15 @@ static int ice_init_pf(struct ice_pf *pf) return -ENOMEM; } + pf->txtime_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); + if (!pf->txtime_txqs) { + bitmap_free(pf->avail_txqs); + pf->avail_txqs = NULL; + bitmap_free(pf->avail_rxqs); + pf->avail_rxqs = NULL; + return -ENOMEM; + } + mutex_init(&pf->vfs.table_lock); hash_init(pf->vfs.table); if (ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) @@ -4221,7 +4217,7 @@ static void ice_set_safe_mode_vlan_cfg(struct ice_pf *pf) status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { dev_err(ice_pf_to_dev(vsi->back), "Failed to update VSI for safe mode VLANs, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); } else { vsi->info.sec_flags = ctxt->info.sec_flags; vsi->info.sw_flags2 = ctxt->info.sw_flags2; @@ -4532,17 +4528,23 @@ ice_init_tx_topology(struct ice_hw *hw, const struct firmware *firmware) dev_info(dev, "Tx scheduling layers switching feature disabled\n"); else dev_info(dev, "Tx scheduling layers switching feature enabled\n"); - /* if there was a change in topology ice_cfg_tx_topo triggered - * a CORER and we need to re-init hw + return 0; + } else if (err == -ENODEV) { + /* If we failed to re-initialize the device, we can no longer + * continue loading. */ - ice_deinit_hw(hw); - err = ice_init_hw(hw); - + dev_warn(dev, "Failed to initialize hardware after applying Tx scheduling configuration.\n"); return err; } else if (err == -EIO) { dev_info(dev, "DDP package does not support Tx scheduling layers switching feature - please update to the latest DDP package and try again\n"); + return 0; + } else if (err == -EEXIST) { + return 0; } + /* Do not treat this as a fatal error. */ + dev_info(dev, "Failed to apply Tx scheduling configuration, err %pe\n", + ERR_PTR(err)); return 0; } @@ -4642,19 +4644,6 @@ static void ice_print_wake_reason(struct ice_pf *pf) } /** - * ice_pf_fwlog_update_module - update 1 module - * @pf: pointer to the PF struct - * @log_level: log_level to use for the @module - * @module: module to update - */ -void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module) -{ - struct ice_hw *hw = &pf->hw; - - hw->fwlog_cfg.module_entries[module].log_level = log_level; -} - -/** * ice_register_netdev - register netdev * @vsi: pointer to the VSI struct */ @@ -4764,7 +4753,6 @@ int ice_init_dev(struct ice_pf *pf) pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port; pf->hw.udp_tunnel_nic.unset_port = ice_udp_tunnel_unset_port; - pf->hw.udp_tunnel_nic.flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP; pf->hw.udp_tunnel_nic.shared = &pf->hw.udp_tunnel_shared; if (pf->hw.tnl.valid_count[TNL_VXLAN]) { pf->hw.udp_tunnel_nic.tables[0].n_entries = @@ -5429,7 +5417,7 @@ static void ice_setup_mc_magic_wake(struct ice_pf *pf) status = ice_aq_manage_mac_write(hw, mac_addr, flags, NULL); if (status) dev_err(dev, "Failed to enable Multicast Magic Packet wake, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); } /** @@ -5895,6 +5883,15 @@ static const struct pci_device_id ice_pci_tbl[] = { { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830_XXV_QSFP), }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830C_SFP), }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E830_XXV_SFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835CC_BACKPLANE), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835CC_QSFP56), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835CC_SFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835C_BACKPLANE), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835C_QSFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835C_SFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835_L_BACKPLANE), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835_L_QSFP), }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E835_L_SFP), }, /* required last entry */ {} }; @@ -7501,7 +7498,8 @@ int ice_vsi_open(struct ice_vsi *vsi) if (err) goto err_setup_rx; - ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc); + if (bitmap_empty(pf->txtime_txqs, pf->max_pf_txqs)) + ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc); if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_SF) { /* Notify the stack of the actual queue counts. */ @@ -7900,69 +7898,6 @@ int ice_change_mtu(struct net_device *netdev, int new_mtu) } /** - * ice_eth_ioctl - Access the hwtstamp interface - * @netdev: network interface device structure - * @ifr: interface request data - * @cmd: ioctl command - */ -static int ice_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; - - switch (cmd) { - case SIOCGHWTSTAMP: - return ice_ptp_get_ts_config(pf, ifr); - case SIOCSHWTSTAMP: - return ice_ptp_set_ts_config(pf, ifr); - default: - return -EOPNOTSUPP; - } -} - -/** - * ice_aq_str - convert AQ err code to a string - * @aq_err: the AQ error code to convert - */ -const char *ice_aq_str(enum ice_aq_err aq_err) -{ - switch (aq_err) { - case ICE_AQ_RC_OK: - return "OK"; - case ICE_AQ_RC_EPERM: - return "ICE_AQ_RC_EPERM"; - case ICE_AQ_RC_ENOENT: - return "ICE_AQ_RC_ENOENT"; - case ICE_AQ_RC_ENOMEM: - return "ICE_AQ_RC_ENOMEM"; - case ICE_AQ_RC_EBUSY: - return "ICE_AQ_RC_EBUSY"; - case ICE_AQ_RC_EEXIST: - return "ICE_AQ_RC_EEXIST"; - case ICE_AQ_RC_EINVAL: - return "ICE_AQ_RC_EINVAL"; - case ICE_AQ_RC_ENOSPC: - return "ICE_AQ_RC_ENOSPC"; - case ICE_AQ_RC_ENOSYS: - return "ICE_AQ_RC_ENOSYS"; - case ICE_AQ_RC_EMODE: - return "ICE_AQ_RC_EMODE"; - case ICE_AQ_RC_ENOSEC: - return "ICE_AQ_RC_ENOSEC"; - case ICE_AQ_RC_EBADSIG: - return "ICE_AQ_RC_EBADSIG"; - case ICE_AQ_RC_ESVN: - return "ICE_AQ_RC_ESVN"; - case ICE_AQ_RC_EBADMAN: - return "ICE_AQ_RC_EBADMAN"; - case ICE_AQ_RC_EBADBUF: - return "ICE_AQ_RC_EBADBUF"; - } - - return "ICE_AQ_RC_UNKNOWN"; -} - -/** * ice_set_rss_lut - Set RSS LUT * @vsi: Pointer to VSI structure * @lut: Lookup table @@ -7987,7 +7922,7 @@ int ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size) status = ice_aq_set_rss_lut(hw, ¶ms); if (status) dev_err(ice_pf_to_dev(vsi->back), "Cannot set RSS lut, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); return status; } @@ -8010,7 +7945,7 @@ int ice_set_rss_key(struct ice_vsi *vsi, u8 *seed) status = ice_aq_set_rss_key(hw, vsi->idx, (struct ice_aqc_get_set_rss_keys *)seed); if (status) dev_err(ice_pf_to_dev(vsi->back), "Cannot set RSS key, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); return status; } @@ -8040,7 +7975,7 @@ int ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size) status = ice_aq_get_rss_lut(hw, ¶ms); if (status) dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS lut, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); return status; } @@ -8063,7 +7998,7 @@ int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed) status = ice_aq_get_rss_key(hw, vsi->idx, (struct ice_aqc_get_set_rss_keys *)seed); if (status) dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS key, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); + status, libie_aq_str(hw->adminq.sq_last_status)); return status; } @@ -8180,7 +8115,7 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (ret) { dev_err(ice_pf_to_dev(vsi->back), "update VSI for bridge mode failed, bmode = %d err %d aq_err %s\n", - bmode, ret, ice_aq_str(hw->adminq.sq_last_status)); + bmode, ret, libie_aq_str(hw->adminq.sq_last_status)); goto out; } /* Update sw flags for book keeping */ @@ -8248,7 +8183,7 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, if (err) { netdev_err(dev, "switch rule update failed, mode = %d err %d aq_err %s\n", mode, err, - ice_aq_str(hw->adminq.sq_last_status)); + libie_aq_str(hw->adminq.sq_last_status)); /* revert hw->evb_veb */ hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB); return err; @@ -9168,7 +9103,7 @@ static int ice_create_q_channels(struct ice_vsi *vsi) list_add_tail(&ch->list, &vsi->ch_list); vsi->tc_map_vsi[i] = ch->ch_vsi; dev_dbg(ice_pf_to_dev(pf), - "successfully created channel: VSI %pK\n", ch->ch_vsi); + "successfully created channel: VSI %p\n", ch->ch_vsi); } return 0; @@ -9353,6 +9288,96 @@ exit: return ret; } +/** + * ice_cfg_txtime - configure Tx Time for the Tx ring + * @tx_ring: pointer to the Tx ring structure + * + * Return: 0 on success, negative value on failure. + */ +static int ice_cfg_txtime(struct ice_tx_ring *tx_ring) +{ + int err, timeout = 50; + struct ice_vsi *vsi; + struct device *dev; + struct ice_pf *pf; + u32 queue; + + if (!tx_ring) + return -EINVAL; + + vsi = tx_ring->vsi; + pf = vsi->back; + while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) { + timeout--; + if (!timeout) + return -EBUSY; + usleep_range(1000, 2000); + } + + queue = tx_ring->q_index; + dev = ice_pf_to_dev(pf); + + /* Ignore return value, and always attempt to enable queue. */ + ice_qp_dis(vsi, queue); + + err = ice_qp_ena(vsi, queue); + if (err) + dev_err(dev, "Failed to enable Tx queue %d for TxTime configuration\n", + queue); + + clear_bit(ICE_CFG_BUSY, pf->state); + return err; +} + +/** + * ice_offload_txtime - set earliest TxTime first + * @netdev: network interface device structure + * @qopt_off: etf queue option offload from the skb to set + * + * Return: 0 on success, negative value on failure. + */ +static int ice_offload_txtime(struct net_device *netdev, + void *qopt_off) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; + struct tc_etf_qopt_offload *qopt; + struct ice_vsi *vsi = np->vsi; + struct ice_tx_ring *tx_ring; + int ret = 0; + + if (!ice_is_feature_supported(pf, ICE_F_TXTIME)) + return -EOPNOTSUPP; + + qopt = qopt_off; + if (!qopt_off || qopt->queue < 0 || qopt->queue >= vsi->num_txq) + return -EINVAL; + + if (qopt->enable) + set_bit(qopt->queue, pf->txtime_txqs); + else + clear_bit(qopt->queue, pf->txtime_txqs); + + if (netif_running(vsi->netdev)) { + tx_ring = vsi->tx_rings[qopt->queue]; + ret = ice_cfg_txtime(tx_ring); + if (ret) + goto err; + } + + netdev_info(netdev, "%s TxTime on queue: %i\n", + str_enable_disable(qopt->enable), qopt->queue); + return 0; + +err: + netdev_err(netdev, "Failed to %s TxTime on queue: %i\n", + str_enable_disable(qopt->enable), qopt->queue); + + if (qopt->enable) + clear_bit(qopt->queue, pf->txtime_txqs); + return ret; +} + static LIST_HEAD(ice_block_cb_list); static int @@ -9416,6 +9441,8 @@ adev_unlock: mutex_unlock(&pf->adev_mutex); } return err; + case TC_SETUP_QDISC_ETF: + return ice_offload_txtime(netdev, type_data); default: return -EOPNOTSUPP; } @@ -9755,7 +9782,6 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_change_mtu = ice_change_mtu, .ndo_get_stats64 = ice_get_stats64, .ndo_set_tx_maxrate = ice_set_tx_maxrate, - .ndo_eth_ioctl = ice_eth_ioctl, .ndo_set_vf_spoofchk = ice_set_vf_spoofchk, .ndo_set_vf_mac = ice_set_vf_mac, .ndo_get_vf_config = ice_get_vf_cfg, @@ -9779,4 +9805,6 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_bpf = ice_xdp, .ndo_xdp_xmit = ice_xdp_xmit, .ndo_xsk_wakeup = ice_xsk_wakeup, + .ndo_hwtstamp_get = ice_ptp_hwtstamp_get, + .ndo_hwtstamp_set = ice_ptp_hwtstamp_set, }; diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index 59e8879ac059..7e187a804dfa 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -22,10 +22,10 @@ int ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length, void *data, bool last_command, bool read_shadow_ram, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; struct ice_aqc_nvm *cmd; - cmd = &desc.params.nvm; + cmd = libie_aq_raw(&desc); if (offset > ICE_AQC_NVM_MAX_OFFSET) return -EINVAL; @@ -125,10 +125,10 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length, void *data, bool last_command, u8 command_flags, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; struct ice_aqc_nvm *cmd; - cmd = &desc.params.nvm; + cmd = libie_aq_raw(&desc); /* In offset the highest byte must be zeroed. */ if (offset & 0xFF000000) @@ -146,7 +146,7 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, cmd->offset_high = (offset >> 16) & 0xFF; cmd->length = cpu_to_le16(length); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); return ice_aq_send_cmd(hw, &desc, data, length, cd); } @@ -161,10 +161,10 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, */ int ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; struct ice_aqc_nvm *cmd; - cmd = &desc.params.nvm; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_erase); @@ -869,7 +869,7 @@ static int ice_discover_flash_size(struct ice_hw *hw) status = ice_read_flat_nvm(hw, offset, &len, &data, false); if (status == -EIO && - hw->adminq.sq_last_status == ICE_AQ_RC_EINVAL) { + hw->adminq.sq_last_status == LIBIE_AQ_RC_EINVAL) { ice_debug(hw, ICE_DBG_NVM, "%s: New upper bound of %u bytes\n", __func__, offset); status = 0; @@ -1182,14 +1182,14 @@ int ice_init_nvm(struct ice_hw *hw) int ice_nvm_validate_checksum(struct ice_hw *hw) { struct ice_aqc_nvm_checksum *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; status = ice_acquire_nvm(hw, ICE_RES_READ); if (status) return status; - cmd = &desc.params.nvm_checksum; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum); cmd->flags = ICE_AQC_NVM_CHECKSUM_VERIFY; @@ -1226,11 +1226,11 @@ int ice_nvm_validate_checksum(struct ice_hw *hw) */ int ice_nvm_write_activate(struct ice_hw *hw, u16 cmd_flags, u8 *response_flags) { + struct libie_aq_desc desc; struct ice_aqc_nvm *cmd; - struct ice_aq_desc desc; int err; - cmd = &desc.params.nvm; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate); cmd->cmd_flags = (u8)(cmd_flags & 0xFF); @@ -1252,7 +1252,7 @@ int ice_nvm_write_activate(struct ice_hw *hw, u16 cmd_flags, u8 *response_flags) */ int ice_aq_nvm_update_empr(struct ice_hw *hw) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_update_empr); @@ -1278,15 +1278,15 @@ ice_nvm_set_pkg_data(struct ice_hw *hw, bool del_pkg_data_flag, u8 *data, u16 length, struct ice_sq_cd *cd) { struct ice_aqc_nvm_pkg_data *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (length != 0 && !data) return -EINVAL; - cmd = &desc.params.pkg_data; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_pkg_data); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); if (del_pkg_data_flag) cmd->cmd_flags |= ICE_AQC_NVM_PKG_DELETE; @@ -1316,17 +1316,17 @@ ice_nvm_pass_component_tbl(struct ice_hw *hw, u8 *data, u16 length, u8 *comp_response_code, struct ice_sq_cd *cd) { struct ice_aqc_nvm_pass_comp_tbl *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; if (!data || !comp_response || !comp_response_code) return -EINVAL; - cmd = &desc.params.pass_comp_tbl; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_pass_component_tbl); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->transfer_flag = transfer_flag; status = ice_aq_send_cmd(hw, &desc, data, length, cd); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 55cad824c5b9..fb0f6365a6d6 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -4,7 +4,6 @@ #include "ice.h" #include "ice_lib.h" #include "ice_trace.h" -#include "ice_cgu_regs.h" static const char ice_pin_names[][64] = { "SDP0", @@ -40,21 +39,19 @@ static const struct ice_ptp_pin_desc ice_pin_desc_e810[] = { { ONE_PPS, { -1, 5 }, { 0, 1 }}, }; -static const char ice_pin_names_nvm[][64] = { - "GNSS", - "SMA1", - "U.FL1", - "SMA2", - "U.FL2", +static const char ice_pin_names_dpll[][64] = { + "SDP20", + "SDP21", + "SDP22", + "SDP23", }; -static const struct ice_ptp_pin_desc ice_pin_desc_e810_sma[] = { +static const struct ice_ptp_pin_desc ice_pin_desc_dpll[] = { /* name, gpio, delay */ - { GNSS, { 1, -1 }, { 0, 0 }}, - { SMA1, { 1, 0 }, { 0, 1 }}, - { UFL1, { -1, 0 }, { 0, 1 }}, - { SMA2, { 3, 2 }, { 0, 1 }}, - { UFL2, { 3, -1 }, { 0, 0 }}, + { SDP0, { -1, 0 }, { 0, 1 }}, + { SDP1, { 1, -1 }, { 0, 0 }}, + { SDP2, { -1, 2 }, { 0, 1 }}, + { SDP3, { 3, -1 }, { 0, 0 }}, }; static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) @@ -93,101 +90,6 @@ static int ice_ptp_find_pin_idx(struct ice_pf *pf, enum ptp_pin_function func, } /** - * ice_ptp_update_sma_data - update SMA pins data according to pins setup - * @pf: Board private structure - * @sma_pins: parsed SMA pins status - * @data: SMA data to update - */ -static void ice_ptp_update_sma_data(struct ice_pf *pf, unsigned int sma_pins[], - u8 *data) -{ - const char *state1, *state2; - - /* Set the right state based on the desired configuration. - * When bit is set, functionality is disabled. - */ - *data &= ~ICE_ALL_SMA_MASK; - if (!sma_pins[UFL1 - 1]) { - if (sma_pins[SMA1 - 1] == PTP_PF_EXTTS) { - state1 = "SMA1 Rx, U.FL1 disabled"; - *data |= ICE_SMA1_TX_EN; - } else if (sma_pins[SMA1 - 1] == PTP_PF_PEROUT) { - state1 = "SMA1 Tx U.FL1 disabled"; - *data |= ICE_SMA1_DIR_EN; - } else { - state1 = "SMA1 disabled, U.FL1 disabled"; - *data |= ICE_SMA1_MASK; - } - } else { - /* U.FL1 Tx will always enable SMA1 Rx */ - state1 = "SMA1 Rx, U.FL1 Tx"; - } - - if (!sma_pins[UFL2 - 1]) { - if (sma_pins[SMA2 - 1] == PTP_PF_EXTTS) { - state2 = "SMA2 Rx, U.FL2 disabled"; - *data |= ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; - } else if (sma_pins[SMA2 - 1] == PTP_PF_PEROUT) { - state2 = "SMA2 Tx, U.FL2 disabled"; - *data |= ICE_SMA2_DIR_EN | ICE_SMA2_UFL2_RX_DIS; - } else { - state2 = "SMA2 disabled, U.FL2 disabled"; - *data |= ICE_SMA2_MASK; - } - } else { - if (!sma_pins[SMA2 - 1]) { - state2 = "SMA2 disabled, U.FL2 Rx"; - *data |= ICE_SMA2_DIR_EN | ICE_SMA2_TX_EN; - } else { - state2 = "SMA2 Tx, U.FL2 Rx"; - *data |= ICE_SMA2_DIR_EN; - } - } - - dev_dbg(ice_pf_to_dev(pf), "%s, %s\n", state1, state2); -} - -/** - * ice_ptp_set_sma_cfg - set the configuration of the SMA control logic - * @pf: Board private structure - * - * Return: 0 on success, negative error code otherwise - */ -static int ice_ptp_set_sma_cfg(struct ice_pf *pf) -{ - const struct ice_ptp_pin_desc *ice_pins = pf->ptp.ice_pin_desc; - struct ptp_pin_desc *pins = pf->ptp.pin_desc; - unsigned int sma_pins[ICE_SMA_PINS_NUM] = {}; - int err; - u8 data; - - /* Read initial pin state value */ - err = ice_read_sma_ctrl(&pf->hw, &data); - if (err) - return err; - - /* Get SMA/U.FL pins states */ - for (int i = 0; i < pf->ptp.info.n_pins; i++) - if (pins[i].func) { - int name_idx = ice_pins[i].name_idx; - - switch (name_idx) { - case SMA1: - case UFL1: - case SMA2: - case UFL2: - sma_pins[name_idx - 1] = pins[i].func; - break; - default: - continue; - } - } - - ice_ptp_update_sma_data(pf, sma_pins, &data); - return ice_write_sma_ctrl(&pf->hw, data); -} - -/** * ice_ptp_cfg_tx_interrupt - Configure Tx timestamp interrupt for the device * @pf: Board private structure * @@ -1734,7 +1636,7 @@ static int ice_ptp_write_perout(struct ice_hw *hw, unsigned int chan, int err; /* Enable/disable CGU 1PPS output for E825C */ - err = ice_cgu_cfg_pps_out(hw, !!period); + err = ice_tspll_cfg_pps_out_e825c(hw, !!period); if (err) return err; } @@ -1879,63 +1781,6 @@ static void ice_ptp_enable_all_perout(struct ice_pf *pf) } /** - * ice_ptp_disable_shared_pin - Disable enabled pin that shares GPIO - * @pf: Board private structure - * @pin: Pin index - * @func: Assigned function - * - * Return: 0 on success, negative error code otherwise - */ -static int ice_ptp_disable_shared_pin(struct ice_pf *pf, unsigned int pin, - enum ptp_pin_function func) -{ - unsigned int gpio_pin; - - switch (func) { - case PTP_PF_PEROUT: - gpio_pin = pf->ptp.ice_pin_desc[pin].gpio[1]; - break; - case PTP_PF_EXTTS: - gpio_pin = pf->ptp.ice_pin_desc[pin].gpio[0]; - break; - default: - return -EOPNOTSUPP; - } - - for (unsigned int i = 0; i < pf->ptp.info.n_pins; i++) { - struct ptp_pin_desc *pin_desc = &pf->ptp.pin_desc[i]; - unsigned int chan = pin_desc->chan; - - /* Skip pin idx from the request */ - if (i == pin) - continue; - - if (pin_desc->func == PTP_PF_PEROUT && - pf->ptp.ice_pin_desc[i].gpio[1] == gpio_pin) { - pf->ptp.perout_rqs[chan].period.sec = 0; - pf->ptp.perout_rqs[chan].period.nsec = 0; - pin_desc->func = PTP_PF_NONE; - pin_desc->chan = 0; - dev_dbg(ice_pf_to_dev(pf), "Disabling pin %u with shared output GPIO pin %u\n", - i, gpio_pin); - return ice_ptp_cfg_perout(pf, &pf->ptp.perout_rqs[chan], - false); - } else if (pf->ptp.pin_desc->func == PTP_PF_EXTTS && - pf->ptp.ice_pin_desc[i].gpio[0] == gpio_pin) { - pf->ptp.extts_rqs[chan].flags &= ~PTP_ENABLE_FEATURE; - pin_desc->func = PTP_PF_NONE; - pin_desc->chan = 0; - dev_dbg(ice_pf_to_dev(pf), "Disabling pin %u with shared input GPIO pin %u\n", - i, gpio_pin); - return ice_ptp_cfg_extts(pf, &pf->ptp.extts_rqs[chan], - false); - } - } - - return 0; -} - -/** * ice_verify_pin - verify if pin supports requested pin function * @info: the driver's PTP info structure * @pin: Pin index @@ -1969,14 +1814,6 @@ static int ice_verify_pin(struct ptp_clock_info *info, unsigned int pin, return -EOPNOTSUPP; } - /* On adapters with SMA_CTRL disable other pins that share same GPIO */ - if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) { - ice_ptp_disable_shared_pin(pf, pin, func); - pf->ptp.pin_desc[pin].func = func; - pf->ptp.pin_desc[pin].chan = chan; - return ice_ptp_set_sma_cfg(pf); - } - return 0; } @@ -2360,23 +2197,24 @@ static int ice_ptp_getcrosststamp(struct ptp_clock_info *info, } /** - * ice_ptp_get_ts_config - ioctl interface to read the timestamping config - * @pf: Board private structure - * @ifr: ioctl data + * ice_ptp_hwtstamp_get - interface to read the timestamping config + * @netdev: Pointer to network interface device structure + * @config: Timestamping configuration structure * * Copy the timestamping config to user buffer */ -int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) +int ice_ptp_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config) { - struct hwtstamp_config *config; + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; if (pf->ptp.state != ICE_PTP_READY) return -EIO; - config = &pf->ptp.tstamp_config; + *config = pf->ptp.tstamp_config; - return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? - -EFAULT : 0; + return 0; } /** @@ -2384,8 +2222,8 @@ int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) * @pf: Board private structure * @config: hwtstamp settings requested or saved */ -static int -ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config) +static int ice_ptp_set_timestamp_mode(struct ice_pf *pf, + struct kernel_hwtstamp_config *config) { switch (config->tx_type) { case HWTSTAMP_TX_OFF: @@ -2429,32 +2267,32 @@ ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config) } /** - * ice_ptp_set_ts_config - ioctl interface to control the timestamping - * @pf: Board private structure - * @ifr: ioctl data + * ice_ptp_hwtstamp_set - interface to control the timestamping + * @netdev: Pointer to network interface device structure + * @config: Timestamping configuration structure + * @extack: Netlink extended ack structure for error reporting * * Get the user config and store it */ -int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) +int ice_ptp_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { - struct hwtstamp_config config; + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; int err; if (pf->ptp.state != ICE_PTP_READY) return -EAGAIN; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; - - err = ice_ptp_set_timestamp_mode(pf, &config); + err = ice_ptp_set_timestamp_mode(pf, config); if (err) return err; /* Return the actual configuration set */ - config = pf->ptp.tstamp_config; + *config = pf->ptp.tstamp_config; - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? - -EFAULT : 0; + return 0; } /** @@ -2500,14 +2338,14 @@ static void ice_ptp_setup_pin_cfg(struct ice_pf *pf) for (unsigned int i = 0; i < pf->ptp.info.n_pins; i++) { const struct ice_ptp_pin_desc *desc = &pf->ptp.ice_pin_desc[i]; struct ptp_pin_desc *pin = &pf->ptp.pin_desc[i]; - const char *name = NULL; + const char *name; if (!ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) name = ice_pin_names[desc->name_idx]; - else if (desc->name_idx != GPIO_NA) - name = ice_pin_names_nvm[desc->name_idx]; - if (name) - strscpy(pin->name, name, sizeof(pin->name)); + else + name = ice_pin_names_dpll[desc->name_idx]; + + strscpy(pin->name, name, sizeof(pin->name)); pin->index = i; } @@ -2519,8 +2357,8 @@ static void ice_ptp_setup_pin_cfg(struct ice_pf *pf) * ice_ptp_disable_pins - Disable PTP pins * @pf: pointer to the PF structure * - * Disable the OS access to the SMA pins. Called to clear out the OS - * indications of pin support when we fail to setup the SMA control register. + * Disable the OS access to the pins. Called to clear out the OS + * indications of pin support when we fail to setup pin array. */ static void ice_ptp_disable_pins(struct ice_pf *pf) { @@ -2561,40 +2399,30 @@ static int ice_ptp_parse_sdp_entries(struct ice_pf *pf, __le16 *entries, for (i = 0; i < num_entries; i++) { u16 entry = le16_to_cpu(entries[i]); DECLARE_BITMAP(bitmap, GPIO_NA); - unsigned int bitmap_idx; + unsigned int idx; bool dir; u16 gpio; *bitmap = FIELD_GET(ICE_AQC_NVM_SDP_AC_PIN_M, entry); + + /* Check if entry's pin bitmap is valid. */ + if (bitmap_empty(bitmap, GPIO_NA)) + continue; + dir = !!FIELD_GET(ICE_AQC_NVM_SDP_AC_DIR_M, entry); gpio = FIELD_GET(ICE_AQC_NVM_SDP_AC_SDP_NUM_M, entry); - for_each_set_bit(bitmap_idx, bitmap, GPIO_NA + 1) { - unsigned int idx; - - /* Check if entry's pin bit is valid */ - if (bitmap_idx >= NUM_PTP_PINS_NVM && - bitmap_idx != GPIO_NA) - continue; - /* Check if pin already exists */ - for (idx = 0; idx < ICE_N_PINS_MAX; idx++) - if (pins[idx].name_idx == bitmap_idx) - break; - - if (idx == ICE_N_PINS_MAX) { - /* Pin not found, setup its entry and name */ - idx = n_pins++; - pins[idx].name_idx = bitmap_idx; - if (bitmap_idx == GPIO_NA) - strscpy(pf->ptp.pin_desc[idx].name, - ice_pin_names[gpio], - sizeof(pf->ptp.pin_desc[idx] - .name)); - } + for (idx = 0; idx < ICE_N_PINS_MAX; idx++) { + if (pins[idx].name_idx == gpio) + break; + } - /* Setup in/out GPIO number */ - pins[idx].gpio[dir] = gpio; + if (idx == ICE_N_PINS_MAX) { + /* Pin not found, setup its entry and name */ + idx = n_pins++; + pins[idx].name_idx = gpio; } + pins[idx].gpio[dir] = gpio; } for (i = 0; i < n_pins; i++) { @@ -2622,10 +2450,10 @@ static void ice_ptp_set_funcs_e82x(struct ice_pf *pf) if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) { pf->ptp.ice_pin_desc = ice_pin_desc_e825c; - pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e825c); + pf->ptp.info.n_pins = ARRAY_SIZE(ice_pin_desc_e825c); } else { pf->ptp.ice_pin_desc = ice_pin_desc_e82x; - pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e82x); + pf->ptp.info.n_pins = ARRAY_SIZE(ice_pin_desc_e82x); } ice_ptp_setup_pin_cfg(pf); } @@ -2651,15 +2479,13 @@ static void ice_ptp_set_funcs_e810(struct ice_pf *pf) if (err) { /* SDP section does not exist in NVM or is corrupted */ if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) { - ptp->ice_pin_desc = ice_pin_desc_e810_sma; - ptp->info.n_pins = - ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e810_sma); + ptp->ice_pin_desc = ice_pin_desc_dpll; + ptp->info.n_pins = ARRAY_SIZE(ice_pin_desc_dpll); } else { pf->ptp.ice_pin_desc = ice_pin_desc_e810; - pf->ptp.info.n_pins = - ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e810); - err = 0; + pf->ptp.info.n_pins = ARRAY_SIZE(ice_pin_desc_e810); } + err = 0; } else { desc = devm_kcalloc(ice_pf_to_dev(pf), ICE_N_PINS_MAX, sizeof(struct ice_ptp_pin_desc), @@ -2677,8 +2503,6 @@ static void ice_ptp_set_funcs_e810(struct ice_pf *pf) ptp->info.pin_config = ptp->pin_desc; ice_ptp_setup_pin_cfg(pf); - if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) - err = ice_ptp_set_sma_cfg(pf); err: if (err) { devm_kfree(ice_pf_to_dev(pf), desc); @@ -2704,7 +2528,7 @@ static void ice_ptp_set_funcs_e830(struct ice_pf *pf) #endif /* CONFIG_ICE_HWTS */ /* Rest of the config is the same as base E810 */ pf->ptp.ice_pin_desc = ice_pin_desc_e810; - pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e810); + pf->ptp.info.n_pins = ARRAY_SIZE(ice_pin_desc_e810); ice_ptp_setup_pin_cfg(pf); } @@ -2877,16 +2701,19 @@ irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf) */ if (hw->dev_caps.ts_dev_info.ts_ll_int_read) { struct ice_ptp_tx *tx = &pf->ptp.port.tx; - u8 idx; + u8 idx, last; if (!ice_pf_state_is_nominal(pf)) return IRQ_HANDLED; spin_lock(&tx->lock); - idx = find_next_bit_wrap(tx->in_use, tx->len, - tx->last_ll_ts_idx_read + 1); - if (idx != tx->len) - ice_ptp_req_tx_single_tstamp(tx, idx); + if (tx->init) { + last = tx->last_ll_ts_idx_read + 1; + idx = find_next_bit_wrap(tx->in_use, tx->len, + last); + if (idx != tx->len) + ice_ptp_req_tx_single_tstamp(tx, idx); + } spin_unlock(&tx->lock); return IRQ_HANDLED; @@ -3069,6 +2896,10 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) if (err) return err; + err = ice_tspll_init(hw); + if (err) + return err; + /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; @@ -3236,6 +3067,13 @@ static int ice_ptp_init_owner(struct ice_pf *pf) return err; } + err = ice_tspll_init(hw); + if (err) { + dev_err(ice_pf_to_dev(pf), "Failed to initialize CGU, status %d\n", + err); + return err; + } + /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 3b769a0cad00..137f2070a2d9 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -202,9 +202,6 @@ enum ice_ptp_pin_nvm { /* Pin definitions for PTP */ #define ICE_N_PINS_MAX 6 -#define ICE_SMA_PINS_NUM 4 -#define ICE_PIN_DESC_ARR_LEN(_arr) (sizeof(_arr) / \ - sizeof(struct ice_ptp_pin_desc)) /** * struct ice_ptp_pin_desc - hardware pin description data @@ -262,7 +259,7 @@ struct ice_ptp { struct ptp_extts_request extts_rqs[GLTSYN_EVNT_H_IDX_MAX]; struct ptp_clock_info info; struct ptp_clock *clock; - struct hwtstamp_config tstamp_config; + struct kernel_hwtstamp_config tstamp_config; u64 reset_time; u32 tx_hwtstamp_skipped; u32 tx_hwtstamp_timeouts; @@ -294,8 +291,11 @@ struct ice_ptp { #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) int ice_ptp_clock_index(struct ice_pf *pf); struct ice_pf; -int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr); -int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr); +int ice_ptp_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config); +int ice_ptp_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); void ice_ptp_restore_timestamp_mode(struct ice_pf *pf); void ice_ptp_extts_event(struct ice_pf *pf); @@ -316,12 +316,16 @@ 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); #else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ -static inline int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) + +static inline int ice_ptp_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config) { return -EOPNOTSUPP; } -static inline int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) +static inline int ice_ptp_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h index 003cdfada3ca..19dddd9b53dd 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h @@ -281,7 +281,7 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { /* struct ice_time_ref_info_e82x * - * E822 hardware can use different sources as the reference for the PTP + * E82X hardware can use different sources as the reference for the PTP * hardware clock. Each clock has different characteristics such as a slightly * different frequency, etc. * @@ -289,8 +289,8 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { * reference. See the struct ice_time_ref_info_e82x for information about the * meaning of each constant. */ -const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { - /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ +const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TSPLL_FREQ] = { + /* ICE_TSPLL_FREQ_25_000 -> 25 MHz */ { /* pll_freq */ 823437500, /* 823.4375 MHz PLL */ @@ -298,7 +298,7 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { 0x136e44fabULL, }, - /* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */ + /* ICE_TSPLL_FREQ_122_880 -> 122.88 MHz */ { /* pll_freq */ 783360000, /* 783.36 MHz */ @@ -306,7 +306,7 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { 0x146cc2177ULL, }, - /* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */ + /* ICE_TSPLL_FREQ_125_000 -> 125 MHz */ { /* pll_freq */ 796875000, /* 796.875 MHz */ @@ -314,7 +314,7 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { 0x141414141ULL, }, - /* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */ + /* ICE_TSPLL_FREQ_153_600 -> 153.6 MHz */ { /* pll_freq */ 816000000, /* 816 MHz */ @@ -322,7 +322,7 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { 0x139b9b9baULL, }, - /* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */ + /* ICE_TSPLL_FREQ_156_250 -> 156.25 MHz */ { /* pll_freq */ 830078125, /* 830.78125 MHz */ @@ -330,7 +330,7 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { 0x134679aceULL, }, - /* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */ + /* ICE_TSPLL_FREQ_245_760 -> 245.76 MHz */ { /* pll_freq */ 783360000, /* 783.36 MHz */ @@ -339,167 +339,6 @@ const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { }, }; -const struct ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = { - /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ - { - /* refclk_pre_div */ - 1, - /* feedback_div */ - 197, - /* frac_n_div */ - 2621440, - /* post_pll_div */ - 6, - }, - - /* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */ - { - /* refclk_pre_div */ - 5, - /* feedback_div */ - 223, - /* frac_n_div */ - 524288, - /* post_pll_div */ - 7, - }, - - /* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */ - { - /* refclk_pre_div */ - 5, - /* feedback_div */ - 223, - /* frac_n_div */ - 524288, - /* post_pll_div */ - 7, - }, - - /* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */ - { - /* refclk_pre_div */ - 5, - /* feedback_div */ - 159, - /* frac_n_div */ - 1572864, - /* post_pll_div */ - 6, - }, - - /* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */ - { - /* refclk_pre_div */ - 5, - /* feedback_div */ - 159, - /* frac_n_div */ - 1572864, - /* post_pll_div */ - 6, - }, - - /* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */ - { - /* refclk_pre_div */ - 10, - /* feedback_div */ - 223, - /* frac_n_div */ - 524288, - /* post_pll_div */ - 7, - }, -}; - -const -struct ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ] = { - /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x19, - /* tspll_ndivratio */ - 1, - /* tspll_fbdiv_intgr */ - 320, - /* tspll_fbdiv_frac */ - 0, - /* ref1588_ck_div */ - 0, - }, - - /* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x29, - /* tspll_ndivratio */ - 3, - /* tspll_fbdiv_intgr */ - 195, - /* tspll_fbdiv_frac */ - 1342177280UL, - /* ref1588_ck_div */ - 0, - }, - - /* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x3E, - /* tspll_ndivratio */ - 2, - /* tspll_fbdiv_intgr */ - 128, - /* tspll_fbdiv_frac */ - 0, - /* ref1588_ck_div */ - 0, - }, - - /* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x33, - /* tspll_ndivratio */ - 3, - /* tspll_fbdiv_intgr */ - 156, - /* tspll_fbdiv_frac */ - 1073741824UL, - /* ref1588_ck_div */ - 0, - }, - - /* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x1F, - /* tspll_ndivratio */ - 5, - /* tspll_fbdiv_intgr */ - 256, - /* tspll_fbdiv_frac */ - 0, - /* ref1588_ck_div */ - 0, - }, - - /* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */ - { - /* tspll_ck_refclkfreq */ - 0x52, - /* tspll_ndivratio */ - 3, - /* tspll_fbdiv_intgr */ - 97, - /* tspll_fbdiv_frac */ - 2818572288UL, - /* ref1588_ck_div */ - 0, - }, -}; - /* struct ice_vernier_info_e82x * * E822 hardware calibrates the delay of the timestamp indication from the diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index ccac84eb34c9..35680dbe4a7f 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -6,7 +6,6 @@ #include "ice_common.h" #include "ice_ptp_hw.h" #include "ice_ptp_consts.h" -#include "ice_cgu_regs.h" static struct dpll_pin_frequency ice_cgu_pin_freq_common[] = { DPLL_PIN_FREQUENCY_1PPS, @@ -150,7 +149,7 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { * | 8 bit s | | 32 bits | * +---------------+ +---------------+ * - * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L + * The increment value is added to the GLTSYN_TIME_R and GLTSYN_TIME_L * registers every clock source tick. Depending on the specific device * configuration, the clock source frequency could be one of a number of * values. @@ -226,547 +225,6 @@ static u64 ice_ptp_read_src_incval(struct ice_hw *hw) } /** - * ice_read_cgu_reg_e82x - Read a CGU register - * @hw: pointer to the HW struct - * @addr: Register address to read - * @val: storage for register value read - * - * Read the contents of a register of the Clock Generation Unit. Only - * applicable to E822 devices. - * - * Return: 0 on success, other error codes when failed to read from CGU - */ -static int ice_read_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 *val) -{ - struct ice_sbq_msg_input cgu_msg = { - .opcode = ice_sbq_msg_rd, - .dest_dev = ice_sbq_dev_cgu, - .msg_addr_low = addr - }; - int err; - - err = ice_sbq_rw_reg(hw, &cgu_msg, ICE_AQ_FLAG_RD); - if (err) { - ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", - addr, err); - return err; - } - - *val = cgu_msg.data; - - return 0; -} - -/** - * ice_write_cgu_reg_e82x - Write a CGU register - * @hw: pointer to the HW struct - * @addr: Register address to write - * @val: value to write into the register - * - * Write the specified value to a register of the Clock Generation Unit. Only - * applicable to E822 devices. - * - * Return: 0 on success, other error codes when failed to write to CGU - */ -static int ice_write_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 val) -{ - struct ice_sbq_msg_input cgu_msg = { - .opcode = ice_sbq_msg_wr, - .dest_dev = ice_sbq_dev_cgu, - .msg_addr_low = addr, - .data = val - }; - int err; - - err = ice_sbq_rw_reg(hw, &cgu_msg, ICE_AQ_FLAG_RD); - if (err) { - ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", - addr, err); - return err; - } - - return err; -} - -/** - * ice_clk_freq_str - Convert time_ref_freq to string - * @clk_freq: Clock frequency - * - * Return: specified TIME_REF clock frequency converted to a string - */ -static const char *ice_clk_freq_str(enum ice_time_ref_freq clk_freq) -{ - switch (clk_freq) { - case ICE_TIME_REF_FREQ_25_000: - return "25 MHz"; - case ICE_TIME_REF_FREQ_122_880: - return "122.88 MHz"; - case ICE_TIME_REF_FREQ_125_000: - return "125 MHz"; - case ICE_TIME_REF_FREQ_153_600: - return "153.6 MHz"; - case ICE_TIME_REF_FREQ_156_250: - return "156.25 MHz"; - case ICE_TIME_REF_FREQ_245_760: - return "245.76 MHz"; - default: - return "Unknown"; - } -} - -/** - * ice_clk_src_str - Convert time_ref_src to string - * @clk_src: Clock source - * - * Return: specified clock source converted to its string name - */ -static const char *ice_clk_src_str(enum ice_clk_src clk_src) -{ - switch (clk_src) { - case ICE_CLK_SRC_TCXO: - return "TCXO"; - case ICE_CLK_SRC_TIME_REF: - return "TIME_REF"; - default: - return "Unknown"; - } -} - -/** - * ice_cfg_cgu_pll_e82x - Configure the Clock Generation Unit - * @hw: pointer to the HW struct - * @clk_freq: Clock frequency to program - * @clk_src: Clock source to select (TIME_REF, or TCXO) - * - * Configure the Clock Generation Unit with the desired clock frequency and - * time reference, enabling the PLL which drives the PTP hardware clock. - * - * Return: - * * %0 - success - * * %-EINVAL - input parameters are incorrect - * * %-EBUSY - failed to lock TS PLL - * * %other - CGU read/write failure - */ -static int ice_cfg_cgu_pll_e82x(struct ice_hw *hw, - enum ice_time_ref_freq clk_freq, - enum ice_clk_src clk_src) -{ - union tspll_ro_bwm_lf bwm_lf; - union nac_cgu_dword19 dw19; - union nac_cgu_dword22 dw22; - union nac_cgu_dword24 dw24; - union nac_cgu_dword9 dw9; - int err; - - if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { - dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", - clk_freq); - return -EINVAL; - } - - if (clk_src >= NUM_ICE_CLK_SRC) { - dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", - clk_src); - return -EINVAL; - } - - if (clk_src == ICE_CLK_SRC_TCXO && - clk_freq != ICE_TIME_REF_FREQ_25_000) { - dev_warn(ice_hw_to_dev(hw), - "TCXO only supports 25 MHz frequency\n"); - return -EINVAL; - } - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); - if (err) - return err; - - /* Log the current clock configuration */ - ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", - str_enabled_disabled(dw24.ts_pll_enable), - ice_clk_src_str(dw24.time_ref_sel), - ice_clk_freq_str(dw9.time_ref_freq_sel), - bwm_lf.plllock_true_lock_cri ? "locked" : "unlocked"); - - /* Disable the PLL before changing the clock source or frequency */ - if (dw24.ts_pll_enable) { - dw24.ts_pll_enable = 0; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); - if (err) - return err; - } - - /* Set the frequency */ - dw9.time_ref_freq_sel = clk_freq; - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); - if (err) - return err; - - /* Configure the TS PLL feedback divisor */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val); - if (err) - return err; - - dw19.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; - dw19.tspll_ndivratio = 1; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val); - if (err) - return err; - - /* Configure the TS PLL post divisor */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val); - if (err) - return err; - - dw22.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; - dw22.time1588clk_sel_div2 = 0; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val); - if (err) - return err; - - /* Configure the TS PLL pre divisor and clock source */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); - if (err) - return err; - - dw24.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div; - dw24.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; - dw24.time_ref_sel = clk_src; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); - if (err) - return err; - - /* Finally, enable the PLL */ - dw24.ts_pll_enable = 1; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); - if (err) - return err; - - /* Wait to verify if the PLL locks */ - usleep_range(1000, 5000); - - err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); - if (err) - return err; - - if (!bwm_lf.plllock_true_lock_cri) { - dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); - return -EBUSY; - } - - /* Log the current clock configuration */ - ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", - str_enabled_disabled(dw24.ts_pll_enable), - ice_clk_src_str(dw24.time_ref_sel), - ice_clk_freq_str(dw9.time_ref_freq_sel), - bwm_lf.plllock_true_lock_cri ? "locked" : "unlocked"); - - return 0; -} - -/** - * ice_cfg_cgu_pll_e825c - Configure the Clock Generation Unit for E825-C - * @hw: pointer to the HW struct - * @clk_freq: Clock frequency to program - * @clk_src: Clock source to select (TIME_REF, or TCXO) - * - * Configure the Clock Generation Unit with the desired clock frequency and - * time reference, enabling the PLL which drives the PTP hardware clock. - * - * Return: - * * %0 - success - * * %-EINVAL - input parameters are incorrect - * * %-EBUSY - failed to lock TS PLL - * * %other - CGU read/write failure - */ -static int ice_cfg_cgu_pll_e825c(struct ice_hw *hw, - enum ice_time_ref_freq clk_freq, - enum ice_clk_src clk_src) -{ - union tspll_ro_lock_e825c ro_lock; - union nac_cgu_dword16_e825c dw16; - union nac_cgu_dword23_e825c dw23; - union nac_cgu_dword19 dw19; - union nac_cgu_dword22 dw22; - union nac_cgu_dword24 dw24; - union nac_cgu_dword9 dw9; - int err; - - if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { - dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", - clk_freq); - return -EINVAL; - } - - if (clk_src >= NUM_ICE_CLK_SRC) { - dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", - clk_src); - return -EINVAL; - } - - if (clk_src == ICE_CLK_SRC_TCXO && - clk_freq != ICE_TIME_REF_FREQ_156_250) { - dev_warn(ice_hw_to_dev(hw), - "TCXO only supports 156.25 MHz frequency\n"); - return -EINVAL; - } - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD16_E825C, &dw16.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val); - if (err) - return err; - - err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); - if (err) - return err; - - /* Log the current clock configuration */ - ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", - str_enabled_disabled(dw24.ts_pll_enable), - ice_clk_src_str(dw23.time_ref_sel), - ice_clk_freq_str(dw9.time_ref_freq_sel), - ro_lock.plllock_true_lock_cri ? "locked" : "unlocked"); - - /* Disable the PLL before changing the clock source or frequency */ - if (dw23.ts_pll_enable) { - dw23.ts_pll_enable = 0; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, - dw23.val); - if (err) - return err; - } - - /* Set the frequency */ - dw9.time_ref_freq_sel = clk_freq; - - /* Enable the correct receiver */ - if (clk_src == ICE_CLK_SRC_TCXO) { - dw9.time_ref_en = 0; - dw9.clk_eref0_en = 1; - } else { - dw9.time_ref_en = 1; - dw9.clk_eref0_en = 0; - } - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); - if (err) - return err; - - /* Choose the referenced frequency */ - dw16.tspll_ck_refclkfreq = - e825c_cgu_params[clk_freq].tspll_ck_refclkfreq; - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD16_E825C, dw16.val); - if (err) - return err; - - /* Configure the TS PLL feedback divisor */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val); - if (err) - return err; - - dw19.tspll_fbdiv_intgr = - e825c_cgu_params[clk_freq].tspll_fbdiv_intgr; - dw19.tspll_ndivratio = - e825c_cgu_params[clk_freq].tspll_ndivratio; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val); - if (err) - return err; - - /* Configure the TS PLL post divisor */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val); - if (err) - return err; - - /* These two are constant for E825C */ - dw22.time1588clk_div = 5; - dw22.time1588clk_sel_div2 = 0; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val); - if (err) - return err; - - /* Configure the TS PLL pre divisor and clock source */ - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val); - if (err) - return err; - - dw23.ref1588_ck_div = - e825c_cgu_params[clk_freq].ref1588_ck_div; - dw23.time_ref_sel = clk_src; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); - if (err) - return err; - - dw24.tspll_fbdiv_frac = - e825c_cgu_params[clk_freq].tspll_fbdiv_frac; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); - if (err) - return err; - - /* Finally, enable the PLL */ - dw23.ts_pll_enable = 1; - - err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); - if (err) - return err; - - /* Wait to verify if the PLL locks */ - usleep_range(1000, 5000); - - err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); - if (err) - return err; - - if (!ro_lock.plllock_true_lock_cri) { - dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); - return -EBUSY; - } - - /* Log the current clock configuration */ - ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", - str_enabled_disabled(dw24.ts_pll_enable), - ice_clk_src_str(dw23.time_ref_sel), - ice_clk_freq_str(dw9.time_ref_freq_sel), - ro_lock.plllock_true_lock_cri ? "locked" : "unlocked"); - - return 0; -} - -#define ICE_ONE_PPS_OUT_AMP_MAX 3 - -/** - * ice_cgu_cfg_pps_out - Configure 1PPS output from CGU - * @hw: pointer to the HW struct - * @enable: true to enable 1PPS output, false to disable it - * - * Return: 0 on success, other negative error code when CGU read/write failed - */ -int ice_cgu_cfg_pps_out(struct ice_hw *hw, bool enable) -{ - union nac_cgu_dword9 dw9; - int err; - - err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); - if (err) - return err; - - dw9.one_pps_out_en = enable; - dw9.one_pps_out_amp = enable * ICE_ONE_PPS_OUT_AMP_MAX; - return ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); -} - -/** - * ice_cfg_cgu_pll_dis_sticky_bits_e82x - disable TS PLL sticky bits - * @hw: pointer to the HW struct - * - * Configure the Clock Generation Unit TS PLL sticky bits so they don't latch on - * losing TS PLL lock, but always show current state. - * - * Return: 0 on success, other error codes when failed to read/write CGU - */ -static int ice_cfg_cgu_pll_dis_sticky_bits_e82x(struct ice_hw *hw) -{ - union tspll_cntr_bist_settings cntr_bist; - int err; - - err = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, - &cntr_bist.val); - if (err) - return err; - - /* Disable sticky lock detection so lock err reported is accurate */ - cntr_bist.i_plllock_sel_0 = 0; - cntr_bist.i_plllock_sel_1 = 0; - - return ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, - cntr_bist.val); -} - -/** - * ice_cfg_cgu_pll_dis_sticky_bits_e825c - disable TS PLL sticky bits for E825-C - * @hw: pointer to the HW struct - * - * Configure the Clock Generation Unit TS PLL sticky bits so they don't latch on - * losing TS PLL lock, but always show current state. - * - * Return: 0 on success, other error codes when failed to read/write CGU - */ -static int ice_cfg_cgu_pll_dis_sticky_bits_e825c(struct ice_hw *hw) -{ - union tspll_bw_tdc_e825c bw_tdc; - int err; - - err = ice_read_cgu_reg_e82x(hw, TSPLL_BW_TDC_E825C, &bw_tdc.val); - if (err) - return err; - - bw_tdc.i_plllock_sel_1_0 = 0; - - return ice_write_cgu_reg_e82x(hw, TSPLL_BW_TDC_E825C, bw_tdc.val); -} - -/** - * ice_init_cgu_e82x - Initialize CGU with settings from firmware - * @hw: pointer to the HW structure - * - * Initialize the Clock Generation Unit of the E822 device. - * - * Return: 0 on success, other error codes when failed to read/write/cfg CGU - */ -static int ice_init_cgu_e82x(struct ice_hw *hw) -{ - struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; - int err; - - /* Disable sticky lock detection so lock err reported is accurate */ - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) - err = ice_cfg_cgu_pll_dis_sticky_bits_e825c(hw); - else - err = ice_cfg_cgu_pll_dis_sticky_bits_e82x(hw); - if (err) - return err; - - /* Configure the CGU PLL using the parameters from the function - * capabilities. - */ - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) - err = ice_cfg_cgu_pll_e825c(hw, ts_info->time_ref, - (enum ice_clk_src)ts_info->clk_src); - else - err = ice_cfg_cgu_pll_e82x(hw, ts_info->time_ref, - (enum ice_clk_src)ts_info->clk_src); - - return err; -} - -/** * ice_ptp_tmr_cmd_to_src_reg - Convert to source timer command value * @hw: pointer to HW struct * @cmd: Timer command @@ -966,7 +424,7 @@ static int ice_write_phy_eth56g(struct ice_hw *hw, u8 port, u32 addr, u32 val) }; int err; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n", err); @@ -993,7 +451,7 @@ static int ice_read_phy_eth56g(struct ice_hw *hw, u8 port, u32 addr, u32 *val) }; int err; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n", err); @@ -2658,20 +2116,6 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) } /** - * ice_ptp_init_phc_e825 - Perform E825 specific PHC initialization - * @hw: pointer to HW struct - * - * Perform E825-specific PTP hardware clock initialization steps. - * - * Return: 0 on success, negative error code otherwise. - */ -static int ice_ptp_init_phc_e825(struct ice_hw *hw) -{ - /* Initialize the Clock Generation Unit */ - return ice_init_cgu_e82x(hw); -} - -/** * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status * @hw: pointer to the HW struct * @ts_status: the timestamp mask pointer @@ -2904,7 +2348,7 @@ ice_read_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 *val) ice_fill_phy_msg_e82x(hw, &msg, port, offset); msg.opcode = ice_sbq_msg_rd; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -2982,7 +2426,7 @@ ice_write_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 val) msg.opcode = ice_sbq_msg_wr; msg.data = val; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -3143,7 +2587,7 @@ ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) msg.opcode = ice_sbq_msg_rd; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -3178,7 +2622,7 @@ ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val) msg.opcode = ice_sbq_msg_wr; msg.data = val; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -3330,7 +2774,6 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw) */ static int ice_ptp_init_phc_e82x(struct ice_hw *hw) { - int err; u32 val; /* Enable reading switch and PHY registers over the sideband queue */ @@ -3340,11 +2783,6 @@ static int ice_ptp_init_phc_e82x(struct ice_hw *hw) val |= (PF_SB_REM_DEV_CTL_SWITCH_READ | PF_SB_REM_DEV_CTL_PHY0); wr32(hw, PF_SB_REM_DEV_CTL, val); - /* Initialize the Clock Generation Unit */ - err = ice_init_cgu_e82x(hw); - if (err) - return err; - /* Set window length for all the ports */ return ice_ptp_set_vernier_wl(hw); } @@ -4829,7 +4267,7 @@ static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) msg.opcode = ice_sbq_msg_rd; msg.dest_dev = ice_sbq_dev_phy_0; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -4860,7 +4298,7 @@ static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) msg.dest_dev = ice_sbq_dev_phy_0; msg.data = val; - err = ice_sbq_rw_reg(hw, &msg, ICE_AQ_FLAG_RD); + err = ice_sbq_rw_reg(hw, &msg, LIBIE_AQ_FLAG_RD); if (err) { ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", err); @@ -6126,7 +5564,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 ice_ptp_init_phc_e825(hw); + return 0; default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 83f20fa7ace7..5896b346e579 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -194,23 +194,6 @@ struct ice_eth56g_mac_reg_cfg { extern const struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD]; -/** - * struct ice_cgu_pll_params_e82x - E82X CGU parameters - * @refclk_pre_div: Reference clock pre-divisor - * @feedback_div: Feedback divisor - * @frac_n_div: Fractional divisor - * @post_pll_div: Post PLL divisor - * - * Clock Generation Unit parameters used to program the PLL based on the - * selected TIME_REF frequency. - */ -struct ice_cgu_pll_params_e82x { - u32 refclk_pre_div; - u32 feedback_div; - u32 frac_n_div; - u32 post_pll_div; -}; - #define E810C_QSFP_C827_0_HANDLE 2 #define E810C_QSFP_C827_1_HANDLE 3 enum ice_e810_c827_idx { @@ -282,31 +265,6 @@ struct ice_cgu_pin_desc { struct dpll_pin_frequency *freq_supp; }; -extern const struct -ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ]; - -/** - * struct ice_cgu_pll_params_e825c - E825C CGU parameters - * @tspll_ck_refclkfreq: tspll_ck_refclkfreq selection - * @tspll_ndivratio: ndiv ratio that goes directly to the pll - * @tspll_fbdiv_intgr: TS PLL integer feedback divide - * @tspll_fbdiv_frac: TS PLL fractional feedback divide - * @ref1588_ck_div: clock divider for tspll ref - * - * Clock Generation Unit parameters used to program the PLL based on the - * selected TIME_REF/TCXO frequency. - */ -struct ice_cgu_pll_params_e825c { - u32 tspll_ck_refclkfreq; - u32 tspll_ndivratio; - u32 tspll_fbdiv_intgr; - u32 tspll_fbdiv_frac; - u32 ref1588_ck_div; -}; - -extern const struct -ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ]; - #define E810C_QSFP_C827_0_HANDLE 2 #define E810C_QSFP_C827_1_HANDLE 3 @@ -314,7 +272,7 @@ ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ]; extern const struct ice_phy_reg_info_eth56g eth56g_phy_res[NUM_ETH56G_PHY_RES]; /* Table of constants related to possible TIME_REF sources */ -extern const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ]; +extern const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TSPLL_FREQ]; /* Table of constants for Vernier calibration on E822 */ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; @@ -328,7 +286,6 @@ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; /* Device agnostic functions */ u8 ice_get_ptp_src_clock_index(struct ice_hw *hw); -int ice_cgu_cfg_pps_out(struct ice_hw *hw, bool enable); bool ice_ptp_lock(struct ice_hw *hw); void ice_ptp_unlock(struct ice_hw *hw); void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd); @@ -357,7 +314,8 @@ void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad); * * Returns the current TIME_REF from the capabilities structure. */ -static inline enum ice_time_ref_freq ice_e82x_time_ref(const struct ice_hw *hw) + +static inline enum ice_tspll_freq ice_e82x_time_ref(const struct ice_hw *hw) { return hw->func_caps.ts_func_info.time_ref; } @@ -371,17 +329,17 @@ static inline enum ice_time_ref_freq ice_e82x_time_ref(const struct ice_hw *hw) * change, such as an update to the CGU registers. */ static inline void -ice_set_e82x_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref) +ice_set_e82x_time_ref(struct ice_hw *hw, enum ice_tspll_freq time_ref) { hw->func_caps.ts_func_info.time_ref = time_ref; } -static inline u64 ice_e82x_pll_freq(enum ice_time_ref_freq time_ref) +static inline u64 ice_e82x_pll_freq(enum ice_tspll_freq time_ref) { return e82x_time_ref[time_ref].pll_freq; } -static inline u64 ice_e82x_nominal_incval(enum ice_time_ref_freq time_ref) +static inline u64 ice_e82x_nominal_incval(enum ice_tspll_freq time_ref) { return e82x_time_ref[time_ref].nominal_incval; } @@ -704,6 +662,7 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) #define ICE_SMA1_MASK (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN) #define ICE_SMA2_MASK (ICE_SMA2_UFL2_RX_DIS | ICE_SMA2_DIR_EN | \ ICE_SMA2_TX_EN) +#define ICE_SMA2_INACTIVE_MASK (ICE_SMA2_DIR_EN | ICE_SMA2_TX_EN) #define ICE_ALL_SMA_MASK (ICE_SMA1_MASK | ICE_SMA2_MASK) #define ICE_SMA_MIN_BIT 3 diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index d9d09296d1d4..fff0c1afdb41 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -123,13 +123,13 @@ ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc, u16 *elems_resp, struct ice_sq_cd *cd) { struct ice_aqc_sched_elem_cmd *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.sched_elem_cmd; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc); cmd->num_elem_req = cpu_to_le16(elems_req); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); if (!status && elems_resp) *elems_resp = le16_to_cpu(cmd->num_elem_resp); @@ -392,10 +392,10 @@ ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport, u8 *num_branches, struct ice_sq_cd *cd) { struct ice_aqc_get_topo *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.get_topo; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo); cmd->port_num = lport; status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); @@ -518,7 +518,7 @@ ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size, struct ice_aqc_query_txsched_res_resp *buf, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res); return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); @@ -683,13 +683,13 @@ ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode, u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd) { struct ice_aqc_rl_profile *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.rl_profile; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, opcode); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); cmd->num_profiles = cpu_to_le16(num_profiles); status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); if (!status && num_processed) diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 0e4dc1a5cff0..843e82fd3bf9 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -9,7 +9,7 @@ #include "ice_dcb_lib.h" #include "ice_flow.h" #include "ice_eswitch.h" -#include "ice_virtchnl_allowlist.h" +#include "virt/allowlist.h" #include "ice_flex_pipe.h" #include "ice_vf_vsi_vlan_ops.h" #include "ice_vlan.h" @@ -933,7 +933,6 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count) bool needs_rebuild = false; struct ice_vsi *vsi; struct ice_vf *vf; - int id; if (!ice_get_num_vfs(pf)) return -ENOENT; @@ -952,17 +951,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count) if (msix_vec_count < ICE_MIN_INTR_PER_VF) return -EINVAL; - /* Transition of PCI VF function number to function_id */ - for (id = 0; id < pci_num_vf(pdev); id++) { - if (vf_dev->devfn == pci_iov_virtfn_devfn(pdev, id)) - break; - } - - if (id == pci_num_vf(pdev)) - return -ENOENT; - - vf = ice_get_vf_by_id(pf, id); - + vf = ice_get_vf_by_dev(pf, vf_dev); if (!vf) return -ENOENT; @@ -972,6 +961,12 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count) return -ENOENT; } + /* No need to rebuild if we're setting to the same value */ + if (msix_vec_count == vf->num_msix) { + ice_put_vf(vf); + return 0; + } + prev_msix = vf->num_msix; prev_queues = vf->num_vf_qs; @@ -1166,10 +1161,12 @@ static u32 ice_globalq_to_pfq(struct ice_pf *pf, u32 globalq) void ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event) { + struct ice_aqc_event_lan_overflow *cmd; u32 gldcb_rtctq, queue; struct ice_vf *vf; - gldcb_rtctq = le32_to_cpu(event->desc.params.lan_overflow.prtdcb_ruptq); + cmd = libie_aq_raw(&event->desc); + gldcb_rtctq = le32_to_cpu(cmd->prtdcb_ruptq); dev_dbg(ice_pf_to_dev(pf), "GLDCB_RTCTQ: 0x%08x\n", gldcb_rtctq); /* event returns device global Rx queue number */ diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.h b/drivers/net/ethernet/intel/ice/ice_sriov.h index 96549ca5c52c..6c4fad09a527 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.h +++ b/drivers/net/ethernet/intel/ice/ice_sriov.h @@ -3,9 +3,9 @@ #ifndef _ICE_SRIOV_H_ #define _ICE_SRIOV_H_ -#include "ice_virtchnl_fdir.h" +#include "virt/fdir.h" #include "ice_vf_lib.h" -#include "ice_virtchnl.h" +#include "virt/virtchnl.h" /* Static VF transaction/status register def */ #define VF_DEVICE_STATUS 0xAA @@ -64,6 +64,7 @@ bool ice_vc_validate_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto); u32 ice_sriov_get_vf_total_msix(struct pci_dev *pdev); int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count); +int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id); #else /* CONFIG_PCI_IOV */ static inline void ice_process_vflr_event(struct ice_pf *pf) { } static inline void ice_free_vfs(struct ice_pf *pf) { } @@ -164,5 +165,11 @@ ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count) { return -EOPNOTSUPP; } + +static inline int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, + struct ice_vsi *vsi, u16 q_id) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_PCI_IOV */ #endif /* _ICE_SRIOV_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 9d9a7edd3618..84848f0123e7 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1511,11 +1511,11 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf, struct ice_sq_cd *cd) { struct ice_aqc_get_sw_cfg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg); - cmd = &desc.params.get_sw_conf; + cmd = libie_aq_raw(&desc); cmd->element = cpu_to_le16(*req_desc); status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); @@ -1541,11 +1541,11 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, { struct ice_aqc_add_update_free_vsi_resp *res; struct ice_aqc_add_get_update_free_vsi *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.vsi_cmd; - res = &desc.params.add_update_free_vsi_res; + cmd = libie_aq_raw(&desc); + res = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi); @@ -1556,7 +1556,7 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, sizeof(vsi_ctx->info), cd); @@ -1585,11 +1585,11 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, { struct ice_aqc_add_update_free_vsi_resp *resp; struct ice_aqc_add_get_update_free_vsi *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.vsi_cmd; - resp = &desc.params.add_update_free_vsi_res; + cmd = libie_aq_raw(&desc); + resp = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi); @@ -1620,17 +1620,17 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, { struct ice_aqc_add_update_free_vsi_resp *resp; struct ice_aqc_add_get_update_free_vsi *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.vsi_cmd; - resp = &desc.params.add_update_free_vsi_res; + cmd = libie_aq_raw(&desc); + resp = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi); cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, sizeof(vsi_ctx->info), cd); @@ -1944,7 +1944,8 @@ int ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd) { - struct ice_aq_desc desc; + struct ice_aqc_sw_rules *cmd; + struct libie_aq_desc desc; int status; if (opc != ice_aqc_opc_add_sw_rules && @@ -1953,13 +1954,13 @@ ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, return -EINVAL; ice_fill_dflt_direct_cmd_desc(&desc, opc); + cmd = libie_aq_raw(&desc); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); - desc.params.sw_rules.num_rules_fltr_entry_index = - cpu_to_le16(num_rules); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); + cmd->num_rules_fltr_entry_index = cpu_to_le16(num_rules); status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd); if (opc != ice_aqc_opc_add_sw_rules && - hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) + hw->adminq.sq_last_status == LIBIE_AQ_RC_ENOENT) status = -ENOENT; if (!status) { @@ -1989,14 +1990,14 @@ ice_aq_add_recipe(struct ice_hw *hw, u16 num_recipes, struct ice_sq_cd *cd) { struct ice_aqc_add_get_recipe *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 buf_size; - cmd = &desc.params.add_get_recipe; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe); cmd->num_sub_recipes = cpu_to_le16(num_recipes); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); buf_size = num_recipes * sizeof(*s_recipe_list); @@ -2026,14 +2027,14 @@ ice_aq_get_recipe(struct ice_hw *hw, u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd) { struct ice_aqc_add_get_recipe *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; u16 buf_size; int status; if (*num_recipes != ICE_MAX_NUM_RECIPES) return -EINVAL; - cmd = &desc.params.add_get_recipe; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe); cmd->return_index = cpu_to_le16(recipe_root); @@ -2118,9 +2119,9 @@ ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 r_assoc, struct ice_sq_cd *cd) { struct ice_aqc_recipe_to_profile *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; - cmd = &desc.params.recipe_to_profile; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile); cmd->profile_id = cpu_to_le16(profile_id); /* Set the recipe ID bit in the bitmask to let the device know which @@ -2144,10 +2145,10 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc, struct ice_sq_cd *cd) { struct ice_aqc_recipe_to_profile *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; int status; - cmd = &desc.params.recipe_to_profile; + cmd = libie_aq_raw(&desc); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile); cmd->profile_id = cpu_to_le16(profile_id); diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h index 07aab6e130cd..4f35ef8d6b29 100644 --- a/drivers/net/ethernet/intel/ice/ice_trace.h +++ b/drivers/net/ethernet/intel/ice/ice_trace.h @@ -130,7 +130,7 @@ DECLARE_EVENT_CLASS(ice_tx_template, __entry->buf = buf; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK buf %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p buf %p", __get_str(devname), __entry->ring, __entry->desc, __entry->buf) ); @@ -158,7 +158,7 @@ DECLARE_EVENT_CLASS(ice_rx_template, __entry->desc = desc; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p", __get_str(devname), __entry->ring, __entry->desc) ); DEFINE_EVENT(ice_rx_template, ice_clean_rx_irq, @@ -182,7 +182,7 @@ DECLARE_EVENT_CLASS(ice_rx_indicate_template, __entry->skb = skb; __assign_str(devname);), - TP_printk("netdev: %s ring: %pK desc: %pK skb %pK", __get_str(devname), + TP_printk("netdev: %s ring: %p desc: %p skb %p", __get_str(devname), __entry->ring, __entry->desc, __entry->skb) ); @@ -205,7 +205,7 @@ DECLARE_EVENT_CLASS(ice_xmit_template, __entry->skb = skb; __assign_str(devname);), - TP_printk("netdev: %s skb: %pK ring: %pK", __get_str(devname), + TP_printk("netdev: %s skb: %p ring: %p", __get_str(devname), __entry->skb, __entry->ring) ); @@ -228,7 +228,7 @@ DECLARE_EVENT_CLASS(ice_tx_tstamp_template, TP_fast_assign(__entry->skb = skb; __entry->idx = idx;), - TP_printk("skb %pK idx %d", + TP_printk("skb %p idx %d", __entry->skb, __entry->idx) ); #define DEFINE_TX_TSTAMP_OP_EVENT(name) \ diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.c b/drivers/net/ethernet/intel/ice/ice_tspll.c new file mode 100644 index 000000000000..66320a4ab86f --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_tspll.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025, Intel Corporation. */ + +#include "ice.h" +#include "ice_lib.h" +#include "ice_ptp_hw.h" + +static const struct +ice_tspll_params_e82x e82x_tspll_params[NUM_ICE_TSPLL_FREQ] = { + [ICE_TSPLL_FREQ_25_000] = { + .refclk_pre_div = 1, + .post_pll_div = 6, + .feedback_div = 197, + .frac_n_div = 2621440, + }, + [ICE_TSPLL_FREQ_122_880] = { + .refclk_pre_div = 5, + .post_pll_div = 7, + .feedback_div = 223, + .frac_n_div = 524288 + }, + [ICE_TSPLL_FREQ_125_000] = { + .refclk_pre_div = 5, + .post_pll_div = 7, + .feedback_div = 223, + .frac_n_div = 524288 + }, + [ICE_TSPLL_FREQ_153_600] = { + .refclk_pre_div = 5, + .post_pll_div = 6, + .feedback_div = 159, + .frac_n_div = 1572864 + }, + [ICE_TSPLL_FREQ_156_250] = { + .refclk_pre_div = 5, + .post_pll_div = 6, + .feedback_div = 159, + .frac_n_div = 1572864 + }, + [ICE_TSPLL_FREQ_245_760] = { + .refclk_pre_div = 10, + .post_pll_div = 7, + .feedback_div = 223, + .frac_n_div = 524288 + }, +}; + +/** + * ice_tspll_clk_freq_str - Convert time_ref_freq to string + * @clk_freq: Clock frequency + * + * Return: specified TIME_REF clock frequency converted to a string. + */ +static const char *ice_tspll_clk_freq_str(enum ice_tspll_freq clk_freq) +{ + switch (clk_freq) { + case ICE_TSPLL_FREQ_25_000: + return "25 MHz"; + case ICE_TSPLL_FREQ_122_880: + return "122.88 MHz"; + case ICE_TSPLL_FREQ_125_000: + return "125 MHz"; + case ICE_TSPLL_FREQ_153_600: + return "153.6 MHz"; + case ICE_TSPLL_FREQ_156_250: + return "156.25 MHz"; + case ICE_TSPLL_FREQ_245_760: + return "245.76 MHz"; + default: + return "Unknown"; + } +} + +/** + * ice_tspll_default_freq - Return default frequency for a MAC type + * @mac_type: MAC type + * + * Return: default TSPLL frequency for a correct MAC type, -ERANGE otherwise. + */ +static enum ice_tspll_freq ice_tspll_default_freq(enum ice_mac_type mac_type) +{ + switch (mac_type) { + case ICE_MAC_GENERIC: + return ICE_TSPLL_FREQ_25_000; + case ICE_MAC_GENERIC_3K_E825: + return ICE_TSPLL_FREQ_156_250; + default: + return -ERANGE; + } +} + +/** + * ice_tspll_check_params - Check if TSPLL params are correct + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF or TCXO) + * + * Return: true if TSPLL params are correct, false otherwise. + */ +static bool ice_tspll_check_params(struct ice_hw *hw, + enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + if (clk_freq >= NUM_ICE_TSPLL_FREQ) { + dev_warn(ice_hw_to_dev(hw), "Invalid TSPLL frequency %u\n", + clk_freq); + return false; + } + + if (clk_src >= NUM_ICE_CLK_SRC) { + dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", + clk_src); + return false; + } + + if ((hw->mac_type == ICE_MAC_GENERIC_3K_E825 || + clk_src == ICE_CLK_SRC_TCXO) && + clk_freq != ice_tspll_default_freq(hw->mac_type)) { + dev_warn(ice_hw_to_dev(hw), "Unsupported frequency for this clock source\n"); + return false; + } + + return true; +} + +/** + * ice_tspll_clk_src_str - Convert time_ref_src to string + * @clk_src: Clock source + * + * Return: specified clock source converted to its string name + */ +static const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src) +{ + switch (clk_src) { + case ICE_CLK_SRC_TCXO: + return "TCXO"; + case ICE_CLK_SRC_TIME_REF: + return "TIME_REF"; + default: + return "Unknown"; + } +} + +/** + * ice_tspll_log_cfg - Log current/new TSPLL configuration + * @hw: Pointer to the HW struct + * @enable: CGU enabled/disabled + * @clk_src: Current clock source + * @tspll_freq: Current clock frequency + * @lock: CGU lock status + * @new_cfg: true if this is a new config + */ +static void ice_tspll_log_cfg(struct ice_hw *hw, bool enable, u8 clk_src, + u8 tspll_freq, bool lock, bool new_cfg) +{ + dev_dbg(ice_hw_to_dev(hw), + "%s TSPLL configuration -- %s, src %s, freq %s, PLL %s\n", + new_cfg ? "New" : "Current", str_enabled_disabled(enable), + ice_tspll_clk_src_str((enum ice_clk_src)clk_src), + ice_tspll_clk_freq_str((enum ice_tspll_freq)tspll_freq), + lock ? "locked" : "unlocked"); +} + +/** + * ice_tspll_cfg_e82x - Configure the Clock Generation Unit TSPLL + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF, or TCXO) + * + * Configure the Clock Generation Unit with the desired clock frequency and + * time reference, enabling the PLL which drives the PTP hardware clock. + * + * Return: + * * %0 - success + * * %-EINVAL - input parameters are incorrect + * * %-EBUSY - failed to lock TSPLL + * * %other - CGU read/write failure + */ +static int ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + u32 val, r9, r24; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); + if (err) + return err; + + err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + !!FIELD_GET(ICE_CGU_RO_BWM_LF_TRUE_LOCK, val), + false); + + /* Disable the PLL before changing the clock source or frequency */ + if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24)) { + r24 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE; + + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); + if (err) + return err; + } + + /* Set the frequency */ + r9 &= ~ICE_CGU_R9_TIME_REF_FREQ_SEL; + r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq); + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); + if (err) + return err; + + /* Configure the TSPLL feedback divisor */ + err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val); + if (err) + return err; + + val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X | ICE_CGU_R19_TSPLL_NDIVRATIO); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X, + e82x_tspll_params[clk_freq].feedback_div); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO, 1); + + err = ice_write_cgu_reg(hw, ICE_CGU_R19, val); + if (err) + return err; + + /* Configure the TSPLL post divisor */ + err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); + if (err) + return err; + + val &= ~(ICE_CGU_R22_TIME1588CLK_DIV | + ICE_CGU_R22_TIME1588CLK_DIV2); + val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV, + e82x_tspll_params[clk_freq].post_pll_div); + + err = ice_write_cgu_reg(hw, ICE_CGU_R22, val); + if (err) + return err; + + /* Configure the TSPLL pre divisor and clock source */ + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); + if (err) + return err; + + r24 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R24_FBDIV_FRAC | + ICE_CGU_R23_R24_TIME_REF_SEL); + r24 |= FIELD_PREP(ICE_CGU_R23_R24_REF1588_CK_DIV, + e82x_tspll_params[clk_freq].refclk_pre_div); + r24 |= FIELD_PREP(ICE_CGU_R24_FBDIV_FRAC, + e82x_tspll_params[clk_freq].frac_n_div); + r24 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src); + + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); + if (err) + return err; + + /* Wait to ensure everything is stable */ + usleep_range(10, 20); + + /* Finally, enable the PLL */ + r24 |= ICE_CGU_R23_R24_TSPLL_ENABLE; + + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); + if (err) + return err; + + /* Wait at least 1 ms to verify if the PLL locks */ + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); + + err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val); + if (err) + return err; + + if (!(val & ICE_CGU_RO_BWM_LF_TRUE_LOCK)) { + dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); + return -EBUSY; + } + + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + true, true); + + return 0; +} + +/** + * ice_tspll_dis_sticky_bits_e82x - disable TSPLL sticky bits + * @hw: Pointer to the HW struct + * + * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on + * losing TSPLL lock, but always show current state. + * + * Return: 0 on success, other error codes when failed to read/write CGU. + */ +static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw) +{ + u32 val; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_CNTR_BIST, &val); + if (err) + return err; + + val &= ~(ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 | + ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1); + + return ice_write_cgu_reg(hw, ICE_CGU_CNTR_BIST, val); +} + +/** + * ice_tspll_cfg_e825c - Configure the TSPLL for E825-C + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF, or TCXO) + * + * Configure the Clock Generation Unit with the desired clock frequency and + * time reference, enabling the PLL which drives the PTP hardware clock. + * + * Return: + * * %0 - success + * * %-EINVAL - input parameters are incorrect + * * %-EBUSY - failed to lock TSPLL + * * %other - CGU read/write failure + */ +static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + u32 val, r9, r23; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); + if (err) + return err; + + err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + !!FIELD_GET(ICE_CGU_RO_LOCK_TRUE_LOCK, val), + false); + + /* Disable the PLL before changing the clock source or frequency */ + if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23)) { + r23 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE; + + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); + if (err) + return err; + } + + if (FIELD_GET(ICE_CGU_R9_TIME_SYNC_EN, r9)) { + r9 &= ~ICE_CGU_R9_TIME_SYNC_EN; + + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); + if (err) + return err; + } + + /* Set the frequency and enable the correct receiver */ + r9 &= ~(ICE_CGU_R9_TIME_REF_FREQ_SEL | ICE_CGU_R9_CLK_EREF0_EN | + ICE_CGU_R9_TIME_REF_EN); + r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq); + if (clk_src == ICE_CLK_SRC_TCXO) + r9 |= ICE_CGU_R9_CLK_EREF0_EN; + else + r9 |= ICE_CGU_R9_TIME_REF_EN; + r9 |= ICE_CGU_R9_TIME_SYNC_EN; + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); + if (err) + return err; + + /* Choose the referenced frequency */ + err = ice_read_cgu_reg(hw, ICE_CGU_R16, &val); + if (err) + return err; + val &= ~ICE_CGU_R16_TSPLL_CK_REFCLKFREQ; + val |= FIELD_PREP(ICE_CGU_R16_TSPLL_CK_REFCLKFREQ, + ICE_TSPLL_CK_REFCLKFREQ_E825); + err = ice_write_cgu_reg(hw, ICE_CGU_R16, val); + if (err) + return err; + + /* Configure the TSPLL feedback divisor */ + err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val); + if (err) + return err; + + val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825 | + ICE_CGU_R19_TSPLL_NDIVRATIO); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825, + ICE_TSPLL_FBDIV_INTGR_E825); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO, + ICE_TSPLL_NDIVRATIO_E825); + + err = ice_write_cgu_reg(hw, ICE_CGU_R19, val); + if (err) + return err; + + /* Configure the TSPLL post divisor, these two are constant */ + err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); + if (err) + return err; + + val &= ~(ICE_CGU_R22_TIME1588CLK_DIV | + ICE_CGU_R22_TIME1588CLK_DIV2); + val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV, 5); + + err = ice_write_cgu_reg(hw, ICE_CGU_R22, val); + if (err) + return err; + + /* Configure the TSPLL pre divisor (constant) and clock source */ + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); + if (err) + return err; + + r23 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R23_R24_TIME_REF_SEL); + r23 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src); + + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); + if (err) + return err; + + /* Clear the R24 register. */ + err = ice_write_cgu_reg(hw, ICE_CGU_R24, 0); + if (err) + return err; + + /* Wait to ensure everything is stable */ + usleep_range(10, 20); + + /* Finally, enable the PLL */ + r23 |= ICE_CGU_R23_R24_TSPLL_ENABLE; + + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); + if (err) + return err; + + /* Wait at least 1 ms to verify if the PLL locks */ + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); + + err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); + if (err) + return err; + + if (!(val & ICE_CGU_RO_LOCK_TRUE_LOCK)) { + dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); + return -EBUSY; + } + + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + true, true); + + return 0; +} + +/** + * ice_tspll_dis_sticky_bits_e825c - disable TSPLL sticky bits for E825-C + * @hw: Pointer to the HW struct + * + * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on + * losing TSPLL lock, but always show current state. + * + * Return: 0 on success, other error codes when failed to read/write CGU. + */ +static int ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw) +{ + u32 val; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_BW_TDC, &val); + if (err) + return err; + + val &= ~ICE_CGU_BW_TDC_PLLLOCK_SEL; + + return ice_write_cgu_reg(hw, ICE_CGU_BW_TDC, val); +} + +/** + * ice_tspll_cfg_pps_out_e825c - Enable/disable 1PPS output and set amplitude + * @hw: pointer to the HW struct + * @enable: true to enable 1PPS output, false to disable it + * + * Return: 0 on success, other negative error code when CGU read/write failed. + */ +int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable) +{ + u32 val; + int err; + + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &val); + if (err) + return err; + + val &= ~(ICE_CGU_R9_ONE_PPS_OUT_EN | ICE_CGU_R9_ONE_PPS_OUT_AMP); + val |= FIELD_PREP(ICE_CGU_R9_ONE_PPS_OUT_EN, enable) | + ICE_CGU_R9_ONE_PPS_OUT_AMP; + + return ice_write_cgu_reg(hw, ICE_CGU_R9, val); +} + +/** + * ice_tspll_cfg - Configure the Clock Generation Unit TSPLL + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF, or TCXO) + * + * Configure the Clock Generation Unit with the desired clock frequency and + * time reference, enabling the TSPLL which drives the PTP hardware clock. + * + * Return: 0 on success, -ERANGE on unsupported MAC type, other negative error + * codes when failed to configure CGU. + */ +static int ice_tspll_cfg(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + switch (hw->mac_type) { + case ICE_MAC_GENERIC: + return ice_tspll_cfg_e82x(hw, clk_freq, clk_src); + case ICE_MAC_GENERIC_3K_E825: + return ice_tspll_cfg_e825c(hw, clk_freq, clk_src); + default: + return -ERANGE; + } +} + +/** + * ice_tspll_dis_sticky_bits - disable TSPLL sticky bits + * @hw: Pointer to the HW struct + * + * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on + * losing TSPLL lock, but always show current state. + * + * Return: 0 on success, -ERANGE on unsupported MAC type. + */ +static int ice_tspll_dis_sticky_bits(struct ice_hw *hw) +{ + switch (hw->mac_type) { + case ICE_MAC_GENERIC: + return ice_tspll_dis_sticky_bits_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: + return ice_tspll_dis_sticky_bits_e825c(hw); + default: + return -ERANGE; + } +} + +/** + * ice_tspll_init - Initialize TSPLL with settings from firmware + * @hw: Pointer to the HW structure + * + * Initialize the Clock Generation Unit of the E82X/E825 device. + * + * Return: 0 on success, other error codes when failed to read/write/cfg CGU. + */ +int ice_tspll_init(struct ice_hw *hw) +{ + struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; + enum ice_tspll_freq tspll_freq; + enum ice_clk_src clk_src; + int err; + + /* Only E822, E823 and E825 products support TSPLL */ + if (hw->mac_type != ICE_MAC_GENERIC && + hw->mac_type != ICE_MAC_GENERIC_3K_E825) + return 0; + + tspll_freq = (enum ice_tspll_freq)ts_info->time_ref; + clk_src = (enum ice_clk_src)ts_info->clk_src; + if (!ice_tspll_check_params(hw, tspll_freq, clk_src)) + return -EINVAL; + + /* Disable sticky lock detection so lock status reported is accurate */ + err = ice_tspll_dis_sticky_bits(hw); + if (err) + return err; + + /* Configure the TSPLL using the parameters from the function + * capabilities. + */ + err = ice_tspll_cfg(hw, tspll_freq, clk_src); + if (err) { + dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to predefined frequency. Retrying with fallback frequency.\n"); + + /* Try to lock to internal TCXO as a fallback. */ + tspll_freq = ice_tspll_default_freq(hw->mac_type); + clk_src = ICE_CLK_SRC_TCXO; + err = ice_tspll_cfg(hw, tspll_freq, clk_src); + if (err) + dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to fallback frequency.\n"); + } + + return err; +} diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.h b/drivers/net/ethernet/intel/ice/ice_tspll.h new file mode 100644 index 000000000000..c0b1232cc07c --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_tspll.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2025, Intel Corporation. */ + +#ifndef _ICE_TSPLL_H_ +#define _ICE_TSPLL_H_ + +/** + * struct ice_tspll_params_e82x - E82X TSPLL parameters + * @refclk_pre_div: Reference clock pre-divisor + * @post_pll_div: Post PLL divisor + * @feedback_div: Feedback divisor + * @frac_n_div: Fractional divisor + * + * Clock Generation Unit parameters used to program the PLL based on the + * selected TIME_REF/TCXO frequency. + */ +struct ice_tspll_params_e82x { + u8 refclk_pre_div; + u8 post_pll_div; + u8 feedback_div; + u32 frac_n_div; +}; + +#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); + +#endif /* _ICE_TSPLL_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 0e5107fe62ad..73f08d02f9c7 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -20,7 +20,6 @@ #define ICE_RX_HDR_SIZE 256 -#define FDIR_DESC_RXDID 0x40 #define ICE_FDIR_CLEAN_DELAY 10 /** @@ -145,6 +144,56 @@ static struct netdev_queue *txring_txq(const struct ice_tx_ring *ring) } /** + * ice_clean_tstamp_ring - clean time stamp ring + * @tx_ring: Tx ring to clean the Time Stamp ring for + */ +static void ice_clean_tstamp_ring(struct ice_tx_ring *tx_ring) +{ + struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; + u32 size; + + if (!tstamp_ring->desc) + return; + + size = ALIGN(tstamp_ring->count * sizeof(struct ice_ts_desc), + PAGE_SIZE); + memset(tstamp_ring->desc, 0, size); + tstamp_ring->next_to_use = 0; +} + +/** + * ice_free_tstamp_ring - free time stamp resources per queue + * @tx_ring: Tx ring to free the Time Stamp ring for + */ +void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring) +{ + struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; + u32 size; + + if (!tstamp_ring->desc) + return; + + ice_clean_tstamp_ring(tx_ring); + size = ALIGN(tstamp_ring->count * sizeof(struct ice_ts_desc), + PAGE_SIZE); + dmam_free_coherent(tx_ring->dev, size, tstamp_ring->desc, + tstamp_ring->dma); + tstamp_ring->desc = NULL; +} + +/** + * ice_free_tx_tstamp_ring - free time stamp resources per Tx ring + * @tx_ring: Tx ring to free the Time Stamp ring for + */ +void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring) +{ + ice_free_tstamp_ring(tx_ring); + kfree_rcu(tx_ring->tstamp_ring, rcu); + tx_ring->tstamp_ring = NULL; + tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME; +} + +/** * ice_clean_tx_ring - Free any empty Tx buffers * @tx_ring: ring to be cleaned */ @@ -182,6 +231,9 @@ tx_skip_free: /* cleanup Tx queue statistics */ netdev_tx_reset_queue(txring_txq(tx_ring)); + + if (ice_is_txtime_cfg(tx_ring)) + ice_free_tx_tstamp_ring(tx_ring); } /** @@ -333,6 +385,84 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget) } /** + * ice_alloc_tstamp_ring - allocate the Time Stamp ring + * @tx_ring: Tx ring to allocate the Time Stamp ring for + * + * Return: 0 on success, negative on error + */ +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); + if (!tstamp_ring) + return -ENOMEM; + + tstamp_ring->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; + return 0; +} + +/** + * ice_setup_tstamp_ring - allocate the Time Stamp ring + * @tx_ring: Tx ring to set up the Time Stamp ring for + * + * Return: 0 on success, negative on error + */ +static int ice_setup_tstamp_ring(struct ice_tx_ring *tx_ring) +{ + struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; + struct device *dev = tx_ring->dev; + u32 size; + + /* round up to nearest page */ + size = ALIGN(tstamp_ring->count * sizeof(struct ice_ts_desc), + PAGE_SIZE); + tstamp_ring->desc = dmam_alloc_coherent(dev, size, &tstamp_ring->dma, + GFP_KERNEL); + if (!tstamp_ring->desc) { + dev_err(dev, "Unable to allocate memory for Time stamp Ring, size=%d\n", + size); + return -ENOMEM; + } + + tstamp_ring->next_to_use = 0; + return 0; +} + +/** + * ice_alloc_setup_tstamp_ring - Allocate and setup the Time Stamp ring + * @tx_ring: Tx ring to allocate and setup the Time Stamp ring for + * + * Return: 0 on success, negative on error + */ +int ice_alloc_setup_tstamp_ring(struct ice_tx_ring *tx_ring) +{ + struct device *dev = tx_ring->dev; + int err; + + err = ice_alloc_tstamp_ring(tx_ring); + if (err) { + dev_err(dev, "Unable to allocate Time stamp ring for Tx ring %d\n", + tx_ring->q_index); + return err; + } + + err = ice_setup_tstamp_ring(tx_ring); + if (err) { + dev_err(dev, "Unable to setup Time stamp ring for Tx ring %d\n", + tx_ring->q_index); + ice_free_tx_tstamp_ring(tx_ring); + return err; + } + return 0; +} + +/** * ice_setup_tx_ring - Allocate the Tx descriptors * @tx_ring: the Tx ring to set up * @@ -707,6 +837,37 @@ ice_alloc_mapped_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *bi) } /** + * ice_init_ctrl_rx_descs - Initialize Rx descriptors for control vsi. + * @rx_ring: ring to init descriptors on + * @count: number of descriptors to initialize + */ +void ice_init_ctrl_rx_descs(struct ice_rx_ring *rx_ring, u32 count) +{ + union ice_32b_rx_flex_desc *rx_desc; + u32 ntu = rx_ring->next_to_use; + + if (!count) + return; + + rx_desc = ICE_RX_DESC(rx_ring, ntu); + + do { + rx_desc++; + ntu++; + if (unlikely(ntu == rx_ring->count)) { + rx_desc = ICE_RX_DESC(rx_ring, 0); + ntu = 0; + } + + rx_desc->wb.status_error0 = 0; + count--; + } while (count); + + if (rx_ring->next_to_use != ntu) + ice_release_rx_desc(rx_ring, ntu); +} + +/** * ice_alloc_rx_bufs - Replace used receive buffers * @rx_ring: ring to place buffers on * @cleaned_count: number of buffers to replace @@ -726,8 +887,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count) struct ice_rx_buf *bi; /* do nothing if no valid netdev defined */ - if ((!rx_ring->netdev && rx_ring->vsi->type != ICE_VSI_CTRL) || - !cleaned_count) + if (!rx_ring->netdev || !cleaned_count) return false; /* get the Rx descriptor and buffer based on next_to_use */ @@ -865,10 +1025,6 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page, rx_buf->page_offset, size); sinfo->xdp_frags_size += size; - /* remember frag count before XDP prog execution; bpf_xdp_adjust_tail() - * can pop off frags but driver has to handle it on its own - */ - rx_ring->nr_frags = sinfo->nr_frags; if (page_is_pfmemalloc(rx_buf->page)) xdp_buff_set_frag_pfmemalloc(xdp); @@ -939,20 +1095,20 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, /** * ice_get_pgcnts - grab page_count() for gathered fragments * @rx_ring: Rx descriptor ring to store the page counts on + * @ntc: the next to clean element (not included in this frame!) * * This function is intended to be called right before running XDP * program so that the page recycling mechanism will be able to take * a correct decision regarding underlying pages; this is done in such * way as XDP program can change the refcount of page */ -static void ice_get_pgcnts(struct ice_rx_ring *rx_ring) +static void ice_get_pgcnts(struct ice_rx_ring *rx_ring, unsigned int ntc) { - u32 nr_frags = rx_ring->nr_frags + 1; u32 idx = rx_ring->first_desc; struct ice_rx_buf *rx_buf; u32 cnt = rx_ring->count; - for (int i = 0; i < nr_frags; i++) { + while (idx != ntc) { rx_buf = &rx_ring->rx_buf[idx]; rx_buf->pgcnt = page_count(rx_buf->page); @@ -1006,10 +1162,9 @@ ice_build_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp) skb_metadata_set(skb, metasize); if (unlikely(xdp_buff_has_frags(xdp))) - xdp_update_skb_shared_info(skb, nr_frags, - sinfo->xdp_frags_size, - nr_frags * xdp->frame_sz, - xdp_buff_is_frag_pfmemalloc(xdp)); + xdp_update_skb_frags_info(skb, nr_frags, sinfo->xdp_frags_size, + nr_frags * xdp->frame_sz, + xdp_buff_get_skb_flags(xdp)); return skb; } @@ -1086,10 +1241,10 @@ ice_construct_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp) memcpy(&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0], sizeof(skb_frag_t) * nr_frags); - xdp_update_skb_shared_info(skb, skinfo->nr_frags + nr_frags, - sinfo->xdp_frags_size, - nr_frags * xdp->frame_sz, - xdp_buff_is_frag_pfmemalloc(xdp)); + xdp_update_skb_frags_info(skb, skinfo->nr_frags + nr_frags, + sinfo->xdp_frags_size, + nr_frags * xdp->frame_sz, + xdp_buff_get_skb_flags(xdp)); } return skb; @@ -1125,62 +1280,90 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf) } /** - * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all frame frags + * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all buffers in frame * @rx_ring: Rx ring with all the auxiliary data * @xdp: XDP buffer carrying linear + frags part - * @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage - * @ntc: a current next_to_clean value to be stored at rx_ring + * @ntc: the next to clean element (not included in this frame!) * @verdict: return code from XDP program execution * - * Walk through gathered fragments and satisfy internal page - * recycle mechanism; we take here an action related to verdict - * returned by XDP program; + * Called after XDP program is completed, or on error with verdict set to + * ICE_XDP_CONSUMED. + * + * Walk through buffers from first_desc to the end of the frame, releasing + * buffers and satisfying internal page recycle mechanism. The action depends + * on verdict from XDP program. */ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, - u32 *xdp_xmit, u32 ntc, u32 verdict) + u32 ntc, u32 verdict) { - u32 nr_frags = rx_ring->nr_frags + 1; u32 idx = rx_ring->first_desc; u32 cnt = rx_ring->count; - u32 post_xdp_frags = 1; struct ice_rx_buf *buf; - int i; + u32 xdp_frags = 0; + int i = 0; if (unlikely(xdp_buff_has_frags(xdp))) - post_xdp_frags += xdp_get_shared_info_from_buff(xdp)->nr_frags; + xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; - for (i = 0; i < post_xdp_frags; i++) { + while (idx != ntc) { buf = &rx_ring->rx_buf[idx]; + if (++idx == cnt) + idx = 0; - if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) { + /* An XDP program could release fragments from the end of the + * buffer. For these, we need to keep the pagecnt_bias as-is. + * To do this, only adjust pagecnt_bias for fragments up to + * the total remaining after the XDP program has run. + */ + if (verdict != ICE_XDP_CONSUMED) ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); - *xdp_xmit |= verdict; - } else if (verdict & ICE_XDP_CONSUMED) { + else if (i++ <= xdp_frags) buf->pagecnt_bias++; - } else if (verdict == ICE_XDP_PASS) { - ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); - } ice_put_rx_buf(rx_ring, buf); - - if (++idx == cnt) - idx = 0; - } - /* handle buffers that represented frags released by XDP prog; - * for these we keep pagecnt_bias as-is; refcount from struct page - * has been decremented within XDP prog and we do not have to increase - * the biased refcnt - */ - for (; i < nr_frags; i++) { - buf = &rx_ring->rx_buf[idx]; - ice_put_rx_buf(rx_ring, buf); - if (++idx == cnt) - idx = 0; } xdp->data = NULL; rx_ring->first_desc = ntc; - rx_ring->nr_frags = 0; +} + +/** + * ice_clean_ctrl_rx_irq - Clean descriptors from flow director Rx ring + * @rx_ring: Rx descriptor ring for ctrl_vsi to transact packets on + * + * This function cleans Rx descriptors from the ctrl_vsi Rx ring used + * to set flow director rules on VFs. + */ +void ice_clean_ctrl_rx_irq(struct ice_rx_ring *rx_ring) +{ + u32 ntc = rx_ring->next_to_clean; + unsigned int total_rx_pkts = 0; + u32 cnt = rx_ring->count; + + while (likely(total_rx_pkts < ICE_DFLT_IRQ_WORK)) { + struct ice_vsi *ctrl_vsi = rx_ring->vsi; + union ice_32b_rx_flex_desc *rx_desc; + u16 stat_err_bits; + + rx_desc = ICE_RX_DESC(rx_ring, ntc); + + stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S); + if (!ice_test_staterr(rx_desc->wb.status_error0, stat_err_bits)) + break; + + dma_rmb(); + + if (ctrl_vsi->vf) + ice_vc_fdir_irq_handler(ctrl_vsi, rx_desc); + + if (++ntc == cnt) + ntc = 0; + total_rx_pkts++; + } + + rx_ring->first_desc = ntc; + rx_ring->next_to_clean = ntc; + ice_init_ctrl_rx_descs(rx_ring, ICE_RX_DESC_UNUSED(rx_ring)); } /** @@ -1195,7 +1378,7 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, * * Returns amount of work completed */ -int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) +static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) { unsigned int total_rx_bytes = 0, total_rx_pkts = 0; unsigned int offset = rx_ring->rx_offset; @@ -1242,17 +1425,6 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) dma_rmb(); ice_trace(clean_rx_irq, rx_ring, rx_desc); - if (rx_desc->wb.rxdid == FDIR_DESC_RXDID || !rx_ring->netdev) { - struct ice_vsi *ctrl_vsi = rx_ring->vsi; - - if (rx_desc->wb.rxdid == FDIR_DESC_RXDID && - ctrl_vsi->vf) - ice_vc_fdir_irq_handler(ctrl_vsi, rx_desc); - if (++ntc == cnt) - ntc = 0; - rx_ring->first_desc = ntc; - continue; - } size = le16_to_cpu(rx_desc->wb.pkt_len) & ICE_RX_FLX_DESC_PKT_LEN_M; @@ -1260,6 +1432,10 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) /* retrieve a buffer from the ring */ rx_buf = ice_get_rx_buf(rx_ring, size, ntc); + /* Increment ntc before calls to ice_put_rx_mbuf() */ + if (++ntc == cnt) + ntc = 0; + if (!xdp->data) { void *hard_start; @@ -1268,24 +1444,23 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) xdp_prepare_buff(xdp, hard_start, offset, size, !!offset); xdp_buff_clear_frags_flag(xdp); } else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) { - ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc, ICE_XDP_CONSUMED); + ice_put_rx_mbuf(rx_ring, xdp, ntc, ICE_XDP_CONSUMED); break; } - if (++ntc == cnt) - ntc = 0; /* skip if it is NOP desc */ if (ice_is_non_eop(rx_ring, rx_desc)) continue; - ice_get_pgcnts(rx_ring); + ice_get_pgcnts(rx_ring, ntc); xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_desc); if (xdp_verdict == ICE_XDP_PASS) goto construct_skb; total_rx_bytes += xdp_get_buff_len(xdp); total_rx_pkts++; - ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); + ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); + xdp_xmit |= xdp_verdict & (ICE_XDP_TX | ICE_XDP_REDIR); continue; construct_skb: @@ -1295,10 +1470,10 @@ construct_skb: skb = ice_construct_skb(rx_ring, xdp); /* exit if we failed to retrieve a buffer */ if (!skb) { - rx_ring->ring_stats->rx_stats.alloc_page_failed++; + rx_ring->ring_stats->rx_stats.alloc_buf_failed++; xdp_verdict = ICE_XDP_CONSUMED; } - ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); + ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); if (!skb) break; @@ -1778,10 +1953,46 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, /* notify HW of packet */ kick = __netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount, netdev_xmit_more()); - if (kick) - /* notify HW of packet */ - writel(i, tx_ring->tail); + if (!kick) + 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_ts_desc *ts_desc; + struct timespec64 ts; + u32 tstamp; + + ts = ktime_to_timespec64(first->skb->tstamp); + tstamp = ts.tv_nsec >> ICE_TXTIME_CTX_RESOLUTION_128NS; + + ts_desc = ICE_TS_DESC(tstamp_ring, j); + ts_desc->tx_desc_idx_tstamp = ice_build_tstamp_desc(i, tstamp); + + j++; + if (j == tstamp_count) { + u32 fetch = tstamp_count - tx_ring->count; + + j = 0; + + /* To prevent an MDD, when wrapping the tstamp ring + * create additional TS descriptors equal to the number + * of the fetch TS descriptors value. HW will merge the + * TS descriptors with the same timestamp value into a + * single descriptor. + */ + for (; j < fetch; j++) { + ts_desc = ICE_TS_DESC(tstamp_ring, j); + ts_desc->tx_desc_idx_tstamp = + ice_build_tstamp_desc(i, tstamp); + } + } + tstamp_ring->next_to_use = j; + writel_relaxed(j, tstamp_ring->tail); + } else { + writel_relaxed(i, tx_ring->tail); + } return; dma_error: diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index a4b1e9514632..841a07bfba54 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -310,6 +310,16 @@ enum ice_dynamic_itr { #define ICE_TX_LEGACY 1 /* descriptor ring, associated with a VSI */ +struct ice_tstamp_ring { + struct ice_tx_ring *tx_ring; /* Backreference to associated Tx ring */ + dma_addr_t dma; /* physical address of ring */ + struct rcu_head rcu; /* to avoid race on free */ + u8 __iomem *tail; + void *desc; + u16 next_to_use; + u16 count; +} ____cacheline_internodealigned_in_smp; + struct ice_rx_ring { /* CL1 - 1st cacheline starts here */ void *desc; /* Descriptor ring memory */ @@ -358,7 +368,6 @@ struct ice_rx_ring { struct ice_tx_ring *xdp_ring; struct ice_rx_ring *next; /* pointer to next ring in q_vector */ struct xsk_buff_pool *xsk_pool; - u32 nr_frags; u16 max_frame; u16 rx_buf_len; dma_addr_t dma; /* physical address of ring */ @@ -403,9 +412,11 @@ struct ice_tx_ring { 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; u8 dcb_tc; /* Traffic class of ring */ u16 quanta_prof_id; @@ -491,6 +502,7 @@ static inline unsigned int ice_rx_pg_order(struct ice_rx_ring *ring) union ice_32b_rx_flex_desc; +void ice_init_ctrl_rx_descs(struct ice_rx_ring *rx_ring, u32 num_descs); bool ice_alloc_rx_bufs(struct ice_rx_ring *rxr, unsigned int cleaned_count); netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev); u16 @@ -500,12 +512,15 @@ void ice_clean_tx_ring(struct ice_tx_ring *tx_ring); void ice_clean_rx_ring(struct ice_rx_ring *rx_ring); int ice_setup_tx_ring(struct ice_tx_ring *tx_ring); int ice_setup_rx_ring(struct ice_rx_ring *rx_ring); +int ice_alloc_setup_tstamp_ring(struct ice_tx_ring *tx_ring); void ice_free_tx_ring(struct ice_tx_ring *tx_ring); void ice_free_rx_ring(struct ice_rx_ring *rx_ring); int ice_napi_poll(struct napi_struct *napi, int budget); int ice_prgm_fdir_fltr(struct ice_vsi *vsi, struct ice_fltr_desc *fdir_desc, u8 *raw_packet); -int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget); void ice_clean_ctrl_tx_irq(struct ice_tx_ring *tx_ring); +void ice_clean_ctrl_rx_irq(struct ice_rx_ring *rx_ring); +void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring); +void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring); #endif /* _ICE_TXRX_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h index 6cf32b404127..99717730f21a 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -54,6 +54,20 @@ ice_build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag) } /** + * ice_build_tstamp_desc - build Tx time stamp descriptor + * @tx_desc: Tx LAN descriptor index + * @tstamp: time stamp + * + * Return: Tx time stamp descriptor + */ +static inline __le32 +ice_build_tstamp_desc(u16 tx_desc, u32 tstamp) +{ + return cpu_to_le32(FIELD_PREP(ICE_TXTIME_TX_DESC_IDX_M, tx_desc) | + FIELD_PREP(ICE_TXTIME_STAMP_M, tstamp)); +} + +/** * ice_get_vlan_tci - get VLAN TCI from Rx flex descriptor * @rx_desc: Rx 32b flex descriptor with RXDID=2 * diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 3d68f465952d..b0a1b67071c5 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -17,7 +17,7 @@ #include "ice_protocol_type.h" #include "ice_sbq_cmd.h" #include "ice_vlan_mode.h" -#include "ice_fwlog.h" +#include <linux/net/intel/libie/fwlog.h> #include <linux/wait.h> #include <net/dscp.h> @@ -293,8 +293,10 @@ struct ice_hw_common_caps { u8 dcb; u8 ieee_1588; u8 rdma; - u8 roce_lag; - u8 sriov_lag; + + bool roce_lag; + bool sriov_lag; + bool sriov_aa_lag; bool nvm_update_pending_nvm; bool nvm_update_pending_orom; @@ -326,17 +328,17 @@ struct ice_hw_common_caps { #define ICE_TS_TMR_IDX_ASSOC_M BIT(24) /* TIME_REF clock rate specification */ -enum ice_time_ref_freq { - ICE_TIME_REF_FREQ_25_000 = 0, - ICE_TIME_REF_FREQ_122_880 = 1, - ICE_TIME_REF_FREQ_125_000 = 2, - ICE_TIME_REF_FREQ_153_600 = 3, - ICE_TIME_REF_FREQ_156_250 = 4, - ICE_TIME_REF_FREQ_245_760 = 5, +enum ice_tspll_freq { + ICE_TSPLL_FREQ_25_000 = 0, + ICE_TSPLL_FREQ_122_880 = 1, + ICE_TSPLL_FREQ_125_000 = 2, + ICE_TSPLL_FREQ_153_600 = 3, + ICE_TSPLL_FREQ_156_250 = 4, + ICE_TSPLL_FREQ_245_760 = 5, - NUM_ICE_TIME_REF_FREQ, + NUM_ICE_TSPLL_FREQ, - ICE_TIME_REF_FREQ_INVALID = -1, + ICE_TSPLL_FREQ_INVALID = -1, }; /* Clock source specification */ @@ -349,7 +351,7 @@ enum ice_clk_src { struct ice_ts_func_info { /* Function specific info */ - enum ice_time_ref_freq time_ref; + enum ice_tspll_freq time_ref; u8 clk_freq; u8 clk_src; u8 tmr_index_assoc; @@ -946,9 +948,7 @@ struct ice_hw { u8 fw_patch; /* firmware patch version */ u32 fw_build; /* firmware build number */ - struct ice_fwlog_cfg fwlog_cfg; - bool fwlog_supported; /* does hardware support FW logging? */ - struct ice_fwlog_ring fwlog_ring; + struct libie_fwlog fwlog; /* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL * register. Used for determining the ITR/INTRL granularity during diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 48cd533e93b7..de9e81ccee66 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -5,7 +5,7 @@ #include "ice.h" #include "ice_lib.h" #include "ice_fltr.h" -#include "ice_virtchnl_allowlist.h" +#include "virt/allowlist.h" /* Public functions which may be accessed by all driver files */ @@ -859,16 +859,13 @@ static void ice_notify_vf_reset(struct ice_vf *vf) int ice_reset_vf(struct ice_vf *vf, u32 flags) { struct ice_pf *pf = vf->pf; - struct ice_lag *lag; struct ice_vsi *vsi; - u8 act_prt, pri_prt; struct device *dev; int err = 0; + u8 act_prt; bool rsd; dev = ice_pf_to_dev(pf); - act_prt = ICE_LAG_INVALID_PORT; - pri_prt = pf->hw.port_info->lport; if (flags & ICE_VF_RESET_NOTIFY) ice_notify_vf_reset(vf); @@ -884,16 +881,8 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) else lockdep_assert_held(&vf->cfg_lock); - lag = pf->lag; mutex_lock(&pf->lag_mutex); - if (lag && lag->bonded && lag->primary) { - act_prt = lag->active_port; - if (act_prt != pri_prt && act_prt != ICE_LAG_INVALID_PORT && - lag->upper_netdev) - ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); - else - act_prt = ICE_LAG_INVALID_PORT; - } + act_prt = ice_lag_prepare_vf_reset(pf->lag); if (ice_is_vf_disabled(vf)) { vsi = ice_get_vf_vsi(vf); @@ -979,9 +968,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) ice_reset_vf_mbx_cnt(vf); out_unlock: - if (lag && lag->bonded && lag->primary && - act_prt != ICE_LAG_INVALID_PORT) - ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); + ice_lag_complete_vf_reset(pf->lag, act_prt); mutex_unlock(&pf->lag_mutex); if (flags & ICE_VF_RESET_LOCK) @@ -1022,6 +1009,9 @@ void ice_initialize_vf_entry(struct ice_vf *vf) vf->num_msix = vfs->num_msix_per; vf->num_vf_qs = vfs->num_qps_per; + /* set default RSS hash configuration */ + vf->rss_hashcfg = ICE_DEFAULT_RSS_HASHCFG; + /* ctrl_vsi_idx will be set to a valid value only when iAVF * creates its first fdir rule. */ diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index 482f4285fd35..b00708907176 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -13,7 +13,7 @@ #include <linux/avf/virtchnl.h> #include "ice_type.h" #include "ice_flow.h" -#include "ice_virtchnl_fdir.h" +#include "virt/fdir.h" #include "ice_vsi_vlan_ops.h" #define ICE_MAX_SRIOV_VFS 256 @@ -106,8 +106,7 @@ struct ice_vf { u16 ctrl_vsi_idx; struct ice_vf_fdir fdir; struct ice_fdir_prof_info fdir_prof_info[ICE_MAX_PTGS]; - /* first vector index of this VF in the PF space */ - int first_vector_idx; + u64 rss_hashcfg; /* RSS hash configuration */ struct ice_sw *vf_sw_id; /* switch ID the VF VSIs connect to */ struct virtchnl_version_info vf_ver; u32 driver_caps; /* reported by VF driver */ @@ -126,10 +125,14 @@ struct ice_vf { u8 link_up:1; /* only valid if VF link is forced */ u8 lldp_tx_ena:1; + u16 num_msix; /* num of MSI-X configured on this VF */ + u32 ptp_caps; unsigned int min_tx_rate; /* Minimum Tx bandwidth limit in Mbps */ unsigned int max_tx_rate; /* Maximum Tx bandwidth limit in Mbps */ + /* first vector index of this VF in the PF space */ + int first_vector_idx; DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ unsigned long vf_caps; /* VF's adv. capabilities */ @@ -154,7 +157,6 @@ struct ice_vf { u16 lldp_recipe_id; u16 lldp_rule_id; - u16 num_msix; /* num of MSI-X configured on this VF */ struct ice_vf_qs_bw qs_bw[ICE_MAX_RSS_QS_PER_VF]; }; @@ -237,6 +239,18 @@ static inline bool ice_vf_is_lldp_ena(struct ice_vf *vf) #ifdef CONFIG_PCI_IOV struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id); + +static inline struct ice_vf *ice_get_vf_by_dev(struct ice_pf *pf, + struct pci_dev *vf_dev) +{ + int vf_id = pci_iov_vf_id(vf_dev); + + if (vf_id < 0) + return NULL; + + return ice_get_vf_by_id(pf, pci_iov_vf_id(vf_dev)); +} + void ice_put_vf(struct ice_vf *vf); bool ice_has_vfs(struct ice_pf *pf); u16 ice_get_num_vfs(struct ice_pf *pf); @@ -263,6 +277,12 @@ static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id) return NULL; } +static inline struct ice_vf *ice_get_vf_by_dev(struct ice_pf *pf, + struct pci_dev *vf_dev) +{ + return NULL; +} + static inline void ice_put_vf(struct ice_vf *vf) { } diff --git a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c index 75c8113e58ee..7798a5d4bc9d 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c @@ -23,18 +23,18 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen, struct ice_sq_cd *cd) { struct ice_aqc_pf_vf_msg *cmd; - struct ice_aq_desc desc; + struct libie_aq_desc desc; ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf); - cmd = &desc.params.virt; + cmd = libie_aq_raw(&desc); cmd->id = cpu_to_le32(vfid); desc.cookie_high = cpu_to_le32(v_opcode); desc.cookie_low = cpu_to_le32(v_retval); if (msglen) - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd); } diff --git a/drivers/net/ethernet/intel/ice/ice_vlan_mode.c b/drivers/net/ethernet/intel/ice/ice_vlan_mode.c index 1279c1ffe31c..fb526cb84776 100644 --- a/drivers/net/ethernet/intel/ice/ice_vlan_mode.c +++ b/drivers/net/ethernet/intel/ice/ice_vlan_mode.c @@ -63,7 +63,7 @@ static int ice_aq_get_vlan_mode(struct ice_hw *hw, struct ice_aqc_get_vlan_mode *get_params) { - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (!get_params) return -EINVAL; @@ -275,7 +275,7 @@ ice_aq_set_vlan_mode(struct ice_hw *hw, struct ice_aqc_set_vlan_mode *set_params) { u8 rdma_packet, mng_vlan_prot_id; - struct ice_aq_desc desc; + struct libie_aq_desc desc; if (!set_params) return -EINVAL; @@ -295,7 +295,7 @@ ice_aq_set_vlan_mode(struct ice_hw *hw, ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_vlan_mode_parameters); - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + desc.flags |= cpu_to_le16(LIBIE_AQ_FLAG_RD); return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params), NULL); 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 5291f2888ef8..ada78f83b3ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c @@ -113,7 +113,7 @@ static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) { dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); goto out; } @@ -169,7 +169,7 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) { dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %d aq_err %s\n", - ena, err, ice_aq_str(hw->adminq.sq_last_status)); + ena, err, libie_aq_str(hw->adminq.sq_last_status)); goto out; } @@ -258,7 +258,7 @@ static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info) ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (ret) { dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n", - ret, ice_aq_str(hw->adminq.sq_last_status)); + ret, libie_aq_str(hw->adminq.sq_last_status)); goto out; } @@ -306,7 +306,7 @@ int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi) ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (ret) dev_err(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n", - ret, ice_aq_str(hw->adminq.sq_last_status)); + ret, libie_aq_str(hw->adminq.sq_last_status)); kfree(ctxt); return ret; @@ -353,7 +353,7 @@ static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) if (status) { netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %s\n", ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status, - ice_aq_str(pf->hw.adminq.sq_last_status)); + libie_aq_str(pf->hw.adminq.sq_last_status)); goto err_out; } @@ -497,7 +497,7 @@ int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN stripping failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); else vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; @@ -544,7 +544,7 @@ int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN stripping failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); else vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; @@ -604,7 +604,7 @@ int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN insertion failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); else vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; @@ -654,7 +654,7 @@ int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN insertion failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); else vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; @@ -720,7 +720,7 @@ __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) { dev_err(ice_pf_to_dev(vsi->back), "update VSI for setting outer port based VLAN failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); } else { vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan; vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; @@ -782,7 +782,7 @@ int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing outer port based VLAN failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); kfree(ctxt); return err; @@ -830,7 +830,7 @@ int ice_vsi_clear_port_vlan(struct ice_vsi *vsi) err = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (err) { dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing port based VLAN failed, err %d aq_err %s\n", - err, ice_aq_str(hw->adminq.sq_last_status)); + err, libie_aq_str(hw->adminq.sq_last_status)); } else { vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan; diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index a3a4eaa17739..575fd48f485f 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -19,52 +19,12 @@ static struct xdp_buff **ice_xdp_buf(struct ice_rx_ring *rx_ring, u32 idx) } /** - * ice_qp_reset_stats - Resets all stats for rings of given index - * @vsi: VSI that contains rings of interest - * @q_idx: ring index in array - */ -static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx) -{ - struct ice_vsi_stats *vsi_stat; - struct ice_pf *pf; - - pf = vsi->back; - if (!pf->vsi_stats) - return; - - vsi_stat = pf->vsi_stats[vsi->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->tx_ring_stats[q_idx]->stats, 0, - sizeof(vsi_stat->tx_ring_stats[q_idx]->stats)); - if (vsi->xdp_rings) - memset(&vsi->xdp_rings[q_idx]->ring_stats->stats, 0, - sizeof(vsi->xdp_rings[q_idx]->ring_stats->stats)); -} - -/** - * ice_qp_clean_rings - Cleans all the rings of a given index - * @vsi: VSI that contains rings of interest - * @q_idx: ring index in array - */ -static void ice_qp_clean_rings(struct ice_vsi *vsi, u16 q_idx) -{ - ice_clean_tx_ring(vsi->tx_rings[q_idx]); - if (vsi->xdp_rings) - ice_clean_tx_ring(vsi->xdp_rings[q_idx]); - ice_clean_rx_ring(vsi->rx_rings[q_idx]); -} - -/** * ice_qvec_toggle_napi - Enables/disables NAPI for a given q_vector * @vsi: VSI that has netdev * @q_vector: q_vector that has NAPI context * @enable: true for enable, false for disable */ -static void +void ice_qvec_toggle_napi(struct ice_vsi *vsi, struct ice_q_vector *q_vector, bool enable) { @@ -83,7 +43,7 @@ ice_qvec_toggle_napi(struct ice_vsi *vsi, struct ice_q_vector *q_vector, * @rx_ring: Rx ring that will have its IRQ disabled * @q_vector: queue vector */ -static void +void ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, struct ice_q_vector *q_vector) { @@ -113,7 +73,7 @@ ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, * @q_vector: queue vector * @qid: queue index */ -static void +void ice_qvec_cfg_msix(struct ice_vsi *vsi, struct ice_q_vector *q_vector, u16 qid) { u16 reg_idx = q_vector->reg_idx; @@ -143,7 +103,7 @@ ice_qvec_cfg_msix(struct ice_vsi *vsi, struct ice_q_vector *q_vector, u16 qid) * @vsi: the VSI that contains queue vector * @q_vector: queue vector */ -static void ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector) +void ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector) { struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; @@ -154,111 +114,6 @@ static void ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector) } /** - * ice_qp_dis - Disables a queue pair - * @vsi: VSI of interest - * @q_idx: ring index in array - * - * Returns 0 on success, negative on failure. - */ -static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) -{ - struct ice_txq_meta txq_meta = { }; - struct ice_q_vector *q_vector; - struct ice_tx_ring *tx_ring; - struct ice_rx_ring *rx_ring; - int fail = 0; - int err; - - if (q_idx >= vsi->num_rxq || q_idx >= vsi->num_txq) - return -EINVAL; - - tx_ring = vsi->tx_rings[q_idx]; - rx_ring = vsi->rx_rings[q_idx]; - q_vector = rx_ring->q_vector; - - synchronize_net(); - netif_carrier_off(vsi->netdev); - netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); - - ice_qvec_dis_irq(vsi, rx_ring, q_vector); - ice_qvec_toggle_napi(vsi, q_vector, false); - - ice_fill_txq_meta(vsi, tx_ring, &txq_meta); - err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, tx_ring, &txq_meta); - if (!fail) - fail = err; - if (vsi->xdp_rings) { - struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_idx]; - - memset(&txq_meta, 0, sizeof(txq_meta)); - ice_fill_txq_meta(vsi, xdp_ring, &txq_meta); - err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, xdp_ring, - &txq_meta); - if (!fail) - fail = err; - } - - ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, false); - ice_qp_clean_rings(vsi, q_idx); - ice_qp_reset_stats(vsi, q_idx); - - return fail; -} - -/** - * ice_qp_ena - Enables a queue pair - * @vsi: VSI of interest - * @q_idx: ring index in array - * - * Returns 0 on success, negative on failure. - */ -static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) -{ - struct ice_q_vector *q_vector; - int fail = 0; - bool link_up; - int err; - - err = ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx); - if (!fail) - fail = err; - - if (ice_is_xdp_ena_vsi(vsi)) { - struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_idx]; - - err = ice_vsi_cfg_single_txq(vsi, vsi->xdp_rings, q_idx); - if (!fail) - fail = err; - ice_set_ring_xdp(xdp_ring); - ice_tx_xsk_pool(vsi, q_idx); - } - - err = ice_vsi_cfg_single_rxq(vsi, q_idx); - if (!fail) - fail = err; - - q_vector = vsi->rx_rings[q_idx]->q_vector; - ice_qvec_cfg_msix(vsi, q_vector, q_idx); - - err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_idx, true); - if (!fail) - fail = err; - - ice_qvec_toggle_napi(vsi, q_vector, true); - ice_qvec_ena_irq(vsi, q_vector); - - /* make sure NAPI sees updated ice_{t,x}_ring::xsk_pool */ - synchronize_net(); - ice_get_link_status(vsi->port_info, &link_up); - if (link_up) { - netif_tx_start_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); - netif_carrier_on(vsi->netdev); - } - - return fail; -} - -/** * ice_xsk_pool_disable - disable a buffer pool region * @vsi: Current VSI * @qid: queue ID diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.h b/drivers/net/ethernet/intel/ice/ice_xsk.h index 8dc5d55e26c5..600cbeeaa203 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.h +++ b/drivers/net/ethernet/intel/ice/ice_xsk.h @@ -23,6 +23,13 @@ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring); void ice_xsk_clean_xdp_ring(struct ice_tx_ring *xdp_ring); bool ice_xmit_zc(struct ice_tx_ring *xdp_ring, struct xsk_buff_pool *xsk_pool); int ice_realloc_zc_buf(struct ice_vsi *vsi, bool zc); +void ice_qvec_cfg_msix(struct ice_vsi *vsi, struct ice_q_vector *q_vector, + u16 qid); +void ice_qvec_toggle_napi(struct ice_vsi *vsi, struct ice_q_vector *q_vector, + bool enable); +void ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector); +void ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, + struct ice_q_vector *q_vector); #else static inline bool ice_xmit_zc(struct ice_tx_ring __always_unused *xdp_ring, struct xsk_buff_pool __always_unused *xsk_pool) @@ -75,5 +82,20 @@ ice_realloc_zc_buf(struct ice_vsi __always_unused *vsi, { return 0; } + +static inline void +ice_qvec_cfg_msix(struct ice_vsi *vsi, struct ice_q_vector *q_vector, + u16 qid) { } + +static inline void +ice_qvec_toggle_napi(struct ice_vsi *vsi, struct ice_q_vector *q_vector, + bool enable) { } + +static inline void +ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector) { } + +static inline void +ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, + struct ice_q_vector *q_vector) { } #endif /* CONFIG_XDP_SOCKETS */ #endif /* !_ICE_XSK_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c b/drivers/net/ethernet/intel/ice/virt/allowlist.c index a3d1579a619a..a07efec19c45 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c +++ b/drivers/net/ethernet/intel/ice/virt/allowlist.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2021, Intel Corporation. */ -#include "ice_virtchnl_allowlist.h" +#include "allowlist.h" /* Purpose of this file is to share functionality to allowlist or denylist * opcodes used in PF <-> VF communication. Group of opcodes: @@ -65,7 +65,7 @@ static const u32 vlan_v2_allowlist_opcodes[] = { /* VIRTCHNL_VF_OFFLOAD_RSS_PF */ static const u32 rss_pf_allowlist_opcodes[] = { VIRTCHNL_OP_CONFIG_RSS_KEY, VIRTCHNL_OP_CONFIG_RSS_LUT, - VIRTCHNL_OP_GET_RSS_HENA_CAPS, VIRTCHNL_OP_SET_RSS_HENA, + VIRTCHNL_OP_GET_RSS_HASHCFG_CAPS, VIRTCHNL_OP_SET_RSS_HASHCFG, VIRTCHNL_OP_CONFIG_RSS_HFUNC, }; diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.h b/drivers/net/ethernet/intel/ice/virt/allowlist.h index d3ae86ded219..d3ae86ded219 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.h +++ b/drivers/net/ethernet/intel/ice/virt/allowlist.h diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/virt/fdir.c index ae83c3914e29..ae83c3914e29 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +++ b/drivers/net/ethernet/intel/ice/virt/fdir.c diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.h b/drivers/net/ethernet/intel/ice/virt/fdir.h index ac6dcab454b4..ac6dcab454b4 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.h +++ b/drivers/net/ethernet/intel/ice/virt/fdir.h diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c new file mode 100644 index 000000000000..370f6ec2a374 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/virt/queues.c @@ -0,0 +1,973 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022, Intel Corporation. */ + +#include "virtchnl.h" +#include "queues.h" +#include "ice_vf_lib_private.h" +#include "ice.h" +#include "ice_base.h" +#include "ice_lib.h" + +/** + * ice_vc_get_max_frame_size - get max frame size allowed for VF + * @vf: VF used to determine max frame size + * + * Max frame size is determined based on the current port's max frame size and + * whether a port VLAN is configured on this VF. The VF is not aware whether + * it's in a port VLAN so the PF needs to account for this in max frame size + * checks and sending the max frame size to the VF. + */ +u16 ice_vc_get_max_frame_size(struct ice_vf *vf) +{ + struct ice_port_info *pi = ice_vf_get_port_info(vf); + u16 max_frame_size; + + max_frame_size = pi->phy.link_info.max_frame_size; + + if (ice_vf_is_port_vlan_ena(vf)) + max_frame_size -= VLAN_HLEN; + + return max_frame_size; +} + +/** + * ice_vc_isvalid_q_id + * @vsi: VSI to check queue ID against + * @qid: VSI relative queue ID + * + * check for the valid queue ID + */ +static bool ice_vc_isvalid_q_id(struct ice_vsi *vsi, u16 qid) +{ + /* allocated Tx and Rx queues should be always equal for VF VSI */ + return qid < vsi->alloc_txq; +} + +/** + * ice_vc_isvalid_ring_len + * @ring_len: length of ring + * + * check for the valid ring count, should be multiple of ICE_REQ_DESC_MULTIPLE + * or zero + */ +static bool ice_vc_isvalid_ring_len(u16 ring_len) +{ + return ring_len == 0 || + (ring_len >= ICE_MIN_NUM_DESC && + ring_len <= ICE_MAX_NUM_DESC_E810 && + !(ring_len % ICE_REQ_DESC_MULTIPLE)); +} + +/** + * ice_vf_cfg_qs_bw - Configure per queue bandwidth + * @vf: pointer to the VF info + * @num_queues: number of queues to be configured + * + * Configure per queue bandwidth. + * + * Return: 0 on success or negative error value. + */ +static int ice_vf_cfg_qs_bw(struct ice_vf *vf, u16 num_queues) +{ + struct ice_hw *hw = &vf->pf->hw; + struct ice_vsi *vsi; + int ret; + u16 i; + + vsi = ice_get_vf_vsi(vf); + if (!vsi) + return -EINVAL; + + for (i = 0; i < num_queues; i++) { + u32 p_rate, min_rate; + u8 tc; + + p_rate = vf->qs_bw[i].peak; + min_rate = vf->qs_bw[i].committed; + tc = vf->qs_bw[i].tc; + if (p_rate) + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MAX_BW, p_rate); + else + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MAX_BW); + if (ret) + return ret; + + if (min_rate) + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MIN_BW, min_rate); + else + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MIN_BW); + + if (ret) + return ret; + } + + return 0; +} + +/** + * ice_vf_cfg_q_quanta_profile - Configure quanta profile + * @vf: pointer to the VF info + * @quanta_prof_idx: pointer to the quanta profile index + * @quanta_size: quanta size to be set + * + * This function chooses available quanta profile and configures the register. + * The quanta profile is evenly divided by the number of device ports, and then + * available to the specific PF and VFs. The first profile for each PF is a + * reserved default profile. Only quanta size of the rest unused profile can be + * modified. + * + * Return: 0 on success or negative error value. + */ +static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size, + u16 *quanta_prof_idx) +{ + const u16 n_desc = calc_quanta_desc(quanta_size); + struct ice_hw *hw = &vf->pf->hw; + const u16 n_cmd = 2 * n_desc; + struct ice_pf *pf = vf->pf; + u16 per_pf, begin_id; + u8 n_used; + u32 reg; + + begin_id = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / hw->dev_caps.num_funcs * + hw->logical_pf_id; + + if (quanta_size == ICE_DFLT_QUANTA) { + *quanta_prof_idx = begin_id; + } else { + per_pf = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / + hw->dev_caps.num_funcs; + n_used = pf->num_quanta_prof_used; + if (n_used < per_pf) { + *quanta_prof_idx = begin_id + 1 + n_used; + pf->num_quanta_prof_used++; + } else { + return -EINVAL; + } + } + + reg = FIELD_PREP(GLCOMM_QUANTA_PROF_QUANTA_SIZE_M, quanta_size) | + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_CMD_M, n_cmd) | + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_DESC_M, n_desc); + wr32(hw, GLCOMM_QUANTA_PROF(*quanta_prof_idx), reg); + + return 0; +} + +/** + * ice_vc_validate_vqs_bitmaps - validate Rx/Tx queue bitmaps from VIRTCHNL + * @vqs: virtchnl_queue_select structure containing bitmaps to validate + * + * Return true on successful validation, else false + */ +static bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs) +{ + if ((!vqs->rx_queues && !vqs->tx_queues) || + vqs->rx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF) || + vqs->tx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF)) + return false; + + return true; +} + +/** + * ice_vf_ena_txq_interrupt - enable Tx queue interrupt via QINT_TQCTL + * @vsi: VSI of the VF to configure + * @q_idx: VF queue index used to determine the queue in the PF's space + */ +void ice_vf_ena_txq_interrupt(struct ice_vsi *vsi, u32 q_idx) +{ + struct ice_hw *hw = &vsi->back->hw; + u32 pfq = vsi->txq_map[q_idx]; + u32 reg; + + reg = rd32(hw, QINT_TQCTL(pfq)); + + /* MSI-X index 0 in the VF's space is always for the OICR, which means + * this is most likely a poll mode VF driver, so don't enable an + * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP + */ + if (!(reg & QINT_TQCTL_MSIX_INDX_M)) + return; + + wr32(hw, QINT_TQCTL(pfq), reg | QINT_TQCTL_CAUSE_ENA_M); +} + +/** + * ice_vf_ena_rxq_interrupt - enable Tx 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 + */ +void ice_vf_ena_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)); + + /* MSI-X index 0 in the VF's space is always for the OICR, which means + * this is most likely a poll mode VF driver, so don't enable an + * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP + */ + if (!(reg & QINT_RQCTL_MSIX_INDX_M)) + return; + + wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M); +} + +/** + * ice_vc_ena_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to enable all or specific queue(s) + */ +int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; + struct ice_vsi *vsi; + unsigned long q_map; + u16 vf_q_id; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_validate_vqs_bitmaps(vqs)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* Enable only Rx rings, Tx rings were enabled by the FW when the + * Tx queue group list was configured and the context bits were + * programmed using ice_vsi_cfg_txqs + */ + q_map = vqs->rx_queues; + for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* Skip queue if enabled */ + if (test_bit(vf_q_id, vf->rxq_ena)) + continue; + + if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true)) { + dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n", + vf_q_id, vsi->vsi_num); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + ice_vf_ena_rxq_interrupt(vsi, vf_q_id); + set_bit(vf_q_id, vf->rxq_ena); + } + + q_map = vqs->tx_queues; + for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* Skip queue if enabled */ + if (test_bit(vf_q_id, vf->txq_ena)) + continue; + + ice_vf_ena_txq_interrupt(vsi, vf_q_id); + set_bit(vf_q_id, vf->txq_ena); + } + + /* Set flag to indicate that queues are enabled */ + if (v_ret == VIRTCHNL_STATUS_SUCCESS) + set_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, v_ret, + NULL, 0); +} + +/** + * ice_vf_vsi_dis_single_txq - disable a single Tx queue + * @vf: VF to disable queue for + * @vsi: VSI for the VF + * @q_id: VF relative (0-based) queue ID + * + * Attempt to disable the Tx queue passed in. If the Tx queue was successfully + * disabled then clear q_id bit in the enabled queues bitmap and return + * success. Otherwise return error. + */ +int ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id) +{ + struct ice_txq_meta txq_meta = { 0 }; + struct ice_tx_ring *ring; + int err; + + if (!test_bit(q_id, vf->txq_ena)) + dev_dbg(ice_pf_to_dev(vsi->back), "Queue %u on VSI %u is not enabled, but stopping it anyway\n", + q_id, vsi->vsi_num); + + ring = vsi->tx_rings[q_id]; + if (!ring) + return -EINVAL; + + ice_fill_txq_meta(vsi, ring, &txq_meta); + + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, vf->vf_id, ring, &txq_meta); + if (err) { + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Tx ring %d on VSI %d\n", + q_id, vsi->vsi_num); + return err; + } + + /* Clear enabled queues flag */ + clear_bit(q_id, vf->txq_ena); + + return 0; +} + +/** + * ice_vc_dis_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to disable all or specific queue(s) + */ +int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; + struct ice_vsi *vsi; + unsigned long q_map; + u16 vf_q_id; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) && + !test_bit(ICE_VF_STATE_QS_ENA, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_validate_vqs_bitmaps(vqs)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (vqs->tx_queues) { + q_map = vqs->tx_queues; + + for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (ice_vf_vsi_dis_single_txq(vf, vsi, vf_q_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + } + } + + q_map = vqs->rx_queues; + /* speed up Rx queue disable by batching them if possible */ + if (q_map && + bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) { + if (ice_vsi_stop_all_rx_rings(vsi)) { + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n", + vsi->vsi_num); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + 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) { + if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* Skip queue if not enabled */ + if (!test_bit(vf_q_id, vf->rxq_ena)) + continue; + + if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id, + true)) { + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n", + vf_q_id, vsi->vsi_num); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* Clear enabled queues flag */ + clear_bit(vf_q_id, vf->rxq_ena); + } + } + + /* Clear enabled queues flag */ + if (v_ret == VIRTCHNL_STATUS_SUCCESS && ice_vf_has_no_qs_ena(vf)) + clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, v_ret, + NULL, 0); +} + +/** + * ice_cfg_interrupt + * @vf: pointer to the VF info + * @vsi: the VSI being configured + * @map: vector map for mapping vectors to queues + * @q_vector: structure for interrupt vector + * configure the IRQ to queue map + */ +static enum virtchnl_status_code +ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi, + struct virtchnl_vector_map *map, + struct ice_q_vector *q_vector) +{ + u16 vsi_q_id, vsi_q_id_idx; + unsigned long qmap; + + q_vector->num_ring_rx = 0; + q_vector->num_ring_tx = 0; + + qmap = map->rxq_map; + for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { + vsi_q_id = vsi_q_id_idx; + + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) + return VIRTCHNL_STATUS_ERR_PARAM; + + q_vector->num_ring_rx++; + q_vector->rx.itr_idx = map->rxitr_idx; + vsi->rx_rings[vsi_q_id]->q_vector = q_vector; + ice_cfg_rxq_interrupt(vsi, vsi_q_id, + q_vector->vf_reg_idx, + q_vector->rx.itr_idx); + } + + qmap = map->txq_map; + for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { + vsi_q_id = vsi_q_id_idx; + + if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) + return VIRTCHNL_STATUS_ERR_PARAM; + + q_vector->num_ring_tx++; + q_vector->tx.itr_idx = map->txitr_idx; + vsi->tx_rings[vsi_q_id]->q_vector = q_vector; + ice_cfg_txq_interrupt(vsi, vsi_q_id, + q_vector->vf_reg_idx, + q_vector->tx.itr_idx); + } + + return VIRTCHNL_STATUS_SUCCESS; +} + +/** + * ice_vc_cfg_irq_map_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to configure the IRQ to queue map + */ +int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + u16 num_q_vectors_mapped, vsi_id, vector_id; + struct virtchnl_irq_map_info *irqmap_info; + struct virtchnl_vector_map *map; + struct ice_vsi *vsi; + int i; + + irqmap_info = (struct virtchnl_irq_map_info *)msg; + num_q_vectors_mapped = irqmap_info->num_vectors; + + /* Check to make sure number of VF vectors mapped is not greater than + * number of VF vectors originally allocated, and check that + * there is actually at least a single VF queue vector mapped + */ + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || + vf->num_msix < num_q_vectors_mapped || + !num_q_vectors_mapped) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + for (i = 0; i < num_q_vectors_mapped; i++) { + struct ice_q_vector *q_vector; + + map = &irqmap_info->vecmap[i]; + + vector_id = map->vector_id; + vsi_id = map->vsi_id; + /* vector_id is always 0-based for each VF, and can never be + * larger than or equal to the max allowed interrupts per VF + */ + if (!(vector_id < vf->num_msix) || + !ice_vc_isvalid_vsi_id(vf, vsi_id) || + (!vector_id && (map->rxq_map || map->txq_map))) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* No need to map VF miscellaneous or rogue vector */ + if (!vector_id) + continue; + + /* Subtract non queue vector from vector_id passed by VF + * to get actual number of VSI queue vector array index + */ + q_vector = vsi->q_vectors[vector_id - ICE_NONQ_VECS_VF]; + if (!q_vector) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + /* lookout for the invalid queue index */ + v_ret = ice_cfg_interrupt(vf, vsi, map, q_vector); + if (v_ret) + goto error_param; + } + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, v_ret, + NULL, 0); +} + +/** + * ice_vc_cfg_q_bw - Configure per queue bandwidth + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer which holds the command descriptor + * + * Configure VF queues bandwidth. + * + * Return: 0 on success or negative error value. + */ +int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_queues_bw_cfg *qbw = + (struct virtchnl_queues_bw_cfg *)msg; + struct ice_vsi *vsi; + u16 i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || + !ice_vc_isvalid_vsi_id(vf, qbw->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF || + qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + for (i = 0; i < qbw->num_queues; i++) { + if (qbw->cfg[i].shaper.peak != 0 && vf->max_tx_rate != 0 && + qbw->cfg[i].shaper.peak > vf->max_tx_rate) { + dev_warn(ice_pf_to_dev(vf->pf), "The maximum queue %d rate limit configuration may not take effect because the maximum TX rate for VF-%d is %d\n", + qbw->cfg[i].queue_id, vf->vf_id, + vf->max_tx_rate); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + if (qbw->cfg[i].shaper.committed != 0 && vf->min_tx_rate != 0 && + qbw->cfg[i].shaper.committed < vf->min_tx_rate) { + dev_warn(ice_pf_to_dev(vf->pf), "The minimum queue %d rate limit configuration may not take effect because the minimum TX rate for VF-%d is %d\n", + qbw->cfg[i].queue_id, vf->vf_id, + vf->min_tx_rate); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + if (qbw->cfg[i].queue_id > vf->num_vf_qs) { + dev_warn(ice_pf_to_dev(vf->pf), "VF-%d trying to configure invalid queue_id\n", + vf->vf_id); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + if (qbw->cfg[i].tc >= ICE_MAX_TRAFFIC_CLASS) { + dev_warn(ice_pf_to_dev(vf->pf), "VF-%d trying to configure a traffic class higher than allowed\n", + vf->vf_id); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + } + + for (i = 0; i < qbw->num_queues; i++) { + vf->qs_bw[i].queue_id = qbw->cfg[i].queue_id; + vf->qs_bw[i].peak = qbw->cfg[i].shaper.peak; + vf->qs_bw[i].committed = qbw->cfg[i].shaper.committed; + vf->qs_bw[i].tc = qbw->cfg[i].tc; + } + + if (ice_vf_cfg_qs_bw(vf, qbw->num_queues)) + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + +err: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUEUE_BW, + v_ret, NULL, 0); +} + +/** + * ice_vc_cfg_q_quanta - Configure per queue quanta + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer which holds the command descriptor + * + * Configure VF queues quanta. + * + * Return: 0 on success or negative error value. + */ +int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg) +{ + u16 quanta_prof_id, quanta_size, start_qid, num_queues, end_qid, i; + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_quanta_cfg *qquanta = + (struct virtchnl_quanta_cfg *)msg; + struct ice_vsi *vsi; + int ret; + + start_qid = qquanta->queue_select.start_queue_id; + num_queues = qquanta->queue_select.num_queues; + + if (check_add_overflow(start_qid, num_queues, &end_qid)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (end_qid > ICE_MAX_RSS_QS_PER_VF || + end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + quanta_size = qquanta->quanta_size; + if (quanta_size > ICE_MAX_QUANTA_SIZE || + quanta_size < ICE_MIN_QUANTA_SIZE) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (quanta_size % 64) { + dev_err(ice_pf_to_dev(vf->pf), "quanta size should be the product of 64\n"); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + ret = ice_vf_cfg_q_quanta_profile(vf, quanta_size, + &quanta_prof_id); + if (ret) { + v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; + goto err; + } + + for (i = start_qid; i < end_qid; i++) + vsi->tx_rings[i]->quanta_prof_id = quanta_prof_id; + +err: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUANTA, + v_ret, NULL, 0); +} + +/** + * ice_vc_cfg_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to configure the Rx/Tx queues + */ +int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_vsi_queue_config_info *qci = + (struct virtchnl_vsi_queue_config_info *)msg; + struct virtchnl_queue_pair_info *qpi; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + int i = -1, q_idx; + bool ena_ts; + u8 act_prt; + + mutex_lock(&pf->lag_mutex); + act_prt = ice_lag_prepare_vf_reset(pf->lag); + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + goto error_param; + + if (!ice_vc_isvalid_vsi_id(vf, qci->vsi_id)) + goto error_param; + + vsi = ice_get_vf_vsi(vf); + if (!vsi) + goto error_param; + + if (qci->num_queue_pairs > ICE_MAX_RSS_QS_PER_VF || + qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { + dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n", + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); + goto error_param; + } + + for (i = 0; i < qci->num_queue_pairs; i++) { + if (!qci->qpair[i].rxq.crc_disable) + continue; + + if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_CRC) || + vf->vlan_strip_ena) + goto error_param; + } + + for (i = 0; i < qci->num_queue_pairs; i++) { + qpi = &qci->qpair[i]; + if (qpi->txq.vsi_id != qci->vsi_id || + qpi->rxq.vsi_id != qci->vsi_id || + qpi->rxq.queue_id != qpi->txq.queue_id || + qpi->txq.headwb_enabled || + !ice_vc_isvalid_ring_len(qpi->txq.ring_len) || + !ice_vc_isvalid_ring_len(qpi->rxq.ring_len) || + !ice_vc_isvalid_q_id(vsi, qpi->txq.queue_id)) { + goto error_param; + } + + q_idx = qpi->rxq.queue_id; + + /* make sure selected "q_idx" is in valid range of queues + * for selected "vsi" + */ + if (q_idx >= vsi->alloc_txq || q_idx >= vsi->alloc_rxq) { + goto error_param; + } + + /* copy Tx queue info from VF into VSI */ + if (qpi->txq.ring_len > 0) { + vsi->tx_rings[q_idx]->dma = qpi->txq.dma_ring_addr; + vsi->tx_rings[q_idx]->count = qpi->txq.ring_len; + + /* Disable any existing queue first */ + if (ice_vf_vsi_dis_single_txq(vf, vsi, q_idx)) + goto error_param; + + /* Configure a queue with the requested settings */ + if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) { + dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure TX queue %d\n", + vf->vf_id, q_idx); + goto error_param; + } + } + + /* copy Rx queue info from VF into VSI */ + if (qpi->rxq.ring_len > 0) { + u16 max_frame_size = ice_vc_get_max_frame_size(vf); + struct ice_rx_ring *ring = vsi->rx_rings[q_idx]; + u32 rxdid; + + ring->dma = qpi->rxq.dma_ring_addr; + ring->count = qpi->rxq.ring_len; + + if (qpi->rxq.crc_disable) + ring->flags |= ICE_RX_FLAGS_CRC_STRIP_DIS; + else + ring->flags &= ~ICE_RX_FLAGS_CRC_STRIP_DIS; + + if (qpi->rxq.databuffer_size != 0 && + (qpi->rxq.databuffer_size > ((16 * 1024) - 128) || + qpi->rxq.databuffer_size < 1024)) + goto error_param; + ring->rx_buf_len = qpi->rxq.databuffer_size; + if (qpi->rxq.max_pkt_size > max_frame_size || + qpi->rxq.max_pkt_size < 64) + goto error_param; + + ring->max_frame = qpi->rxq.max_pkt_size; + /* add space for the port VLAN since the VF driver is + * not expected to account for it in the MTU + * calculation + */ + if (ice_vf_is_port_vlan_ena(vf)) + ring->max_frame += VLAN_HLEN; + + if (ice_vsi_cfg_single_rxq(vsi, q_idx)) { + dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure RX queue %d\n", + vf->vf_id, q_idx); + goto error_param; + } + + /* If Rx flex desc is supported, select RXDID for Rx + * queues. Otherwise, use legacy 32byte descriptor + * format. Legacy 16byte descriptor is not supported. + * If this RXDID is selected, return error. + */ + if (vf->driver_caps & + VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) { + rxdid = qpi->rxq.rxdid; + if (!(BIT(rxdid) & pf->supported_rxdids)) + goto error_param; + } else { + rxdid = ICE_RXDID_LEGACY_1; + } + + ena_ts = ((vf->driver_caps & + VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) && + (vf->driver_caps & VIRTCHNL_VF_CAP_PTP) && + (qpi->rxq.flags & VIRTCHNL_PTP_RX_TSTAMP)); + + ice_write_qrxflxp_cntxt(&vsi->back->hw, + vsi->rxq_map[q_idx], rxdid, + ICE_RXDID_PRIO, ena_ts); + } + } + + ice_lag_complete_vf_reset(pf->lag, act_prt); + mutex_unlock(&pf->lag_mutex); + + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, + VIRTCHNL_STATUS_SUCCESS, NULL, 0); +error_param: + /* disable whatever we can */ + for (; i >= 0; i--) { + if (ice_vsi_ctrl_one_rx_ring(vsi, false, i, true)) + dev_err(ice_pf_to_dev(pf), "VF-%d could not disable RX queue %d\n", + vf->vf_id, i); + if (ice_vf_vsi_dis_single_txq(vf, vsi, i)) + dev_err(ice_pf_to_dev(pf), "VF-%d could not disable TX queue %d\n", + vf->vf_id, i); + } + + ice_lag_complete_vf_reset(pf->lag, act_prt); + mutex_unlock(&pf->lag_mutex); + + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, + VIRTCHNL_STATUS_ERR_PARAM, NULL, 0); +} + +/** + * ice_vc_request_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * VFs get a default number of queues but can use this message to request a + * different number. If the request is successful, PF will reset the VF and + * return 0. If unsuccessful, PF will send message informing VF of number of + * available queue pairs via virtchnl message response to VF. + */ +int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_vf_res_request *vfres = + (struct virtchnl_vf_res_request *)msg; + u16 req_queues = vfres->num_queue_pairs; + struct ice_pf *pf = vf->pf; + u16 max_allowed_vf_queues; + u16 tx_rx_queue_left; + struct device *dev; + u16 cur_queues; + + dev = ice_pf_to_dev(pf); + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + cur_queues = vf->num_vf_qs; + tx_rx_queue_left = min_t(u16, ice_get_avail_txq_count(pf), + ice_get_avail_rxq_count(pf)); + max_allowed_vf_queues = tx_rx_queue_left + cur_queues; + if (!req_queues) { + dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n", + vf->vf_id); + } else if (req_queues > ICE_MAX_RSS_QS_PER_VF) { + dev_err(dev, "VF %d tried to request more than %d queues.\n", + vf->vf_id, ICE_MAX_RSS_QS_PER_VF); + vfres->num_queue_pairs = ICE_MAX_RSS_QS_PER_VF; + } else if (req_queues > cur_queues && + req_queues - cur_queues > tx_rx_queue_left) { + dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n", + vf->vf_id, req_queues - cur_queues, tx_rx_queue_left); + vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues, + ICE_MAX_RSS_QS_PER_VF); + } else { + /* request is successful, then reset VF */ + vf->num_req_qs = req_queues; + ice_reset_vf(vf, ICE_VF_RESET_NOTIFY); + dev_info(dev, "VF %d granted request of %u queues.\n", + vf->vf_id, req_queues); + return 0; + } + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, + v_ret, (u8 *)vfres, sizeof(*vfres)); +} + diff --git a/drivers/net/ethernet/intel/ice/virt/queues.h b/drivers/net/ethernet/intel/ice/virt/queues.h new file mode 100644 index 000000000000..c4a792cecea1 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/virt/queues.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2022, Intel Corporation. */ + +#ifndef _ICE_VIRT_QUEUES_H_ +#define _ICE_VIRT_QUEUES_H_ + +#include <linux/types.h> + +struct ice_vf; + +u16 ice_vc_get_max_frame_size(struct ice_vf *vf); +int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg); +int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg); +int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg); +int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg); +int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg); +int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg); +int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg); + +#endif /* _ICE_VIRT_QUEUES_H_ */ diff --git a/drivers/net/ethernet/intel/ice/virt/rss.c b/drivers/net/ethernet/intel/ice/virt/rss.c new file mode 100644 index 000000000000..cbdbb32d512b --- /dev/null +++ b/drivers/net/ethernet/intel/ice/virt/rss.c @@ -0,0 +1,719 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022, Intel Corporation. */ + +#include "rss.h" +#include "ice_vf_lib_private.h" +#include "ice.h" + +#define FIELD_SELECTOR(proto_hdr_field) \ + BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK) + +struct ice_vc_hdr_match_type { + u32 vc_hdr; /* virtchnl headers (VIRTCHNL_PROTO_HDR_XXX) */ + u32 ice_hdr; /* ice headers (ICE_FLOW_SEG_HDR_XXX) */ +}; + +static const struct ice_vc_hdr_match_type ice_vc_hdr_list[] = { + {VIRTCHNL_PROTO_HDR_NONE, ICE_FLOW_SEG_HDR_NONE}, + {VIRTCHNL_PROTO_HDR_ETH, ICE_FLOW_SEG_HDR_ETH}, + {VIRTCHNL_PROTO_HDR_S_VLAN, ICE_FLOW_SEG_HDR_VLAN}, + {VIRTCHNL_PROTO_HDR_C_VLAN, ICE_FLOW_SEG_HDR_VLAN}, + {VIRTCHNL_PROTO_HDR_IPV4, ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER}, + {VIRTCHNL_PROTO_HDR_IPV6, ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER}, + {VIRTCHNL_PROTO_HDR_TCP, ICE_FLOW_SEG_HDR_TCP}, + {VIRTCHNL_PROTO_HDR_UDP, ICE_FLOW_SEG_HDR_UDP}, + {VIRTCHNL_PROTO_HDR_SCTP, ICE_FLOW_SEG_HDR_SCTP}, + {VIRTCHNL_PROTO_HDR_PPPOE, ICE_FLOW_SEG_HDR_PPPOE}, + {VIRTCHNL_PROTO_HDR_GTPU_IP, ICE_FLOW_SEG_HDR_GTPU_IP}, + {VIRTCHNL_PROTO_HDR_GTPU_EH, ICE_FLOW_SEG_HDR_GTPU_EH}, + {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN, + ICE_FLOW_SEG_HDR_GTPU_DWN}, + {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP, + ICE_FLOW_SEG_HDR_GTPU_UP}, + {VIRTCHNL_PROTO_HDR_L2TPV3, ICE_FLOW_SEG_HDR_L2TPV3}, + {VIRTCHNL_PROTO_HDR_ESP, ICE_FLOW_SEG_HDR_ESP}, + {VIRTCHNL_PROTO_HDR_AH, ICE_FLOW_SEG_HDR_AH}, + {VIRTCHNL_PROTO_HDR_PFCP, ICE_FLOW_SEG_HDR_PFCP_SESSION}, +}; + +struct ice_vc_hash_field_match_type { + u32 vc_hdr; /* virtchnl headers + * (VIRTCHNL_PROTO_HDR_XXX) + */ + u32 vc_hash_field; /* virtchnl hash fields selector + * FIELD_SELECTOR((VIRTCHNL_PROTO_HDR_ETH_XXX)) + */ + u64 ice_hash_field; /* ice hash fields + * (BIT_ULL(ICE_FLOW_FIELD_IDX_XXX)) + */ +}; + +static const struct +ice_vc_hash_field_match_type ice_vc_hash_field_list[] = { + {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC), + BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA)}, + {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), + BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA)}, + {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), + ICE_FLOW_HASH_ETH}, + {VIRTCHNL_PROTO_HDR_ETH, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE), + BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE)}, + {VIRTCHNL_PROTO_HDR_S_VLAN, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_S_VLAN_ID), + BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN)}, + {VIRTCHNL_PROTO_HDR_C_VLAN, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_C_VLAN_ID), + BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), + ICE_FLOW_HASH_IPV4}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) | + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) | + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), + ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), + ICE_FLOW_HASH_IPV6}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) | + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) | + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), + ICE_FLOW_HASH_IPV6 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, + {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), + BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, + {VIRTCHNL_PROTO_HDR_TCP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)}, + {VIRTCHNL_PROTO_HDR_TCP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)}, + {VIRTCHNL_PROTO_HDR_TCP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), + ICE_FLOW_HASH_TCP_PORT}, + {VIRTCHNL_PROTO_HDR_UDP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)}, + {VIRTCHNL_PROTO_HDR_UDP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)}, + {VIRTCHNL_PROTO_HDR_UDP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), + ICE_FLOW_HASH_UDP_PORT}, + {VIRTCHNL_PROTO_HDR_SCTP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)}, + {VIRTCHNL_PROTO_HDR_SCTP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), + BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)}, + {VIRTCHNL_PROTO_HDR_SCTP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) | + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), + ICE_FLOW_HASH_SCTP_PORT}, + {VIRTCHNL_PROTO_HDR_PPPOE, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PPPOE_SESS_ID), + BIT_ULL(ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID)}, + {VIRTCHNL_PROTO_HDR_GTPU_IP, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPU_IP_TEID), + BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID)}, + {VIRTCHNL_PROTO_HDR_L2TPV3, + FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID), + BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID)}, + {VIRTCHNL_PROTO_HDR_ESP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ESP_SPI), + BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI)}, + {VIRTCHNL_PROTO_HDR_AH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_AH_SPI), + BIT_ULL(ICE_FLOW_FIELD_IDX_AH_SPI)}, + {VIRTCHNL_PROTO_HDR_PFCP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PFCP_SEID), + BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)}, +}; + +/** + * ice_vc_validate_pattern + * @vf: pointer to the VF info + * @proto: virtchnl protocol headers + * + * validate the pattern is supported or not. + * + * Return: true on success, false on error. + */ +bool +ice_vc_validate_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto) +{ + bool is_ipv4 = false; + bool is_ipv6 = false; + bool is_udp = false; + u16 ptype = -1; + int i = 0; + + while (i < proto->count && + proto->proto_hdr[i].type != VIRTCHNL_PROTO_HDR_NONE) { + switch (proto->proto_hdr[i].type) { + case VIRTCHNL_PROTO_HDR_ETH: + ptype = ICE_PTYPE_MAC_PAY; + break; + case VIRTCHNL_PROTO_HDR_IPV4: + ptype = ICE_PTYPE_IPV4_PAY; + is_ipv4 = true; + break; + case VIRTCHNL_PROTO_HDR_IPV6: + ptype = ICE_PTYPE_IPV6_PAY; + is_ipv6 = true; + break; + case VIRTCHNL_PROTO_HDR_UDP: + if (is_ipv4) + ptype = ICE_PTYPE_IPV4_UDP_PAY; + else if (is_ipv6) + ptype = ICE_PTYPE_IPV6_UDP_PAY; + is_udp = true; + break; + case VIRTCHNL_PROTO_HDR_TCP: + if (is_ipv4) + ptype = ICE_PTYPE_IPV4_TCP_PAY; + else if (is_ipv6) + ptype = ICE_PTYPE_IPV6_TCP_PAY; + break; + case VIRTCHNL_PROTO_HDR_SCTP: + if (is_ipv4) + ptype = ICE_PTYPE_IPV4_SCTP_PAY; + else if (is_ipv6) + ptype = ICE_PTYPE_IPV6_SCTP_PAY; + break; + case VIRTCHNL_PROTO_HDR_GTPU_IP: + case VIRTCHNL_PROTO_HDR_GTPU_EH: + if (is_ipv4) + ptype = ICE_MAC_IPV4_GTPU; + else if (is_ipv6) + ptype = ICE_MAC_IPV6_GTPU; + goto out; + case VIRTCHNL_PROTO_HDR_L2TPV3: + if (is_ipv4) + ptype = ICE_MAC_IPV4_L2TPV3; + else if (is_ipv6) + ptype = ICE_MAC_IPV6_L2TPV3; + goto out; + case VIRTCHNL_PROTO_HDR_ESP: + if (is_ipv4) + ptype = is_udp ? ICE_MAC_IPV4_NAT_T_ESP : + ICE_MAC_IPV4_ESP; + else if (is_ipv6) + ptype = is_udp ? ICE_MAC_IPV6_NAT_T_ESP : + ICE_MAC_IPV6_ESP; + goto out; + case VIRTCHNL_PROTO_HDR_AH: + if (is_ipv4) + ptype = ICE_MAC_IPV4_AH; + else if (is_ipv6) + ptype = ICE_MAC_IPV6_AH; + goto out; + case VIRTCHNL_PROTO_HDR_PFCP: + if (is_ipv4) + ptype = ICE_MAC_IPV4_PFCP_SESSION; + else if (is_ipv6) + ptype = ICE_MAC_IPV6_PFCP_SESSION; + goto out; + default: + break; + } + i++; + } + +out: + return ice_hw_ptype_ena(&vf->pf->hw, ptype); +} + +/** + * ice_vc_parse_rss_cfg - parses hash fields and headers from + * a specific virtchnl RSS cfg + * @hw: pointer to the hardware + * @rss_cfg: pointer to the virtchnl RSS cfg + * @hash_cfg: pointer to the HW hash configuration + * + * Return true if all the protocol header and hash fields in the RSS cfg could + * be parsed, else return false + * + * This function parses the virtchnl RSS cfg to be the intended + * hash fields and the intended header for RSS configuration + */ +static bool ice_vc_parse_rss_cfg(struct ice_hw *hw, + struct virtchnl_rss_cfg *rss_cfg, + struct ice_rss_hash_cfg *hash_cfg) +{ + const struct ice_vc_hash_field_match_type *hf_list; + const struct ice_vc_hdr_match_type *hdr_list; + int i, hf_list_len, hdr_list_len; + u32 *addl_hdrs = &hash_cfg->addl_hdrs; + u64 *hash_flds = &hash_cfg->hash_flds; + + /* set outer layer RSS as default */ + hash_cfg->hdr_type = ICE_RSS_OUTER_HEADERS; + + if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) + hash_cfg->symm = true; + else + hash_cfg->symm = false; + + hf_list = ice_vc_hash_field_list; + hf_list_len = ARRAY_SIZE(ice_vc_hash_field_list); + hdr_list = ice_vc_hdr_list; + hdr_list_len = ARRAY_SIZE(ice_vc_hdr_list); + + for (i = 0; i < rss_cfg->proto_hdrs.count; i++) { + struct virtchnl_proto_hdr *proto_hdr = + &rss_cfg->proto_hdrs.proto_hdr[i]; + bool hdr_found = false; + int j; + + /* Find matched ice headers according to virtchnl headers. */ + for (j = 0; j < hdr_list_len; j++) { + struct ice_vc_hdr_match_type hdr_map = hdr_list[j]; + + if (proto_hdr->type == hdr_map.vc_hdr) { + *addl_hdrs |= hdr_map.ice_hdr; + hdr_found = true; + } + } + + if (!hdr_found) + return false; + + /* Find matched ice hash fields according to + * virtchnl hash fields. + */ + for (j = 0; j < hf_list_len; j++) { + struct ice_vc_hash_field_match_type hf_map = hf_list[j]; + + if (proto_hdr->type == hf_map.vc_hdr && + proto_hdr->field_selector == hf_map.vc_hash_field) { + *hash_flds |= hf_map.ice_hash_field; + break; + } + } + } + + return true; +} + +/** + * ice_vf_adv_rss_offload_ena - determine if capabilities support advanced + * RSS offloads + * @caps: VF driver negotiated capabilities + * + * Return true if VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF capability is set, + * else return false + */ +static bool ice_vf_adv_rss_offload_ena(u32 caps) +{ + return !!(caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF); +} + +/** + * ice_vc_handle_rss_cfg + * @vf: pointer to the VF info + * @msg: pointer to the message buffer + * @add: add a RSS config if true, otherwise delete a RSS config + * + * This function adds/deletes a RSS config + */ +int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add) +{ + u32 v_opcode = add ? VIRTCHNL_OP_ADD_RSS_CFG : VIRTCHNL_OP_DEL_RSS_CFG; + struct virtchnl_rss_cfg *rss_cfg = (struct virtchnl_rss_cfg *)msg; + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct device *dev = ice_pf_to_dev(vf->pf); + struct ice_hw *hw = &vf->pf->hw; + struct ice_vsi *vsi; + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + dev_dbg(dev, "VF %d attempting to configure RSS, but RSS is not supported by the PF\n", + vf->vf_id); + v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; + goto error_param; + } + + if (!ice_vf_adv_rss_offload_ena(vf->driver_caps)) { + dev_dbg(dev, "VF %d attempting to configure RSS, but Advanced RSS offload is not supported\n", + vf->vf_id); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (rss_cfg->proto_hdrs.count > VIRTCHNL_MAX_NUM_PROTO_HDRS || + rss_cfg->rss_algorithm < VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC || + rss_cfg->rss_algorithm > VIRTCHNL_RSS_ALG_XOR_SYMMETRIC) { + dev_dbg(dev, "VF %d attempting to configure RSS, but RSS configuration is not valid\n", + vf->vf_id); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) { + struct ice_vsi_ctx *ctx; + u8 lut_type, hash_type; + int status; + + lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; + hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR : + ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; + goto error_param; + } + + ctx->info.q_opt_rss = + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) | + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type); + + /* Preserve existing queueing option setting */ + ctx->info.q_opt_rss |= (vsi->info.q_opt_rss & + ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M); + ctx->info.q_opt_tc = vsi->info.q_opt_tc; + ctx->info.q_opt_flags = vsi->info.q_opt_rss; + + ctx->info.valid_sections = + cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); + + status = ice_update_vsi(hw, vsi->idx, ctx, NULL); + if (status) { + dev_err(dev, "update VSI for RSS failed, err %d aq_err %s\n", + status, libie_aq_str(hw->adminq.sq_last_status)); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + } else { + vsi->info.q_opt_rss = ctx->info.q_opt_rss; + } + + kfree(ctx); + } else { + struct ice_rss_hash_cfg cfg; + + /* Only check for none raw pattern case */ + if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + cfg.addl_hdrs = ICE_FLOW_SEG_HDR_NONE; + cfg.hash_flds = ICE_HASH_INVALID; + cfg.hdr_type = ICE_RSS_ANY_HEADERS; + + if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &cfg)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (add) { + if (ice_add_rss_cfg(hw, vsi, &cfg)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + dev_err(dev, "ice_add_rss_cfg failed for vsi = %d, v_ret = %d\n", + vsi->vsi_num, v_ret); + } + } else { + int status; + + status = ice_rem_rss_cfg(hw, vsi->idx, &cfg); + /* We just ignore -ENOENT, because if two configurations + * share the same profile remove one of them actually + * removes both, since the profile is deleted. + */ + if (status && status != -ENOENT) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + dev_err(dev, "ice_rem_rss_cfg failed for VF ID:%d, error:%d\n", + vf->vf_id, status); + } + } + } + +error_param: + return ice_vc_send_msg_to_vf(vf, v_opcode, v_ret, NULL, 0); +} + +/** + * ice_vc_config_rss_key + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Configure the VF's RSS key + */ +int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_rss_key *vrk = + (struct virtchnl_rss_key *)msg; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (ice_set_rss_key(vsi, vrk->key)) + v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, v_ret, + NULL, 0); +} + +/** + * ice_vc_config_rss_lut + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Configure the VF's RSS LUT + */ +int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (vrl->lut_entries != ICE_LUT_VSI_SIZE) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE)) + v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret, + NULL, 0); +} + +/** + * ice_vc_config_rss_hfunc + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Configure the VF's RSS Hash function + */ +int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_rss_hfunc *vrh = (struct virtchnl_rss_hfunc *)msg; + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vrh->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + + if (vrh->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) + hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ; + + if (ice_set_rss_hfunc(vsi, hfunc)) + v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_HFUNC, v_ret, + NULL, 0); +} + +/** + * ice_vc_get_rss_hashcfg - return the RSS Hash configuration + * @vf: pointer to the VF info + */ +int ice_vc_get_rss_hashcfg(struct ice_vf *vf) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_rss_hashcfg *vrh = NULL; + int len = 0, ret; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + dev_err(ice_pf_to_dev(vf->pf), "RSS not supported by PF\n"); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + len = sizeof(struct virtchnl_rss_hashcfg); + vrh = kzalloc(len, GFP_KERNEL); + if (!vrh) { + v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; + len = 0; + goto err; + } + + vrh->hashcfg = ICE_DEFAULT_RSS_HASHCFG; +err: + /* send the response back to the VF */ + ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HASHCFG_CAPS, v_ret, + (u8 *)vrh, len); + kfree(vrh); + return ret; +} + +/** + * ice_vc_set_rss_hashcfg - set RSS Hash configuration bits for the VF + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + */ +int ice_vc_set_rss_hashcfg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_rss_hashcfg *vrh = (struct virtchnl_rss_hashcfg *)msg; + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + struct device *dev; + int status; + + dev = ice_pf_to_dev(pf); + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { + dev_err(dev, "RSS not supported by PF\n"); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + /* clear all previously programmed RSS configuration to allow VF drivers + * the ability to customize the RSS configuration and/or completely + * disable RSS + */ + status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); + if (status && !vrh->hashcfg) { + /* only report failure to clear the current RSS configuration if + * that was clearly the VF's intention (i.e. vrh->hashcfg = 0) + */ + v_ret = ice_err_to_virt_err(status); + goto err; + } else if (status) { + /* allow the VF to update the RSS configuration even on failure + * to clear the current RSS confguration in an attempt to keep + * RSS in a working state + */ + dev_warn(dev, "Failed to clear the RSS configuration for VF %u\n", + vf->vf_id); + } + + if (vrh->hashcfg) { + status = ice_add_avf_rss_cfg(&pf->hw, vsi, vrh->hashcfg); + v_ret = ice_err_to_virt_err(status); + } + + /* save the requested VF configuration */ + if (!v_ret) + vf->rss_hashcfg = vrh->hashcfg; + + /* send the response to the VF */ +err: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_SET_RSS_HASHCFG, v_ret, + NULL, 0); +} + diff --git a/drivers/net/ethernet/intel/ice/virt/rss.h b/drivers/net/ethernet/intel/ice/virt/rss.h new file mode 100644 index 000000000000..784d4c43ce8b --- /dev/null +++ b/drivers/net/ethernet/intel/ice/virt/rss.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2022, Intel Corporation. */ + +#ifndef _ICE_VIRT_RSS_H_ +#define _ICE_VIRT_RSS_H_ + +#include <linux/types.h> + +struct ice_vf; + +int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add); +int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg); +int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg); +int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg); +int ice_vc_get_rss_hashcfg(struct ice_vf *vf); +int ice_vc_set_rss_hashcfg(struct ice_vf *vf, u8 *msg); + +#endif /* _ICE_VIRT_RSS_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/virt/virtchnl.c index eeeb9968e477..f3f921134379 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.c @@ -1,170 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2022, Intel Corporation. */ -#include "ice_virtchnl.h" +#include "virtchnl.h" +#include "queues.h" +#include "rss.h" #include "ice_vf_lib_private.h" #include "ice.h" #include "ice_base.h" #include "ice_lib.h" #include "ice_fltr.h" -#include "ice_virtchnl_allowlist.h" +#include "allowlist.h" #include "ice_vf_vsi_vlan_ops.h" #include "ice_vlan.h" #include "ice_flex_pipe.h" #include "ice_dcb_lib.h" -#define FIELD_SELECTOR(proto_hdr_field) \ - BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK) - -struct ice_vc_hdr_match_type { - u32 vc_hdr; /* virtchnl headers (VIRTCHNL_PROTO_HDR_XXX) */ - u32 ice_hdr; /* ice headers (ICE_FLOW_SEG_HDR_XXX) */ -}; - -static const struct ice_vc_hdr_match_type ice_vc_hdr_list[] = { - {VIRTCHNL_PROTO_HDR_NONE, ICE_FLOW_SEG_HDR_NONE}, - {VIRTCHNL_PROTO_HDR_ETH, ICE_FLOW_SEG_HDR_ETH}, - {VIRTCHNL_PROTO_HDR_S_VLAN, ICE_FLOW_SEG_HDR_VLAN}, - {VIRTCHNL_PROTO_HDR_C_VLAN, ICE_FLOW_SEG_HDR_VLAN}, - {VIRTCHNL_PROTO_HDR_IPV4, ICE_FLOW_SEG_HDR_IPV4 | - ICE_FLOW_SEG_HDR_IPV_OTHER}, - {VIRTCHNL_PROTO_HDR_IPV6, ICE_FLOW_SEG_HDR_IPV6 | - ICE_FLOW_SEG_HDR_IPV_OTHER}, - {VIRTCHNL_PROTO_HDR_TCP, ICE_FLOW_SEG_HDR_TCP}, - {VIRTCHNL_PROTO_HDR_UDP, ICE_FLOW_SEG_HDR_UDP}, - {VIRTCHNL_PROTO_HDR_SCTP, ICE_FLOW_SEG_HDR_SCTP}, - {VIRTCHNL_PROTO_HDR_PPPOE, ICE_FLOW_SEG_HDR_PPPOE}, - {VIRTCHNL_PROTO_HDR_GTPU_IP, ICE_FLOW_SEG_HDR_GTPU_IP}, - {VIRTCHNL_PROTO_HDR_GTPU_EH, ICE_FLOW_SEG_HDR_GTPU_EH}, - {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN, - ICE_FLOW_SEG_HDR_GTPU_DWN}, - {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP, - ICE_FLOW_SEG_HDR_GTPU_UP}, - {VIRTCHNL_PROTO_HDR_L2TPV3, ICE_FLOW_SEG_HDR_L2TPV3}, - {VIRTCHNL_PROTO_HDR_ESP, ICE_FLOW_SEG_HDR_ESP}, - {VIRTCHNL_PROTO_HDR_AH, ICE_FLOW_SEG_HDR_AH}, - {VIRTCHNL_PROTO_HDR_PFCP, ICE_FLOW_SEG_HDR_PFCP_SESSION}, -}; - -struct ice_vc_hash_field_match_type { - u32 vc_hdr; /* virtchnl headers - * (VIRTCHNL_PROTO_HDR_XXX) - */ - u32 vc_hash_field; /* virtchnl hash fields selector - * FIELD_SELECTOR((VIRTCHNL_PROTO_HDR_ETH_XXX)) - */ - u64 ice_hash_field; /* ice hash fields - * (BIT_ULL(ICE_FLOW_FIELD_IDX_XXX)) - */ -}; - -static const struct -ice_vc_hash_field_match_type ice_vc_hash_field_list[] = { - {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC), - BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA)}, - {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), - BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA)}, - {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), - ICE_FLOW_HASH_ETH}, - {VIRTCHNL_PROTO_HDR_ETH, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE), - BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE)}, - {VIRTCHNL_PROTO_HDR_S_VLAN, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_S_VLAN_ID), - BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN)}, - {VIRTCHNL_PROTO_HDR_C_VLAN, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_C_VLAN_ID), - BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), - ICE_FLOW_HASH_IPV4}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) | - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) | - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), - ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), - ICE_FLOW_HASH_IPV6}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) | - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) | - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), - ICE_FLOW_HASH_IPV6 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, - {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), - BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, - {VIRTCHNL_PROTO_HDR_TCP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)}, - {VIRTCHNL_PROTO_HDR_TCP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)}, - {VIRTCHNL_PROTO_HDR_TCP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), - ICE_FLOW_HASH_TCP_PORT}, - {VIRTCHNL_PROTO_HDR_UDP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)}, - {VIRTCHNL_PROTO_HDR_UDP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)}, - {VIRTCHNL_PROTO_HDR_UDP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), - ICE_FLOW_HASH_UDP_PORT}, - {VIRTCHNL_PROTO_HDR_SCTP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)}, - {VIRTCHNL_PROTO_HDR_SCTP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), - BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)}, - {VIRTCHNL_PROTO_HDR_SCTP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) | - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), - ICE_FLOW_HASH_SCTP_PORT}, - {VIRTCHNL_PROTO_HDR_PPPOE, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PPPOE_SESS_ID), - BIT_ULL(ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID)}, - {VIRTCHNL_PROTO_HDR_GTPU_IP, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPU_IP_TEID), - BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID)}, - {VIRTCHNL_PROTO_HDR_L2TPV3, - FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID), - BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID)}, - {VIRTCHNL_PROTO_HDR_ESP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ESP_SPI), - BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI)}, - {VIRTCHNL_PROTO_HDR_AH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_AH_SPI), - BIT_ULL(ICE_FLOW_FIELD_IDX_AH_SPI)}, - {VIRTCHNL_PROTO_HDR_PFCP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PFCP_SEID), - BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)}, -}; - /** * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF * @pf: pointer to the PF structure @@ -304,10 +154,10 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval, msg, msglen, NULL); - if (aq_ret && pf->hw.mailboxq.sq_last_status != ICE_AQ_RC_ENOSYS) { + if (aq_ret && pf->hw.mailboxq.sq_last_status != LIBIE_AQ_RC_ENOSYS) { dev_info(dev, "Unable to send the message to VF %d ret %d aq_err %s\n", vf->vf_id, aq_ret, - ice_aq_str(pf->hw.mailboxq.sq_last_status)); + libie_aq_str(pf->hw.mailboxq.sq_last_status)); return -EIO; } @@ -338,28 +188,6 @@ static int ice_vc_get_ver_msg(struct ice_vf *vf, u8 *msg) } /** - * ice_vc_get_max_frame_size - get max frame size allowed for VF - * @vf: VF used to determine max frame size - * - * Max frame size is determined based on the current port's max frame size and - * whether a port VLAN is configured on this VF. The VF is not aware whether - * it's in a port VLAN so the PF needs to account for this in max frame size - * checks and sending the max frame size to the VF. - */ -static u16 ice_vc_get_max_frame_size(struct ice_vf *vf) -{ - struct ice_port_info *pi = ice_vf_get_port_info(vf); - u16 max_frame_size; - - max_frame_size = pi->phy.link_info.max_frame_size; - - if (ice_vf_is_port_vlan_ena(vf)) - max_frame_size -= VLAN_HLEN; - - return max_frame_size; -} - -/** * ice_vc_get_vlan_caps * @hw: pointer to the hw * @vf: pointer to the VF info @@ -559,488 +387,6 @@ bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) } /** - * ice_vc_isvalid_q_id - * @vsi: VSI to check queue ID against - * @qid: VSI relative queue ID - * - * check for the valid queue ID - */ -static bool ice_vc_isvalid_q_id(struct ice_vsi *vsi, u16 qid) -{ - /* allocated Tx and Rx queues should be always equal for VF VSI */ - return qid < vsi->alloc_txq; -} - -/** - * ice_vc_isvalid_ring_len - * @ring_len: length of ring - * - * check for the valid ring count, should be multiple of ICE_REQ_DESC_MULTIPLE - * or zero - */ -static bool ice_vc_isvalid_ring_len(u16 ring_len) -{ - return ring_len == 0 || - (ring_len >= ICE_MIN_NUM_DESC && - ring_len <= ICE_MAX_NUM_DESC && - !(ring_len % ICE_REQ_DESC_MULTIPLE)); -} - -/** - * ice_vc_validate_pattern - * @vf: pointer to the VF info - * @proto: virtchnl protocol headers - * - * validate the pattern is supported or not. - * - * Return: true on success, false on error. - */ -bool -ice_vc_validate_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto) -{ - bool is_ipv4 = false; - bool is_ipv6 = false; - bool is_udp = false; - u16 ptype = -1; - int i = 0; - - while (i < proto->count && - proto->proto_hdr[i].type != VIRTCHNL_PROTO_HDR_NONE) { - switch (proto->proto_hdr[i].type) { - case VIRTCHNL_PROTO_HDR_ETH: - ptype = ICE_PTYPE_MAC_PAY; - break; - case VIRTCHNL_PROTO_HDR_IPV4: - ptype = ICE_PTYPE_IPV4_PAY; - is_ipv4 = true; - break; - case VIRTCHNL_PROTO_HDR_IPV6: - ptype = ICE_PTYPE_IPV6_PAY; - is_ipv6 = true; - break; - case VIRTCHNL_PROTO_HDR_UDP: - if (is_ipv4) - ptype = ICE_PTYPE_IPV4_UDP_PAY; - else if (is_ipv6) - ptype = ICE_PTYPE_IPV6_UDP_PAY; - is_udp = true; - break; - case VIRTCHNL_PROTO_HDR_TCP: - if (is_ipv4) - ptype = ICE_PTYPE_IPV4_TCP_PAY; - else if (is_ipv6) - ptype = ICE_PTYPE_IPV6_TCP_PAY; - break; - case VIRTCHNL_PROTO_HDR_SCTP: - if (is_ipv4) - ptype = ICE_PTYPE_IPV4_SCTP_PAY; - else if (is_ipv6) - ptype = ICE_PTYPE_IPV6_SCTP_PAY; - break; - case VIRTCHNL_PROTO_HDR_GTPU_IP: - case VIRTCHNL_PROTO_HDR_GTPU_EH: - if (is_ipv4) - ptype = ICE_MAC_IPV4_GTPU; - else if (is_ipv6) - ptype = ICE_MAC_IPV6_GTPU; - goto out; - case VIRTCHNL_PROTO_HDR_L2TPV3: - if (is_ipv4) - ptype = ICE_MAC_IPV4_L2TPV3; - else if (is_ipv6) - ptype = ICE_MAC_IPV6_L2TPV3; - goto out; - case VIRTCHNL_PROTO_HDR_ESP: - if (is_ipv4) - ptype = is_udp ? ICE_MAC_IPV4_NAT_T_ESP : - ICE_MAC_IPV4_ESP; - else if (is_ipv6) - ptype = is_udp ? ICE_MAC_IPV6_NAT_T_ESP : - ICE_MAC_IPV6_ESP; - goto out; - case VIRTCHNL_PROTO_HDR_AH: - if (is_ipv4) - ptype = ICE_MAC_IPV4_AH; - else if (is_ipv6) - ptype = ICE_MAC_IPV6_AH; - goto out; - case VIRTCHNL_PROTO_HDR_PFCP: - if (is_ipv4) - ptype = ICE_MAC_IPV4_PFCP_SESSION; - else if (is_ipv6) - ptype = ICE_MAC_IPV6_PFCP_SESSION; - goto out; - default: - break; - } - i++; - } - -out: - return ice_hw_ptype_ena(&vf->pf->hw, ptype); -} - -/** - * ice_vc_parse_rss_cfg - parses hash fields and headers from - * a specific virtchnl RSS cfg - * @hw: pointer to the hardware - * @rss_cfg: pointer to the virtchnl RSS cfg - * @hash_cfg: pointer to the HW hash configuration - * - * Return true if all the protocol header and hash fields in the RSS cfg could - * be parsed, else return false - * - * This function parses the virtchnl RSS cfg to be the intended - * hash fields and the intended header for RSS configuration - */ -static bool ice_vc_parse_rss_cfg(struct ice_hw *hw, - struct virtchnl_rss_cfg *rss_cfg, - struct ice_rss_hash_cfg *hash_cfg) -{ - const struct ice_vc_hash_field_match_type *hf_list; - const struct ice_vc_hdr_match_type *hdr_list; - int i, hf_list_len, hdr_list_len; - u32 *addl_hdrs = &hash_cfg->addl_hdrs; - u64 *hash_flds = &hash_cfg->hash_flds; - - /* set outer layer RSS as default */ - hash_cfg->hdr_type = ICE_RSS_OUTER_HEADERS; - - if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) - hash_cfg->symm = true; - else - hash_cfg->symm = false; - - hf_list = ice_vc_hash_field_list; - hf_list_len = ARRAY_SIZE(ice_vc_hash_field_list); - hdr_list = ice_vc_hdr_list; - hdr_list_len = ARRAY_SIZE(ice_vc_hdr_list); - - for (i = 0; i < rss_cfg->proto_hdrs.count; i++) { - struct virtchnl_proto_hdr *proto_hdr = - &rss_cfg->proto_hdrs.proto_hdr[i]; - bool hdr_found = false; - int j; - - /* Find matched ice headers according to virtchnl headers. */ - for (j = 0; j < hdr_list_len; j++) { - struct ice_vc_hdr_match_type hdr_map = hdr_list[j]; - - if (proto_hdr->type == hdr_map.vc_hdr) { - *addl_hdrs |= hdr_map.ice_hdr; - hdr_found = true; - } - } - - if (!hdr_found) - return false; - - /* Find matched ice hash fields according to - * virtchnl hash fields. - */ - for (j = 0; j < hf_list_len; j++) { - struct ice_vc_hash_field_match_type hf_map = hf_list[j]; - - if (proto_hdr->type == hf_map.vc_hdr && - proto_hdr->field_selector == hf_map.vc_hash_field) { - *hash_flds |= hf_map.ice_hash_field; - break; - } - } - } - - return true; -} - -/** - * ice_vf_adv_rss_offload_ena - determine if capabilities support advanced - * RSS offloads - * @caps: VF driver negotiated capabilities - * - * Return true if VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF capability is set, - * else return false - */ -static bool ice_vf_adv_rss_offload_ena(u32 caps) -{ - return !!(caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF); -} - -/** - * ice_vc_handle_rss_cfg - * @vf: pointer to the VF info - * @msg: pointer to the message buffer - * @add: add a RSS config if true, otherwise delete a RSS config - * - * This function adds/deletes a RSS config - */ -static int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add) -{ - u32 v_opcode = add ? VIRTCHNL_OP_ADD_RSS_CFG : VIRTCHNL_OP_DEL_RSS_CFG; - struct virtchnl_rss_cfg *rss_cfg = (struct virtchnl_rss_cfg *)msg; - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct device *dev = ice_pf_to_dev(vf->pf); - struct ice_hw *hw = &vf->pf->hw; - struct ice_vsi *vsi; - - if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { - dev_dbg(dev, "VF %d attempting to configure RSS, but RSS is not supported by the PF\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; - goto error_param; - } - - if (!ice_vf_adv_rss_offload_ena(vf->driver_caps)) { - dev_dbg(dev, "VF %d attempting to configure RSS, but Advanced RSS offload is not supported\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (rss_cfg->proto_hdrs.count > VIRTCHNL_MAX_NUM_PROTO_HDRS || - rss_cfg->rss_algorithm < VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC || - rss_cfg->rss_algorithm > VIRTCHNL_RSS_ALG_XOR_SYMMETRIC) { - dev_dbg(dev, "VF %d attempting to configure RSS, but RSS configuration is not valid\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) { - struct ice_vsi_ctx *ctx; - u8 lut_type, hash_type; - int status; - - lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; - hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR : - ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; - goto error_param; - } - - ctx->info.q_opt_rss = - FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) | - FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type); - - /* Preserve existing queueing option setting */ - ctx->info.q_opt_rss |= (vsi->info.q_opt_rss & - ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M); - ctx->info.q_opt_tc = vsi->info.q_opt_tc; - ctx->info.q_opt_flags = vsi->info.q_opt_rss; - - ctx->info.valid_sections = - cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); - - status = ice_update_vsi(hw, vsi->idx, ctx, NULL); - if (status) { - dev_err(dev, "update VSI for RSS failed, err %d aq_err %s\n", - status, ice_aq_str(hw->adminq.sq_last_status)); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - } else { - vsi->info.q_opt_rss = ctx->info.q_opt_rss; - } - - kfree(ctx); - } else { - struct ice_rss_hash_cfg cfg; - - /* Only check for none raw pattern case */ - if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - cfg.addl_hdrs = ICE_FLOW_SEG_HDR_NONE; - cfg.hash_flds = ICE_HASH_INVALID; - cfg.hdr_type = ICE_RSS_ANY_HEADERS; - - if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &cfg)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (add) { - if (ice_add_rss_cfg(hw, vsi, &cfg)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "ice_add_rss_cfg failed for vsi = %d, v_ret = %d\n", - vsi->vsi_num, v_ret); - } - } else { - int status; - - status = ice_rem_rss_cfg(hw, vsi->idx, &cfg); - /* We just ignore -ENOENT, because if two configurations - * share the same profile remove one of them actually - * removes both, since the profile is deleted. - */ - if (status && status != -ENOENT) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "ice_rem_rss_cfg failed for VF ID:%d, error:%d\n", - vf->vf_id, status); - } - } - } - -error_param: - return ice_vc_send_msg_to_vf(vf, v_opcode, v_ret, NULL, 0); -} - -/** - * ice_vc_config_rss_key - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * Configure the VF's RSS key - */ -static int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_rss_key *vrk = - (struct virtchnl_rss_key *)msg; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (ice_set_rss_key(vsi, vrk->key)) - v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, v_ret, - NULL, 0); -} - -/** - * ice_vc_config_rss_lut - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * Configure the VF's RSS LUT - */ -static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg) -{ - struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vrl->lut_entries != ICE_LUT_VSI_SIZE) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE)) - v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret, - NULL, 0); -} - -/** - * ice_vc_config_rss_hfunc - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * Configure the VF's RSS Hash function - */ -static int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg) -{ - struct virtchnl_rss_hfunc *vrh = (struct virtchnl_rss_hfunc *)msg; - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vrh->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vrh->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) - hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ; - - if (ice_set_rss_hfunc(vsi, hfunc)) - v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_HFUNC, v_ret, - NULL, 0); -} - -/** * ice_vc_get_qos_caps - Get current QoS caps from PF * @vf: pointer to the VF info * @@ -1122,110 +468,6 @@ err: } /** - * ice_vf_cfg_qs_bw - Configure per queue bandwidth - * @vf: pointer to the VF info - * @num_queues: number of queues to be configured - * - * Configure per queue bandwidth. - * - * Return: 0 on success or negative error value. - */ -static int ice_vf_cfg_qs_bw(struct ice_vf *vf, u16 num_queues) -{ - struct ice_hw *hw = &vf->pf->hw; - struct ice_vsi *vsi; - int ret; - u16 i; - - vsi = ice_get_vf_vsi(vf); - if (!vsi) - return -EINVAL; - - for (i = 0; i < num_queues; i++) { - u32 p_rate, min_rate; - u8 tc; - - p_rate = vf->qs_bw[i].peak; - min_rate = vf->qs_bw[i].committed; - tc = vf->qs_bw[i].tc; - if (p_rate) - ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, - vf->qs_bw[i].queue_id, - ICE_MAX_BW, p_rate); - else - ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, - vf->qs_bw[i].queue_id, - ICE_MAX_BW); - if (ret) - return ret; - - if (min_rate) - ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, - vf->qs_bw[i].queue_id, - ICE_MIN_BW, min_rate); - else - ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, - vf->qs_bw[i].queue_id, - ICE_MIN_BW); - - if (ret) - return ret; - } - - return 0; -} - -/** - * ice_vf_cfg_q_quanta_profile - Configure quanta profile - * @vf: pointer to the VF info - * @quanta_prof_idx: pointer to the quanta profile index - * @quanta_size: quanta size to be set - * - * This function chooses available quanta profile and configures the register. - * The quanta profile is evenly divided by the number of device ports, and then - * available to the specific PF and VFs. The first profile for each PF is a - * reserved default profile. Only quanta size of the rest unused profile can be - * modified. - * - * Return: 0 on success or negative error value. - */ -static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size, - u16 *quanta_prof_idx) -{ - const u16 n_desc = calc_quanta_desc(quanta_size); - struct ice_hw *hw = &vf->pf->hw; - const u16 n_cmd = 2 * n_desc; - struct ice_pf *pf = vf->pf; - u16 per_pf, begin_id; - u8 n_used; - u32 reg; - - begin_id = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / hw->dev_caps.num_funcs * - hw->logical_pf_id; - - if (quanta_size == ICE_DFLT_QUANTA) { - *quanta_prof_idx = begin_id; - } else { - per_pf = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / - hw->dev_caps.num_funcs; - n_used = pf->num_quanta_prof_used; - if (n_used < per_pf) { - *quanta_prof_idx = begin_id + 1 + n_used; - pf->num_quanta_prof_used++; - } else { - return -EINVAL; - } - } - - reg = FIELD_PREP(GLCOMM_QUANTA_PROF_QUANTA_SIZE_M, quanta_size) | - FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_CMD_M, n_cmd) | - FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_DESC_M, n_desc); - wr32(hw, GLCOMM_QUANTA_PROF(*quanta_prof_idx), reg); - - return 0; -} - -/** * ice_vc_cfg_promiscuous_mode_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer @@ -1407,773 +649,6 @@ error_param: } /** - * ice_vc_validate_vqs_bitmaps - validate Rx/Tx queue bitmaps from VIRTCHNL - * @vqs: virtchnl_queue_select structure containing bitmaps to validate - * - * Return true on successful validation, else false - */ -static bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs) -{ - if ((!vqs->rx_queues && !vqs->tx_queues) || - vqs->rx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF) || - vqs->tx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF)) - return false; - - return true; -} - -/** - * ice_vf_ena_txq_interrupt - enable Tx queue interrupt via QINT_TQCTL - * @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_ena_txq_interrupt(struct ice_vsi *vsi, u32 q_idx) -{ - struct ice_hw *hw = &vsi->back->hw; - u32 pfq = vsi->txq_map[q_idx]; - u32 reg; - - reg = rd32(hw, QINT_TQCTL(pfq)); - - /* MSI-X index 0 in the VF's space is always for the OICR, which means - * this is most likely a poll mode VF driver, so don't enable an - * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP - */ - if (!(reg & QINT_TQCTL_MSIX_INDX_M)) - return; - - wr32(hw, QINT_TQCTL(pfq), reg | QINT_TQCTL_CAUSE_ENA_M); -} - -/** - * ice_vf_ena_rxq_interrupt - enable Tx 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_ena_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)); - - /* MSI-X index 0 in the VF's space is always for the OICR, which means - * this is most likely a poll mode VF driver, so don't enable an - * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP - */ - if (!(reg & QINT_RQCTL_MSIX_INDX_M)) - return; - - wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M); -} - -/** - * ice_vc_ena_qs_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to enable all or specific queue(s) - */ -static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_queue_select *vqs = - (struct virtchnl_queue_select *)msg; - struct ice_vsi *vsi; - unsigned long q_map; - u16 vf_q_id; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_validate_vqs_bitmaps(vqs)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Enable only Rx rings, Tx rings were enabled by the FW when the - * Tx queue group list was configured and the context bits were - * programmed using ice_vsi_cfg_txqs - */ - q_map = vqs->rx_queues; - for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Skip queue if enabled */ - if (test_bit(vf_q_id, vf->rxq_ena)) - continue; - - if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true)) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n", - vf_q_id, vsi->vsi_num); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - ice_vf_ena_rxq_interrupt(vsi, vf_q_id); - set_bit(vf_q_id, vf->rxq_ena); - } - - q_map = vqs->tx_queues; - for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Skip queue if enabled */ - if (test_bit(vf_q_id, vf->txq_ena)) - continue; - - ice_vf_ena_txq_interrupt(vsi, vf_q_id); - set_bit(vf_q_id, vf->txq_ena); - } - - /* Set flag to indicate that queues are enabled */ - if (v_ret == VIRTCHNL_STATUS_SUCCESS) - set_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); - -error_param: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, v_ret, - NULL, 0); -} - -/** - * ice_vf_vsi_dis_single_txq - disable a single Tx queue - * @vf: VF to disable queue for - * @vsi: VSI for the VF - * @q_id: VF relative (0-based) queue ID - * - * Attempt to disable the Tx queue passed in. If the Tx queue was successfully - * disabled then clear q_id bit in the enabled queues bitmap and return - * success. Otherwise return error. - */ -static int -ice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id) -{ - struct ice_txq_meta txq_meta = { 0 }; - struct ice_tx_ring *ring; - int err; - - if (!test_bit(q_id, vf->txq_ena)) - dev_dbg(ice_pf_to_dev(vsi->back), "Queue %u on VSI %u is not enabled, but stopping it anyway\n", - q_id, vsi->vsi_num); - - ring = vsi->tx_rings[q_id]; - if (!ring) - return -EINVAL; - - ice_fill_txq_meta(vsi, ring, &txq_meta); - - err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, vf->vf_id, ring, &txq_meta); - if (err) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Tx ring %d on VSI %d\n", - q_id, vsi->vsi_num); - return err; - } - - /* Clear enabled queues flag */ - clear_bit(q_id, vf->txq_ena); - - return 0; -} - -/** - * ice_vc_dis_qs_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to disable all or specific queue(s) - */ -static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_queue_select *vqs = - (struct virtchnl_queue_select *)msg; - struct ice_vsi *vsi; - unsigned long q_map; - u16 vf_q_id; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) && - !test_bit(ICE_VF_STATE_QS_ENA, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_validate_vqs_bitmaps(vqs)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vqs->tx_queues) { - q_map = vqs->tx_queues; - - for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { - if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (ice_vf_vsi_dis_single_txq(vf, vsi, vf_q_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - } - } - - q_map = vqs->rx_queues; - /* speed up Rx queue disable by batching them if possible */ - if (q_map && - bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) { - if (ice_vsi_stop_all_rx_rings(vsi)) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n", - vsi->vsi_num); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - 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) { - if (!ice_vc_isvalid_q_id(vsi, vf_q_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Skip queue if not enabled */ - if (!test_bit(vf_q_id, vf->rxq_ena)) - continue; - - if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id, - true)) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n", - vf_q_id, vsi->vsi_num); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Clear enabled queues flag */ - clear_bit(vf_q_id, vf->rxq_ena); - } - } - - /* Clear enabled queues flag */ - if (v_ret == VIRTCHNL_STATUS_SUCCESS && ice_vf_has_no_qs_ena(vf)) - clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); - -error_param: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, v_ret, - NULL, 0); -} - -/** - * ice_cfg_interrupt - * @vf: pointer to the VF info - * @vsi: the VSI being configured - * @map: vector map for mapping vectors to queues - * @q_vector: structure for interrupt vector - * configure the IRQ to queue map - */ -static enum virtchnl_status_code -ice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi, - struct virtchnl_vector_map *map, - struct ice_q_vector *q_vector) -{ - u16 vsi_q_id, vsi_q_id_idx; - unsigned long qmap; - - q_vector->num_ring_rx = 0; - q_vector->num_ring_tx = 0; - - qmap = map->rxq_map; - for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { - vsi_q_id = vsi_q_id_idx; - - if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) - return VIRTCHNL_STATUS_ERR_PARAM; - - q_vector->num_ring_rx++; - q_vector->rx.itr_idx = map->rxitr_idx; - vsi->rx_rings[vsi_q_id]->q_vector = q_vector; - ice_cfg_rxq_interrupt(vsi, vsi_q_id, - q_vector->vf_reg_idx, - q_vector->rx.itr_idx); - } - - qmap = map->txq_map; - for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { - vsi_q_id = vsi_q_id_idx; - - if (!ice_vc_isvalid_q_id(vsi, vsi_q_id)) - return VIRTCHNL_STATUS_ERR_PARAM; - - q_vector->num_ring_tx++; - q_vector->tx.itr_idx = map->txitr_idx; - vsi->tx_rings[vsi_q_id]->q_vector = q_vector; - ice_cfg_txq_interrupt(vsi, vsi_q_id, - q_vector->vf_reg_idx, - q_vector->tx.itr_idx); - } - - return VIRTCHNL_STATUS_SUCCESS; -} - -/** - * ice_vc_cfg_irq_map_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to configure the IRQ to queue map - */ -static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - u16 num_q_vectors_mapped, vsi_id, vector_id; - struct virtchnl_irq_map_info *irqmap_info; - struct virtchnl_vector_map *map; - struct ice_vsi *vsi; - int i; - - irqmap_info = (struct virtchnl_irq_map_info *)msg; - num_q_vectors_mapped = irqmap_info->num_vectors; - - /* Check to make sure number of VF vectors mapped is not greater than - * number of VF vectors originally allocated, and check that - * there is actually at least a single VF queue vector mapped - */ - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || - vf->num_msix < num_q_vectors_mapped || - !num_q_vectors_mapped) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - for (i = 0; i < num_q_vectors_mapped; i++) { - struct ice_q_vector *q_vector; - - map = &irqmap_info->vecmap[i]; - - vector_id = map->vector_id; - vsi_id = map->vsi_id; - /* vector_id is always 0-based for each VF, and can never be - * larger than or equal to the max allowed interrupts per VF - */ - if (!(vector_id < vf->num_msix) || - !ice_vc_isvalid_vsi_id(vf, vsi_id) || - (!vector_id && (map->rxq_map || map->txq_map))) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* No need to map VF miscellaneous or rogue vector */ - if (!vector_id) - continue; - - /* Subtract non queue vector from vector_id passed by VF - * to get actual number of VSI queue vector array index - */ - q_vector = vsi->q_vectors[vector_id - ICE_NONQ_VECS_VF]; - if (!q_vector) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* lookout for the invalid queue index */ - v_ret = ice_cfg_interrupt(vf, vsi, map, q_vector); - if (v_ret) - goto error_param; - } - -error_param: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, v_ret, - NULL, 0); -} - -/** - * ice_vc_cfg_q_bw - Configure per queue bandwidth - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer which holds the command descriptor - * - * Configure VF queues bandwidth. - * - * Return: 0 on success or negative error value. - */ -static int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_queues_bw_cfg *qbw = - (struct virtchnl_queues_bw_cfg *)msg; - struct ice_vsi *vsi; - u16 i; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || - !ice_vc_isvalid_vsi_id(vf, qbw->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF || - qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { - dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", - vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - for (i = 0; i < qbw->num_queues; i++) { - if (qbw->cfg[i].shaper.peak != 0 && vf->max_tx_rate != 0 && - qbw->cfg[i].shaper.peak > vf->max_tx_rate) { - dev_warn(ice_pf_to_dev(vf->pf), "The maximum queue %d rate limit configuration may not take effect because the maximum TX rate for VF-%d is %d\n", - qbw->cfg[i].queue_id, vf->vf_id, - vf->max_tx_rate); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - if (qbw->cfg[i].shaper.committed != 0 && vf->min_tx_rate != 0 && - qbw->cfg[i].shaper.committed < vf->min_tx_rate) { - dev_warn(ice_pf_to_dev(vf->pf), "The minimum queue %d rate limit configuration may not take effect because the minimum TX rate for VF-%d is %d\n", - qbw->cfg[i].queue_id, vf->vf_id, - vf->min_tx_rate); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - if (qbw->cfg[i].queue_id > vf->num_vf_qs) { - dev_warn(ice_pf_to_dev(vf->pf), "VF-%d trying to configure invalid queue_id\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - if (qbw->cfg[i].tc >= ICE_MAX_TRAFFIC_CLASS) { - dev_warn(ice_pf_to_dev(vf->pf), "VF-%d trying to configure a traffic class higher than allowed\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - } - - for (i = 0; i < qbw->num_queues; i++) { - vf->qs_bw[i].queue_id = qbw->cfg[i].queue_id; - vf->qs_bw[i].peak = qbw->cfg[i].shaper.peak; - vf->qs_bw[i].committed = qbw->cfg[i].shaper.committed; - vf->qs_bw[i].tc = qbw->cfg[i].tc; - } - - if (ice_vf_cfg_qs_bw(vf, qbw->num_queues)) - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - -err: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUEUE_BW, - v_ret, NULL, 0); -} - -/** - * ice_vc_cfg_q_quanta - Configure per queue quanta - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer which holds the command descriptor - * - * Configure VF queues quanta. - * - * Return: 0 on success or negative error value. - */ -static int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg) -{ - u16 quanta_prof_id, quanta_size, start_qid, num_queues, end_qid, i; - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_quanta_cfg *qquanta = - (struct virtchnl_quanta_cfg *)msg; - struct ice_vsi *vsi; - int ret; - - start_qid = qquanta->queue_select.start_queue_id; - num_queues = qquanta->queue_select.num_queues; - - if (check_add_overflow(start_qid, num_queues, &end_qid)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (end_qid > ICE_MAX_RSS_QS_PER_VF || - end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { - dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", - vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - quanta_size = qquanta->quanta_size; - if (quanta_size > ICE_MAX_QUANTA_SIZE || - quanta_size < ICE_MIN_QUANTA_SIZE) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (quanta_size % 64) { - dev_err(ice_pf_to_dev(vf->pf), "quanta size should be the product of 64\n"); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - ret = ice_vf_cfg_q_quanta_profile(vf, quanta_size, - &quanta_prof_id); - if (ret) { - v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; - goto err; - } - - for (i = start_qid; i < end_qid; i++) - vsi->tx_rings[i]->quanta_prof_id = quanta_prof_id; - -err: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUANTA, - v_ret, NULL, 0); -} - -/** - * ice_vc_cfg_qs_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to configure the Rx/Tx queues - */ -static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) -{ - struct virtchnl_vsi_queue_config_info *qci = - (struct virtchnl_vsi_queue_config_info *)msg; - struct virtchnl_queue_pair_info *qpi; - struct ice_pf *pf = vf->pf; - struct ice_lag *lag; - struct ice_vsi *vsi; - u8 act_prt, pri_prt; - int i = -1, q_idx; - bool ena_ts; - - lag = pf->lag; - mutex_lock(&pf->lag_mutex); - act_prt = ICE_LAG_INVALID_PORT; - pri_prt = pf->hw.port_info->lport; - if (lag && lag->bonded && lag->primary) { - act_prt = lag->active_port; - if (act_prt != pri_prt && act_prt != ICE_LAG_INVALID_PORT && - lag->upper_netdev) - ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); - else - act_prt = ICE_LAG_INVALID_PORT; - } - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) - goto error_param; - - if (!ice_vc_isvalid_vsi_id(vf, qci->vsi_id)) - goto error_param; - - vsi = ice_get_vf_vsi(vf); - if (!vsi) - goto error_param; - - if (qci->num_queue_pairs > ICE_MAX_RSS_QS_PER_VF || - qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { - dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n", - vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); - goto error_param; - } - - for (i = 0; i < qci->num_queue_pairs; i++) { - if (!qci->qpair[i].rxq.crc_disable) - continue; - - if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_CRC) || - vf->vlan_strip_ena) - goto error_param; - } - - for (i = 0; i < qci->num_queue_pairs; i++) { - qpi = &qci->qpair[i]; - if (qpi->txq.vsi_id != qci->vsi_id || - qpi->rxq.vsi_id != qci->vsi_id || - qpi->rxq.queue_id != qpi->txq.queue_id || - qpi->txq.headwb_enabled || - !ice_vc_isvalid_ring_len(qpi->txq.ring_len) || - !ice_vc_isvalid_ring_len(qpi->rxq.ring_len) || - !ice_vc_isvalid_q_id(vsi, qpi->txq.queue_id)) { - goto error_param; - } - - q_idx = qpi->rxq.queue_id; - - /* make sure selected "q_idx" is in valid range of queues - * for selected "vsi" - */ - if (q_idx >= vsi->alloc_txq || q_idx >= vsi->alloc_rxq) { - goto error_param; - } - - /* copy Tx queue info from VF into VSI */ - if (qpi->txq.ring_len > 0) { - vsi->tx_rings[q_idx]->dma = qpi->txq.dma_ring_addr; - vsi->tx_rings[q_idx]->count = qpi->txq.ring_len; - - /* Disable any existing queue first */ - if (ice_vf_vsi_dis_single_txq(vf, vsi, q_idx)) - goto error_param; - - /* Configure a queue with the requested settings */ - if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) { - dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure TX queue %d\n", - vf->vf_id, q_idx); - goto error_param; - } - } - - /* copy Rx queue info from VF into VSI */ - if (qpi->rxq.ring_len > 0) { - u16 max_frame_size = ice_vc_get_max_frame_size(vf); - struct ice_rx_ring *ring = vsi->rx_rings[q_idx]; - u32 rxdid; - - ring->dma = qpi->rxq.dma_ring_addr; - ring->count = qpi->rxq.ring_len; - - if (qpi->rxq.crc_disable) - ring->flags |= ICE_RX_FLAGS_CRC_STRIP_DIS; - else - ring->flags &= ~ICE_RX_FLAGS_CRC_STRIP_DIS; - - if (qpi->rxq.databuffer_size != 0 && - (qpi->rxq.databuffer_size > ((16 * 1024) - 128) || - qpi->rxq.databuffer_size < 1024)) - goto error_param; - ring->rx_buf_len = qpi->rxq.databuffer_size; - if (qpi->rxq.max_pkt_size > max_frame_size || - qpi->rxq.max_pkt_size < 64) - goto error_param; - - ring->max_frame = qpi->rxq.max_pkt_size; - /* add space for the port VLAN since the VF driver is - * not expected to account for it in the MTU - * calculation - */ - if (ice_vf_is_port_vlan_ena(vf)) - ring->max_frame += VLAN_HLEN; - - if (ice_vsi_cfg_single_rxq(vsi, q_idx)) { - dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure RX queue %d\n", - vf->vf_id, q_idx); - goto error_param; - } - - /* If Rx flex desc is supported, select RXDID for Rx - * queues. Otherwise, use legacy 32byte descriptor - * format. Legacy 16byte descriptor is not supported. - * If this RXDID is selected, return error. - */ - if (vf->driver_caps & - VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) { - rxdid = qpi->rxq.rxdid; - if (!(BIT(rxdid) & pf->supported_rxdids)) - goto error_param; - } else { - rxdid = ICE_RXDID_LEGACY_1; - } - - ena_ts = ((vf->driver_caps & - VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) && - (vf->driver_caps & VIRTCHNL_VF_CAP_PTP) && - (qpi->rxq.flags & VIRTCHNL_PTP_RX_TSTAMP)); - - ice_write_qrxflxp_cntxt(&vsi->back->hw, - vsi->rxq_map[q_idx], rxdid, - ICE_RXDID_PRIO, ena_ts); - } - } - - if (lag && lag->bonded && lag->primary && - act_prt != ICE_LAG_INVALID_PORT) - ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); - mutex_unlock(&pf->lag_mutex); - - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, - VIRTCHNL_STATUS_SUCCESS, NULL, 0); -error_param: - /* disable whatever we can */ - for (; i >= 0; i--) { - if (ice_vsi_ctrl_one_rx_ring(vsi, false, i, true)) - dev_err(ice_pf_to_dev(pf), "VF-%d could not disable RX queue %d\n", - vf->vf_id, i); - if (ice_vf_vsi_dis_single_txq(vf, vsi, i)) - dev_err(ice_pf_to_dev(pf), "VF-%d could not disable TX queue %d\n", - vf->vf_id, i); - } - - if (lag && lag->bonded && lag->primary && - act_prt != ICE_LAG_INVALID_PORT) - ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); - mutex_unlock(&pf->lag_mutex); - - ice_lag_move_new_vf_nodes(vf); - - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, - VIRTCHNL_STATUS_ERR_PARAM, NULL, 0); -} - -/** * ice_can_vf_change_mac * @vf: pointer to the VF info * @@ -2547,66 +1022,6 @@ static int ice_vc_del_mac_addr_msg(struct ice_vf *vf, u8 *msg) } /** - * ice_vc_request_qs_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * VFs get a default number of queues but can use this message to request a - * different number. If the request is successful, PF will reset the VF and - * return 0. If unsuccessful, PF will send message informing VF of number of - * available queue pairs via virtchnl message response to VF. - */ -static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_vf_res_request *vfres = - (struct virtchnl_vf_res_request *)msg; - u16 req_queues = vfres->num_queue_pairs; - struct ice_pf *pf = vf->pf; - u16 max_allowed_vf_queues; - u16 tx_rx_queue_left; - struct device *dev; - u16 cur_queues; - - dev = ice_pf_to_dev(pf); - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - cur_queues = vf->num_vf_qs; - tx_rx_queue_left = min_t(u16, ice_get_avail_txq_count(pf), - ice_get_avail_rxq_count(pf)); - max_allowed_vf_queues = tx_rx_queue_left + cur_queues; - if (!req_queues) { - dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n", - vf->vf_id); - } else if (req_queues > ICE_MAX_RSS_QS_PER_VF) { - dev_err(dev, "VF %d tried to request more than %d queues.\n", - vf->vf_id, ICE_MAX_RSS_QS_PER_VF); - vfres->num_queue_pairs = ICE_MAX_RSS_QS_PER_VF; - } else if (req_queues > cur_queues && - req_queues - cur_queues > tx_rx_queue_left) { - dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n", - vf->vf_id, req_queues - cur_queues, tx_rx_queue_left); - vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues, - ICE_MAX_RSS_QS_PER_VF); - } else { - /* request is successful, then reset VF */ - vf->num_req_qs = req_queues; - ice_reset_vf(vf, ICE_VF_RESET_NOTIFY); - dev_info(dev, "VF %d granted request of %u queues.\n", - vf->vf_id, req_queues); - return 0; - } - -error_param: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, - v_ret, (u8 *)vfres, sizeof(*vfres)); -} - -/** * ice_vf_vlan_offload_ena - determine if capabilities support VLAN offloads * @caps: VF driver negotiated capabilities * @@ -2621,7 +1036,7 @@ static bool ice_vf_vlan_offload_ena(u32 caps) * ice_is_vlan_promisc_allowed - check if VLAN promiscuous config is allowed * @vf: VF used to determine if VLAN promiscuous config is allowed */ -static bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) +bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) { if ((test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) || test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) && @@ -2640,8 +1055,8 @@ static bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) * This function should only be called if VLAN promiscuous mode is allowed, * which can be determined via ice_is_vlan_promisc_allowed(). */ -static int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi, - struct ice_vlan *vlan) +int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi, + struct ice_vlan *vlan) { u8 promisc_m = 0; int status; @@ -2999,108 +1414,6 @@ error_param: } /** - * ice_vc_get_rss_hena - return the RSS HENA bits allowed by the hardware - * @vf: pointer to the VF info - */ -static int ice_vc_get_rss_hena(struct ice_vf *vf) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_rss_hena *vrh = NULL; - int len = 0, ret; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { - dev_err(ice_pf_to_dev(vf->pf), "RSS not supported by PF\n"); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - len = sizeof(struct virtchnl_rss_hena); - vrh = kzalloc(len, GFP_KERNEL); - if (!vrh) { - v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; - len = 0; - goto err; - } - - vrh->hena = ICE_DEFAULT_RSS_HENA; -err: - /* send the response back to the VF */ - ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS, v_ret, - (u8 *)vrh, len); - kfree(vrh); - return ret; -} - -/** - * ice_vc_set_rss_hena - set RSS HENA bits for the VF - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - */ -static int ice_vc_set_rss_hena(struct ice_vf *vf, u8 *msg) -{ - struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct ice_pf *pf = vf->pf; - struct ice_vsi *vsi; - struct device *dev; - int status; - - dev = ice_pf_to_dev(pf); - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { - dev_err(dev, "RSS not supported by PF\n"); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - /* clear all previously programmed RSS configuration to allow VF drivers - * the ability to customize the RSS configuration and/or completely - * disable RSS - */ - status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); - if (status && !vrh->hena) { - /* only report failure to clear the current RSS configuration if - * that was clearly the VF's intention (i.e. vrh->hena = 0) - */ - v_ret = ice_err_to_virt_err(status); - goto err; - } else if (status) { - /* allow the VF to update the RSS configuration even on failure - * to clear the current RSS confguration in an attempt to keep - * RSS in a working state - */ - dev_warn(dev, "Failed to clear the RSS configuration for VF %u\n", - vf->vf_id); - } - - if (vrh->hena) { - status = ice_add_avf_rss_cfg(&pf->hw, vsi, vrh->hena); - v_ret = ice_err_to_virt_err(status); - } - - /* send the response to the VF */ -err: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, v_ret, - NULL, 0); -} - -/** * ice_vc_query_rxdid - query RXDID supported by DDP package * @vf: pointer to VF info * @@ -3856,48 +2169,6 @@ ice_vc_ena_vlan_offload(struct ice_vsi *vsi, return 0; } -#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX 3 -#define ICE_L2TSEL_BIT_OFFSET 23 -enum ice_l2tsel { - ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND, - ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1, -}; - -/** - * ice_vsi_update_l2tsel - update l2tsel field for all Rx rings on this VSI - * @vsi: VSI used to update l2tsel on - * @l2tsel: l2tsel setting requested - * - * Use the l2tsel setting to update all of the Rx queue context bits for l2tsel. - * This will modify which descriptor field the first offloaded VLAN will be - * stripped into. - */ -static void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel) -{ - struct ice_hw *hw = &vsi->back->hw; - u32 l2tsel_bit; - int i; - - if (l2tsel == ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND) - l2tsel_bit = 0; - else - l2tsel_bit = BIT(ICE_L2TSEL_BIT_OFFSET); - - for (i = 0; i < vsi->alloc_rxq; i++) { - u16 pfq = vsi->rxq_map[i]; - u32 qrx_context_offset; - u32 regval; - - qrx_context_offset = - QRX_CONTEXT(ICE_L2TSEL_QRX_CONTEXT_REG_IDX, pfq); - - regval = rd32(hw, qrx_context_offset); - regval &= ~BIT(ICE_L2TSEL_BIT_OFFSET); - regval |= l2tsel_bit; - wr32(hw, qrx_context_offset, regval); - } -} - /** * ice_vc_ena_vlan_stripping_v2_msg * @vf: VF the message was received from @@ -4243,8 +2514,8 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = { .add_vlan_msg = ice_vc_add_vlan_msg, .remove_vlan_msg = ice_vc_remove_vlan_msg, .query_rxdid = ice_vc_query_rxdid, - .get_rss_hena = ice_vc_get_rss_hena, - .set_rss_hena_msg = ice_vc_set_rss_hena, + .get_rss_hashcfg = ice_vc_get_rss_hashcfg, + .set_rss_hashcfg = ice_vc_set_rss_hashcfg, .ena_vlan_stripping = ice_vc_ena_vlan_stripping, .dis_vlan_stripping = ice_vc_dis_vlan_stripping, .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, @@ -4380,8 +2651,8 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = { .add_vlan_msg = ice_vc_add_vlan_msg, .remove_vlan_msg = ice_vc_remove_vlan_msg, .query_rxdid = ice_vc_query_rxdid, - .get_rss_hena = ice_vc_get_rss_hena, - .set_rss_hena_msg = ice_vc_set_rss_hena, + .get_rss_hashcfg = ice_vc_get_rss_hashcfg, + .set_rss_hashcfg = ice_vc_set_rss_hashcfg, .ena_vlan_stripping = ice_vc_ena_vlan_stripping, .dis_vlan_stripping = ice_vc_dis_vlan_stripping, .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, @@ -4582,11 +2853,11 @@ error_handler: case VIRTCHNL_OP_GET_SUPPORTED_RXDIDS: err = ops->query_rxdid(vf); break; - case VIRTCHNL_OP_GET_RSS_HENA_CAPS: - err = ops->get_rss_hena(vf); + case VIRTCHNL_OP_GET_RSS_HASHCFG_CAPS: + err = ops->get_rss_hashcfg(vf); break; - case VIRTCHNL_OP_SET_RSS_HENA: - err = ops->set_rss_hena_msg(vf, msg); + case VIRTCHNL_OP_SET_RSS_HASHCFG: + err = ops->set_rss_hashcfg(vf, msg); break; case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: err = ops->ena_vlan_stripping(vf); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/virt/virtchnl.h index 222990f229d5..71bb456e2d71 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h +++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.h @@ -57,8 +57,8 @@ struct ice_virtchnl_ops { int (*add_vlan_msg)(struct ice_vf *vf, u8 *msg); int (*remove_vlan_msg)(struct ice_vf *vf, u8 *msg); int (*query_rxdid)(struct ice_vf *vf); - int (*get_rss_hena)(struct ice_vf *vf); - int (*set_rss_hena_msg)(struct ice_vf *vf, u8 *msg); + int (*get_rss_hashcfg)(struct ice_vf *vf); + int (*set_rss_hashcfg)(struct ice_vf *vf, u8 *msg); int (*ena_vlan_stripping)(struct ice_vf *vf); int (*dis_vlan_stripping)(struct ice_vf *vf); int (*handle_rss_cfg_msg)(struct ice_vf *vf, u8 *msg, bool add); @@ -92,12 +92,31 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id); void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, struct ice_mbx_data *mbxdata); +void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx); +void ice_vf_ena_txq_interrupt(struct ice_vsi *vsi, u32 q_idx); +int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi, + struct ice_vlan *vlan); +bool ice_is_vlan_promisc_allowed(struct ice_vf *vf); #else /* CONFIG_PCI_IOV */ static inline void ice_virtchnl_set_dflt_ops(struct ice_vf *vf) { } static inline void ice_virtchnl_set_repr_ops(struct ice_vf *vf) { } static inline void ice_vc_notify_vf_link_state(struct ice_vf *vf) { } static inline void ice_vc_notify_link_state(struct ice_pf *pf) { } static inline void ice_vc_notify_reset(struct ice_pf *pf) { } +static inline void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx) { } +static inline void ice_vf_ena_txq_interrupt(struct ice_vsi *vsi, u32 q_idx) { } + +static inline int ice_vf_ena_vlan_promisc(struct ice_vf *vf, + struct ice_vsi *vsi, + struct ice_vlan *vlan) +{ + return -EOPNOTSUPP; +} + +static inline bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) +{ + return false; +} static inline int ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, |