Skip to content

Commit

Permalink
net: ethtool: add support for MAC Merge layer
Browse files Browse the repository at this point in the history
The MAC merge sublayer (IEEE 802.3-2018 clause 99) is one of 2
specifications (the other being Frame Preemption; IEEE 802.1Q-2018
clause 6.7.2), which work together to minimize latency caused by frame
interference at TX. The overall goal of TSN is for normal traffic and
traffic with a bounded deadline to be able to cohabitate on the same L2
network and not bother each other too much.

The standards achieve this (partly) by introducing the concept of
preemptible traffic, i.e. Ethernet frames that have a custom value for
the Start-of-Frame-Delimiter (SFD), and these frames can be fragmented
and reassembled at L2 on a link-local basis. The non-preemptible frames
are called express traffic, they are transmitted using a normal SFD, and
they can preempt preemptible frames, therefore having lower latency,
which can matter at lower (100 Mbps) link speeds, or at high MTUs (jumbo
frames around 9K). Preemption is not recursive, i.e. a P frame cannot
preempt another P frame. Preemption also does not depend upon priority,
or otherwise said, an E frame with prio 0 will still preempt a P frame
with prio 7.

In terms of implementation, the standards talk about the presence of an
express MAC (eMAC) which handles express traffic, and a preemptible MAC
(pMAC) which handles preemptible traffic, and these MACs are multiplexed
on the same MII by a MAC merge layer.

To support frame preemption, the definition of the SFD was generalized
to SMD (Start-of-mPacket-Delimiter), where an mPacket is essentially an
Ethernet frame fragment, or a complete frame. Stations unaware of an SMD
value different from the standard SFD will treat P frames as error
frames. To prevent that from happening, a negotiation process is
defined.

On RX, packets are dispatched to the eMAC or pMAC after being filtered
by their SMD. On TX, the eMAC/pMAC classification decision is taken by
the 802.1Q spec, based on packet priority (each of the 8 user priority
values may have an admin-status of preemptible or express).

The MAC Merge layer and the Frame Preemption parameters have some degree
of independence in terms of how software stacks are supposed to deal
with them. The activation of the MM layer is supposed to be controlled
by an LLDP daemon (after it has been communicated that the link partner
also supports it), after which a (hardware-based or not) verification
handshake takes place, before actually enabling the feature. So the
process is intended to be relatively plug-and-play. Whereas FP settings
are supposed to be coordinated across a network using something
approximating NETCONF.

The support contained here is exclusively for the 802.3 (MAC Merge)
portions and not for the 802.1Q (Frame Preemption) parts. This API is
sufficient for an LLDP daemon to do its job. The FP adminStatus variable
from 802.1Q is outside the scope of an LLDP daemon.

I have taken a few creative licenses and augmented the Linux kernel UAPI
compared to the standard managed objects recommended by IEEE 802.3.
These are:

- ETHTOOL_A_MM_PMAC_ENABLED: According to Figure 99-6: Receive
  Processing state diagram, a MAC Merge layer is always supposed to be
  able to receive P frames. However, this implies keeping the pMAC
  powered on, which will consume needless power in applications where FP
  will never be used. If LLDP is used, the reception of an Additional
  Ethernet Capabilities TLV from the link partner is sufficient
  indication that the pMAC should be enabled. So my proposal is that in
  Linux, we keep the pMAC turned off by default and that user space
  turns it on when needed.

- ETHTOOL_A_MM_VERIFY_ENABLED: The IEEE managed object is called
  aMACMergeVerifyDisableTx. I opted for consistency (positive logic) in
  the boolean netlink attributes offered, so this is also positive here.
  Other than the meaning being reversed, they correspond to the same
  thing.

- ETHTOOL_A_MM_MAX_VERIFY_TIME: I found it most reasonable for a LLDP
  daemon to maximize the verifyTime variable (delay between SMD-V
  transmissions), to maximize its chances that the LP replies. IEEE says
  that the verifyTime can range between 1 and 128 ms, but the NXP ENETC
  stupidly keeps this variable in a 7 bit register, so the maximum
  supported value is 127 ms. I could have chosen to hardcode this in the
  LLDP daemon to a lower value, but why not let the kernel expose its
  supported range directly.

- ETHTOOL_A_MM_TX_MIN_FRAG_SIZE: the standard managed object is called
  aMACMergeAddFragSize, and expresses the "additional" fragment size
  (on top of ETH_ZLEN), whereas this expresses the absolute value of the
  fragment size.

- ETHTOOL_A_MM_RX_MIN_FRAG_SIZE: there doesn't appear to exist a managed
  object mandated by the standard, but user space clearly needs to know
  what is the minimum supported fragment size of our local receiver,
  since LLDP must advertise a value no lower than that.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vladimir Oltean authored and David S. Miller committed Jan 23, 2023
