Skip to content

Commit 7083893

Browse files
ansamalintelkuba-moo
authored andcommitted
ice: Implement driver functionality to dump serdes equalizer values
To debug link issues in the field, serdes Tx/Rx equalizer values help to determine the health of serdes lane. Extend 'ethtool -d' option to dump serdes Tx/Rx equalizer. The following list of equalizer param is supported a. rx_equalization_pre2 b. rx_equalization_pre1 c. rx_equalization_post1 d. rx_equalization_bflf e. rx_equalization_bfhf f. rx_equalization_drate g. tx_equalization_pre1 h. tx_equalization_pre3 i. tx_equalization_atten j. tx_equalization_post1 k. tx_equalization_pre2 Reviewed-by: Simon Horman <[email protected]> Reviewed-by: Jesse Brandeburg <[email protected]> Signed-off-by: Anil Samal <[email protected]> Tested-by: Pucha Himasekhar Reddy <[email protected]> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ac21add commit 7083893

File tree

5 files changed

+245
-2
lines changed

5 files changed

+245
-2
lines changed

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,55 @@ struct ice_aqc_get_sensor_reading_resp {
14611461
} data;
14621462
};
14631463

1464+
/* DNL call command (indirect 0x0682)
1465+
* Struct is used for both command and response
1466+
*/
1467+
struct ice_aqc_dnl_call_command {
1468+
u8 ctx; /* Used in command, reserved in response */
1469+
u8 reserved;
1470+
__le16 activity_id;
1471+
#define ICE_AQC_ACT_ID_DNL 0x1129
1472+
__le32 reserved1;
1473+
__le32 addr_high;
1474+
__le32 addr_low;
1475+
};
1476+
1477+
struct ice_aqc_dnl_equa_param {
1478+
__le16 data_in;
1479+
#define ICE_AQC_RX_EQU_SHIFT 8
1480+
#define ICE_AQC_RX_EQU_PRE2 (0x10 << ICE_AQC_RX_EQU_SHIFT)
1481+
#define ICE_AQC_RX_EQU_PRE1 (0x11 << ICE_AQC_RX_EQU_SHIFT)
1482+
#define ICE_AQC_RX_EQU_POST1 (0x12 << ICE_AQC_RX_EQU_SHIFT)
1483+
#define ICE_AQC_RX_EQU_BFLF (0x13 << ICE_AQC_RX_EQU_SHIFT)
1484+
#define ICE_AQC_RX_EQU_BFHF (0x14 << ICE_AQC_RX_EQU_SHIFT)
1485+
#define ICE_AQC_RX_EQU_DRATE (0x15 << ICE_AQC_RX_EQU_SHIFT)
1486+
#define ICE_AQC_TX_EQU_PRE1 0x0
1487+
#define ICE_AQC_TX_EQU_PRE3 0x3
1488+
#define ICE_AQC_TX_EQU_ATTEN 0x4
1489+
#define ICE_AQC_TX_EQU_POST1 0x8
1490+
#define ICE_AQC_TX_EQU_PRE2 0xC
1491+
__le16 op_code_serdes_sel;
1492+
#define ICE_AQC_OP_CODE_SHIFT 4
1493+
#define ICE_AQC_OP_CODE_RX_EQU (0x9 << ICE_AQC_OP_CODE_SHIFT)
1494+
#define ICE_AQC_OP_CODE_TX_EQU (0x10 << ICE_AQC_OP_CODE_SHIFT)
1495+
__le32 reserved[3];
1496+
};
1497+
1498+
struct ice_aqc_dnl_equa_respon {
1499+
/* Equalization value can be negative */
1500+
int val;
1501+
__le32 reserved[3];
1502+
};
1503+
1504+
/* DNL call command/response buffer (indirect 0x0682) */
1505+
struct ice_aqc_dnl_call {
1506+
union {
1507+
struct ice_aqc_dnl_equa_param txrx_equa_reqs;
1508+
__le32 stores[4];
1509+
struct ice_aqc_dnl_equa_respon txrx_equa_resp;
1510+
} sto;
1511+
};
1512+
14641513
struct ice_aqc_link_topo_params {
14651514
u8 lport_num;
14661515
u8 lport_num_valid;
@@ -2564,6 +2613,7 @@ struct ice_aq_desc {
25642613
struct ice_aqc_get_link_status get_link_status;
25652614
struct ice_aqc_event_lan_overflow lan_overflow;
25662615
struct ice_aqc_get_link_topo get_link_topo;
2616+
struct ice_aqc_dnl_call_command dnl_call;
25672617
struct ice_aqc_i2c read_write_i2c;
25682618
struct ice_aqc_read_i2c_resp read_i2c_resp;
25692619
struct ice_aqc_get_set_tx_topo get_set_tx_topo;
@@ -2688,6 +2738,7 @@ enum ice_adminq_opc {
26882738
ice_aqc_opc_set_phy_rec_clk_out = 0x0630,
26892739
ice_aqc_opc_get_phy_rec_clk_out = 0x0631,
26902740
ice_aqc_opc_get_sensor_reading = 0x0632,
2741+
ice_aqc_opc_dnl_call = 0x0682,
26912742
ice_aqc_opc_get_link_topo = 0x06E0,
26922743
ice_aqc_opc_read_i2c = 0x06E2,
26932744
ice_aqc_opc_write_i2c = 0x06E3,

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,6 +3371,43 @@ int ice_update_link_info(struct ice_port_info *pi)
33713371
return status;
33723372
}
33733373

3374+
/**
3375+
* ice_aq_get_phy_equalization - function to read serdes equaliser
3376+
* value from firmware using admin queue command.
3377+
* @hw: pointer to the HW struct
3378+
* @data_in: represents the serdes equalization parameter requested
3379+
* @op_code: represents the serdes number and flag to represent tx or rx
3380+
* @serdes_num: represents the serdes number
3381+
* @output: pointer to the caller-supplied buffer to return serdes equaliser
3382+
*
3383+
* Return: non-zero status on error and 0 on success.
3384+
*/
3385+
int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
3386+
u8 serdes_num, int *output)
3387+
{
3388+
struct ice_aqc_dnl_call_command *cmd;
3389+
struct ice_aqc_dnl_call buf = {};
3390+
struct ice_aq_desc desc;
3391+
int err;
3392+
3393+
buf.sto.txrx_equa_reqs.data_in = cpu_to_le16(data_in);
3394+
buf.sto.txrx_equa_reqs.op_code_serdes_sel =
3395+
cpu_to_le16(op_code | (serdes_num & 0xF));
3396+
cmd = &desc.params.dnl_call;
3397+
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dnl_call);
3398+
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_BUF |
3399+
ICE_AQ_FLAG_RD |
3400+
ICE_AQ_FLAG_SI);
3401+
desc.datalen = cpu_to_le16(sizeof(struct ice_aqc_dnl_call));
3402+
cmd->activity_id = cpu_to_le16(ICE_AQC_ACT_ID_DNL);
3403+
3404+
err = ice_aq_send_cmd(hw, &desc, &buf, sizeof(struct ice_aqc_dnl_call),
3405+
NULL);
3406+
*output = err ? 0 : buf.sto.txrx_equa_resp.val;
3407+
3408+
return err;
3409+
}
3410+
33743411
#define FEC_REG_PORT(port) { \
33753412
FEC_CORR_LOW_REG_PORT##port, \
33763413
FEC_CORR_HIGH_REG_PORT##port, \

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ int
142142
ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
143143
struct ice_port_info *pi);
144144
bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);
145+
int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
146+
u8 serdes_num, int *output);
145147
int
146148
ice_aq_get_fec_stats(struct ice_hw *hw, u16 pcs_quad, u16 pcs_port,
147149
enum ice_fec_stats_types fec_type, u32 *output);

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

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,8 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
463463

