Skip to content

Commit 5333ec3

Browse files
kubalewskiNipaLocal
authored and
NipaLocal
committed
ice: add phase offset monitor for all PPS dpll inputs
Implement new admin command and helper function to handle/obtain CGU measurements for input pins, initialize PPS dpll capabilities using new command. Add callbacks to control dpll device feature: all-inputs-phase-offset-monitor. Allow enable/disable of all inputs monitoring for ice PPS dpll device. If feature is enabled provide users with measured phase offsets and notifications. Reviewed-by: Milena Olech <[email protected]> Signed-off-by: Arkadiusz Kubalewski <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 234a96e commit 5333ec3

File tree

6 files changed

+243
-4
lines changed

6 files changed

+243
-4
lines changed

drivers/net/ethernet/intel/ice/ice_adminq_cmd.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,22 @@ struct ice_aqc_get_pkg_info_resp {
22722272
struct ice_aqc_get_pkg_info pkg_info[];
22732273
};
22742274

2275+
#define ICE_CGU_INPUT_PHASE_OFFSET_BYTES 6
2276+
2277+
struct ice_cgu_input_measure {
2278+
u8 phase_offset[ICE_CGU_INPUT_PHASE_OFFSET_BYTES];
2279+
__le32 freq;
2280+
} __packed __aligned(sizeof(__le16));
2281+
2282+
#define ICE_AQC_GET_CGU_IN_MEAS_DPLL_IDX_M ICE_M(0xf, 0)
2283+
2284+
/* Get CGU input measurements command response data structure (indirect 0x0C59) */
2285+
struct ice_aqc_get_cgu_input_measure {
2286+
u8 dpll_idx_opt;
2287+
u8 length;
2288+
u8 rsvd[6];
2289+
};
2290+
22752291
#define ICE_AQC_GET_CGU_MAX_PHASE_ADJ GENMASK(30, 0)
22762292

