[PATCH v5 6/7] can: netlink: add can_priv::do_get_auto_tdcv() to retrieve tdcv from device

From: Vincent Mailhol
Date: Sat Aug 14 2021 - 23:34:22 EST


Some CAN device can measure the TDCV (Transmission Delay Compensation
Value) automatically for each transmitted CAN frames.

A callback function do_get_auto_tdcv() is added to retrieve that
value. This function is used only if CAN_CTRLMODE_TDC_AUTO is enabled
(if CAN_CTRLMODE_TDC_MANUAL is selected, the TDCV value is provided by
the user).

If the device does not support reporting of TDCV, do_get_auto_tdcv()
should be set to NULL and TDCV will not be reported by the netlink
interface.

On success, do_get_auto_tdcv() shall return 0. If the value can not be
measured by the device, for example because network is down or because
no frames were transmitted yet, can_priv::do_get_auto_tdcv() shall
return a negative error code (e.g. -EINVAL) to signify that the value
is not yet available. In such cases, TDCV is not reported by the
netlink interface.

CC: Stefan Mätje <stefan.maetje@xxxxxx>
Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
---
drivers/net/can/dev/netlink.c | 15 ++++++++++++---
include/linux/can/dev.h | 1 +
2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
index f05745c96b9c..776284593b5d 100644
--- a/drivers/net/can/dev/netlink.c
+++ b/drivers/net/can/dev/netlink.c
@@ -362,7 +362,8 @@ static size_t can_tdc_get_size(const struct net_device *dev)
}

if (can_tdc_is_enabled(priv)) {
- if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL)
+ if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL ||
+ priv->do_get_auto_tdcv)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
if (priv->tdc_const->tdcf_max)
@@ -435,8 +436,16 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev)
goto err_cancel;

if (can_tdc_is_enabled(priv)) {
- if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL &&
- nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdc->tdcv))
+ u32 tdcv;
+ int err = -EINVAL;
+
+ if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) {
+ tdcv = tdc->tdcv;
+ err = 0;
+ } else if (priv->do_get_auto_tdcv) {
+ err = priv->do_get_auto_tdcv(dev, &tdcv);
+ }
+ if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
goto err_cancel;
if (nla_put_u32(skb, IFLA_CAN_TDC_TDCO, tdc->tdco))
goto err_cancel;
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index fa75e29182a3..266d0fe9de9d 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -74,6 +74,7 @@ struct can_priv {
enum can_state *state);
int (*do_get_berr_counter)(const struct net_device *dev,
struct can_berr_counter *bec);
+ int (*do_get_auto_tdcv)(const struct net_device *dev, u32 *tdcv);

unsigned int echo_skb_max;
struct sk_buff **echo_skb;
--
2.31.1