Merge branch 'Add-ethtool-extended-link-state'
Ido Schimmel says: ==================== Add ethtool extended link state Amit says: Currently, device drivers can only indicate to user space if the network link is up or down, without additional information. This patch set provides an infrastructure that allows these drivers to expose more information to user space about the link state. The information can save users' time when trying to understand why a link is not operationally up, for example. The above is achieved by extending the existing ethtool LINKSTATE_GET command with attributes that carry the extended state. For example, no link due to missing cable: $ ethtool ethX ... Link detected: no (No cable) Beside the general extended state, drivers can pass additional information about the link state using the sub-state field. For example: $ ethtool ethX ... Link detected: no (Autoneg, No partner detected) In the future the infrastructure can be extended - for example - to allow PHY drivers to report whether a downshift to a lower speed occurred. Something like: $ ethtool ethX ... Link detected: yes (downshifted) Patch set overview: Patches #1-#3 move mlxsw ethtool code to a separate file Patches #4-#5 add the ethtool infrastructure for extended link state Patches #6-#7 add support of extended link state in the mlxsw driver Patches #8-#10 add test cases Changes since v1: * In documentation, show ETHTOOL_LINK_EXT_STATE_* and ETHTOOL_LINK_EXT_SUBSTATE_* constants instead of user-space strings * Add `_CI_` to cable_issue substates to be consistent with other substates * Keep the commit messages within 75 columns * Use u8 variable for __link_ext_substate * Document the meaning of -ENODATA in get_link_ext_state() callback description * Do not zero data->link_ext_state_provided after getting an error * Use `ret` variable for error value Changes since RFC: * Move documentation patch before ethtool patch * Add nla_total_size() instead of sizeof() directly * Return an error code from linkstate_get_ext_state() * Remove SHORTED_CABLE, add CABLE_TEST_FAILURE instead * Check if the interface is administratively up before setting ext_state * Document all sub-states ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
2dac017dbd
|
@ -443,10 +443,11 @@ supports.
|
|||
LINKSTATE_GET
|
||||
=============
|
||||
|
||||
Requests link state information. At the moment, only link up/down flag (as
|
||||
provided by ``ETHTOOL_GLINK`` ioctl command) is provided but some future
|
||||
extensions are planned (e.g. link down reason). This request does not have any
|
||||
attributes.
|
||||
Requests link state information. Link up/down flag (as provided by
|
||||
``ETHTOOL_GLINK`` ioctl command) is provided. Optionally, extended state might
|
||||
be provided as well. In general, extended state describes reasons for why a port
|
||||
is down, or why it operates in some non-obvious mode. This request does not have
|
||||
any attributes.
|
||||
|
||||
Request contents:
|
||||
|
||||
|
@ -461,16 +462,135 @@ Kernel response contents:
|
|||
``ETHTOOL_A_LINKSTATE_LINK`` bool link state (up/down)
|
||||
``ETHTOOL_A_LINKSTATE_SQI`` u32 Current Signal Quality Index
|
||||
``ETHTOOL_A_LINKSTATE_SQI_MAX`` u32 Max support SQI value
|
||||
``ETHTOOL_A_LINKSTATE_EXT_STATE`` u8 link extended state
|
||||
``ETHTOOL_A_LINKSTATE_EXT_SUBSTATE`` u8 link extended substate
|
||||
==================================== ====== ============================
|
||||
|
||||
For most NIC drivers, the value of ``ETHTOOL_A_LINKSTATE_LINK`` returns
|
||||
carrier flag provided by ``netif_carrier_ok()`` but there are drivers which
|
||||
define their own handler.
|
||||
|
||||
``ETHTOOL_A_LINKSTATE_EXT_STATE`` and ``ETHTOOL_A_LINKSTATE_EXT_SUBSTATE`` are
|
||||
optional values. ethtool core can provide either both
|
||||
``ETHTOOL_A_LINKSTATE_EXT_STATE`` and ``ETHTOOL_A_LINKSTATE_EXT_SUBSTATE``,
|
||||
or only ``ETHTOOL_A_LINKSTATE_EXT_STATE``, or none of them.
|
||||
|
||||
``LINKSTATE_GET`` allows dump requests (kernel returns reply messages for all
|
||||
devices supporting the request).
|
||||
|
||||
|
||||
Link extended states:
|
||||
|
||||
================================================ ============================================
|
||||
``ETHTOOL_LINK_EXT_STATE_AUTONEG`` States relating to the autonegotiation or
|
||||
issues therein
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE`` Failure during link training
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH`` Logical mismatch in physical coding sublayer
|
||||
or forward error correction sublayer
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY`` Signal integrity issues
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_NO_CABLE`` No cable connected
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE`` Failure is related to cable,
|
||||
e.g., unsupported cable
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE`` Failure is related to EEPROM, e.g., failure
|
||||
during reading or parsing the data
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE`` Failure during calibration algorithm
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED`` The hardware is not able to provide the
|
||||
power required from cable or module
|
||||
|
||||
``ETHTOOL_LINK_EXT_STATE_OVERHEAT`` The module is overheated
|
||||
================================================= ============================================
|
||||
|
||||
Link extended substates:
|
||||
|
||||
Autoneg substates:
|
||||
|
||||
============================================================== ================================
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED`` Peer side is down
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED`` Ack not received from peer side
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED`` Next page exchange failed
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE`` Peer side is down during force
|
||||
mode or there is no agreement of
|
||||
speed
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE`` Forward error correction modes
|
||||
in both sides are mismatched
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD`` No Highest Common Denominator
|
||||
============================================================== ================================
|
||||
|
||||
Link training substates:
|
||||
|
||||
========================================================================== ====================
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED`` Frames were not
|
||||
recognized, the
|
||||
lock failed
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT`` The lock did not
|
||||
occur before
|
||||
timeout
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY`` Peer side did not
|
||||
send ready signal
|
||||
after training
|
||||
process
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT`` Remote side is not
|
||||
ready yet
|
||||
========================================================================== ====================
|
||||
|
||||
Link logical mismatch substates:
|
||||
|
||||
=============================================================== ===============================
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK`` Physical coding sublayer was
|
||||
not locked in first phase -
|
||||
block lock
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK`` Physical coding sublayer was
|
||||
not locked in second phase -
|
||||
alignment markers lock
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS`` Physical coding sublayer did
|
||||
not get align status
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED`` FC forward error correction is
|
||||
not locked
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED`` RS forward error correction is
|
||||
not locked
|
||||
=============================================================== ===============================
|
||||
|
||||
Bad signal integrity substates:
|
||||
|
||||
================================================================= =============================
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS`` Large number of physical
|
||||
errors
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE`` The system attempted to
|
||||
operate the cable at a rate
|
||||
that is not formally
|
||||
supported, which led to
|
||||
signal integrity issues
|
||||
================================================================= =============================
|
||||
|
||||
Cable issue substates:
|
||||
|
||||
================================================== ============================================
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE`` Unsupported cable
|
||||
|
||||
``ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE`` Cable test failure
|
||||
================================================== ============================================
|
||||
|
||||
DEBUG_GET
|
||||
=========
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
|
|||
spectrum_mr_tcam.o spectrum_mr.o \
|
||||
spectrum_qdisc.o spectrum_span.o \
|
||||
spectrum_nve.o spectrum_nve_vxlan.o \
|
||||
spectrum_dpipe.o spectrum_trap.o
|
||||
spectrum_dpipe.o spectrum_trap.o \
|
||||
spectrum_ethtool.o
|
||||
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
|
||||
mlxsw_spectrum-$(CONFIG_PTP_1588_CLOCK) += spectrum_ptp.o
|
||||
obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o
|
||||
|
|
|
@ -5438,6 +5438,56 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port,
|
|||
MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0);
|
||||
}
|
||||
|
||||
/* PDDR - Port Diagnostics Database Register
|
||||
* -----------------------------------------
|
||||
* The PDDR enables to read the Phy debug database
|
||||
*/
|
||||
#define MLXSW_REG_PDDR_ID 0x5031
|
||||
#define MLXSW_REG_PDDR_LEN 0x100
|
||||
|
||||
MLXSW_REG_DEFINE(pddr, MLXSW_REG_PDDR_ID, MLXSW_REG_PDDR_LEN);
|
||||
|
||||
/* reg_pddr_local_port
|
||||
* Local port number.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pddr, local_port, 0x00, 16, 8);
|
||||
|
||||
enum mlxsw_reg_pddr_page_select {
|
||||
MLXSW_REG_PDDR_PAGE_SELECT_TROUBLESHOOTING_INFO = 1,
|
||||
};
|
||||
|
||||
/* reg_pddr_page_select
|
||||
* Page select index.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pddr, page_select, 0x04, 0, 8);
|
||||
|
||||
enum mlxsw_reg_pddr_trblsh_group_opcode {
|
||||
/* Monitor opcodes */
|
||||
MLXSW_REG_PDDR_TRBLSH_GROUP_OPCODE_MONITOR,
|
||||
};
|
||||
|
||||
/* reg_pddr_group_opcode
|
||||
* Group selector.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pddr, trblsh_group_opcode, 0x08, 0, 16);
|
||||
|
||||
/* reg_pddr_status_opcode
|
||||
* Group selector.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pddr, trblsh_status_opcode, 0x0C, 0, 16);
|
||||
|
||||
static inline void mlxsw_reg_pddr_pack(char *payload, u8 local_port,
|
||||
u8 page_select)
|
||||
{
|
||||
MLXSW_REG_ZERO(pddr, payload);
|
||||
mlxsw_reg_pddr_local_port_set(payload, local_port);
|
||||
mlxsw_reg_pddr_page_select_set(payload, page_select);
|
||||
}
|
||||
|
||||
/* PMTM - Port Module Type Mapping Register
|
||||
* ----------------------------------------
|
||||
* The PMTM allows query or configuration of module types.
|
||||
|
@ -10758,6 +10808,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
|
|||
MLXSW_REG(pbmc),
|
||||
MLXSW_REG(pspa),
|
||||
MLXSW_REG(pplr),
|
||||
MLXSW_REG(pddr),
|
||||
MLXSW_REG(pmtm),
|
||||
MLXSW_REG(htgt),
|
||||
MLXSW_REG(hpkt),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -178,6 +178,39 @@ struct mlxsw_sp {
|
|||
u32 lowest_shaper_bs;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_ptp_ops {
|
||||
struct mlxsw_sp_ptp_clock *
|
||||
(*clock_init)(struct mlxsw_sp *mlxsw_sp, struct device *dev);
|
||||
void (*clock_fini)(struct mlxsw_sp_ptp_clock *clock);
|
||||
|
||||
struct mlxsw_sp_ptp_state *(*init)(struct mlxsw_sp *mlxsw_sp);
|
||||
void (*fini)(struct mlxsw_sp_ptp_state *ptp_state);
|
||||
|
||||
/* Notify a driver that a packet that might be PTP was received. Driver
|
||||
* is responsible for freeing the passed-in SKB.
|
||||
*/
|
||||
void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
|
||||
u8 local_port);
|
||||
|
||||
/* Notify a driver that a timestamped packet was transmitted. Driver
|
||||
* is responsible for freeing the passed-in SKB.
|
||||
*/
|
||||
void (*transmitted)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
|
||||
u8 local_port);
|
||||
|
||||
int (*hwtstamp_get)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct hwtstamp_config *config);
|
||||
int (*hwtstamp_set)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct hwtstamp_config *config);
|
||||
void (*shaper_work)(struct work_struct *work);
|
||||
int (*get_ts_info)(struct mlxsw_sp *mlxsw_sp,
|
||||
struct ethtool_ts_info *info);
|
||||
int (*get_stats_count)(void);
|
||||
void (*get_stats_strings)(u8 **p);
|
||||
void (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u64 *data, int data_index);
|
||||
};
|
||||
|
||||
static inline struct mlxsw_sp_upper *
|
||||
mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
|
||||
{
|
||||
|
@ -393,6 +426,13 @@ enum mlxsw_sp_flood_type {
|
|||
MLXSW_SP_FLOOD_TYPE_MC,
|
||||
};
|
||||
|
||||
int mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
int mtu, bool pause_en);
|
||||
int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
|
||||
int prio, char *ppcnt_pl);
|
||||
int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
bool is_up);
|
||||
|
||||
/* spectrum_buffers.c */
|
||||
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp);
|
||||
void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp);
|
||||
|
@ -1126,4 +1166,9 @@ static inline struct net *mlxsw_sp_net(struct mlxsw_sp *mlxsw_sp)
|
|||
return mlxsw_core_net(mlxsw_sp->core);
|
||||
}
|
||||
|
||||
/* spectrum_ethtool.c */
|
||||
extern const struct ethtool_ops mlxsw_sp_port_ethtool_ops;
|
||||
extern const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops;
|
||||
extern const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -110,8 +110,8 @@ static int mlxsw_sp_port_pg_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct ieee_ets *ets)
|
||||
static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct ieee_ets *ets)
|
||||
{
|
||||
bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
|
||||
struct ieee_ets *my_ets = mlxsw_sp_port->dcb.ets;
|
||||
|
@ -180,7 +180,7 @@ static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
}
|
||||
|
||||
/* Ingress configuration. */
|
||||
err = mlxsw_sp_port_headroom_set(mlxsw_sp_port, ets);
|
||||
err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets);
|
||||
if (err)
|
||||
goto err_port_headroom_set;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -86,6 +86,22 @@ struct net_device;
|
|||
u32 ethtool_op_get_link(struct net_device *dev);
|
||||
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti);
|
||||
|
||||
|
||||
/**
|
||||
* struct ethtool_link_ext_state_info - link extended state and substate.
|
||||
*/
|
||||
struct ethtool_link_ext_state_info {
|
||||
enum ethtool_link_ext_state link_ext_state;
|
||||
union {
|
||||
enum ethtool_link_ext_substate_autoneg autoneg;
|
||||
enum ethtool_link_ext_substate_link_training link_training;
|
||||
enum ethtool_link_ext_substate_link_logical_mismatch link_logical_mismatch;
|
||||
enum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity;
|
||||
enum ethtool_link_ext_substate_cable_issue cable_issue;
|
||||
u8 __link_ext_substate;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ethtool_rxfh_indir_default - get default value for RX flow hash indirection
|
||||
* @index: Index in RX flow hash indirection table
|
||||
|
@ -245,6 +261,11 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
|
|||
* @get_link: Report whether physical link is up. Will only be called if
|
||||
* the netdev is up. Should usually be set to ethtool_op_get_link(),
|
||||
* which uses netif_carrier_ok().
|
||||
* @get_link_ext_state: Report link extended state. Should set link_ext_state and
|
||||
* link_ext_substate (link_ext_substate of 0 means link_ext_substate is unknown,
|
||||
* do not attach ext_substate attribute to netlink message). If link_ext_state
|
||||
* and link_ext_substate are unknown, return -ENODATA. If not implemented,
|
||||
* link_ext_state and link_ext_substate will not be sent to userspace.
|
||||
* @get_eeprom: Read data from the device EEPROM.
|
||||
* Should fill in the magic field. Don't need to check len for zero
|
||||
* or wraparound. Fill in the data argument with the eeprom values
|
||||
|
@ -384,6 +405,8 @@ struct ethtool_ops {
|
|||
void (*set_msglevel)(struct net_device *, u32);
|
||||
int (*nway_reset)(struct net_device *);
|
||||
u32 (*get_link)(struct net_device *);
|
||||
int (*get_link_ext_state)(struct net_device *,
|
||||
struct ethtool_link_ext_state_info *);
|
||||
int (*get_eeprom_len)(struct net_device *);
|
||||
int (*get_eeprom)(struct net_device *,
|
||||
struct ethtool_eeprom *, u8 *);
|
||||
|
|
|
@ -579,6 +579,76 @@ struct ethtool_pauseparam {
|
|||
__u32 tx_pause;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_state - link extended state
|
||||
*/
|
||||
enum ethtool_link_ext_state {
|
||||
ETHTOOL_LINK_EXT_STATE_AUTONEG,
|
||||
ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
|
||||
ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
|
||||
ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
|
||||
ETHTOOL_LINK_EXT_STATE_NO_CABLE,
|
||||
ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
|
||||
ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE,
|
||||
ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE,
|
||||
ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED,
|
||||
ETHTOOL_LINK_EXT_STATE_OVERHEAT,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_substate_autoneg - more information in addition to
|
||||
* ETHTOOL_LINK_EXT_STATE_AUTONEG.
|
||||
*/
|
||||
enum ethtool_link_ext_substate_autoneg {
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED = 1,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_substate_link_training - more information in addition to
|
||||
* ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE.
|
||||
*/
|
||||
enum ethtool_link_ext_substate_link_training {
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED = 1,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_substate_logical_mismatch - more information in addition
|
||||
* to ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH.
|
||||
*/
|
||||
enum ethtool_link_ext_substate_link_logical_mismatch {
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK = 1,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_substate_bad_signal_integrity - more information in
|
||||
* addition to ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY.
|
||||
*/
|
||||
enum ethtool_link_ext_substate_bad_signal_integrity {
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS = 1,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_link_ext_substate_cable_issue - more information in
|
||||
* addition to ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE.
|
||||
*/
|
||||
enum ethtool_link_ext_substate_cable_issue {
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE = 1,
|
||||
ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE,
|
||||
};
|
||||
|
||||
#define ETH_GSTRING_LEN 32
|
||||
|
||||
/**
|
||||
|
|
|
@ -236,6 +236,8 @@ enum {
|
|||
ETHTOOL_A_LINKSTATE_LINK, /* u8 */
|
||||
ETHTOOL_A_LINKSTATE_SQI, /* u32 */
|
||||
ETHTOOL_A_LINKSTATE_SQI_MAX, /* u32 */
|
||||
ETHTOOL_A_LINKSTATE_EXT_STATE, /* u8 */
|
||||
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE, /* u8 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_LINKSTATE_CNT,
|
||||
|
|
|
@ -9,10 +9,12 @@ struct linkstate_req_info {
|
|||
};
|
||||
|
||||
struct linkstate_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
int link;
|
||||
int sqi;
|
||||
int sqi_max;
|
||||
struct ethnl_reply_data base;
|
||||
int link;
|
||||
int sqi;
|
||||
int sqi_max;
|
||||
bool link_ext_state_provided;
|
||||
struct ethtool_link_ext_state_info ethtool_link_ext_state_info;
|
||||
};
|
||||
|
||||
#define LINKSTATE_REPDATA(__reply_base) \
|
||||
|
@ -25,6 +27,8 @@ linkstate_get_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = {
|
|||
[ETHTOOL_A_LINKSTATE_LINK] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_LINKSTATE_SQI] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_LINKSTATE_SQI_MAX] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_LINKSTATE_EXT_STATE] = { .type = NLA_REJECT },
|
||||
[ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .type = NLA_REJECT },
|
||||
};
|
||||
|
||||
static int linkstate_get_sqi(struct net_device *dev)
|
||||
|
@ -61,6 +65,23 @@ static int linkstate_get_sqi_max(struct net_device *dev)
|
|||
mutex_unlock(&phydev->lock);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
static int linkstate_get_link_ext_state(struct net_device *dev,
|
||||
struct linkstate_reply_data *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!dev->ethtool_ops->get_link_ext_state)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = dev->ethtool_ops->get_link_ext_state(dev, &data->ethtool_link_ext_state_info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->link_ext_state_provided = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
||||
|
@ -86,6 +107,12 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
|||
goto out;
|
||||
data->sqi_max = ret;
|
||||
|
||||
if (dev->flags & IFF_UP) {
|
||||
ret = linkstate_get_link_ext_state(dev, data);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP && ret != -ENODATA)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
ethnl_ops_complete(dev);
|
||||
|
@ -107,6 +134,12 @@ static int linkstate_reply_size(const struct ethnl_req_info *req_base,
|
|||
if (data->sqi_max != -EOPNOTSUPP)
|
||||
len += nla_total_size(sizeof(u32));
|
||||
|
||||
if (data->link_ext_state_provided)
|
||||
len += nla_total_size(sizeof(u8)); /* LINKSTATE_EXT_STATE */
|
||||
|
||||
if (data->ethtool_link_ext_state_info.__link_ext_substate)
|
||||
len += nla_total_size(sizeof(u8)); /* LINKSTATE_EXT_SUBSTATE */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -128,6 +161,17 @@ static int linkstate_fill_reply(struct sk_buff *skb,
|
|||
nla_put_u32(skb, ETHTOOL_A_LINKSTATE_SQI_MAX, data->sqi_max))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (data->link_ext_state_provided) {
|
||||
if (nla_put_u8(skb, ETHTOOL_A_LINKSTATE_EXT_STATE,
|
||||
data->ethtool_link_ext_state_info.link_ext_state))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (data->ethtool_link_ext_state_info.__link_ext_substate &&
|
||||
nla_put_u8(skb, ETHTOOL_A_LINKSTATE_EXT_SUBSTATE,
|
||||
data->ethtool_link_ext_state_info.__link_ext_substate))
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,23 +50,6 @@ cleanup()
|
|||
h1_destroy
|
||||
}
|
||||
|
||||
different_speeds_get()
|
||||
{
|
||||
local dev1=$1; shift
|
||||
local dev2=$1; shift
|
||||
local with_mode=$1; shift
|
||||
local adver=$1; shift
|
||||
|
||||
local -a speeds_arr
|
||||
|
||||
speeds_arr=($(common_speeds_get $dev1 $dev2 $with_mode $adver))
|
||||
if [[ ${#speeds_arr[@]} < 2 ]]; then
|
||||
check_err 1 "cannot check different speeds. There are not enough speeds"
|
||||
fi
|
||||
|
||||
echo ${speeds_arr[0]} ${speeds_arr[1]}
|
||||
}
|
||||
|
||||
same_speeds_autoneg_off()
|
||||
{
|
||||
# Check that when each of the reported speeds is forced, the links come
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ALL_TESTS="
|
||||
autoneg
|
||||
autoneg_force_mode
|
||||
no_cable
|
||||
"
|
||||
|
||||
NUM_NETIFS=2
|
||||
source lib.sh
|
||||
source ethtool_lib.sh
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
swp1=${NETIFS[p1]}
|
||||
swp2=${NETIFS[p2]}
|
||||
swp3=$NETIF_NO_CABLE
|
||||
}
|
||||
|
||||
ethtool_extended_state_check()
|
||||
{
|
||||
local dev=$1; shift
|
||||
local expected_ext_state=$1; shift
|
||||
local expected_ext_substate=${1:-""}; shift
|
||||
|
||||
local ext_state=$(ethtool $dev | grep "Link detected" \
|
||||
| cut -d "(" -f2 | cut -d ")" -f1)
|
||||
local ext_substate=$(echo $ext_state | cut -sd "," -f2 \
|
||||
| sed -e 's/^[[:space:]]*//')
|
||||
ext_state=$(echo $ext_state | cut -d "," -f1)
|
||||
|
||||
[[ $ext_state == $expected_ext_state ]]
|
||||
check_err $? "Expected \"$expected_ext_state\", got \"$ext_state\""
|
||||
|
||||
[[ $ext_substate == $expected_ext_substate ]]
|
||||
check_err $? "Expected \"$expected_ext_substate\", got \"$ext_substate\""
|
||||
}
|
||||
|
||||
autoneg()
|
||||
{
|
||||
RET=0
|
||||
|
||||
ip link set dev $swp1 up
|
||||
|
||||
sleep 4
|
||||
ethtool_extended_state_check $swp1 "Autoneg" "No partner detected"
|
||||
|
||||
log_test "Autoneg, No partner detected"
|
||||
|
||||
ip link set dev $swp1 down
|
||||
}
|
||||
|
||||
autoneg_force_mode()
|
||||
{
|
||||
RET=0
|
||||
|
||||
ip link set dev $swp1 up
|
||||
ip link set dev $swp2 up
|
||||
|
||||
local -a speeds_arr=($(different_speeds_get $swp1 $swp2 0 0))
|
||||
local speed1=${speeds_arr[0]}
|
||||
local speed2=${speeds_arr[1]}
|
||||
|
||||
ethtool_set $swp1 speed $speed1 autoneg off
|
||||
ethtool_set $swp2 speed $speed2 autoneg off
|
||||
|
||||
sleep 4
|
||||
ethtool_extended_state_check $swp1 "Autoneg" \
|
||||
"No partner detected during force mode"
|
||||
|
||||
ethtool_extended_state_check $swp2 "Autoneg" \
|
||||
"No partner detected during force mode"
|
||||
|
||||
log_test "Autoneg, No partner detected during force mode"
|
||||
|
||||
ethtool -s $swp2 autoneg on
|
||||
ethtool -s $swp1 autoneg on
|
||||
|
||||
ip link set dev $swp2 down
|
||||
ip link set dev $swp1 down
|
||||
}
|
||||
|
||||
no_cable()
|
||||
{
|
||||
RET=0
|
||||
|
||||
ip link set dev $swp3 up
|
||||
|
||||
sleep 1
|
||||
ethtool_extended_state_check $swp3 "No cable"
|
||||
|
||||
log_test "No cable"
|
||||
|
||||
ip link set dev $swp3 down
|
||||
}
|
||||
|
||||
setup_prepare
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
|
@ -67,3 +67,20 @@ common_speeds_get()
|
|||
<(printf '%s\n' "${dev1_speeds[@]}" | sort -u) \
|
||||
<(printf '%s\n' "${dev2_speeds[@]}" | sort -u)
|
||||
}
|
||||
|
||||
different_speeds_get()
|
||||
{
|
||||
local dev1=$1; shift
|
||||
local dev2=$1; shift
|
||||
local with_mode=$1; shift
|
||||
local adver=$1; shift
|
||||
|
||||
local -a speeds_arr
|
||||
|
||||
speeds_arr=($(common_speeds_get $dev1 $dev2 $with_mode $adver))
|
||||
if [[ ${#speeds_arr[@]} < 2 ]]; then
|
||||
check_err 1 "cannot check different speeds. There are not enough speeds"
|
||||
fi
|
||||
|
||||
echo ${speeds_arr[0]} ${speeds_arr[1]}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ NETIFS[p6]=veth5
|
|||
NETIFS[p7]=veth6
|
||||
NETIFS[p8]=veth7
|
||||
|
||||
# Port that does not have a cable connected.
|
||||
NETIF_NO_CABLE=eth8
|
||||
|
||||
##############################################################################
|
||||
# Defines
|
||||
|
||||
|
|
Loading…
Reference in New Issue