From patchwork Mon Aug 15 07:12:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qi Zhang X-Patchwork-Id: 114972 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8413EA00C3; Mon, 15 Aug 2022 01:04:50 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2DED7427F7; Mon, 15 Aug 2022 01:03:38 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by mails.dpdk.org (Postfix) with ESMTP id 3281342BB1 for ; Mon, 15 Aug 2022 01:03:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660518216; x=1692054216; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XtmCKa6K2ZXGMhfnjtZyjDl3qJBKvbPWM3WT2qUJLV0=; b=GmxKHyO5uVcQ7qeIwxPscLpeaQ3IQFx/RZfYv59I3DrZ19vj+Od5OoHk a9geoNAEAgfG+fF96uZVXmxsslckcH0VLl50qRcfLKZbzSck8rEDYs+YS kO05Q0rDb20d1UHwJ+nx3jimDFLSBceSdB/9Wc/GOYVW9QzHPBw/U0pvZ 95szJgU8nQp/4apsp9aWoJZpnRBV02faS6ZqXgGXrw/cauQCRI8tqv6d7 Fgfdqq/0f0+7EoKcChSnAHEMJ77cDzyCO+c5By+JK4OXQB1QTM1PqXINx e6oMyLsW7YgweTo7TUjNSWkzLDpe9d9ksyhNdzJ1vlZ8a3EPd9L8MffHp Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10439"; a="289427570" X-IronPort-AV: E=Sophos;i="5.93,237,1654585200"; d="scan'208";a="289427570" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Aug 2022 16:03:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.93,237,1654585200"; d="scan'208";a="934296613" Received: from dpdk-qzhan15-test02.sh.intel.com ([10.67.115.4]) by fmsmga005.fm.intel.com with ESMTP; 14 Aug 2022 16:03:34 -0700 From: Qi Zhang To: qiming.yang@intel.com Cc: dev@dpdk.org, Qi Zhang , Sergey Temerkhanov Subject: [PATCH 15/70] net/ice/base: implement 56G PHY access functions Date: Mon, 15 Aug 2022 03:12:11 -0400 Message-Id: <20220815071306.2910599-16-qi.z.zhang@intel.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220815071306.2910599-1-qi.z.zhang@intel.com> References: <20220815071306.2910599-1-qi.z.zhang@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Implement 56G PHY register and memory read/write functions to facilitate PTP support Signed-off-by: Sergey Temerkhanov Signed-off-by: Qi Zhang --- drivers/net/ice/base/ice_ptp_hw.c | 1094 +++++++++++++++++++++++++++-- drivers/net/ice/base/ice_ptp_hw.h | 44 +- drivers/net/ice/base/ice_type.h | 11 + 3 files changed, 1090 insertions(+), 59 deletions(-) diff --git a/drivers/net/ice/base/ice_ptp_hw.c b/drivers/net/ice/base/ice_ptp_hw.c index 22d0774dd7..1c5fd799f6 100644 --- a/drivers/net/ice/base/ice_ptp_hw.c +++ b/drivers/net/ice/base/ice_ptp_hw.c @@ -395,7 +395,976 @@ static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw) ice_flush(hw); } -/* E822 family functions +/** + * ice_ptp_clean_cmd - Clean the timer command register + * @hw: pointer to HW struct + * + * Zero out the GLTSYN_CMD to avoid any residual command execution. + */ +static void ice_ptp_clean_cmd(struct ice_hw *hw) +{ + wr32(hw, GLTSYN_CMD, 0); + ice_flush(hw); +} + +/* 56G PHY access functions */ +static const u32 eth56g_port_base[ICE_NUM_PHY_PORTS] = { + ICE_PHY0_BASE, + ICE_PHY1_BASE, + ICE_PHY2_BASE, + ICE_PHY3_BASE, + ICE_PHY4_BASE, +}; + +/** + * ice_write_phy_eth56g_raw_lp - Write a PHY port register with lock parameter + * @hw: pointer to the HW struct + * @reg_addr: PHY register address + * @val: Value to write + * @lock_sbq: true to lock the sideband queue + */ +static enum ice_status +ice_write_phy_eth56g_raw_lp(struct ice_hw *hw, u32 reg_addr, u32 val, + bool lock_sbq) +{ + struct ice_sbq_msg_input phy_msg; + enum ice_status status; + + phy_msg.opcode = ice_sbq_msg_wr; + + phy_msg.msg_addr_low = ICE_LO_WORD(reg_addr); + phy_msg.msg_addr_high = ICE_HI_WORD(reg_addr); + + phy_msg.data = val; + phy_msg.dest_dev = phy_56g; + + status = ice_sbq_rw_reg_lp(hw, &phy_msg, lock_sbq); + + if (status) + ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n", + status); + + return status; +} + +/** + * ice_read_phy_eth56g_raw_lp - Read a PHY port register with lock parameter + * @hw: pointer to the HW struct + * @reg_addr: PHY port register address + * @val: Pointer to the value to read (out param) + * @lock_sbq: true to lock the sideband queue + */ +static enum ice_status +ice_read_phy_eth56g_raw_lp(struct ice_hw *hw, u32 reg_addr, u32 *val, + bool lock_sbq) +{ + struct ice_sbq_msg_input phy_msg; + enum ice_status status; + + phy_msg.opcode = ice_sbq_msg_rd; + + phy_msg.msg_addr_low = ICE_LO_WORD(reg_addr); + phy_msg.msg_addr_high = ICE_HI_WORD(reg_addr); + + phy_msg.dest_dev = phy_56g; + + status = ice_sbq_rw_reg_lp(hw, &phy_msg, lock_sbq); + + if (status) + ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n", + status); + else + *val = phy_msg.data; + + return status; +} + +/** + * ice_phy_port_reg_address_eth56g - Calculate a PHY port register address + * @port: Port number to be written + * @offset: Offset from PHY port register base + * @address: The result address + */ +static enum ice_status +ice_phy_port_reg_address_eth56g(u8 port, u16 offset, u32 *address) +{ + u8 phy, lane; + + if (port >= ICE_NUM_EXTERNAL_PORTS) + return ICE_ERR_OUT_OF_RANGE; + + phy = port / ICE_PORTS_PER_QUAD; + lane = port % ICE_PORTS_PER_QUAD; + + *address = offset + eth56g_port_base[phy] + + PHY_PTP_LANE_ADDR_STEP * lane; + + return ICE_SUCCESS; +} + +/** + * ice_write_phy_reg_eth56g_lp - Write a PHY port register with lock parameter + * @hw: pointer to the HW struct + * @port: Port number to be written + * @offset: Offset from PHY port register base + * @val: Value to write + * @lock_sbq: true to lock the sideband queue + */ +static enum ice_status +ice_write_phy_reg_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset, u32 val, + bool lock_sbq) +{ + enum ice_status status; + u32 reg_addr; + + status = ice_phy_port_reg_address_eth56g(port, offset, ®_addr); + if (status) + return status; + + return ice_write_phy_eth56g_raw_lp(hw, reg_addr, val, lock_sbq); +} + +/** + * ice_write_phy_reg_eth56g - Write a PHY port register with sbq locked + * @hw: pointer to the HW struct + * @port: Port number to be written + * @offset: Offset from PHY port register base + * @val: Value to write + */ +enum ice_status +ice_write_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 val) +{ + return ice_write_phy_reg_eth56g_lp(hw, port, offset, val, true); +} + +/** + * ice_read_phy_reg_eth56g_lp - Read a PHY port register with + * lock parameter + * @hw: pointer to the HW struct + * @port: Port number to be read + * @offset: Offset from PHY port register base + * @val: Pointer to the value to read (out param) + * @lock_sbq: true to lock the sideband queue + */ +static enum ice_status +ice_read_phy_reg_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset, u32 *val, + bool lock_sbq) +{ + enum ice_status status; + u32 reg_addr; + + status = ice_phy_port_reg_address_eth56g(port, offset, ®_addr); + if (status) + return status; + + return ice_read_phy_eth56g_raw_lp(hw, reg_addr, val, lock_sbq); +} + +/** + * ice_read_phy_reg_eth56g - Read a PHY port register with sbq locked + * @hw: pointer to the HW struct + * @port: Port number to be read + * @offset: Offset from PHY port register base + * @val: Pointer to the value to read (out param) + */ +enum ice_status +ice_read_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 *val) +{ + return ice_read_phy_reg_eth56g_lp(hw, port, offset, val, true); +} + +/** + * ice_is_64b_phy_reg_eth56g - Check if this is a 64bit PHY register + * @low_addr: the low address to check + * + * Checks if the provided low address is one of the known 64bit PHY values + * represented as two 32bit registers. + */ +static bool ice_is_64b_phy_reg_eth56g(u16 low_addr) +{ + switch (low_addr) { + case PHY_REG_TX_TIMER_INC_PRE_L: + case PHY_REG_RX_TIMER_INC_PRE_L: + case PHY_REG_TX_CAPTURE_L: + case PHY_REG_RX_CAPTURE_L: + case PHY_REG_TOTAL_TX_OFFSET_L: + case PHY_REG_TOTAL_RX_OFFSET_L: + return true; + default: + return false; + } +} + +/** + * ice_is_40b_phy_reg_eth56g - Check if this is a 40bit PHY register + * @low_addr: the low address to check + * + * Checks if the provided low address is one of the known 40bit PHY values + * split into two registers with the lower 8 bits in the low register and the + * upper 32 bits in the high register. + */ +static bool ice_is_40b_phy_reg_eth56g(u16 low_addr) +{ + switch (low_addr) { + case PHY_REG_TIMETUS_L: + return true; + default: + return false; + } +} + +/** + * ice_read_40b_phy_reg_eth56g - Read a 40bit value from PHY registers + * @hw: pointer to the HW struct + * @port: PHY port to read from + * @low_addr: offset of the lower register to read from + * @val: on return, the contents of the 40bit value from the PHY registers + * + * Reads the two registers associated with a 40bit value and returns it in the + * val pointer. + * This function checks that the caller has specified a known 40 bit register + * offset + */ +static enum ice_status +ice_read_40b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) +{ + u16 high_addr = low_addr + sizeof(u32); + enum ice_status status; + u32 lo, hi; + + if (!ice_is_40b_phy_reg_eth56g(low_addr)) + return ICE_ERR_PARAM; + + status = ice_read_phy_reg_eth56g(hw, port, low_addr, &lo); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register %#08x\n, status %d", + (int)low_addr, status); + return status; + } + + status = ice_read_phy_reg_eth56g(hw, port, low_addr + sizeof(u32), &hi); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register %08x\n, status %d", + high_addr, status); + return status; + } + + *val = ((u64)hi << P_REG_40B_HIGH_S) | (lo & P_REG_40B_LOW_M); + + return ICE_SUCCESS; +} + +/** + * ice_read_64b_phy_reg_eth56g - Read a 64bit value from PHY registers + * @hw: pointer to the HW struct + * @port: PHY port to read from + * @low_addr: offset of the lower register to read from + * @val: on return, the contents of the 64bit value from the PHY registers + * + * Reads the two registers associated with a 64bit value and returns it in the + * val pointer. + * This function checks that the caller has specified a known 64 bit register + * offset + */ +static enum ice_status +ice_read_64b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) +{ + u16 high_addr = low_addr + sizeof(u32); + enum ice_status status; + u32 lo, hi; + + if (!ice_is_64b_phy_reg_eth56g(low_addr)) + return ICE_ERR_PARAM; + + status = ice_read_phy_reg_eth56g(hw, port, low_addr, &lo); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register %#08x\n, status %d", + low_addr, status); + return status; + } + + status = ice_read_phy_reg_eth56g(hw, port, high_addr, &hi); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register %#08x\n, status %d", + high_addr, status); + return status; + } + + *val = ((u64)hi << 32) | lo; + + return ICE_SUCCESS; +} + +/** + * ice_write_40b_phy_reg_eth56g - Write a 40b value to the PHY + * @hw: pointer to the HW struct + * @port: port to write to + * @low_addr: offset of the low register + * @val: 40b value to write + * + * Write the provided 40b value to the two associated registers by splitting + * it up into two chunks, the lower 8 bits and the upper 32 bits. + * This function checks that the caller has specified a known 40 bit register + * offset + */ +static enum ice_status +ice_write_40b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) +{ + u16 high_addr = low_addr + sizeof(u32); + enum ice_status status; + u32 lo, hi; + + if (!ice_is_40b_phy_reg_eth56g(low_addr)) + return ICE_ERR_PARAM; + + lo = (u32)(val & P_REG_40B_LOW_M); + hi = (u32)(val >> P_REG_40B_HIGH_S); + + status = ice_write_phy_reg_eth56g(hw, port, low_addr, lo); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d", + low_addr, status); + return status; + } + + status = ice_write_phy_reg_eth56g(hw, port, high_addr, hi); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d", + high_addr, status); + return status; + } + + return ICE_SUCCESS; +} + +/** + * ice_write_64b_phy_reg_eth56g - Write a 64bit value to PHY registers + * @hw: pointer to the HW struct + * @port: PHY port to read from + * @low_addr: offset of the lower register to read from + * @val: the contents of the 64bit value to write to PHY + * + * Write the 64bit value to the two associated 32bit PHY registers. + * This function checks that the caller has specified a known 64 bit register + * offset + */ +static enum ice_status +ice_write_64b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) +{ + u16 high_addr = low_addr + sizeof(u32); + enum ice_status status; + u32 lo, hi; + + if (!ice_is_64b_phy_reg_eth56g(low_addr)) + return ICE_ERR_PARAM; + + lo = ICE_LO_DWORD(val); + hi = ICE_HI_DWORD(val); + + status = ice_write_phy_reg_eth56g(hw, port, low_addr, lo); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d", + low_addr, status); + return status; + } + + status = ice_write_phy_reg_eth56g(hw, port, high_addr, hi); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d", + high_addr, status); + return status; + } + + return ICE_SUCCESS; +} + +/** + * ice_ptp_prep_port_adj_eth56g - Prepare a single port for time adjust + * @hw: pointer to HW struct + * @port: Port number to be programmed + * @time: time in cycles to adjust the port Tx and Rx clocks + * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the + * sq_lock has already been locked at a higher level + * + * Program the port for an atomic adjustment by writing the Tx and Rx timer + * registers. The atomic adjustment won't be completed until the driver issues + * an ICE_PTP_ADJ_TIME command. + * + * Note that time is not in units of nanoseconds. It is in clock time + * including the lower sub-nanosecond portion of the port timer. + * + * Negative adjustments are supported using 2s complement arithmetic. + */ +enum ice_status +ice_ptp_prep_port_adj_eth56g(struct ice_hw *hw, u8 port, s64 time, + bool lock_sbq) +{ + enum ice_status status; + u32 l_time, u_time; + + l_time = ICE_LO_DWORD(time); + u_time = ICE_HI_DWORD(time); + + /* Tx case */ + status = ice_write_phy_reg_eth56g_lp(hw, port, + PHY_REG_TX_TIMER_INC_PRE_L, + l_time, lock_sbq); + if (status) + goto exit_err; + + status = ice_write_phy_reg_eth56g_lp(hw, port, + PHY_REG_TX_TIMER_INC_PRE_U, + u_time, lock_sbq); + if (status) + goto exit_err; + + /* Rx case */ + status = ice_write_phy_reg_eth56g_lp(hw, port, + PHY_REG_RX_TIMER_INC_PRE_L, + l_time, lock_sbq); + if (status) + goto exit_err; + + status = ice_write_phy_reg_eth56g_lp(hw, port, + PHY_REG_RX_TIMER_INC_PRE_U, + u_time, lock_sbq); + if (status) + goto exit_err; + + return ICE_SUCCESS; + +exit_err: + ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, status %d\n", + port, status); + return status; +} + +/** + * ice_ptp_read_phy_incval_eth56g - Read a PHY port's current incval + * @hw: pointer to the HW struct + * @port: the port to read + * @incval: on return, the time_clk_cyc incval for this port + * + * Read the time_clk_cyc increment value for a given PHY port. + */ +enum ice_status +ice_ptp_read_phy_incval_eth56g(struct ice_hw *hw, u8 port, u64 *incval) +{ + enum ice_status status; + + status = ice_read_40b_phy_reg_eth56g(hw, port, PHY_REG_TIMETUS_L, + incval); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read TIMETUS_L, status %d\n", + status); + return status; + } + + ice_debug(hw, ICE_DBG_PTP, "read INCVAL = 0x%016llx\n", + (unsigned long long)*incval); + + return ICE_SUCCESS; +} + +/** + * ice_ptp_read_port_capture_eth56g - Read a port's local time capture + * @hw: pointer to HW struct + * @port: Port number to read + * @tx_ts: on return, the Tx port time capture + * @rx_ts: on return, the Rx port time capture + * + * Read the port's Tx and Rx local time capture values. + */ +enum ice_status +ice_ptp_read_port_capture_eth56g(struct ice_hw *hw, u8 port, u64 *tx_ts, + u64 *rx_ts) +{ + enum ice_status status; + + /* Tx case */ + status = ice_read_64b_phy_reg_eth56g(hw, port, PHY_REG_TX_CAPTURE_L, + tx_ts); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, status %d\n", + status); + return status; + } + + ice_debug(hw, ICE_DBG_PTP, "tx_init = %#016llx\n", + (unsigned long long)*tx_ts); + + /* Rx case */ + status = ice_read_64b_phy_reg_eth56g(hw, port, PHY_REG_RX_CAPTURE_L, + rx_ts); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, status %d\n", + status); + return status; + } + + ice_debug(hw, ICE_DBG_PTP, "rx_init = %#016llx\n", + (unsigned long long)*rx_ts); + + return ICE_SUCCESS; +} + +/** + * ice_ptp_one_port_cmd_eth56g - Prepare a single PHY port for a timer command + * @hw: pointer to HW struct + * @port: Port to which cmd has to be sent + * @cmd: Command to be sent to the port + * @lock_sbq: true if the sideband queue lock must be acquired + * + * Prepare the requested port for an upcoming timer sync command. + */ +enum ice_status +ice_ptp_one_port_cmd_eth56g(struct ice_hw *hw, u8 port, + enum ice_ptp_tmr_cmd cmd, bool lock_sbq) +{ + enum ice_status status; + u32 cmd_val, val; + u8 tmr_idx; + + tmr_idx = ice_get_ptp_src_clock_index(hw); + cmd_val = tmr_idx << SEL_PHY_SRC; + switch (cmd) { + case ICE_PTP_INIT_TIME: + cmd_val |= PHY_CMD_INIT_TIME; + break; + case ICE_PTP_INIT_INCVAL: + cmd_val |= PHY_CMD_INIT_INCVAL; + break; + case ICE_PTP_ADJ_TIME: + cmd_val |= PHY_CMD_ADJ_TIME; + break; + case ICE_PTP_ADJ_TIME_AT_TIME: + cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; + break; + case ICE_PTP_READ_TIME: + cmd_val |= PHY_CMD_READ_TIME; + break; + default: + ice_warn(hw, "Unknown timer command %u\n", cmd); + return ICE_ERR_PARAM; + } + + /* Tx case */ + /* Read, modify, write */ + status = ice_read_phy_reg_eth56g_lp(hw, port, PHY_REG_TX_TMR_CMD, &val, + lock_sbq); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, status %d\n", + status); + return status; + } + + /* Modify necessary bits only and perform write */ + val &= ~TS_CMD_MASK; + val |= cmd_val; + + status = ice_write_phy_reg_eth56g_lp(hw, port, PHY_REG_TX_TMR_CMD, val, + lock_sbq); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, status %d\n", + status); + return status; + } + + /* Rx case */ + /* Read, modify, write */ + status = ice_read_phy_reg_eth56g_lp(hw, port, PHY_REG_RX_TMR_CMD, &val, + lock_sbq); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, status %d\n", + status); + return status; + } + + /* Modify necessary bits only and perform write */ + val &= ~TS_CMD_MASK; + val |= cmd_val; + + status = ice_write_phy_reg_eth56g_lp(hw, port, PHY_REG_RX_TMR_CMD, val, + lock_sbq); + if (status) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, status %d\n", + status); + return status; + } + + return ICE_SUCCESS; +} + +/** + * ice_ptp_port_cmd_eth56g - Prepare all ports for a timer command + * @hw: pointer to the HW struct + * @cmd: timer command to prepare + * @lock_sbq: true if the sideband queue lock must be acquired + * + * Prepare all ports connected to this device for an upcoming timer sync + * command. + */ +static enum ice_status +ice_ptp_port_cmd_eth56g(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, + bool lock_sbq) +{ + enum ice_status status; + u8 port; + + for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { + if (!(hw->ena_lports & BIT(port))) + continue; + + status = ice_ptp_one_port_cmd_eth56g(hw, port, cmd, lock_sbq); + if (status) + return status; + } + + return ICE_SUCCESS; +} + +/** + * ice_calc_fixed_tx_offset_eth56g - Calculated Fixed Tx offset for a port + * @hw: pointer to the HW struct + * @link_spd: the Link speed to calculate for + * + * Calculate the fixed offset due to known static latency data. + */ +static u64 +ice_calc_fixed_tx_offset_eth56g(struct ice_hw *hw, + enum ice_ptp_link_spd link_spd) +{ + u64 fixed_offset = 0; + return fixed_offset; +} + +/** + * ice_phy_cfg_tx_offset_eth56g - Configure total Tx timestamp offset + * @hw: pointer to the HW struct + * @port: the PHY port to configure + * + * Program the PHY_REG_TOTAL_TX_OFFSET register with the total number of TUs to + * adjust Tx timestamps by. + * + * To avoid overflow, when calculating the offset based on the known static + * latency values, we use measurements in 1/100th of a nanosecond, and divide + * the TUs per second up front. This avoids overflow while allowing + * calculation of the adjustment using integer arithmetic. + */ +enum ice_status ice_phy_cfg_tx_offset_eth56g(struct ice_hw *hw, u8 port) +{ + enum ice_ptp_link_spd link_spd = ICE_PTP_LNK_SPD_10G; + enum ice_status status; + u64 total_offset; + + total_offset = ice_calc_fixed_tx_offset_eth56g(hw, link_spd); + + /* Now that the total offset has been calculated, program it to the + * PHY and indicate that the Tx offset is ready. After this, + * timestamps will be enabled. + */ + status = ice_write_64b_phy_reg_eth56g(hw, port, + PHY_REG_TOTAL_TX_OFFSET_L, + total_offset); + if (status) + return status; + + return ice_write_phy_reg_eth56g(hw, port, PHY_REG_TX_OFFSET_READY, 1); +} + +/** + * ice_calc_fixed_rx_offset_eth56g - Calculated the fixed Rx offset for a port + * @hw: pointer to HW struct + * @link_spd: The Link speed to calculate for + * + * Determine the fixed Rx latency for a given link speed. + */ +static u64 +ice_calc_fixed_rx_offset_eth56g(struct ice_hw *hw, + enum ice_ptp_link_spd link_spd) +{ + u64 fixed_offset = 0; + return fixed_offset; +} + +/** + * ice_phy_cfg_rx_offset_eth56g - Configure total Rx timestamp offset + * @hw: pointer to the HW struct + * @port: the PHY port to configure + * + * Program the PHY_REG_TOTAL_RX_OFFSET register with the number of Time Units to + * adjust Rx timestamps by. This combines calculations from the Vernier offset + * measurements taken in hardware with some data about known fixed delay as + * well as adjusting for multi-lane alignment delay. + * + * This function must be called only after the offset registers are valid, + * i.e. after the Vernier calibration wait has passed, to ensure that the PHY + * has measured the offset. + * + * To avoid overflow, when calculating the offset based on the known static + * latency values, we use measurements in 1/100th of a nanosecond, and divide + * the TUs per second up front. This avoids overflow while allowing + * calculation of the adjustment using integer arithmetic. + */ +enum ice_status ice_phy_cfg_rx_offset_eth56g(struct ice_hw *hw, u8 port) +{ + enum ice_status status; + u64 total_offset; + + total_offset = ice_calc_fixed_rx_offset_eth56g(hw, 0); + + /* Now that the total offset has been calculated, program it to the + * PHY and indicate that the Rx offset is ready. After this, + * timestamps will be enabled. + */ + status = ice_write_64b_phy_reg_eth56g(hw, port, + PHY_REG_TOTAL_RX_OFFSET_L, + total_offset); + if (status) + return status; + + return ice_write_phy_reg_eth56g(hw, port, PHY_REG_RX_OFFSET_READY, 1); +} + +/** + * ice_read_phy_and_phc_time_eth56g - Simultaneously capture PHC and PHY time + * @hw: pointer to the HW struct + * @port: the PHY port to read + * @phy_time: on return, the 64bit PHY timer value + * @phc_time: on return, the lower 64bits of PHC time + * + * Issue a ICE_PTP_READ_TIME timer command to simultaneously capture the PHY + * and PHC timer values. + */ +static enum ice_status +ice_read_phy_and_phc_time_eth56g(struct ice_hw *hw, u8 port, u64 *phy_time, + u64 *phc_time) +{ + enum ice_status status; + u64 tx_time, rx_time; + u32 zo, lo; + u8 tmr_idx; + + tmr_idx = ice_get_ptp_src_clock_index(hw); + + /* Prepare the PHC timer for a ICE_PTP_READ_TIME capture command */ + ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME); + + /* Prepare the PHY timer for a ICE_PTP_READ_TIME capture command */ + status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_READ_TIME, true); + if (status) + return status; + + /* Issue the sync to start the ICE_PTP_READ_TIME capture */ + ice_ptp_exec_tmr_cmd(hw); + ice_ptp_clean_cmd(hw); + + /* Read the captured PHC time from the shadow time registers */ + zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); + lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); + *phc_time = (u64)lo << 32 | zo; + + /* Read the captured PHY time from the PHY shadow registers */ + status = ice_ptp_read_port_capture_eth56g(hw, port, &tx_time, &rx_time); + if (status) + return status; + + /* If the PHY Tx and Rx timers don't match, log a warning message. + * Note that this should not happen in normal circumstances since the + * driver always programs them together. + */ + if (tx_time != rx_time) + ice_warn(hw, "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", + port, (unsigned long long)tx_time, + (unsigned long long)rx_time); + + *phy_time = tx_time; + + return ICE_SUCCESS; +} + +/** + * ice_sync_phy_timer_eth56g - Synchronize the PHY timer with PHC timer + * @hw: pointer to the HW struct + * @port: the PHY port to synchronize + * + * Perform an adjustment to ensure that the PHY and PHC timers are in sync. + * This is done by issuing a ICE_PTP_READ_TIME command which triggers a + * simultaneous read of the PHY timer and PHC timer. Then we use the + * difference to calculate an appropriate 2s complement addition to add + * to the PHY timer in order to ensure it reads the same value as the + * primary PHC timer. + */ +static enum ice_status ice_sync_phy_timer_eth56g(struct ice_hw *hw, u8 port) +{ + u64 phc_time, phy_time, difference; + enum ice_status status; + + if (!ice_ptp_lock(hw)) { + ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); + return ICE_ERR_NOT_READY; + } + + status = ice_read_phy_and_phc_time_eth56g(hw, port, &phy_time, + &phc_time); + if (status) + goto err_unlock; + + /* Calculate the amount required to add to the port time in order for + * it to match the PHC time. + * + * Note that the port adjustment is done using 2s complement + * arithmetic. This is convenient since it means that we can simply + * calculate the difference between the PHC time and the port time, + * and it will be interpreted correctly. + */ + + ice_ptp_src_cmd(hw, ICE_PTP_NOP); + difference = phc_time - phy_time; + + status = ice_ptp_prep_port_adj_eth56g(hw, port, (s64)difference, true); + if (status) + goto err_unlock; + + status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_ADJ_TIME, true); + if (status) + goto err_unlock; + + /* Issue the sync to activate the time adjustment */ + ice_ptp_exec_tmr_cmd(hw); + ice_ptp_clean_cmd(hw); + + /* Re-capture the timer values to flush the command registers and + * verify that the time was properly adjusted. + */ + + status = ice_read_phy_and_phc_time_eth56g(hw, port, &phy_time, + &phc_time); + if (status) + goto err_unlock; + + ice_info(hw, "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", + port, (unsigned long long)phy_time, + (unsigned long long)phc_time); + +err_unlock: + ice_ptp_unlock(hw); + return status; +} + +/** + * ice_stop_phy_timer_eth56g - Stop the PHY clock timer + * @hw: pointer to the HW struct + * @port: the PHY port to stop + * @soft_reset: if true, hold the SOFT_RESET bit of PHY_REG_PS + * + * Stop the clock of a PHY port. This must be done as part of the flow to + * re-calibrate Tx and Rx timestamping offsets whenever the clock time is + * initialized or when link speed changes. + */ +enum ice_status +ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset) +{ + enum ice_status status; + + status = ice_write_phy_reg_eth56g(hw, port, PHY_REG_TX_OFFSET_READY, 0); + if (status) + return status; + + status = ice_write_phy_reg_eth56g(hw, port, PHY_REG_RX_OFFSET_READY, 0); + if (status) + return status; + + ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); + + return ICE_SUCCESS; +} + +/** + * ice_start_phy_timer_eth56g - Start the PHY clock timer + * @hw: pointer to the HW struct + * @port: the PHY port to start + * @bypass: unused, for compatibility + * + * Start the clock of a PHY port. This must be done as part of the flow to + * re-calibrate Tx and Rx timestamping offsets whenever the clock time is + * initialized or when link speed changes. + * + */ +enum ice_status +ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool bypass) +{ + enum ice_status status; + u32 lo, hi; + u64 incval; + u8 tmr_idx; + + tmr_idx = ice_get_ptp_src_clock_index(hw); + + status = ice_stop_phy_timer_eth56g(hw, port, false); + if (status) + return status; + + ice_ptp_src_cmd(hw, ICE_PTP_NOP); + + lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); + hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); + incval = (u64)hi << 32 | lo; + + status = ice_write_40b_phy_reg_eth56g(hw, port, PHY_REG_TIMETUS_L, + incval); + if (status) + return status; + + status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_INIT_INCVAL, + true); + if (status) + return status; + + ice_ptp_exec_tmr_cmd(hw); + + status = ice_sync_phy_timer_eth56g(hw, port); + if (status) + return status; + + /* Program the Tx offset */ + status = ice_phy_cfg_tx_offset_eth56g(hw, port); + if (status) + return status; + + /* Program the Rx offset */ + status = ice_phy_cfg_rx_offset_eth56g(hw, port); + if (status) + return status; + + ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); + + return ICE_SUCCESS; +} + +/** + * ice_ptp_read_tx_hwtstamp_status_eth56g - Get the current TX timestamp + * status mask. Returns the mask of ports where TX timestamps are available + * @hw: pointer to the HW struct + * @ts_status: the timestamp mask pointer + */ +enum ice_status +ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) +{ + enum ice_status status; + + status = ice_read_phy_eth56g_raw_lp(hw, PHY_PTP_INT_STATUS, ts_status, + true); + if (status) + return status; + + ice_debug(hw, ICE_DBG_PTP, "PHY interrupt status: %x\n", *ts_status); + + return ICE_SUCCESS; +} + +/* ---------------------------------------------------------------------------- + * E822 family functions * * The following functions operate on the E822 family of devices. */ @@ -1013,7 +1982,7 @@ static enum ice_status ice_ptp_init_phc_e822(struct ice_hw *hw) * @time: Time to initialize the PHY port clocks to * * Program the PHY port registers with a new initial time value. The port - * clock will be initialized once the driver issues an INIT_TIME sync + * clock will be initialized once the driver issues an ICE_PTP_INIT_TIME sync * command. The time value is the upper 32 bits of the PHY timer, usually in * units of nominal nanoseconds. */ @@ -1065,7 +2034,7 @@ ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) * * Program the port for an atomic adjustment by writing the Tx and Rx timer * registers. The atomic adjustment won't be completed until the driver issues - * an ADJ_TIME command. + * an ICE_PTP_ADJ_TIME command. * * Note that time is not in units of nanoseconds. It is in clock time * including the lower sub-nanosecond portion of the port timer. @@ -1121,7 +2090,7 @@ ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time, * * Prepare the PHY ports for an atomic time adjustment by programming the PHY * Tx and Rx port registers. The actual adjustment is completed by issuing an - * ADJ_TIME or ADJ_TIME_AT_TIME sync command. + * ICE_PTP_ADJ_TIME or ICE_PTP_ADJ_TIME_AT_TIME sync command. */ static enum ice_status ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj, bool lock_sbq) @@ -1157,7 +2126,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj, bool lock_sbq) * * Prepare each of the PHY ports for a new increment value by programming the * port's TIMETUS registers. The new increment value will be updated after - * issuing an INIT_INCVAL command. + * issuing an ICE_PTP_INIT_INCVAL command. */ static enum ice_status ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) @@ -1213,7 +2182,7 @@ ice_ptp_read_phy_incval_e822(struct ice_hw *hw, u8 port, u64 *incval) * @target_time: target time to program * * Program the PHY port Tx and Rx TIMER_CNT_ADJ registers used for the - * ADJ_TIME_AT_TIME command. This should be used in conjunction with + * ICE_PTP_ADJ_TIME_AT_TIME command. This should be used in conjunction with * ice_ptp_prep_phy_adj_e822 to program an atomic adjustment that is * delayed until a specified target time. * @@ -1331,19 +2300,19 @@ ice_ptp_one_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd, tmr_idx = ice_get_ptp_src_clock_index(hw); cmd_val = tmr_idx << SEL_PHY_SRC; switch (cmd) { - case INIT_TIME: + case ICE_PTP_INIT_TIME: cmd_val |= PHY_CMD_INIT_TIME; break; - case INIT_INCVAL: + case ICE_PTP_INIT_INCVAL: cmd_val |= PHY_CMD_INIT_INCVAL; break; - case ADJ_TIME: + case ICE_PTP_ADJ_TIME: cmd_val |= PHY_CMD_ADJ_TIME; break; - case ADJ_TIME_AT_TIME: + case ICE_PTP_ADJ_TIME_AT_TIME: cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; break; - case READ_TIME: + case ICE_PTP_READ_TIME: cmd_val |= PHY_CMD_READ_TIME; break; default: @@ -2300,8 +3269,8 @@ ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port) * @phy_time: on return, the 64bit PHY timer value * @phc_time: on return, the lower 64bits of PHC time * - * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC - * timer values. + * Issue a ICE_PTP_READ_TIME timer command to simultaneously capture the PHY + * and PHC timer values. */ static enum ice_status ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, @@ -2314,15 +3283,15 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, tmr_idx = ice_get_ptp_src_clock_index(hw); - /* Prepare the PHC timer for a READ_TIME capture command */ - ice_ptp_src_cmd(hw, READ_TIME); + /* Prepare the PHC timer for a ICE_PTP_READ_TIME capture command */ + ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME); - /* Prepare the PHY timer for a READ_TIME capture command */ - status = ice_ptp_one_port_cmd_e822(hw, port, READ_TIME, true); + /* Prepare the PHY timer for a ICE_PTP_READ_TIME capture command */ + status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_READ_TIME, true); if (status) return status; - /* Issue the sync to start the READ_TIME capture */ + /* Issue the sync to start the ICE_PTP_READ_TIME capture */ ice_ptp_exec_tmr_cmd(hw); /* Read the captured PHC time from the shadow time registers */ @@ -2355,10 +3324,11 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, * @port: the PHY port to synchronize * * Perform an adjustment to ensure that the PHY and PHC timers are in sync. - * This is done by issuing a READ_TIME command which triggers a simultaneous - * read of the PHY timer and PHC timer. Then we use the difference to - * calculate an appropriate 2s complement addition to add to the PHY timer in - * order to ensure it reads the same value as the primary PHC timer. + * This is done by issuing a ICE_PTP_READ_TIME command which triggers a + * simultaneous read of the PHY timer and PHC timer. Then we use the + * difference to calculate an appropriate 2s complement addition to add + * to the PHY timer in order to ensure it reads the same value as the + * primary PHC timer. */ static enum ice_status ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) { @@ -2388,10 +3358,13 @@ static enum ice_status ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) if (status) goto err_unlock; - status = ice_ptp_one_port_cmd_e822(hw, port, ADJ_TIME, true); + status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_ADJ_TIME, true); if (status) goto err_unlock; + /* Init PHC mstr/src cmd for exec during sync */ + ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME); + /* Issue the sync to activate the time adjustment */ ice_ptp_exec_tmr_cmd(hw); @@ -2513,10 +3486,13 @@ ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) if (status) return status; - status = ice_ptp_one_port_cmd_e822(hw, port, INIT_INCVAL, true); + status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_INIT_INCVAL, true); if (status) return status; + /* Init PHC mstr/src cmd for exec during sync */ + ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME); + ice_ptp_exec_tmr_cmd(hw); status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); @@ -2538,7 +3514,7 @@ ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) if (status) return status; - status = ice_ptp_one_port_cmd_e822(hw, port, INIT_INCVAL, true); + status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_INIT_INCVAL, true); if (status) return status; @@ -2870,7 +3846,7 @@ static enum ice_status ice_ptp_init_phc_e810(struct ice_hw *hw) * * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the * initial clock time. The time will not actually be programmed until the - * driver issues an INIT_TIME command. + * driver issues an ICE_PTP_INIT_TIME command. * * The time value is the upper 32 bits of the PHY timer, usually in units of * nominal nanoseconds. @@ -2906,7 +3882,7 @@ static enum ice_status ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) * * Prepare the PHY port for an atomic adjustment by programming the PHY * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment - * is completed by issuing an ADJ_TIME sync command. + * is completed by issuing an ICE_PTP_ADJ_TIME sync command. * * The adjustment value only contains the portion used for the upper 32bits of * the PHY timer, usually in units of nominal nanoseconds. Negative @@ -2949,7 +3925,7 @@ ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj, bool lock_sbq) * * Prepare the PHY port for a new increment value by programming the PHY * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is - * completed by issuing an INIT_INCVAL command. + * completed by issuing an ICE_PTP_INIT_INCVAL command. */ static enum ice_status ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) @@ -2987,8 +3963,8 @@ ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation for * a target time adjust, which will trigger an adjustment of the clock in the * future. The actual adjustment will occur the next time the PHY port timer - * crosses over the provided value after the driver issues an ADJ_TIME_AT_TIME - * command. + * crosses over the provided value after the driver issues an + * ICE_PTP_ADJ_TIME_AT_TIME command. * * The time value is the upper 32 bits of the PHY timer, usually in units of * nominal nanoseconds. @@ -3035,19 +4011,19 @@ ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, u32 cmd_val, val; switch (cmd) { - case INIT_TIME: + case ICE_PTP_INIT_TIME: cmd_val = GLTSYN_CMD_INIT_TIME; break; - case INIT_INCVAL: + case ICE_PTP_INIT_INCVAL: cmd_val = GLTSYN_CMD_INIT_INCVAL; break; - case ADJ_TIME: + case ICE_PTP_ADJ_TIME: cmd_val = GLTSYN_CMD_ADJ_TIME; break; - case ADJ_TIME_AT_TIME: + case ICE_PTP_ADJ_TIME_AT_TIME: cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; break; - case READ_TIME: + case ICE_PTP_READ_TIME: cmd_val = GLTSYN_CMD_READ_TIME; break; default: @@ -3375,19 +4351,19 @@ void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) cmd_val = tmr_idx << SEL_CPK_SRC; switch (cmd) { - case INIT_TIME: + case ICE_PTP_INIT_TIME: cmd_val |= GLTSYN_CMD_INIT_TIME; break; - case INIT_INCVAL: + case ICE_PTP_INIT_INCVAL: cmd_val |= GLTSYN_CMD_INIT_INCVAL; break; - case ADJ_TIME: + case ICE_PTP_ADJ_TIME: cmd_val |= GLTSYN_CMD_ADJ_TIME; break; - case ADJ_TIME_AT_TIME: + case ICE_PTP_ADJ_TIME_AT_TIME: cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME; break; - case READ_TIME: + case ICE_PTP_READ_TIME: cmd_val |= GLTSYN_CMD_READ_TIME; break; default: @@ -3418,10 +4394,19 @@ ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, bool lock_sbq) ice_ptp_src_cmd(hw, cmd); /* Next, prepare the ports */ - if (ice_is_e810(hw)) + switch (hw->phy_cfg) { + case ICE_PHY_ETH56G: + status = ice_ptp_port_cmd_eth56g(hw, cmd, lock_sbq); + break; + case ICE_PHY_E810: status = ice_ptp_port_cmd_e810(hw, cmd, lock_sbq); - else + break; + case ICE_PHY_E822: status = ice_ptp_port_cmd_e822(hw, cmd, lock_sbq); + break; + default: + status = ICE_ERR_NOT_SUPPORTED; + } if (status) { ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, status %d\n", cmd, status); @@ -3470,7 +4455,7 @@ enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time) if (status) return status; - return ice_ptp_tmr_cmd(hw, INIT_TIME, true); + return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_TIME, true); } /** @@ -3483,8 +4468,8 @@ enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time) * * 1) Write the increment value to the source timer shadow registers * 2) Write the increment value to the PHY timer shadow registers - * 3) Issue an INIT_INCVAL timer command to synchronously switch both the - * source and port timers to the new increment value at the next clock + * 3) Issue an ICE_PTP_INIT_INCVAL timer command to synchronously switch both + * the source and port timers to the new increment value at the next clock * cycle. */ enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval) @@ -3505,7 +4490,7 @@ enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval) if (status) return status; - return ice_ptp_tmr_cmd(hw, INIT_INCVAL, true); + return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_INCVAL, true); } /** @@ -3541,8 +4526,8 @@ enum ice_status ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) * * 1) Write the adjustment to the source timer shadow registers * 2) Write the adjustment to the PHY timer shadow registers - * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to - * both the source and port timers at the next clock cycle. + * 3) Issue an ICE_PTP_ADJ_TIME timer command to synchronously apply the + * adjustment to both the source and port timers at the next clock cycle. */ enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq) { @@ -3566,7 +4551,7 @@ enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq) if (status) return status; - return ice_ptp_tmr_cmd(hw, ADJ_TIME, lock_sbq); + return ice_ptp_tmr_cmd(hw, ICE_PTP_ADJ_TIME, lock_sbq); } /** @@ -3582,7 +4567,8 @@ enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq) * 2) Write the target time to the source timer shadow time registers * 3) Write the adjustment to the PHY timers shadow adjust registers * 4) Write the target time to the PHY timers shadow adjust registers - * 5) Issue an ADJ_TIME_AT_TIME command to initiate the atomic adjustment. + * 5) Issue an ICE_PTP_ADJ_TIME_AT_TIME command to initiate the atomic + * adjustment. */ enum ice_status ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj) @@ -3596,9 +4582,9 @@ ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj) time_hi = ICE_HI_DWORD(at_time); /* Write the desired clock adjustment into the GLTSYN_SHADJ register. - * For an ADJ_TIME_AT_TIME command, this set of registers represents - * the value to add to the clock time. It supports subtraction by - * interpreting the value as a 2's complement integer. + * For an ICE_PTP_ADJ_TIME_AT_TIME command, this set of registers + * represents the value to add to the clock time. It supports + * subtraction by interpreting the value as a 2's complement integer. */ wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); @@ -3624,7 +4610,7 @@ ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj) if (status) return status; - return ice_ptp_tmr_cmd(hw, ADJ_TIME_AT_TIME, true); + return ice_ptp_tmr_cmd(hw, ICE_PTP_ADJ_TIME_AT_TIME, true); } /** diff --git a/drivers/net/ice/base/ice_ptp_hw.h b/drivers/net/ice/base/ice_ptp_hw.h index ecb79eaea9..a030a9d4ed 100644 --- a/drivers/net/ice/base/ice_ptp_hw.h +++ b/drivers/net/ice/base/ice_ptp_hw.h @@ -6,11 +6,12 @@ #define _ICE_PTP_HW_H_ enum ice_ptp_tmr_cmd { - INIT_TIME, - INIT_INCVAL, - ADJ_TIME, - ADJ_TIME_AT_TIME, - READ_TIME + ICE_PTP_INIT_TIME, + ICE_PTP_INIT_INCVAL, + ICE_PTP_ADJ_TIME, + ICE_PTP_ADJ_TIME_AT_TIME, + ICE_PTP_READ_TIME, + ICE_PTP_NOP, }; enum ice_ptp_serdes { @@ -232,6 +233,39 @@ enum ice_status ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data); enum ice_status ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data); bool ice_is_pca9575_present(struct ice_hw *hw); +void +ice_ptp_process_cgu_err(struct ice_hw *hw, struct ice_rq_event_info *event); +/* ETH56G family functions */ +enum ice_status +ice_read_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 *val); +enum ice_status +ice_write_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 val); +enum ice_status +ice_read_phy_mem_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 *val); +enum ice_status +ice_write_phy_mem_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 val); + +enum ice_status +ice_ptp_prep_port_adj_eth56g(struct ice_hw *hw, u8 port, s64 time, + bool lock_sbq); + +enum ice_status +ice_ptp_read_phy_incval_eth56g(struct ice_hw *hw, u8 port, u64 *incval); +enum ice_status +ice_ptp_read_port_capture_eth56g(struct ice_hw *hw, u8 port, + u64 *tx_ts, u64 *rx_ts); +enum ice_status +ice_ptp_one_port_cmd_eth56g(struct ice_hw *hw, u8 port, + enum ice_ptp_tmr_cmd cmd, bool lock_sbq); +enum ice_status +ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status); +enum ice_status +ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); +enum ice_status +ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool bypass); +enum ice_status ice_phy_cfg_tx_offset_eth56g(struct ice_hw *hw, u8 port); +enum ice_status ice_phy_cfg_rx_offset_eth56g(struct ice_hw *hw, u8 port); + #define PFTSYN_SEM_BYTES 4 #define ICE_PTP_CLOCK_INDEX_0 0x00 diff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h index 15b12bfc8d..a17accff19 100644 --- a/drivers/net/ice/base/ice_type.h +++ b/drivers/net/ice/base/ice_type.h @@ -1135,6 +1135,13 @@ struct ice_switch_info { ice_declare_bitmap(prof_res_bm[ICE_MAX_NUM_PROFILES], ICE_MAX_FV_WORDS); }; +/* PHY configuration */ +enum ice_phy_cfg { + ICE_PHY_E810 = 1, + ICE_PHY_E822, + ICE_PHY_ETH56G, +}; + /* Port hardware description */ struct ice_hw { u8 *hw_addr; @@ -1159,6 +1166,7 @@ struct ice_hw { u8 revision_id; u8 pf_id; /* device profile info */ + enum ice_phy_cfg phy_cfg; u8 logical_pf_id; u16 max_burst_size; /* driver sets this value */ @@ -1233,6 +1241,9 @@ struct ice_hw { #define ICE_PORTS_PER_PHY 8 #define ICE_NUM_EXTERNAL_PORTS ICE_PORTS_PER_PHY + /* bitmap of enabled logical ports */ + u32 ena_lports; + /* Active package version (currently active) */ struct ice_pkg_ver active_pkg_ver; u32 pkg_seg_id;