Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
ice: fix crash on probe for DPLL enabled E810 LOM
Browse files Browse the repository at this point in the history
The E810 Lan On Motherboard (LOM) design is vendor specific. Intel
provides the reference design, but it is up to vendor on the final
product design. For some cases, like Linux DPLL support, the static
values defined in the driver does not reflect the actual LOM design.
Current implementation of dpll pins is causing the crash on probe
of the ice driver for such DPLL enabled E810 LOM designs:

WARNING: (...) at drivers/dpll/dpll_core.c:495 dpll_pin_get+0x2c4/0x330
...
Call Trace:
 <TASK>
 ? __warn+0x83/0x130
 ? dpll_pin_get+0x2c4/0x330
 ? report_bug+0x1b7/0x1d0
 ? handle_bug+0x42/0x70
 ? exc_invalid_op+0x18/0x70
 ? asm_exc_invalid_op+0x1a/0x20
 ? dpll_pin_get+0x117/0x330
 ? dpll_pin_get+0x2c4/0x330
 ? dpll_pin_get+0x117/0x330
 ice_dpll_get_pins.isra.0+0x52/0xe0 [ice]
...

The number of dpll pins enabled by LOM vendor is greater than expected
and defined in the driver for Intel designed NICs, which causes the crash.

Prevent the crash and allow generic pin initialization within Linux DPLL
subsystem for DPLL enabled E810 LOM designs.

Newly designed solution for described issue will be based on "per HW
design" pin initialization. It requires pin information dynamically
acquired from the firmware and is already in progress, planned for
next-tree only.

Fixes: d7999f5 ("ice: implement dpll interface to control cgu")
Reviewed-by: Karol Kolacinski <karol.kolacinski@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
kubalewski authored and Paolo Abeni committed Oct 29, 2024
1 parent 3e13a8c commit 6e58c33
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
70 changes: 70 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_dpll.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define ICE_DPLL_PIN_IDX_INVALID 0xff
#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

/**
* enum ice_dpll_pin_type - enumerate ice pin types:
Expand Down Expand Up @@ -2063,6 +2064,73 @@ static int ice_dpll_init_worker(struct ice_pf *pf)
return 0;
}

/**
* ice_dpll_init_info_pins_generic - initializes generic pins info
* @pf: board private structure
* @input: if input pins initialized
*
* Init information for generic pins, cache them in PF's pins structures.
*
* Return:
* * 0 - success
* * negative - init failure reason
*/
static int ice_dpll_init_info_pins_generic(struct ice_pf *pf, bool input)
{
struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps;
static const char labels[][sizeof("99")] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "10", "11", "12", "13", "14", "15" };
u32 cap = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
enum ice_dpll_pin_type pin_type;
int i, pin_num, ret = -EINVAL;
struct ice_dpll_pin *pins;
u32 phase_adj_max;

if (input) {
pin_num = pf->dplls.num_inputs;
pins = pf->dplls.inputs;
phase_adj_max = pf->dplls.input_phase_adj_max;
pin_type = ICE_DPLL_PIN_TYPE_INPUT;
cap |= DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE;
} else {
pin_num = pf->dplls.num_outputs;
pins = pf->dplls.outputs;
phase_adj_max = pf->dplls.output_phase_adj_max;
pin_type = ICE_DPLL_PIN_TYPE_OUTPUT;
}
if (pin_num > ARRAY_SIZE(labels))
return ret;

for (i = 0; i < pin_num; i++) {
pins[i].idx = i;
pins[i].prop.board_label = labels[i];
pins[i].prop.phase_range.min = phase_adj_max;
pins[i].prop.phase_range.max = -phase_adj_max;
pins[i].prop.capabilities = cap;
pins[i].pf = pf;
ret = ice_dpll_pin_state_update(pf, &pins[i], pin_type, NULL);
if (ret)
break;
if (input && pins[i].freq == ICE_DPLL_PIN_GEN_RCLK_FREQ)
pins[i].prop.type = DPLL_PIN_TYPE_MUX;
else
pins[i].prop.type = DPLL_PIN_TYPE_EXT;
if (!input)
continue;
ret = ice_aq_get_cgu_ref_prio(&pf->hw, de->dpll_idx, i,
&de->input_prio[i]);
if (ret)
break;
ret = ice_aq_get_cgu_ref_prio(&pf->hw, dp->dpll_idx, i,
&dp->input_prio[i]);
if (ret)
break;
}

return ret;
}

/**
* ice_dpll_init_info_direct_pins - initializes direct pins info
* @pf: board private structure
Expand Down Expand Up @@ -2101,6 +2169,8 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
default:
return -EINVAL;
}
if (num_pins != ice_cgu_get_num_pins(hw, input))
return ice_dpll_init_info_pins_generic(pf, input);

for (i = 0; i < num_pins; i++) {
caps = 0;
Expand Down
21 changes: 19 additions & 2 deletions drivers/net/ethernet/intel/ice/ice_ptp_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = {
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
{ "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS,
ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz },
{ "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0, },
};

static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = {
Expand All @@ -52,7 +51,6 @@ static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = {
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
{ "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS,
ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz },
{ "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, },
};

static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_outputs[] = {
Expand Down Expand Up @@ -5964,6 +5962,25 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size)
return t;
}

/**
* ice_cgu_get_num_pins - 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_num_pins(struct ice_hw *hw, bool input)
{
const struct ice_cgu_pin_desc *t;
int size;

t = ice_cgu_get_pin_desc(hw, input, &size);
if (t)
return size;

return 0;
}

/**
* ice_cgu_get_pin_type - get pin's type
* @hw: pointer to the hw struct
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/ice/ice_ptp_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data);
int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data);
bool ice_is_pca9575_present(struct ice_hw *hw);
int ice_cgu_get_num_pins(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);
Expand Down

0 comments on commit 6e58c33

Please sign in to comment.