|
4 | 4 | #include "ice.h"
|
5 | 5 | #include "ice_lib.h"
|
6 | 6 |
|
| 7 | +/** |
| 8 | + * ice_get_ptp_clock_index - Get the PTP clock index |
| 9 | + * @pf: the PF pointer |
| 10 | + * |
| 11 | + * Determine the clock index of the PTP clock associated with this device. If |
| 12 | + * this is the PF controlling the clock, just use the local access to the |
| 13 | + * clock device pointer. |
| 14 | + * |
| 15 | + * Otherwise, read from the driver shared parameters to determine the clock |
| 16 | + * index value. |
| 17 | + * |
| 18 | + * Returns: the index of the PTP clock associated with this device, or -1 if |
| 19 | + * there is no associated clock. |
| 20 | + */ |
| 21 | +int ice_get_ptp_clock_index(struct ice_pf *pf) |
| 22 | +{ |
| 23 | + struct device *dev = ice_pf_to_dev(pf); |
| 24 | + enum ice_aqc_driver_params param_idx; |
| 25 | + struct ice_hw *hw = &pf->hw; |
| 26 | + u8 tmr_idx; |
| 27 | + u32 value; |
| 28 | + int err; |
| 29 | + |
| 30 | + /* Use the ptp_clock structure if we're the main PF */ |
| 31 | + if (pf->ptp.clock) |
| 32 | + return ptp_clock_index(pf->ptp.clock); |
| 33 | + |
| 34 | + tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc; |
| 35 | + if (!tmr_idx) |
| 36 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0; |
| 37 | + else |
| 38 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1; |
| 39 | + |
| 40 | + err = ice_aq_get_driver_param(hw, param_idx, &value, NULL); |
| 41 | + if (err) { |
| 42 | + dev_err(dev, "Failed to read PTP clock index parameter, err %d aq_err %s\n", |
| 43 | + err, ice_aq_str(hw->adminq.sq_last_status)); |
| 44 | + return -1; |
| 45 | + } |
| 46 | + |
| 47 | + /* The PTP clock index is an integer, and will be between 0 and |
| 48 | + * INT_MAX. The highest bit of the driver shared parameter is used to |
| 49 | + * indicate whether or not the currently stored clock index is valid. |
| 50 | + */ |
| 51 | + if (!(value & PTP_SHARED_CLK_IDX_VALID)) |
| 52 | + return -1; |
| 53 | + |
| 54 | + return value & ~PTP_SHARED_CLK_IDX_VALID; |
| 55 | +} |
| 56 | + |
| 57 | +/** |
| 58 | + * ice_set_ptp_clock_index - Set the PTP clock index |
| 59 | + * @pf: the PF pointer |
| 60 | + * |
| 61 | + * Set the PTP clock index for this device into the shared driver parameters, |
| 62 | + * so that other PFs associated with this device can read it. |
| 63 | + * |
| 64 | + * If the PF is unable to store the clock index, it will log an error, but |
| 65 | + * will continue operating PTP. |
| 66 | + */ |
| 67 | +static void ice_set_ptp_clock_index(struct ice_pf *pf) |
| 68 | +{ |
| 69 | + struct device *dev = ice_pf_to_dev(pf); |
| 70 | + enum ice_aqc_driver_params param_idx; |
| 71 | + struct ice_hw *hw = &pf->hw; |
| 72 | + u8 tmr_idx; |
| 73 | + u32 value; |
| 74 | + int err; |
| 75 | + |
| 76 | + if (!pf->ptp.clock) |
| 77 | + return; |
| 78 | + |
| 79 | + tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc; |
| 80 | + if (!tmr_idx) |
| 81 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0; |
| 82 | + else |
| 83 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1; |
| 84 | + |
| 85 | + value = (u32)ptp_clock_index(pf->ptp.clock); |
| 86 | + if (value > INT_MAX) { |
| 87 | + dev_err(dev, "PTP Clock index is too large to store\n"); |
| 88 | + return; |
| 89 | + } |
| 90 | + value |= PTP_SHARED_CLK_IDX_VALID; |
| 91 | + |
| 92 | + err = ice_aq_set_driver_param(hw, param_idx, value, NULL); |
| 93 | + if (err) { |
| 94 | + dev_err(dev, "Failed to set PTP clock index parameter, err %d aq_err %s\n", |
| 95 | + err, ice_aq_str(hw->adminq.sq_last_status)); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +/** |
| 100 | + * ice_clear_ptp_clock_index - Clear the PTP clock index |
| 101 | + * @pf: the PF pointer |
| 102 | + * |
| 103 | + * Clear the PTP clock index for this device. Must be called when |
| 104 | + * unregistering the PTP clock, in order to ensure other PFs stop reporting |
| 105 | + * a clock object that no longer exists. |
| 106 | + */ |
| 107 | +static void ice_clear_ptp_clock_index(struct ice_pf *pf) |
| 108 | +{ |
| 109 | + struct device *dev = ice_pf_to_dev(pf); |
| 110 | + enum ice_aqc_driver_params param_idx; |
| 111 | + struct ice_hw *hw = &pf->hw; |
| 112 | + u8 tmr_idx; |
| 113 | + int err; |
| 114 | + |
| 115 | + /* Do not clear the index if we don't own the timer */ |
| 116 | + if (!hw->func_caps.ts_func_info.src_tmr_owned) |
| 117 | + return; |
| 118 | + |
| 119 | + tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc; |
| 120 | + if (!tmr_idx) |
| 121 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0; |
| 122 | + else |
| 123 | + param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1; |
| 124 | + |
| 125 | + err = ice_aq_set_driver_param(hw, param_idx, 0, NULL); |
| 126 | + if (err) { |
| 127 | + dev_dbg(dev, "Failed to clear PTP clock index parameter, err %d aq_err %s\n", |
| 128 | + err, ice_aq_str(hw->adminq.sq_last_status)); |
| 129 | + } |
| 130 | +} |
| 131 | + |
7 | 132 | /**
|
8 | 133 | * ice_ptp_read_src_clk_reg - Read the source clock register
|
9 | 134 | * @pf: Board private structure
|
@@ -377,6 +502,9 @@ static int ice_ptp_init_owner(struct ice_pf *pf)
|
377 | 502 | if (err)
|
378 | 503 | goto err_clk;
|
379 | 504 |
|
| 505 | + /* Store the PTP clock index for other PFs */ |
| 506 | + ice_set_ptp_clock_index(pf); |
| 507 | + |
380 | 508 | return 0;
|
381 | 509 |
|
382 | 510 | err_clk:
|
@@ -431,6 +559,7 @@ void ice_ptp_release(struct ice_pf *pf)
|
431 | 559 | if (!pf->ptp.clock)
|
432 | 560 | return;
|
433 | 561 |
|
| 562 | + ice_clear_ptp_clock_index(pf); |
434 | 563 | ptp_clock_unregister(pf->ptp.clock);
|
435 | 564 | pf->ptp.clock = NULL;
|
436 | 565 |
|
|
0 commit comments