From f5128a76726105f398d7ee70ee523dd4f68d62f4 Mon Sep 17 00:00:00 2001 From: ChunYuZhiQiang Date: Tue, 27 Oct 2026 14:50:12 +0800 Subject: [PATCH] can: dev: can_tdc_fill_info(): don't read automatic TDCV if interface is down The automatic TDCV readback calls into the driver via do_get_auto_tdcv(). Some drivers, such as xcan_get_auto_tdcv(), read controller registers without taking a runtime PM reference, so calling this while the interface is down can touch registers whose clocks are gated. Gate do_get_auto_tdcv() on netif_running() in can_tdc_fill_info() and adjust can_tdc_get_size() and can_data_bittiming_get_size() so that only the automatic TDCV size is skipped when the interface is down. The other TDC parameters are still reported, as they are meaningful while the interface is down. This is a defensive hardening based on code inspection; the automatic TDCV path has not been triggered on hardware. Signed-off-by: ChunYuZhiQiang Reviewed-by: Vincent Mailhol Fixes: e8060f08cd69 ("can: netlink: add can_priv::do_get_auto_tdcv() to retrieve tdcv from device") Link: https://patch.msgid.link/20261027065012.191348-2-chunyuzhiqiang@yinhe.ht [mkl: fix open parenthesis alignment] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/netlink.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index b958c04d53db..081dfddda000 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -720,7 +720,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], return 0; } -static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, +static size_t can_tdc_get_size(const struct net_device *dev, + struct data_bittiming_params *dbt_params, u32 tdc_flags) { bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; @@ -742,7 +743,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, } if (tdc_flags) { - if (tdc_manual || dbt_params->do_get_auto_tdcv) + if (tdc_manual || + (dbt_params->do_get_auto_tdcv && netif_running(dev))) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */ if (dbt_params->tdc_const->tdcf_max) @@ -752,7 +754,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, return size; } -static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params, +static size_t can_data_bittiming_get_size(const struct net_device *dev, + struct data_bittiming_params *dbt_params, u32 tdc_flags) { size_t size = 0; @@ -764,7 +767,7 @@ static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_para if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST */ size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) * dbt_params->data_bitrate_const_cnt); - size += can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */ + size += can_tdc_get_size(dev, dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */ return size; } @@ -825,10 +828,10 @@ static size_t can_get_size(const struct net_device *dev) size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */ size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */ - size += can_data_bittiming_get_size(&priv->fd, + size += can_data_bittiming_get_size(dev, &priv->fd, priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); - size += can_data_bittiming_get_size(&priv->xl, + size += can_data_bittiming_get_size(dev, &priv->xl, priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */ priv->ctrlmode & CAN_CTRLMODE_XL_TMS); @@ -910,7 +913,7 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev, if (tdc_manual) { tdcv = tdc->tdcv; err = 0; - } else if (dbt_params->do_get_auto_tdcv) { + } else if (dbt_params->do_get_auto_tdcv && netif_running(dev)) { err = dbt_params->do_get_auto_tdcv(dev, &tdcv); } if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))