Commit 4fa7011d authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2023-09-18 (ice)

This series contains updates to ice driver only.

Sergey prepends ICE_ to PTP timer commands to clearly convey namespace
of commands.

Karol adds retrying to acquire hardware semaphore for cross-timestamping
and avoids writing to timestamp registers on E822 devices. He also
renames some defines to be more clear and align with the data sheet.
Additionally, a range check is moved in order to reduce duplicated code.

Jake adds cross-timestamping support for E823 devices as well as adds
checks against netlist to aid in determining support for GNSS. He also
corrects improper pin assignment for certain E810-T devices and
refactors/cleanups PTP related code such as adding PHY model to ease checks
for different needed implementations, removing unneeded EXTTS flag, and
adding macro to check for source timer owner.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a76c22e2 89776a6a
......@@ -196,9 +196,10 @@
#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_PTP_EXTTS,
ICE_F_PHY_RCLK,
ICE_F_SMA_CTRL,
ICE_F_CGU,
......
......@@ -1393,6 +1393,7 @@ struct ice_aqc_link_topo_params {
#define ICE_AQC_LINK_TOPO_NODE_TYPE_ID_EEPROM 8
#define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL 9
#define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX 10
#define ICE_AQC_LINK_TOPO_NODE_TYPE_GPS 11
#define ICE_AQC_LINK_TOPO_NODE_CTX_S 4
#define ICE_AQC_LINK_TOPO_NODE_CTX_M \
(0xF << ICE_AQC_LINK_TOPO_NODE_CTX_S)
......@@ -1435,6 +1436,7 @@ struct ice_aqc_get_link_topo {
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_GPS 0x48
u8 rsvd[9];
};
......
......@@ -2764,6 +2764,21 @@ bool ice_is_pf_c827(struct ice_hw *hw)
return false;
}
/**
* ice_is_gps_in_netlist
* @hw: pointer to the hw struct
*
* Check if the GPS generic device is present in the netlist
*/
bool ice_is_gps_in_netlist(struct ice_hw *hw)
{
if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_GPS,
ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_GPS, NULL))
return false;
return true;
}
/**
* ice_aq_list_caps - query function/device capabilities
* @hw: pointer to the HW struct
......
......@@ -93,6 +93,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
struct ice_aqc_get_phy_caps_data *caps,
struct ice_sq_cd *cd);
bool ice_is_pf_c827(struct ice_hw *hw);
bool ice_is_gps_in_netlist(struct ice_hw *hw);
int
ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, u8 node_part_number,
u16 *node_handle);
......
......@@ -389,6 +389,9 @@ bool ice_gnss_is_gps_present(struct ice_hw *hw)
if (!hw->func_caps.ts_func_info.src_tmr_owned)
return false;
if (!ice_is_gps_in_netlist(hw))
return false;
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
if (ice_is_e810t(hw)) {
int err;
......
......@@ -3989,11 +3989,10 @@ void ice_init_feature_support(struct ice_pf *pf)
case ICE_DEV_ID_E810_XXV_QSFP:
case ICE_DEV_ID_E810_XXV_SFP:
ice_set_feature_support(pf, ICE_F_DSCP);
ice_set_feature_support(pf, ICE_F_PTP_EXTTS);
if (ice_is_phy_rclk_present(&pf->hw))
ice_set_feature_support(pf, ICE_F_PHY_RCLK);
/* If we don't own the timer - don't enable other caps */
if (!pf->hw.func_caps.ts_func_info.src_tmr_owned)
if (!ice_pf_src_tmr_owned(pf))
break;
if (ice_is_cgu_present(&pf->hw))
ice_set_feature_support(pf, ICE_F_CGU);
......
......@@ -3159,7 +3159,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
ena_mask &= ~PFINT_OICR_TSYN_EVNT_M;
if (hw->func_caps.ts_func_info.src_tmr_owned) {
if (ice_pf_src_tmr_owned(pf)) {
/* Save EVENTs from GLTSYN register */
pf->ptp.ext_ts_irq |= gltsyn_stat &
(GLTSYN_STAT_EVENT0_M |
......
......@@ -436,7 +436,7 @@ static void ice_clear_ptp_clock_index(struct ice_pf *pf)
int err;
/* Do not clear the index if we don't own the timer */
if (!hw->func_caps.ts_func_info.src_tmr_owned)
if (!ice_pf_src_tmr_owned(pf))
return;
tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
......@@ -1366,6 +1366,7 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
{
struct ice_ptp_port *ptp_port;
struct ice_hw *hw = &pf->hw;
if (!test_bit(ICE_FLAG_PTP, pf->flags))
return;
......@@ -1380,11 +1381,16 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
/* Update cached link status for this port immediately */
ptp_port->link_up = linkup;
/* E810 devices do not need to reconfigure the PHY */
if (ice_is_e810(&pf->hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
/* Do not reconfigure E810 PHY */
return;
ice_ptp_port_phy_restart(ptp_port);
case ICE_PHY_E822:
ice_ptp_port_phy_restart(ptp_port);
return;
default:
dev_warn(ice_pf_to_dev(pf), "%s: Unknown PHY type\n", __func__);
}
}
/**
......@@ -1976,21 +1982,32 @@ ice_ptp_get_syncdevicetime(ktime_t *device,
u32 hh_lock, hh_art_ctl;
int i;
/* Get the HW lock */
hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
#define MAX_HH_HW_LOCK_TRIES 5
#define MAX_HH_CTL_LOCK_TRIES 100
for (i = 0; i < MAX_HH_HW_LOCK_TRIES; i++) {
/* Get the HW lock */
hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
if (hh_lock & PFHH_SEM_BUSY_M) {
usleep_range(10000, 15000);
continue;
}
break;
}
if (hh_lock & PFHH_SEM_BUSY_M) {
dev_err(ice_pf_to_dev(pf), "PTP failed to get hh lock\n");
return -EFAULT;
return -EBUSY;
}
/* Program cmd to master timer */
ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
/* Start the ART and device clock sync sequence */
hh_art_ctl = rd32(hw, GLHH_ART_CTL);
hh_art_ctl = hh_art_ctl | GLHH_ART_CTL_ACTIVE_M;
wr32(hw, GLHH_ART_CTL, hh_art_ctl);
#define MAX_HH_LOCK_TRIES 100
for (i = 0; i < MAX_HH_LOCK_TRIES; i++) {
for (i = 0; i < MAX_HH_CTL_LOCK_TRIES; i++) {
/* Wait for sync to complete */
hh_art_ctl = rd32(hw, GLHH_ART_CTL);
if (hh_art_ctl & GLHH_ART_CTL_ACTIVE_M) {
......@@ -2014,19 +2031,23 @@ ice_ptp_get_syncdevicetime(ktime_t *device,
break;
}
}
/* Clear the master timer */
ice_ptp_src_cmd(hw, ICE_PTP_NOP);
/* Release HW lock */
hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
hh_lock = hh_lock & ~PFHH_SEM_BUSY_M;
wr32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), hh_lock);
if (i == MAX_HH_LOCK_TRIES)
if (i == MAX_HH_CTL_LOCK_TRIES)
return -ETIMEDOUT;
return 0;
}
/**
* ice_ptp_getcrosststamp_e822 - Capture a device cross timestamp
* ice_ptp_getcrosststamp_e82x - Capture a device cross timestamp
* @info: the driver's PTP info structure
* @cts: The memory to fill the cross timestamp info
*
......@@ -2034,14 +2055,14 @@ ice_ptp_get_syncdevicetime(ktime_t *device,
* clock. Fill the cross timestamp information and report it back to the
* caller.
*
* This is only valid for E822 devices which have support for generating the
* cross timestamp via PCIe PTM.
* This is only valid for E822 and E823 devices which have support for
* generating the cross timestamp via PCIe PTM.
*
* In order to correctly correlate the ART timestamp back to the TSC time, the
* CPU must have X86_FEATURE_TSC_KNOWN_FREQ.
*/
static int
ice_ptp_getcrosststamp_e822(struct ptp_clock_info *info,
ice_ptp_getcrosststamp_e82x(struct ptp_clock_info *info,
struct system_device_crosststamp *cts)
{
struct ice_pf *pf = ptp_info_to_pf(info);
......@@ -2246,18 +2267,20 @@ ice_ptp_setup_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info)
static void
ice_ptp_setup_pins_e810(struct ice_pf *pf, struct ptp_clock_info *info)
{
info->n_per_out = N_PER_OUT_E810;
if (ice_is_feature_supported(pf, ICE_F_PTP_EXTTS))
info->n_ext_ts = N_EXT_TS_E810;
if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) {
info->n_ext_ts = N_EXT_TS_E810;
info->n_per_out = N_PER_OUT_E810T;
info->n_pins = NUM_PTP_PINS_E810T;
info->verify = ice_verify_pin_e810t;
/* Complete setup of the SMA pins */
ice_ptp_setup_sma_pins_e810t(pf, info);
} else if (ice_is_e810t(&pf->hw)) {
info->n_ext_ts = N_EXT_TS_NO_SMA_E810T;
info->n_per_out = N_PER_OUT_NO_SMA_E810T;
} else {
info->n_per_out = N_PER_OUT_E810;
info->n_ext_ts = N_EXT_TS_E810;
}
}
......@@ -2275,22 +2298,22 @@ ice_ptp_setup_pins_e823(struct ice_pf *pf, struct ptp_clock_info *info)
}
/**
* ice_ptp_set_funcs_e822 - Set specialized functions for E822 support
* ice_ptp_set_funcs_e82x - Set specialized functions for E82x support
* @pf: Board private structure
* @info: PTP info to fill
*
* Assign functions to the PTP capabiltiies structure for E822 devices.
* Assign functions to the PTP capabiltiies structure for E82x devices.
* Functions which operate across all device families should be set directly
* in ice_ptp_set_caps. Only add functions here which are distinct for E822
* in ice_ptp_set_caps. Only add functions here which are distinct for E82x
* devices.
*/
static void
ice_ptp_set_funcs_e822(struct ice_pf *pf, struct ptp_clock_info *info)
ice_ptp_set_funcs_e82x(struct ice_pf *pf, struct ptp_clock_info *info)
{
#ifdef CONFIG_ICE_HWTS
if (boot_cpu_has(X86_FEATURE_ART) &&
boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ))
info->getcrosststamp = ice_ptp_getcrosststamp_e822;
info->getcrosststamp = ice_ptp_getcrosststamp_e82x;
#endif /* CONFIG_ICE_HWTS */
}
......@@ -2324,6 +2347,8 @@ ice_ptp_set_funcs_e810(struct ice_pf *pf, struct ptp_clock_info *info)
static void
ice_ptp_set_funcs_e823(struct ice_pf *pf, struct ptp_clock_info *info)
{
ice_ptp_set_funcs_e82x(pf, info);
info->enable = ice_ptp_gpio_enable_e823;
ice_ptp_setup_pins_e823(pf, info);
}
......@@ -2351,7 +2376,7 @@ static void ice_ptp_set_caps(struct ice_pf *pf)
else if (ice_is_e823(&pf->hw))
ice_ptp_set_funcs_e823(pf, info);
else
ice_ptp_set_funcs_e822(pf, info);
ice_ptp_set_funcs_e82x(pf, info);
}
/**
......@@ -2474,7 +2499,7 @@ void ice_ptp_reset(struct ice_pf *pf)
if (test_bit(ICE_PFR_REQ, pf->state))
goto pfr;
if (!hw->func_caps.ts_func_info.src_tmr_owned)
if (!ice_pf_src_tmr_owned(pf))
goto reset_ts;
err = ice_ptp_init_phc(hw);
......@@ -2685,14 +2710,22 @@ static int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp)
*/
static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port)
{
struct ice_hw *hw = &pf->hw;
mutex_init(&ptp_port->ps_lock);
if (ice_is_e810(&pf->hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_ptp_init_tx_e810(pf, &ptp_port->tx);
case ICE_PHY_E822:
kthread_init_delayed_work(&ptp_port->ov_work,
ice_ptp_wait_for_offsets);
kthread_init_delayed_work(&ptp_port->ov_work,
ice_ptp_wait_for_offsets);
return ice_ptp_init_tx_e822(pf, &ptp_port->tx, ptp_port->port_num);
return ice_ptp_init_tx_e822(pf, &ptp_port->tx,
ptp_port->port_num);
default:
return -ENODEV;
}
}
/**
......@@ -2713,10 +2746,12 @@ void ice_ptp_init(struct ice_pf *pf)
struct ice_hw *hw = &pf->hw;
int err;
ice_ptp_init_phy_model(hw);
/* If this function owns the clock hardware, it must allocate and
* configure the PTP clock device to represent it.
*/
if (hw->func_caps.ts_func_info.src_tmr_owned) {
if (ice_pf_src_tmr_owned(pf)) {
err = ice_ptp_init_owner(pf);
if (err)
goto err;
......
......@@ -233,7 +233,7 @@ static u64 ice_ptp_read_src_incval(struct ice_hw *hw)
*
* Prepare the source timer for an upcoming timer sync command.
*/
static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
{
u32 cmd_val;
u8 tmr_idx;
......@@ -242,19 +242,19 @@ static 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;
case ICE_PTP_NOP:
......@@ -294,9 +294,9 @@ ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
{
int phy_port, phy, quadtype;
phy_port = port % ICE_PORTS_PER_PHY;
phy = port / ICE_PORTS_PER_PHY;
quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;
phy_port = port % ICE_PORTS_PER_PHY_E822;
phy = port / ICE_PORTS_PER_PHY_E822;
quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E822;
if (quadtype == 0) {
msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
......@@ -621,20 +621,25 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
* Fill a message buffer for accessing a register in a quad shared between
* multiple PHYs.
*/
static void
static int
ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
{
u32 addr;
if (quad >= ICE_MAX_QUAD)
return -EINVAL;
msg->dest_dev = rmn_0;
if ((quad % ICE_NUM_QUAD_TYPE) == 0)
if ((quad % ICE_QUADS_PER_PHY_E822) == 0)
addr = Q_0_BASE + offset;
else
addr = Q_1_BASE + offset;
msg->msg_addr_low = lower_16_bits(addr);
msg->msg_addr_high = upper_16_bits(addr);
return 0;
}
/**
......@@ -653,10 +658,10 @@ ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
struct ice_sbq_msg_input msg = {0};
int err;
if (quad >= ICE_MAX_QUAD)
return -EINVAL;
err = ice_fill_quad_msg_e822(&msg, quad, offset);
if (err)
return err;
ice_fill_quad_msg_e822(&msg, quad, offset);
msg.opcode = ice_sbq_msg_rd;
err = ice_sbq_rw_reg(hw, &msg);
......@@ -687,10 +692,10 @@ ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
struct ice_sbq_msg_input msg = {0};
int err;
if (quad >= ICE_MAX_QUAD)
return -EINVAL;
err = ice_fill_quad_msg_e822(&msg, quad, offset);
if (err)
return err;
ice_fill_quad_msg_e822(&msg, quad, offset);
msg.opcode = ice_sbq_msg_wr;
msg.data = val;
......@@ -754,29 +759,32 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
* @quad: the quad to read from
* @idx: the timestamp index to reset
*
* Clear a timestamp, resetting its valid bit, from the PHY quad block that is
* shared between the internal PHYs on the E822 devices.
* Read the timestamp out of the quad to clear its timestamp status bit from
* the PHY quad block that is shared between the internal PHYs of the E822
* devices.
*
* Note that unlike E810, software cannot directly write to the quad memory
* bank registers. E822 relies on the ice_get_phy_tx_tstamp_ready() function
* to determine which timestamps are valid. Reading a timestamp auto-clears
* the valid bit.
*
* To directly clear the contents of the timestamp block entirely, discarding
* all timestamp data at once, software should instead use
* ice_ptp_reset_ts_memory_quad_e822().
*
* This function should only be called on an idx whose bit is set according to
* ice_get_phy_tx_tstamp_ready().
*/
static int
ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
{
u16 lo_addr, hi_addr;
u64 unused_tstamp;
int err;
lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
err);
return err;
}
err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
err = ice_read_phy_tstamp_e822(hw, quad, idx, &unused_tstamp);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
err);
ice_debug(hw, ICE_DBG_PTP, "Failed to read the timestamp register for quad %u, idx %u, err %d\n",
quad, idx, err);
return err;
}
......@@ -1151,7 +1159,7 @@ static int 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.
*/
......@@ -1200,7 +1208,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.
......@@ -1253,7 +1261,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 int
ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
......@@ -1288,7 +1296,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
*
* 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 int
ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
......@@ -1374,19 +1382,19 @@ ice_ptp_write_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 READ_TIME:
case ICE_PTP_READ_TIME:
cmd_val |= PHY_CMD_READ_TIME;
break;
case ADJ_TIME_AT_TIME:
case ICE_PTP_ADJ_TIME_AT_TIME:
cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
break;
case ICE_PTP_NOP:
......@@ -2322,8 +2330,8 @@ int ice_phy_cfg_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 int
ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
......@@ -2336,15 +2344,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 */
err = ice_ptp_one_port_cmd(hw, port, READ_TIME);
/* Prepare the PHY timer for a ICE_PTP_READ_TIME capture command */
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_READ_TIME);
if (err)
return err;
/* 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 */
......@@ -2378,10 +2386,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 int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
{
......@@ -2411,7 +2420,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
if (err)
goto err_unlock;
err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME);
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_ADJ_TIME);
if (err)
goto err_unlock;
......@@ -2534,7 +2543,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
if (err)
return err;
err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_INIT_INCVAL);
if (err)
return err;
......@@ -2562,7 +2571,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
if (err)
return err;
err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
err = ice_ptp_one_port_cmd(hw, port, ICE_PTP_INIT_INCVAL);
if (err)
return err;
......@@ -2811,28 +2820,39 @@ ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
* @lport: the lport to read from
* @idx: the timestamp index to reset
*
* Clear a timestamp, resetting its valid bit, from the timestamp block of the
* external PHY on the E810 device.
* Read the timestamp and then forcibly overwrite its value to clear the valid
* bit from the timestamp block of the external PHY on the E810 device.
*
* This function should only be called on an idx whose bit is set according to
* ice_get_phy_tx_tstamp_ready().
*/
static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
{
u32 lo_addr, hi_addr;
u64 unused_tstamp;
int err;
err = ice_read_phy_tstamp_e810(hw, lport, idx, &unused_tstamp);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read the timestamp register for lport %u, idx %u, err %d\n",
lport, idx, err);
return err;
}
lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
err = ice_write_phy_reg_e810(hw, lo_addr, 0);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
err);
ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register for lport %u, idx %u, err %d\n",
lport, idx, err);
return err;
}
err = ice_write_phy_reg_e810(hw, hi_addr, 0);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
err);
ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register for lport %u, idx %u, err %d\n",
lport, idx, err);
return err;
}
......@@ -2883,7 +2903,7 @@ static int 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.
......@@ -2918,7 +2938,7 @@ static int 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
......@@ -2958,7 +2978,7 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
*
* 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 int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
{
......@@ -3001,19 +3021,19 @@ static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
int err;
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 READ_TIME:
case ICE_PTP_READ_TIME:
cmd_val = GLTSYN_CMD_READ_TIME;
break;
case ADJ_TIME_AT_TIME:
case ICE_PTP_ADJ_TIME_AT_TIME:
cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
break;
case ICE_PTP_NOP:
......@@ -3275,6 +3295,21 @@ void ice_ptp_unlock(struct ice_hw *hw)
wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
}
/**
* ice_ptp_init_phy_model - Initialize hw->phy_model based on device type
* @hw: pointer to the HW structure
*
* Determine the PHY model for the device, and initialize hw->phy_model
* for use by other functions.
*/
void ice_ptp_init_phy_model(struct ice_hw *hw)
{
if (ice_is_e810(hw))
hw->phy_model = ICE_PHY_E810;
else
hw->phy_model = ICE_PHY_E822;
}
/**
* ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
* @hw: pointer to HW struct
......@@ -3293,10 +3328,17 @@ static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
ice_ptp_src_cmd(hw, cmd);
/* Next, prepare the ports */
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
err = ice_ptp_port_cmd_e810(hw, cmd);
else
break;
case ICE_PHY_E822:
err = ice_ptp_port_cmd_e822(hw, cmd);
break;
default:
err = -EOPNOTSUPP;
}
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n",
cmd, err);
......@@ -3338,14 +3380,21 @@ int ice_ptp_init_time(struct ice_hw *hw, u64 time)
/* PHY timers */
/* Fill Rx and Tx ports and send msg to PHY */
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
else
break;
case ICE_PHY_E822:
err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
break;
default:
err = -EOPNOTSUPP;
}
if (err)
return err;
return ice_ptp_tmr_cmd(hw, INIT_TIME);
return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_TIME);
}
/**
......@@ -3358,8 +3407,8 @@ int 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.
*/
int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
......@@ -3373,14 +3422,21 @@ int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
err = ice_ptp_prep_phy_incval_e810(hw, incval);
else
break;
case ICE_PHY_E822:
err = ice_ptp_prep_phy_incval_e822(hw, incval);
break;
default:
err = -EOPNOTSUPP;
}
if (err)
return err;
return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_INCVAL);
}
/**
......@@ -3414,8 +3470,8 @@ int 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.
*/
int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
{
......@@ -3425,21 +3481,28 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
/* Write the desired clock adjustment into the GLTSYN_SHADJ register.
* For an ADJ_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 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);
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
err = ice_ptp_prep_phy_adj_e810(hw, adj);
else
break;
case ICE_PHY_E822:
err = ice_ptp_prep_phy_adj_e822(hw, adj);
break;
default:
err = -EOPNOTSUPP;
}
if (err)
return err;
return ice_ptp_tmr_cmd(hw, ADJ_TIME);
return ice_ptp_tmr_cmd(hw, ICE_PTP_ADJ_TIME);
}
/**
......@@ -3455,10 +3518,14 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
*/
int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
{
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
else
case ICE_PHY_E822:
return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
default:
return -EOPNOTSUPP;
}
}
/**
......@@ -3467,16 +3534,26 @@ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
* @block: the block to read from
* @idx: the timestamp index to reset
*
* Clear a timestamp, resetting its valid bit, from the timestamp block. For
* E822 devices, the block is the quad to clear from. For E810 devices, the
* block is the logical port to clear from.
* Clear a timestamp from the timestamp block, discarding its value without
* returning it. This resets the memory status bit for the timestamp index
* allowing it to be reused for another timestamp in the future.
*
* For E822 devices, the block number is the PHY quad to clear from. For E810
* devices, the block number is the logical port to clear from.
*
* This function must only be called on a timestamp index whose valid bit is
* set according to ice_get_phy_tx_tstamp_ready().
*/
int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
{
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_clear_phy_tstamp_e810(hw, block, idx);
else
case ICE_PHY_E822:
return ice_clear_phy_tstamp_e822(hw, block, idx);
default:
return -EOPNOTSUPP;
}
}
/**
......@@ -3569,10 +3646,14 @@ int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx)
*/
void ice_ptp_reset_ts_memory(struct ice_hw *hw)
{
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E822:
ice_ptp_reset_ts_memory_e822(hw);
break;
case ICE_PHY_E810:
default:
return;
ice_ptp_reset_ts_memory_e822(hw);
}
}
/**
......@@ -3591,10 +3672,14 @@ int ice_ptp_init_phc(struct ice_hw *hw)
/* Clear event err indications for auxiliary pins */
(void)rd32(hw, GLTSYN_STAT(src_idx));
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_ptp_init_phc_e810(hw);
else
case ICE_PHY_E822:
return ice_ptp_init_phc_e822(hw);
default:
return -EOPNOTSUPP;
}
}
/**
......@@ -3610,12 +3695,17 @@ int ice_ptp_init_phc(struct ice_hw *hw)
*/
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
{
if (ice_is_e810(hw))
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_get_phy_tx_tstamp_ready_e810(hw, block,
tstamp_ready);
else
case ICE_PHY_E822:
return ice_get_phy_tx_tstamp_ready_e822(hw, block,
tstamp_ready);
break;
default:
return -EOPNOTSUPP;
}
}
/**
......
......@@ -6,11 +6,11 @@
#include <linux/dpll.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,
};
......@@ -203,6 +203,7 @@ extern const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD];
u8 ice_get_ptp_src_clock_index(struct ice_hw *hw);
bool ice_ptp_lock(struct ice_hw *hw);
void ice_ptp_unlock(struct ice_hw *hw);
void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd);
int ice_ptp_init_time(struct ice_hw *hw, u64 time);
int ice_ptp_write_incval(struct ice_hw *hw, u64 incval);
int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval);
......@@ -284,6 +285,8 @@ int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx,
enum dpll_lock_status *dpll_state);
int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num);
void ice_ptp_init_phy_model(struct ice_hw *hw);
#define PFTSYN_SEM_BYTES 4
#define ICE_PTP_CLOCK_INDEX_0 0x00
......
......@@ -822,6 +822,13 @@ struct ice_mbx_data {
u16 async_watermark_val;
};
/* PHY model */
enum ice_phy_model {
ICE_PHY_UNSUP = -1,
ICE_PHY_E810 = 1,
ICE_PHY_E822,
};
/* Port hardware description */
struct ice_hw {
u8 __iomem *hw_addr;
......@@ -843,6 +850,7 @@ struct ice_hw {
u8 revision_id;
u8 pf_id; /* device profile info */
enum ice_phy_model phy_model;
u16 max_burst_size; /* driver sets this value */
......@@ -901,13 +909,13 @@ struct ice_hw {
/* INTRL granularity in 1 us */
u8 intrl_gran;
#define ICE_PHY_PER_NAC 1
#define ICE_MAX_QUAD 2
#define ICE_NUM_QUAD_TYPE 2
#define ICE_PORTS_PER_QUAD 4
#define ICE_PHY_0_LAST_QUAD 1
#define ICE_PORTS_PER_PHY 8
#define ICE_NUM_EXTERNAL_PORTS ICE_PORTS_PER_PHY
#define ICE_PHY_PER_NAC_E822 1
#define ICE_MAX_QUAD 2
#define ICE_QUADS_PER_PHY_E822 2
#define ICE_PORTS_PER_PHY_E822 8
#define ICE_PORTS_PER_QUAD 4
#define ICE_PORTS_PER_PHY_E810 4
#define ICE_NUM_EXTERNAL_PORTS (ICE_MAX_QUAD * ICE_PORTS_PER_QUAD)
/* Active package version (currently active) */
struct ice_pkg_ver active_pkg_ver;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment