1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2022-2023 NXP
9 struct ethnl_req_info base
;
12 struct mm_reply_data
{
13 struct ethnl_reply_data base
;
14 struct ethtool_mm_state state
;
15 struct ethtool_mm_stats stats
;
18 #define MM_REPDATA(__reply_base) \
19 container_of(__reply_base, struct mm_reply_data, base)
21 #define ETHTOOL_MM_STAT_CNT \
22 (__ETHTOOL_A_MM_STAT_CNT - (ETHTOOL_A_MM_STAT_PAD + 1))
24 const struct nla_policy ethnl_mm_get_policy
[ETHTOOL_A_MM_HEADER
+ 1] = {
25 [ETHTOOL_A_MM_HEADER
] = NLA_POLICY_NESTED(ethnl_header_policy_stats
),
28 static int mm_prepare_data(const struct ethnl_req_info
*req_base
,
29 struct ethnl_reply_data
*reply_base
,
30 const struct genl_info
*info
)
32 struct mm_reply_data
*data
= MM_REPDATA(reply_base
);
33 struct net_device
*dev
= reply_base
->dev
;
34 const struct ethtool_ops
*ops
;
37 ops
= dev
->ethtool_ops
;
42 ethtool_stats_init((u64
*)&data
->stats
,
43 sizeof(data
->stats
) / sizeof(u64
));
45 ret
= ethnl_ops_begin(dev
);
49 ret
= ops
->get_mm(dev
, &data
->state
);
53 if (ops
->get_mm_stats
&& (req_base
->flags
& ETHTOOL_FLAG_STATS
))
54 ops
->get_mm_stats(dev
, &data
->stats
);
57 ethnl_ops_complete(dev
);
62 static int mm_reply_size(const struct ethnl_req_info
*req_base
,
63 const struct ethnl_reply_data
*reply_base
)
67 len
+= nla_total_size(sizeof(u8
)); /* _MM_PMAC_ENABLED */
68 len
+= nla_total_size(sizeof(u8
)); /* _MM_TX_ENABLED */
69 len
+= nla_total_size(sizeof(u8
)); /* _MM_TX_ACTIVE */
70 len
+= nla_total_size(sizeof(u8
)); /* _MM_VERIFY_ENABLED */
71 len
+= nla_total_size(sizeof(u8
)); /* _MM_VERIFY_STATUS */
72 len
+= nla_total_size(sizeof(u32
)); /* _MM_VERIFY_TIME */
73 len
+= nla_total_size(sizeof(u32
)); /* _MM_MAX_VERIFY_TIME */
74 len
+= nla_total_size(sizeof(u32
)); /* _MM_TX_MIN_FRAG_SIZE */
75 len
+= nla_total_size(sizeof(u32
)); /* _MM_RX_MIN_FRAG_SIZE */
77 if (req_base
->flags
& ETHTOOL_FLAG_STATS
)
78 len
+= nla_total_size(0) + /* _MM_STATS */
79 nla_total_size_64bit(sizeof(u64
)) * ETHTOOL_MM_STAT_CNT
;
84 static int mm_put_stat(struct sk_buff
*skb
, u64 val
, u16 attrtype
)
86 if (val
== ETHTOOL_STAT_NOT_SET
)
88 if (nla_put_u64_64bit(skb
, attrtype
, val
, ETHTOOL_A_MM_STAT_PAD
))
93 static int mm_put_stats(struct sk_buff
*skb
,
94 const struct ethtool_mm_stats
*stats
)
98 nest
= nla_nest_start(skb
, ETHTOOL_A_MM_STATS
);
102 if (mm_put_stat(skb
, stats
->MACMergeFrameAssErrorCount
,
103 ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS
) ||
104 mm_put_stat(skb
, stats
->MACMergeFrameSmdErrorCount
,
105 ETHTOOL_A_MM_STAT_SMD_ERRORS
) ||
106 mm_put_stat(skb
, stats
->MACMergeFrameAssOkCount
,
107 ETHTOOL_A_MM_STAT_REASSEMBLY_OK
) ||
108 mm_put_stat(skb
, stats
->MACMergeFragCountRx
,
109 ETHTOOL_A_MM_STAT_RX_FRAG_COUNT
) ||
110 mm_put_stat(skb
, stats
->MACMergeFragCountTx
,
111 ETHTOOL_A_MM_STAT_TX_FRAG_COUNT
) ||
112 mm_put_stat(skb
, stats
->MACMergeHoldCount
,
113 ETHTOOL_A_MM_STAT_HOLD_COUNT
))
116 nla_nest_end(skb
, nest
);
120 nla_nest_cancel(skb
, nest
);
124 static int mm_fill_reply(struct sk_buff
*skb
,
125 const struct ethnl_req_info
*req_base
,
126 const struct ethnl_reply_data
*reply_base
)
128 const struct mm_reply_data
*data
= MM_REPDATA(reply_base
);
129 const struct ethtool_mm_state
*state
= &data
->state
;
131 if (nla_put_u8(skb
, ETHTOOL_A_MM_TX_ENABLED
, state
->tx_enabled
) ||
132 nla_put_u8(skb
, ETHTOOL_A_MM_TX_ACTIVE
, state
->tx_active
) ||
133 nla_put_u8(skb
, ETHTOOL_A_MM_PMAC_ENABLED
, state
->pmac_enabled
) ||
134 nla_put_u8(skb
, ETHTOOL_A_MM_VERIFY_ENABLED
, state
->verify_enabled
) ||
135 nla_put_u8(skb
, ETHTOOL_A_MM_VERIFY_STATUS
, state
->verify_status
) ||
136 nla_put_u32(skb
, ETHTOOL_A_MM_VERIFY_TIME
, state
->verify_time
) ||
137 nla_put_u32(skb
, ETHTOOL_A_MM_MAX_VERIFY_TIME
, state
->max_verify_time
) ||
138 nla_put_u32(skb
, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE
, state
->tx_min_frag_size
) ||
139 nla_put_u32(skb
, ETHTOOL_A_MM_RX_MIN_FRAG_SIZE
, state
->rx_min_frag_size
))
142 if (req_base
->flags
& ETHTOOL_FLAG_STATS
&&
143 mm_put_stats(skb
, &data
->stats
))
149 const struct nla_policy ethnl_mm_set_policy
[ETHTOOL_A_MM_MAX
+ 1] = {
150 [ETHTOOL_A_MM_HEADER
] = NLA_POLICY_NESTED(ethnl_header_policy
),
151 [ETHTOOL_A_MM_VERIFY_ENABLED
] = NLA_POLICY_MAX(NLA_U8
, 1),
152 [ETHTOOL_A_MM_VERIFY_TIME
] = NLA_POLICY_RANGE(NLA_U32
, 1, 128),
153 [ETHTOOL_A_MM_TX_ENABLED
] = NLA_POLICY_MAX(NLA_U8
, 1),
154 [ETHTOOL_A_MM_PMAC_ENABLED
] = NLA_POLICY_MAX(NLA_U8
, 1),
155 [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE
] = NLA_POLICY_RANGE(NLA_U32
, 60, 252),
158 static void mm_state_to_cfg(const struct ethtool_mm_state
*state
,
159 struct ethtool_mm_cfg
*cfg
)
161 /* We could also compare state->verify_status against
162 * ETHTOOL_MM_VERIFY_STATUS_DISABLED, but state->verify_enabled
163 * is more like an administrative state which should be seen in
164 * ETHTOOL_MSG_MM_GET replies. For example, a port with verification
165 * disabled might be in the ETHTOOL_MM_VERIFY_STATUS_INITIAL
168 cfg
->verify_enabled
= state
->verify_enabled
;
169 cfg
->verify_time
= state
->verify_time
;
170 cfg
->tx_enabled
= state
->tx_enabled
;
171 cfg
->pmac_enabled
= state
->pmac_enabled
;
172 cfg
->tx_min_frag_size
= state
->tx_min_frag_size
;
176 ethnl_set_mm_validate(struct ethnl_req_info
*req_info
, struct genl_info
*info
)
178 const struct ethtool_ops
*ops
= req_info
->dev
->ethtool_ops
;
180 return ops
->get_mm
&& ops
->set_mm
? 1 : -EOPNOTSUPP
;
183 static int ethnl_set_mm(struct ethnl_req_info
*req_info
, struct genl_info
*info
)
185 struct netlink_ext_ack
*extack
= info
->extack
;
186 struct net_device
*dev
= req_info
->dev
;
187 struct ethtool_mm_state state
= {};
188 struct nlattr
**tb
= info
->attrs
;
189 struct ethtool_mm_cfg cfg
= {};
193 ret
= dev
->ethtool_ops
->get_mm(dev
, &state
);
197 mm_state_to_cfg(&state
, &cfg
);
199 ethnl_update_bool(&cfg
.verify_enabled
, tb
[ETHTOOL_A_MM_VERIFY_ENABLED
],
201 ethnl_update_u32(&cfg
.verify_time
, tb
[ETHTOOL_A_MM_VERIFY_TIME
], &mod
);
202 ethnl_update_bool(&cfg
.tx_enabled
, tb
[ETHTOOL_A_MM_TX_ENABLED
], &mod
);
203 ethnl_update_bool(&cfg
.pmac_enabled
, tb
[ETHTOOL_A_MM_PMAC_ENABLED
],
205 ethnl_update_u32(&cfg
.tx_min_frag_size
,
206 tb
[ETHTOOL_A_MM_TX_MIN_FRAG_SIZE
], &mod
);
211 if (cfg
.verify_time
> state
.max_verify_time
) {
212 NL_SET_ERR_MSG_ATTR(extack
, tb
[ETHTOOL_A_MM_VERIFY_TIME
],
213 "verifyTime exceeds device maximum");
217 if (cfg
.verify_enabled
&& !cfg
.tx_enabled
) {
218 NL_SET_ERR_MSG(extack
, "Verification requires TX enabled");
222 if (cfg
.tx_enabled
&& !cfg
.pmac_enabled
) {
223 NL_SET_ERR_MSG(extack
, "TX enabled requires pMAC enabled");
227 ret
= dev
->ethtool_ops
->set_mm(dev
, &cfg
, extack
);
228 return ret
< 0 ? ret
: 1;
231 const struct ethnl_request_ops ethnl_mm_request_ops
= {
232 .request_cmd
= ETHTOOL_MSG_MM_GET
,
233 .reply_cmd
= ETHTOOL_MSG_MM_GET_REPLY
,
234 .hdr_attr
= ETHTOOL_A_MM_HEADER
,
235 .req_info_size
= sizeof(struct mm_req_info
),
236 .reply_data_size
= sizeof(struct mm_reply_data
),
238 .prepare_data
= mm_prepare_data
,
239 .reply_size
= mm_reply_size
,
240 .fill_reply
= mm_fill_reply
,
242 .set_validate
= ethnl_set_mm_validate
,
244 .set_ntf_cmd
= ETHTOOL_MSG_MM_NTF
,
247 /* Returns whether a given device supports the MAC merge layer
248 * (has an eMAC and a pMAC). Must be called under rtnl_lock() and
251 bool __ethtool_dev_mm_supported(struct net_device
*dev
)
253 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
254 struct ethtool_mm_state state
= {};
255 int ret
= -EOPNOTSUPP
;
257 if (ops
&& ops
->get_mm
)
258 ret
= ops
->get_mm(dev
, &state
);
263 bool ethtool_dev_mm_supported(struct net_device
*dev
)
265 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
274 ret
= ethnl_ops_begin(dev
);
278 supported
= __ethtool_dev_mm_supported(dev
);
280 ethnl_ops_complete(dev
);
284 EXPORT_SYMBOL_GPL(ethtool_dev_mm_supported
);