Skip to content

Commit faf9c27

Browse files
author
CKI KWF Bot
committed
Merge: ice: implement low latency PHY timer updates
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/830 JIRA: https://issues.redhat.com/browse/RHEL-74286 Patches implement low latency PHY timer updates. Signed-off-by: Petr Oros <poros@redhat.com> Approved-by: Michal Schmidt <mschmidt@redhat.com> Approved-by: mheib <mheib@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 6d49071 + 54f2668 commit faf9c27

File tree

5 files changed

+202
-34
lines changed

5 files changed

+202
-34
lines changed

drivers/net/ethernet/intel/ice/ice_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,6 +2600,7 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
26002600

26012601
info->ts_ll_read = ((number & ICE_TS_LL_TX_TS_READ_M) != 0);
26022602
info->ts_ll_int_read = ((number & ICE_TS_LL_TX_TS_INT_READ_M) != 0);
2603+
info->ll_phy_tmr_update = ((number & ICE_TS_LL_PHY_TMR_UPDATE_M) != 0);
26032604

26042605
info->ena_ports = logical_id;
26052606
info->tmr_own_map = phys_id;
@@ -2622,6 +2623,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
26222623
info->ts_ll_read);
26232624
ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_int_read = %u\n",
26242625
info->ts_ll_int_read);
2626+
ice_debug(hw, ICE_DBG_INIT, "dev caps: ll_phy_tmr_update = %u\n",
2627+
info->ll_phy_tmr_update);
26252628
ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",
26262629
info->ena_ports);
26272630
ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n",

drivers/net/ethernet/intel/ice/ice_ptp.c

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,9 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
464464
*/
465465
void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
466466
{
467+
struct ice_e810_params *params;
467468
struct ice_ptp_port *ptp_port;
469+
unsigned long flags;
468470
struct sk_buff *skb;
469471
struct ice_pf *pf;
470472

@@ -473,6 +475,7 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
473475

474476
ptp_port = container_of(tx, struct ice_ptp_port, tx);
475477
pf = ptp_port_to_pf(ptp_port);
478+
params = &pf->hw.ptp.phy.e810;
476479

477480
/* Drop packets which have waited for more than 2 seconds */
478481
if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
@@ -489,11 +492,17 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
489492

490493
ice_trace(tx_tstamp_fw_req, tx->tstamps[idx].skb, idx);
491494

495+
spin_lock_irqsave(&params->atqbal_wq.lock, flags);
496+
497+
params->atqbal_flags |= ATQBAL_FLAGS_INTR_IN_PROGRESS;
498+
492499
/* Write TS index to read to the PF register so the FW can read it */
493-
wr32(&pf->hw, PF_SB_ATQBAL,
494-
TS_LL_READ_TS_INTR | FIELD_PREP(TS_LL_READ_TS_IDX, idx) |
495-
TS_LL_READ_TS);
500+
wr32(&pf->hw, REG_LL_PROXY_H,
501+
REG_LL_PROXY_H_TS_INTR_ENA | FIELD_PREP(REG_LL_PROXY_H_TS_IDX, idx) |
502+
REG_LL_PROXY_H_EXEC);
496503
tx->last_ll_ts_idx_read = idx;
504+
505+
spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
497506
}
498507

499508
/**
@@ -504,35 +513,52 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
504513
{
505514
struct skb_shared_hwtstamps shhwtstamps = {};
506515
u8 idx = tx->last_ll_ts_idx_read;
516+
struct ice_e810_params *params;
507517
struct ice_ptp_port *ptp_port;
508518
u64 raw_tstamp, tstamp;
509519
bool drop_ts = false;
510520
struct sk_buff *skb;
521+
unsigned long flags;
522+
struct device *dev;
511523
struct ice_pf *pf;
512-
u32 val;
524+
u32 reg_ll_high;
513525

514526
if (!tx->init || tx->last_ll_ts_idx_read < 0)
515527
return;
516528

517529
ptp_port = container_of(tx, struct ice_ptp_port, tx);
518530
pf = ptp_port_to_pf(ptp_port);
531+
dev = ice_pf_to_dev(pf);
532+
params = &pf->hw.ptp.phy.e810;
519533

520534
ice_trace(tx_tstamp_fw_done, tx->tstamps[idx].skb, idx);
521535

522-
val = rd32(&pf->hw, PF_SB_ATQBAL);
536+
spin_lock_irqsave(&params->atqbal_wq.lock, flags);
537+
538+
if (!(params->atqbal_flags & ATQBAL_FLAGS_INTR_IN_PROGRESS))
539+
dev_dbg(dev, "%s: low latency interrupt request not in progress?\n",
540+
__func__);
541+
542+
/* Read the low 32 bit value */
543+
raw_tstamp = rd32(&pf->hw, REG_LL_PROXY_L);
544+
/* Read the status together with high TS part */
545+
reg_ll_high = rd32(&pf->hw, REG_LL_PROXY_H);
546+
547+
/* Wake up threads waiting on low latency interface */
548+
params->atqbal_flags &= ~ATQBAL_FLAGS_INTR_IN_PROGRESS;
549+
550+
wake_up_locked(&params->atqbal_wq);
551+
552+
spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
523553

