@@ -607,6 +607,11 @@ struct ice_pf {
#define ICE_VF_AGG_NODE_ID_START 65
#define ICE_MAX_VF_AGG_NODES 32
struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
+
+ enum ice_eec_state synce_dpll_state;
+ u8 synce_dpll_pin;
+ enum ice_eec_state ptp_dpll_state;
+ u8 ptp_dpll_pin;
};
struct ice_netdev_priv {
@@ -1808,6 +1808,36 @@ struct ice_aqc_add_rdma_qset_data {
struct ice_aqc_add_tx_rdma_qset_entry rdma_qsets[];
};
+/* Get CGU DPLL status (direct 0x0C66) */
+struct ice_aqc_get_cgu_dpll_status {
+ u8 dpll_num;
+ u8 ref_state;
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_LOS BIT(0)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_SCM BIT(1)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_CFM BIT(2)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_GST BIT(3)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_PFM BIT(4)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_ESYNC BIT(6)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_FAST_LOCK_EN BIT(7)
+ __le16 dpll_state;
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK BIT(0)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO BIT(1)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY BIT(2)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_FLHIT BIT(5)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_PSLHIT BIT(7)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT 8
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SEL \
+ ICE_M(0x1F, ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT)
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE_SHIFT 13
+#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE \
+ ICE_M(0x7, ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE_SHIFT)
+ __le32 phase_offset_h;
+ __le32 phase_offset_l;
+ u8 eec_mode;
+ u8 rsvd[1];
+ __le16 node_handle;
+};
+
/* Configure Firmware Logging Command (indirect 0xFF09)
* Logging Information Read Response (indirect 0xFF10)
* Note: The 0xFF10 command has no input parameters.
@@ -2039,6 +2069,7 @@ struct ice_aq_desc {
struct ice_aqc_fw_logging fw_logging;
struct ice_aqc_get_clear_fw_log get_clear_fw_log;
struct ice_aqc_download_pkg download_pkg;
+ struct ice_aqc_get_cgu_dpll_status get_cgu_dpll_status;
struct ice_aqc_driver_shared_params drv_shared_params;
struct ice_aqc_set_mac_lb set_mac_lb;
struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
@@ -2205,6 +2236,9 @@ enum ice_adminq_opc {
ice_aqc_opc_update_pkg = 0x0C42,
ice_aqc_opc_get_pkg_info_list = 0x0C43,
+ /* 1588/SyncE commands/events */
+ ice_aqc_opc_get_cgu_dpll_status = 0x0C66,
+
ice_aqc_opc_driver_shared_params = 0x0C90,
/* Standalone Commands/Events */
@@ -4644,6 +4644,42 @@ ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
return ice_status_to_errno(status);
}
+/**
+ * ice_aq_get_cgu_dpll_status
+ * @hw: pointer to the HW struct
+ * @dpll_num: DPLL index
+ * @ref_state: Reference clock state
+ * @dpll_state: DPLL state
+ * @phase_offset: Phase offset in ps
+ * @eec_mode: EEC_mode
+ *
+ * Get CGU DPLL status (0x0C66)
+ */
+enum ice_status
+ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state,
+ u16 *dpll_state, u64 *phase_offset, u8 *eec_mode)
+{
+ struct ice_aqc_get_cgu_dpll_status *cmd;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_dpll_status);
+ cmd = &desc.params.get_cgu_dpll_status;
+ cmd->dpll_num = dpll_num;
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+ if (!status) {
+ *ref_state = cmd->ref_state;
+ *dpll_state = le16_to_cpu(cmd->dpll_state);
+ *phase_offset = le32_to_cpu(cmd->phase_offset_h);
+ *phase_offset <<= 32;
+ *phase_offset += le32_to_cpu(cmd->phase_offset_l);
+ *eec_mode = cmd->eec_mode;
+ }
+
+ return status;
+}
+
/**
* ice_replay_pre_init - replay pre initialization
* @hw: pointer to the HW struct
@@ -106,6 +106,7 @@ enum ice_status
ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags,
struct ice_sq_cd *cd);
bool ice_is_e810(struct ice_hw *hw);
+bool ice_is_e810t(struct ice_hw *hw);
enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
enum ice_status
ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
@@ -162,6 +163,9 @@ ice_cfg_vsi_rdma(struct ice_port_info *pi, u16 vsi_handle, u16 tc_bitmap,
int
ice_ena_vsi_rdma_qset(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
u16 *rdma_qset, u16 num_qsets, u32 *qset_teid);
+enum ice_status
+ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state,
+ u16 *dpll_state, u64 *phase_offset, u8 *eec_mode);
int
ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
u16 *q_id);
@@ -189,7 +193,6 @@ ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
void
ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
u64 *prev_stat, u64 *cur_stat);
-bool ice_is_e810t(struct ice_hw *hw);
enum ice_status
ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
struct ice_aqc_txsched_elem_data *buf);
@@ -58,4 +58,7 @@
/* Intel(R) Ethernet Connection E822-L 1GbE */
#define ICE_DEV_ID_E822L_SGMII 0x189A
+#define ICE_SUBDEV_ID_E810T 0x000E
+#define ICE_SUBDEV_ID_E810T2 0x000F
+
#endif /* _ICE_DEVIDS_H_ */
@@ -1766,6 +1766,36 @@ static void ice_ptp_tx_tstamp_cleanup(struct ice_ptp_tx *tx)
}
}
+static void ice_handle_cgu_state(struct ice_pf *pf)
+{
+ enum ice_eec_state cgu_state;
+ u8 pin;
+
+ cgu_state = ice_get_zl_dpll_state(&pf->hw, ICE_CGU_DPLL_SYNCE, &pin);
+ if (pf->synce_dpll_state != cgu_state) {
+ pf->synce_dpll_state = cgu_state;
+ pf->synce_dpll_pin = pin;
+
+ dev_warn(ice_pf_to_dev(pf),
+ "<DPLL%i> state changed to: %d, pin %d",
+ ICE_CGU_DPLL_SYNCE,
+ pf->synce_dpll_state,
+ pin);
+ }
+
+ cgu_state = ice_get_zl_dpll_state(&pf->hw, ICE_CGU_DPLL_PTP, &pin);
+ if (pf->ptp_dpll_state != cgu_state) {
+ pf->ptp_dpll_state = cgu_state;
+ pf->ptp_dpll_pin = pin;
+
+ dev_warn(ice_pf_to_dev(pf),
+ "<DPLL%i> state changed to: %d, pin %d",
+ ICE_CGU_DPLL_PTP,
+ pf->ptp_dpll_state,
+ pin);
+ }
+}
+
static void ice_ptp_periodic_work(struct kthread_work *work)
{
struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work);
@@ -1774,6 +1804,10 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
if (!test_bit(ICE_FLAG_PTP, pf->flags))
return;
+ if (ice_is_feature_supported(pf, ICE_F_CGU) &&
+ pf->hw.func_caps.ts_func_info.src_tmr_owned)
+ ice_handle_cgu_state(pf);
+
ice_ptp_update_cached_phctime(pf);
ice_ptp_tx_tstamp_cleanup(&pf->ptp.port.tx);
@@ -1958,3 +1992,4 @@ void ice_ptp_release(struct ice_pf *pf)
dev_info(ice_pf_to_dev(pf), "Removed PTP clock\n");
}
+
@@ -375,6 +375,54 @@ static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
return 0;
}
+/**
+ * ice_get_zl_dpll_state - get the state of the DPLL
+ * @hw: pointer to the hw struct
+ * @dpll_idx: Index of internal DPLL unit
+ * @pin: pointer to a buffer for returning currently active pin
+ *
+ * This function will read the state of the DPLL(dpll_idx). If optional
+ * parameter pin is given it'll be used to retrieve currently active pin.
+ *
+ * Return: state of the DPLL
+ */
+enum ice_eec_state
+ice_get_zl_dpll_state(struct ice_hw *hw, u8 dpll_idx, u8 *pin)
+{
+ enum ice_status status;
+ u64 phase_offset;
+ u16 dpll_state;
+ u8 ref_state;
+ u8 eec_mode;
+
+ if (dpll_idx >= ICE_CGU_DPLL_MAX)
+ return ICE_EEC_STATE_INVALID;
+
+ status = ice_aq_get_cgu_dpll_status(hw, dpll_idx, &ref_state,
+ &dpll_state, &phase_offset,
+ &eec_mode);
+ if (status)
+ return ICE_EEC_STATE_INVALID;
+
+ if (pin) {
+ /* current ref pin in dpll_state_refsel_status_X register */
+ *pin = (dpll_state &
+ ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SEL) >>
+ ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT;
+ }
+
+ if (dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK) {
+ if (dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY)
+ return ICE_EEC_STATE_LOCKED_HO_ACQ;
+ else
+ return ICE_EEC_STATE_LOCKED;
+ } else if ((dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO) &&
+ (dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY)) {
+ return ICE_EEC_STATE_HOLDOVER;
+ }
+ return ICE_EEC_STATE_FREERUN;
+}
+
/* Device agnostic functions
*
* The following functions implement useful behavior to hide the differences
@@ -12,6 +12,18 @@ enum ice_ptp_tmr_cmd {
READ_TIME
};
+enum ice_eec_state {
+ ICE_EEC_STATE_INVALID = 0, /* state is not valid */
+ ICE_EEC_STATE_FREERUN, /* clock is free-running */
+ ICE_EEC_STATE_LOCKED, /* clock is locked to the reference,
+ * but the holdover memory is not valid
+ */
+ ICE_EEC_STATE_LOCKED_HO_ACQ, /* clock is locked to the reference
+ * and holdover memory is valid
+ */
+ ICE_EEC_STATE_HOLDOVER, /* clock is in holdover mode */
+};
+
/* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for
* the E810 devices. Based off of a PLL with an 812.5 MHz frequency.
*/
@@ -33,6 +45,8 @@ int ice_ptp_init_phy_e810(struct ice_hw *hw);
int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data);
bool ice_is_pca9575_present(struct ice_hw *hw);
+enum ice_eec_state
+ice_get_zl_dpll_state(struct ice_hw *hw, u8 dpll_idx, u8 *pin);
#define PFTSYN_SEM_BYTES 4
@@ -98,4 +112,24 @@ bool ice_is_pca9575_present(struct ice_hw *hw);
#define ICE_SMA_MAX_BIT_E810T 7
#define ICE_PCA9575_P1_OFFSET 8
+enum ice_e810t_cgu_dpll {
+ ICE_CGU_DPLL_SYNCE,
+ ICE_CGU_DPLL_PTP,
+ ICE_CGU_DPLL_MAX
+};
+
+enum ice_e810t_cgu_pins {
+ REF0P,
+ REF0N,
+ REF1P,
+ REF1N,
+ REF2P,
+ REF2N,
+ REF3P,
+ REF3N,
+ REF4P,
+ REF4N,
+ NUM_E810T_CGU_PINS
+};
+
#endif /* _ICE_PTP_HW_H_ */
Implement SyncE DPLL monitoring for E810-T devices. Poll loop will periodically check the state of the DPLL and cache it in the pf structure. State changes will be logged in the system log. Signed-off-by: Maciej Machnikowski <maciej.machnikowski@intel.com> --- drivers/net/ethernet/intel/ice/ice.h | 5 ++ .../net/ethernet/intel/ice/ice_adminq_cmd.h | 34 +++++++++++++ drivers/net/ethernet/intel/ice/ice_common.c | 36 ++++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 5 +- drivers/net/ethernet/intel/ice/ice_devids.h | 3 ++ drivers/net/ethernet/intel/ice/ice_ptp.c | 35 ++++++++++++++ drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 48 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 34 +++++++++++++ 8 files changed, 199 insertions(+), 1 deletion(-)