Commit e2193f9f authored by Karol Kolacinski's avatar Karol Kolacinski Committed by Tony Nguyen
Browse files

ice: enable timesync operation on 2xNAC E825 devices



According to the E825C specification, SBQ address for ports on a single
complex is device 2 for PHY 0 and device 13 for PHY1.
For accessing ports on a dual complex E825C (so called 2xNAC mode),
the driver should use destination device 2 (referred as phy_0) for
the current complex PHY and device 13 (referred as phy_0_peer) for
peer complex PHY.

Differentiate SBQ destination device by checking if current PF port
number is on the same PHY as target port number.

Adjust 'ice_get_lane_number' function to provide unique port number for
ports from PHY1 in 'dual' mode config (by adding fixed offset for PHY1
ports). Cache this value in ice_hw struct.

Introduce ice_get_primary_hw wrapper to get access to timesync register
not available from second NAC.

Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: default avatarKarol Kolacinski <karol.kolacinski@intel.com>
Co-developed-by: default avatarGrzegorz Nitka <grzegorz.nitka@intel.com>
Signed-off-by: default avatarGrzegorz Nitka <grzegorz.nitka@intel.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 1fd9c91f
Loading
Loading
Loading
Loading
+58 −2
Original line number Diff line number Diff line
@@ -193,8 +193,6 @@

#define ice_pf_to_dev(pf) (&((pf)->pdev->dev))

#define ice_pf_src_tmr_owned(pf) ((pf)->hw.func_caps.ts_func_info.src_tmr_owned)

enum ice_feature {
	ICE_F_DSCP,
	ICE_F_PHY_RCLK,
@@ -1046,4 +1044,62 @@ static inline void ice_clear_rdma_cap(struct ice_pf *pf)
}

extern const struct xdp_metadata_ops ice_xdp_md_ops;

/**
 * ice_is_dual - Check if given config is multi-NAC
 * @hw: pointer to HW structure
 *
 * Return: true if the device is running in mutli-NAC (Network
 * Acceleration Complex) configuration variant, false otherwise
 * (always false for non-E825 devices).
 */
static inline bool ice_is_dual(struct ice_hw *hw)
{
	return hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
	       (hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_DUAL_M);
}

/**
 * ice_is_primary - Check if given device belongs to the primary complex
 * @hw: pointer to HW structure
 *
 * Check if given PF/HW is running on primary complex in multi-NAC
 * configuration.
 *
 * Return: true if the device is dual, false otherwise (always true
 * for non-E825 devices).
 */
static inline bool ice_is_primary(struct ice_hw *hw)
{
	return hw->mac_type != ICE_MAC_GENERIC_3K_E825 ||
	       !ice_is_dual(hw) ||
	       (hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_PRIMARY_M);
}

/**
 * ice_pf_src_tmr_owned - Check if a primary timer is owned by PF
 * @pf: pointer to PF structure
 *
 * Return: true if PF owns primary timer, false otherwise.
 */
static inline bool ice_pf_src_tmr_owned(struct ice_pf *pf)
{
	return pf->hw.func_caps.ts_func_info.src_tmr_owned &&
	       ice_is_primary(&pf->hw);
}

/**
 * ice_get_primary_hw - Get pointer to primary ice_hw structure
 * @pf: pointer to PF structure
 *
 * Return: A pointer to ice_hw structure with access to timesync
 * register space.
 */
static inline struct ice_hw *ice_get_primary_hw(struct ice_pf *pf)
{
	if (!pf->adapter->ctrl_pf)
		return &pf->hw;
	else
		return &pf->adapter->ctrl_pf->hw;
}
#endif /* _ICE_H_ */
+5 −1
Original line number Diff line number Diff line
@@ -1135,6 +1135,8 @@ int ice_init_hw(struct ice_hw *hw)
		}
	}

	hw->lane_num = ice_get_phy_lane_number(hw);

	return 0;
err_unroll_fltr_mgmt_struct:
	ice_cleanup_fltr_mgmt_struct(hw);
@@ -4082,10 +4084,12 @@ int ice_get_phy_lane_number(struct ice_hw *hw)
			continue;

		if (hw->pf_id == lport) {
			if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
			    ice_is_dual(hw) && !ice_is_primary(hw))
				lane += ICE_PORTS_PER_QUAD;
			kfree(options);
			return lane;
		}

		lport++;
	}

+37 −12
Original line number Diff line number Diff line
@@ -305,6 +305,9 @@ u64 ice_ptp_read_src_clk_reg(struct ice_pf *pf,
	u32 hi, lo, lo2;
	u8 tmr_idx;

	if (!ice_is_primary(hw))
		hw = ice_get_primary_hw(pf);

	tmr_idx = ice_get_ptp_src_clock_index(hw);
	guard(spinlock)(&pf->adapter->ptp_gltsyn_time_lock);
	/* Read the system timestamp pre PHC read */
@@ -2985,6 +2988,32 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
				   msecs_to_jiffies(err ? 10 : 500));
}

/**
 * ice_ptp_prepare_rebuild_sec - Prepare second NAC for PTP reset or rebuild
 * @pf: Board private structure
 * @rebuild: rebuild if true, prepare if false
 * @reset_type: the reset type being performed
 */
static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
					enum ice_reset_req reset_type)
{
	struct list_head *entry;

	list_for_each(entry, &pf->adapter->ports.ports) {
		struct ice_ptp_port *port = list_entry(entry,
						       struct ice_ptp_port,
						       list_node);
		struct ice_pf *peer_pf = ptp_port_to_pf(port);

		if (!ice_is_primary(&peer_pf->hw)) {
			if (rebuild)
				ice_ptp_rebuild(peer_pf, reset_type);
			else
				ice_ptp_prepare_for_reset(peer_pf, reset_type);
		}
	}
}

