Merge branch 'dpll-add-all-inputs-phase-offset-monitor'
Arkadiusz Kubalewski says:
====================
dpll: add all inputs phase offset monitor
Add dpll device level feature: phase offset monitor.
Phase offset measurement is typically performed against the current active
source. However, some DPLL (Digital Phase-Locked Loop) devices may offer
the capability to monitor phase offsets across all available inputs.
The attribute and current feature state shall be included in the response
message of the ``DPLL_CMD_DEVICE_GET`` command for supported DPLL devices.
In such cases, users can also control the feature using the
``DPLL_CMD_DEVICE_SET`` command by setting the ``enum dpll_feature_state``
values for the attribute.
Once enabled the phase offset measurements for the input shall be returned
in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.
Implement feature support in ice driver for dpll-enabled devices.
Verify capability:
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/dpll.yaml \
--dump device-get
[{'clock-id': 4658613174691613800,
'id': 0,
'lock-status': 'locked-ho-acq',
'mode': 'automatic',
'mode-supported': ['automatic'],
'module-name': 'ice',
'type': 'eec'},
{'clock-id': 4658613174691613800,
'id': 1,
'lock-status': 'locked-ho-acq',
'mode': 'automatic',
'mode-supported': ['automatic'],
'module-name': 'ice',
'phase-offset-monitor': 'disable',
'type': 'pps'}]
Enable the feature:
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/dpll.yaml \
--do device-set --json '{"id":1, "phase-offset-monitor":"enable"}'
Verify feature is enabled:
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/dpll.yaml \
--dump device-get
[
[...]
{'capabilities': {'all-inputs-phase-offset-monitor'},
'clock-id': 4658613174691613800,
'id': 1,
[...]
'phase-offset-monitor': 'enable',
[...]]
v6:
- rebase.
====================
Link: https://patch.msgid.link/20250612152835.1703397-1-arkadiusz.kubalewski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -214,6 +214,24 @@ offset values are fractional with 3-digit decimal places and shell be
|
||||
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
|
||||
modulo divided to get fractional part.
|
||||
|
||||
Phase offset monitor
|
||||
====================
|
||||
|
||||
Phase offset measurement is typically performed against the current active
|
||||
source. However, some DPLL (Digital Phase-Locked Loop) devices may offer
|
||||
the capability to monitor phase offsets across all available inputs.
|
||||
The attribute and current feature state shall be included in the response
|
||||
message of the ``DPLL_CMD_DEVICE_GET`` command for supported DPLL devices.
|
||||
In such cases, users can also control the feature using the
|
||||
``DPLL_CMD_DEVICE_SET`` command by setting the ``enum dpll_feature_state``
|
||||
values for the attribute.
|
||||
Once enabled the phase offset measurements for the input shall be returned
|
||||
in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.
|
||||
|
||||
=============================== ========================
|
||||
``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature
|
||||
=============================== ========================
|
||||
|
||||
Embedded SYNC
|
||||
=============
|
||||
|
||||
|
||||
@@ -240,6 +240,20 @@ definitions:
|
||||
integer part of a measured phase offset value.
|
||||
Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
|
||||
fractional part of a measured phase offset value.
|
||||
-
|
||||
type: enum
|
||||
name: feature-state
|
||||
doc: |
|
||||
Allow control (enable/disable) and status checking over features.
|
||||
entries:
|
||||
-
|
||||
name: disable
|
||||
doc: |
|
||||
feature shall be disabled
|
||||
-
|
||||
name: enable
|
||||
doc: |
|
||||
feature shall be enabled
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
@@ -293,6 +307,14 @@ attribute-sets:
|
||||
be put to message multiple times to indicate possible parallel
|
||||
quality levels (e.g. one specified by ITU option 1 and another
|
||||
one specified by option 2).
|
||||
-
|
||||
name: phase-offset-monitor
|
||||
type: u32
|
||||
enum: feature-state
|
||||
doc: Receive or request state of phase offset monitor feature.
|
||||
If enabled, dpll device shall monitor and notify all currently
|
||||
available inputs for changes of their phase offset against the
|
||||
dpll device.
|
||||
-
|
||||
name: pin
|
||||
enum-name: dpll_a_pin
|
||||
@@ -483,6 +505,7 @@ operations:
|
||||
- temp
|
||||
- clock-id
|
||||
- type
|
||||
- phase-offset-monitor
|
||||
|
||||
dump:
|
||||
reply: *dev-attrs
|
||||
@@ -499,6 +522,7 @@ operations:
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
- phase-offset-monitor
|
||||
-
|
||||
name: device-create-ntf
|
||||
doc: Notification about device appearing
|
||||
|
||||
@@ -126,6 +126,26 @@ dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct dpll_device_ops *ops = dpll_device_ops(dpll);
|
||||
enum dpll_feature_state state;
|
||||
int ret;
|
||||
|
||||
if (ops->phase_offset_monitor_set && ops->phase_offset_monitor_get) {
|
||||
ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll),
|
||||
&state, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (nla_put_u32(msg, DPLL_A_PHASE_OFFSET_MONITOR, state))
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll,
|
||||
struct netlink_ext_ack *extack)
|
||||
@@ -591,6 +611,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
|
||||
return ret;
|
||||
if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
|
||||
return -EMSGSIZE;
|
||||
ret = dpll_msg_add_phase_offset_monitor(msg, dpll, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -746,6 +769,31 @@ int dpll_pin_change_ntf(struct dpll_pin *pin)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);
|
||||
|
||||
static int
|
||||
dpll_phase_offset_monitor_set(struct dpll_device *dpll, struct nlattr *a,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct dpll_device_ops *ops = dpll_device_ops(dpll);
|
||||
enum dpll_feature_state state = nla_get_u32(a), old_state;
|
||||
int ret;
|
||||
|
||||
if (!(ops->phase_offset_monitor_set && ops->phase_offset_monitor_get)) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, a, "dpll device not capable of phase offset monitor");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll), &old_state,
|
||||
extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG(extack, "unable to get current state of phase offset monitor");
|
||||
return ret;
|
||||
}
|
||||
if (state == old_state)
|
||||
return 0;
|
||||
|
||||
return ops->phase_offset_monitor_set(dpll, dpll_priv(dpll), state,
|
||||
extack);
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
struct netlink_ext_ack *extack)
|
||||
@@ -1533,10 +1581,27 @@ int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
return genlmsg_reply(msg, info);
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (info->attrs[DPLL_A_PHASE_OFFSET_MONITOR]) {
|
||||
struct nlattr *a = info->attrs[DPLL_A_PHASE_OFFSET_MONITOR];
|
||||
|
||||
ret = dpll_phase_offset_monitor_set(dpll, a, info->extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
/* placeholder for set command */
|
||||
return 0;
|
||||
struct dpll_device *dpll = info->user_ptr[0];
|
||||
|
||||
return dpll_set_from_nlattr(dpll, info);
|
||||
}
|
||||
|
||||
int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
@@ -37,8 +37,9 @@ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = {
|
||||
};
|
||||
|
||||
/* DPLL_CMD_DEVICE_SET - do */
|
||||
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_ID + 1] = {
|
||||
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_PHASE_OFFSET_MONITOR + 1] = {
|
||||
[DPLL_A_ID] = { .type = NLA_U32, },
|
||||
[DPLL_A_PHASE_OFFSET_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1),
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_ID_GET - do */
|
||||
@@ -105,7 +106,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
|
||||
.doit = dpll_nl_device_set_doit,
|
||||
.post_doit = dpll_post_doit,
|
||||
.policy = dpll_device_set_nl_policy,
|
||||
.maxattr = DPLL_A_ID,
|
||||
.maxattr = DPLL_A_PHASE_OFFSET_MONITOR,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2272,6 +2272,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) */
|
||||
@@ -2721,6 +2737,7 @@ struct ice_aq_desc {
|
||||
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_get_cgu_input_measure get_cgu_input_measure;
|
||||
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;
|
||||
@@ -2772,6 +2789,8 @@ 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_ESRCH = 3, /* Bad opcode */
|
||||
ICE_AQ_RC_EAGAIN = 8, /* Try again */
|
||||
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 */
|
||||
@@ -2927,6 +2946,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,
|
||||
|
||||
@@ -4970,6 +4970,32 @@ ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ice_aq_desc desc;
|
||||
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_measure);
|
||||
cmd = &desc.params.get_cgu_input_measure;
|
||||
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
|
||||
|
||||
@@ -229,6 +229,9 @@ 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_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);
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#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
|
||||
@@ -792,6 +794,67 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -1757,6 +1820,8 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
|
||||
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);
|
||||
@@ -2216,6 +2281,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
|
||||
@@ -2260,6 +2332,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 == ICE_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 == ICE_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,
|
||||
ice_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
|
||||
@@ -2346,14 +2522,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 */
|
||||
@@ -2368,6 +2549,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 */
|
||||
@@ -2782,7 +2966,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);
|
||||
}
|
||||
|
||||
@@ -2816,12 +3000,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;
|
||||
|
||||
@@ -31,6 +31,7 @@ enum ice_dpll_pin_sw {
|
||||
* @prop: pin properties
|
||||
* @freq: current frequency of a pin
|
||||
* @phase_adjust: current phase adjust value
|
||||
* @phase_offset: monitored phase offset value
|
||||
*/
|
||||
struct ice_dpll_pin {
|
||||
struct dpll_pin *pin;
|
||||
@@ -46,6 +47,7 @@ struct ice_dpll_pin {
|
||||
struct ice_dpll_pin *input;
|
||||
struct ice_dpll_pin *output;
|
||||
enum dpll_pin_direction direction;
|
||||
s64 phase_offset;
|
||||
u8 status;
|
||||
bool active;
|
||||
bool hidden;
|
||||
@@ -64,8 +66,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;
|
||||
@@ -81,8 +85,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)
|
||||
@@ -101,6 +107,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;
|
||||
@@ -121,6 +128,7 @@ struct ice_dplls {
|
||||
u64 clock_id;
|
||||
s32 input_phase_adj_max;
|
||||
s32 output_phase_adj_max;
|
||||
u32 periodic_counter;
|
||||
bool generic;
|
||||
};
|
||||
|
||||
|
||||
@@ -7936,6 +7936,10 @@ const char *ice_aq_str(enum ice_aq_err aq_err)
|
||||
return "ICE_AQ_RC_EPERM";
|
||||
case ICE_AQ_RC_ENOENT:
|
||||
return "ICE_AQ_RC_ENOENT";
|
||||
case ICE_AQ_RC_ESRCH:
|
||||
return "ICE_AQ_RC_ESRCH";
|
||||
case ICE_AQ_RC_EAGAIN:
|
||||
return "ICE_AQ_RC_EAGAIN";
|
||||
case ICE_AQ_RC_ENOMEM:
|
||||
return "ICE_AQ_RC_ENOMEM";
|
||||
case ICE_AQ_RC_EBUSY:
|
||||
|
||||
@@ -30,6 +30,14 @@ struct dpll_device_ops {
|
||||
void *dpll_priv,
|
||||
unsigned long *qls,
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*phase_offset_monitor_set)(const struct dpll_device *dpll,
|
||||
void *dpll_priv,
|
||||
enum dpll_feature_state state,
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*phase_offset_monitor_get)(const struct dpll_device *dpll,
|
||||
void *dpll_priv,
|
||||
enum dpll_feature_state *state,
|
||||
struct netlink_ext_ack *extack);
|
||||
};
|
||||
|
||||
struct dpll_pin_ops {
|
||||
|
||||
@@ -192,6 +192,17 @@ enum dpll_pin_capabilities {
|
||||
|
||||
#define DPLL_PHASE_OFFSET_DIVIDER 1000
|
||||
|
||||
/**
|
||||
* enum dpll_feature_state - Allow control (enable/disable) and status checking
|
||||
* over features.
|
||||
* @DPLL_FEATURE_STATE_DISABLE: feature shall be disabled
|
||||
* @DPLL_FEATURE_STATE_ENABLE: feature shall be enabled
|
||||
*/
|
||||
enum dpll_feature_state {
|
||||
DPLL_FEATURE_STATE_DISABLE,
|
||||
DPLL_FEATURE_STATE_ENABLE,
|
||||
};
|
||||
|
||||
enum dpll_a {
|
||||
DPLL_A_ID = 1,
|
||||
DPLL_A_MODULE_NAME,
|
||||
@@ -204,6 +215,7 @@ enum dpll_a {
|
||||
DPLL_A_TYPE,
|
||||
DPLL_A_LOCK_STATUS_ERROR,
|
||||
DPLL_A_CLOCK_QUALITY_LEVEL,
|
||||
DPLL_A_PHASE_OFFSET_MONITOR,
|
||||
|
||||
__DPLL_A_MAX,
|
||||
DPLL_A_MAX = (__DPLL_A_MAX - 1)
|
||||
|
||||
Reference in New Issue
Block a user