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 const struct nla_policy ethnl_coalesce_get_policy
[] = {
55 [ETHTOOL_A_COALESCE_HEADER
] =
56 NLA_POLICY_NESTED(ethnl_header_policy
),
59 static int coalesce_prepare_data(const struct ethnl_req_info
*req_base
,
60 struct ethnl_reply_data
*reply_base
,
61 struct genl_info
*info
)
63 struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
64 struct net_device
*dev
= reply_base
->dev
;
67 if (!dev
->ethtool_ops
->get_coalesce
)
69 data
->supported_params
= dev
->ethtool_ops
->supported_coalesce_params
;
70 ret
= ethnl_ops_begin(dev
);
73 ret
= dev
->ethtool_ops
->get_coalesce(dev
, &data
->coalesce
);
74 ethnl_ops_complete(dev
);
79 static int coalesce_reply_size(const struct ethnl_req_info
*req_base
,
80 const struct ethnl_reply_data
*reply_base
)
82 return nla_total_size(sizeof(u32
)) + /* _RX_USECS */
83 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES */
84 nla_total_size(sizeof(u32
)) + /* _RX_USECS_IRQ */
85 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_IRQ */
86 nla_total_size(sizeof(u32
)) + /* _TX_USECS */
87 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES */
88 nla_total_size(sizeof(u32
)) + /* _TX_USECS_IRQ */
89 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_IRQ */
90 nla_total_size(sizeof(u32
)) + /* _STATS_BLOCK_USECS */
91 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_RX */
92 nla_total_size(sizeof(u8
)) + /* _USE_ADAPTIVE_TX */
93 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_LOW */
94 nla_total_size(sizeof(u32
)) + /* _RX_USECS_LOW */
95 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_LOW */
96 nla_total_size(sizeof(u32
)) + /* _TX_USECS_LOW */
97 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_LOW */
98 nla_total_size(sizeof(u32
)) + /* _PKT_RATE_HIGH */
99 nla_total_size(sizeof(u32
)) + /* _RX_USECS_HIGH */
100 nla_total_size(sizeof(u32
)) + /* _RX_MAX_FRAMES_HIGH */
101 nla_total_size(sizeof(u32
)) + /* _TX_USECS_HIGH */
102 nla_total_size(sizeof(u32
)) + /* _TX_MAX_FRAMES_HIGH */
103 nla_total_size(sizeof(u32
)); /* _RATE_SAMPLE_INTERVAL */
106 static bool coalesce_put_u32(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
107 u32 supported_params
)
109 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
111 return nla_put_u32(skb
, attr_type
, val
);
114 static bool coalesce_put_bool(struct sk_buff
*skb
, u16 attr_type
, u32 val
,
115 u32 supported_params
)
117 if (!val
&& !(supported_params
& attr_to_mask(attr_type
)))
119 return nla_put_u8(skb
, attr_type
, !!val
);
122 static int coalesce_fill_reply(struct sk_buff
*skb
,
123 const struct ethnl_req_info
*req_base
,
124 const struct ethnl_reply_data
*reply_base
)
126 const struct coalesce_reply_data
*data
= COALESCE_REPDATA(reply_base
);
127 const struct ethtool_coalesce
*coal
= &data
->coalesce
;
128 u32 supported
= data
->supported_params
;
130 if (coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS
,
131 coal
->rx_coalesce_usecs
, supported
) ||
132 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES
,
133 coal
->rx_max_coalesced_frames
, supported
) ||
134 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_IRQ
,
135 coal
->rx_coalesce_usecs_irq
, supported
) ||
136 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
,
137 coal
->rx_max_coalesced_frames_irq
, supported
) ||
138 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS
,
139 coal
->tx_coalesce_usecs
, supported
) ||
140 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES
,
141 coal
->tx_max_coalesced_frames
, supported
) ||
142 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_IRQ
,
143 coal
->tx_coalesce_usecs_irq
, supported
) ||
144 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
,
145 coal
->tx_max_coalesced_frames_irq
, supported
) ||
146 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
,
147 coal
->stats_block_coalesce_usecs
, supported
) ||
148 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
,
149 coal
->use_adaptive_rx_coalesce
, supported
) ||
150 coalesce_put_bool(skb
, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
,
151 coal
->use_adaptive_tx_coalesce
, supported
) ||
152 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_LOW
,
153 coal
->pkt_rate_low
, supported
) ||
154 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_LOW
,
155 coal
->rx_coalesce_usecs_low
, supported
) ||
156 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
,
157 coal
->rx_max_coalesced_frames_low
, supported
) ||
158 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_LOW
,
159 coal
->tx_coalesce_usecs_low
, supported
) ||
160 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
,
161 coal
->tx_max_coalesced_frames_low
, supported
) ||
162 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_PKT_RATE_HIGH
,
163 coal
->pkt_rate_high
, supported
) ||
164 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_USECS_HIGH
,
165 coal
->rx_coalesce_usecs_high
, supported
) ||
166 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
,
167 coal
->rx_max_coalesced_frames_high
, supported
) ||
168 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_USECS_HIGH
,
169 coal
->tx_coalesce_usecs_high
, supported
) ||
170 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
,
171 coal
->tx_max_coalesced_frames_high
, supported
) ||
172 coalesce_put_u32(skb
, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
,
173 coal
->rate_sample_interval
, supported
))
179 const struct ethnl_request_ops ethnl_coalesce_request_ops
= {
180 .request_cmd
= ETHTOOL_MSG_COALESCE_GET
,
181 .reply_cmd
= ETHTOOL_MSG_COALESCE_GET_REPLY
,
182 .hdr_attr
= ETHTOOL_A_COALESCE_HEADER
,
183 .req_info_size
= sizeof(struct coalesce_req_info
),
184 .reply_data_size
= sizeof(struct coalesce_reply_data
),
186 .prepare_data
= coalesce_prepare_data
,
187 .reply_size
= coalesce_reply_size
,
188 .fill_reply
= coalesce_fill_reply
,
193 const struct nla_policy ethnl_coalesce_set_policy
[] = {
194 [ETHTOOL_A_COALESCE_HEADER
] =
195 NLA_POLICY_NESTED(ethnl_header_policy
),
196 [ETHTOOL_A_COALESCE_RX_USECS
] = { .type
= NLA_U32
},
197 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES
] = { .type
= NLA_U32
},
198 [ETHTOOL_A_COALESCE_RX_USECS_IRQ
] = { .type
= NLA_U32
},
199 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
200 [ETHTOOL_A_COALESCE_TX_USECS
] = { .type
= NLA_U32
},
201 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES
] = { .type
= NLA_U32
},
202 [ETHTOOL_A_COALESCE_TX_USECS_IRQ
] = { .type
= NLA_U32
},
203 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
] = { .type
= NLA_U32
},
204 [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
] = { .type
= NLA_U32
},
205 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
] = { .type
= NLA_U8
},
206 [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
] = { .type
= NLA_U8
},
207 [ETHTOOL_A_COALESCE_PKT_RATE_LOW
] = { .type
= NLA_U32
},
208 [ETHTOOL_A_COALESCE_RX_USECS_LOW
] = { .type
= NLA_U32
},
209 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
210 [ETHTOOL_A_COALESCE_TX_USECS_LOW
] = { .type
= NLA_U32
},
211 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
] = { .type
= NLA_U32
},
212 [ETHTOOL_A_COALESCE_PKT_RATE_HIGH
] = { .type
= NLA_U32
},
213 [ETHTOOL_A_COALESCE_RX_USECS_HIGH
] = { .type
= NLA_U32
},
214 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
215 [ETHTOOL_A_COALESCE_TX_USECS_HIGH
] = { .type
= NLA_U32
},
216 [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
] = { .type
= NLA_U32
},
217 [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
] = { .type
= NLA_U32
},
220 int ethnl_set_coalesce(struct sk_buff
*skb
, struct genl_info
*info
)
222 struct ethtool_coalesce coalesce
= {};
223 struct ethnl_req_info req_info
= {};
224 struct nlattr
**tb
= info
->attrs
;
225 const struct ethtool_ops
*ops
;
226 struct net_device
*dev
;
227 u32 supported_params
;
232 ret
= ethnl_parse_header_dev_get(&req_info
,
233 tb
[ETHTOOL_A_COALESCE_HEADER
],
234 genl_info_net(info
), info
->extack
,
239 ops
= dev
->ethtool_ops
;
241 if (!ops
->get_coalesce
|| !ops
->set_coalesce
)
244 /* make sure that only supported parameters are present */
245 supported_params
= ops
->supported_coalesce_params
;
246 for (a
= ETHTOOL_A_COALESCE_RX_USECS
; a
< __ETHTOOL_A_COALESCE_CNT
; a
++)
247 if (tb
[a
] && !(supported_params
& attr_to_mask(a
))) {
249 NL_SET_ERR_MSG_ATTR(info
->extack
, tb
[a
],
250 "cannot modify an unsupported parameter");
255 ret
= ethnl_ops_begin(dev
);
258 ret
= ops
->get_coalesce(dev
, &coalesce
);
262 ethnl_update_u32(&coalesce
.rx_coalesce_usecs
,
263 tb
[ETHTOOL_A_COALESCE_RX_USECS
], &mod
);
264 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames
,
265 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES
], &mod
);
266 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_irq
,
267 tb
[ETHTOOL_A_COALESCE_RX_USECS_IRQ
], &mod
);
268 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_irq
,
269 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ
], &mod
);
270 ethnl_update_u32(&coalesce
.tx_coalesce_usecs
,
271 tb
[ETHTOOL_A_COALESCE_TX_USECS
], &mod
);
272 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames
,
273 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES
], &mod
);
274 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_irq
,
275 tb
[ETHTOOL_A_COALESCE_TX_USECS_IRQ
], &mod
);
276 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_irq
,
277 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ
], &mod
);
278 ethnl_update_u32(&coalesce
.stats_block_coalesce_usecs
,
279 tb
[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS
], &mod
);
280 ethnl_update_bool32(&coalesce
.use_adaptive_rx_coalesce
,
281 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX
], &mod
);
282 ethnl_update_bool32(&coalesce
.use_adaptive_tx_coalesce
,
283 tb
[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX
], &mod
);
284 ethnl_update_u32(&coalesce
.pkt_rate_low
,
285 tb
[ETHTOOL_A_COALESCE_PKT_RATE_LOW
], &mod
);
286 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_low
,
287 tb
[ETHTOOL_A_COALESCE_RX_USECS_LOW
], &mod
);
288 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_low
,
289 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW
], &mod
);
290 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_low
,
291 tb
[ETHTOOL_A_COALESCE_TX_USECS_LOW
], &mod
);
292 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_low
,
293 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW
], &mod
);
294 ethnl_update_u32(&coalesce
.pkt_rate_high
,
295 tb
[ETHTOOL_A_COALESCE_PKT_RATE_HIGH
], &mod
);
296 ethnl_update_u32(&coalesce
.rx_coalesce_usecs_high
,
297 tb
[ETHTOOL_A_COALESCE_RX_USECS_HIGH
], &mod
);
298 ethnl_update_u32(&coalesce
.rx_max_coalesced_frames_high
,
299 tb
[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH
], &mod
);
300 ethnl_update_u32(&coalesce
.tx_coalesce_usecs_high
,
301 tb
[ETHTOOL_A_COALESCE_TX_USECS_HIGH
], &mod
);
302 ethnl_update_u32(&coalesce
.tx_max_coalesced_frames_high
,
303 tb
[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH
], &mod
);
304 ethnl_update_u32(&coalesce
.rate_sample_interval
,
305 tb
[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL
], &mod
);
310 ret
= dev
->ethtool_ops
->set_coalesce(dev
, &coalesce
);
313 ethtool_notify(dev
, ETHTOOL_MSG_COALESCE_NTF
, NULL
);
316 ethnl_ops_complete(dev
);