1 parent 40e0b09 commit 2b30f82
Showing 7 changed files with 451 additions and 2 deletions.
99 changes: 99 additions & 0 deletions include/linux/ethtool.h
Original file line number Diff line number Diff line change
@@ -477,6 +477,98 @@ struct ethtool_module_power_mode_params {
enum ethtool_module_power_mode mode;
};

/**
* struct ethtool_mm_state - 802.3 MAC merge layer state
* @verify_time:
* wait time between verification attempts in ms (according to clause
* 30.14.1.6 aMACMergeVerifyTime)
* @max_verify_time:
* maximum accepted value for the @verify_time variable in set requests
* @verify_status:
* state of the verification state machine of the MM layer (according to
* clause 30.14.1.2 aMACMergeStatusVerify)
* @tx_enabled:
* set if the MM layer is administratively enabled in the TX direction
* (according to clause 30.14.1.3 aMACMergeEnableTx)
* @tx_active:
* set if the MM layer is enabled in the TX direction, which makes FP
* possible (according to 30.14.1.5 aMACMergeStatusTx). This should be
* true if MM is enabled, and the verification status is either verified,
* or disabled.
* @pmac_enabled:
* set if the preemptible MAC is powered on and is able to receive
* preemptible packets and respond to verification frames.
* @verify_enabled:
* set if the Verify function of the MM layer (which sends SMD-V
* verification requests) is administratively enabled (regardless of
* whether it is currently in the ETHTOOL_MM_VERIFY_STATUS_DISABLED state
* or not), according to clause 30.14.1.4 aMACMergeVerifyDisableTx (but
* using positive rather than negative logic). The device should always
* respond to received SMD-V requests as long as @pmac_enabled is set.
* @tx_min_frag_size:
* the minimum size of non-final mPacket fragments that the link partner
* supports receiving, expressed in octets. Compared to the definition
* from clause 30.14.1.7 aMACMergeAddFragSize which is expressed in the
* range 0 to 3 (requiring a translation to the size in octets according
* to the formula 64 * (1 + addFragSize) - 4), a value in a continuous and
* unbounded range can be specified here.
* @rx_min_frag_size:
* the minimum size of non-final mPacket fragments that this device
* supports receiving, expressed in octets.
*/
struct ethtool_mm_state {
u32 verify_time;
u32 max_verify_time;
enum ethtool_mm_verify_status verify_status;
bool tx_enabled;
bool tx_active;
bool pmac_enabled;
bool verify_enabled;
u32 tx_min_frag_size;
u32 rx_min_frag_size;
};

/**
* struct ethtool_mm_cfg - 802.3 MAC merge layer configuration
* @verify_time: see struct ethtool_mm_state
* @verify_enabled: see struct ethtool_mm_state
* @tx_enabled: see struct ethtool_mm_state
* @pmac_enabled: see struct ethtool_mm_state
* @tx_min_frag_size: see struct ethtool_mm_state
*/
struct ethtool_mm_cfg {
u32 verify_time;
bool verify_enabled;
bool tx_enabled;
bool pmac_enabled;
u32 tx_min_frag_size;
};

/**
* struct ethtool_mm_stats - 802.3 MAC merge layer statistics
* @MACMergeFrameAssErrorCount:
* received MAC frames with reassembly errors
* @MACMergeFrameSmdErrorCount:
* received MAC frames/fragments rejected due to unknown or incorrect SMD
* @MACMergeFrameAssOkCount:
* received MAC frames that were successfully reassembled and passed up
* @MACMergeFragCountRx:
* number of additional correct SMD-C mPackets received due to preemption
* @MACMergeFragCountTx:
* number of additional mPackets sent due to preemption
* @MACMergeHoldCount:
* number of times the MM layer entered the HOLD state, which blocks
* transmission of preemptible traffic
*/
struct ethtool_mm_stats {
u64 MACMergeFrameAssErrorCount;
u64 MACMergeFrameSmdErrorCount;
u64 MACMergeFrameAssOkCount;
u64 MACMergeFragCountRx;
u64 MACMergeFragCountTx;
u64 MACMergeHoldCount;
};