464464
static int ice_get_regs_len(struct net_device __always_unused *netdev)
465465
{
466-
return sizeof(ice_regs_dump_list);
466+
return (sizeof(ice_regs_dump_list) +
467+
sizeof(struct ice_regdump_to_ethtool));
467468
}
468469

469470
/**
@@ -681,6 +682,137 @@ static int ice_get_port_topology(struct ice_hw *hw, u8 lport,
681682
return 0;
682683
}
683684

685+
/**
686+
* ice_get_tx_rx_equa - read serdes tx rx equaliser param
687+
* @hw: pointer to the HW struct
688+
* @serdes_num: represents the serdes number
689+
* @ptr: structure to read all serdes parameter for given serdes
690+
*
691+
* Return: all serdes equalization parameter supported per serdes number
692+
*/
693+
static int ice_get_tx_rx_equa(struct ice_hw *hw, u8 serdes_num,
694+
struct ice_serdes_equalization_to_ethtool *ptr)
695+
{
696+
int err;
697+
698+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE1,
699+
ICE_AQC_OP_CODE_TX_EQU, serdes_num,
700+
&ptr->tx_equalization_pre1);
701+
if (err)
702+
return err;
703+
704+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE3,
705+
ICE_AQC_OP_CODE_TX_EQU, serdes_num,
706+
&ptr->tx_equalization_pre3);
707+
if (err)
708+
return err;
709+
710+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_ATTEN,
711+
ICE_AQC_OP_CODE_TX_EQU, serdes_num,
712+
&ptr->tx_equalization_atten);
713+
if (err)
714+
return err;
715+
716+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_POST1,
717+
ICE_AQC_OP_CODE_TX_EQU, serdes_num,
718+
&ptr->tx_equalization_post1);
719+
if (err)
720+
return err;
721+
722+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE2,
723+
ICE_AQC_OP_CODE_TX_EQU, serdes_num,
724+
&ptr->tx_equalization_pre2);
725+
if (err)
726+
return err;
727+
728+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE2,
729+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
730+
&ptr->rx_equalization_pre2);
731+
if (err)
732+
return err;
733+
734+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE1,
735+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
736+
&ptr->rx_equalization_pre1);
737+
if (err)
738+
return err;
739+
740+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_POST1,
741+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
742+
&ptr->rx_equalization_post1);
743+
if (err)
744+
return err;
745+
746+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFLF,
747+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
748+
&ptr->rx_equalization_bflf);
749+
if (err)
750+
return err;
751+
752+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFHF,
753+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
754+
&ptr->rx_equalization_bfhf);
755+
if (err)
756+
return err;
757+
758+
err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_DRATE,
759+
ICE_AQC_OP_CODE_RX_EQU, serdes_num,
760+
&ptr->rx_equalization_drate);
761+
if (err)
762+
return err;
763+
764+
return 0;
765+
}
766+
767+
/**
768+
* ice_get_extended_regs - returns FEC correctable, uncorrectable stats per
769+
* pcsquad, pcsport
770+
* @netdev: pointer to net device structure
771+
* @p: output buffer to fill requested register dump
772+
*
773+
* Return: 0 on success, negative on failure.
774+
*/
775+
static int ice_get_extended_regs(struct net_device *netdev, void *p)
776+
{
777+
struct ice_netdev_priv *np = netdev_priv(netdev);
778+
struct ice_regdump_to_ethtool *ice_prv_regs_buf;
779+
struct ice_port_topology port_topology = {};
780+
struct ice_port_info *pi;
781+
struct ice_pf *pf;
782+
struct ice_hw *hw;
783+
unsigned int i;
784+
int err;
785+
786+
pf = np->vsi->back;
787+
hw = &pf->hw;
788+
pi = np->vsi->port_info;
789+
790+
/* Serdes parameters are not supported if not the PF VSI */
791+
if (np->vsi->type != ICE_VSI_PF || !pi)
792+
return -EINVAL;
793+
794+
err = ice_get_port_topology(hw, pi->lport, &port_topology);
795+
if (err)
796+
return -EINVAL;
797+
if (port_topology.serdes_lane_count > 4)
798+
return -EINVAL;
799+
800+
ice_prv_regs_buf = p;
801+
802+
/* Get serdes equalization parameter for available serdes */
803+
for (i = 0; i < port_topology.serdes_lane_count; i++) {
804+
u8 serdes_num = 0;
805+
806+
serdes_num = port_topology.primary_serdes_lane + i;
807+
err = ice_get_tx_rx_equa(hw, serdes_num,
808+
&ice_prv_regs_buf->equalization[i]);
809+
if (err)
810+
return -EINVAL;
811+
}
812+
813+
return 0;
814+
}
815+
684816
static void
685817
ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
686818
{
@@ -690,10 +822,12 @@ ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
690822
u32 *regs_buf = (u32 *)p;
691823
unsigned int i;
692824

693-
regs->version = 1;
825+
regs->version = 2;
694826

695827
for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i)
696828
regs_buf[i] = rd32(hw, ice_regs_dump_list[i]);
829+
830+
ice_get_extended_regs(netdev, (void *)&regs_buf[i]);
697831
}
698832

699833
static u32 ice_get_msglevel(struct net_device *netdev)

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,25 @@ struct ice_phy_type_to_ethtool {
99
u8 link_mode;
1010
};
1111

12+
struct ice_serdes_equalization_to_ethtool {
13+
int rx_equalization_pre2;
14+
int rx_equalization_pre1;
15+
int rx_equalization_post1;
16+
int rx_equalization_bflf;
17+
int rx_equalization_bfhf;
18+
int rx_equalization_drate;
19+
int tx_equalization_pre1;
20+
int tx_equalization_pre3;
21+
int tx_equalization_atten;
22+
int tx_equalization_post1;
23+
int tx_equalization_pre2;
24+
};
25+
26+
struct ice_regdump_to_ethtool {
27+
/* A multilane port can have max 4 serdes */
28+
struct ice_serdes_equalization_to_ethtool equalization[4];
29+
};
30+
1231
/* Port topology from lport i.e.
1332
* serdes mapping, pcsquad, macport, cage etc...
1433
*/

0 commit comments

Comments
 (0)