524554
/* When the bit is cleared, the TS is ready in the register */
525-
if (val & TS_LL_READ_TS) {
555+
if (reg_ll_high & REG_LL_PROXY_H_EXEC) {
526556
dev_err(ice_pf_to_dev(pf), "Failed to get the Tx tstamp - FW not ready");
527557
return;
528558
}
529559

530560
/* High 8 bit value of the TS is on the bits 16:23 */
531-
raw_tstamp = FIELD_GET(TS_LL_READ_TS_HIGH, val);
532-
raw_tstamp <<= 32;
533-
534-
/* Read the low 32 bit value */
535-
raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH);
561+
raw_tstamp |= ((u64)FIELD_GET(REG_LL_PROXY_H_TS_HIGH, reg_ll_high)) << 32;
536562

537563
/* Devices using this interface always verify the timestamp differs
538564
* relative to the last cached timestamp value.

drivers/net/ethernet/intel/ice/ice_ptp_hw.c

Lines changed: 138 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4856,33 +4856,46 @@ static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
48564856
static int
48574857
ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
48584858
{
4859+
struct ice_e810_params *params = &hw->ptp.phy.e810;
4860+
unsigned long flags;
48594861
u32 val;
4860-
u8 i;
4862+
int err;
4863+
4864+
spin_lock_irqsave(&params->atqbal_wq.lock, flags);
4865+
4866+
/* Wait for any pending in-progress low latency interrupt */
4867+
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
4868+
!(params->atqbal_flags &
4869+
ATQBAL_FLAGS_INTR_IN_PROGRESS));
4870+
if (err) {
4871+
spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
4872+
return err;
4873+
}
48614874

48624875
/* Write TS index to read to the PF register so the FW can read it */
4863-
val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS;
4864-
wr32(hw, PF_SB_ATQBAL, val);
4876+
val = FIELD_PREP(REG_LL_PROXY_H_TS_IDX, idx) | REG_LL_PROXY_H_EXEC;
4877+
wr32(hw, REG_LL_PROXY_H, val);
48654878

48664879
/* Read the register repeatedly until the FW provides us the TS */
4867-
for (i = TS_LL_READ_RETRIES; i > 0; i--) {
4868-
val = rd32(hw, PF_SB_ATQBAL);
4880+
err = read_poll_timeout_atomic(rd32, val,
4881+
!FIELD_GET(REG_LL_PROXY_H_EXEC, val), 10,
4882+
REG_LL_PROXY_H_TIMEOUT_US, false, hw,
4883+
REG_LL_PROXY_H);
4884+
if (err) {
4885+
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
4886+
spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
4887+
return err;
4888+
}
48694889

4870-
/* When the bit is cleared, the TS is ready in the register */
4871-
if (!(FIELD_GET(TS_LL_READ_TS, val))) {
4872-
/* High 8 bit value of the TS is on the bits 16:23 */
4873-
*hi = FIELD_GET(TS_LL_READ_TS_HIGH, val);
4890+
/* High 8 bit value of the TS is on the bits 16:23 */
4891+
*hi = FIELD_GET(REG_LL_PROXY_H_TS_HIGH, val);
48744892

4875-
/* Read the low 32 bit value and set the TS valid bit */
4876-
*lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID;
4877-
return 0;
4878-
}
4893+
/* Read the low 32 bit value and set the TS valid bit */
4894+
*lo = rd32(hw, REG_LL_PROXY_L) | TS_VALID;
48794895

4880-
udelay(10);
4881-
}
4896+
spin_unlock_irqrestore(&params->atqbal_wq.lock, flags);
48824897

4883-
/* FW failed to provide the TS in time */
4884-
ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
4885-
return -EINVAL;
4898+
return 0;
48864899
}
48874900

