If the interface is down, the CAN controller might be powered down, the clock disabled, and/or its external reset asserted. Don't call do_get_berr_counter() or do_get_auto_tdcv() to read the CAN controller if the interface is down. This fixes a generic logic problem that exists on all platforms. As a result, IFLA_CAN_BERR_COUNTER is no longer reported for down interfaces, and the automatic TDCV readback is skipped. The other TDC parameters are still reported, as they are meaningful while the interface is down. This is intentional: the counters and the automatic TDCV are not meaningful in that state, and calling into the driver can wake a runtime-suspended controller or touch registers whose clocks are gated. Fixes: ec56acfef2af1 ("can: flexcan: flexcan_get_berr_counter(): switch on clocks before accessing ecr register") Cc: stable@vger.kernel.org Signed-off-by: ChunYuZhiQiang --- v6: - Only gate do_get_auto_tdcv() on netif_running(), as suggested by Vincent Mailhol and Marc Kleine-Budde. The other TDC parameters are still reported for down interfaces. - Adjust can_tdc_get_size() so that only the automatic TDCV size is skipped when the interface is down. - Keep the berr-counter gating unchanged. --- drivers/net/can/dev/netlink.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 6f83b87d54fc..ae0cef791ef3 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -517,7 +517,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], } static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, - u32 tdc_flags) + u32 tdc_flags, bool auto_tdcv_running) { bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; size_t size; @@ -538,7 +538,7 @@ 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 && auto_tdcv_running)) 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) @@ -548,8 +548,9 @@ 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, - u32 tdc_flags) +static size_t +can_data_bittiming_get_size(struct data_bittiming_params *dbt_params, + u32 tdc_flags, bool auto_tdcv_running) { size_t size = 0; @@ -560,7 +561,8 @@ static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_para if (dbt_params->data_bitrate_const) /* IFLA_CAN_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_TDC */ + + size += can_tdc_get_size(dbt_params, tdc_flags, auto_tdcv_running); /* IFLA_CAN_TDC */ return size; } @@ -584,7 +586,7 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */ size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ - if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ + if (priv->do_get_berr_counter && netif_running(dev)) /* IFLA_CAN_BERR_COUNTER */ size += nla_total_size(sizeof(struct can_berr_counter)); if (priv->termination_const) { size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */ @@ -598,7 +600,8 @@ static size_t can_get_size(const struct net_device *dev) size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */ size += can_data_bittiming_get_size(&priv->fd, - priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); + priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK, + netif_running(dev)); return size; } @@ -675,7 +678,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)) @@ -735,7 +738,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) || nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) || - (priv->do_get_berr_counter && + (priv->do_get_berr_counter && netif_running(dev) && !priv->do_get_berr_counter(dev, &bec) && nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || -- 2.47.3