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
;
13 struct kernel_ethtool_coalesce kernel_coalesce
;
17 #define COALESCE_REPDATA(__reply_base) \
18 container_of(__reply_base, struct coalesce_reply_data, base)
20 #define __SUPPORTED_OFFSET ETHTOOL_A_COALESCE_RX_USECS
21 static u32
attr_to_mask(unsigned int attr_type
)
23 return BIT(attr_type
- __SUPPORTED_OFFSET
);
26 /* build time check that indices in ethtool_ops::supported_coalesce_params
27 * match corresponding attribute types with an offset
29 #define __CHECK_SUPPORTED_OFFSET(x) \
30 static_assert((ETHTOOL_ ## x) == \
31 BIT((ETHTOOL_A_ ## x) - __SUPPORTED_OFFSET))
32 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS
);
33 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES
);
34 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_IRQ
);
35 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_IRQ
);
36 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS
);
37 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES
);
38 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_IRQ
);
39 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_IRQ
);
40 __CHECK_SUPPORTED_OFFSET(COALESCE_STATS_BLOCK_USECS
);
41 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_RX
);
42 __CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_TX
);
43 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_LOW
);
44 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_LOW
);
45 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_LOW
);
46 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_LOW
);
47 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_LOW
);
48 __CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_HIGH
);
49 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_HIGH
);
50 __CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH
);
51 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH
);
52 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH
);
53 __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL
);
55 const struct nla_policy ethnl_coalesce_get_policy
[] = {
56 [ETHTOOL_A_COALESCE_HEADER
] =
57 NLA_POLICY_NESTED(ethnl_header_policy
),
60 static int coalesce_prepare_data(const struct ethnl_req_info
*req_base
,
61 struct ethnl_reply_data
*reply_base
,
62 struct genl_info
*info
)
64 struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
65 struct netlink_ext_ack
*extack
= info
? info
->extack
: NULL
;
66 struct net_device
*dev
= reply_base
->dev
;
69 if (!dev
->ethtool_ops
->get_coalesce
)
71 data
->supported_params
= dev
->ethtool_ops
->supported_coalesce_params
;
72 ret
= ethnl_ops_begin(dev
);
75 ret
= dev
->ethtool_ops
->get_coalesce(dev
, &data
->coalesce
,
76 &data
->kernel_coalesce
, extack
);
77 ethnl_ops_complete(dev
);
82 static int coalesce_reply_size(const struct ethnl_req_info
*req_base
,
83 const struct ethnl_reply_data
*reply_base
)
85 return nla_total_size(sizeof(u32
)) + /* _RX_USECS */
86 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES */
87 nla_total_size(sizeof(u32
)) + /* _RX_USECS_IRQ */
88 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_IRQ */
89 nla_total_size(sizeof(u32
)) + /* _TX_USECS */
90 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES */
91 nla_total_size(sizeof(u32
)) + /* _TX_USECS_IRQ */
92 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_IRQ */
93 nla_total_size(sizeof(u32
)) + /* _STATS_BLOCK_USECS */
94 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_RX */
95 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_TX */
96 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_LOW */
97 nla_total_size(sizeof(u32
)) + /* _RX_USECS_LOW */
98 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_LOW */
99 nla_total_size(sizeof(u32
)) + /* _TX_USECS_LOW */
100 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_LOW */
101 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_HIGH */
102 nla_total_size(sizeof(u32
)) + /* _RX_USECS_HIGH */
103 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_HIGH */
104 nla_total_size(sizeof(u32
)) + /* _TX_USECS_HIGH */
105 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_HIGH */
106 nla_total_size(sizeof(u32
)) + /* _RATE_SAMPLE_INTERVAL */
107 nla_total_size(sizeof(u8
)) + /* _USE_CQE_MODE_TX */
108 nla_total_size(sizeof(u8
)); /* _USE_CQE_MODE_RX */
111 static bool coalesce_put_u32(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
112 u32 supported_params
)
114 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
116 return nla_put_u32(skb
, attr_type
, val
);
119 static bool coalesce_put_bool(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
120 u32 supported_params
)
122 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
124 return nla_put_u8(skb
, attr_type
, !!val
);
127 static int coalesce_fill_reply(struct sk_buff
*skb
,
128 const struct ethnl_req_info
*req_base
,
129 const struct ethnl_reply_data
*reply_base
)
131 const struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
132 const struct kernel_ethtool_coalesce
*kcoal
= &data
->kernel_coalesce
;
133 const struct ethtool_coalesce
*coal
= &data
->coalesce
;
134 u32 supported
= data
->supported_params
;
136 if (coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS
,
137 coal
->rx_coalesce_usecs
, supported
) ||
138 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES
,
139 coal
->rx_max_coalesced_frames
, supported
) ||
140 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_IRQ
,
141 coal
->rx_coalesce_usecs_irq
, supported
) ||
142 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
,
143 coal
->rx_max_coalesced_frames_irq
, supported
) ||
144 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS
,
145 coal
->tx_coalesce_usecs
, supported
) ||
146 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES
,
147 coal
->tx_max_coalesced_frames
, supported
) ||
148 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_IRQ
,
149 coal
->tx_coalesce_usecs_irq
, supported
) ||
150 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
,
151 coal
->tx_max_coalesced_frames_irq
, supported
) ||
152 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
,
153 coal
->stats_block_coalesce_usecs
, supported
) ||
154 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
,
155 coal
->use_adaptive_rx_coalesce
, supported
) ||
156 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
,
157 coal
->use_adaptive_tx_coalesce
, supported
) ||
158 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_LOW
,
159 coal
->pkt_rate_low
, supported
) ||
160 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_LOW
,
161 coal
->rx_coalesce_usecs_low
, supported
) ||
162 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
,
163 coal
->rx_max_coalesced_frames_low
, supported
) ||
164 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_LOW
,
165 coal
->tx_coalesce_usecs_low
, supported
) ||
166 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
,
167 coal
->tx_max_coalesced_frames_low
, supported
) ||
168 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_HIGH
,
169 coal
->pkt_rate_high
, supported
) ||
170 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_HIGH
,
171 coal
->rx_coalesce_usecs_high
, supported
) ||
172 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
,
173 coal
->rx_max_coalesced_frames_high
, supported
) ||
174 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_HIGH
,
175 coal
->tx_coalesce_usecs_high
, supported
) ||
176 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
,
177 coal
->tx_max_coalesced_frames_high
, supported
) ||
178 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
,
179 coal
->rate_sample_interval
, supported
) ||
180 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX
,
181 kcoal
->use_cqe_mode_tx
, supported
) ||
182 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX
,
183 kcoal
->use_cqe_mode_rx
, supported
))
189 const struct ethnl_request_ops ethnl_coalesce_request_ops
= {
190 .request_cmd
= ETHTOOL_MSG_COALESCE_GET
,
191 .reply_cmd
= ETHTOOL_MSG_COALESCE_GET_REPLY
,
192 .hdr_attr
= ETHTOOL_A_COALESCE_HEADER
,
193 .req_info_size
= sizeof(struct coalesce_req_info
),
194 .reply_data_size
= sizeof(struct coalesce_reply_data
),
196 .prepare_data
= coalesce_prepare_data
,
197 .reply_size
= coalesce_reply_size
,
198 .fill_reply
= coalesce_fill_reply
,
203 const struct nla_policy ethnl_coalesce_set_policy
[] = {
204 [ETHTOOL_A_COALESCE_HEADER
] =
205 NLA_POLICY_NESTED(ethnl_header_policy
),
206 [ETHTOOL_A_COALESCE_RX_USECS
] = { .type
= NLA_U32
},
207 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES
] = { .type
= NLA_U32
},
208 [ETHTOOL_A_COALESCE_RX_USECS_IRQ
] = { .type
= NLA_U32
},
209 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
210 [ETHTOOL_A_COALESCE_TX_USECS
] = { .type
= NLA_U32
},
211 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES
] = { .type
= NLA_U32
},
212 [ETHTOOL_A_COALESCE_TX_USECS_IRQ
] = { .type
= NLA_U32
},
213 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
214 [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
] = { .type
= NLA_U32
},
215 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
] = { .type
= NLA_U8
},
216 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
] = { .type
= NLA_U8
},
217 [ETHTOOL_A_COALESCE_PKT_RATE_LOW
] = { .type
= NLA_U32
},
218 [ETHTOOL_A_COALESCE_RX_USECS_LOW
] = { .type
= NLA_U32
},
219 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
220 [ETHTOOL_A_COALESCE_TX_USECS_LOW
] = { .type
= NLA_U32
},
221 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
222 [ETHTOOL_A_COALESCE_PKT_RATE_HIGH
] = { .type
= NLA_U32
},
223 [ETHTOOL_A_COALESCE_RX_USECS_HIGH
] = { .type
= NLA_U32
},
224 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
225 [ETHTOOL_A_COALESCE_TX_USECS_HIGH
] = { .type
= NLA_U32
},
226 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
227 [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
] = { .type
= NLA_U32
},
228 [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX
] = NLA_POLICY_MAX(NLA_U8
, 1),
229 [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX
] = NLA_POLICY_MAX(NLA_U8
, 1),
232 int ethnl_set_coalesce(struct sk_buff
*skb
, struct genl_info
*info
)
234 struct kernel_ethtool_coalesce kernel_coalesce
= {};
235 struct ethtool_coalesce coalesce
= {};
236 struct ethnl_req_info req_info
= {};
237 struct nlattr
**tb
= info
->attrs
;
238 const struct ethtool_ops
*ops
;
239 struct net_device
*dev
;
240 u32 supported_params
;
245 ret
= ethnl_parse_header_dev_get(&req_info
,
246 tb
[ETHTOOL_A_COALESCE_HEADER
],
247 genl_info_net(info
), info
->extack
,
252 ops
= dev
->ethtool_ops
;
254 if (!ops
->get_coalesce
|| !ops
->set_coalesce
)
257 /* make sure that only supported parameters are present */
258 supported_params
= ops
->supported_coalesce_params
;
259 for (a
= ETHTOOL_A_COALESCE_RX_USECS
; a
< __ETHTOOL_A_COALESCE_CNT
; a
++)
260 if (tb
[a
] && !(supported_params
& attr_to_mask(a
))) {
262 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[a
],
263 "cannot modify an unsupported parameter");
268 ret
= ethnl_ops_begin(dev
);
271 ret
= ops
->get_coalesce(dev
, &coalesce
, &kernel_coalesce
,
276 ethnl_update_u32(&coalesce
.rx_coalesce_usecs
,
277 tb
[ETHTOOL_A_COALESCE_RX_USECS
], &mod
);
278 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames
,
279 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES
], &mod
);
280 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_irq
,
281 tb
[ETHTOOL_A_COALESCE_RX_USECS_IRQ
], &mod
);
282 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_irq
,
283 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
], &mod
);
284 ethnl_update_u32(&coalesce
.tx_coalesce_usecs
,
285 tb
[ETHTOOL_A_COALESCE_TX_USECS
], &mod
);
286 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames
,
287 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES
], &mod
);
288 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_irq
,
289 tb
[ETHTOOL_A_COALESCE_TX_USECS_IRQ
], &mod
);
290 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_irq
,
291 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
], &mod
);
292 ethnl_update_u32(&coalesce
.stats_block_coalesce_usecs
,
293 tb
[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
], &mod
);
294 ethnl_update_bool32(&coalesce
.use_adaptive_rx_coalesce
,
295 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
], &mod
);
296 ethnl_update_bool32(&coalesce
.use_adaptive_tx_coalesce
,
297 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
], &mod
);
298 ethnl_update_u32(&coalesce
.pkt_rate_low
,
299 tb
[ETHTOOL_A_COALESCE_PKT_RATE_LOW
], &mod
);
300 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_low
,
301 tb
[ETHTOOL_A_COALESCE_RX_USECS_LOW
], &mod
);
302 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_low
,
303 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
], &mod
);
304 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_low
,
305 tb
[ETHTOOL_A_COALESCE_TX_USECS_LOW
], &mod
);
306 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_low
,
307 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
], &mod
);
308 ethnl_update_u32(&coalesce
.pkt_rate_high
,
309 tb
[ETHTOOL_A_COALESCE_PKT_RATE_HIGH
], &mod
);
310 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_high
,
311 tb
[ETHTOOL_A_COALESCE_RX_USECS_HIGH
], &mod
);
312 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_high
,
313 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
], &mod
);
314 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_high
,
315 tb
[ETHTOOL_A_COALESCE_TX_USECS_HIGH
], &mod
);
316 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_high
,
317 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
], &mod
);
318 ethnl_update_u32(&coalesce
.rate_sample_interval
,
319 tb
[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
], &mod
);
320 ethnl_update_u8(&kernel_coalesce
.use_cqe_mode_tx
,
321 tb
[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX
], &mod
);
322 ethnl_update_u8(&kernel_coalesce
.use_cqe_mode_rx
,
323 tb
[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX
], &mod
);
328 ret
= dev
->ethtool_ops
->set_coalesce(dev
, &coalesce
, &kernel_coalesce
,
332 ethtool_notify(dev
, ETHTOOL_MSG_COALESCE_NTF
, NULL
);
335 ethnl_ops_complete(dev
);