22772293
/* Get CGU abilities command response data structure (indirect 0x0C61) */
@@ -2721,6 +2737,7 @@ struct ice_aq_desc {
27212737
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
27222738
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
27232739
struct ice_aqc_download_pkg download_pkg;
2740+
struct ice_aqc_get_cgu_input_measure get_cgu_input_measure;
27242741
struct ice_aqc_set_cgu_input_config set_cgu_input_config;
27252742
struct ice_aqc_get_cgu_input_config get_cgu_input_config;
27262743
struct ice_aqc_set_cgu_output_config set_cgu_output_config;
@@ -2772,6 +2789,8 @@ enum ice_aq_err {
27722789
ICE_AQ_RC_OK = 0, /* Success */
27732790
ICE_AQ_RC_EPERM = 1, /* Operation not permitted */
27742791
ICE_AQ_RC_ENOENT = 2, /* No such element */
2792+
ICE_AQ_RC_ESRCH = 3, /* Bad opcode */
2793+
ICE_AQ_RC_EAGAIN = 8, /* Try again */
27752794
ICE_AQ_RC_ENOMEM = 9, /* Out of memory */
27762795
ICE_AQ_RC_EBUSY = 12, /* Device or resource busy */
27772796
ICE_AQ_RC_EEXIST = 13, /* Object already exists */
@@ -2927,6 +2946,7 @@ enum ice_adminq_opc {
29272946
ice_aqc_opc_get_pkg_info_list = 0x0C43,
29282947

29292948
/* 1588/SyncE commands/events */
2949+
ice_aqc_opc_get_cgu_input_measure = 0x0C59,
29302950
ice_aqc_opc_get_cgu_abilities = 0x0C61,
29312951
ice_aqc_opc_set_cgu_input_config = 0x0C62,
29322952
ice_aqc_opc_get_cgu_input_config = 0x0C63,

drivers/net/ethernet/intel/ice/ice_common.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4966,6 +4966,32 @@ ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
49664966
return status;
49674967
}
49684968

4969+
/**
4970+
* ice_aq_get_cgu_input_pin_measure - get input pin signal measurements
4971+
* @hw: pointer to the HW struct
4972+
* @dpll_idx: index of dpll to be measured
4973+
* @meas: array to be filled with results
4974+
* @meas_num: max number of results array can hold
4975+
*
4976+
* Get CGU measurements (0x0C59) of phase and frequency offsets for input
4977+
* pins on given dpll.
4978+
*
4979+
* Return: 0 on success or negative value on failure.
4980+
*/
4981+
int ice_aq_get_cgu_input_pin_measure(struct ice_hw *hw, u8 dpll_idx,
4982+
struct ice_cgu_input_measure *meas,
4983+
u16 meas_num)
4984+
{
4985+
struct ice_aqc_get_cgu_input_measure *cmd;
4986+
struct ice_aq_desc desc;
4987+
4988+
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_measure);
4989+
cmd = &desc.params.get_cgu_input_measure;
4990+
cmd->dpll_idx_opt = dpll_idx & ICE_AQC_GET_CGU_IN_MEAS_DPLL_IDX_M;
4991+
4992+
return ice_aq_send_cmd(hw, &desc, meas, meas_num * sizeof(*meas), NULL);
4993+
}
4994+
49694995
/**
49704996
* ice_aq_get_cgu_abilities - get cgu abilities
49714997
* @hw: pointer to the HW struct

drivers/net/ethernet/intel/ice/ice_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ void ice_replay_post(struct ice_hw *hw);
229229
struct ice_q_ctx *
230230
ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle);
231231
int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in, u16 flag);
232+
int ice_aq_get_cgu_input_pin_measure(struct ice_hw *hw, u8 dpll_idx,
233+
struct ice_cgu_input_measure *meas,
234+
u16 meas_num);
232235
int
233236
ice_aq_get_cgu_abilities(struct ice_hw *hw,
234237
struct ice_aqc_get_cgu_abilities *abilities);

drivers/net/ethernet/intel/ice/ice_dpll.c

Lines changed: 184 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#define ICE_DPLL_RCLK_NUM_PER_PF 1
1212
#define ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT 25
1313
#define ICE_DPLL_PIN_GEN_RCLK_FREQ 1953125
14+
#define ICE_DPLL_INPUT_REF_NUM 10
15+
#define ICE_DPLL_PHASE_OFFSET_PERIOD 2
1416

1517
/**
1618
* enum ice_dpll_pin_type - enumerate ice pin types:
@@ -587,6 +589,63 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv,
587589
return 0;
588590
}
589591

592+
/**
593+
* ice_dpll_features_set - set dpll's features
594+
* @dpll: registered dpll pointer
595+
* @dpll_priv: private data pointer passed on dpll registration
596+
* @features: mask of features to be set
597+
* @extack: error reporting
598+
*
599+
* Dpll subsystem callback. Enable/disable features of dpll.
600+
*
601+
* Context: Acquires and releases pf->dplls.lock
602+
* Return: 0 - success
603+
*/
604+
static int ice_dpll_features_set(const struct dpll_device *dpll,
605+
void *dpll_priv, u32 features,
606+
struct netlink_ext_ack *extack)
607+
{
608+
struct ice_dpll *d = dpll_priv;
609+
struct ice_pf *pf = d->pf;
610+
611+
mutex_lock(&pf->dplls.lock);
612+
if (features & DPLL_FEATURES_ALL_INPUTS_PHASE_OFFSET_MONITOR)
613+
d->phase_offset_monitor_period = ICE_DPLL_PHASE_OFFSET_PERIOD;
614+
else
615+
d->phase_offset_monitor_period = 0;
616+
mutex_unlock(&pf->dplls.lock);
617+
618+
return 0;
619+
}
620+
621+
/**
622+
* ice_dpll_features_get - get dpll's features
623+
* @dpll: registered dpll pointer
624+
* @dpll_priv: private data pointer passed on dpll registration
625+
* @features: on success holds currently enabled features of dpll
626+
* @extack: error reporting
627+
*
628+
* Dpll subsystem callback. Provides currently enabled features of dpll.
629+
*
630+
* Context: Acquires and releases pf->dplls.lock
631+
* Return: 0 - success
632+
*/
633+
static int ice_dpll_features_get(const struct dpll_device *dpll,
634+
void *dpll_priv, u32 *features,
635+
struct netlink_ext_ack *extack)
636+
{
637+
struct ice_dpll *d = dpll_priv;
638+
struct ice_pf *pf = d->pf;
639+
640+
mutex_lock(&pf->dplls.lock);
641+
*features = 0;
642+
if (d->phase_offset_monitor_period)
643+
*features |= DPLL_FEATURES_ALL_INPUTS_PHASE_OFFSET_MONITOR;
644+
mutex_unlock(&pf->dplls.lock);
645+
646+
return 0;
647+
}
648+
590649
/**
591650
* ice_dpll_pin_state_set - set pin's state on dpll
592651
* @pin: pointer to a pin
@@ -1093,12 +1152,15 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
10931152
const struct dpll_device *dpll, void *dpll_priv,
10941153
s64 *phase_offset, struct netlink_ext_ack *extack)
10951154
{
1155+
struct ice_dpll_pin *p = pin_priv;
10961156
struct ice_dpll *d = dpll_priv;
10971157
struct ice_pf *pf = d->pf;
10981158

10991159
mutex_lock(&pf->dplls.lock);
11001160
if (d->active_input == pin)
11011161
*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
1162+
else if (d->phase_offset_monitor_period)
1163+
*phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
11021164
else
11031165
*phase_offset = 0;
11041166
mutex_unlock(&pf->dplls.lock);
@@ -1457,6 +1519,8 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
14571519
static const struct dpll_device_ops ice_dpll_ops = {
14581520
.lock_status_get = ice_dpll_lock_status_get,
14591521
.mode_get = ice_dpll_mode_get,
1522+
.features_set = ice_dpll_features_set,
1523+
.features_get = ice_dpll_features_get,
14601524
};
14611525

14621526
/**
@@ -1503,6 +1567,110 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
15031567
}
15041568
}
15051569

1570+
/**
1571+
* ice_dpll_is_pps_phase_monitor - check if dpll capable of phase offset monitor
1572+
* @pf: pf private structure
1573+
*
1574+
* Check if firmware is capable of supporting admin command to provide
1575+
* phase offset monitoring on all the input pins on PPS dpll.
1576+
*
1577+
* Returns:
1578+
* * true - PPS dpll phase offset monitoring is supported
1579+
* * false - PPS dpll phase offset monitoring is not supported
1580+
*/
1581+
static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
1582+
{
1583+
struct ice_cgu_input_measure meas[ICE_DPLL_INPUT_REF_NUM];
1584+
int ret = ice_aq_get_cgu_input_pin_measure(&pf->hw, DPLL_TYPE_PPS, meas,
1585+
ARRAY_SIZE(meas));
1586+
1587+
if (ret && pf->hw.adminq.sq_last_status == ICE_AQ_RC_ESRCH)
1588+
return false;
1589+
1590+
return true;
1591+
}
1592+
1593+
/**
1594+
* ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes
1595+
* @pins: array of ice_dpll_pin pointers registered within dpll subsystem
1596+
* @pin_num: number of pins
1597+
* @phase_offset_ntf_mask: bitmask of pin indexes to notify
1598+
*
1599+
* Iterate over array of pins and call dpll subsystem pin notify if
1600+
* corresponding pin index within bitmask is set.
1601+
*
1602+
* Context: Must be called while pf->dplls.lock is released.
1603+
*/
1604+
static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins,
1605+
u8 pin_num,
1606+
u32 phase_offset_ntf_mask)
1607+
{
1608+
int i = 0;
1609+
1610+
for (i = 0; i < pin_num; i++)
1611+
if (phase_offset_ntf_mask & (1 << i))
1612+
dpll_pin_change_ntf(pins[i].pin);
1613+
}
1614+
1615+
/**
1616+
* ice_dpll_pps_update_phase_offsets - update phase offset measurements
1617+
* @pf: pf private structure
1618+
* @phase_offset_pins_updated: returns mask of updated input pin indexes
1619+
*
1620+
* Read phase offset measurements for PPS dpll device and store values in
1621+
* input pins array. On success phase_offset_pins_updated - fills bitmask of
1622+
* updated input pin indexes, pins shall be notified.
1623+
*
1624+
* Context: Shall be called with pf->dplls.lock being locked.
1625+
* Returns:
1626+
* * 0 - success or no data available
1627+
* * negative - AQ failure
1628+
*/
1629+
static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf,
1630+
u32 *phase_offset_pins_updated)
1631+
{
1632+
struct ice_cgu_input_measure meas[ICE_DPLL_INPUT_REF_NUM];
1633+
struct ice_dpll_pin *p;
1634+
s64 phase_offset, tmp;
1635+
int i, j, ret;
1636+
1637+
*phase_offset_pins_updated = 0;
1638+
ret = ice_aq_get_cgu_input_pin_measure(&pf->hw, DPLL_TYPE_PPS, meas,
1639+
ARRAY_SIZE(meas));
1640+
if (ret && pf->hw.adminq.sq_last_status == ICE_AQ_RC_EAGAIN) {
1641+
return 0;
1642+
} else if (ret) {
1643+
dev_err(ice_pf_to_dev(pf),
1644+
"failed to get input pin measurements dpll=%d, ret=%d %s\n",
1645+
DPLL_TYPE_PPS, ret,
1646+
ice_aq_str(pf->hw.adminq.sq_last_status));
1647+
return ret;
1648+
}
1649+
for (i = 0; i < pf->dplls.num_inputs; i++) {
1650+
p = &pf->dplls.inputs[i];
1651+
phase_offset = 0;
1652+
for (j = 0; j < ICE_CGU_INPUT_PHASE_OFFSET_BYTES; j++) {
1653+
tmp = meas[i].phase_offset[j];
1654+
#ifdef __LITTLE_ENDIAN
1655+
phase_offset += tmp << 8 * j;
1656+
#else
1657+
phase_offset += tmp << 8 *
1658+
(ICE_CGU_INPUT_PHASE_OFFSET_BYTES - 1 - j);
1659+
#endif
1660+
}
1661+
phase_offset = sign_extend64(phase_offset, 47);
1662+
if (p->phase_offset != phase_offset) {
1663+
dev_dbg(ice_pf_to_dev(pf),
1664+
"phase offset changed for pin:%d old:%llx, new:%llx\n",
1665+
p->idx, p->phase_offset, phase_offset);
1666+
p->phase_offset = phase_offset;
1667+
*phase_offset_pins_updated |= (1 << i);
1668+
}
1669+
}
1670+
1671+
return 0;
1672+
}
1673+
15061674
/**
15071675
* ice_dpll_update_state - update dpll state
15081676
* @pf: pf private structure
@@ -1589,14 +1757,19 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
15891757
struct ice_pf *pf = container_of(d, struct ice_pf, dplls);
15901758
struct ice_dpll *de = &pf->dplls.eec;
15911759
struct ice_dpll *dp = &pf->dplls.pps;
1760+
u32 phase_offset_ntf = 0;
15921761
int ret = 0;
15931762

15941763
if (ice_is_reset_in_progress(pf->state))
15951764
goto resched;
15961765
mutex_lock(&pf->dplls.lock);
1766+
d->periodic_counter++;
15971767
ret = ice_dpll_update_state(pf, de, false);
15981768
if (!ret)
15991769
ret = ice_dpll_update_state(pf, dp, false);
1770+
if (!ret && dp->phase_offset_monitor_period &&
1771+
d->periodic_counter % dp->phase_offset_monitor_period == 0)
1772+
ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf);
16001773
if (ret) {
16011774
d->cgu_state_acq_err_num++;
16021775
/* stop rescheduling this worker */
@@ -1611,6 +1784,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
16111784
mutex_unlock(&pf->dplls.lock);
16121785
ice_dpll_notify_changes(de);
16131786
ice_dpll_notify_changes(dp);
1787+
if (phase_offset_ntf)
1788+
ice_dpll_pins_notify_mask(d->inputs, d->num_inputs,
1789+
phase_offset_ntf);
16141790