48884901
/**
@@ -5064,6 +5077,55 @@ static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
50645077
return 0;
50655078
}
50665079

5080+
/**
5081+
* ice_ptp_prep_phy_adj_ll_e810 - Prep PHY ports for a time adjustment
5082+
* @hw: pointer to HW struct
5083+
* @adj: adjustment value to program
5084+
*
5085+
* Use the low latency firmware interface to program PHY time adjustment to
5086+
* all PHY ports.
5087+
*
5088+
* Return: 0 on success, -EBUSY on timeout
5089+
*/
5090+
static int ice_ptp_prep_phy_adj_ll_e810(struct ice_hw *hw, s32 adj)
5091+
{
5092+
const u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
5093+
struct ice_e810_params *params = &hw->ptp.phy.e810;
5094+
u32 val;
5095+
int err;
5096+
5097+
spin_lock_irq(&params->atqbal_wq.lock);
5098+
5099+
/* Wait for any pending in-progress low latency interrupt */
5100+
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
5101+
!(params->atqbal_flags &
5102+
ATQBAL_FLAGS_INTR_IN_PROGRESS));
5103+
if (err) {
5104+
spin_unlock_irq(&params->atqbal_wq.lock);
5105+
return err;
5106+
}
5107+
5108+
wr32(hw, REG_LL_PROXY_L, adj);
5109+
val = FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_CMD_M, REG_LL_PROXY_H_PHY_TMR_CMD_ADJ) |
5110+
FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_IDX_M, tmr_idx) | REG_LL_PROXY_H_EXEC;
5111+
wr32(hw, REG_LL_PROXY_H, val);
5112+
5113+
/* Read the register repeatedly until the FW indicates completion */
5114+
err = read_poll_timeout_atomic(rd32, val,
5115+
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
5116+
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
5117+
REG_LL_PROXY_H);
5118+
if (err) {
5119+
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
5120+
spin_unlock_irq(&params->atqbal_wq.lock);
5121+
return err;
5122+
}
5123+
5124+
spin_unlock_irq(&params->atqbal_wq.lock);
5125+
5126+
return 0;
5127+
}
5128+
50675129
/**
50685130
* ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
50695131
* @hw: pointer to HW struct
@@ -5082,6 +5144,9 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
50825144
u8 tmr_idx;
50835145
int err;
50845146

5147+
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
5148+
return ice_ptp_prep_phy_adj_ll_e810(hw, adj);
5149+
50855150
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
50865151

50875152
/* Adjustments are represented as signed 2's complement values in
@@ -5104,6 +5169,56 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
51045169
return 0;
51055170
}
51065171

5172+
/**
5173+
* ice_ptp_prep_phy_incval_ll_e810 - Prep PHY ports increment value change
5174+
* @hw: pointer to HW struct
5175+
* @incval: The new 40bit increment value to prepare
5176+
*
5177+
* Use the low latency firmware interface to program PHY time increment value
5178+
* for all PHY ports.
5179+
*
5180+
* Return: 0 on success, -EBUSY on timeout
5181+
*/
5182+
static int ice_ptp_prep_phy_incval_ll_e810(struct ice_hw *hw, u64 incval)
5183+
{
5184+
const u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
5185+
struct ice_e810_params *params = &hw->ptp.phy.e810;
5186+
u32 val;
5187+
int err;
5188+
5189+
spin_lock_irq(&params->atqbal_wq.lock);
5190+
5191+
/* Wait for any pending in-progress low latency interrupt */
5192+
err = wait_event_interruptible_locked_irq(params->atqbal_wq,
5193+
!(params->atqbal_flags &
5194+
ATQBAL_FLAGS_INTR_IN_PROGRESS));
5195+
if (err) {
5196+
spin_unlock_irq(&params->atqbal_wq.lock);
5197+
return err;
5198+
}
5199+
5200+
wr32(hw, REG_LL_PROXY_L, lower_32_bits(incval));
5201+
val = FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_CMD_M, REG_LL_PROXY_H_PHY_TMR_CMD_FREQ) |
5202+
FIELD_PREP(REG_LL_PROXY_H_TS_HIGH, (u8)upper_32_bits(incval)) |
5203+
FIELD_PREP(REG_LL_PROXY_H_PHY_TMR_IDX_M, tmr_idx) | REG_LL_PROXY_H_EXEC;
5204+
wr32(hw, REG_LL_PROXY_H, val);
5205+
5206+
/* Read the register repeatedly until the FW indicates completion */
5207+
err = read_poll_timeout_atomic(rd32, val,
5208+
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
5209+
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
5210+
REG_LL_PROXY_H);
5211+
if (err) {
5212+
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
5213+
spin_unlock_irq(&params->atqbal_wq.lock);
5214+
return err;
5215+
}
5216+
5217+
spin_unlock_irq(&params->atqbal_wq.lock);
5218+
5219+
return 0;
5220+
}
5221+
51075222
/**
51085223
* ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
51095224
* @hw: pointer to HW struct
@@ -5119,6 +5234,9 @@ static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
51195234
u8 tmr_idx;
51205235
int err;
51215236

5237+
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
5238+
return ice_ptp_prep_phy_incval_ll_e810(hw, incval);
5239+
51225240
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
51235241
low = lower_32_bits(incval);
51245242
high = upper_32_bits(incval);
@@ -5403,6 +5521,8 @@ static void ice_ptp_init_phy_e810(struct ice_ptp_hw *ptp)
54035521
ptp->phy_model = ICE_PHY_E810;
54045522
ptp->num_lports = 8;
54055523
ptp->ports_per_phy = 4;
5524+
5525+
init_waitqueue_head(&ptp->phy.e810.atqbal_wq);
54065526
}
54075527

54085528
/* Device agnostic functions

drivers/net/ethernet/intel/ice/ice_ptp_hw.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -693,11 +693,18 @@ static inline bool ice_is_dual(struct ice_hw *hw)
693693
#define BYTES_PER_IDX_ADDR_L 4
694694

695695
/* Tx timestamp low latency read definitions */
696-
#define TS_LL_READ_RETRIES 200
697-
#define TS_LL_READ_TS_HIGH GENMASK(23, 16)
698-
#define TS_LL_READ_TS_IDX GENMASK(29, 24)
699-
#define TS_LL_READ_TS_INTR BIT(30)
700-
#define TS_LL_READ_TS BIT(31)
696+
#define REG_LL_PROXY_H_TIMEOUT_US 2000
697+
#define REG_LL_PROXY_H_PHY_TMR_CMD_M GENMASK(7, 6)
698+
#define REG_LL_PROXY_H_PHY_TMR_CMD_ADJ 0x1
699+
#define REG_LL_PROXY_H_PHY_TMR_CMD_FREQ 0x2
700+
#define REG_LL_PROXY_H_TS_HIGH GENMASK(23, 16)
701+
#define REG_LL_PROXY_H_PHY_TMR_IDX_M BIT(24)
702+
#define REG_LL_PROXY_H_TS_IDX GENMASK(29, 24)
703+
#define REG_LL_PROXY_H_TS_INTR_ENA BIT(30)
704+
#define REG_LL_PROXY_H_EXEC BIT(31)
705+
706+
#define REG_LL_PROXY_L PF_SB_ATQBAH
707+
#define REG_LL_PROXY_H PF_SB_ATQBAL
701708