/**
* struct ethtool_ops - optional netdev operations
* @cap_link_lanes_supported: indicates if the driver supports lanes
@@ -649,6 +741,9 @@ struct ethtool_module_power_mode_params {
* plugged-in.
* @set_module_power_mode: Set the power mode policy for the plug-in module
* used by the network device.
* @get_mm: Query the 802.3 MAC Merge layer state.
* @set_mm: Set the 802.3 MAC Merge layer parameters.
* @get_mm_stats: Query the 802.3 MAC Merge layer statistics.
*
* All operations are optional (i.e. the function pointer may be set
* to %NULL) and callers must take this into account. Callers must
@@ -787,6 +882,10 @@ struct ethtool_ops {
int (*set_module_power_mode)(struct net_device *dev,
const struct ethtool_module_power_mode_params *params,
struct netlink_ext_ack *extack);
int (*get_mm)(struct net_device *dev, struct ethtool_mm_state *state);
int (*set_mm)(struct net_device *dev, struct ethtool_mm_cfg *cfg,
struct netlink_ext_ack *extack);
void (*get_mm_stats)(struct net_device *dev, struct ethtool_mm_stats *stats);
};

int ethtool_check_ops(const struct ethtool_ops *ops);
25 changes: 25 additions & 0 deletions include/uapi/linux/ethtool.h
Original file line number Diff line number Diff line change
@@ -779,6 +779,31 @@ enum ethtool_podl_pse_pw_d_status {
ETHTOOL_PODL_PSE_PW_D_STATUS_ERROR,
};

/**
* enum ethtool_mm_verify_status - status of MAC Merge Verify function
* @ETHTOOL_MM_VERIFY_STATUS_UNKNOWN:
* verification status is unknown
* @ETHTOOL_MM_VERIFY_STATUS_INITIAL:
* the 802.3 Verify State diagram is in the state INIT_VERIFICATION
* @ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
* the Verify State diagram is in the state VERIFICATION_IDLE,
* SEND_VERIFY or WAIT_FOR_RESPONSE
* @ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
* indicates that the Verify State diagram is in the state VERIFIED
* @ETHTOOL_MM_VERIFY_STATUS_FAILED:
* the Verify State diagram is in the state VERIFY_FAIL
* @ETHTOOL_MM_VERIFY_STATUS_DISABLED:
* verification of preemption operation is disabled
*/
enum ethtool_mm_verify_status {
ETHTOOL_MM_VERIFY_STATUS_UNKNOWN,
ETHTOOL_MM_VERIFY_STATUS_INITIAL,
ETHTOOL_MM_VERIFY_STATUS_VERIFYING,
ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED,
ETHTOOL_MM_VERIFY_STATUS_FAILED,
ETHTOOL_MM_VERIFY_STATUS_DISABLED,
};

/**
* struct ethtool_gstrings - string set for data tagging
* @cmd: Command number = %ETHTOOL_GSTRINGS
47 changes: 47 additions & 0 deletions include/uapi/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
@@ -55,6 +55,8 @@ enum {
ETHTOOL_MSG_PLCA_GET_CFG,
ETHTOOL_MSG_PLCA_SET_CFG,
ETHTOOL_MSG_PLCA_GET_STATUS,
ETHTOOL_MSG_MM_GET,
ETHTOOL_MSG_MM_SET,

/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
@@ -105,6 +107,8 @@ enum {
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
ETHTOOL_MSG_PLCA_NTF,
ETHTOOL_MSG_MM_GET_REPLY,
ETHTOOL_MSG_MM_NTF,

/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@@ -922,6 +926,49 @@ enum {
ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
};

/* MAC Merge (802.3) */

enum {
ETHTOOL_A_MM_STAT_UNSPEC,
ETHTOOL_A_MM_STAT_PAD,

/* aMACMergeFrameAssErrorCount */
ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS, /* u64 */
/* aMACMergeFrameSmdErrorCount */
ETHTOOL_A_MM_STAT_SMD_ERRORS, /* u64 */
/* aMACMergeFrameAssOkCount */
ETHTOOL_A_MM_STAT_REASSEMBLY_OK, /* u64 */
/* aMACMergeFragCountRx */
ETHTOOL_A_MM_STAT_RX_FRAG_COUNT, /* u64 */
/* aMACMergeFragCountTx */
ETHTOOL_A_MM_STAT_TX_FRAG_COUNT, /* u64 */
/* aMACMergeHoldCount */
ETHTOOL_A_MM_STAT_HOLD_COUNT, /* u64 */

/* add new constants above here */
__ETHTOOL_A_MM_STAT_CNT,
ETHTOOL_A_MM_STAT_MAX = (__ETHTOOL_A_MM_STAT_CNT - 1)
};

enum {
ETHTOOL_A_MM_UNSPEC,
ETHTOOL_A_MM_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_MM_PMAC_ENABLED, /* u8 */
ETHTOOL_A_MM_TX_ENABLED, /* u8 */
ETHTOOL_A_MM_TX_ACTIVE, /* u8 */
ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, /* u32 */
ETHTOOL_A_MM_RX_MIN_FRAG_SIZE, /* u32 */
ETHTOOL_A_MM_VERIFY_ENABLED, /* u8 */
ETHTOOL_A_MM_VERIFY_STATUS, /* u8 */
ETHTOOL_A_MM_VERIFY_TIME, /* u32 */
ETHTOOL_A_MM_MAX_VERIFY_TIME, /* u32 */
ETHTOOL_A_MM_STATS, /* nest - _A_MM_STAT_* */

/* add new constants above here */
__ETHTOOL_A_MM_CNT,
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
};

/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
4 changes: 2 additions & 2 deletions net/ethtool/Makefile
Original file line number Diff line number Diff line change
@@ -7,5 +7,5 @@ obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
linkstate.o debug.o wol.o features.o privflags.o rings.o \
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \
pse-pd.o plca.o
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
module.o pse-pd.o plca.o mm.o
Loading

0 comments on commit 2b30f82

Please sign in to comment.