1 // SPDX-License-Identifier: GPL-2.0-only
6 struct coalesce_req_info
{
7 struct ethnl_req_info base
;
10 struct coalesce_reply_data
{
11 struct ethnl_reply_data base
;
12 struct ethtool_coalesce coalesce
;
16 #define COALESCE_REPDATA(__reply_base) \
17 container_of(__reply_base, struct coalesce_reply_data, base)
19 #define __SUPPORTED_OFFSET ETHTOOL_A_COALESCE_RX_USECS
20 static u32
attr_to_mask(unsigned int attr_type
)
22 return BIT(attr_type
- __SUPPORTED_OFFSET
);
25 /* build time check that indices in ethtool_ops::supported_coalesce_params
26 * match corresponding attribute types with an offset
28 #define __CHECK_SUPPORTED_OFFSET(x) \
29 static_assert((ETHTOOL_ ## x) == \
30 BIT((ETHTOOL_A_ ## x) - __SUPPORTED_OFFSET))
31 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS
);
32 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES
);
33 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_IRQ
);
34 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_IRQ
);
35 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS
);
36 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES
);
37 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_IRQ
);
38 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_IRQ
);
39 __CHECK_SUPPORTED_OFFSET(COALESCE_STATS_BLOCK_USECS
);
40 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_RX
);
41 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_TX
);
42 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_LOW
);
43 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_LOW
);
44 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_LOW
);
45 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_LOW
);
46 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_LOW
);
47 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_HIGH
);
48 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_HIGH
);
49 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH
);
50 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH
);
51 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH
);
52 __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL
);
54 static const struct nla_policy
55 coalesce_get_policy
[ETHTOOL_A_COALESCE_MAX
+ 1] = {
56 [ETHTOOL_A_COALESCE_UNSPEC
] = { .type
= NLA_REJECT
},
57 [ETHTOOL_A_COALESCE_HEADER
] = { .type
= NLA_NESTED
},
58 [ETHTOOL_A_COALESCE_RX_USECS
] = { .type
= NLA_REJECT
},
59 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES
] = { .type
= NLA_REJECT
},
60 [ETHTOOL_A_COALESCE_RX_USECS_IRQ
] = { .type
= NLA_REJECT
},
61 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
] = { .type
= NLA_REJECT
},
62 [ETHTOOL_A_COALESCE_TX_USECS
] = { .type
= NLA_REJECT
},
63 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES
] = { .type
= NLA_REJECT
},
64 [ETHTOOL_A_COALESCE_TX_USECS_IRQ
] = { .type
= NLA_REJECT
},
65 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
] = { .type
= NLA_REJECT
},
66 [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
] = { .type
= NLA_REJECT
},
67 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
] = { .type
= NLA_REJECT
},
68 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
] = { .type
= NLA_REJECT
},
69 [ETHTOOL_A_COALESCE_PKT_RATE_LOW
] = { .type
= NLA_REJECT
},
70 [ETHTOOL_A_COALESCE_RX_USECS_LOW
] = { .type
= NLA_REJECT
},
71 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
] = { .type
= NLA_REJECT
},
72 [ETHTOOL_A_COALESCE_TX_USECS_LOW
] = { .type
= NLA_REJECT
},
73 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
] = { .type
= NLA_REJECT
},
74 [ETHTOOL_A_COALESCE_PKT_RATE_HIGH
] = { .type
= NLA_REJECT
},
75 [ETHTOOL_A_COALESCE_RX_USECS_HIGH
] = { .type
= NLA_REJECT
},
76 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
] = { .type
= NLA_REJECT
},
77 [ETHTOOL_A_COALESCE_TX_USECS_HIGH
] = { .type
= NLA_REJECT
},
78 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
] = { .type
= NLA_REJECT
},
79 [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
] = { .type
= NLA_REJECT
},
82 static int coalesce_prepare_data(const struct ethnl_req_info
*req_base
,
83 struct ethnl_reply_data
*reply_base
,
84 struct genl_info
*info
)
86 struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
87 struct net_device
*dev
= reply_base
->dev
;
90 if (!dev
->ethtool_ops
->get_coalesce
)
92 data
->supported_params
= dev
->ethtool_ops
->supported_coalesce_params
;
93 ret
= ethnl_ops_begin(dev
);
96 ret
= dev
->ethtool_ops
->get_coalesce(dev
, &data
->coalesce
);
97 ethnl_ops_complete(dev
);
102 static int coalesce_reply_size(const struct ethnl_req_info
*req_base
,
103 const struct ethnl_reply_data
*reply_base
)
105 return nla_total_size(sizeof(u32
)) + /* _RX_USECS */
106 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES */
107 nla_total_size(sizeof(u32
)) + /* _RX_USECS_IRQ */
108 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_IRQ */
109 nla_total_size(sizeof(u32
)) + /* _TX_USECS */
110 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES */
111 nla_total_size(sizeof(u32
)) + /* _TX_USECS_IRQ */
112 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_IRQ */
113 nla_total_size(sizeof(u32
)) + /* _STATS_BLOCK_USECS */
114 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_RX */
115 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_TX */
116 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_LOW */
117 nla_total_size(sizeof(u32
)) + /* _RX_USECS_LOW */
118 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_LOW */
119 nla_total_size(sizeof(u32
)) + /* _TX_USECS_LOW */
120 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_LOW */
121 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_HIGH */
122 nla_total_size(sizeof(u32
)) + /* _RX_USECS_HIGH */
123 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_HIGH */
124 nla_total_size(sizeof(u32
)) + /* _TX_USECS_HIGH */
125 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_HIGH */
126 nla_total_size(sizeof(u32
)); /* _RATE_SAMPLE_INTERVAL */
129 static bool coalesce_put_u32(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
130 u32 supported_params
)
132 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
134 return nla_put_u32(skb
, attr_type
, val
);
137 static bool coalesce_put_bool(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
138 u32 supported_params
)
140 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
142 return nla_put_u8(skb
, attr_type
, !!val
);
145 static int coalesce_fill_reply(struct sk_buff
*skb
,
146 const struct ethnl_req_info
*req_base
,
147 const struct ethnl_reply_data
*reply_base
)
149 const struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
150 const struct ethtool_coalesce
*coal
= &data
->coalesce
;
151 u32 supported
= data
->supported_params
;
153 if (coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS
,
154 coal
->rx_coalesce_usecs
, supported
) ||
155 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES
,
156 coal
->rx_max_coalesced_frames
, supported
) ||
157 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_IRQ
,
158 coal
->rx_coalesce_usecs_irq
, supported
) ||
159 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
,
160 coal
->rx_max_coalesced_frames_irq
, supported
) ||
161 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS
,
162 coal
->tx_coalesce_usecs
, supported
) ||
163 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES
,
164 coal
->tx_max_coalesced_frames
, supported
) ||
165 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_IRQ
,
166 coal
->tx_coalesce_usecs_irq
, supported
) ||
167 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
,
168 coal
->tx_max_coalesced_frames_irq
, supported
) ||
169 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
,
170 coal
->stats_block_coalesce_usecs
, supported
) ||
171 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
,
172 coal
->use_adaptive_rx_coalesce
, supported
) ||
173 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
,
174 coal
->use_adaptive_tx_coalesce
, supported
) ||
175 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_LOW
,
176 coal
->pkt_rate_low
, supported
) ||
177 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_LOW
,
178 coal
->rx_coalesce_usecs_low
, supported
) ||
179 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
,
180 coal
->rx_max_coalesced_frames_low
, supported
) ||
181 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_LOW
,
182 coal
->tx_coalesce_usecs_low
, supported
) ||
183 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
,
184 coal
->tx_max_coalesced_frames_low
, supported
) ||
185 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_HIGH
,
186 coal
->pkt_rate_high
, supported
) ||
187 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_HIGH
,
188 coal
->rx_coalesce_usecs_high
, supported
) ||
189 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
,
190 coal
->rx_max_coalesced_frames_high
, supported
) ||
191 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_HIGH
,
192 coal
->tx_coalesce_usecs_high
, supported
) ||
193 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
,
194 coal
->tx_max_coalesced_frames_high
, supported
) ||
195 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
,
196 coal
->rate_sample_interval
, supported
))
202 const struct ethnl_request_ops ethnl_coalesce_request_ops
= {
203 .request_cmd
= ETHTOOL_MSG_COALESCE_GET
,
204 .reply_cmd
= ETHTOOL_MSG_COALESCE_GET_REPLY
,
205 .hdr_attr
= ETHTOOL_A_COALESCE_HEADER
,
206 .max_attr
= ETHTOOL_A_COALESCE_MAX
,
207 .req_info_size
= sizeof(struct coalesce_req_info
),
208 .reply_data_size
= sizeof(struct coalesce_reply_data
),
209 .request_policy
= coalesce_get_policy
,
211 .prepare_data
= coalesce_prepare_data
,
212 .reply_size
= coalesce_reply_size
,
213 .fill_reply
= coalesce_fill_reply
,
218 static const struct nla_policy
219 coalesce_set_policy
[ETHTOOL_A_COALESCE_MAX
+ 1] = {
220 [ETHTOOL_A_COALESCE_UNSPEC
] = { .type
= NLA_REJECT
},
221 [ETHTOOL_A_COALESCE_HEADER
] = { .type
= NLA_NESTED
},
222 [ETHTOOL_A_COALESCE_RX_USECS
] = { .type
= NLA_U32
},
223 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES
] = { .type
= NLA_U32
},
224 [ETHTOOL_A_COALESCE_RX_USECS_IRQ
] = { .type
= NLA_U32
},
225 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
226 [ETHTOOL_A_COALESCE_TX_USECS
] = { .type
= NLA_U32
},
227 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES
] = { .type
= NLA_U32
},
228 [ETHTOOL_A_COALESCE_TX_USECS_IRQ
] = { .type
= NLA_U32
},
229 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
230 [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
] = { .type
= NLA_U32
},
231 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
] = { .type
= NLA_U8
},
232 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
] = { .type
= NLA_U8
},
233 [ETHTOOL_A_COALESCE_PKT_RATE_LOW
] = { .type
= NLA_U32
},
234 [ETHTOOL_A_COALESCE_RX_USECS_LOW
] = { .type
= NLA_U32
},
235 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
236 [ETHTOOL_A_COALESCE_TX_USECS_LOW
] = { .type
= NLA_U32
},
237 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
238 [ETHTOOL_A_COALESCE_PKT_RATE_HIGH
] = { .type
= NLA_U32
},
239 [ETHTOOL_A_COALESCE_RX_USECS_HIGH
] = { .type
= NLA_U32
},
240 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
241 [ETHTOOL_A_COALESCE_TX_USECS_HIGH
] = { .type
= NLA_U32
},
242 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
243 [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
] = { .type
= NLA_U32
},
246 int ethnl_set_coalesce(struct sk_buff
*skb
, struct genl_info
*info
)
248 struct nlattr
*tb
[ETHTOOL_A_COALESCE_MAX
+ 1];
249 struct ethtool_coalesce coalesce
= {};
250 struct ethnl_req_info req_info
= {};
251 const struct ethtool_ops
*ops
;
252 struct net_device
*dev
;
253 u32 supported_params
;
258 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
,
259 ETHTOOL_A_COALESCE_MAX
, coalesce_set_policy
,
263 ret
= ethnl_parse_header_dev_get(&req_info
,
264 tb
[ETHTOOL_A_COALESCE_HEADER
],
265 genl_info_net(info
), info
->extack
,
270 ops
= dev
->ethtool_ops
;
272 if (!ops
->get_coalesce
|| !ops
->set_coalesce
)
275 /* make sure that only supported parameters are present */
276 supported_params
= ops
->supported_coalesce_params
;
277 for (a
= ETHTOOL_A_COALESCE_RX_USECS
; a
< __ETHTOOL_A_COALESCE_CNT
; a
++)
278 if (tb
[a
] && !(supported_params
& attr_to_mask(a
))) {
280 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[a
],
281 "cannot modify an unsupported parameter");
286 ret
= ethnl_ops_begin(dev
);
289 ret
= ops
->get_coalesce(dev
, &coalesce
);
293 ethnl_update_u32(&coalesce
.rx_coalesce_usecs
,
294 tb
[ETHTOOL_A_COALESCE_RX_USECS
], &mod
);
295 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames
,
296 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES
], &mod
);
297 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_irq
,
298 tb
[ETHTOOL_A_COALESCE_RX_USECS_IRQ
], &mod
);
299 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_irq
,
300 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
], &mod
);
301 ethnl_update_u32(&coalesce
.tx_coalesce_usecs
,
302 tb
[ETHTOOL_A_COALESCE_TX_USECS
], &mod
);
303 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames
,
304 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES
], &mod
);
305 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_irq
,
306 tb
[ETHTOOL_A_COALESCE_TX_USECS_IRQ
], &mod
);
307 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_irq
,
308 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
], &mod
);
309 ethnl_update_u32(&coalesce
.stats_block_coalesce_usecs
,
310 tb
[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
], &mod
);
311 ethnl_update_bool32(&coalesce
.use_adaptive_rx_coalesce
,
312 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
], &mod
);
313 ethnl_update_bool32(&coalesce
.use_adaptive_tx_coalesce
,
314 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
], &mod
);
315 ethnl_update_u32(&coalesce
.pkt_rate_low
,
316 tb
[ETHTOOL_A_COALESCE_PKT_RATE_LOW
], &mod
);
317 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_low
,
318 tb
[ETHTOOL_A_COALESCE_RX_USECS_LOW
], &mod
);
319 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_low
,
320 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
], &mod
);
321 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_low
,
322 tb
[ETHTOOL_A_COALESCE_TX_USECS_LOW
], &mod
);
323 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_low
,
324 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
], &mod
);
325 ethnl_update_u32(&coalesce
.pkt_rate_high
,
326 tb
[ETHTOOL_A_COALESCE_PKT_RATE_HIGH
], &mod
);
327 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_high
,
328 tb
[ETHTOOL_A_COALESCE_RX_USECS_HIGH
], &mod
);
329 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_high
,
330 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
], &mod
);
331 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_high
,
332 tb
[ETHTOOL_A_COALESCE_TX_USECS_HIGH
], &mod
);
333 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_high
,
334 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
], &mod
);
335 ethnl_update_u32(&coalesce
.rate_sample_interval
,
336 tb
[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
], &mod
);
341 ret
= dev
->ethtool_ops
->set_coalesce(dev
, &coalesce
);
344 ethtool_notify(dev
, ETHTOOL_MSG_COALESCE_NTF
, NULL
);
347 ethnl_ops_complete(dev
);