/**
 * ice_ptp_prepare_for_reset - Prepare PTP for reset
 * @pf: Board private structure
@@ -2993,6 +3022,7 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
{
	struct ice_ptp *ptp = &pf->ptp;
	struct ice_hw *hw = &pf->hw;
	u8 src_tmr;

	if (ptp->state != ICE_PTP_READY)
@@ -3008,6 +3038,9 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
	if (reset_type == ICE_RESET_PFR)
		return;

	if (ice_pf_src_tmr_owned(pf) && hw->mac_type == ICE_MAC_GENERIC_3K_E825)
		ice_ptp_prepare_rebuild_sec(pf, false, reset_type);

	ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx);

	/* Disable periodic outputs */
@@ -3129,13 +3162,6 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
	dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err);
}

static bool ice_is_primary(struct ice_hw *hw)
{
	return hw->mac_type == ICE_MAC_GENERIC_3K_E825 && ice_is_dual(hw) ?
		       !!(hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_PRIMARY_M) :
		       true;
}

static int ice_ptp_setup_adapter(struct ice_pf *pf)
{
	if (!ice_pf_src_tmr_owned(pf) || !ice_is_primary(&pf->hw))
@@ -3355,17 +3381,16 @@ void ice_ptp_init(struct ice_pf *pf)
{
	struct ice_ptp *ptp = &pf->ptp;
	struct ice_hw *hw = &pf->hw;
	int lane_num, err;
	int err;

	ptp->state = ICE_PTP_INITIALIZING;

	lane_num = ice_get_phy_lane_number(hw);
	if (lane_num < 0) {
		err = lane_num;
	if (hw->lane_num < 0) {
		err = hw->lane_num;
		goto err_exit;
	}
	ptp->port.port_num = hw->lane_num;

	ptp->port.port_num = (u8)lane_num;
	ice_ptp_init_hw(hw);

	ice_ptp_init_tx_interrupt_mode(pf);
+33 −6
Original line number Diff line number Diff line
@@ -874,8 +874,12 @@ static u32 ice_ptp_tmr_cmd_to_port_reg(struct ice_hw *hw,
 */
void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
	u32 cmd_val = ice_ptp_tmr_cmd_to_src_reg(hw, cmd);

	if (!ice_is_primary(hw))
		hw = ice_get_primary_hw(pf);

	wr32(hw, GLTSYN_CMD, cmd_val);
}

@@ -891,6 +895,9 @@ static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);

	if (!ice_is_primary(hw))
		hw = ice_get_primary_hw(pf);

	guard(spinlock)(&pf->adapter->ptp_gltsyn_time_lock);
	wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
	ice_flush(hw);
@@ -922,10 +929,18 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)
static enum ice_sbq_dev_id ice_ptp_get_dest_dev_e825(struct ice_hw *hw,
						     u8 port)
{
	/* On a single complex E825, PHY 0 is always destination device phy_0
	u8 curr_phy, tgt_phy;

	tgt_phy = port >= hw->ptp.ports_per_phy;
	curr_phy = hw->lane_num >= hw->ptp.ports_per_phy;
	/* In the driver, lanes 4..7 are in fact 0..3 on a second PHY.
	 * On a single complex E825C, PHY 0 is always destination device phy_0
	 * and PHY 1 is phy_0_peer.
	 * On dual complex E825C, device phy_0 points to PHY on a current
	 * complex and phy_0_peer to PHY on a different complex.
	 */
	if (port >= hw->ptp.ports_per_phy)
	if ((!ice_is_dual(hw) && tgt_phy == 1) ||
	    (ice_is_dual(hw) && tgt_phy != curr_phy))
		return ice_sbq_dev_phy_0_peer;
	else
		return ice_sbq_dev_phy_0;
@@ -2417,6 +2432,7 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)
static int ice_read_phy_and_phc_time_eth56g(struct ice_hw *hw, u8 port,
					    u64 *phy_time, u64 *phc_time)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
	u64 tx_time, rx_time;
	u32 zo, lo;
	u8 tmr_idx;
@@ -2436,8 +2452,13 @@ static int ice_read_phy_and_phc_time_eth56g(struct ice_hw *hw, u8 port,
	ice_ptp_exec_tmr_cmd(hw);

	/* Read the captured PHC time from the shadow time registers */
	if (ice_is_primary(hw)) {
		zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
		lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
	} else {
		zo = rd32(ice_get_primary_hw(pf), GLTSYN_SHTIME_0(tmr_idx));
		lo = rd32(ice_get_primary_hw(pf), GLTSYN_SHTIME_L(tmr_idx));
	}
	*phc_time = (u64)lo << 32 | zo;

	/* Read the captured PHY time from the PHY shadow registers */
@@ -2574,6 +2595,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset)
 */
int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
	u32 lo, hi;
	u64 incval;
	u8 tmr_idx;
@@ -2599,8 +2621,13 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
	if (err)
		return err;

	if (ice_is_primary(hw)) {
		lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
		hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
	} else {
		lo = rd32(ice_get_primary_hw(pf), GLTSYN_INCVAL_L(tmr_idx));
		hi = rd32(ice_get_primary_hw(pf), GLTSYN_INCVAL_H(tmr_idx));
	}
	incval = (u64)hi << 32 | lo;

	err = ice_write_40b_ptp_reg_eth56g(hw, port, PHY_REG_TIMETUS_L, incval);
+0 −5
Original line number Diff line number Diff line
@@ -444,11 +444,6 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)
	}
}

static inline bool ice_is_dual(struct ice_hw *hw)
{
	return !!(hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_DUAL_M);
}

#define PFTSYN_SEM_BYTES	4

#define ICE_PTP_CLOCK_INDEX_0	0x00
Loading