162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) 2021, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "ice.h"
562306a36Sopenharmony_ci#include "ice_lib.h"
662306a36Sopenharmony_ci#include "ice_trace.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define E810_OUT_PROP_DELAY_NS 1
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define UNKNOWN_INCVAL_E822 0x100000000ULL
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic const struct ptp_pin_desc ice_pin_desc_e810t[] = {
1362306a36Sopenharmony_ci	/* name    idx   func         chan */
1462306a36Sopenharmony_ci	{ "GNSS",  GNSS, PTP_PF_EXTTS, 0, { 0, } },
1562306a36Sopenharmony_ci	{ "SMA1",  SMA1, PTP_PF_NONE, 1, { 0, } },
1662306a36Sopenharmony_ci	{ "U.FL1", UFL1, PTP_PF_NONE, 1, { 0, } },
1762306a36Sopenharmony_ci	{ "SMA2",  SMA2, PTP_PF_NONE, 2, { 0, } },
1862306a36Sopenharmony_ci	{ "U.FL2", UFL2, PTP_PF_NONE, 2, { 0, } },
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci * ice_get_sma_config_e810t
2362306a36Sopenharmony_ci * @hw: pointer to the hw struct
2462306a36Sopenharmony_ci * @ptp_pins: pointer to the ptp_pin_desc struture
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Read the configuration of the SMA control logic and put it into the
2762306a36Sopenharmony_ci * ptp_pin_desc structure
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistatic int
3062306a36Sopenharmony_ciice_get_sma_config_e810t(struct ice_hw *hw, struct ptp_pin_desc *ptp_pins)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	u8 data, i;
3362306a36Sopenharmony_ci	int status;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* Read initial pin state */
3662306a36Sopenharmony_ci	status = ice_read_sma_ctrl_e810t(hw, &data);
3762306a36Sopenharmony_ci	if (status)
3862306a36Sopenharmony_ci		return status;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/* initialize with defaults */
4162306a36Sopenharmony_ci	for (i = 0; i < NUM_PTP_PINS_E810T; i++) {
4262306a36Sopenharmony_ci		snprintf(ptp_pins[i].name, sizeof(ptp_pins[i].name),
4362306a36Sopenharmony_ci			 "%s", ice_pin_desc_e810t[i].name);
4462306a36Sopenharmony_ci		ptp_pins[i].index = ice_pin_desc_e810t[i].index;
4562306a36Sopenharmony_ci		ptp_pins[i].func = ice_pin_desc_e810t[i].func;
4662306a36Sopenharmony_ci		ptp_pins[i].chan = ice_pin_desc_e810t[i].chan;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* Parse SMA1/UFL1 */
5062306a36Sopenharmony_ci	switch (data & ICE_SMA1_MASK_E810T) {
5162306a36Sopenharmony_ci	case ICE_SMA1_MASK_E810T:
5262306a36Sopenharmony_ci	default:
5362306a36Sopenharmony_ci		ptp_pins[SMA1].func = PTP_PF_NONE;
5462306a36Sopenharmony_ci		ptp_pins[UFL1].func = PTP_PF_NONE;
5562306a36Sopenharmony_ci		break;
5662306a36Sopenharmony_ci	case ICE_SMA1_DIR_EN_E810T:
5762306a36Sopenharmony_ci		ptp_pins[SMA1].func = PTP_PF_PEROUT;
5862306a36Sopenharmony_ci		ptp_pins[UFL1].func = PTP_PF_NONE;
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case ICE_SMA1_TX_EN_E810T:
6162306a36Sopenharmony_ci		ptp_pins[SMA1].func = PTP_PF_EXTTS;
6262306a36Sopenharmony_ci		ptp_pins[UFL1].func = PTP_PF_NONE;
6362306a36Sopenharmony_ci		break;
6462306a36Sopenharmony_ci	case 0:
6562306a36Sopenharmony_ci		ptp_pins[SMA1].func = PTP_PF_EXTTS;
6662306a36Sopenharmony_ci		ptp_pins[UFL1].func = PTP_PF_PEROUT;
6762306a36Sopenharmony_ci		break;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Parse SMA2/UFL2 */
7162306a36Sopenharmony_ci	switch (data & ICE_SMA2_MASK_E810T) {
7262306a36Sopenharmony_ci	case ICE_SMA2_MASK_E810T:
7362306a36Sopenharmony_ci	default:
7462306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_NONE;
7562306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_NONE;
7662306a36Sopenharmony_ci		break;
7762306a36Sopenharmony_ci	case (ICE_SMA2_TX_EN_E810T | ICE_SMA2_UFL2_RX_DIS_E810T):
7862306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_EXTTS;
7962306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_NONE;
8062306a36Sopenharmony_ci		break;
8162306a36Sopenharmony_ci	case (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_UFL2_RX_DIS_E810T):
8262306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_PEROUT;
8362306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_NONE;
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	case (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_TX_EN_E810T):
8662306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_NONE;
8762306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_EXTTS;
8862306a36Sopenharmony_ci		break;
8962306a36Sopenharmony_ci	case ICE_SMA2_DIR_EN_E810T:
9062306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_PEROUT;
9162306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_EXTTS;
9262306a36Sopenharmony_ci		break;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return 0;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/**
9962306a36Sopenharmony_ci * ice_ptp_set_sma_config_e810t
10062306a36Sopenharmony_ci * @hw: pointer to the hw struct
10162306a36Sopenharmony_ci * @ptp_pins: pointer to the ptp_pin_desc struture
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Set the configuration of the SMA control logic based on the configuration in
10462306a36Sopenharmony_ci * num_pins parameter
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_cistatic int
10762306a36Sopenharmony_ciice_ptp_set_sma_config_e810t(struct ice_hw *hw,
10862306a36Sopenharmony_ci			     const struct ptp_pin_desc *ptp_pins)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	int status;
11162306a36Sopenharmony_ci	u8 data;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* SMA1 and UFL1 cannot be set to TX at the same time */
11462306a36Sopenharmony_ci	if (ptp_pins[SMA1].func == PTP_PF_PEROUT &&
11562306a36Sopenharmony_ci	    ptp_pins[UFL1].func == PTP_PF_PEROUT)
11662306a36Sopenharmony_ci		return -EINVAL;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* SMA2 and UFL2 cannot be set to RX at the same time */
11962306a36Sopenharmony_ci	if (ptp_pins[SMA2].func == PTP_PF_EXTTS &&
12062306a36Sopenharmony_ci	    ptp_pins[UFL2].func == PTP_PF_EXTTS)
12162306a36Sopenharmony_ci		return -EINVAL;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* Read initial pin state value */
12462306a36Sopenharmony_ci	status = ice_read_sma_ctrl_e810t(hw, &data);
12562306a36Sopenharmony_ci	if (status)
12662306a36Sopenharmony_ci		return status;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Set the right sate based on the desired configuration */
12962306a36Sopenharmony_ci	data &= ~ICE_SMA1_MASK_E810T;
13062306a36Sopenharmony_ci	if (ptp_pins[SMA1].func == PTP_PF_NONE &&
13162306a36Sopenharmony_ci	    ptp_pins[UFL1].func == PTP_PF_NONE) {
13262306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA1 + U.FL1 disabled");
13362306a36Sopenharmony_ci		data |= ICE_SMA1_MASK_E810T;
13462306a36Sopenharmony_ci	} else if (ptp_pins[SMA1].func == PTP_PF_EXTTS &&
13562306a36Sopenharmony_ci		   ptp_pins[UFL1].func == PTP_PF_NONE) {
13662306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA1 RX");
13762306a36Sopenharmony_ci		data |= ICE_SMA1_TX_EN_E810T;
13862306a36Sopenharmony_ci	} else if (ptp_pins[SMA1].func == PTP_PF_NONE &&
13962306a36Sopenharmony_ci		   ptp_pins[UFL1].func == PTP_PF_PEROUT) {
14062306a36Sopenharmony_ci		/* U.FL 1 TX will always enable SMA 1 RX */
14162306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA1 RX + U.FL1 TX");
14262306a36Sopenharmony_ci	} else if (ptp_pins[SMA1].func == PTP_PF_EXTTS &&
14362306a36Sopenharmony_ci		   ptp_pins[UFL1].func == PTP_PF_PEROUT) {
14462306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA1 RX + U.FL1 TX");
14562306a36Sopenharmony_ci	} else if (ptp_pins[SMA1].func == PTP_PF_PEROUT &&
14662306a36Sopenharmony_ci		   ptp_pins[UFL1].func == PTP_PF_NONE) {
14762306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA1 TX");
14862306a36Sopenharmony_ci		data |= ICE_SMA1_DIR_EN_E810T;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	data &= ~ICE_SMA2_MASK_E810T;
15262306a36Sopenharmony_ci	if (ptp_pins[SMA2].func == PTP_PF_NONE &&
15362306a36Sopenharmony_ci	    ptp_pins[UFL2].func == PTP_PF_NONE) {
15462306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA2 + U.FL2 disabled");
15562306a36Sopenharmony_ci		data |= ICE_SMA2_MASK_E810T;
15662306a36Sopenharmony_ci	} else if (ptp_pins[SMA2].func == PTP_PF_EXTTS &&
15762306a36Sopenharmony_ci			ptp_pins[UFL2].func == PTP_PF_NONE) {
15862306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA2 RX");
15962306a36Sopenharmony_ci		data |= (ICE_SMA2_TX_EN_E810T |
16062306a36Sopenharmony_ci			 ICE_SMA2_UFL2_RX_DIS_E810T);
16162306a36Sopenharmony_ci	} else if (ptp_pins[SMA2].func == PTP_PF_NONE &&
16262306a36Sopenharmony_ci		   ptp_pins[UFL2].func == PTP_PF_EXTTS) {
16362306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "UFL2 RX");
16462306a36Sopenharmony_ci		data |= (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_TX_EN_E810T);
16562306a36Sopenharmony_ci	} else if (ptp_pins[SMA2].func == PTP_PF_PEROUT &&
16662306a36Sopenharmony_ci		   ptp_pins[UFL2].func == PTP_PF_NONE) {
16762306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA2 TX");
16862306a36Sopenharmony_ci		data |= (ICE_SMA2_DIR_EN_E810T |
16962306a36Sopenharmony_ci			 ICE_SMA2_UFL2_RX_DIS_E810T);
17062306a36Sopenharmony_ci	} else if (ptp_pins[SMA2].func == PTP_PF_PEROUT &&
17162306a36Sopenharmony_ci		   ptp_pins[UFL2].func == PTP_PF_EXTTS) {
17262306a36Sopenharmony_ci		dev_info(ice_hw_to_dev(hw), "SMA2 TX + U.FL2 RX");
17362306a36Sopenharmony_ci		data |= ICE_SMA2_DIR_EN_E810T;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return ice_write_sma_ctrl_e810t(hw, data);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/**
18062306a36Sopenharmony_ci * ice_ptp_set_sma_e810t
18162306a36Sopenharmony_ci * @info: the driver's PTP info structure
18262306a36Sopenharmony_ci * @pin: pin index in kernel structure
18362306a36Sopenharmony_ci * @func: Pin function to be set (PTP_PF_NONE, PTP_PF_EXTTS or PTP_PF_PEROUT)
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * Set the configuration of a single SMA pin
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic int
18862306a36Sopenharmony_ciice_ptp_set_sma_e810t(struct ptp_clock_info *info, unsigned int pin,
18962306a36Sopenharmony_ci		      enum ptp_pin_function func)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct ptp_pin_desc ptp_pins[NUM_PTP_PINS_E810T];
19262306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
19362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
19462306a36Sopenharmony_ci	int err;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (pin < SMA1 || func > PTP_PF_PEROUT)
19762306a36Sopenharmony_ci		return -EOPNOTSUPP;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	err = ice_get_sma_config_e810t(hw, ptp_pins);
20062306a36Sopenharmony_ci	if (err)
20162306a36Sopenharmony_ci		return err;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Disable the same function on the other pin sharing the channel */
20462306a36Sopenharmony_ci	if (pin == SMA1 && ptp_pins[UFL1].func == func)
20562306a36Sopenharmony_ci		ptp_pins[UFL1].func = PTP_PF_NONE;
20662306a36Sopenharmony_ci	if (pin == UFL1 && ptp_pins[SMA1].func == func)
20762306a36Sopenharmony_ci		ptp_pins[SMA1].func = PTP_PF_NONE;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (pin == SMA2 && ptp_pins[UFL2].func == func)
21062306a36Sopenharmony_ci		ptp_pins[UFL2].func = PTP_PF_NONE;
21162306a36Sopenharmony_ci	if (pin == UFL2 && ptp_pins[SMA2].func == func)
21262306a36Sopenharmony_ci		ptp_pins[SMA2].func = PTP_PF_NONE;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* Set up new pin function in the temp table */
21562306a36Sopenharmony_ci	ptp_pins[pin].func = func;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return ice_ptp_set_sma_config_e810t(hw, ptp_pins);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/**
22162306a36Sopenharmony_ci * ice_verify_pin_e810t
22262306a36Sopenharmony_ci * @info: the driver's PTP info structure
22362306a36Sopenharmony_ci * @pin: Pin index
22462306a36Sopenharmony_ci * @func: Assigned function
22562306a36Sopenharmony_ci * @chan: Assigned channel
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci * Verify if pin supports requested pin function. If the Check pins consistency.
22862306a36Sopenharmony_ci * Reconfigure the SMA logic attached to the given pin to enable its
22962306a36Sopenharmony_ci * desired functionality
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_cistatic int
23262306a36Sopenharmony_ciice_verify_pin_e810t(struct ptp_clock_info *info, unsigned int pin,
23362306a36Sopenharmony_ci		     enum ptp_pin_function func, unsigned int chan)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	/* Don't allow channel reassignment */
23662306a36Sopenharmony_ci	if (chan != ice_pin_desc_e810t[pin].chan)
23762306a36Sopenharmony_ci		return -EOPNOTSUPP;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Check if functions are properly assigned */
24062306a36Sopenharmony_ci	switch (func) {
24162306a36Sopenharmony_ci	case PTP_PF_NONE:
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	case PTP_PF_EXTTS:
24462306a36Sopenharmony_ci		if (pin == UFL1)
24562306a36Sopenharmony_ci			return -EOPNOTSUPP;
24662306a36Sopenharmony_ci		break;
24762306a36Sopenharmony_ci	case PTP_PF_PEROUT:
24862306a36Sopenharmony_ci		if (pin == UFL2 || pin == GNSS)
24962306a36Sopenharmony_ci			return -EOPNOTSUPP;
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci	case PTP_PF_PHYSYNC:
25262306a36Sopenharmony_ci		return -EOPNOTSUPP;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return ice_ptp_set_sma_e810t(info, pin, func);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/**
25962306a36Sopenharmony_ci * ice_set_tx_tstamp - Enable or disable Tx timestamping
26062306a36Sopenharmony_ci * @pf: The PF pointer to search in
26162306a36Sopenharmony_ci * @on: bool value for whether timestamps are enabled or disabled
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_cistatic void ice_set_tx_tstamp(struct ice_pf *pf, bool on)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct ice_vsi *vsi;
26662306a36Sopenharmony_ci	u32 val;
26762306a36Sopenharmony_ci	u16 i;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
27062306a36Sopenharmony_ci	if (!vsi)
27162306a36Sopenharmony_ci		return;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Set the timestamp enable flag for all the Tx rings */
27462306a36Sopenharmony_ci	ice_for_each_txq(vsi, i) {
27562306a36Sopenharmony_ci		if (!vsi->tx_rings[i])
27662306a36Sopenharmony_ci			continue;
27762306a36Sopenharmony_ci		vsi->tx_rings[i]->ptp_tx = on;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Configure the Tx timestamp interrupt */
28162306a36Sopenharmony_ci	val = rd32(&pf->hw, PFINT_OICR_ENA);
28262306a36Sopenharmony_ci	if (on)
28362306a36Sopenharmony_ci		val |= PFINT_OICR_TSYN_TX_M;
28462306a36Sopenharmony_ci	else
28562306a36Sopenharmony_ci		val &= ~PFINT_OICR_TSYN_TX_M;
28662306a36Sopenharmony_ci	wr32(&pf->hw, PFINT_OICR_ENA, val);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	pf->ptp.tstamp_config.tx_type = on ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/**
29262306a36Sopenharmony_ci * ice_set_rx_tstamp - Enable or disable Rx timestamping
29362306a36Sopenharmony_ci * @pf: The PF pointer to search in
29462306a36Sopenharmony_ci * @on: bool value for whether timestamps are enabled or disabled
29562306a36Sopenharmony_ci */
29662306a36Sopenharmony_cistatic void ice_set_rx_tstamp(struct ice_pf *pf, bool on)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct ice_vsi *vsi;
29962306a36Sopenharmony_ci	u16 i;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
30262306a36Sopenharmony_ci	if (!vsi)
30362306a36Sopenharmony_ci		return;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Set the timestamp flag for all the Rx rings */
30662306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
30762306a36Sopenharmony_ci		if (!vsi->rx_rings[i])
30862306a36Sopenharmony_ci			continue;
30962306a36Sopenharmony_ci		vsi->rx_rings[i]->ptp_rx = on;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	pf->ptp.tstamp_config.rx_filter = on ? HWTSTAMP_FILTER_ALL :
31362306a36Sopenharmony_ci					       HWTSTAMP_FILTER_NONE;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * ice_ptp_cfg_timestamp - Configure timestamp for init/deinit
31862306a36Sopenharmony_ci * @pf: Board private structure
31962306a36Sopenharmony_ci * @ena: bool value to enable or disable time stamp
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci * This function will configure timestamping during PTP initialization
32262306a36Sopenharmony_ci * and deinitialization
32362306a36Sopenharmony_ci */
32462306a36Sopenharmony_civoid ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	ice_set_tx_tstamp(pf, ena);
32762306a36Sopenharmony_ci	ice_set_rx_tstamp(pf, ena);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/**
33162306a36Sopenharmony_ci * ice_get_ptp_clock_index - Get the PTP clock index
33262306a36Sopenharmony_ci * @pf: the PF pointer
33362306a36Sopenharmony_ci *
33462306a36Sopenharmony_ci * Determine the clock index of the PTP clock associated with this device. If
33562306a36Sopenharmony_ci * this is the PF controlling the clock, just use the local access to the
33662306a36Sopenharmony_ci * clock device pointer.
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * Otherwise, read from the driver shared parameters to determine the clock
33962306a36Sopenharmony_ci * index value.
34062306a36Sopenharmony_ci *
34162306a36Sopenharmony_ci * Returns: the index of the PTP clock associated with this device, or -1 if
34262306a36Sopenharmony_ci * there is no associated clock.
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_ciint ice_get_ptp_clock_index(struct ice_pf *pf)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
34762306a36Sopenharmony_ci	enum ice_aqc_driver_params param_idx;
34862306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
34962306a36Sopenharmony_ci	u8 tmr_idx;
35062306a36Sopenharmony_ci	u32 value;
35162306a36Sopenharmony_ci	int err;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* Use the ptp_clock structure if we're the main PF */
35462306a36Sopenharmony_ci	if (pf->ptp.clock)
35562306a36Sopenharmony_ci		return ptp_clock_index(pf->ptp.clock);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
35862306a36Sopenharmony_ci	if (!tmr_idx)
35962306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
36062306a36Sopenharmony_ci	else
36162306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	err = ice_aq_get_driver_param(hw, param_idx, &value, NULL);
36462306a36Sopenharmony_ci	if (err) {
36562306a36Sopenharmony_ci		dev_err(dev, "Failed to read PTP clock index parameter, err %d aq_err %s\n",
36662306a36Sopenharmony_ci			err, ice_aq_str(hw->adminq.sq_last_status));
36762306a36Sopenharmony_ci		return -1;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* The PTP clock index is an integer, and will be between 0 and
37162306a36Sopenharmony_ci	 * INT_MAX. The highest bit of the driver shared parameter is used to
37262306a36Sopenharmony_ci	 * indicate whether or not the currently stored clock index is valid.
37362306a36Sopenharmony_ci	 */
37462306a36Sopenharmony_ci	if (!(value & PTP_SHARED_CLK_IDX_VALID))
37562306a36Sopenharmony_ci		return -1;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return value & ~PTP_SHARED_CLK_IDX_VALID;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/**
38162306a36Sopenharmony_ci * ice_set_ptp_clock_index - Set the PTP clock index
38262306a36Sopenharmony_ci * @pf: the PF pointer
38362306a36Sopenharmony_ci *
38462306a36Sopenharmony_ci * Set the PTP clock index for this device into the shared driver parameters,
38562306a36Sopenharmony_ci * so that other PFs associated with this device can read it.
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * If the PF is unable to store the clock index, it will log an error, but
38862306a36Sopenharmony_ci * will continue operating PTP.
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic void ice_set_ptp_clock_index(struct ice_pf *pf)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
39362306a36Sopenharmony_ci	enum ice_aqc_driver_params param_idx;
39462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
39562306a36Sopenharmony_ci	u8 tmr_idx;
39662306a36Sopenharmony_ci	u32 value;
39762306a36Sopenharmony_ci	int err;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (!pf->ptp.clock)
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
40362306a36Sopenharmony_ci	if (!tmr_idx)
40462306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
40562306a36Sopenharmony_ci	else
40662306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	value = (u32)ptp_clock_index(pf->ptp.clock);
40962306a36Sopenharmony_ci	if (value > INT_MAX) {
41062306a36Sopenharmony_ci		dev_err(dev, "PTP Clock index is too large to store\n");
41162306a36Sopenharmony_ci		return;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci	value |= PTP_SHARED_CLK_IDX_VALID;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	err = ice_aq_set_driver_param(hw, param_idx, value, NULL);
41662306a36Sopenharmony_ci	if (err) {
41762306a36Sopenharmony_ci		dev_err(dev, "Failed to set PTP clock index parameter, err %d aq_err %s\n",
41862306a36Sopenharmony_ci			err, ice_aq_str(hw->adminq.sq_last_status));
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/**
42362306a36Sopenharmony_ci * ice_clear_ptp_clock_index - Clear the PTP clock index
42462306a36Sopenharmony_ci * @pf: the PF pointer
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * Clear the PTP clock index for this device. Must be called when
42762306a36Sopenharmony_ci * unregistering the PTP clock, in order to ensure other PFs stop reporting
42862306a36Sopenharmony_ci * a clock object that no longer exists.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_cistatic void ice_clear_ptp_clock_index(struct ice_pf *pf)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
43362306a36Sopenharmony_ci	enum ice_aqc_driver_params param_idx;
43462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
43562306a36Sopenharmony_ci	u8 tmr_idx;
43662306a36Sopenharmony_ci	int err;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Do not clear the index if we don't own the timer */
43962306a36Sopenharmony_ci	if (!hw->func_caps.ts_func_info.src_tmr_owned)
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
44362306a36Sopenharmony_ci	if (!tmr_idx)
44462306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
44562306a36Sopenharmony_ci	else
44662306a36Sopenharmony_ci		param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	err = ice_aq_set_driver_param(hw, param_idx, 0, NULL);
44962306a36Sopenharmony_ci	if (err) {
45062306a36Sopenharmony_ci		dev_dbg(dev, "Failed to clear PTP clock index parameter, err %d aq_err %s\n",
45162306a36Sopenharmony_ci			err, ice_aq_str(hw->adminq.sq_last_status));
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/**
45662306a36Sopenharmony_ci * ice_ptp_read_src_clk_reg - Read the source clock register
45762306a36Sopenharmony_ci * @pf: Board private structure
45862306a36Sopenharmony_ci * @sts: Optional parameter for holding a pair of system timestamps from
45962306a36Sopenharmony_ci *       the system clock. Will be ignored if NULL is given.
46062306a36Sopenharmony_ci */
46162306a36Sopenharmony_cistatic u64
46262306a36Sopenharmony_ciice_ptp_read_src_clk_reg(struct ice_pf *pf, struct ptp_system_timestamp *sts)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
46562306a36Sopenharmony_ci	u32 hi, lo, lo2;
46662306a36Sopenharmony_ci	u8 tmr_idx;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	tmr_idx = ice_get_ptp_src_clock_index(hw);
46962306a36Sopenharmony_ci	/* Read the system timestamp pre PHC read */
47062306a36Sopenharmony_ci	ptp_read_system_prets(sts);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	lo = rd32(hw, GLTSYN_TIME_L(tmr_idx));
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* Read the system timestamp post PHC read */
47562306a36Sopenharmony_ci	ptp_read_system_postts(sts);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	hi = rd32(hw, GLTSYN_TIME_H(tmr_idx));
47862306a36Sopenharmony_ci	lo2 = rd32(hw, GLTSYN_TIME_L(tmr_idx));
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (lo2 < lo) {
48162306a36Sopenharmony_ci		/* if TIME_L rolled over read TIME_L again and update
48262306a36Sopenharmony_ci		 * system timestamps
48362306a36Sopenharmony_ci		 */
48462306a36Sopenharmony_ci		ptp_read_system_prets(sts);
48562306a36Sopenharmony_ci		lo = rd32(hw, GLTSYN_TIME_L(tmr_idx));
48662306a36Sopenharmony_ci		ptp_read_system_postts(sts);
48762306a36Sopenharmony_ci		hi = rd32(hw, GLTSYN_TIME_H(tmr_idx));
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return ((u64)hi << 32) | lo;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/**
49462306a36Sopenharmony_ci * ice_ptp_extend_32b_ts - Convert a 32b nanoseconds timestamp to 64b
49562306a36Sopenharmony_ci * @cached_phc_time: recently cached copy of PHC time
49662306a36Sopenharmony_ci * @in_tstamp: Ingress/egress 32b nanoseconds timestamp value
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * Hardware captures timestamps which contain only 32 bits of nominal
49962306a36Sopenharmony_ci * nanoseconds, as opposed to the 64bit timestamps that the stack expects.
50062306a36Sopenharmony_ci * Note that the captured timestamp values may be 40 bits, but the lower
50162306a36Sopenharmony_ci * 8 bits are sub-nanoseconds and generally discarded.
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * Extend the 32bit nanosecond timestamp using the following algorithm and
50462306a36Sopenharmony_ci * assumptions:
50562306a36Sopenharmony_ci *
50662306a36Sopenharmony_ci * 1) have a recently cached copy of the PHC time
50762306a36Sopenharmony_ci * 2) assume that the in_tstamp was captured 2^31 nanoseconds (~2.1
50862306a36Sopenharmony_ci *    seconds) before or after the PHC time was captured.
50962306a36Sopenharmony_ci * 3) calculate the delta between the cached time and the timestamp
51062306a36Sopenharmony_ci * 4) if the delta is smaller than 2^31 nanoseconds, then the timestamp was
51162306a36Sopenharmony_ci *    captured after the PHC time. In this case, the full timestamp is just
51262306a36Sopenharmony_ci *    the cached PHC time plus the delta.
51362306a36Sopenharmony_ci * 5) otherwise, if the delta is larger than 2^31 nanoseconds, then the
51462306a36Sopenharmony_ci *    timestamp was captured *before* the PHC time, i.e. because the PHC
51562306a36Sopenharmony_ci *    cache was updated after the timestamp was captured by hardware. In this
51662306a36Sopenharmony_ci *    case, the full timestamp is the cached time minus the inverse delta.
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * This algorithm works even if the PHC time was updated after a Tx timestamp
51962306a36Sopenharmony_ci * was requested, but before the Tx timestamp event was reported from
52062306a36Sopenharmony_ci * hardware.
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * This calculation primarily relies on keeping the cached PHC time up to
52362306a36Sopenharmony_ci * date. If the timestamp was captured more than 2^31 nanoseconds after the
52462306a36Sopenharmony_ci * PHC time, it is possible that the lower 32bits of PHC time have
52562306a36Sopenharmony_ci * overflowed more than once, and we might generate an incorrect timestamp.
52662306a36Sopenharmony_ci *
52762306a36Sopenharmony_ci * This is prevented by (a) periodically updating the cached PHC time once
52862306a36Sopenharmony_ci * a second, and (b) discarding any Tx timestamp packet if it has waited for
52962306a36Sopenharmony_ci * a timestamp for more than one second.
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_cistatic u64 ice_ptp_extend_32b_ts(u64 cached_phc_time, u32 in_tstamp)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	u32 delta, phc_time_lo;
53462306a36Sopenharmony_ci	u64 ns;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Extract the lower 32 bits of the PHC time */
53762306a36Sopenharmony_ci	phc_time_lo = (u32)cached_phc_time;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* Calculate the delta between the lower 32bits of the cached PHC
54062306a36Sopenharmony_ci	 * time and the in_tstamp value
54162306a36Sopenharmony_ci	 */
54262306a36Sopenharmony_ci	delta = (in_tstamp - phc_time_lo);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* Do not assume that the in_tstamp is always more recent than the
54562306a36Sopenharmony_ci	 * cached PHC time. If the delta is large, it indicates that the
54662306a36Sopenharmony_ci	 * in_tstamp was taken in the past, and should be converted
54762306a36Sopenharmony_ci	 * forward.
54862306a36Sopenharmony_ci	 */
54962306a36Sopenharmony_ci	if (delta > (U32_MAX / 2)) {
55062306a36Sopenharmony_ci		/* reverse the delta calculation here */
55162306a36Sopenharmony_ci		delta = (phc_time_lo - in_tstamp);
55262306a36Sopenharmony_ci		ns = cached_phc_time - delta;
55362306a36Sopenharmony_ci	} else {
55462306a36Sopenharmony_ci		ns = cached_phc_time + delta;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return ns;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/**
56162306a36Sopenharmony_ci * ice_ptp_extend_40b_ts - Convert a 40b timestamp to 64b nanoseconds
56262306a36Sopenharmony_ci * @pf: Board private structure
56362306a36Sopenharmony_ci * @in_tstamp: Ingress/egress 40b timestamp value
56462306a36Sopenharmony_ci *
56562306a36Sopenharmony_ci * The Tx and Rx timestamps are 40 bits wide, including 32 bits of nominal
56662306a36Sopenharmony_ci * nanoseconds, 7 bits of sub-nanoseconds, and a valid bit.
56762306a36Sopenharmony_ci *
56862306a36Sopenharmony_ci *  *--------------------------------------------------------------*
56962306a36Sopenharmony_ci *  | 32 bits of nanoseconds | 7 high bits of sub ns underflow | v |
57062306a36Sopenharmony_ci *  *--------------------------------------------------------------*
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * The low bit is an indicator of whether the timestamp is valid. The next
57362306a36Sopenharmony_ci * 7 bits are a capture of the upper 7 bits of the sub-nanosecond underflow,
57462306a36Sopenharmony_ci * and the remaining 32 bits are the lower 32 bits of the PHC timer.
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci * It is assumed that the caller verifies the timestamp is valid prior to
57762306a36Sopenharmony_ci * calling this function.
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * Extract the 32bit nominal nanoseconds and extend them. Use the cached PHC
58062306a36Sopenharmony_ci * time stored in the device private PTP structure as the basis for timestamp
58162306a36Sopenharmony_ci * extension.
58262306a36Sopenharmony_ci *
58362306a36Sopenharmony_ci * See ice_ptp_extend_32b_ts for a detailed explanation of the extension
58462306a36Sopenharmony_ci * algorithm.
58562306a36Sopenharmony_ci */
58662306a36Sopenharmony_cistatic u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	const u64 mask = GENMASK_ULL(31, 0);
58962306a36Sopenharmony_ci	unsigned long discard_time;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Discard the hardware timestamp if the cached PHC time is too old */
59262306a36Sopenharmony_ci	discard_time = pf->ptp.cached_phc_jiffies + msecs_to_jiffies(2000);
59362306a36Sopenharmony_ci	if (time_is_before_jiffies(discard_time)) {
59462306a36Sopenharmony_ci		pf->ptp.tx_hwtstamp_discarded++;
59562306a36Sopenharmony_ci		return 0;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
59962306a36Sopenharmony_ci				     (in_tstamp >> 8) & mask);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci/**
60362306a36Sopenharmony_ci * ice_ptp_is_tx_tracker_up - Check if Tx tracker is ready for new timestamps
60462306a36Sopenharmony_ci * @tx: the PTP Tx timestamp tracker to check
60562306a36Sopenharmony_ci *
60662306a36Sopenharmony_ci * Check that a given PTP Tx timestamp tracker is up, i.e. that it is ready
60762306a36Sopenharmony_ci * to accept new timestamp requests.
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * Assumes the tx->lock spinlock is already held.
61062306a36Sopenharmony_ci */
61162306a36Sopenharmony_cistatic bool
61262306a36Sopenharmony_ciice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	lockdep_assert_held(&tx->lock);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return tx->init && !tx->calibrating;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/**
62062306a36Sopenharmony_ci * ice_ptp_process_tx_tstamp - Process Tx timestamps for a port
62162306a36Sopenharmony_ci * @tx: the PTP Tx timestamp tracker
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci * Process timestamps captured by the PHY associated with this port. To do
62462306a36Sopenharmony_ci * this, loop over each index with a waiting skb.
62562306a36Sopenharmony_ci *
62662306a36Sopenharmony_ci * If a given index has a valid timestamp, perform the following steps:
62762306a36Sopenharmony_ci *
62862306a36Sopenharmony_ci * 1) check that the timestamp request is not stale
62962306a36Sopenharmony_ci * 2) check that a timestamp is ready and available in the PHY memory bank
63062306a36Sopenharmony_ci * 3) read and copy the timestamp out of the PHY register
63162306a36Sopenharmony_ci * 4) unlock the index by clearing the associated in_use bit
63262306a36Sopenharmony_ci * 5) check if the timestamp is stale, and discard if so
63362306a36Sopenharmony_ci * 6) extend the 40 bit timestamp value to get a 64 bit timestamp value
63462306a36Sopenharmony_ci * 7) send this 64 bit timestamp to the stack
63562306a36Sopenharmony_ci *
63662306a36Sopenharmony_ci * Note that we do not hold the tracking lock while reading the Tx timestamp.
63762306a36Sopenharmony_ci * This is because reading the timestamp requires taking a mutex that might
63862306a36Sopenharmony_ci * sleep.
63962306a36Sopenharmony_ci *
64062306a36Sopenharmony_ci * The only place where we set in_use is when a new timestamp is initiated
64162306a36Sopenharmony_ci * with a slot index. This is only called in the hard xmit routine where an
64262306a36Sopenharmony_ci * SKB has a request flag set. The only places where we clear this bit is this
64362306a36Sopenharmony_ci * function, or during teardown when the Tx timestamp tracker is being
64462306a36Sopenharmony_ci * removed. A timestamp index will never be re-used until the in_use bit for
64562306a36Sopenharmony_ci * that index is cleared.
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci * If a Tx thread starts a new timestamp, we might not begin processing it
64862306a36Sopenharmony_ci * right away but we will notice it at the end when we re-queue the task.
64962306a36Sopenharmony_ci *
65062306a36Sopenharmony_ci * If a Tx thread starts a new timestamp just after this function exits, the
65162306a36Sopenharmony_ci * interrupt for that timestamp should re-trigger this function once
65262306a36Sopenharmony_ci * a timestamp is ready.
65362306a36Sopenharmony_ci *
65462306a36Sopenharmony_ci * In cases where the PTP hardware clock was directly adjusted, some
65562306a36Sopenharmony_ci * timestamps may not be able to safely use the timestamp extension math. In
65662306a36Sopenharmony_ci * this case, software will set the stale bit for any outstanding Tx
65762306a36Sopenharmony_ci * timestamps when the clock is adjusted. Then this function will discard
65862306a36Sopenharmony_ci * those captured timestamps instead of sending them to the stack.
65962306a36Sopenharmony_ci *
66062306a36Sopenharmony_ci * If a Tx packet has been waiting for more than 2 seconds, it is not possible
66162306a36Sopenharmony_ci * to correctly extend the timestamp using the cached PHC time. It is
66262306a36Sopenharmony_ci * extremely unlikely that a packet will ever take this long to timestamp. If
66362306a36Sopenharmony_ci * we detect a Tx timestamp request that has waited for this long we assume
66462306a36Sopenharmony_ci * the packet will never be sent by hardware and discard it without reading
66562306a36Sopenharmony_ci * the timestamp register.
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_cistatic void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct ice_ptp_port *ptp_port;
67062306a36Sopenharmony_ci	struct ice_pf *pf;
67162306a36Sopenharmony_ci	struct ice_hw *hw;
67262306a36Sopenharmony_ci	u64 tstamp_ready;
67362306a36Sopenharmony_ci	bool link_up;
67462306a36Sopenharmony_ci	int err;
67562306a36Sopenharmony_ci	u8 idx;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (!tx->init)
67862306a36Sopenharmony_ci		return;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	ptp_port = container_of(tx, struct ice_ptp_port, tx);
68162306a36Sopenharmony_ci	pf = ptp_port_to_pf(ptp_port);
68262306a36Sopenharmony_ci	hw = &pf->hw;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Read the Tx ready status first */
68562306a36Sopenharmony_ci	err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready);
68662306a36Sopenharmony_ci	if (err)
68762306a36Sopenharmony_ci		return;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/* Drop packets if the link went down */
69062306a36Sopenharmony_ci	link_up = ptp_port->link_up;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	for_each_set_bit(idx, tx->in_use, tx->len) {
69362306a36Sopenharmony_ci		struct skb_shared_hwtstamps shhwtstamps = {};
69462306a36Sopenharmony_ci		u8 phy_idx = idx + tx->offset;
69562306a36Sopenharmony_ci		u64 raw_tstamp = 0, tstamp;
69662306a36Sopenharmony_ci		bool drop_ts = !link_up;
69762306a36Sopenharmony_ci		struct sk_buff *skb;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		/* Drop packets which have waited for more than 2 seconds */
70062306a36Sopenharmony_ci		if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
70162306a36Sopenharmony_ci			drop_ts = true;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci			/* Count the number of Tx timestamps that timed out */
70462306a36Sopenharmony_ci			pf->ptp.tx_hwtstamp_timeouts++;
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		/* Only read a timestamp from the PHY if its marked as ready
70862306a36Sopenharmony_ci		 * by the tstamp_ready register. This avoids unnecessary
70962306a36Sopenharmony_ci		 * reading of timestamps which are not yet valid. This is
71062306a36Sopenharmony_ci		 * important as we must read all timestamps which are valid
71162306a36Sopenharmony_ci		 * and only timestamps which are valid during each interrupt.
71262306a36Sopenharmony_ci		 * If we do not, the hardware logic for generating a new
71362306a36Sopenharmony_ci		 * interrupt can get stuck on some devices.
71462306a36Sopenharmony_ci		 */
71562306a36Sopenharmony_ci		if (!(tstamp_ready & BIT_ULL(phy_idx))) {
71662306a36Sopenharmony_ci			if (drop_ts)
71762306a36Sopenharmony_ci				goto skip_ts_read;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci			continue;
72062306a36Sopenharmony_ci		}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		ice_trace(tx_tstamp_fw_req, tx->tstamps[idx].skb, idx);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		err = ice_read_phy_tstamp(hw, tx->block, phy_idx, &raw_tstamp);
72562306a36Sopenharmony_ci		if (err && !drop_ts)
72662306a36Sopenharmony_ci			continue;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		ice_trace(tx_tstamp_fw_done, tx->tstamps[idx].skb, idx);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		/* For PHYs which don't implement a proper timestamp ready
73162306a36Sopenharmony_ci		 * bitmap, verify that the timestamp value is different
73262306a36Sopenharmony_ci		 * from the last cached timestamp. If it is not, skip this for
73362306a36Sopenharmony_ci		 * now assuming it hasn't yet been captured by hardware.
73462306a36Sopenharmony_ci		 */
73562306a36Sopenharmony_ci		if (!drop_ts && tx->verify_cached &&
73662306a36Sopenharmony_ci		    raw_tstamp == tx->tstamps[idx].cached_tstamp)
73762306a36Sopenharmony_ci			continue;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		/* Discard any timestamp value without the valid bit set */
74062306a36Sopenharmony_ci		if (!(raw_tstamp & ICE_PTP_TS_VALID))
74162306a36Sopenharmony_ci			drop_ts = true;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ciskip_ts_read:
74462306a36Sopenharmony_ci		spin_lock(&tx->lock);
74562306a36Sopenharmony_ci		if (tx->verify_cached && raw_tstamp)
74662306a36Sopenharmony_ci			tx->tstamps[idx].cached_tstamp = raw_tstamp;
74762306a36Sopenharmony_ci		clear_bit(idx, tx->in_use);
74862306a36Sopenharmony_ci		skb = tx->tstamps[idx].skb;
74962306a36Sopenharmony_ci		tx->tstamps[idx].skb = NULL;
75062306a36Sopenharmony_ci		if (test_and_clear_bit(idx, tx->stale))
75162306a36Sopenharmony_ci			drop_ts = true;
75262306a36Sopenharmony_ci		spin_unlock(&tx->lock);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		/* It is unlikely but possible that the SKB will have been
75562306a36Sopenharmony_ci		 * flushed at this point due to link change or teardown.
75662306a36Sopenharmony_ci		 */
75762306a36Sopenharmony_ci		if (!skb)
75862306a36Sopenharmony_ci			continue;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		if (drop_ts) {
76162306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
76262306a36Sopenharmony_ci			continue;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		/* Extend the timestamp using cached PHC time */
76662306a36Sopenharmony_ci		tstamp = ice_ptp_extend_40b_ts(pf, raw_tstamp);
76762306a36Sopenharmony_ci		if (tstamp) {
76862306a36Sopenharmony_ci			shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
76962306a36Sopenharmony_ci			ice_trace(tx_tstamp_complete, skb, idx);
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		skb_tstamp_tx(skb, &shhwtstamps);
77362306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci/**
77862306a36Sopenharmony_ci * ice_ptp_tx_tstamp - Process Tx timestamps for this function.
77962306a36Sopenharmony_ci * @tx: Tx tracking structure to initialize
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding incomplete
78262306a36Sopenharmony_ci * Tx timestamps, or ICE_TX_TSTAMP_WORK_DONE otherwise.
78362306a36Sopenharmony_ci */
78462306a36Sopenharmony_cistatic enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	bool more_timestamps;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!tx->init)
78962306a36Sopenharmony_ci		return ICE_TX_TSTAMP_WORK_DONE;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* Process the Tx timestamp tracker */
79262306a36Sopenharmony_ci	ice_ptp_process_tx_tstamp(tx);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* Check if there are outstanding Tx timestamps */
79562306a36Sopenharmony_ci	spin_lock(&tx->lock);
79662306a36Sopenharmony_ci	more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len);
79762306a36Sopenharmony_ci	spin_unlock(&tx->lock);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (more_timestamps)
80062306a36Sopenharmony_ci		return ICE_TX_TSTAMP_WORK_PENDING;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return ICE_TX_TSTAMP_WORK_DONE;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci/**
80662306a36Sopenharmony_ci * ice_ptp_alloc_tx_tracker - Initialize tracking for Tx timestamps
80762306a36Sopenharmony_ci * @tx: Tx tracking structure to initialize
80862306a36Sopenharmony_ci *
80962306a36Sopenharmony_ci * Assumes that the length has already been initialized. Do not call directly,
81062306a36Sopenharmony_ci * use the ice_ptp_init_tx_* instead.
81162306a36Sopenharmony_ci */
81262306a36Sopenharmony_cistatic int
81362306a36Sopenharmony_ciice_ptp_alloc_tx_tracker(struct ice_ptp_tx *tx)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	unsigned long *in_use, *stale;
81662306a36Sopenharmony_ci	struct ice_tx_tstamp *tstamps;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	tstamps = kcalloc(tx->len, sizeof(*tstamps), GFP_KERNEL);
81962306a36Sopenharmony_ci	in_use = bitmap_zalloc(tx->len, GFP_KERNEL);
82062306a36Sopenharmony_ci	stale = bitmap_zalloc(tx->len, GFP_KERNEL);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (!tstamps || !in_use || !stale) {
82362306a36Sopenharmony_ci		kfree(tstamps);
82462306a36Sopenharmony_ci		bitmap_free(in_use);
82562306a36Sopenharmony_ci		bitmap_free(stale);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		return -ENOMEM;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	tx->tstamps = tstamps;
83162306a36Sopenharmony_ci	tx->in_use = in_use;
83262306a36Sopenharmony_ci	tx->stale = stale;
83362306a36Sopenharmony_ci	tx->init = 1;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	spin_lock_init(&tx->lock);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	return 0;
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/**
84162306a36Sopenharmony_ci * ice_ptp_flush_tx_tracker - Flush any remaining timestamps from the tracker
84262306a36Sopenharmony_ci * @pf: Board private structure
84362306a36Sopenharmony_ci * @tx: the tracker to flush
84462306a36Sopenharmony_ci *
84562306a36Sopenharmony_ci * Called during teardown when a Tx tracker is being removed.
84662306a36Sopenharmony_ci */
84762306a36Sopenharmony_cistatic void
84862306a36Sopenharmony_ciice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
85162306a36Sopenharmony_ci	u64 tstamp_ready;
85262306a36Sopenharmony_ci	int err;
85362306a36Sopenharmony_ci	u8 idx;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready);
85662306a36Sopenharmony_ci	if (err) {
85762306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "Failed to get the Tx tstamp ready bitmap for block %u, err %d\n",
85862306a36Sopenharmony_ci			tx->block, err);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		/* If we fail to read the Tx timestamp ready bitmap just
86162306a36Sopenharmony_ci		 * skip clearing the PHY timestamps.
86262306a36Sopenharmony_ci		 */
86362306a36Sopenharmony_ci		tstamp_ready = 0;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	for_each_set_bit(idx, tx->in_use, tx->len) {
86762306a36Sopenharmony_ci		u8 phy_idx = idx + tx->offset;
86862306a36Sopenharmony_ci		struct sk_buff *skb;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		/* In case this timestamp is ready, we need to clear it. */
87162306a36Sopenharmony_ci		if (!hw->reset_ongoing && (tstamp_ready & BIT_ULL(phy_idx)))
87262306a36Sopenharmony_ci			ice_clear_phy_tstamp(hw, tx->block, phy_idx);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		spin_lock(&tx->lock);
87562306a36Sopenharmony_ci		skb = tx->tstamps[idx].skb;
87662306a36Sopenharmony_ci		tx->tstamps[idx].skb = NULL;
87762306a36Sopenharmony_ci		clear_bit(idx, tx->in_use);
87862306a36Sopenharmony_ci		clear_bit(idx, tx->stale);
87962306a36Sopenharmony_ci		spin_unlock(&tx->lock);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		/* Count the number of Tx timestamps flushed */
88262306a36Sopenharmony_ci		pf->ptp.tx_hwtstamp_flushed++;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		/* Free the SKB after we've cleared the bit */
88562306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci/**
89062306a36Sopenharmony_ci * ice_ptp_mark_tx_tracker_stale - Mark unfinished timestamps as stale
89162306a36Sopenharmony_ci * @tx: the tracker to mark
89262306a36Sopenharmony_ci *
89362306a36Sopenharmony_ci * Mark currently outstanding Tx timestamps as stale. This prevents sending
89462306a36Sopenharmony_ci * their timestamp value to the stack. This is required to prevent extending
89562306a36Sopenharmony_ci * the 40bit hardware timestamp incorrectly.
89662306a36Sopenharmony_ci *
89762306a36Sopenharmony_ci * This should be called when the PTP clock is modified such as after a set
89862306a36Sopenharmony_ci * time request.
89962306a36Sopenharmony_ci */
90062306a36Sopenharmony_cistatic void
90162306a36Sopenharmony_ciice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	spin_lock(&tx->lock);
90462306a36Sopenharmony_ci	bitmap_or(tx->stale, tx->stale, tx->in_use, tx->len);
90562306a36Sopenharmony_ci	spin_unlock(&tx->lock);
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci/**
90962306a36Sopenharmony_ci * ice_ptp_release_tx_tracker - Release allocated memory for Tx tracker
91062306a36Sopenharmony_ci * @pf: Board private structure
91162306a36Sopenharmony_ci * @tx: Tx tracking structure to release
91262306a36Sopenharmony_ci *
91362306a36Sopenharmony_ci * Free memory associated with the Tx timestamp tracker.
91462306a36Sopenharmony_ci */
91562306a36Sopenharmony_cistatic void
91662306a36Sopenharmony_ciice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	spin_lock(&tx->lock);
91962306a36Sopenharmony_ci	tx->init = 0;
92062306a36Sopenharmony_ci	spin_unlock(&tx->lock);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* wait for potentially outstanding interrupt to complete */
92362306a36Sopenharmony_ci	synchronize_irq(pf->oicr_irq.virq);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	ice_ptp_flush_tx_tracker(pf, tx);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	kfree(tx->tstamps);
92862306a36Sopenharmony_ci	tx->tstamps = NULL;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	bitmap_free(tx->in_use);
93162306a36Sopenharmony_ci	tx->in_use = NULL;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	bitmap_free(tx->stale);
93462306a36Sopenharmony_ci	tx->stale = NULL;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	tx->len = 0;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci/**
94062306a36Sopenharmony_ci * ice_ptp_init_tx_e822 - Initialize tracking for Tx timestamps
94162306a36Sopenharmony_ci * @pf: Board private structure
94262306a36Sopenharmony_ci * @tx: the Tx tracking structure to initialize
94362306a36Sopenharmony_ci * @port: the port this structure tracks
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * Initialize the Tx timestamp tracker for this port. For generic MAC devices,
94662306a36Sopenharmony_ci * the timestamp block is shared for all ports in the same quad. To avoid
94762306a36Sopenharmony_ci * ports using the same timestamp index, logically break the block of
94862306a36Sopenharmony_ci * registers into chunks based on the port number.
94962306a36Sopenharmony_ci */
95062306a36Sopenharmony_cistatic int
95162306a36Sopenharmony_ciice_ptp_init_tx_e822(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	tx->block = port / ICE_PORTS_PER_QUAD;
95462306a36Sopenharmony_ci	tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E822;
95562306a36Sopenharmony_ci	tx->len = INDEX_PER_PORT_E822;
95662306a36Sopenharmony_ci	tx->verify_cached = 0;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return ice_ptp_alloc_tx_tracker(tx);
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci/**
96262306a36Sopenharmony_ci * ice_ptp_init_tx_e810 - Initialize tracking for Tx timestamps
96362306a36Sopenharmony_ci * @pf: Board private structure
96462306a36Sopenharmony_ci * @tx: the Tx tracking structure to initialize
96562306a36Sopenharmony_ci *
96662306a36Sopenharmony_ci * Initialize the Tx timestamp tracker for this PF. For E810 devices, each
96762306a36Sopenharmony_ci * port has its own block of timestamps, independent of the other ports.
96862306a36Sopenharmony_ci */
96962306a36Sopenharmony_cistatic int
97062306a36Sopenharmony_ciice_ptp_init_tx_e810(struct ice_pf *pf, struct ice_ptp_tx *tx)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	tx->block = pf->hw.port_info->lport;
97362306a36Sopenharmony_ci	tx->offset = 0;
97462306a36Sopenharmony_ci	tx->len = INDEX_PER_PORT_E810;
97562306a36Sopenharmony_ci	/* The E810 PHY does not provide a timestamp ready bitmap. Instead,
97662306a36Sopenharmony_ci	 * verify new timestamps against cached copy of the last read
97762306a36Sopenharmony_ci	 * timestamp.
97862306a36Sopenharmony_ci	 */
97962306a36Sopenharmony_ci	tx->verify_cached = 1;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return ice_ptp_alloc_tx_tracker(tx);
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci/**
98562306a36Sopenharmony_ci * ice_ptp_update_cached_phctime - Update the cached PHC time values
98662306a36Sopenharmony_ci * @pf: Board specific private structure
98762306a36Sopenharmony_ci *
98862306a36Sopenharmony_ci * This function updates the system time values which are cached in the PF
98962306a36Sopenharmony_ci * structure and the Rx rings.
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * This function must be called periodically to ensure that the cached value
99262306a36Sopenharmony_ci * is never more than 2 seconds old.
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * Note that the cached copy in the PF PTP structure is always updated, even
99562306a36Sopenharmony_ci * if we can't update the copy in the Rx rings.
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci * Return:
99862306a36Sopenharmony_ci * * 0 - OK, successfully updated
99962306a36Sopenharmony_ci * * -EAGAIN - PF was busy, need to reschedule the update
100062306a36Sopenharmony_ci */
100162306a36Sopenharmony_cistatic int ice_ptp_update_cached_phctime(struct ice_pf *pf)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
100462306a36Sopenharmony_ci	unsigned long update_before;
100562306a36Sopenharmony_ci	u64 systime;
100662306a36Sopenharmony_ci	int i;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	update_before = pf->ptp.cached_phc_jiffies + msecs_to_jiffies(2000);
100962306a36Sopenharmony_ci	if (pf->ptp.cached_phc_time &&
101062306a36Sopenharmony_ci	    time_is_before_jiffies(update_before)) {
101162306a36Sopenharmony_ci		unsigned long time_taken = jiffies - pf->ptp.cached_phc_jiffies;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		dev_warn(dev, "%u msecs passed between update to cached PHC time\n",
101462306a36Sopenharmony_ci			 jiffies_to_msecs(time_taken));
101562306a36Sopenharmony_ci		pf->ptp.late_cached_phc_updates++;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Read the current PHC time */
101962306a36Sopenharmony_ci	systime = ice_ptp_read_src_clk_reg(pf, NULL);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/* Update the cached PHC time stored in the PF structure */
102262306a36Sopenharmony_ci	WRITE_ONCE(pf->ptp.cached_phc_time, systime);
102362306a36Sopenharmony_ci	WRITE_ONCE(pf->ptp.cached_phc_jiffies, jiffies);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (test_and_set_bit(ICE_CFG_BUSY, pf->state))
102662306a36Sopenharmony_ci		return -EAGAIN;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	ice_for_each_vsi(pf, i) {
102962306a36Sopenharmony_ci		struct ice_vsi *vsi = pf->vsi[i];
103062306a36Sopenharmony_ci		int j;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		if (!vsi)
103362306a36Sopenharmony_ci			continue;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		if (vsi->type != ICE_VSI_PF)
103662306a36Sopenharmony_ci			continue;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		ice_for_each_rxq(vsi, j) {
103962306a36Sopenharmony_ci			if (!vsi->rx_rings[j])
104062306a36Sopenharmony_ci				continue;
104162306a36Sopenharmony_ci			WRITE_ONCE(vsi->rx_rings[j]->cached_phctime, systime);
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, pf->state);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	return 0;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci/**
105062306a36Sopenharmony_ci * ice_ptp_reset_cached_phctime - Reset cached PHC time after an update
105162306a36Sopenharmony_ci * @pf: Board specific private structure
105262306a36Sopenharmony_ci *
105362306a36Sopenharmony_ci * This function must be called when the cached PHC time is no longer valid,
105462306a36Sopenharmony_ci * such as after a time adjustment. It marks any currently outstanding Tx
105562306a36Sopenharmony_ci * timestamps as stale and updates the cached PHC time for both the PF and Rx
105662306a36Sopenharmony_ci * rings.
105762306a36Sopenharmony_ci *
105862306a36Sopenharmony_ci * If updating the PHC time cannot be done immediately, a warning message is
105962306a36Sopenharmony_ci * logged and the work item is scheduled immediately to minimize the window
106062306a36Sopenharmony_ci * with a wrong cached timestamp.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_cistatic void ice_ptp_reset_cached_phctime(struct ice_pf *pf)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
106562306a36Sopenharmony_ci	int err;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* Update the cached PHC time immediately if possible, otherwise
106862306a36Sopenharmony_ci	 * schedule the work item to execute soon.
106962306a36Sopenharmony_ci	 */
107062306a36Sopenharmony_ci	err = ice_ptp_update_cached_phctime(pf);
107162306a36Sopenharmony_ci	if (err) {
107262306a36Sopenharmony_ci		/* If another thread is updating the Rx rings, we won't
107362306a36Sopenharmony_ci		 * properly reset them here. This could lead to reporting of
107462306a36Sopenharmony_ci		 * invalid timestamps, but there isn't much we can do.
107562306a36Sopenharmony_ci		 */
107662306a36Sopenharmony_ci		dev_warn(dev, "%s: ICE_CFG_BUSY, unable to immediately update cached PHC time\n",
107762306a36Sopenharmony_ci			 __func__);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		/* Queue the work item to update the Rx rings when possible */
108062306a36Sopenharmony_ci		kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work,
108162306a36Sopenharmony_ci					   msecs_to_jiffies(10));
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	/* Mark any outstanding timestamps as stale, since they might have
108562306a36Sopenharmony_ci	 * been captured in hardware before the time update. This could lead
108662306a36Sopenharmony_ci	 * to us extending them with the wrong cached value resulting in
108762306a36Sopenharmony_ci	 * incorrect timestamp values.
108862306a36Sopenharmony_ci	 */
108962306a36Sopenharmony_ci	ice_ptp_mark_tx_tracker_stale(&pf->ptp.port.tx);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci/**
109362306a36Sopenharmony_ci * ice_ptp_read_time - Read the time from the device
109462306a36Sopenharmony_ci * @pf: Board private structure
109562306a36Sopenharmony_ci * @ts: timespec structure to hold the current time value
109662306a36Sopenharmony_ci * @sts: Optional parameter for holding a pair of system timestamps from
109762306a36Sopenharmony_ci *       the system clock. Will be ignored if NULL is given.
109862306a36Sopenharmony_ci *
109962306a36Sopenharmony_ci * This function reads the source clock registers and stores them in a timespec.
110062306a36Sopenharmony_ci * However, since the registers are 64 bits of nanoseconds, we must convert the
110162306a36Sopenharmony_ci * result to a timespec before we can return.
110262306a36Sopenharmony_ci */
110362306a36Sopenharmony_cistatic void
110462306a36Sopenharmony_ciice_ptp_read_time(struct ice_pf *pf, struct timespec64 *ts,
110562306a36Sopenharmony_ci		  struct ptp_system_timestamp *sts)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	u64 time_ns = ice_ptp_read_src_clk_reg(pf, sts);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	*ts = ns_to_timespec64(time_ns);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci/**
111362306a36Sopenharmony_ci * ice_ptp_write_init - Set PHC time to provided value
111462306a36Sopenharmony_ci * @pf: Board private structure
111562306a36Sopenharmony_ci * @ts: timespec structure that holds the new time value
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci * Set the PHC time to the specified time provided in the timespec.
111862306a36Sopenharmony_ci */
111962306a36Sopenharmony_cistatic int ice_ptp_write_init(struct ice_pf *pf, struct timespec64 *ts)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	u64 ns = timespec64_to_ns(ts);
112262306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	return ice_ptp_init_time(hw, ns);
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci/**
112862306a36Sopenharmony_ci * ice_ptp_write_adj - Adjust PHC clock time atomically
112962306a36Sopenharmony_ci * @pf: Board private structure
113062306a36Sopenharmony_ci * @adj: Adjustment in nanoseconds
113162306a36Sopenharmony_ci *
113262306a36Sopenharmony_ci * Perform an atomic adjustment of the PHC time by the specified number of
113362306a36Sopenharmony_ci * nanoseconds.
113462306a36Sopenharmony_ci */
113562306a36Sopenharmony_cistatic int ice_ptp_write_adj(struct ice_pf *pf, s32 adj)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	return ice_ptp_adj_clock(hw, adj);
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/**
114362306a36Sopenharmony_ci * ice_base_incval - Get base timer increment value
114462306a36Sopenharmony_ci * @pf: Board private structure
114562306a36Sopenharmony_ci *
114662306a36Sopenharmony_ci * Look up the base timer increment value for this device. The base increment
114762306a36Sopenharmony_ci * value is used to define the nominal clock tick rate. This increment value
114862306a36Sopenharmony_ci * is programmed during device initialization. It is also used as the basis
114962306a36Sopenharmony_ci * for calculating adjustments using scaled_ppm.
115062306a36Sopenharmony_ci */
115162306a36Sopenharmony_cistatic u64 ice_base_incval(struct ice_pf *pf)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
115462306a36Sopenharmony_ci	u64 incval;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	if (ice_is_e810(hw))
115762306a36Sopenharmony_ci		incval = ICE_PTP_NOMINAL_INCVAL_E810;
115862306a36Sopenharmony_ci	else if (ice_e822_time_ref(hw) < NUM_ICE_TIME_REF_FREQ)
115962306a36Sopenharmony_ci		incval = ice_e822_nominal_incval(ice_e822_time_ref(hw));
116062306a36Sopenharmony_ci	else
116162306a36Sopenharmony_ci		incval = UNKNOWN_INCVAL_E822;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	dev_dbg(ice_pf_to_dev(pf), "PTP: using base increment value of 0x%016llx\n",
116462306a36Sopenharmony_ci		incval);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	return incval;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci/**
117062306a36Sopenharmony_ci * ice_ptp_check_tx_fifo - Check whether Tx FIFO is in an OK state
117162306a36Sopenharmony_ci * @port: PTP port for which Tx FIFO is checked
117262306a36Sopenharmony_ci */
117362306a36Sopenharmony_cistatic int ice_ptp_check_tx_fifo(struct ice_ptp_port *port)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	int quad = port->port_num / ICE_PORTS_PER_QUAD;
117662306a36Sopenharmony_ci	int offs = port->port_num % ICE_PORTS_PER_QUAD;
117762306a36Sopenharmony_ci	struct ice_pf *pf;
117862306a36Sopenharmony_ci	struct ice_hw *hw;
117962306a36Sopenharmony_ci	u32 val, phy_sts;
118062306a36Sopenharmony_ci	int err;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	pf = ptp_port_to_pf(port);
118362306a36Sopenharmony_ci	hw = &pf->hw;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (port->tx_fifo_busy_cnt == FIFO_OK)
118662306a36Sopenharmony_ci		return 0;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* need to read FIFO state */
118962306a36Sopenharmony_ci	if (offs == 0 || offs == 1)
119062306a36Sopenharmony_ci		err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO01_STATUS,
119162306a36Sopenharmony_ci					     &val);
119262306a36Sopenharmony_ci	else
119362306a36Sopenharmony_ci		err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO23_STATUS,
119462306a36Sopenharmony_ci					     &val);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	if (err) {
119762306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to check port %d Tx FIFO, err %d\n",
119862306a36Sopenharmony_ci			port->port_num, err);
119962306a36Sopenharmony_ci		return err;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (offs & 0x1)
120362306a36Sopenharmony_ci		phy_sts = (val & Q_REG_FIFO13_M) >> Q_REG_FIFO13_S;
120462306a36Sopenharmony_ci	else
120562306a36Sopenharmony_ci		phy_sts = (val & Q_REG_FIFO02_M) >> Q_REG_FIFO02_S;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (phy_sts & FIFO_EMPTY) {
120862306a36Sopenharmony_ci		port->tx_fifo_busy_cnt = FIFO_OK;
120962306a36Sopenharmony_ci		return 0;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	port->tx_fifo_busy_cnt++;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	dev_dbg(ice_pf_to_dev(pf), "Try %d, port %d FIFO not empty\n",
121562306a36Sopenharmony_ci		port->tx_fifo_busy_cnt, port->port_num);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (port->tx_fifo_busy_cnt == ICE_PTP_FIFO_NUM_CHECKS) {
121862306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf),
121962306a36Sopenharmony_ci			"Port %d Tx FIFO still not empty; resetting quad %d\n",
122062306a36Sopenharmony_ci			port->port_num, quad);
122162306a36Sopenharmony_ci		ice_ptp_reset_ts_memory_quad_e822(hw, quad);
122262306a36Sopenharmony_ci		port->tx_fifo_busy_cnt = FIFO_OK;
122362306a36Sopenharmony_ci		return 0;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return -EAGAIN;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci/**
123062306a36Sopenharmony_ci * ice_ptp_wait_for_offsets - Check for valid Tx and Rx offsets
123162306a36Sopenharmony_ci * @work: Pointer to the kthread_work structure for this task
123262306a36Sopenharmony_ci *
123362306a36Sopenharmony_ci * Check whether hardware has completed measuring the Tx and Rx offset values
123462306a36Sopenharmony_ci * used to configure and enable vernier timestamp calibration.
123562306a36Sopenharmony_ci *
123662306a36Sopenharmony_ci * Once the offset in either direction is measured, configure the associated
123762306a36Sopenharmony_ci * registers with the calibrated offset values and enable timestamping. The Tx
123862306a36Sopenharmony_ci * and Rx directions are configured independently as soon as their associated
123962306a36Sopenharmony_ci * offsets are known.
124062306a36Sopenharmony_ci *
124162306a36Sopenharmony_ci * This function reschedules itself until both Tx and Rx calibration have
124262306a36Sopenharmony_ci * completed.
124362306a36Sopenharmony_ci */
124462306a36Sopenharmony_cistatic void ice_ptp_wait_for_offsets(struct kthread_work *work)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct ice_ptp_port *port;
124762306a36Sopenharmony_ci	struct ice_pf *pf;
124862306a36Sopenharmony_ci	struct ice_hw *hw;
124962306a36Sopenharmony_ci	int tx_err;
125062306a36Sopenharmony_ci	int rx_err;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	port = container_of(work, struct ice_ptp_port, ov_work.work);
125362306a36Sopenharmony_ci	pf = ptp_port_to_pf(port);
125462306a36Sopenharmony_ci	hw = &pf->hw;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state)) {
125762306a36Sopenharmony_ci		/* wait for device driver to complete reset */
125862306a36Sopenharmony_ci		kthread_queue_delayed_work(pf->ptp.kworker,
125962306a36Sopenharmony_ci					   &port->ov_work,
126062306a36Sopenharmony_ci					   msecs_to_jiffies(100));
126162306a36Sopenharmony_ci		return;
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	tx_err = ice_ptp_check_tx_fifo(port);
126562306a36Sopenharmony_ci	if (!tx_err)
126662306a36Sopenharmony_ci		tx_err = ice_phy_cfg_tx_offset_e822(hw, port->port_num);
126762306a36Sopenharmony_ci	rx_err = ice_phy_cfg_rx_offset_e822(hw, port->port_num);
126862306a36Sopenharmony_ci	if (tx_err || rx_err) {
126962306a36Sopenharmony_ci		/* Tx and/or Rx offset not yet configured, try again later */
127062306a36Sopenharmony_ci		kthread_queue_delayed_work(pf->ptp.kworker,
127162306a36Sopenharmony_ci					   &port->ov_work,
127262306a36Sopenharmony_ci					   msecs_to_jiffies(100));
127362306a36Sopenharmony_ci		return;
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci/**
127862306a36Sopenharmony_ci * ice_ptp_port_phy_stop - Stop timestamping for a PHY port
127962306a36Sopenharmony_ci * @ptp_port: PTP port to stop
128062306a36Sopenharmony_ci */
128162306a36Sopenharmony_cistatic int
128262306a36Sopenharmony_ciice_ptp_port_phy_stop(struct ice_ptp_port *ptp_port)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct ice_pf *pf = ptp_port_to_pf(ptp_port);
128562306a36Sopenharmony_ci	u8 port = ptp_port->port_num;
128662306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
128762306a36Sopenharmony_ci	int err;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	if (ice_is_e810(hw))
129062306a36Sopenharmony_ci		return 0;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	mutex_lock(&ptp_port->ps_lock);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	err = ice_stop_phy_timer_e822(hw, port, true);
129762306a36Sopenharmony_ci	if (err)
129862306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d down, err %d\n",
129962306a36Sopenharmony_ci			port, err);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	mutex_unlock(&ptp_port->ps_lock);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return err;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci/**
130762306a36Sopenharmony_ci * ice_ptp_port_phy_restart - (Re)start and calibrate PHY timestamping
130862306a36Sopenharmony_ci * @ptp_port: PTP port for which the PHY start is set
130962306a36Sopenharmony_ci *
131062306a36Sopenharmony_ci * Start the PHY timestamping block, and initiate Vernier timestamping
131162306a36Sopenharmony_ci * calibration. If timestamping cannot be calibrated (such as if link is down)
131262306a36Sopenharmony_ci * then disable the timestamping block instead.
131362306a36Sopenharmony_ci */
131462306a36Sopenharmony_cistatic int
131562306a36Sopenharmony_ciice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct ice_pf *pf = ptp_port_to_pf(ptp_port);
131862306a36Sopenharmony_ci	u8 port = ptp_port->port_num;
131962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
132062306a36Sopenharmony_ci	int err;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (ice_is_e810(hw))
132362306a36Sopenharmony_ci		return 0;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (!ptp_port->link_up)
132662306a36Sopenharmony_ci		return ice_ptp_port_phy_stop(ptp_port);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	mutex_lock(&ptp_port->ps_lock);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* temporarily disable Tx timestamps while calibrating PHY offset */
133362306a36Sopenharmony_ci	spin_lock(&ptp_port->tx.lock);
133462306a36Sopenharmony_ci	ptp_port->tx.calibrating = true;
133562306a36Sopenharmony_ci	spin_unlock(&ptp_port->tx.lock);
133662306a36Sopenharmony_ci	ptp_port->tx_fifo_busy_cnt = 0;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* Start the PHY timer in Vernier mode */
133962306a36Sopenharmony_ci	err = ice_start_phy_timer_e822(hw, port);
134062306a36Sopenharmony_ci	if (err)
134162306a36Sopenharmony_ci		goto out_unlock;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	/* Enable Tx timestamps right away */
134462306a36Sopenharmony_ci	spin_lock(&ptp_port->tx.lock);
134562306a36Sopenharmony_ci	ptp_port->tx.calibrating = false;
134662306a36Sopenharmony_ci	spin_unlock(&ptp_port->tx.lock);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	kthread_queue_delayed_work(pf->ptp.kworker, &ptp_port->ov_work, 0);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ciout_unlock:
135162306a36Sopenharmony_ci	if (err)
135262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d up, err %d\n",
135362306a36Sopenharmony_ci			port, err);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	mutex_unlock(&ptp_port->ps_lock);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	return err;
135862306a36Sopenharmony_ci}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci/**
136162306a36Sopenharmony_ci * ice_ptp_link_change - Reconfigure PTP after link status change
136262306a36Sopenharmony_ci * @pf: Board private structure
136362306a36Sopenharmony_ci * @port: Port for which the PHY start is set
136462306a36Sopenharmony_ci * @linkup: Link is up or down
136562306a36Sopenharmony_ci */
136662306a36Sopenharmony_civoid ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct ice_ptp_port *ptp_port;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
137162306a36Sopenharmony_ci		return;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (WARN_ON_ONCE(port >= ICE_NUM_EXTERNAL_PORTS))
137462306a36Sopenharmony_ci		return;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	ptp_port = &pf->ptp.port;
137762306a36Sopenharmony_ci	if (WARN_ON_ONCE(ptp_port->port_num != port))
137862306a36Sopenharmony_ci		return;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	/* Update cached link status for this port immediately */
138162306a36Sopenharmony_ci	ptp_port->link_up = linkup;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	/* E810 devices do not need to reconfigure the PHY */
138462306a36Sopenharmony_ci	if (ice_is_e810(&pf->hw))
138562306a36Sopenharmony_ci		return;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	ice_ptp_port_phy_restart(ptp_port);
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci/**
139162306a36Sopenharmony_ci * ice_ptp_tx_ena_intr - Enable or disable the Tx timestamp interrupt
139262306a36Sopenharmony_ci * @pf: PF private structure
139362306a36Sopenharmony_ci * @ena: bool value to enable or disable interrupt
139462306a36Sopenharmony_ci * @threshold: Minimum number of packets at which intr is triggered
139562306a36Sopenharmony_ci *
139662306a36Sopenharmony_ci * Utility function to enable or disable Tx timestamp interrupt and threshold
139762306a36Sopenharmony_ci */
139862306a36Sopenharmony_cistatic int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
140162306a36Sopenharmony_ci	int err = 0;
140262306a36Sopenharmony_ci	int quad;
140362306a36Sopenharmony_ci	u32 val;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	ice_ptp_reset_ts_memory(hw);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	for (quad = 0; quad < ICE_MAX_QUAD; quad++) {
140862306a36Sopenharmony_ci		err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
140962306a36Sopenharmony_ci					     &val);
141062306a36Sopenharmony_ci		if (err)
141162306a36Sopenharmony_ci			break;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		if (ena) {
141462306a36Sopenharmony_ci			val |= Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
141562306a36Sopenharmony_ci			val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_THR_M;
141662306a36Sopenharmony_ci			val |= ((threshold << Q_REG_TX_MEM_GBL_CFG_INTR_THR_S) &
141762306a36Sopenharmony_ci				Q_REG_TX_MEM_GBL_CFG_INTR_THR_M);
141862306a36Sopenharmony_ci		} else {
141962306a36Sopenharmony_ci			val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
142062306a36Sopenharmony_ci		}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
142362306a36Sopenharmony_ci					      val);
142462306a36Sopenharmony_ci		if (err)
142562306a36Sopenharmony_ci			break;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	if (err)
142962306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed in intr ena, err %d\n",
143062306a36Sopenharmony_ci			err);
143162306a36Sopenharmony_ci	return err;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci/**
143562306a36Sopenharmony_ci * ice_ptp_reset_phy_timestamping - Reset PHY timestamping block
143662306a36Sopenharmony_ci * @pf: Board private structure
143762306a36Sopenharmony_ci */
143862306a36Sopenharmony_cistatic void ice_ptp_reset_phy_timestamping(struct ice_pf *pf)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	ice_ptp_port_phy_restart(&pf->ptp.port);
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci/**
144462306a36Sopenharmony_ci * ice_ptp_adjfine - Adjust clock increment rate
144562306a36Sopenharmony_ci * @info: the driver's PTP info structure
144662306a36Sopenharmony_ci * @scaled_ppm: Parts per million with 16-bit fractional field
144762306a36Sopenharmony_ci *
144862306a36Sopenharmony_ci * Adjust the frequency of the clock by the indicated scaled ppm from the
144962306a36Sopenharmony_ci * base frequency.
145062306a36Sopenharmony_ci */
145162306a36Sopenharmony_cistatic int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
145462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
145562306a36Sopenharmony_ci	u64 incval;
145662306a36Sopenharmony_ci	int err;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	incval = adjust_by_scaled_ppm(ice_base_incval(pf), scaled_ppm);
145962306a36Sopenharmony_ci	err = ice_ptp_write_incval_locked(hw, incval);
146062306a36Sopenharmony_ci	if (err) {
146162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to set incval, err %d\n",
146262306a36Sopenharmony_ci			err);
146362306a36Sopenharmony_ci		return -EIO;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	return 0;
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci/**
147062306a36Sopenharmony_ci * ice_ptp_extts_event - Process PTP external clock event
147162306a36Sopenharmony_ci * @pf: Board private structure
147262306a36Sopenharmony_ci */
147362306a36Sopenharmony_civoid ice_ptp_extts_event(struct ice_pf *pf)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct ptp_clock_event event;
147662306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
147762306a36Sopenharmony_ci	u8 chan, tmr_idx;
147862306a36Sopenharmony_ci	u32 hi, lo;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
148162306a36Sopenharmony_ci	/* Event time is captured by one of the two matched registers
148262306a36Sopenharmony_ci	 *      GLTSYN_EVNT_L: 32 LSB of sampled time event
148362306a36Sopenharmony_ci	 *      GLTSYN_EVNT_H: 32 MSB of sampled time event
148462306a36Sopenharmony_ci	 * Event is defined in GLTSYN_EVNT_0 register
148562306a36Sopenharmony_ci	 */
148662306a36Sopenharmony_ci	for (chan = 0; chan < GLTSYN_EVNT_H_IDX_MAX; chan++) {
148762306a36Sopenharmony_ci		/* Check if channel is enabled */
148862306a36Sopenharmony_ci		if (pf->ptp.ext_ts_irq & (1 << chan)) {
148962306a36Sopenharmony_ci			lo = rd32(hw, GLTSYN_EVNT_L(chan, tmr_idx));
149062306a36Sopenharmony_ci			hi = rd32(hw, GLTSYN_EVNT_H(chan, tmr_idx));
149162306a36Sopenharmony_ci			event.timestamp = (((u64)hi) << 32) | lo;
149262306a36Sopenharmony_ci			event.type = PTP_CLOCK_EXTTS;
149362306a36Sopenharmony_ci			event.index = chan;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci			/* Fire event */
149662306a36Sopenharmony_ci			ptp_clock_event(pf->ptp.clock, &event);
149762306a36Sopenharmony_ci			pf->ptp.ext_ts_irq &= ~(1 << chan);
149862306a36Sopenharmony_ci		}
149962306a36Sopenharmony_ci	}
150062306a36Sopenharmony_ci}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci/**
150362306a36Sopenharmony_ci * ice_ptp_cfg_extts - Configure EXTTS pin and channel
150462306a36Sopenharmony_ci * @pf: Board private structure
150562306a36Sopenharmony_ci * @ena: true to enable; false to disable
150662306a36Sopenharmony_ci * @chan: GPIO channel (0-3)
150762306a36Sopenharmony_ci * @gpio_pin: GPIO pin
150862306a36Sopenharmony_ci * @extts_flags: request flags from the ptp_extts_request.flags
150962306a36Sopenharmony_ci */
151062306a36Sopenharmony_cistatic int
151162306a36Sopenharmony_ciice_ptp_cfg_extts(struct ice_pf *pf, bool ena, unsigned int chan, u32 gpio_pin,
151262306a36Sopenharmony_ci		  unsigned int extts_flags)
151362306a36Sopenharmony_ci{
151462306a36Sopenharmony_ci	u32 func, aux_reg, gpio_reg, irq_reg;
151562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
151662306a36Sopenharmony_ci	u8 tmr_idx;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	if (chan > (unsigned int)pf->ptp.info.n_ext_ts)
151962306a36Sopenharmony_ci		return -EINVAL;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	irq_reg = rd32(hw, PFINT_OICR_ENA);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (ena) {
152662306a36Sopenharmony_ci		/* Enable the interrupt */
152762306a36Sopenharmony_ci		irq_reg |= PFINT_OICR_TSYN_EVNT_M;
152862306a36Sopenharmony_ci		aux_reg = GLTSYN_AUX_IN_0_INT_ENA_M;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci#define GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE	BIT(0)
153162306a36Sopenharmony_ci#define GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE	BIT(1)
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci		/* set event level to requested edge */
153462306a36Sopenharmony_ci		if (extts_flags & PTP_FALLING_EDGE)
153562306a36Sopenharmony_ci			aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE;
153662306a36Sopenharmony_ci		if (extts_flags & PTP_RISING_EDGE)
153762306a36Sopenharmony_ci			aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		/* Write GPIO CTL reg.
154062306a36Sopenharmony_ci		 * 0x1 is input sampled by EVENT register(channel)
154162306a36Sopenharmony_ci		 * + num_in_channels * tmr_idx
154262306a36Sopenharmony_ci		 */
154362306a36Sopenharmony_ci		func = 1 + chan + (tmr_idx * 3);
154462306a36Sopenharmony_ci		gpio_reg = ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) &
154562306a36Sopenharmony_ci			    GLGEN_GPIO_CTL_PIN_FUNC_M);
154662306a36Sopenharmony_ci		pf->ptp.ext_ts_chan |= (1 << chan);
154762306a36Sopenharmony_ci	} else {
154862306a36Sopenharmony_ci		/* clear the values we set to reset defaults */
154962306a36Sopenharmony_ci		aux_reg = 0;
155062306a36Sopenharmony_ci		gpio_reg = 0;
155162306a36Sopenharmony_ci		pf->ptp.ext_ts_chan &= ~(1 << chan);
155262306a36Sopenharmony_ci		if (!pf->ptp.ext_ts_chan)
155362306a36Sopenharmony_ci			irq_reg &= ~PFINT_OICR_TSYN_EVNT_M;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_ENA, irq_reg);
155762306a36Sopenharmony_ci	wr32(hw, GLTSYN_AUX_IN(chan, tmr_idx), aux_reg);
155862306a36Sopenharmony_ci	wr32(hw, GLGEN_GPIO_CTL(gpio_pin), gpio_reg);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	return 0;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci/**
156462306a36Sopenharmony_ci * ice_ptp_cfg_clkout - Configure clock to generate periodic wave
156562306a36Sopenharmony_ci * @pf: Board private structure
156662306a36Sopenharmony_ci * @chan: GPIO channel (0-3)
156762306a36Sopenharmony_ci * @config: desired periodic clk configuration. NULL will disable channel
156862306a36Sopenharmony_ci * @store: If set to true the values will be stored
156962306a36Sopenharmony_ci *
157062306a36Sopenharmony_ci * Configure the internal clock generator modules to generate the clock wave of
157162306a36Sopenharmony_ci * specified period.
157262306a36Sopenharmony_ci */
157362306a36Sopenharmony_cistatic int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan,
157462306a36Sopenharmony_ci			      struct ice_perout_channel *config, bool store)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	u64 current_time, period, start_time, phase;
157762306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
157862306a36Sopenharmony_ci	u32 func, val, gpio_pin;
157962306a36Sopenharmony_ci	u8 tmr_idx;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	/* 0. Reset mode & out_en in AUX_OUT */
158462306a36Sopenharmony_ci	wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), 0);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	/* If we're disabling the output, clear out CLKO and TGT and keep
158762306a36Sopenharmony_ci	 * output level low
158862306a36Sopenharmony_ci	 */
158962306a36Sopenharmony_ci	if (!config || !config->ena) {
159062306a36Sopenharmony_ci		wr32(hw, GLTSYN_CLKO(chan, tmr_idx), 0);
159162306a36Sopenharmony_ci		wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), 0);
159262306a36Sopenharmony_ci		wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), 0);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		val = GLGEN_GPIO_CTL_PIN_DIR_M;
159562306a36Sopenharmony_ci		gpio_pin = pf->ptp.perout_channels[chan].gpio_pin;
159662306a36Sopenharmony_ci		wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		/* Store the value if requested */
159962306a36Sopenharmony_ci		if (store)
160062306a36Sopenharmony_ci			memset(&pf->ptp.perout_channels[chan], 0,
160162306a36Sopenharmony_ci			       sizeof(struct ice_perout_channel));
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		return 0;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	period = config->period;
160662306a36Sopenharmony_ci	start_time = config->start_time;
160762306a36Sopenharmony_ci	div64_u64_rem(start_time, period, &phase);
160862306a36Sopenharmony_ci	gpio_pin = config->gpio_pin;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	/* 1. Write clkout with half of required period value */
161162306a36Sopenharmony_ci	if (period & 0x1) {
161262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "CLK Period must be an even value\n");
161362306a36Sopenharmony_ci		goto err;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	period >>= 1;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	/* For proper operation, the GLTSYN_CLKO must be larger than clock tick
161962306a36Sopenharmony_ci	 */
162062306a36Sopenharmony_ci#define MIN_PULSE 3
162162306a36Sopenharmony_ci	if (period <= MIN_PULSE || period > U32_MAX) {
162262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "CLK Period must be > %d && < 2^33",
162362306a36Sopenharmony_ci			MIN_PULSE * 2);
162462306a36Sopenharmony_ci		goto err;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	wr32(hw, GLTSYN_CLKO(chan, tmr_idx), lower_32_bits(period));
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	/* Allow time for programming before start_time is hit */
163062306a36Sopenharmony_ci	current_time = ice_ptp_read_src_clk_reg(pf, NULL);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/* if start time is in the past start the timer at the nearest second
163362306a36Sopenharmony_ci	 * maintaining phase
163462306a36Sopenharmony_ci	 */
163562306a36Sopenharmony_ci	if (start_time < current_time)
163662306a36Sopenharmony_ci		start_time = div64_u64(current_time + NSEC_PER_SEC - 1,
163762306a36Sopenharmony_ci				       NSEC_PER_SEC) * NSEC_PER_SEC + phase;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (ice_is_e810(hw))
164062306a36Sopenharmony_ci		start_time -= E810_OUT_PROP_DELAY_NS;
164162306a36Sopenharmony_ci	else
164262306a36Sopenharmony_ci		start_time -= ice_e822_pps_delay(ice_e822_time_ref(hw));
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	/* 2. Write TARGET time */
164562306a36Sopenharmony_ci	wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time));
164662306a36Sopenharmony_ci	wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), upper_32_bits(start_time));
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/* 3. Write AUX_OUT register */
164962306a36Sopenharmony_ci	val = GLTSYN_AUX_OUT_0_OUT_ENA_M | GLTSYN_AUX_OUT_0_OUTMOD_M;
165062306a36Sopenharmony_ci	wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), val);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	/* 4. write GPIO CTL reg */
165362306a36Sopenharmony_ci	func = 8 + chan + (tmr_idx * 4);
165462306a36Sopenharmony_ci	val = GLGEN_GPIO_CTL_PIN_DIR_M |
165562306a36Sopenharmony_ci	      ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) & GLGEN_GPIO_CTL_PIN_FUNC_M);
165662306a36Sopenharmony_ci	wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	/* Store the value if requested */
165962306a36Sopenharmony_ci	if (store) {
166062306a36Sopenharmony_ci		memcpy(&pf->ptp.perout_channels[chan], config,
166162306a36Sopenharmony_ci		       sizeof(struct ice_perout_channel));
166262306a36Sopenharmony_ci		pf->ptp.perout_channels[chan].start_time = phase;
166362306a36Sopenharmony_ci	}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	return 0;
166662306a36Sopenharmony_cierr:
166762306a36Sopenharmony_ci	dev_err(ice_pf_to_dev(pf), "PTP failed to cfg per_clk\n");
166862306a36Sopenharmony_ci	return -EFAULT;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci/**
167262306a36Sopenharmony_ci * ice_ptp_disable_all_clkout - Disable all currently configured outputs
167362306a36Sopenharmony_ci * @pf: pointer to the PF structure
167462306a36Sopenharmony_ci *
167562306a36Sopenharmony_ci * Disable all currently configured clock outputs. This is necessary before
167662306a36Sopenharmony_ci * certain changes to the PTP hardware clock. Use ice_ptp_enable_all_clkout to
167762306a36Sopenharmony_ci * re-enable the clocks again.
167862306a36Sopenharmony_ci */
167962306a36Sopenharmony_cistatic void ice_ptp_disable_all_clkout(struct ice_pf *pf)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	uint i;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	for (i = 0; i < pf->ptp.info.n_per_out; i++)
168462306a36Sopenharmony_ci		if (pf->ptp.perout_channels[i].ena)
168562306a36Sopenharmony_ci			ice_ptp_cfg_clkout(pf, i, NULL, false);
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci/**
168962306a36Sopenharmony_ci * ice_ptp_enable_all_clkout - Enable all configured periodic clock outputs
169062306a36Sopenharmony_ci * @pf: pointer to the PF structure
169162306a36Sopenharmony_ci *
169262306a36Sopenharmony_ci * Enable all currently configured clock outputs. Use this after
169362306a36Sopenharmony_ci * ice_ptp_disable_all_clkout to reconfigure the output signals according to
169462306a36Sopenharmony_ci * their configuration.
169562306a36Sopenharmony_ci */
169662306a36Sopenharmony_cistatic void ice_ptp_enable_all_clkout(struct ice_pf *pf)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	uint i;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	for (i = 0; i < pf->ptp.info.n_per_out; i++)
170162306a36Sopenharmony_ci		if (pf->ptp.perout_channels[i].ena)
170262306a36Sopenharmony_ci			ice_ptp_cfg_clkout(pf, i, &pf->ptp.perout_channels[i],
170362306a36Sopenharmony_ci					   false);
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci/**
170762306a36Sopenharmony_ci * ice_ptp_gpio_enable_e810 - Enable/disable ancillary features of PHC
170862306a36Sopenharmony_ci * @info: the driver's PTP info structure
170962306a36Sopenharmony_ci * @rq: The requested feature to change
171062306a36Sopenharmony_ci * @on: Enable/disable flag
171162306a36Sopenharmony_ci */
171262306a36Sopenharmony_cistatic int
171362306a36Sopenharmony_ciice_ptp_gpio_enable_e810(struct ptp_clock_info *info,
171462306a36Sopenharmony_ci			 struct ptp_clock_request *rq, int on)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
171762306a36Sopenharmony_ci	struct ice_perout_channel clk_cfg = {0};
171862306a36Sopenharmony_ci	bool sma_pres = false;
171962306a36Sopenharmony_ci	unsigned int chan;
172062306a36Sopenharmony_ci	u32 gpio_pin;
172162306a36Sopenharmony_ci	int err;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL))
172462306a36Sopenharmony_ci		sma_pres = true;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	switch (rq->type) {
172762306a36Sopenharmony_ci	case PTP_CLK_REQ_PEROUT:
172862306a36Sopenharmony_ci		chan = rq->perout.index;
172962306a36Sopenharmony_ci		if (sma_pres) {
173062306a36Sopenharmony_ci			if (chan == ice_pin_desc_e810t[SMA1].chan)
173162306a36Sopenharmony_ci				clk_cfg.gpio_pin = GPIO_20;
173262306a36Sopenharmony_ci			else if (chan == ice_pin_desc_e810t[SMA2].chan)
173362306a36Sopenharmony_ci				clk_cfg.gpio_pin = GPIO_22;
173462306a36Sopenharmony_ci			else
173562306a36Sopenharmony_ci				return -1;
173662306a36Sopenharmony_ci		} else if (ice_is_e810t(&pf->hw)) {
173762306a36Sopenharmony_ci			if (chan == 0)
173862306a36Sopenharmony_ci				clk_cfg.gpio_pin = GPIO_20;
173962306a36Sopenharmony_ci			else
174062306a36Sopenharmony_ci				clk_cfg.gpio_pin = GPIO_22;
174162306a36Sopenharmony_ci		} else if (chan == PPS_CLK_GEN_CHAN) {
174262306a36Sopenharmony_ci			clk_cfg.gpio_pin = PPS_PIN_INDEX;
174362306a36Sopenharmony_ci		} else {
174462306a36Sopenharmony_ci			clk_cfg.gpio_pin = chan;
174562306a36Sopenharmony_ci		}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci		clk_cfg.period = ((rq->perout.period.sec * NSEC_PER_SEC) +
174862306a36Sopenharmony_ci				   rq->perout.period.nsec);
174962306a36Sopenharmony_ci		clk_cfg.start_time = ((rq->perout.start.sec * NSEC_PER_SEC) +
175062306a36Sopenharmony_ci				       rq->perout.start.nsec);
175162306a36Sopenharmony_ci		clk_cfg.ena = !!on;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		err = ice_ptp_cfg_clkout(pf, chan, &clk_cfg, true);
175462306a36Sopenharmony_ci		break;
175562306a36Sopenharmony_ci	case PTP_CLK_REQ_EXTTS:
175662306a36Sopenharmony_ci		chan = rq->extts.index;
175762306a36Sopenharmony_ci		if (sma_pres) {
175862306a36Sopenharmony_ci			if (chan < ice_pin_desc_e810t[SMA2].chan)
175962306a36Sopenharmony_ci				gpio_pin = GPIO_21;
176062306a36Sopenharmony_ci			else
176162306a36Sopenharmony_ci				gpio_pin = GPIO_23;
176262306a36Sopenharmony_ci		} else if (ice_is_e810t(&pf->hw)) {
176362306a36Sopenharmony_ci			if (chan == 0)
176462306a36Sopenharmony_ci				gpio_pin = GPIO_21;
176562306a36Sopenharmony_ci			else
176662306a36Sopenharmony_ci				gpio_pin = GPIO_23;
176762306a36Sopenharmony_ci		} else {
176862306a36Sopenharmony_ci			gpio_pin = chan;
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		err = ice_ptp_cfg_extts(pf, !!on, chan, gpio_pin,
177262306a36Sopenharmony_ci					rq->extts.flags);
177362306a36Sopenharmony_ci		break;
177462306a36Sopenharmony_ci	default:
177562306a36Sopenharmony_ci		return -EOPNOTSUPP;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	return err;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci/**
178262306a36Sopenharmony_ci * ice_ptp_gpio_enable_e823 - Enable/disable ancillary features of PHC
178362306a36Sopenharmony_ci * @info: the driver's PTP info structure
178462306a36Sopenharmony_ci * @rq: The requested feature to change
178562306a36Sopenharmony_ci * @on: Enable/disable flag
178662306a36Sopenharmony_ci */
178762306a36Sopenharmony_cistatic int ice_ptp_gpio_enable_e823(struct ptp_clock_info *info,
178862306a36Sopenharmony_ci				    struct ptp_clock_request *rq, int on)
178962306a36Sopenharmony_ci{
179062306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
179162306a36Sopenharmony_ci	struct ice_perout_channel clk_cfg = {0};
179262306a36Sopenharmony_ci	int err;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	switch (rq->type) {
179562306a36Sopenharmony_ci	case PTP_CLK_REQ_PPS:
179662306a36Sopenharmony_ci		clk_cfg.gpio_pin = PPS_PIN_INDEX;
179762306a36Sopenharmony_ci		clk_cfg.period = NSEC_PER_SEC;
179862306a36Sopenharmony_ci		clk_cfg.ena = !!on;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci		err = ice_ptp_cfg_clkout(pf, PPS_CLK_GEN_CHAN, &clk_cfg, true);
180162306a36Sopenharmony_ci		break;
180262306a36Sopenharmony_ci	case PTP_CLK_REQ_EXTTS:
180362306a36Sopenharmony_ci		err = ice_ptp_cfg_extts(pf, !!on, rq->extts.index,
180462306a36Sopenharmony_ci					TIME_SYNC_PIN_INDEX, rq->extts.flags);
180562306a36Sopenharmony_ci		break;
180662306a36Sopenharmony_ci	default:
180762306a36Sopenharmony_ci		return -EOPNOTSUPP;
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	return err;
181162306a36Sopenharmony_ci}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci/**
181462306a36Sopenharmony_ci * ice_ptp_gettimex64 - Get the time of the clock
181562306a36Sopenharmony_ci * @info: the driver's PTP info structure
181662306a36Sopenharmony_ci * @ts: timespec64 structure to hold the current time value
181762306a36Sopenharmony_ci * @sts: Optional parameter for holding a pair of system timestamps from
181862306a36Sopenharmony_ci *       the system clock. Will be ignored if NULL is given.
181962306a36Sopenharmony_ci *
182062306a36Sopenharmony_ci * Read the device clock and return the correct value on ns, after converting it
182162306a36Sopenharmony_ci * into a timespec struct.
182262306a36Sopenharmony_ci */
182362306a36Sopenharmony_cistatic int
182462306a36Sopenharmony_ciice_ptp_gettimex64(struct ptp_clock_info *info, struct timespec64 *ts,
182562306a36Sopenharmony_ci		   struct ptp_system_timestamp *sts)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
182862306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	if (!ice_ptp_lock(hw)) {
183162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to get time\n");
183262306a36Sopenharmony_ci		return -EBUSY;
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	ice_ptp_read_time(pf, ts, sts);
183662306a36Sopenharmony_ci	ice_ptp_unlock(hw);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	return 0;
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci/**
184262306a36Sopenharmony_ci * ice_ptp_settime64 - Set the time of the clock
184362306a36Sopenharmony_ci * @info: the driver's PTP info structure
184462306a36Sopenharmony_ci * @ts: timespec64 structure that holds the new time value
184562306a36Sopenharmony_ci *
184662306a36Sopenharmony_ci * Set the device clock to the user input value. The conversion from timespec
184762306a36Sopenharmony_ci * to ns happens in the write function.
184862306a36Sopenharmony_ci */
184962306a36Sopenharmony_cistatic int
185062306a36Sopenharmony_ciice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
185362306a36Sopenharmony_ci	struct timespec64 ts64 = *ts;
185462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
185562306a36Sopenharmony_ci	int err;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	/* For Vernier mode, we need to recalibrate after new settime
185862306a36Sopenharmony_ci	 * Start with disabling timestamp block
185962306a36Sopenharmony_ci	 */
186062306a36Sopenharmony_ci	if (pf->ptp.port.link_up)
186162306a36Sopenharmony_ci		ice_ptp_port_phy_stop(&pf->ptp.port);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	if (!ice_ptp_lock(hw)) {
186462306a36Sopenharmony_ci		err = -EBUSY;
186562306a36Sopenharmony_ci		goto exit;
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	/* Disable periodic outputs */
186962306a36Sopenharmony_ci	ice_ptp_disable_all_clkout(pf);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	err = ice_ptp_write_init(pf, &ts64);
187262306a36Sopenharmony_ci	ice_ptp_unlock(hw);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	if (!err)
187562306a36Sopenharmony_ci		ice_ptp_reset_cached_phctime(pf);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	/* Reenable periodic outputs */
187862306a36Sopenharmony_ci	ice_ptp_enable_all_clkout(pf);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	/* Recalibrate and re-enable timestamp block */
188162306a36Sopenharmony_ci	if (pf->ptp.port.link_up)
188262306a36Sopenharmony_ci		ice_ptp_port_phy_restart(&pf->ptp.port);
188362306a36Sopenharmony_ciexit:
188462306a36Sopenharmony_ci	if (err) {
188562306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to set time %d\n", err);
188662306a36Sopenharmony_ci		return err;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	return 0;
189062306a36Sopenharmony_ci}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci/**
189362306a36Sopenharmony_ci * ice_ptp_adjtime_nonatomic - Do a non-atomic clock adjustment
189462306a36Sopenharmony_ci * @info: the driver's PTP info structure
189562306a36Sopenharmony_ci * @delta: Offset in nanoseconds to adjust the time by
189662306a36Sopenharmony_ci */
189762306a36Sopenharmony_cistatic int ice_ptp_adjtime_nonatomic(struct ptp_clock_info *info, s64 delta)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	struct timespec64 now, then;
190062306a36Sopenharmony_ci	int ret;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	then = ns_to_timespec64(delta);
190362306a36Sopenharmony_ci	ret = ice_ptp_gettimex64(info, &now, NULL);
190462306a36Sopenharmony_ci	if (ret)
190562306a36Sopenharmony_ci		return ret;
190662306a36Sopenharmony_ci	now = timespec64_add(now, then);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	return ice_ptp_settime64(info, (const struct timespec64 *)&now);
190962306a36Sopenharmony_ci}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci/**
191262306a36Sopenharmony_ci * ice_ptp_adjtime - Adjust the time of the clock by the indicated delta
191362306a36Sopenharmony_ci * @info: the driver's PTP info structure
191462306a36Sopenharmony_ci * @delta: Offset in nanoseconds to adjust the time by
191562306a36Sopenharmony_ci */
191662306a36Sopenharmony_cistatic int ice_ptp_adjtime(struct ptp_clock_info *info, s64 delta)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
191962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
192062306a36Sopenharmony_ci	struct device *dev;
192162306a36Sopenharmony_ci	int err;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	/* Hardware only supports atomic adjustments using signed 32-bit
192662306a36Sopenharmony_ci	 * integers. For any adjustment outside this range, perform
192762306a36Sopenharmony_ci	 * a non-atomic get->adjust->set flow.
192862306a36Sopenharmony_ci	 */
192962306a36Sopenharmony_ci	if (delta > S32_MAX || delta < S32_MIN) {
193062306a36Sopenharmony_ci		dev_dbg(dev, "delta = %lld, adjtime non-atomic\n", delta);
193162306a36Sopenharmony_ci		return ice_ptp_adjtime_nonatomic(info, delta);
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if (!ice_ptp_lock(hw)) {
193562306a36Sopenharmony_ci		dev_err(dev, "PTP failed to acquire semaphore in adjtime\n");
193662306a36Sopenharmony_ci		return -EBUSY;
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	/* Disable periodic outputs */
194062306a36Sopenharmony_ci	ice_ptp_disable_all_clkout(pf);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	err = ice_ptp_write_adj(pf, delta);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	/* Reenable periodic outputs */
194562306a36Sopenharmony_ci	ice_ptp_enable_all_clkout(pf);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	ice_ptp_unlock(hw);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (err) {
195062306a36Sopenharmony_ci		dev_err(dev, "PTP failed to adjust time, err %d\n", err);
195162306a36Sopenharmony_ci		return err;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	ice_ptp_reset_cached_phctime(pf);
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	return 0;
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci#ifdef CONFIG_ICE_HWTS
196062306a36Sopenharmony_ci/**
196162306a36Sopenharmony_ci * ice_ptp_get_syncdevicetime - Get the cross time stamp info
196262306a36Sopenharmony_ci * @device: Current device time
196362306a36Sopenharmony_ci * @system: System counter value read synchronously with device time
196462306a36Sopenharmony_ci * @ctx: Context provided by timekeeping code
196562306a36Sopenharmony_ci *
196662306a36Sopenharmony_ci * Read device and system (ART) clock simultaneously and return the corrected
196762306a36Sopenharmony_ci * clock values in ns.
196862306a36Sopenharmony_ci */
196962306a36Sopenharmony_cistatic int
197062306a36Sopenharmony_ciice_ptp_get_syncdevicetime(ktime_t *device,
197162306a36Sopenharmony_ci			   struct system_counterval_t *system,
197262306a36Sopenharmony_ci			   void *ctx)
197362306a36Sopenharmony_ci{
197462306a36Sopenharmony_ci	struct ice_pf *pf = (struct ice_pf *)ctx;
197562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
197662306a36Sopenharmony_ci	u32 hh_lock, hh_art_ctl;
197762306a36Sopenharmony_ci	int i;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	/* Get the HW lock */
198062306a36Sopenharmony_ci	hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
198162306a36Sopenharmony_ci	if (hh_lock & PFHH_SEM_BUSY_M) {
198262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "PTP failed to get hh lock\n");
198362306a36Sopenharmony_ci		return -EFAULT;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	/* Start the ART and device clock sync sequence */
198762306a36Sopenharmony_ci	hh_art_ctl = rd32(hw, GLHH_ART_CTL);
198862306a36Sopenharmony_ci	hh_art_ctl = hh_art_ctl | GLHH_ART_CTL_ACTIVE_M;
198962306a36Sopenharmony_ci	wr32(hw, GLHH_ART_CTL, hh_art_ctl);
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci#define MAX_HH_LOCK_TRIES 100
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	for (i = 0; i < MAX_HH_LOCK_TRIES; i++) {
199462306a36Sopenharmony_ci		/* Wait for sync to complete */
199562306a36Sopenharmony_ci		hh_art_ctl = rd32(hw, GLHH_ART_CTL);
199662306a36Sopenharmony_ci		if (hh_art_ctl & GLHH_ART_CTL_ACTIVE_M) {
199762306a36Sopenharmony_ci			udelay(1);
199862306a36Sopenharmony_ci			continue;
199962306a36Sopenharmony_ci		} else {
200062306a36Sopenharmony_ci			u32 hh_ts_lo, hh_ts_hi, tmr_idx;
200162306a36Sopenharmony_ci			u64 hh_ts;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci			tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
200462306a36Sopenharmony_ci			/* Read ART time */
200562306a36Sopenharmony_ci			hh_ts_lo = rd32(hw, GLHH_ART_TIME_L);
200662306a36Sopenharmony_ci			hh_ts_hi = rd32(hw, GLHH_ART_TIME_H);
200762306a36Sopenharmony_ci			hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
200862306a36Sopenharmony_ci			*system = convert_art_ns_to_tsc(hh_ts);
200962306a36Sopenharmony_ci			/* Read Device source clock time */
201062306a36Sopenharmony_ci			hh_ts_lo = rd32(hw, GLTSYN_HHTIME_L(tmr_idx));
201162306a36Sopenharmony_ci			hh_ts_hi = rd32(hw, GLTSYN_HHTIME_H(tmr_idx));
201262306a36Sopenharmony_ci			hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
201362306a36Sopenharmony_ci			*device = ns_to_ktime(hh_ts);
201462306a36Sopenharmony_ci			break;
201562306a36Sopenharmony_ci		}
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci	/* Release HW lock */
201862306a36Sopenharmony_ci	hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
201962306a36Sopenharmony_ci	hh_lock = hh_lock & ~PFHH_SEM_BUSY_M;
202062306a36Sopenharmony_ci	wr32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), hh_lock);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if (i == MAX_HH_LOCK_TRIES)
202362306a36Sopenharmony_ci		return -ETIMEDOUT;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	return 0;
202662306a36Sopenharmony_ci}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci/**
202962306a36Sopenharmony_ci * ice_ptp_getcrosststamp_e822 - Capture a device cross timestamp
203062306a36Sopenharmony_ci * @info: the driver's PTP info structure
203162306a36Sopenharmony_ci * @cts: The memory to fill the cross timestamp info
203262306a36Sopenharmony_ci *
203362306a36Sopenharmony_ci * Capture a cross timestamp between the ART and the device PTP hardware
203462306a36Sopenharmony_ci * clock. Fill the cross timestamp information and report it back to the
203562306a36Sopenharmony_ci * caller.
203662306a36Sopenharmony_ci *
203762306a36Sopenharmony_ci * This is only valid for E822 devices which have support for generating the
203862306a36Sopenharmony_ci * cross timestamp via PCIe PTM.
203962306a36Sopenharmony_ci *
204062306a36Sopenharmony_ci * In order to correctly correlate the ART timestamp back to the TSC time, the
204162306a36Sopenharmony_ci * CPU must have X86_FEATURE_TSC_KNOWN_FREQ.
204262306a36Sopenharmony_ci */
204362306a36Sopenharmony_cistatic int
204462306a36Sopenharmony_ciice_ptp_getcrosststamp_e822(struct ptp_clock_info *info,
204562306a36Sopenharmony_ci			    struct system_device_crosststamp *cts)
204662306a36Sopenharmony_ci{
204762306a36Sopenharmony_ci	struct ice_pf *pf = ptp_info_to_pf(info);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	return get_device_system_crosststamp(ice_ptp_get_syncdevicetime,
205062306a36Sopenharmony_ci					     pf, NULL, cts);
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci#endif /* CONFIG_ICE_HWTS */
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci/**
205562306a36Sopenharmony_ci * ice_ptp_get_ts_config - ioctl interface to read the timestamping config
205662306a36Sopenharmony_ci * @pf: Board private structure
205762306a36Sopenharmony_ci * @ifr: ioctl data
205862306a36Sopenharmony_ci *
205962306a36Sopenharmony_ci * Copy the timestamping config to user buffer
206062306a36Sopenharmony_ci */
206162306a36Sopenharmony_ciint ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	struct hwtstamp_config *config;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
206662306a36Sopenharmony_ci		return -EIO;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	config = &pf->ptp.tstamp_config;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
207162306a36Sopenharmony_ci		-EFAULT : 0;
207262306a36Sopenharmony_ci}
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci/**
207562306a36Sopenharmony_ci * ice_ptp_set_timestamp_mode - Setup driver for requested timestamp mode
207662306a36Sopenharmony_ci * @pf: Board private structure
207762306a36Sopenharmony_ci * @config: hwtstamp settings requested or saved
207862306a36Sopenharmony_ci */
207962306a36Sopenharmony_cistatic int
208062306a36Sopenharmony_ciice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	switch (config->tx_type) {
208362306a36Sopenharmony_ci	case HWTSTAMP_TX_OFF:
208462306a36Sopenharmony_ci		ice_set_tx_tstamp(pf, false);
208562306a36Sopenharmony_ci		break;
208662306a36Sopenharmony_ci	case HWTSTAMP_TX_ON:
208762306a36Sopenharmony_ci		ice_set_tx_tstamp(pf, true);
208862306a36Sopenharmony_ci		break;
208962306a36Sopenharmony_ci	default:
209062306a36Sopenharmony_ci		return -ERANGE;
209162306a36Sopenharmony_ci	}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	switch (config->rx_filter) {
209462306a36Sopenharmony_ci	case HWTSTAMP_FILTER_NONE:
209562306a36Sopenharmony_ci		ice_set_rx_tstamp(pf, false);
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
209862306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
209962306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
210062306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_EVENT:
210162306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
210262306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
210362306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_SYNC:
210462306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
210562306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
210662306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
210762306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
210862306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
210962306a36Sopenharmony_ci	case HWTSTAMP_FILTER_NTP_ALL:
211062306a36Sopenharmony_ci	case HWTSTAMP_FILTER_ALL:
211162306a36Sopenharmony_ci		ice_set_rx_tstamp(pf, true);
211262306a36Sopenharmony_ci		break;
211362306a36Sopenharmony_ci	default:
211462306a36Sopenharmony_ci		return -ERANGE;
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	return 0;
211862306a36Sopenharmony_ci}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci/**
212162306a36Sopenharmony_ci * ice_ptp_set_ts_config - ioctl interface to control the timestamping
212262306a36Sopenharmony_ci * @pf: Board private structure
212362306a36Sopenharmony_ci * @ifr: ioctl data
212462306a36Sopenharmony_ci *
212562306a36Sopenharmony_ci * Get the user config and store it
212662306a36Sopenharmony_ci */
212762306a36Sopenharmony_ciint ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr)
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	struct hwtstamp_config config;
213062306a36Sopenharmony_ci	int err;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
213362306a36Sopenharmony_ci		return -EAGAIN;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
213662306a36Sopenharmony_ci		return -EFAULT;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	err = ice_ptp_set_timestamp_mode(pf, &config);
213962306a36Sopenharmony_ci	if (err)
214062306a36Sopenharmony_ci		return err;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	/* Return the actual configuration set */
214362306a36Sopenharmony_ci	config = pf->ptp.tstamp_config;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
214662306a36Sopenharmony_ci		-EFAULT : 0;
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci/**
215062306a36Sopenharmony_ci * ice_ptp_rx_hwtstamp - Check for an Rx timestamp
215162306a36Sopenharmony_ci * @rx_ring: Ring to get the VSI info
215262306a36Sopenharmony_ci * @rx_desc: Receive descriptor
215362306a36Sopenharmony_ci * @skb: Particular skb to send timestamp with
215462306a36Sopenharmony_ci *
215562306a36Sopenharmony_ci * The driver receives a notification in the receive descriptor with timestamp.
215662306a36Sopenharmony_ci * The timestamp is in ns, so we must convert the result first.
215762306a36Sopenharmony_ci */
215862306a36Sopenharmony_civoid
215962306a36Sopenharmony_ciice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring,
216062306a36Sopenharmony_ci		    union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb)
216162306a36Sopenharmony_ci{
216262306a36Sopenharmony_ci	struct skb_shared_hwtstamps *hwtstamps;
216362306a36Sopenharmony_ci	u64 ts_ns, cached_time;
216462306a36Sopenharmony_ci	u32 ts_high;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (!(rx_desc->wb.time_stamp_low & ICE_PTP_TS_VALID))
216762306a36Sopenharmony_ci		return;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	cached_time = READ_ONCE(rx_ring->cached_phctime);
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/* Do not report a timestamp if we don't have a cached PHC time */
217262306a36Sopenharmony_ci	if (!cached_time)
217362306a36Sopenharmony_ci		return;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	/* Use ice_ptp_extend_32b_ts directly, using the ring-specific cached
217662306a36Sopenharmony_ci	 * PHC value, rather than accessing the PF. This also allows us to
217762306a36Sopenharmony_ci	 * simply pass the upper 32bits of nanoseconds directly. Calling
217862306a36Sopenharmony_ci	 * ice_ptp_extend_40b_ts is unnecessary as it would just discard these
217962306a36Sopenharmony_ci	 * bits itself.
218062306a36Sopenharmony_ci	 */
218162306a36Sopenharmony_ci	ts_high = le32_to_cpu(rx_desc->wb.flex_ts.ts_high);
218262306a36Sopenharmony_ci	ts_ns = ice_ptp_extend_32b_ts(cached_time, ts_high);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	hwtstamps = skb_hwtstamps(skb);
218562306a36Sopenharmony_ci	memset(hwtstamps, 0, sizeof(*hwtstamps));
218662306a36Sopenharmony_ci	hwtstamps->hwtstamp = ns_to_ktime(ts_ns);
218762306a36Sopenharmony_ci}
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci/**
219062306a36Sopenharmony_ci * ice_ptp_disable_sma_pins_e810t - Disable E810-T SMA pins
219162306a36Sopenharmony_ci * @pf: pointer to the PF structure
219262306a36Sopenharmony_ci * @info: PTP clock info structure
219362306a36Sopenharmony_ci *
219462306a36Sopenharmony_ci * Disable the OS access to the SMA pins. Called to clear out the OS
219562306a36Sopenharmony_ci * indications of pin support when we fail to setup the E810-T SMA control
219662306a36Sopenharmony_ci * register.
219762306a36Sopenharmony_ci */
219862306a36Sopenharmony_cistatic void
219962306a36Sopenharmony_ciice_ptp_disable_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info)
220062306a36Sopenharmony_ci{
220162306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	dev_warn(dev, "Failed to configure E810-T SMA pin control\n");
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	info->enable = NULL;
220662306a36Sopenharmony_ci	info->verify = NULL;
220762306a36Sopenharmony_ci	info->n_pins = 0;
220862306a36Sopenharmony_ci	info->n_ext_ts = 0;
220962306a36Sopenharmony_ci	info->n_per_out = 0;
221062306a36Sopenharmony_ci}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci/**
221362306a36Sopenharmony_ci * ice_ptp_setup_sma_pins_e810t - Setup the SMA pins
221462306a36Sopenharmony_ci * @pf: pointer to the PF structure
221562306a36Sopenharmony_ci * @info: PTP clock info structure
221662306a36Sopenharmony_ci *
221762306a36Sopenharmony_ci * Finish setting up the SMA pins by allocating pin_config, and setting it up
221862306a36Sopenharmony_ci * according to the current status of the SMA. On failure, disable all of the
221962306a36Sopenharmony_ci * extended SMA pin support.
222062306a36Sopenharmony_ci */
222162306a36Sopenharmony_cistatic void
222262306a36Sopenharmony_ciice_ptp_setup_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
222562306a36Sopenharmony_ci	int err;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	/* Allocate memory for kernel pins interface */
222862306a36Sopenharmony_ci	info->pin_config = devm_kcalloc(dev, info->n_pins,
222962306a36Sopenharmony_ci					sizeof(*info->pin_config), GFP_KERNEL);
223062306a36Sopenharmony_ci	if (!info->pin_config) {
223162306a36Sopenharmony_ci		ice_ptp_disable_sma_pins_e810t(pf, info);
223262306a36Sopenharmony_ci		return;
223362306a36Sopenharmony_ci	}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	/* Read current SMA status */
223662306a36Sopenharmony_ci	err = ice_get_sma_config_e810t(&pf->hw, info->pin_config);
223762306a36Sopenharmony_ci	if (err)
223862306a36Sopenharmony_ci		ice_ptp_disable_sma_pins_e810t(pf, info);
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci/**
224262306a36Sopenharmony_ci * ice_ptp_setup_pins_e810 - Setup PTP pins in sysfs
224362306a36Sopenharmony_ci * @pf: pointer to the PF instance
224462306a36Sopenharmony_ci * @info: PTP clock capabilities
224562306a36Sopenharmony_ci */
224662306a36Sopenharmony_cistatic void
224762306a36Sopenharmony_ciice_ptp_setup_pins_e810(struct ice_pf *pf, struct ptp_clock_info *info)
224862306a36Sopenharmony_ci{
224962306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) {
225062306a36Sopenharmony_ci		info->n_ext_ts = N_EXT_TS_E810;
225162306a36Sopenharmony_ci		info->n_per_out = N_PER_OUT_E810T;
225262306a36Sopenharmony_ci		info->n_pins = NUM_PTP_PINS_E810T;
225362306a36Sopenharmony_ci		info->verify = ice_verify_pin_e810t;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		/* Complete setup of the SMA pins */
225662306a36Sopenharmony_ci		ice_ptp_setup_sma_pins_e810t(pf, info);
225762306a36Sopenharmony_ci	} else if (ice_is_e810t(&pf->hw)) {
225862306a36Sopenharmony_ci		info->n_ext_ts = N_EXT_TS_NO_SMA_E810T;
225962306a36Sopenharmony_ci		info->n_per_out = N_PER_OUT_NO_SMA_E810T;
226062306a36Sopenharmony_ci	} else {
226162306a36Sopenharmony_ci		info->n_per_out = N_PER_OUT_E810;
226262306a36Sopenharmony_ci		info->n_ext_ts = N_EXT_TS_E810;
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci}
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci/**
226762306a36Sopenharmony_ci * ice_ptp_setup_pins_e823 - Setup PTP pins in sysfs
226862306a36Sopenharmony_ci * @pf: pointer to the PF instance
226962306a36Sopenharmony_ci * @info: PTP clock capabilities
227062306a36Sopenharmony_ci */
227162306a36Sopenharmony_cistatic void
227262306a36Sopenharmony_ciice_ptp_setup_pins_e823(struct ice_pf *pf, struct ptp_clock_info *info)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	info->pps = 1;
227562306a36Sopenharmony_ci	info->n_per_out = 0;
227662306a36Sopenharmony_ci	info->n_ext_ts = 1;
227762306a36Sopenharmony_ci}
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci/**
228062306a36Sopenharmony_ci * ice_ptp_set_funcs_e822 - Set specialized functions for E822 support
228162306a36Sopenharmony_ci * @pf: Board private structure
228262306a36Sopenharmony_ci * @info: PTP info to fill
228362306a36Sopenharmony_ci *
228462306a36Sopenharmony_ci * Assign functions to the PTP capabiltiies structure for E822 devices.
228562306a36Sopenharmony_ci * Functions which operate across all device families should be set directly
228662306a36Sopenharmony_ci * in ice_ptp_set_caps. Only add functions here which are distinct for E822
228762306a36Sopenharmony_ci * devices.
228862306a36Sopenharmony_ci */
228962306a36Sopenharmony_cistatic void
229062306a36Sopenharmony_ciice_ptp_set_funcs_e822(struct ice_pf *pf, struct ptp_clock_info *info)
229162306a36Sopenharmony_ci{
229262306a36Sopenharmony_ci#ifdef CONFIG_ICE_HWTS
229362306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_ART) &&
229462306a36Sopenharmony_ci	    boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ))
229562306a36Sopenharmony_ci		info->getcrosststamp = ice_ptp_getcrosststamp_e822;
229662306a36Sopenharmony_ci#endif /* CONFIG_ICE_HWTS */
229762306a36Sopenharmony_ci}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci/**
230062306a36Sopenharmony_ci * ice_ptp_set_funcs_e810 - Set specialized functions for E810 support
230162306a36Sopenharmony_ci * @pf: Board private structure
230262306a36Sopenharmony_ci * @info: PTP info to fill
230362306a36Sopenharmony_ci *
230462306a36Sopenharmony_ci * Assign functions to the PTP capabiltiies structure for E810 devices.
230562306a36Sopenharmony_ci * Functions which operate across all device families should be set directly
230662306a36Sopenharmony_ci * in ice_ptp_set_caps. Only add functions here which are distinct for e810
230762306a36Sopenharmony_ci * devices.
230862306a36Sopenharmony_ci */
230962306a36Sopenharmony_cistatic void
231062306a36Sopenharmony_ciice_ptp_set_funcs_e810(struct ice_pf *pf, struct ptp_clock_info *info)
231162306a36Sopenharmony_ci{
231262306a36Sopenharmony_ci	info->enable = ice_ptp_gpio_enable_e810;
231362306a36Sopenharmony_ci	ice_ptp_setup_pins_e810(pf, info);
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/**
231762306a36Sopenharmony_ci * ice_ptp_set_funcs_e823 - Set specialized functions for E823 support
231862306a36Sopenharmony_ci * @pf: Board private structure
231962306a36Sopenharmony_ci * @info: PTP info to fill
232062306a36Sopenharmony_ci *
232162306a36Sopenharmony_ci * Assign functions to the PTP capabiltiies structure for E823 devices.
232262306a36Sopenharmony_ci * Functions which operate across all device families should be set directly
232362306a36Sopenharmony_ci * in ice_ptp_set_caps. Only add functions here which are distinct for e823
232462306a36Sopenharmony_ci * devices.
232562306a36Sopenharmony_ci */
232662306a36Sopenharmony_cistatic void
232762306a36Sopenharmony_ciice_ptp_set_funcs_e823(struct ice_pf *pf, struct ptp_clock_info *info)
232862306a36Sopenharmony_ci{
232962306a36Sopenharmony_ci	info->enable = ice_ptp_gpio_enable_e823;
233062306a36Sopenharmony_ci	ice_ptp_setup_pins_e823(pf, info);
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci/**
233462306a36Sopenharmony_ci * ice_ptp_set_caps - Set PTP capabilities
233562306a36Sopenharmony_ci * @pf: Board private structure
233662306a36Sopenharmony_ci */
233762306a36Sopenharmony_cistatic void ice_ptp_set_caps(struct ice_pf *pf)
233862306a36Sopenharmony_ci{
233962306a36Sopenharmony_ci	struct ptp_clock_info *info = &pf->ptp.info;
234062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	snprintf(info->name, sizeof(info->name) - 1, "%s-%s-clk",
234362306a36Sopenharmony_ci		 dev_driver_string(dev), dev_name(dev));
234462306a36Sopenharmony_ci	info->owner = THIS_MODULE;
234562306a36Sopenharmony_ci	info->max_adj = 100000000;
234662306a36Sopenharmony_ci	info->adjtime = ice_ptp_adjtime;
234762306a36Sopenharmony_ci	info->adjfine = ice_ptp_adjfine;
234862306a36Sopenharmony_ci	info->gettimex64 = ice_ptp_gettimex64;
234962306a36Sopenharmony_ci	info->settime64 = ice_ptp_settime64;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (ice_is_e810(&pf->hw))
235262306a36Sopenharmony_ci		ice_ptp_set_funcs_e810(pf, info);
235362306a36Sopenharmony_ci	else if (ice_is_e823(&pf->hw))
235462306a36Sopenharmony_ci		ice_ptp_set_funcs_e823(pf, info);
235562306a36Sopenharmony_ci	else
235662306a36Sopenharmony_ci		ice_ptp_set_funcs_e822(pf, info);
235762306a36Sopenharmony_ci}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci/**
236062306a36Sopenharmony_ci * ice_ptp_create_clock - Create PTP clock device for userspace
236162306a36Sopenharmony_ci * @pf: Board private structure
236262306a36Sopenharmony_ci *
236362306a36Sopenharmony_ci * This function creates a new PTP clock device. It only creates one if we
236462306a36Sopenharmony_ci * don't already have one. Will return error if it can't create one, but success
236562306a36Sopenharmony_ci * if we already have a device. Should be used by ice_ptp_init to create clock
236662306a36Sopenharmony_ci * initially, and prevent global resets from creating new clock devices.
236762306a36Sopenharmony_ci */
236862306a36Sopenharmony_cistatic long ice_ptp_create_clock(struct ice_pf *pf)
236962306a36Sopenharmony_ci{
237062306a36Sopenharmony_ci	struct ptp_clock_info *info;
237162306a36Sopenharmony_ci	struct ptp_clock *clock;
237262306a36Sopenharmony_ci	struct device *dev;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	/* No need to create a clock device if we already have one */
237562306a36Sopenharmony_ci	if (pf->ptp.clock)
237662306a36Sopenharmony_ci		return 0;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	ice_ptp_set_caps(pf);
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	info = &pf->ptp.info;
238162306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	/* Attempt to register the clock before enabling the hardware. */
238462306a36Sopenharmony_ci	clock = ptp_clock_register(info, dev);
238562306a36Sopenharmony_ci	if (IS_ERR(clock))
238662306a36Sopenharmony_ci		return PTR_ERR(clock);
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	pf->ptp.clock = clock;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	return 0;
239162306a36Sopenharmony_ci}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci/**
239462306a36Sopenharmony_ci * ice_ptp_request_ts - Request an available Tx timestamp index
239562306a36Sopenharmony_ci * @tx: the PTP Tx timestamp tracker to request from
239662306a36Sopenharmony_ci * @skb: the SKB to associate with this timestamp request
239762306a36Sopenharmony_ci */
239862306a36Sopenharmony_cis8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
239962306a36Sopenharmony_ci{
240062306a36Sopenharmony_ci	u8 idx;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	spin_lock(&tx->lock);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/* Check that this tracker is accepting new timestamp requests */
240562306a36Sopenharmony_ci	if (!ice_ptp_is_tx_tracker_up(tx)) {
240662306a36Sopenharmony_ci		spin_unlock(&tx->lock);
240762306a36Sopenharmony_ci		return -1;
240862306a36Sopenharmony_ci	}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	/* Find and set the first available index */
241162306a36Sopenharmony_ci	idx = find_first_zero_bit(tx->in_use, tx->len);
241262306a36Sopenharmony_ci	if (idx < tx->len) {
241362306a36Sopenharmony_ci		/* We got a valid index that no other thread could have set. Store
241462306a36Sopenharmony_ci		 * a reference to the skb and the start time to allow discarding old
241562306a36Sopenharmony_ci		 * requests.
241662306a36Sopenharmony_ci		 */
241762306a36Sopenharmony_ci		set_bit(idx, tx->in_use);
241862306a36Sopenharmony_ci		clear_bit(idx, tx->stale);
241962306a36Sopenharmony_ci		tx->tstamps[idx].start = jiffies;
242062306a36Sopenharmony_ci		tx->tstamps[idx].skb = skb_get(skb);
242162306a36Sopenharmony_ci		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
242262306a36Sopenharmony_ci		ice_trace(tx_tstamp_request, skb, idx);
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	spin_unlock(&tx->lock);
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	/* return the appropriate PHY timestamp register index, -1 if no
242862306a36Sopenharmony_ci	 * indexes were available.
242962306a36Sopenharmony_ci	 */
243062306a36Sopenharmony_ci	if (idx >= tx->len)
243162306a36Sopenharmony_ci		return -1;
243262306a36Sopenharmony_ci	else
243362306a36Sopenharmony_ci		return idx + tx->offset;
243462306a36Sopenharmony_ci}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci/**
243762306a36Sopenharmony_ci * ice_ptp_process_ts - Process the PTP Tx timestamps
243862306a36Sopenharmony_ci * @pf: Board private structure
243962306a36Sopenharmony_ci *
244062306a36Sopenharmony_ci * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding Tx
244162306a36Sopenharmony_ci * timestamps that need processing, and ICE_TX_TSTAMP_WORK_DONE otherwise.
244262306a36Sopenharmony_ci */
244362306a36Sopenharmony_cienum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	return ice_ptp_tx_tstamp(&pf->ptp.port.tx);
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistatic void ice_ptp_periodic_work(struct kthread_work *work)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work);
245162306a36Sopenharmony_ci	struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp);
245262306a36Sopenharmony_ci	int err;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
245562306a36Sopenharmony_ci		return;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	err = ice_ptp_update_cached_phctime(pf);
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	/* Run twice a second or reschedule if phc update failed */
246062306a36Sopenharmony_ci	kthread_queue_delayed_work(ptp->kworker, &ptp->work,
246162306a36Sopenharmony_ci				   msecs_to_jiffies(err ? 10 : 500));
246262306a36Sopenharmony_ci}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci/**
246562306a36Sopenharmony_ci * ice_ptp_reset - Initialize PTP hardware clock support after reset
246662306a36Sopenharmony_ci * @pf: Board private structure
246762306a36Sopenharmony_ci */
246862306a36Sopenharmony_civoid ice_ptp_reset(struct ice_pf *pf)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	struct ice_ptp *ptp = &pf->ptp;
247162306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
247262306a36Sopenharmony_ci	struct timespec64 ts;
247362306a36Sopenharmony_ci	int err, itr = 1;
247462306a36Sopenharmony_ci	u64 time_diff;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	if (test_bit(ICE_PFR_REQ, pf->state))
247762306a36Sopenharmony_ci		goto pfr;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	if (!hw->func_caps.ts_func_info.src_tmr_owned)
248062306a36Sopenharmony_ci		goto reset_ts;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	err = ice_ptp_init_phc(hw);
248362306a36Sopenharmony_ci	if (err)
248462306a36Sopenharmony_ci		goto err;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	/* Acquire the global hardware lock */
248762306a36Sopenharmony_ci	if (!ice_ptp_lock(hw)) {
248862306a36Sopenharmony_ci		err = -EBUSY;
248962306a36Sopenharmony_ci		goto err;
249062306a36Sopenharmony_ci	}
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	/* Write the increment time value to PHY and LAN */
249362306a36Sopenharmony_ci	err = ice_ptp_write_incval(hw, ice_base_incval(pf));
249462306a36Sopenharmony_ci	if (err) {
249562306a36Sopenharmony_ci		ice_ptp_unlock(hw);
249662306a36Sopenharmony_ci		goto err;
249762306a36Sopenharmony_ci	}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	/* Write the initial Time value to PHY and LAN using the cached PHC
250062306a36Sopenharmony_ci	 * time before the reset and time difference between stopping and
250162306a36Sopenharmony_ci	 * starting the clock.
250262306a36Sopenharmony_ci	 */
250362306a36Sopenharmony_ci	if (ptp->cached_phc_time) {
250462306a36Sopenharmony_ci		time_diff = ktime_get_real_ns() - ptp->reset_time;
250562306a36Sopenharmony_ci		ts = ns_to_timespec64(ptp->cached_phc_time + time_diff);
250662306a36Sopenharmony_ci	} else {
250762306a36Sopenharmony_ci		ts = ktime_to_timespec64(ktime_get_real());
250862306a36Sopenharmony_ci	}
250962306a36Sopenharmony_ci	err = ice_ptp_write_init(pf, &ts);
251062306a36Sopenharmony_ci	if (err) {
251162306a36Sopenharmony_ci		ice_ptp_unlock(hw);
251262306a36Sopenharmony_ci		goto err;
251362306a36Sopenharmony_ci	}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	/* Release the global hardware lock */
251662306a36Sopenharmony_ci	ice_ptp_unlock(hw);
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	if (!ice_is_e810(hw)) {
251962306a36Sopenharmony_ci		/* Enable quad interrupts */
252062306a36Sopenharmony_ci		err = ice_ptp_tx_ena_intr(pf, true, itr);
252162306a36Sopenharmony_ci		if (err)
252262306a36Sopenharmony_ci			goto err;
252362306a36Sopenharmony_ci	}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_cireset_ts:
252662306a36Sopenharmony_ci	/* Restart the PHY timestamping block */
252762306a36Sopenharmony_ci	ice_ptp_reset_phy_timestamping(pf);
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_cipfr:
253062306a36Sopenharmony_ci	/* Init Tx structures */
253162306a36Sopenharmony_ci	if (ice_is_e810(&pf->hw)) {
253262306a36Sopenharmony_ci		err = ice_ptp_init_tx_e810(pf, &ptp->port.tx);
253362306a36Sopenharmony_ci	} else {
253462306a36Sopenharmony_ci		kthread_init_delayed_work(&ptp->port.ov_work,
253562306a36Sopenharmony_ci					  ice_ptp_wait_for_offsets);
253662306a36Sopenharmony_ci		err = ice_ptp_init_tx_e822(pf, &ptp->port.tx,
253762306a36Sopenharmony_ci					   ptp->port.port_num);
253862306a36Sopenharmony_ci	}
253962306a36Sopenharmony_ci	if (err)
254062306a36Sopenharmony_ci		goto err;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	set_bit(ICE_FLAG_PTP, pf->flags);
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	/* Start periodic work going */
254562306a36Sopenharmony_ci	kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	dev_info(ice_pf_to_dev(pf), "PTP reset successful\n");
254862306a36Sopenharmony_ci	return;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_cierr:
255162306a36Sopenharmony_ci	dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err);
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci/**
255562306a36Sopenharmony_ci * ice_ptp_prepare_for_reset - Prepare PTP for reset
255662306a36Sopenharmony_ci * @pf: Board private structure
255762306a36Sopenharmony_ci */
255862306a36Sopenharmony_civoid ice_ptp_prepare_for_reset(struct ice_pf *pf)
255962306a36Sopenharmony_ci{
256062306a36Sopenharmony_ci	struct ice_ptp *ptp = &pf->ptp;
256162306a36Sopenharmony_ci	u8 src_tmr;
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	clear_bit(ICE_FLAG_PTP, pf->flags);
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	/* Disable timestamping for both Tx and Rx */
256662306a36Sopenharmony_ci	ice_ptp_cfg_timestamp(pf, false);
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&ptp->work);
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	if (test_bit(ICE_PFR_REQ, pf->state))
257162306a36Sopenharmony_ci		return;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	/* Disable periodic outputs */
257662306a36Sopenharmony_ci	ice_ptp_disable_all_clkout(pf);
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	src_tmr = ice_get_ptp_src_clock_index(&pf->hw);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	/* Disable source clock */
258162306a36Sopenharmony_ci	wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M);
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/* Acquire PHC and system timer to restore after reset */
258462306a36Sopenharmony_ci	ptp->reset_time = ktime_get_real_ns();
258562306a36Sopenharmony_ci}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci/**
258862306a36Sopenharmony_ci * ice_ptp_init_owner - Initialize PTP_1588_CLOCK device
258962306a36Sopenharmony_ci * @pf: Board private structure
259062306a36Sopenharmony_ci *
259162306a36Sopenharmony_ci * Setup and initialize a PTP clock device that represents the device hardware
259262306a36Sopenharmony_ci * clock. Save the clock index for other functions connected to the same
259362306a36Sopenharmony_ci * hardware resource.
259462306a36Sopenharmony_ci */
259562306a36Sopenharmony_cistatic int ice_ptp_init_owner(struct ice_pf *pf)
259662306a36Sopenharmony_ci{
259762306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
259862306a36Sopenharmony_ci	struct timespec64 ts;
259962306a36Sopenharmony_ci	int err, itr = 1;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	err = ice_ptp_init_phc(hw);
260262306a36Sopenharmony_ci	if (err) {
260362306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "Failed to initialize PHC, err %d\n",
260462306a36Sopenharmony_ci			err);
260562306a36Sopenharmony_ci		return err;
260662306a36Sopenharmony_ci	}
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	/* Acquire the global hardware lock */
260962306a36Sopenharmony_ci	if (!ice_ptp_lock(hw)) {
261062306a36Sopenharmony_ci		err = -EBUSY;
261162306a36Sopenharmony_ci		goto err_exit;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	/* Write the increment time value to PHY and LAN */
261562306a36Sopenharmony_ci	err = ice_ptp_write_incval(hw, ice_base_incval(pf));
261662306a36Sopenharmony_ci	if (err) {
261762306a36Sopenharmony_ci		ice_ptp_unlock(hw);
261862306a36Sopenharmony_ci		goto err_exit;
261962306a36Sopenharmony_ci	}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	ts = ktime_to_timespec64(ktime_get_real());
262262306a36Sopenharmony_ci	/* Write the initial Time value to PHY and LAN */
262362306a36Sopenharmony_ci	err = ice_ptp_write_init(pf, &ts);
262462306a36Sopenharmony_ci	if (err) {
262562306a36Sopenharmony_ci		ice_ptp_unlock(hw);
262662306a36Sopenharmony_ci		goto err_exit;
262762306a36Sopenharmony_ci	}
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	/* Release the global hardware lock */
263062306a36Sopenharmony_ci	ice_ptp_unlock(hw);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	if (!ice_is_e810(hw)) {
263362306a36Sopenharmony_ci		/* Enable quad interrupts */
263462306a36Sopenharmony_ci		err = ice_ptp_tx_ena_intr(pf, true, itr);
263562306a36Sopenharmony_ci		if (err)
263662306a36Sopenharmony_ci			goto err_exit;
263762306a36Sopenharmony_ci	}
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	/* Ensure we have a clock device */
264062306a36Sopenharmony_ci	err = ice_ptp_create_clock(pf);
264162306a36Sopenharmony_ci	if (err)
264262306a36Sopenharmony_ci		goto err_clk;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	/* Store the PTP clock index for other PFs */
264562306a36Sopenharmony_ci	ice_set_ptp_clock_index(pf);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	return 0;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_cierr_clk:
265062306a36Sopenharmony_ci	pf->ptp.clock = NULL;
265162306a36Sopenharmony_cierr_exit:
265262306a36Sopenharmony_ci	return err;
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci/**
265662306a36Sopenharmony_ci * ice_ptp_init_work - Initialize PTP work threads
265762306a36Sopenharmony_ci * @pf: Board private structure
265862306a36Sopenharmony_ci * @ptp: PF PTP structure
265962306a36Sopenharmony_ci */
266062306a36Sopenharmony_cistatic int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp)
266162306a36Sopenharmony_ci{
266262306a36Sopenharmony_ci	struct kthread_worker *kworker;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	/* Initialize work functions */
266562306a36Sopenharmony_ci	kthread_init_delayed_work(&ptp->work, ice_ptp_periodic_work);
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	/* Allocate a kworker for handling work required for the ports
266862306a36Sopenharmony_ci	 * connected to the PTP hardware clock.
266962306a36Sopenharmony_ci	 */
267062306a36Sopenharmony_ci	kworker = kthread_create_worker(0, "ice-ptp-%s",
267162306a36Sopenharmony_ci					dev_name(ice_pf_to_dev(pf)));
267262306a36Sopenharmony_ci	if (IS_ERR(kworker))
267362306a36Sopenharmony_ci		return PTR_ERR(kworker);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	ptp->kworker = kworker;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	/* Start periodic work going */
267862306a36Sopenharmony_ci	kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	return 0;
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci/**
268462306a36Sopenharmony_ci * ice_ptp_init_port - Initialize PTP port structure
268562306a36Sopenharmony_ci * @pf: Board private structure
268662306a36Sopenharmony_ci * @ptp_port: PTP port structure
268762306a36Sopenharmony_ci */
268862306a36Sopenharmony_cistatic int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port)
268962306a36Sopenharmony_ci{
269062306a36Sopenharmony_ci	mutex_init(&ptp_port->ps_lock);
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	if (ice_is_e810(&pf->hw))
269362306a36Sopenharmony_ci		return ice_ptp_init_tx_e810(pf, &ptp_port->tx);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	kthread_init_delayed_work(&ptp_port->ov_work,
269662306a36Sopenharmony_ci				  ice_ptp_wait_for_offsets);
269762306a36Sopenharmony_ci	return ice_ptp_init_tx_e822(pf, &ptp_port->tx, ptp_port->port_num);
269862306a36Sopenharmony_ci}
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci/**
270162306a36Sopenharmony_ci * ice_ptp_init - Initialize PTP hardware clock support
270262306a36Sopenharmony_ci * @pf: Board private structure
270362306a36Sopenharmony_ci *
270462306a36Sopenharmony_ci * Set up the device for interacting with the PTP hardware clock for all
270562306a36Sopenharmony_ci * functions, both the function that owns the clock hardware, and the
270662306a36Sopenharmony_ci * functions connected to the clock hardware.
270762306a36Sopenharmony_ci *
270862306a36Sopenharmony_ci * The clock owner will allocate and register a ptp_clock with the
270962306a36Sopenharmony_ci * PTP_1588_CLOCK infrastructure. All functions allocate a kthread and work
271062306a36Sopenharmony_ci * items used for asynchronous work such as Tx timestamps and periodic work.
271162306a36Sopenharmony_ci */
271262306a36Sopenharmony_civoid ice_ptp_init(struct ice_pf *pf)
271362306a36Sopenharmony_ci{
271462306a36Sopenharmony_ci	struct ice_ptp *ptp = &pf->ptp;
271562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
271662306a36Sopenharmony_ci	int err;
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	/* If this function owns the clock hardware, it must allocate and
271962306a36Sopenharmony_ci	 * configure the PTP clock device to represent it.
272062306a36Sopenharmony_ci	 */
272162306a36Sopenharmony_ci	if (hw->func_caps.ts_func_info.src_tmr_owned) {
272262306a36Sopenharmony_ci		err = ice_ptp_init_owner(pf);
272362306a36Sopenharmony_ci		if (err)
272462306a36Sopenharmony_ci			goto err;
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	ptp->port.port_num = hw->pf_id;
272862306a36Sopenharmony_ci	err = ice_ptp_init_port(pf, &ptp->port);
272962306a36Sopenharmony_ci	if (err)
273062306a36Sopenharmony_ci		goto err;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	/* Start the PHY timestamping block */
273362306a36Sopenharmony_ci	ice_ptp_reset_phy_timestamping(pf);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	set_bit(ICE_FLAG_PTP, pf->flags);
273662306a36Sopenharmony_ci	err = ice_ptp_init_work(pf, ptp);
273762306a36Sopenharmony_ci	if (err)
273862306a36Sopenharmony_ci		goto err;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	dev_info(ice_pf_to_dev(pf), "PTP init successful\n");
274162306a36Sopenharmony_ci	return;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_cierr:
274462306a36Sopenharmony_ci	/* If we registered a PTP clock, release it */
274562306a36Sopenharmony_ci	if (pf->ptp.clock) {
274662306a36Sopenharmony_ci		ptp_clock_unregister(ptp->clock);
274762306a36Sopenharmony_ci		pf->ptp.clock = NULL;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci	clear_bit(ICE_FLAG_PTP, pf->flags);
275062306a36Sopenharmony_ci	dev_err(ice_pf_to_dev(pf), "PTP failed %d\n", err);
275162306a36Sopenharmony_ci}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci/**
275462306a36Sopenharmony_ci * ice_ptp_release - Disable the driver/HW support and unregister the clock
275562306a36Sopenharmony_ci * @pf: Board private structure
275662306a36Sopenharmony_ci *
275762306a36Sopenharmony_ci * This function handles the cleanup work required from the initialization by
275862306a36Sopenharmony_ci * clearing out the important information and unregistering the clock
275962306a36Sopenharmony_ci */
276062306a36Sopenharmony_civoid ice_ptp_release(struct ice_pf *pf)
276162306a36Sopenharmony_ci{
276262306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
276362306a36Sopenharmony_ci		return;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	/* Disable timestamping for both Tx and Rx */
276662306a36Sopenharmony_ci	ice_ptp_cfg_timestamp(pf, false);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx);
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	clear_bit(ICE_FLAG_PTP, pf->flags);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&pf->ptp.work);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	ice_ptp_port_phy_stop(&pf->ptp.port);
277562306a36Sopenharmony_ci	mutex_destroy(&pf->ptp.port.ps_lock);
277662306a36Sopenharmony_ci	if (pf->ptp.kworker) {
277762306a36Sopenharmony_ci		kthread_destroy_worker(pf->ptp.kworker);
277862306a36Sopenharmony_ci		pf->ptp.kworker = NULL;
277962306a36Sopenharmony_ci	}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	if (!pf->ptp.clock)
278262306a36Sopenharmony_ci		return;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	/* Disable periodic outputs */
278562306a36Sopenharmony_ci	ice_ptp_disable_all_clkout(pf);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	ice_clear_ptp_clock_index(pf);
278862306a36Sopenharmony_ci	ptp_clock_unregister(pf->ptp.clock);
278962306a36Sopenharmony_ci	pf->ptp.clock = NULL;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	dev_info(ice_pf_to_dev(pf), "Removed PTP clock\n");
279262306a36Sopenharmony_ci}
2793