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
  *     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
        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);
 
        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
 
        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,
        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,
        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
 
 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
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022-2023 NXP
+ */
+#include "common.h"
+#include "netlink.h"
+
+struct mm_req_info {
+       struct ethnl_req_info           base;
+};
+
+struct mm_reply_data {
+       struct ethnl_reply_data         base;
+       struct ethtool_mm_state         state;
+       struct ethtool_mm_stats         stats;
+};
+
+#define MM_REPDATA(__reply_base) \
+       container_of(__reply_base, struct mm_reply_data, base)
+
+#define ETHTOOL_MM_STAT_CNT \
+       (__ETHTOOL_A_MM_STAT_CNT - (ETHTOOL_A_MM_STAT_PAD + 1))
+
+const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1] = {
+       [ETHTOOL_A_MM_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy_stats),
+};
+
+static int mm_prepare_data(const struct ethnl_req_info *req_base,
+                          struct ethnl_reply_data *reply_base,
+                          struct genl_info *info)
+{
+       struct mm_reply_data *data = MM_REPDATA(reply_base);
+       struct net_device *dev = reply_base->dev;
+       const struct ethtool_ops *ops;
+       int ret;
+
+       ops = dev->ethtool_ops;
+
+       if (!ops->get_mm)
+               return -EOPNOTSUPP;
+
+       ethtool_stats_init((u64 *)&data->stats,
+                          sizeof(data->stats) / sizeof(u64));
+
+       ret = ethnl_ops_begin(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = ops->get_mm(dev, &data->state);
+       if (ret)
+               goto out_complete;
+
+       if (ops->get_mm_stats && (req_base->flags & ETHTOOL_FLAG_STATS))
+               ops->get_mm_stats(dev, &data->stats);
+
+out_complete:
+       ethnl_ops_complete(dev);
+
+       return 0;
+}
+
+static int mm_reply_size(const struct ethnl_req_info *req_base,
+                        const struct ethnl_reply_data *reply_base)
+{
+       int len = 0;
+
+       len += nla_total_size(sizeof(u8)); /* _MM_PMAC_ENABLED */
+       len += nla_total_size(sizeof(u8)); /* _MM_TX_ENABLED */
+       len += nla_total_size(sizeof(u8)); /* _MM_TX_ACTIVE */
+       len += nla_total_size(sizeof(u8)); /* _MM_VERIFY_ENABLED */
+       len += nla_total_size(sizeof(u8)); /* _MM_VERIFY_STATUS */
+       len += nla_total_size(sizeof(u32)); /* _MM_VERIFY_TIME */
+       len += nla_total_size(sizeof(u32)); /* _MM_MAX_VERIFY_TIME */
+       len += nla_total_size(sizeof(u32)); /* _MM_TX_MIN_FRAG_SIZE */
+       len += nla_total_size(sizeof(u32)); /* _MM_RX_MIN_FRAG_SIZE */
+
+       if (req_base->flags & ETHTOOL_FLAG_STATS)
+               len += nla_total_size(0) + /* _MM_STATS */
+                      nla_total_size_64bit(sizeof(u64)) * ETHTOOL_MM_STAT_CNT;
+
+       return len;
+}
+
+static int mm_put_stat(struct sk_buff *skb, u64 val, u16 attrtype)
+{
+       if (val == ETHTOOL_STAT_NOT_SET)
+               return 0;
+       if (nla_put_u64_64bit(skb, attrtype, val, ETHTOOL_A_MM_STAT_PAD))
+               return -EMSGSIZE;
+       return 0;
+}
+
+static int mm_put_stats(struct sk_buff *skb,
+                       const struct ethtool_mm_stats *stats)
+{
+       struct nlattr *nest;
+
+       nest = nla_nest_start(skb, ETHTOOL_A_MM_STATS);
+       if (!nest)
+               return -EMSGSIZE;
+
+       if (mm_put_stat(skb, stats->MACMergeFrameAssErrorCount,
+                       ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS) ||
+           mm_put_stat(skb, stats->MACMergeFrameSmdErrorCount,
+                       ETHTOOL_A_MM_STAT_SMD_ERRORS) ||
+           mm_put_stat(skb, stats->MACMergeFrameAssOkCount,
+                       ETHTOOL_A_MM_STAT_REASSEMBLY_OK) ||
+           mm_put_stat(skb, stats->MACMergeFragCountRx,
+                       ETHTOOL_A_MM_STAT_RX_FRAG_COUNT) ||
+           mm_put_stat(skb, stats->MACMergeFragCountTx,
+                       ETHTOOL_A_MM_STAT_TX_FRAG_COUNT) ||
+           mm_put_stat(skb, stats->MACMergeHoldCount,
+                       ETHTOOL_A_MM_STAT_HOLD_COUNT))
+               goto err_cancel;
+
+       nla_nest_end(skb, nest);
+       return 0;
+
+err_cancel:
+       nla_nest_cancel(skb, nest);
+       return -EMSGSIZE;
+}
+
+static int mm_fill_reply(struct sk_buff *skb,
+                        const struct ethnl_req_info *req_base,
+                        const struct ethnl_reply_data *reply_base)
+{
+       const struct mm_reply_data *data = MM_REPDATA(reply_base);
+       const struct ethtool_mm_state *state = &data->state;
+
+       if (nla_put_u8(skb, ETHTOOL_A_MM_TX_ENABLED, state->tx_enabled) ||
+           nla_put_u8(skb, ETHTOOL_A_MM_TX_ACTIVE, state->tx_active) ||
+           nla_put_u8(skb, ETHTOOL_A_MM_PMAC_ENABLED, state->pmac_enabled) ||
+           nla_put_u8(skb, ETHTOOL_A_MM_VERIFY_ENABLED, state->verify_enabled) ||
+           nla_put_u8(skb, ETHTOOL_A_MM_VERIFY_STATUS, state->verify_status) ||
+           nla_put_u32(skb, ETHTOOL_A_MM_VERIFY_TIME, state->verify_time) ||
+           nla_put_u32(skb, ETHTOOL_A_MM_MAX_VERIFY_TIME, state->max_verify_time) ||
+           nla_put_u32(skb, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, state->tx_min_frag_size) ||
+           nla_put_u32(skb, ETHTOOL_A_MM_RX_MIN_FRAG_SIZE, state->rx_min_frag_size))
+               return -EMSGSIZE;
+
+       if (req_base->flags & ETHTOOL_FLAG_STATS &&
+           mm_put_stats(skb, &data->stats))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+const struct ethnl_request_ops ethnl_mm_request_ops = {
+       .request_cmd            = ETHTOOL_MSG_MM_GET,
+       .reply_cmd              = ETHTOOL_MSG_MM_GET_REPLY,
+       .hdr_attr               = ETHTOOL_A_MM_HEADER,
+       .req_info_size          = sizeof(struct mm_req_info),
+       .reply_data_size        = sizeof(struct mm_reply_data),
+
+       .prepare_data           = mm_prepare_data,
+       .reply_size             = mm_reply_size,
+       .fill_reply             = mm_fill_reply,
+};
+
+const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1] = {
+       [ETHTOOL_A_MM_HEADER]           = NLA_POLICY_NESTED(ethnl_header_policy),
+       [ETHTOOL_A_MM_VERIFY_ENABLED]   = NLA_POLICY_MAX(NLA_U8, 1),
+       [ETHTOOL_A_MM_VERIFY_TIME]      = NLA_POLICY_RANGE(NLA_U32, 1, 128),
+       [ETHTOOL_A_MM_TX_ENABLED]       = NLA_POLICY_MAX(NLA_U8, 1),
+       [ETHTOOL_A_MM_PMAC_ENABLED]     = NLA_POLICY_MAX(NLA_U8, 1),
+       [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE] = NLA_POLICY_RANGE(NLA_U32, 60, 252),
+};
+
+static void mm_state_to_cfg(const struct ethtool_mm_state *state,
+                           struct ethtool_mm_cfg *cfg)
+{
+       /* We could also compare state->verify_status against
+        * ETHTOOL_MM_VERIFY_STATUS_DISABLED, but state->verify_enabled
+        * is more like an administrative state which should be seen in
+        * ETHTOOL_MSG_MM_GET replies. For example, a port with verification
+        * disabled might be in the ETHTOOL_MM_VERIFY_STATUS_INITIAL
+        * if it's down.
+        */
+       cfg->verify_enabled = state->verify_enabled;
+       cfg->verify_time = state->verify_time;
+       cfg->tx_enabled = state->tx_enabled;
+       cfg->pmac_enabled = state->pmac_enabled;
+       cfg->tx_min_frag_size = state->tx_min_frag_size;
+}
+
+int ethnl_set_mm(struct sk_buff *skb, struct genl_info *info)
+{
+       struct netlink_ext_ack *extack = info->extack;
+       struct ethnl_req_info req_info = {};
+       struct ethtool_mm_state state = {};
+       struct nlattr **tb = info->attrs;
+       struct ethtool_mm_cfg cfg = {};
+       const struct ethtool_ops *ops;
+       struct net_device *dev;
+       bool mod = false;
+       int ret;
+
+       ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_MM_HEADER],
+                                        genl_info_net(info), extack, true);
+       if (ret)
+               return ret;
+
+       dev = req_info.dev;
+       ops = dev->ethtool_ops;
+
+       if (!ops->get_mm || !ops->set_mm) {
+               ret = -EOPNOTSUPP;
+               goto out_dev_put;
+       }
+
+       rtnl_lock();
+       ret = ethnl_ops_begin(dev);
+       if (ret < 0)
+               goto out_rtnl_unlock;
+
+       ret = ops->get_mm(dev, &state);
+       if (ret)
+               goto out_complete;
+
+       mm_state_to_cfg(&state, &cfg);
+
+       ethnl_update_bool(&cfg.verify_enabled, tb[ETHTOOL_A_MM_VERIFY_ENABLED],
+                         &mod);
+       ethnl_update_u32(&cfg.verify_time, tb[ETHTOOL_A_MM_VERIFY_TIME], &mod);
+       ethnl_update_bool(&cfg.tx_enabled, tb[ETHTOOL_A_MM_TX_ENABLED], &mod);
+       ethnl_update_bool(&cfg.pmac_enabled, tb[ETHTOOL_A_MM_PMAC_ENABLED],
+                         &mod);
+       ethnl_update_u32(&cfg.tx_min_frag_size,
+                        tb[ETHTOOL_A_MM_TX_MIN_FRAG_SIZE], &mod);
+
+       if (!mod)
+               goto out_complete;
+
+       if (cfg.verify_time > state.max_verify_time) {
+               NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_MM_VERIFY_TIME],
+                                   "verifyTime exceeds device maximum");
+               ret = -ERANGE;
+               goto out_complete;
+       }
+
+       ret = ops->set_mm(dev, &cfg, extack);
+       if (ret)
+               goto out_complete;
+
+       ethtool_notify(dev, ETHTOOL_MSG_MM_NTF, NULL);
+
+out_complete:
+       ethnl_ops_complete(dev);
+out_rtnl_unlock:
+       rtnl_unlock();
+out_dev_put:
+       ethnl_parse_header_dev_put(&req_info);
+       return ret;
+}
 
        [ETHTOOL_MSG_RSS_GET]           = ðnl_rss_request_ops,
        [ETHTOOL_MSG_PLCA_GET_CFG]      = ðnl_plca_cfg_request_ops,
        [ETHTOOL_MSG_PLCA_GET_STATUS]   = ðnl_plca_status_request_ops,
