diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_ptp.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ptp.c | 192 |
1 files changed, 159 insertions, 33 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 0014a1002ed3..4d9e122837fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -313,7 +313,7 @@ static void ice_set_rx_tstamp(struct ice_pf *pf, bool on) * This function will configure timestamping during PTP initialization * and deinitialization */ -static void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena) +void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena) { ice_set_tx_tstamp(pf, ena); ice_set_rx_tstamp(pf, ena); @@ -1777,6 +1777,122 @@ static void ice_ptp_periodic_work(struct kthread_work *work) } /** + * ice_ptp_reset - Initialize PTP hardware clock support after reset + * @pf: Board private structure + */ +void ice_ptp_reset(struct ice_pf *pf) +{ + struct ice_ptp *ptp = &pf->ptp; + struct ice_hw *hw = &pf->hw; + struct timespec64 ts; + u64 time_diff; + int err = 1; + u8 src_idx; + + if (test_bit(ICE_PFR_REQ, pf->state)) + goto pfr; + + src_idx = hw->func_caps.ts_func_info.tmr_index_owned; + + wr32(hw, GLTSYN_SYNC_DLAY, 0); + + /* Enable source clocks */ + wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); + + /* Enable PHY time sync */ + err = ice_ptp_init_phy_e810(hw); + if (err) + goto err; + + /* Clear event status indications for auxiliary pins */ + (void)rd32(hw, GLTSYN_STAT(src_idx)); + + /* Acquire the global hardware lock */ + if (!ice_ptp_lock(hw)) { + err = -EBUSY; + goto err; + } + + /* Write the increment time value to PHY and LAN */ + err = ice_ptp_write_incval(hw, ICE_PTP_NOMINAL_INCVAL_E810); + if (err) { + ice_ptp_unlock(hw); + goto err; + } + + /* Write the initial Time value to PHY and LAN using the cached PHC + * time before the reset and time difference between stopping and + * starting the clock. + */ + if (ptp->cached_phc_time) { + time_diff = ktime_get_real_ns() - ptp->reset_time; + ts = ns_to_timespec64(ptp->cached_phc_time + time_diff); + } else { + ts = ktime_to_timespec64(ktime_get_real()); + } + err = ice_ptp_write_init(pf, &ts); + if (err) { + ice_ptp_unlock(hw); + goto err; + } + + /* Release the global hardware lock */ + ice_ptp_unlock(hw); + +pfr: + /* Init Tx structures */ + if (ice_is_e810(&pf->hw)) + err = ice_ptp_init_tx_e810(pf, &ptp->port.tx); + if (err) + goto err; + + set_bit(ICE_FLAG_PTP, pf->flags); + + /* Start periodic work going */ + kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0); + + dev_info(ice_pf_to_dev(pf), "PTP reset successful\n"); + return; + +err: + dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err); +} + +/** + * ice_ptp_prepare_for_reset - Prepare PTP for reset + * @pf: Board private structure + */ +void ice_ptp_prepare_for_reset(struct ice_pf *pf) +{ + struct ice_ptp *ptp = &pf->ptp; + u8 src_tmr; + + clear_bit(ICE_FLAG_PTP, pf->flags); + + /* Disable timestamping for both Tx and Rx */ + ice_ptp_cfg_timestamp(pf, false); + + kthread_cancel_delayed_work_sync(&ptp->work); + kthread_cancel_work_sync(&ptp->extts_work); + + if (test_bit(ICE_PFR_REQ, pf->state)) + return; + + ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); + + /* Disable periodic outputs */ + ice_ptp_disable_all_clkout(pf); + + src_tmr = ice_get_ptp_src_clock_index(&pf->hw); + + /* Disable source clock */ + wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M); + + /* Acquire PHC and system timer to restore after reset */ + ptp->reset_time = ktime_get_real_ns(); +} + +/** * ice_ptp_init_owner - Initialize PTP_1588_CLOCK device * @pf: Board private structure * @@ -1786,7 +1902,6 @@ static void ice_ptp_periodic_work(struct kthread_work *work) */ static int ice_ptp_init_owner(struct ice_pf *pf) { - struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; struct timespec64 ts; u8 src_idx; @@ -1845,12 +1960,39 @@ static int ice_ptp_init_owner(struct ice_pf *pf) err_clk: pf->ptp.clock = NULL; err_exit: - dev_err(dev, "PTP failed to register clock, err %d\n", err); - return err; } /** + * ice_ptp_init_work - Initialize PTP work threads + * @pf: Board private structure + * @ptp: PF PTP structure + */ +static int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp) +{ + struct kthread_worker *kworker; + + /* Initialize work functions */ + kthread_init_delayed_work(&ptp->work, ice_ptp_periodic_work); + kthread_init_work(&ptp->extts_work, ice_ptp_extts_work); + + /* Allocate a kworker for handling work required for the ports + * connected to the PTP hardware clock. + */ + kworker = kthread_create_worker(0, "ice-ptp-%s", + dev_name(ice_pf_to_dev(pf))); + if (IS_ERR(kworker)) + return PTR_ERR(kworker); + + ptp->kworker = kworker; + + /* Start periodic work going */ + kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0); + + return 0; +} + +/** * ice_ptp_init - Initialize the PTP support after device probe or reset * @pf: Board private structure * @@ -1860,8 +2002,7 @@ err_exit: */ void ice_ptp_init(struct ice_pf *pf) { - struct device *dev = ice_pf_to_dev(pf); - struct kthread_worker *kworker; + struct ice_ptp *ptp = &pf->ptp; struct ice_hw *hw = &pf->hw; int err; @@ -1873,44 +2014,29 @@ void ice_ptp_init(struct ice_pf *pf) if (hw->func_caps.ts_func_info.src_tmr_owned) { err = ice_ptp_init_owner(pf); if (err) - return; + goto err; } - /* Disable timestamping for both Tx and Rx */ - ice_ptp_cfg_timestamp(pf, false); - - /* Initialize the PTP port Tx timestamp tracker */ - ice_ptp_init_tx_e810(pf, &pf->ptp.port.tx); - - /* Initialize work functions */ - kthread_init_delayed_work(&pf->ptp.work, ice_ptp_periodic_work); - kthread_init_work(&pf->ptp.extts_work, ice_ptp_extts_work); - - /* Allocate a kworker for handling work required for the ports - * connected to the PTP hardware clock. - */ - kworker = kthread_create_worker(0, "ice-ptp-%s", dev_name(dev)); - if (IS_ERR(kworker)) { - err = PTR_ERR(kworker); - goto err_kworker; - } - pf->ptp.kworker = kworker; + err = ice_ptp_init_tx_e810(pf, &pf->ptp.port.tx); + if (err) + goto err; set_bit(ICE_FLAG_PTP, pf->flags); + err = ice_ptp_init_work(pf, ptp); + if (err) + goto err; - /* Start periodic work going */ - kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work, 0); - - dev_info(dev, "PTP init successful\n"); + dev_info(ice_pf_to_dev(pf), "PTP init successful\n"); return; -err_kworker: +err: /* If we registered a PTP clock, release it */ if (pf->ptp.clock) { - ptp_clock_unregister(pf->ptp.clock); + ptp_clock_unregister(ptp->clock); pf->ptp.clock = NULL; } - dev_err(dev, "PTP failed %d\n", err); + clear_bit(ICE_FLAG_PTP, pf->flags); + dev_err(ice_pf_to_dev(pf), "PTP failed %d\n", err); } /** |