Skip to content

Commit 00d0f31

Browse files
committed
net: ethtool: coalesce: try to make user settings stick twice
SET_COALESCE may change operation mode and parameters in one call. Changing operation mode may cause the driver to reset the parameter values to what is a reasonable default for new operation mode. Since driver does not know which parameters come from user and which are echoed back from ->get, driver may ignore the parameters when switching operation modes. This used to be inevitable for ioctl() but in netlink we know which parameters are actually specified by the user. We could inform which parameters were set by the user but this would lead to a lot of code duplication in the drivers. Instead try to call the drivers twice if both mode and params are changed. The set method already checks if any params need updating so in case the driver did the right thing the first time around - there will be no second call to it's ->set method (only an extra call to ->get()). For mlx5 for example before this patch we'd see: # ethtool -C eth0 adaptive-rx on adaptive-tx on # ethtool -C eth0 adaptive-rx off adaptive-tx off \ tx-usecs 123 rx-usecs 123 Adaptive RX: off TX: off rx-usecs: 3 rx-frames: 32 tx-usecs: 16 tx-frames: 32 [...] After the change: # ethtool -C eth0 adaptive-rx on adaptive-tx on # ethtool -C eth0 adaptive-rx off adaptive-tx off \ tx-usecs 123 rx-usecs 123 Adaptive RX: off TX: off rx-usecs: 123 rx-frames: 32 tx-usecs: 123 tx-frames: 32 [...] This only works for netlink, so it's a small discrepancy between netlink and ioctl(). Since we anticipate most users to move to netlink I believe it's worth making their lives easier. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 086c161 commit 00d0f31

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

Documentation/networking/ethtool-netlink.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,10 @@ such that the corresponding bit in ``ethtool_ops::supported_coalesce_params``
10991099
is not set), regardless of their values. Driver may impose additional
11001100
constraints on coalescing parameters and their values.
11011101

1102+
Compared to requests issued via the ``ioctl()`` netlink version of this request
1103+
will try harder to make sure that values specified by the user have been applied
1104+
and may call the driver twice.
1105+
11021106

11031107
PAUSE_GET
11041108
=========

net/ethtool/coalesce.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,20 +254,22 @@ ethnl_set_coalesce_validate(struct ethnl_req_info *req_info,
254254
}
255255

256256
static int
257-
ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info)
257+
__ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info,
258+
bool *dual_change)
258259
{
259260
struct kernel_ethtool_coalesce kernel_coalesce = {};
260261
struct net_device *dev = req_info->dev;
261262
struct ethtool_coalesce coalesce = {};
263+
bool mod_mode = false, mod = false;
262264
struct nlattr **tb = info->attrs;
263-
bool mod = false;
264265
int ret;
265266

266267
ret = dev->ethtool_ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
267268
info->extack);
268269
if (ret < 0)
269270
return ret;
270271

272+
/* Update values */
271273
ethnl_update_u32(&coalesce.rx_coalesce_usecs,
272274
tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
273275
ethnl_update_u32(&coalesce.rx_max_coalesced_frames,
@@ -286,10 +288,6 @@ ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info)
286288
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ], &mod);
287289
ethnl_update_u32(&coalesce.stats_block_coalesce_usecs,
288290
tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS], &mod);
289-
ethnl_update_bool32(&coalesce.use_adaptive_rx_coalesce,
290-
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX], &mod);
291-
ethnl_update_bool32(&coalesce.use_adaptive_tx_coalesce,
292-
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX], &mod);
293291
ethnl_update_u32(&coalesce.pkt_rate_low,
294292
tb[ETHTOOL_A_COALESCE_PKT_RATE_LOW], &mod);
295293
ethnl_update_u32(&coalesce.rx_coalesce_usecs_low,
@@ -312,24 +310,58 @@ ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info)
312310
tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH], &mod);
313311
ethnl_update_u32(&coalesce.rate_sample_interval,
314312
tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL], &mod);
315-
ethnl_update_u8(&kernel_coalesce.use_cqe_mode_tx,
316-
tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX], &mod);
317-
ethnl_update_u8(&kernel_coalesce.use_cqe_mode_rx,
318-
tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX], &mod);
319313
ethnl_update_u32(&kernel_coalesce.tx_aggr_max_bytes,
320314
tb[ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES], &mod);
321315
ethnl_update_u32(&kernel_coalesce.tx_aggr_max_frames,
322316
tb[ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES], &mod);
323317
ethnl_update_u32(&kernel_coalesce.tx_aggr_time_usecs,
324318
tb[ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS], &mod);
325-
if (!mod)
319+
320+
/* Update operation modes */
321+
ethnl_update_bool32(&coalesce.use_adaptive_rx_coalesce,
322+
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX], &mod_mode);
323+
ethnl_update_bool32(&coalesce.use_adaptive_tx_coalesce,
324+
tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX], &mod_mode);
325+
ethnl_update_u8(&kernel_coalesce.use_cqe_mode_tx,
326+
tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX], &mod_mode);
327+
ethnl_update_u8(&kernel_coalesce.use_cqe_mode_rx,
328+
tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX], &mod_mode);
329+
330+
*dual_change = mod && mod_mode;
331+
if (!mod && !mod_mode)
326332
return 0;
327333

328334
ret = dev->ethtool_ops->set_coalesce(dev, &coalesce, &kernel_coalesce,
329335
info->extack);
330336
return ret < 0 ? ret : 1;
331337
}
332338

339+
static int
340+
ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info)
341+
{
342+
bool dual_change;
343+
int err, ret;
344+
345+
/* SET_COALESCE may change operation mode and parameters in one call.
346+
* Changing operation mode may cause the driver to reset the parameter
347+
* values, and therefore ignore user input (driver does not know which
348+
* parameters come from user and which are echoed back from ->get).
349+
* To not complicate the drivers if user tries to change both the mode
350+
* and parameters at once - call the driver twice.
351+
*/
352+
err = __ethnl_set_coalesce(req_info, info, &dual_change);
353+
if (err < 0)
354+
return err;
355+
ret = err;
356+
357+
if (ret && dual_change) {
358+
err = __ethnl_set_coalesce(req_info, info, &dual_change);
359+
if (err < 0)
360+
return err;
361+
}
362+
return ret;
363+
}
364+
333365
const struct ethnl_request_ops ethnl_coalesce_request_ops = {
334366
.request_cmd = ETHTOOL_MSG_COALESCE_GET,
335367
.reply_cmd = ETHTOOL_MSG_COALESCE_GET_REPLY,

0 commit comments

Comments
 (0)