702709
/* Internal PHY timestamp address */
703710
#define TS_L(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U))

drivers/net/ethernet/intel/ice/ice_type.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "ice_sbq_cmd.h"
1919
#include "ice_vlan_mode.h"
2020
#include "ice_fwlog.h"
21+
#include <linux/wait.h>
2122

2223
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
2324
{
@@ -368,6 +369,7 @@ struct ice_ts_func_info {
368369
#define ICE_TS_TMR1_ENA_M BIT(26)
369370
#define ICE_TS_LL_TX_TS_READ_M BIT(28)
370371
#define ICE_TS_LL_TX_TS_INT_READ_M BIT(29)
372+
#define ICE_TS_LL_PHY_TMR_UPDATE_M BIT(30)
371373

372374
struct ice_ts_dev_info {
373375
/* Device specific info */
@@ -382,6 +384,7 @@ struct ice_ts_dev_info {
382384
u8 tmr1_ena;
383385
u8 ts_ll_read;
384386
u8 ts_ll_int_read;
387+
u8 ll_phy_tmr_update;
385388
};
386389

387390
#define ICE_NAC_TOPO_PRIMARY_M BIT(0)
@@ -848,6 +851,14 @@ struct ice_mbx_data {
848851
#define ICE_PORTS_PER_QUAD 4
849852
#define ICE_GET_QUAD_NUM(port) ((port) / ICE_PORTS_PER_QUAD)
850853

854+
#define ATQBAL_FLAGS_INTR_IN_PROGRESS BIT(0)
855+
856+
struct ice_e810_params {
857+
/* The wait queue lock also protects the low latency interface */
858+
wait_queue_head_t atqbal_wq;
859+
unsigned int atqbal_flags;
860+
};
861+
851862
struct ice_eth56g_params {
852863
u8 num_phys;
853864
u8 phy_addr[2];
@@ -857,6 +868,7 @@ struct ice_eth56g_params {
857868
};
858869

859870
union ice_phy_params {
871+
struct ice_e810_params e810;
860872
struct ice_eth56g_params eth56g;
861873
};
862874

0 commit comments

Comments
 (0)