+       [ETHTOOL_MSG_MM_GET]            = ðnl_mm_request_ops,
 };
 
 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
        [ETHTOOL_MSG_FEC_NTF]           = ðnl_fec_request_ops,
        [ETHTOOL_MSG_MODULE_NTF]        = ðnl_module_request_ops,
        [ETHTOOL_MSG_PLCA_NTF]          = ðnl_plca_cfg_request_ops,
+       [ETHTOOL_MSG_MM_NTF]            = ðnl_mm_request_ops,
 };
 
 /* default notification handler */
        [ETHTOOL_MSG_FEC_NTF]           = ethnl_default_notify,
        [ETHTOOL_MSG_MODULE_NTF]        = ethnl_default_notify,
        [ETHTOOL_MSG_PLCA_NTF]          = ethnl_default_notify,
+       [ETHTOOL_MSG_MM_NTF]            = ethnl_default_notify,
 };
 
 void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
                .policy = ethnl_plca_get_status_policy,
                .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1,
        },
+       {
+               .cmd    = ETHTOOL_MSG_MM_GET,
+               .doit   = ethnl_default_doit,
+               .start  = ethnl_default_start,
+               .dumpit = ethnl_default_dumpit,
+               .done   = ethnl_default_done,
+               .policy = ethnl_mm_get_policy,
+               .maxattr = ARRAY_SIZE(ethnl_mm_get_policy) - 1,
+       },
+       {
+               .cmd    = ETHTOOL_MSG_MM_SET,
+               .flags  = GENL_UNS_ADMIN_PERM,
+               .doit   = ethnl_set_mm,
+               .policy = ethnl_mm_set_policy,
+               .maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
+       },
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
 
 extern const struct ethnl_request_ops ethnl_rss_request_ops;
 extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
 extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
+extern const struct ethnl_request_ops ethnl_mm_request_ops;
 
 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
 extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1];
 extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1];
 extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
+extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
+extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
 
 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_module(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info);
+int ethnl_set_mm(struct sk_buff *skb, struct genl_info *info);
 
 extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
 extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];