16151791
resched:
16161792
/* Run twice a second or reschedule if update failed */
@@ -1987,6 +2163,7 @@ ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu)
19872163
* @d: dpll to be initialized
19882164
* @cgu: if cgu is present and controlled by this NIC
19892165
* @type: type of dpll being initialized
2166+
* @caps: bitmap of capabilities of dpll
19902167
*
19912168
* Allocate dpll instance for this board in dpll subsystem, if cgu is controlled
19922169
* by this NIC, register dpll with the callback ops.
@@ -1997,7 +2174,7 @@ ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu)
19972174
*/
19982175
static int
19992176
ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
2000-
enum dpll_type type)
2177+
enum dpll_type type, u32 caps)
20012178
{
20022179
u64 clock_id = pf->dplls.clock_id;
20032180
int ret;
@@ -2012,7 +2189,8 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
20122189
d->pf = pf;
20132190
if (cgu) {
20142191
ice_dpll_update_state(pf, d, true);
2015-
ret = dpll_device_register(d->dpll, type, 0, &ice_dpll_ops, d);
2192+
ret = dpll_device_register(d->dpll, type, caps, &ice_dpll_ops,
2193+
d);
20162194
if (ret) {
20172195
dpll_device_put(d->dpll);
20182196
return ret;
@@ -2426,10 +2604,12 @@ void ice_dpll_init(struct ice_pf *pf)
24262604
err = ice_dpll_init_info(pf, cgu);
24272605
if (err)
24282606
goto err_exit;
2429-
err = ice_dpll_init_dpll(pf, &pf->dplls.eec, cgu, DPLL_TYPE_EEC);
2607+
err = ice_dpll_init_dpll(pf, &pf->dplls.eec, cgu, DPLL_TYPE_EEC, 0);
24302608
if (err)
24312609
goto deinit_info;
2432-
err = ice_dpll_init_dpll(pf, &pf->dplls.pps, cgu, DPLL_TYPE_PPS);
2610+
err = ice_dpll_init_dpll(pf, &pf->dplls.pps, cgu, DPLL_TYPE_PPS,
2611+
!ice_dpll_is_pps_phase_monitor(pf) ? 0 :
2612+
DPLL_FEATURES_ALL_INPUTS_PHASE_OFFSET_MONITOR);
24332613
if (err)
24342614
goto deinit_eec;
24352615
err = ice_dpll_init_pins(pf, cgu);

0 commit comments

Comments
 (0)