/** * i40e_ptp_init - Initialize the 1588 support after device probe or reset * @pf: Board private structure * * This function sets device up for 1588 support. The first time it is run, it * will create a PHC clock device. It does not create a clock device if one * already exists. It also reconfigures the device after a reset. **/ void i40e_ptp_init(struct i40e_pf *pf) { struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; struct i40e_hw *hw = &pf->hw; u32 pf_id; long err; /* Only one PF is assigned to control 1588 logic per port. Do not * enable any support for PFs not assigned via PRTTSYN_CTL0.PF_ID */ pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> I40E_PRTTSYN_CTL0_PF_ID_SHIFT; if (hw->pf_id != pf_id) { pf->flags &= ~I40E_FLAG_PTP; dev_info(&pf->pdev->dev, "%s: PTP not supported on %s\n", __func__, netdev->name); return; } /* we have to initialize the lock first, since we can't control * when the user will enter the PHC device entry points */ spin_lock_init(&pf->tmreg_lock); /* ensure we have a clock device */ err = i40e_ptp_create_clock(pf); if (err) { pf->ptp_clock = NULL; dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", __func__); } else { struct timespec64 ts; u32 regval; dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, netdev->name); pf->flags |= I40E_FLAG_PTP; /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; wr32(hw, I40E_PRTTSYN_CTL0, regval); regval = rd32(hw, I40E_PRTTSYN_CTL1); regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK; wr32(hw, I40E_PRTTSYN_CTL1, regval); /* Set the increment value per clock tick. */ i40e_ptp_set_increment(pf); /* reset timestamping mode */ i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config); /* Set the clock value. */ ts = ktime_to_timespec64(ktime_get_real()); i40e_ptp_settime(&pf->ptp_caps, &ts); } }
/** * i40e_ptp_restore_hw_time - Restore the ptp_prev_hw_time + delta to PTP regs * @pf: Board private structure * * Restore the PTP hardware clock registers. We previously cached the PTP * hardware time as pf->ptp_prev_hw_time. To be as accurate as possible, * update this value based on the time delta since the time was saved, using * CLOCK_MONOTONIC (via ktime_get()) to calculate the time difference. * * This ensures that the hardware clock is restored to nearly what it should * have been if a reset had not occurred. */ void i40e_ptp_restore_hw_time(struct i40e_pf *pf) { ktime_t delta = ktime_sub(ktime_get(), pf->ptp_reset_start); /* Update the previous HW time with the ktime delta */ timespec64_add_ns(&pf->ptp_prev_hw_time, ktime_to_ns(delta)); /* Restore the hardware clock registers */ i40e_ptp_settime(&pf->ptp_caps, &pf->ptp_prev_hw_time); }
/** * i40e_ptp_init - Initialize the 1588 support after device probe or reset * @pf: Board private structure * * This function sets device up for 1588 support. The first time it is run, it * will create a PHC clock device. It does not create a clock device if one * already exists. It also reconfigures the device after a reset. **/ void i40e_ptp_init(struct i40e_pf *pf) { struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; struct i40e_hw *hw = &pf->hw; long err; /* we have to initialize the lock first, since we can't control * when the user will enter the PHC device entry points */ spin_lock_init(&pf->tmreg_lock); /* ensure we have a clock device */ err = i40e_ptp_create_clock(pf); if (err) { pf->ptp_clock = NULL; dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", __func__); } else { struct timespec ts; u32 regval; dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, netdev->name); pf->flags |= I40E_FLAG_PTP; /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; wr32(hw, I40E_PRTTSYN_CTL0, regval); regval = rd32(hw, I40E_PRTTSYN_CTL1); regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK; wr32(hw, I40E_PRTTSYN_CTL1, regval); /* Set the increment value per clock tick. */ i40e_ptp_set_increment(pf); /* reset timestamping mode */ i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config); /* Set the clock value. */ ts = ktime_to_timespec(ktime_get_real()); i40e_ptp_settime(&pf->ptp_caps, &ts); } }