From: Arkadiusz Kubalewski Hardware variants of E830 may support an unmanaged DPLL where the configuration is hardcoded within the hardware and firmware, meaning users cannot modify settings. However, users are able to check the DPLL lock status and obtain configuration information through the Linux DPLL and devlink health subsystem. Availability of 'loss of lock' health status code determines if such support is available, if true, register single DPLL device with 1 input and 1 output and provide hardcoded/read only properties of a pin and DPLL device. User is only allowed to check DPLL device status and receive notifications on DPLL lock status change. When present, the DPLL device locks to an external signal provided through the PCIe/OCP pin. The expected input signal is 1PPS (1 Pulse Per Second) embedded on a 10MHz reference clock. The DPLL produces output: - for MAC (Media Access Control) & PHY (Physical Layer) clocks, - 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer. Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Signed-off-by: Arkadiusz Kubalewski Signed-off-by: Grzegorz Nitka Signed-off-by: Tony Nguyen --- .../device_drivers/ethernet/intel/ice.rst | 80 +++++ .../net/ethernet/intel/ice/devlink/health.c | 4 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 12 + drivers/net/ethernet/intel/ice/ice_common.c | 135 ++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 8 + drivers/net/ethernet/intel/ice/ice_dpll.c | 311 ++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_dpll.h | 11 + drivers/net/ethernet/intel/ice/ice_main.c | 14 +- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 46 +++ drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 + 10 files changed, 599 insertions(+), 23 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index 0bca293cf9cb..34b5b7a5ad1c 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -941,6 +941,86 @@ To see input signal on those PTP pins, you need to configure DPLL properly. Output signal is only visible on DPLL and to send it to the board SMA/U.FL pins, DPLL output pins have to be manually configured. +Unmanaged DPLL Support +---------------------- +Hardware variants of E830 may support an unmanaged DPLL: + +- Intel(R) Ethernet Network Adapter E830-XXVDA8F for OCP 3.0, + +- Intel(R) Ethernet Network Adapter E830-XXVDA4F. + +In the case of the unmanaged DPLL, the configuration is hardcoded within the +hardware and firmware, meaning users cannot modify settings. However, +users can check the DPLL lock status and obtain configuration information +through the DPLL subsystem. + +When present, the DPLL device locks to an external signal provided through the +PCIe/OCP pin. The expected input signal is 1PPS (1 Pulse Per Second) embedded +on a 10MHz reference clock. +The DPLL produces output: + +- for MAC (Media Access Control) & PHY (Physical Layer) clocks, + +- 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer. + +Example output of querying the DPLL subsystem can be found below. + +.. code-block:: console + :caption: Dumping the DPLL pins + + $ --spec Documentation/netlink/specs/dpll.yaml --dump pin-get + [{'board-label': '1588-TIME_SYNC', + 'capabilities': set(), + 'clock-id': 282574471561216, + 'esync-frequency': 1, + 'esync-frequency-supported': [{'frequency-max': 1, 'frequency-min': 1}], + 'esync-pulse': 25, + 'frequency': 10000000, + 'id': 13, + 'module-name': 'ice', + 'parent-device': [{'direction': 'input', + 'parent-id': 6, + 'state': 'connected'}], + 'phase-adjust-max': 0, + 'phase-adjust-min': 0, + 'type': 'ext'}, + {'board-label': 'MAC-PHY-CLK', + 'capabilities': set(), + 'clock-id': 282574471561216, + 'frequency': 156250000, + 'id': 14, + 'module-name': 'ice', + 'parent-device': [{'direction': 'output', + 'parent-id': 6, + 'state': 'connected'}], + 'phase-adjust-max': 0, + 'phase-adjust-min': 0, + 'type': 'synce-eth-port'}, + {'board-label': '1588-TIME_REF', + 'capabilities': set(), + 'clock-id': 282574471561216, + 'frequency': 1, + 'id': 15, + 'module-name': 'ice', + 'parent-device': [{'direction': 'output', + 'parent-id': 6, + 'state': 'connected'}], + 'phase-adjust-max': 0, + 'phase-adjust-min': 0, + 'type': 'int-oscillator'}] + +.. code-block:: console + :caption: Dumping the DPLL devices + + $ --spec Documentation/netlink/specs/dpll.yaml --dump device-get + [{'clock-id': 282574471561216, + 'id': 6, + 'lock-status': 'locked', + 'mode': 'automatic', + 'mode-supported': ['automatic'], + 'module-name': 'ice', + 'type': 'eec'}] + GNSS module ----------- Requires kernel compiled with CONFIG_GNSS=y or CONFIG_GNSS=m. diff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c index 8e9a8a8178d4..31e6c5107c97 100644 --- a/drivers/net/ethernet/intel/ice/devlink/health.c +++ b/drivers/net/ethernet/intel/ice/devlink/health.c @@ -101,6 +101,8 @@ static const struct ice_health_status ice_health_status_lookup[] = { "Supplied MIB file is invalid. DCB reverted to default configuration.", "Disable FW-LLDP and check DCBx system configuration.", {ice_port_number_label, "MIB ID"}}, + {ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK, "Local DPLL lock status", + NULL,}, }; static int ice_health_status_lookup_compare(const void *a, const void *b) @@ -242,6 +244,8 @@ void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info pf->health_reporters.fw_status = *health_info; devlink_health_report(pf->health_reporters.fw, "FW syndrome reported", NULL); + if (status_code == ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK) + ice_dpll_lock_state_set_unmanaged(pf, health_info, true); break; case ICE_AQC_HEALTH_STATUS_PF: case ICE_AQC_HEALTH_STATUS_PORT: diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 859e9c66f3e7..3f8c1b8befc3 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1498,6 +1498,7 @@ struct ice_aqc_get_link_topo { #define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21 #define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032 0x24 #define ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384 0x25 +#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640 0x27 #define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30 #define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31 #define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47 @@ -2481,11 +2482,14 @@ enum ice_aqc_health_status { ICE_AQC_HEALTH_STATUS_ERR_BMC_RESET = 0x50B, ICE_AQC_HEALTH_STATUS_ERR_LAST_MNG_FAIL = 0x50C, ICE_AQC_HEALTH_STATUS_ERR_RESOURCE_ALLOC_FAIL = 0x50D, + ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK = 0x601, ICE_AQC_HEALTH_STATUS_ERR_FW_LOOP = 0x1000, ICE_AQC_HEALTH_STATUS_ERR_FW_PFR_FAIL = 0x1001, ICE_AQC_HEALTH_STATUS_ERR_LAST_FAIL_AQ = 0x1002, }; +#define ICE_AQC_HEALTH_STATUS_CODE_NUM 64 + /* Get Health Status (indirect 0xFF22) */ struct ice_aqc_get_health_status { __le16 health_status_count; @@ -2512,6 +2516,13 @@ struct ice_aqc_health_status_elem { __le32 internal_data2; }; +/* Get Health Status response buffer entry, (0xFF21) + * repeated per reported health status + */ +struct ice_aqc_health_status_supp_elem { + __le16 health_status_code; +}; + /* Admin Queue command opcodes */ enum ice_adminq_opc { /* AQ commands */ @@ -2675,6 +2686,7 @@ enum ice_adminq_opc { /* System Diagnostic commands */ ice_aqc_opc_set_health_status_cfg = 0xFF20, + ice_aqc_opc_get_supported_health_status_codes = 0xFF21, ice_aqc_opc_get_health_status = 0xFF22, /* FW Logging Commands */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 046bc9c65c51..e499a28e8e22 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -3081,6 +3081,29 @@ bool ice_is_cgu_in_netlist(struct ice_hw *hw) return false; } +/** + * ice_is_unmanaged_cgu_in_netlist - check for unmanaged CGU presence + * @hw: pointer to the hw struct + * + * Check if the unmanaged Clock Generation Unit (CGU) device is present in the + * netlist. Save the CGU part number in the hw structure for later use. + * Return: + * * true - unmanaged cgu is present + * * false - unmanaged cgu is not present + */ +bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw) +{ + if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL, + ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640, + NULL)) { + hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640; + return true; + } + + return false; +} + /** * ice_is_gps_in_netlist * @hw: pointer to the hw struct @@ -6343,6 +6366,118 @@ bool ice_is_fw_health_report_supported(struct ice_hw *hw) ICE_FW_API_HEALTH_REPORT_PATCH); } +/** + * ice_aq_get_health_status_supported - get supported health status codes + * @hw: pointer to the HW struct + * @buff: pointer to buffer where health status elements will be stored + * @num: number of health status elements buffer can hold + * + * Return: + * * 0 - success, + * * negative - AQ error code. + */ +static int +ice_aq_get_health_status_supported(struct ice_hw *hw, + struct ice_aqc_health_status_supp_elem *buff, + int num) +{ + u16 code = ice_aqc_opc_get_supported_health_status_codes; + struct libie_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, code); + + return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL); +} + +/** + * ice_aq_get_health_status - get current health status array from the firmware + * @hw: pointer to the HW struct + * @buff: pointer to buffer where health status elements will be stored + * @num: number of health status elements buffer can hold + * + * Return: + * * 0 - success, + * * negative - AQ error code. + */ +int ice_aq_get_health_status(struct ice_hw *hw, + struct ice_aqc_health_status_elem *buff, int num) +{ + struct libie_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, + ice_aqc_opc_get_health_status); + + return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL); +} + +/** + * ice_is_health_status_code_supported - check if health status code is supported + * @hw: pointer to the hardware structure + * @code: health status code to check + * @supported: pointer to boolean result + * + * Return: 0 on success, negative error code otherwise + */ +int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code, + bool *supported) +{ + const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM; + struct ice_aqc_health_status_supp_elem *buff; + int ret; + + buff = kcalloc(BUFF_SIZE, sizeof(*buff), GFP_KERNEL); + if (!buff) + return -ENOMEM; + ret = ice_aq_get_health_status_supported(hw, buff, BUFF_SIZE); + if (ret) + goto free_buff; + for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++) + if (le16_to_cpu(buff[i].health_status_code) == code) { + *supported = true; + break; + } + +free_buff: + kfree(buff); + return ret; +} + +/** + * ice_get_last_health_status_code - get last health status for given code + * @hw: pointer to the hardware structure + * @out: pointer to the health status struct to be filled + * @code: health status code to check + * + * Return: 0 on success, negative error code otherwise + */ +int ice_get_last_health_status_code(struct ice_hw *hw, + struct ice_aqc_health_status_elem *out, + u16 code) +{ + const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM; + struct ice_aqc_health_status_elem *buff; + int ret, last_status = -1; + + buff = kcalloc(BUFF_SIZE, sizeof(*buff), GFP_KERNEL); + if (!buff) + return -ENOMEM; + ret = ice_aq_get_health_status(hw, buff, BUFF_SIZE); + if (ret) + goto free_buff; + for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++) + if (le16_to_cpu(buff[i].health_status_code) == code) + last_status = i; + + if (last_status >= 0) + memcpy(out, &buff[last_status], sizeof(*out)); + else + memset(out, 0, sizeof(*out)); + +free_buff: + kfree(buff); + return ret; +} + /** * ice_aq_set_health_status_cfg - Configure FW health events * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index e700ac0dc347..cbecee66e2a7 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -162,6 +162,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw); bool ice_is_clock_mux_in_netlist(struct ice_hw *hw); bool ice_is_cgu_in_netlist(struct ice_hw *hw); +bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw); bool ice_is_gps_in_netlist(struct ice_hw *hw); int ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, @@ -188,6 +189,13 @@ ice_get_link_default_override(struct ice_link_default_override_tlv *ldo, struct ice_port_info *pi); bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps); bool ice_is_fw_health_report_supported(struct ice_hw *hw); +int ice_aq_get_health_status(struct ice_hw *hw, + struct ice_aqc_health_status_elem *buff, int num); +int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code, + bool *supported); +int ice_get_last_health_status_code(struct ice_hw *hw, + struct ice_aqc_health_status_elem *out, + u16 code); int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source); int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code, u8 serdes_num, int *output); diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 53b54e395a2e..c53ce0e4e804 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -17,6 +17,8 @@ #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_HEALTH_STATUS_LOCKED 1 +#define ICE_DPLL_HEALTH_STATUS_UNLOCKED 0 #define ICE_DPLL_PIN_SW_INPUT_ABS(in_idx) \ (ICE_DPLL_SW_PIN_INPUT_BASE_SFP + (in_idx)) @@ -79,6 +81,10 @@ static const struct dpll_pin_frequency ice_esync_range[] = { DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ), }; +static const struct dpll_pin_frequency ice_esync_range_unmanaged[] = { + DPLL_PIN_FREQUENCY_1PPS, +}; + /** * ice_dpll_is_sw_pin - check if given pin shall be controlled by SW * @pf: private board structure @@ -1008,9 +1014,11 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, return -EBUSY; mutex_lock(&pf->dplls.lock); - ret = ice_dpll_pin_state_update(pf, p, pin_type, extack); - if (ret) - goto unlock; + if (!pf->dplls.unmanaged) { + ret = ice_dpll_pin_state_update(pf, p, pin_type, extack); + if (ret) + goto unlock; + } if (pin_type == ICE_DPLL_PIN_TYPE_INPUT || pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) *state = p->state[d->dpll_idx]; @@ -2036,9 +2044,12 @@ ice_dpll_input_esync_get(const struct dpll_pin *pin, void *pin_priv, mutex_unlock(&pf->dplls.lock); return -EOPNOTSUPP; } - esync->range = ice_esync_range; + if (pf->dplls.unmanaged) + esync->range = ice_esync_range_unmanaged; + else + esync->range = ice_esync_range; esync->range_num = ARRAY_SIZE(ice_esync_range); - if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) { + if (p->flags[0] & ICE_DPLL_IN_ESYNC_ENABLED) { esync->freq = DPLL_PIN_FREQUENCY_1_HZ; esync->pulse = ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT; } else { @@ -2436,6 +2447,21 @@ static const struct dpll_pin_ops ice_dpll_output_ops = { .esync_get = ice_dpll_output_esync_get, }; +static const struct dpll_pin_ops ice_dpll_input_unmanaged_ops = { + .frequency_get = ice_dpll_input_frequency_get, + .direction_get = ice_dpll_input_direction, + .state_on_dpll_get = ice_dpll_input_state_get, +#if defined(HAVE_DPLL_ESYNC) + .esync_get = ice_dpll_input_esync_get, +#endif /* HAVE_DPLL_ESYNC */ +}; + +static const struct dpll_pin_ops ice_dpll_output_unmanaged_ops = { + .frequency_get = ice_dpll_output_frequency_get, + .direction_get = ice_dpll_output_direction, + .state_on_dpll_get = ice_dpll_output_state_get, +}; + static const struct dpll_device_ops ice_dpll_ops = { .lock_status_get = ice_dpll_lock_status_get, .mode_get = ice_dpll_mode_get, @@ -3000,9 +3026,11 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu, ret = ice_dpll_register_pins(first, pins, ops, count); if (ret) goto release_pins; - ret = ice_dpll_register_pins(second, pins, ops, count); - if (ret) - goto unregister_first; + if (second) { + ret = ice_dpll_register_pins(second, pins, ops, count); + if (ret) + goto unregister_first; + } } return 0; @@ -3112,6 +3140,18 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) struct ice_dpll *de = &d->eec; struct ice_dpll *dp = &d->pps; + if (d->unmanaged) { + ice_dpll_unregister_pins(de->dpll, inputs, + &ice_dpll_input_unmanaged_ops, + num_inputs); + ice_dpll_unregister_pins(de->dpll, outputs, + &ice_dpll_output_unmanaged_ops, + num_outputs); + ice_dpll_release_pins(inputs, num_inputs); + ice_dpll_release_pins(outputs, num_outputs); + return; + } + ice_dpll_deinit_rclk_pin(pf); if (cgu) { ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_input_ops, @@ -3155,24 +3195,35 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) */ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) { + const struct dpll_pin_ops *output_ops; + const struct dpll_pin_ops *input_ops; int ret, count; + if (!pf->dplls.unmanaged) { + input_ops = &ice_dpll_input_ops; + output_ops = &ice_dpll_output_ops; + } else { + input_ops = &ice_dpll_input_unmanaged_ops; + output_ops = &ice_dpll_output_unmanaged_ops; + } + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0, - pf->dplls.num_inputs, - &ice_dpll_input_ops, + pf->dplls.num_inputs, input_ops, pf->dplls.eec.dpll, pf->dplls.pps.dpll); if (ret) return ret; count = pf->dplls.num_inputs; - if (cgu) { + if (cgu || pf->dplls.unmanaged) { ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs, count, pf->dplls.num_outputs, - &ice_dpll_output_ops, + output_ops, pf->dplls.eec.dpll, pf->dplls.pps.dpll); if (ret) goto deinit_inputs; + if (pf->dplls.unmanaged) + return 0; count += pf->dplls.num_outputs; if (!pf->dplls.generic) { ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.sma, @@ -3224,11 +3275,11 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) deinit_outputs: ice_dpll_deinit_direct_pins(cgu, pf->dplls.outputs, pf->dplls.num_outputs, - &ice_dpll_output_ops, pf->dplls.pps.dpll, + output_ops, pf->dplls.pps.dpll, pf->dplls.eec.dpll); deinit_inputs: ice_dpll_deinit_direct_pins(cgu, pf->dplls.inputs, pf->dplls.num_inputs, - &ice_dpll_input_ops, pf->dplls.pps.dpll, + input_ops, pf->dplls.pps.dpll, pf->dplls.eec.dpll); return ret; } @@ -3284,7 +3335,8 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, if (type == DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf)) ops = &ice_dpll_pom_ops; - ice_dpll_update_state(pf, d, true); + if (!pf->dplls.unmanaged) + ice_dpll_update_state(pf, d, true); ret = dpll_device_register(d->dpll, type, ops, d); if (ret) { dpll_device_put(d->dpll); @@ -3310,6 +3362,33 @@ static void ice_dpll_deinit_worker(struct ice_pf *pf) kthread_destroy_worker(d->kworker); } +/** + * ice_dpll_pin_freq_info - find pin frequency from supported ones + * @hw: pointer to the hardware structure + * @pin_idx: pin index + * @input: if input pin + * + * This function searches through the array of supported frequencies for a + * DPLL pin and returns single frequency pin is capable, if pin support only + * one frequency. Shall be used only for dpll with driver hardcoded frequency. + * + * Return: + * * 0 - failure, pin uses multiple frequencies, + * * frequency - success. + */ +static u64 ice_dpll_pin_freq_info(struct ice_hw *hw, u8 pin_idx, bool input) +{ + struct dpll_pin_frequency *freqs; + u8 freq_num; + + /* Get supported frequencies for this pin */ + freqs = ice_cgu_get_pin_freq_supp(hw, pin_idx, input, &freq_num); + if (!freqs || freq_num != 1 || freqs[0].min != freqs[0].max) + return 0; + + return freqs[0].min; +} + /** * ice_dpll_init_worker - Initialize DPLLs periodic worker * @pf: board private structure @@ -3469,6 +3548,15 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, pins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input); pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input); if (input) { + if (pf->dplls.unmanaged) { + pins[i].freq = ice_dpll_pin_freq_info(hw, i, + input); + pins[i].state[0] = DPLL_PIN_STATE_CONNECTED; + pins[i].status = + ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP; + pins[i].flags[0] = ICE_DPLL_IN_ESYNC_ENABLED; + continue; + } ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i, &de->input_prio[i]); if (ret) @@ -3482,6 +3570,12 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, if (ice_dpll_is_sw_pin(pf, i, true)) pins[i].hidden = true; } else { + if (pf->dplls.unmanaged) { + pins[i].freq = ice_dpll_pin_freq_info(hw, i, + input); + pins[i].state[0] = DPLL_PIN_STATE_CONNECTED; + continue; + } ret = ice_cgu_get_output_pin_state_caps(hw, i, &caps); if (ret) return ret; @@ -3499,10 +3593,13 @@ 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) + if (input && !pf->dplls.unmanaged) { ret = ice_dpll_init_ref_sync_inputs(pf); + if (ret) + return ret; + } - return ret; + return 0; } /** @@ -3653,6 +3750,81 @@ static void ice_dpll_deinit_info(struct ice_pf *pf) kfree(pf->dplls.pps.input_prio); } +/** + * ice_dpll_lock_state_init_unmanaged - initialize lock state for unmanaged dpll + * @pf: board private structure + * + * Initialize the lock state for unmanaged DPLL by checking health status. + * For unmanaged DPLL, we rely on hardware autonomous operation. + * + * Return: + * * 0 - success + * * negative - init failure reason + */ +static int ice_dpll_lock_state_init_unmanaged(struct ice_pf *pf) +{ + u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK; + struct ice_aqc_health_status_elem buff; + int ret; + + ret = ice_get_last_health_status_code(&pf->hw, &buff, code); + if (ret) + return ret; + ice_dpll_lock_state_set_unmanaged(pf, &buff, false); + + return ret; +} + +/** + * ice_dpll_init_info_unmanaged - init dpll information for unmanaged dpll + * @pf: board private structure + * + * Acquire (from HW) and set basic dpll information (on pf->dplls struct). + * For unmanaged dpll mode. + * + * Return: + * * 0 - success + * * negative - init failure reason + */ +static int ice_dpll_init_info_unmanaged(struct ice_pf *pf) +{ + struct ice_dplls *d = &pf->dplls; + struct ice_dpll *de = &d->eec; + int ret = 0; + + d->clock_id = ice_generate_clock_id(pf); + d->num_inputs = ice_cgu_get_pin_num(&pf->hw, true); + d->num_outputs = ice_cgu_get_pin_num(&pf->hw, false); + ice_dpll_lock_state_init_unmanaged(pf); + d->inputs = kcalloc(d->num_inputs, sizeof(*d->inputs), GFP_KERNEL); + if (!d->inputs) + return -ENOMEM; + + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); + if (ret) + goto deinit_info; + + d->outputs = kcalloc(d->num_outputs, sizeof(*d->outputs), GFP_KERNEL); + if (!d->outputs) { + ret = -ENOMEM; + goto deinit_info; + } + + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT); + if (ret) + goto deinit_info; + + de->mode = DPLL_MODE_AUTOMATIC; + dev_dbg(ice_pf_to_dev(pf), "%s - success, inputs:%u, outputs:%u\n", + __func__, d->num_inputs, d->num_outputs); + return 0; +deinit_info: + dev_err(ice_pf_to_dev(pf), "%s - fail: d->inputs:%p, d->outputs:%p\n", + __func__, d->inputs, d->outputs); + ice_dpll_deinit_info(pf); + return ret; +} + /** * ice_dpll_init_info - prepare pf's dpll information structure * @pf: board private structure @@ -3686,6 +3858,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) dp->dpll_idx = abilities.pps_dpll_idx; d->num_inputs = abilities.num_inputs; d->num_outputs = abilities.num_outputs; + d->input_phase_adj_max = le32_to_cpu(abilities.max_in_phase_adj) & ICE_AQC_GET_CGU_MAX_PHASE_ADJ; d->output_phase_adj_max = le32_to_cpu(abilities.max_out_phase_adj) & @@ -3752,6 +3925,42 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) return ret; } +/** + * ice_dpll_lock_state_set_unmanaged - determine lock state from health status + * @pf: board private structure + * @buff: health status buffer + * @notify: if true, notify dpll device + * + * Set unmanaged dpll lock state based on health status code and internal data. + * Context: Acquires and releases pf->dplls.lock (must release before notify + * if called). + */ +void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf, + const struct ice_aqc_health_status_elem *buff, + bool notify) +{ + u32 internal_data = le32_to_cpu(buff->internal_data1); + struct ice_dpll *d = &pf->dplls.eec; + + if (!ice_pf_src_tmr_owned(pf)) + return; + + mutex_lock(&pf->dplls.lock); + if (buff->health_status_code == 0 || + internal_data == ICE_DPLL_HEALTH_STATUS_LOCKED) + d->dpll_state = DPLL_LOCK_STATUS_LOCKED; + else + d->dpll_state = DPLL_LOCK_STATUS_UNLOCKED; + + if (d->prev_dpll_state == d->dpll_state) + notify = false; + else + d->prev_dpll_state = d->dpll_state; + mutex_unlock(&pf->dplls.lock); + if (notify && d->dpll) + dpll_device_change_ntf(d->dpll); +} + /** * ice_dpll_deinit - Disable the driver/HW support for dpll subsystem * the dpll device. @@ -3771,15 +3980,55 @@ void ice_dpll_deinit(struct ice_pf *pf) if (cgu) ice_dpll_deinit_worker(pf); - ice_dpll_deinit_pins(pf, cgu); - ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu); - ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu); + ice_dpll_deinit_pins(pf, cgu || pf->dplls.unmanaged); + if (pf->dplls.pps.dpll) + ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu); + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu || pf->dplls.unmanaged); ice_dpll_deinit_info(pf); mutex_destroy(&pf->dplls.lock); } /** - * ice_dpll_init - initialize support for dpll subsystem + * ice_dpll_init_unmanaged - initialize support for unmanaged dpll subsystem + * @pf: board private structure + * + * Set up the device dplls for unmanaged mode, register them and pins connected + * within Linux dpll subsystem. Allow userspace to obtain state of DPLL. + * + * Context: Initializes pf->dplls.lock mutex. + */ +static void ice_dpll_init_unmanaged(struct ice_pf *pf) +{ + struct ice_dplls *d = &pf->dplls; + int err; + + if (!ice_pf_src_tmr_owned(pf)) + return; + err = ice_dpll_init_info_unmanaged(pf); + if (err) + goto err_exit; + mutex_init(&d->lock); + err = ice_dpll_init_dpll(pf, &pf->dplls.eec, true, DPLL_TYPE_EEC); + if (err) + goto deinit_info; + err = ice_dpll_init_pins(pf, true); + if (err) + goto deinit_eec; + set_bit(ICE_FLAG_DPLL, pf->flags); + + return; + +deinit_eec: + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, true); +deinit_info: + ice_dpll_deinit_info(pf); + mutex_destroy(&d->lock); +err_exit: + dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err); +} + +/** + * ice_dpll_init_managed - initialize support for managed dpll subsystem * @pf: board private structure * * Set up the device dplls, register them and pins connected within Linux dpll @@ -3788,7 +4037,7 @@ void ice_dpll_deinit(struct ice_pf *pf) * * Context: Initializes pf->dplls.lock mutex. */ -void ice_dpll_init(struct ice_pf *pf) +static void ice_dpll_init_managed(struct ice_pf *pf) { bool cgu = ice_is_feature_supported(pf, ICE_F_CGU); struct ice_dplls *d = &pf->dplls; @@ -3828,3 +4077,21 @@ void ice_dpll_init(struct ice_pf *pf) mutex_destroy(&d->lock); dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err); } + +/** + * ice_dpll_init - initialize support for dpll subsystem + * @pf: board private structure + * + * Set up the device dplls, register them and pins connected within Linux dpll + * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL + * configuration requests. + * + * Context: Initializes pf->dplls.lock mutex. + */ +void ice_dpll_init(struct ice_pf *pf) +{ + if (!pf->dplls.unmanaged) + ice_dpll_init_managed(pf); + else + ice_dpll_init_unmanaged(pf); +} diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index c0da03384ce9..fa61b4178b3c 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -8,6 +8,9 @@ #define ICE_DPLL_RCLK_NUM_MAX 4 +#define ICE_DPLL_UNMANAGED_PIN_NUM 4 +#define ICE_DPLL_IN_ESYNC_ENABLED ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN + /** * enum ice_dpll_pin_sw - enumerate ice software pin indices: * @ICE_DPLL_PIN_SW_1_IDX: index of first SW pin @@ -132,14 +135,22 @@ struct ice_dplls { s32 output_phase_adj_max; u32 periodic_counter; bool generic; + bool unmanaged; }; #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) void ice_dpll_init(struct ice_pf *pf); void ice_dpll_deinit(struct ice_pf *pf); +void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf, + const struct ice_aqc_health_status_elem *buff, + bool notify); #else static inline void ice_dpll_init(struct ice_pf *pf) { } static inline void ice_dpll_deinit(struct ice_pf *pf) { } +static inline void +ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf, + const struct ice_aqc_health_status_elem *buff, + bool notify) { } #endif #endif diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 2533876f1a2f..d0c3f9b78536 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4797,8 +4797,20 @@ static void ice_init_features(struct ice_pf *pf) if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_init(pf); + /* Initialize unmanaged DPLL detection */ + { + u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK; + int err; + + err = ice_is_health_status_code_supported(&pf->hw, code, + &pf->dplls.unmanaged); + if (err || !ice_is_unmanaged_cgu_in_netlist(&pf->hw)) + pf->dplls.unmanaged = false; + } + if (ice_is_feature_supported(pf, ICE_F_CGU) || - ice_is_feature_supported(pf, ICE_F_PHY_RCLK)) + ice_is_feature_supported(pf, ICE_F_PHY_RCLK) || + pf->dplls.unmanaged) ice_dpll_init(pf); /* Note: Flow director init failure is non-fatal to load */ diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index 35680dbe4a7f..4abbb9fd607d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -20,6 +20,10 @@ static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = { DPLL_PIN_FREQUENCY_10MHZ, }; +static struct dpll_pin_frequency ice_cgu_pin_freq_156_25mhz[] = { + DPLL_PIN_FREQUENCY_RANGE(156250000, 156250000), +}; + static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = { { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, @@ -131,6 +135,18 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { { "NONE", ZL_OUT5, 0, 0 }, }; +static const struct ice_cgu_pin_desc ice_e830_unmanaged_inputs[] = { + { "1588-TIME_SYNC", 0, DPLL_PIN_TYPE_EXT, + ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz }, +}; + +static const struct ice_cgu_pin_desc ice_e830_unmanaged_outputs[] = { + { "MAC-PHY-CLK", 0, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + ARRAY_SIZE(ice_cgu_pin_freq_156_25mhz), ice_cgu_pin_freq_156_25mhz }, + { "1588-TIME_REF", 1, DPLL_PIN_TYPE_INT_OSCILLATOR, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz}, +}; + /* Low level functions for interacting with and managing the device clock used * for the Precision Time Protocol. * @@ -5684,6 +5700,24 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size) case ICE_DEV_ID_E823C_SGMII: t = ice_cgu_get_pin_desc_e823(hw, input, size); break; + case ICE_DEV_ID_E830CC_BACKPLANE: + case ICE_DEV_ID_E830CC_QSFP56: + case ICE_DEV_ID_E830CC_SFP: + case ICE_DEV_ID_E830CC_SFP_DD: + case ICE_DEV_ID_E830C_BACKPLANE: + case ICE_DEV_ID_E830C_QSFP: + case ICE_DEV_ID_E830C_SFP: + case ICE_DEV_ID_E830_XXV_BACKPLANE: + case ICE_DEV_ID_E830_XXV_QSFP: + case ICE_DEV_ID_E830_XXV_SFP: + if (input) { + t = ice_e830_unmanaged_inputs; + *size = ARRAY_SIZE(ice_e830_unmanaged_inputs); + } else { + t = ice_e830_unmanaged_outputs; + *size = ARRAY_SIZE(ice_e830_unmanaged_outputs); + } + break; default: break; } @@ -5710,6 +5744,18 @@ int ice_cgu_get_num_pins(struct ice_hw *hw, bool input) return 0; } +/** + * ice_cgu_get_pin_num - get pin description array size + * @hw: pointer to the hw struct + * @input: if request is done against input or output pins + * + * Return: size of pin description array for given hw. + */ +int ice_cgu_get_pin_num(struct ice_hw *hw, bool input) +{ + return ice_cgu_get_num_pins(hw, input); +} + /** * ice_cgu_get_pin_type - get pin's type * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 5896b346e579..93901bccf1c4 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -356,6 +356,7 @@ int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data); int ice_write_sma_ctrl(struct ice_hw *hw, u8 data); int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries); int ice_cgu_get_num_pins(struct ice_hw *hw, bool input); +int ice_cgu_get_pin_num(struct ice_hw *hw, bool input); enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input); struct dpll_pin_frequency * ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num); -- 2.47.1 From: Grzegorz Nitka Unify handling of PHY firmware load delays across all E800 family devices. There is an existing mechanism to poll GL_MNG_FWSM_FW_LOADING_M bit of GL_MNG_FWSM register in order to verify whether PHY FW loading completed or not. Previously, this logic was limited to E827 variants only. Also, inform a user of possible delay in initialization process, by dumping informational message in dmesg log ("Link initialization is blocked by PHY FW initialization. Link initialization will continue after PHY FW initialization completes."). Signed-off-by: Grzegorz Nitka Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 79 ++++++--------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index e499a28e8e22..5d3c3b894437 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -203,42 +203,6 @@ bool ice_is_generic_mac(struct ice_hw *hw) hw->mac_type == ICE_MAC_GENERIC_3K_E825); } -/** - * ice_is_pf_c827 - check if pf contains c827 phy - * @hw: pointer to the hw struct - * - * Return: true if the device has c827 phy. - */ -static bool ice_is_pf_c827(struct ice_hw *hw) -{ - struct ice_aqc_get_link_topo cmd = {}; - u8 node_part_number; - u16 node_handle; - int status; - - if (hw->mac_type != ICE_MAC_E810) - return false; - - if (hw->device_id != ICE_DEV_ID_E810C_QSFP) - return true; - - cmd.addr.topo_params.node_type_ctx = - FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY) | - FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ICE_AQC_LINK_TOPO_NODE_CTX_PORT); - cmd.addr.topo_params.index = 0; - - status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number, - &node_handle); - - if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827) - return false; - - if (node_handle == E810C_QSFP_C827_0_HANDLE || node_handle == E810C_QSFP_C827_1_HANDLE) - return true; - - return false; -} - /** * ice_clear_pf_cfg - Clear PF configuration * @hw: pointer to the hardware structure @@ -958,30 +922,31 @@ static void ice_get_itr_intrl_gran(struct ice_hw *hw) } /** - * ice_wait_for_fw - wait for full FW readiness + * ice_wait_fw_load - wait for PHY firmware loading to complete * @hw: pointer to the hardware structure - * @timeout: milliseconds that can elapse before timing out + * @timeout: milliseconds that can elapse before timing out, 0 to bypass waiting * - * Return: 0 on success, -ETIMEDOUT on timeout. + * Return: + * * 0 on success + * * negative on timeout */ -static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout) +static int ice_wait_fw_load(struct ice_hw *hw, u32 timeout) { - int fw_loading; - u32 elapsed = 0; + int fw_loading_reg; - while (elapsed <= timeout) { - fw_loading = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M; + if (!timeout) + return 0; - /* firmware was not yet loaded, we have to wait more */ - if (fw_loading) { - elapsed += 100; - msleep(100); - continue; - } + fw_loading_reg = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M; + /* notify the user only once if PHY FW is still loading */ + if (fw_loading_reg) + dev_info(ice_hw_to_dev(hw), "Link initialization is blocked by PHY FW initialization. Link initialization will continue after PHY FW initialization completes.\n"); + else return 0; - } - return -ETIMEDOUT; + return rd32_poll_timeout(hw, GL_MNG_FWSM, fw_loading_reg, + !(fw_loading_reg & GL_MNG_FWSM_FW_LOADING_M), + 10000, timeout * 1000); } static int __fwlog_send_cmd(void *priv, struct libie_aq_desc *desc, void *buf, @@ -1171,12 +1136,10 @@ int ice_init_hw(struct ice_hw *hw) * due to necessity of loading FW from an external source. * This can take even half a minute. */ - if (ice_is_pf_c827(hw)) { - status = ice_wait_for_fw(hw, 30000); - if (status) { - dev_err(ice_hw_to_dev(hw), "ice_wait_for_fw timed out"); - goto err_unroll_fltr_mgmt_struct; - } + status = ice_wait_fw_load(hw, 30000); + if (status) { + dev_err(ice_hw_to_dev(hw), "ice_wait_fw_load timed out"); + goto err_unroll_fltr_mgmt_struct; } hw->lane_num = ice_get_phy_lane_number(hw); -- 2.47.1 From: Birger Koblitz Add support for 10G-BX modules, i.e. 10GBit Ethernet over a single strand Single-Mode fiber. The initialization of a 10G-BX SFP+ is the same as for a 10G SX/LX module, and is identified according to SFF-8472 table 5-3, footnote 3 by the 10G Ethernet Compliance Codes field being empty, the Nominal Bit Rate being compatible with 12.5GBit, and the module being a fiber module with a Single Mode fiber link length. This was tested using a Lightron WSPXG-HS3LC-IEA 1270/1330nm 10km transceiver: $ sudo ethtool -m enp1s0f1 Identifier : 0x03 (SFP) Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID) Connector : 0x07 (LC) Transceiver codes : 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 Encoding : 0x01 (8B/10B) BR Nominal : 10300MBd Rate identifier : 0x00 (unspecified) Length (SMF) : 10km Length (OM2) : 0m Length (OM1) : 0m Length (Copper or Active cable) : 0m Length (OM3) : 0m Laser wavelength : 1330nm Vendor name : Lightron Inc. Vendor OUI : 00:13:c5 Vendor PN : WSPXG-HS3LC-IEA Vendor rev : 0000 Option values : 0x00 0x1a Option : TX_DISABLE implemented BR margin max : 0% BR margin min : 0% Vendor SN : S142228617 Date code : 140611 Optical diagnostics support : Yes Signed-off-by: Birger Koblitz Reviewed-by: Andrew Lunn Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 7 +++ .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 + drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 43 ++++++++++++++++--- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h | 2 + drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 + 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 3069b583fd81..89c7fed7b8fc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -342,6 +342,13 @@ static int ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, return 0; } + if (hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1) { + *speed = IXGBE_LINK_SPEED_10GB_FULL; + *autoneg = false; + return 0; + } + /* * Determine link capabilities based on the stored value of AUTOC, * which represents EEPROM defaults. If AUTOC value has not been diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 2ad81f687a84..bb4b53fee234 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -351,6 +351,8 @@ static int ixgbe_get_link_ksettings(struct net_device *netdev, case ixgbe_sfp_type_1g_lx_core1: case ixgbe_sfp_type_1g_bx_core0: case ixgbe_sfp_type_1g_bx_core1: + case ixgbe_sfp_type_10g_bx_core0: + case ixgbe_sfp_type_10g_bx_core1: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 2449e4cf2679..3330cb334a17 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -1534,8 +1534,10 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) struct ixgbe_adapter *adapter = hw->back; u8 oui_bytes[3] = {0, 0, 0}; u8 bitrate_nominal = 0; + u8 sm_length_100m = 0; u8 comp_codes_10g = 0; u8 comp_codes_1g = 0; + u8 sm_length_km = 0; u16 enforce_sfp = 0; u32 vendor_oui = 0; u8 identifier = 0; @@ -1678,6 +1680,31 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) else hw->phy.sfp_type = ixgbe_sfp_type_1g_bx_core1; + /* Support Ethernet 10G-BX, checking the Bit Rate + * Nominal Value as per SFF-8472 to be 12.5 Gb/s (67h) and + * Single Mode fibre with at least 1km link length + */ + } else if ((!comp_codes_10g) && (bitrate_nominal == 0x67) && + (!(cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)) && + (!(cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE))) { + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_SM_LENGTH_KM, + &sm_length_km); + if (status != 0) + goto err_read_i2c_eeprom; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_SM_LENGTH_100M, + &sm_length_100m); + if (status != 0) + goto err_read_i2c_eeprom; + if (sm_length_km > 0 || sm_length_100m >= 10) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_10g_bx_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_10g_bx_core1; + } } else { hw->phy.sfp_type = ixgbe_sfp_type_unknown; } @@ -1768,7 +1795,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) { + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) { hw->phy.type = ixgbe_phy_sfp_unsupported; return -EOPNOTSUPP; } @@ -1786,7 +1815,9 @@ int ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) { + hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) return 0; @@ -2016,20 +2047,22 @@ int ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, return -EOPNOTSUPP; /* - * Limiting active cables and 1G Phys must be initialized as + * Limiting active cables, 10G BX and 1G Phys must be initialized as * SR modules */ if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || sfp_type == ixgbe_sfp_type_1g_lx_core0 || sfp_type == ixgbe_sfp_type_1g_cu_core0 || sfp_type == ixgbe_sfp_type_1g_sx_core0 || - sfp_type == ixgbe_sfp_type_1g_bx_core0) + sfp_type == ixgbe_sfp_type_1g_bx_core0 || + sfp_type == ixgbe_sfp_type_10g_bx_core0) sfp_type = ixgbe_sfp_type_srlr_core0; else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || sfp_type == ixgbe_sfp_type_1g_lx_core1 || sfp_type == ixgbe_sfp_type_1g_cu_core1 || sfp_type == ixgbe_sfp_type_1g_sx_core1 || - sfp_type == ixgbe_sfp_type_1g_bx_core1) + sfp_type == ixgbe_sfp_type_1g_bx_core1 || + sfp_type == ixgbe_sfp_type_10g_bx_core1) sfp_type = ixgbe_sfp_type_srlr_core1; /* Read offset to PHY init contents */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index 81179c60af4e..039ba4b6c120 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -32,6 +32,8 @@ #define IXGBE_SFF_QSFP_1GBE_COMP 0x86 #define IXGBE_SFF_QSFP_CABLE_LENGTH 0x92 #define IXGBE_SFF_QSFP_DEVICE_TECH 0x93 +#define IXGBE_SFF_SM_LENGTH_KM 0xE +#define IXGBE_SFF_SM_LENGTH_100M 0xF /* Bitmasks */ #define IXGBE_SFF_DA_PASSIVE_CABLE 0x4 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index b1bfeb21537a..61f2ef67defd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3286,6 +3286,8 @@ enum ixgbe_sfp_type { ixgbe_sfp_type_1g_lx_core1 = 14, ixgbe_sfp_type_1g_bx_core0 = 15, ixgbe_sfp_type_1g_bx_core1 = 16, + ixgbe_sfp_type_10g_bx_core0 = 17, + ixgbe_sfp_type_10g_bx_core1 = 18, ixgbe_sfp_type_not_present = 0xFFFE, ixgbe_sfp_type_unknown = 0xFFFF -- 2.47.1 From: Natalia Wochtman Flex array should be at the end of the structure and use [] syntax Remove unused fields of ixgbevf_q_vector. They aren't used since busy poll was moved to core code in commit 508aac6dee02 ("ixgbevf: get rid of custom busy polling code"). Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Signed-off-by: Natalia Wochtman Reviewed-by: Jacob Keller Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 039187607e98..516a6fdd23d0 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -241,23 +241,7 @@ struct ixgbevf_q_vector { char name[IFNAMSIZ + 9]; /* for dynamic allocation of rings associated with this q_vector */ - struct ixgbevf_ring ring[0] ____cacheline_internodealigned_in_smp; -#ifdef CONFIG_NET_RX_BUSY_POLL - unsigned int state; -#define IXGBEVF_QV_STATE_IDLE 0 -#define IXGBEVF_QV_STATE_NAPI 1 /* NAPI owns this QV */ -#define IXGBEVF_QV_STATE_POLL 2 /* poll owns this QV */ -#define IXGBEVF_QV_STATE_DISABLED 4 /* QV is disabled */ -#define IXGBEVF_QV_OWNED (IXGBEVF_QV_STATE_NAPI | IXGBEVF_QV_STATE_POLL) -#define IXGBEVF_QV_LOCKED (IXGBEVF_QV_OWNED | IXGBEVF_QV_STATE_DISABLED) -#define IXGBEVF_QV_STATE_NAPI_YIELD 8 /* NAPI yielded this QV */ -#define IXGBEVF_QV_STATE_POLL_YIELD 16 /* poll yielded this QV */ -#define IXGBEVF_QV_YIELD (IXGBEVF_QV_STATE_NAPI_YIELD | \ - IXGBEVF_QV_STATE_POLL_YIELD) -#define IXGBEVF_QV_USER_PEND (IXGBEVF_QV_STATE_POLL | \ - IXGBEVF_QV_STATE_POLL_YIELD) - spinlock_t lock; -#endif /* CONFIG_NET_RX_BUSY_POLL */ + struct ixgbevf_ring ring[] ____cacheline_internodealigned_in_smp; }; /* microsecond values for various ITR rates shifted by 2 to fit itr register -- 2.47.1 From: Emil Tantilov Convert vport state to a bitmap and remove the DOWN state which is redundant in the existing logic. There are no functional changes aside from the use of bitwise operations when setting and checking the states. Removed the double underscore to be consistent with the naming of other bitmaps in the header and renamed current_state to vport_is_up to match the meaning of the new variable. Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Chittim Madhu Signed-off-by: Emil Tantilov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 12 ++++------ .../net/ethernet/intel/idpf/idpf_ethtool.c | 12 +++++----- drivers/net/ethernet/intel/idpf/idpf_lib.c | 24 +++++++++---------- .../ethernet/intel/idpf/idpf_singleq_txrx.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++-- drivers/net/ethernet/intel/idpf/xdp.c | 2 +- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 50fa7be0c00d..8cfc68cbfa06 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -131,14 +131,12 @@ enum idpf_cap_field { /** * enum idpf_vport_state - Current vport state - * @__IDPF_VPORT_DOWN: Vport is down - * @__IDPF_VPORT_UP: Vport is up - * @__IDPF_VPORT_STATE_LAST: Must be last, number of states + * @IDPF_VPORT_UP: Vport is up + * @IDPF_VPORT_STATE_NBITS: Must be last, number of states */ enum idpf_vport_state { - __IDPF_VPORT_DOWN, - __IDPF_VPORT_UP, - __IDPF_VPORT_STATE_LAST, + IDPF_VPORT_UP, + IDPF_VPORT_STATE_NBITS }; /** @@ -162,7 +160,7 @@ struct idpf_netdev_priv { u16 vport_idx; u16 max_tx_hdr_size; u16 tx_max_bufs; - enum idpf_vport_state state; + DECLARE_BITMAP(state, IDPF_VPORT_STATE_NBITS); struct rtnl_link_stats64 netstats; spinlock_t stats_lock; }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index a5a1eec9ade8..eed166bc46f3 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -386,7 +386,7 @@ static int idpf_get_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; rxfh->hfunc = ETH_RSS_HASH_TOP; @@ -436,7 +436,7 @@ static int idpf_set_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && @@ -1167,7 +1167,7 @@ static void idpf_get_ethtool_stats(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) { + if (!test_bit(IDPF_VPORT_UP, np->state)) { idpf_vport_ctrl_unlock(netdev); return; @@ -1319,7 +1319,7 @@ static int idpf_get_q_coalesce(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; if (q_num >= vport->num_rxq && q_num >= vport->num_txq) { @@ -1507,7 +1507,7 @@ static int idpf_set_coalesce(struct net_device *netdev, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto unlock_mutex; for (i = 0; i < vport->num_txq; i++) { @@ -1710,7 +1710,7 @@ static void idpf_get_ts_stats(struct net_device *netdev, ts_stats->err = u64_stats_read(&vport->tstamp_stats.discarded); } while (u64_stats_fetch_retry(&vport->tstamp_stats.stats_sync, start)); - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) goto exit; for (u16 i = 0; i < vport->num_txq_grp; i++) { diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 8a941f0fb048..7a7e101afeb6 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -519,7 +519,7 @@ static int idpf_del_mac_filter(struct idpf_vport *vport, } spin_unlock_bh(&vport_config->mac_filter_list_lock); - if (np->state == __IDPF_VPORT_UP) { + if (test_bit(IDPF_VPORT_UP, np->state)) { int err; err = idpf_add_del_mac_filters(vport, np, false, async); @@ -590,7 +590,7 @@ static int idpf_add_mac_filter(struct idpf_vport *vport, if (err) return err; - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) err = idpf_add_del_mac_filters(vport, np, true, async); return err; @@ -894,7 +894,7 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); - if (np->state <= __IDPF_VPORT_DOWN) + if (!test_bit(IDPF_VPORT_UP, np->state)) return; if (rtnl) @@ -921,7 +921,7 @@ static void idpf_vport_stop(struct idpf_vport *vport, bool rtnl) idpf_xdp_rxq_info_deinit_all(vport); idpf_vport_queues_rel(vport); idpf_vport_intr_rel(vport); - np->state = __IDPF_VPORT_DOWN; + clear_bit(IDPF_VPORT_UP, np->state); if (rtnl) rtnl_unlock(); @@ -1345,7 +1345,7 @@ static int idpf_up_complete(struct idpf_vport *vport) netif_tx_start_all_queues(vport->netdev); } - np->state = __IDPF_VPORT_UP; + set_bit(IDPF_VPORT_UP, np->state); return 0; } @@ -1391,7 +1391,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) struct idpf_vport_config *vport_config; int err; - if (np->state != __IDPF_VPORT_DOWN) + if (test_bit(IDPF_VPORT_UP, np->state)) return -EBUSY; if (rtnl) @@ -1602,7 +1602,7 @@ void idpf_init_task(struct work_struct *work) /* Once state is put into DOWN, driver is ready for dev_open */ np = netdev_priv(vport->netdev); - np->state = __IDPF_VPORT_DOWN; + clear_bit(IDPF_VPORT_UP, np->state); if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags)) idpf_vport_open(vport, true); @@ -1801,7 +1801,7 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter) continue; np = netdev_priv(adapter->netdevs[i]); - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) set_bit(IDPF_VPORT_UP_REQUESTED, adapter->vport_config[i]->flags); } @@ -1939,7 +1939,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, enum idpf_vport_reset_cause reset_cause) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); - enum idpf_vport_state current_state = np->state; + bool vport_is_up = test_bit(IDPF_VPORT_UP, np->state); struct idpf_adapter *adapter = vport->adapter; struct idpf_vport *new_vport; int err; @@ -1990,7 +1990,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, goto free_vport; } - if (current_state <= __IDPF_VPORT_DOWN) { + if (!vport_is_up) { idpf_send_delete_queues_msg(vport); } else { set_bit(IDPF_VPORT_DEL_QUEUES, vport->flags); @@ -2023,7 +2023,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, if (err) goto err_open; - if (current_state == __IDPF_VPORT_UP) + if (vport_is_up) err = idpf_vport_open(vport, false); goto free_vport; @@ -2033,7 +2033,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, vport->num_rxq, vport->num_bufq); err_open: - if (current_state == __IDPF_VPORT_UP) + if (vport_is_up) idpf_vport_open(vport, false); free_vport: diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c index 61e613066140..e3ddf18dcbf5 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c @@ -570,7 +570,7 @@ static bool idpf_tx_singleq_clean(struct idpf_tx_queue *tx_q, int napi_budget, np = netdev_priv(tx_q->netdev); nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx); - dont_wake = np->state != __IDPF_VPORT_UP || + dont_wake = !test_bit(IDPF_VPORT_UP, np->state) || !netif_carrier_ok(tx_q->netdev); __netif_txq_completed_wake(nq, ss.packets, ss.bytes, IDPF_DESC_UNUSED(tx_q), IDPF_TX_WAKE_THRESH, diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 828f7c444d30..1993a3b0da59 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2275,7 +2275,7 @@ static bool idpf_tx_clean_complq(struct idpf_compl_queue *complq, int budget, /* Update BQL */ nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx); - dont_wake = !complq_ok || np->state != __IDPF_VPORT_UP || + dont_wake = !complq_ok || !test_bit(IDPF_VPORT_UP, np->state) || !netif_carrier_ok(tx_q->netdev); /* Check if the TXQ needs to and can be restarted */ __netif_txq_completed_wake(nq, tx_q->cleaned_pkts, tx_q->cleaned_bytes, diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index cbb5fa30f5a0..44cd4b466c48 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -68,7 +68,7 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter, vport->link_up = v2e->link_status; - if (np->state != __IDPF_VPORT_UP) + if (!test_bit(IDPF_VPORT_UP, np->state)) return; if (vport->link_up) { @@ -2755,7 +2755,7 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) /* Don't send get_stats message if the link is down */ - if (np->state <= __IDPF_VPORT_DOWN) + if (!test_bit(IDPF_VPORT_UP, np->state)) return 0; stats_msg.vport_id = cpu_to_le32(vport->vport_id); diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c index 21ce25b0567f..958d16f87424 100644 --- a/drivers/net/ethernet/intel/idpf/xdp.c +++ b/drivers/net/ethernet/intel/idpf/xdp.c @@ -418,7 +418,7 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport, if (test_bit(IDPF_REMOVE_IN_PROG, vport->adapter->flags) || !test_bit(IDPF_VPORT_REG_NETDEV, cfg->flags) || !!vport->xdp_prog == !!prog) { - if (np->state == __IDPF_VPORT_UP) + if (test_bit(IDPF_VPORT_UP, np->state)) idpf_xdp_copy_prog_to_rqs(vport, prog); old = xchg(&vport->xdp_prog, prog); -- 2.47.1 The caller, ethtool_set_eeprom(), already performs the same checks so these are unnecessary in the driver. This reverts commit 90fb7db49c6d ("e1000e: fix heap overflow in e1000_set_eeprom"), however, corrections for RCT have been kept. Link: https://lore.kernel.org/all/db92fcc8-114d-4e85-9d15-7860545bc65e@suse.de/ Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/ethtool.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index cee57a2149ab..7b1ac90b3de4 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -551,9 +551,9 @@ static int e1000_set_eeprom(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - size_t total_len, max_len; u16 *eeprom_buff; int ret_val = 0; + size_t max_len; int first_word; int last_word; void *ptr; @@ -571,10 +571,6 @@ static int e1000_set_eeprom(struct net_device *netdev, max_len = hw->nvm.word_size * 2; - if (check_add_overflow(eeprom->offset, eeprom->len, &total_len) || - total_len > max_len) - return -EFBIG; - first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); -- 2.47.1 From: Alok Tiwari ixgbe_non_sfp_link_config() is called twice in ixgbe_open() once to assign its return value to err and again in the conditional check. This patch uses the stored err value instead of calling the function a second time. This avoids redundant work and ensures consistent error reporting. Also fix a small typo in the ixgbe_remove() comment: "The could be caused" -> "This could be caused". Signed-off-by: Alok Tiwari Reviewed-by: Jedrzej Jagielski Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 3190ce7e44c7..4af3b3e71ff1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7449,7 +7449,7 @@ int ixgbe_open(struct net_device *netdev) adapter->hw.link.link_info.link_cfg_err); err = ixgbe_non_sfp_link_config(&adapter->hw); - if (ixgbe_non_sfp_link_config(&adapter->hw)) + if (err) e_dev_err("Link setup failed, err %d.\n", err); } @@ -12046,7 +12046,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * @pdev: PCI device information struct * * ixgbe_remove is called by the PCI subsystem to alert the driver - * that it should release a PCI device. The could be caused by a + * that it should release a PCI device. This could be caused by a * Hot-Plug event, or because the driver is going to be removed from * memory. **/ -- 2.47.1 From: Alok Tiwari idpf_compl_queue uses a union for comp, comp_4b, and desc_ring. The release path should check complq->desc_ring to determine whether the DMA descriptor ring is allocated. The current check against comp works but is leftover from a previous commit and is misleading in this context. Switching the check to desc_ring improves readability and more directly reflects the intended meaning, since desc_ring is the field representing the allocated DMA-backed descriptor ring. No functional change. Signed-off-by: Alok Tiwari Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 1993a3b0da59..e2b6b9e26102 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -134,7 +134,7 @@ static void idpf_compl_desc_rel(struct idpf_compl_queue *complq) { idpf_xsk_clear_queue(complq, VIRTCHNL2_QUEUE_TYPE_TX_COMPLETION); - if (!complq->comp) + if (!complq->desc_ring) return; dma_free_coherent(complq->netdev->dev.parent, complq->size, -- 2.47.1 From: Alok Tiwari The error messages in idpf_rx_desc_alloc_all() used the group index i when reporting memory allocation failures for individual Rx and Rx buffer queues. This is incorrect. Update the messages to use the correct queue index j and include the queue group index i for clearer identification of the affected Rx and Rx buffer queues. Signed-off-by: Alok Tiwari Reviewed-by: Simon Horman Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index e2b6b9e26102..1d91c56f7469 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -922,8 +922,8 @@ static int idpf_rx_desc_alloc_all(struct idpf_vport *vport) err = idpf_rx_desc_alloc(vport, q); if (err) { pci_err(vport->adapter->pdev, - "Memory allocation for Rx Queue %u failed\n", - i); + "Memory allocation for Rx queue %u from queue group %u failed\n", + j, i); goto err_out; } } @@ -939,8 +939,8 @@ static int idpf_rx_desc_alloc_all(struct idpf_vport *vport) err = idpf_bufq_desc_alloc(vport, q); if (err) { pci_err(vport->adapter->pdev, - "Memory allocation for Rx Buffer Queue %u failed\n", - i); + "Memory allocation for Rx Buffer Queue %u from queue group %u failed\n", + j, i); goto err_out; } } -- 2.47.1 From: Alok Tiwari - Fix a typo in the ice_fdir_has_frag() kernel-doc comment ("is" -> "if") - Correct the NVM erase error message format string from "0x02%x" to "0x%02x" so the module value is printed correctly. Signed-off-by: Alok Tiwari Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_fdir.c | 2 +- drivers/net/ethernet/intel/ice/ice_fw_update.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.c b/drivers/net/ethernet/intel/ice/ice_fdir.c index 26b357c0ae15..b29fbdec9442 100644 --- a/drivers/net/ethernet/intel/ice/ice_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_fdir.c @@ -1121,7 +1121,7 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input, * ice_fdir_has_frag - does flow type have 2 ptypes * @flow: flow ptype * - * returns true is there is a fragment packet for this ptype + * Return: true if there is a fragment packet for this ptype */ bool ice_fdir_has_frag(enum ice_fltr_ptype flow) { diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c index d86db081579f..973a13d3d92a 100644 --- a/drivers/net/ethernet/intel/ice/ice_fw_update.c +++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c @@ -534,7 +534,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", + dev_err(dev, "Firmware failed to erase %s (module 0x%02x), aq_err %s\n", component, module, libie_aq_str((enum libie_aq_err)completion_retval)); NL_SET_ERR_MSG_MOD(extack, "Firmware failed to erase flash"); -- 2.47.1 From: Alok Tiwari The current dev_warn messages for too many VLAN changes are confusing and one place incorrectly references "add" instead of "delete" VLANs due to copy-paste errors. - Use dev_info instead of dev_warn to lower the log level. - Rephrase the message to: "virtchnl: Too many VLAN [add|delete] ([v1|v2]) requests; splitting into multiple messages to PF\n". Suggested-by: Przemek Kitszel Signed-off-by: Alok Tiwari Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 34a422a4a29c..88156082a41d 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -793,7 +793,8 @@ void iavf_add_vlans(struct iavf_adapter *adapter) len = virtchnl_struct_size(vvfl, vlan_id, count); if (len > IAVF_MAX_AQ_BUF_SIZE) { - dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); + dev_info(&adapter->pdev->dev, + "virtchnl: Too many VLAN add (v1) requests; splitting into multiple messages to PF\n"); while (len > IAVF_MAX_AQ_BUF_SIZE) len = virtchnl_struct_size(vvfl, vlan_id, --count); @@ -838,7 +839,8 @@ void iavf_add_vlans(struct iavf_adapter *adapter) len = virtchnl_struct_size(vvfl_v2, filters, count); if (len > IAVF_MAX_AQ_BUF_SIZE) { - dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); + dev_info(&adapter->pdev->dev, + "virtchnl: Too many VLAN add (v2) requests; splitting into multiple messages to PF\n"); while (len > IAVF_MAX_AQ_BUF_SIZE) len = virtchnl_struct_size(vvfl_v2, filters, --count); @@ -941,7 +943,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) len = virtchnl_struct_size(vvfl, vlan_id, count); if (len > IAVF_MAX_AQ_BUF_SIZE) { - dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n"); + dev_info(&adapter->pdev->dev, + "virtchnl: Too many VLAN delete (v1) requests; splitting into multiple messages to PF\n"); while (len > IAVF_MAX_AQ_BUF_SIZE) len = virtchnl_struct_size(vvfl, vlan_id, --count); @@ -987,7 +990,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) len = virtchnl_struct_size(vvfl_v2, filters, count); if (len > IAVF_MAX_AQ_BUF_SIZE) { - dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); + dev_info(&adapter->pdev->dev, + "virtchnl: Too many VLAN delete (v2) requests; splitting into multiple messages to PF\n"); while (len > IAVF_MAX_AQ_BUF_SIZE) len = virtchnl_struct_size(vvfl_v2, filters, --count); -- 2.47.1