diff options
Diffstat (limited to 'drivers/net/can')
29 files changed, 1608 insertions, 499 deletions
diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c index a94bd67c670c..394d6974f481 100644 --- a/drivers/net/can/dev/calc_bittiming.c +++ b/drivers/net/can/dev/calc_bittiming.c @@ -173,13 +173,15 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, const struct can_bittiming *dbt, - u32 *ctrlmode, u32 ctrlmode_supported) + u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported) { - if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO)) + u32 tdc_auto = tdc_mask & CAN_CTRLMODE_TDC_AUTO_MASK; + + if (!tdc_const || !(ctrlmode_supported & tdc_auto)) return; - *ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; + *ctrlmode &= ~tdc_mask; /* As specified in ISO 11898-1 section 11.3.3 "Transmitter * delay compensation" (TDC) is only applicable if data BRP is @@ -193,6 +195,6 @@ void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, if (sample_point_in_tc < tdc_const->tdco_min) return; tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max); - *ctrlmode |= CAN_CTRLMODE_TDC_AUTO; + *ctrlmode |= tdc_auto; } } diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 3913971125de..15ccedbb3f8d 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -4,17 +4,17 @@ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/workqueue.h> #include <linux/can.h> #include <linux/can/can-ml.h> #include <linux/can/dev.h> #include <linux/can/skb.h> #include <linux/gpio/consumer.h> +#include <linux/if_arp.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> #include <linux/of.h> +#include <linux/slab.h> +#include <linux/workqueue.h> static void can_update_state_error_stats(struct net_device *dev, enum can_state new_state) @@ -88,6 +88,39 @@ const char *can_get_state_str(const enum can_state state) } EXPORT_SYMBOL_GPL(can_get_state_str); +const char *can_get_ctrlmode_str(u32 ctrlmode) +{ + switch (ctrlmode & ~(ctrlmode - 1)) { + case 0: + return "none"; + case CAN_CTRLMODE_LOOPBACK: + return "loopback"; + case CAN_CTRLMODE_LISTENONLY: + return "listen-only"; + case CAN_CTRLMODE_3_SAMPLES: + return "triple-sampling"; + case CAN_CTRLMODE_ONE_SHOT: + return "one-shot"; + case CAN_CTRLMODE_BERR_REPORTING: + return "berr-reporting"; + case CAN_CTRLMODE_FD: + return "fd"; + case CAN_CTRLMODE_PRESUME_ACK: + return "presume-ack"; + case CAN_CTRLMODE_FD_NON_ISO: + return "fd-non-iso"; + case CAN_CTRLMODE_CC_LEN8_DLC: + return "cc-len8-dlc"; + case CAN_CTRLMODE_TDC_AUTO: + return "fd-tdc-auto"; + case CAN_CTRLMODE_TDC_MANUAL: + return "fd-tdc-manual"; + default: + return "<unknown>"; + } +} +EXPORT_SYMBOL_GPL(can_get_ctrlmode_str); + static enum can_state can_state_err_to_state(u16 err) { if (err < CAN_ERROR_WARNING_THRESHOLD) @@ -240,6 +273,8 @@ void can_setup(struct net_device *dev) { dev->type = ARPHRD_CAN; dev->mtu = CAN_MTU; + dev->min_mtu = CAN_MTU; + dev->max_mtu = CAN_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 10; @@ -309,6 +344,21 @@ void free_candev(struct net_device *dev) } EXPORT_SYMBOL_GPL(free_candev); +void can_set_default_mtu(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (priv->ctrlmode & CAN_CTRLMODE_FD) { + dev->mtu = CANFD_MTU; + dev->min_mtu = CANFD_MTU; + dev->max_mtu = CANFD_MTU; + } else { + dev->mtu = CAN_MTU; + dev->min_mtu = CAN_MTU; + dev->max_mtu = CAN_MTU; + } +} + /* changing MTU and control mode for CAN/CANFD devices */ int can_change_mtu(struct net_device *dev, int new_mtu) { @@ -347,6 +397,26 @@ int can_change_mtu(struct net_device *dev, int new_mtu) } EXPORT_SYMBOL_GPL(can_change_mtu); +/* helper to define static CAN controller features at device creation time */ +int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode) +{ + struct can_priv *priv = netdev_priv(dev); + + /* alloc_candev() succeeded => netdev_priv() is valid at this point */ + if (priv->ctrlmode_supported & static_mode) { + netdev_warn(dev, + "Controller features can not be supported and static at the same time\n"); + return -EINVAL; + } + priv->ctrlmode = static_mode; + + /* override MTU which was set by default in can_setup()? */ + can_set_default_mtu(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(can_set_static_ctrlmode); + /* generic implementation of netdev_ops::ndo_eth_ioctl for CAN devices * supporting hardware timestamps */ diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index d9f6ab3efb97..0591406b6f32 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -36,116 +36,245 @@ static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { [IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 }, }; -static int can_validate_bittiming(const struct can_bittiming *bt, - struct netlink_ext_ack *extack) +static int can_validate_bittiming(struct nlattr *data[], + struct netlink_ext_ack *extack, + int ifla_can_bittiming) { + struct can_bittiming *bt; + + if (!data[ifla_can_bittiming]) + return 0; + + static_assert(__alignof__(*bt) <= NLA_ALIGNTO); + bt = nla_data(data[ifla_can_bittiming]); + /* sample point is in one-tenth of a percent */ if (bt->sample_point >= 1000) { NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%"); - return -EINVAL; } return 0; } -static int can_validate(struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) +static int can_validate_tdc(struct nlattr *data_tdc, + struct netlink_ext_ack *extack, u32 tdc_flags) { - bool is_can_fd = false; + bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; + bool tdc_auto = tdc_flags & CAN_CTRLMODE_TDC_AUTO_MASK; + int err; + + if (tdc_auto && tdc_manual) { + NL_SET_ERR_MSG(extack, + "TDC manual and auto modes are mutually exclusive"); + return -EOPNOTSUPP; + } + + /* If one of the CAN_CTRLMODE_TDC_* flag is set then TDC + * must be set and vice-versa + */ + if ((tdc_auto || tdc_manual) && !data_tdc) { + NL_SET_ERR_MSG(extack, "TDC parameters are missing"); + return -EOPNOTSUPP; + } + if (!(tdc_auto || tdc_manual) && data_tdc) { + NL_SET_ERR_MSG(extack, "TDC mode (auto or manual) is missing"); + return -EOPNOTSUPP; + } + + /* If providing TDC parameters, at least TDCO is needed. TDCV + * is needed if and only if CAN_CTRLMODE_TDC_MANUAL is set + */ + if (data_tdc) { + struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; + + err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, + data_tdc, can_tdc_policy, extack); + if (err) + return err; + + if (tb_tdc[IFLA_CAN_TDC_TDCV]) { + if (tdc_auto) { + NL_SET_ERR_MSG(extack, + "TDCV is incompatible with TDC auto mode"); + return -EOPNOTSUPP; + } + } else { + if (tdc_manual) { + NL_SET_ERR_MSG(extack, + "TDC manual mode requires TDCV"); + return -EOPNOTSUPP; + } + } + + if (!tb_tdc[IFLA_CAN_TDC_TDCO]) { + NL_SET_ERR_MSG(extack, "TDCO is missing"); + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int can_validate_databittiming(struct nlattr *data[], + struct netlink_ext_ack *extack, + int ifla_can_data_bittiming, u32 flags) +{ + struct nlattr *data_tdc; + const char *type; + u32 tdc_flags; + bool is_on; int err; /* Make sure that valid CAN FD configurations always consist of * - nominal/arbitration bittiming * - data bittiming * - control mode with CAN_CTRLMODE_FD set - * - TDC parameters are coherent (details below) + * - TDC parameters are coherent (details in can_validate_tdc()) */ + if (ifla_can_data_bittiming == IFLA_CAN_DATA_BITTIMING) { + data_tdc = data[IFLA_CAN_TDC]; + tdc_flags = flags & CAN_CTRLMODE_FD_TDC_MASK; + is_on = flags & CAN_CTRLMODE_FD; + type = "FD"; + } else { + return -EOPNOTSUPP; /* Place holder for CAN XL */ + } + + if (is_on) { + if (!data[IFLA_CAN_BITTIMING] || !data[ifla_can_data_bittiming]) { + NL_SET_ERR_MSG_FMT(extack, + "Provide both nominal and %s data bittiming", + type); + return -EOPNOTSUPP; + } + } else { + if (data[ifla_can_data_bittiming]) { + NL_SET_ERR_MSG_FMT(extack, + "%s data bittiming requires CAN %s", + type, type); + return -EOPNOTSUPP; + } + if (data_tdc) { + NL_SET_ERR_MSG_FMT(extack, + "%s TDC requires CAN %s", + type, type); + return -EOPNOTSUPP; + } + } + + err = can_validate_bittiming(data, extack, ifla_can_data_bittiming); + if (err) + return err; + + err = can_validate_tdc(data_tdc, extack, tdc_flags); + if (err) + return err; + + return 0; +} + +static int can_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + u32 flags = 0; + int err; + if (!data) return 0; if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); - u32 tdc_flags = cm->flags & CAN_CTRLMODE_FD_TDC_MASK; - is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; + flags = cm->flags & cm->mask; + } - /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */ - if (tdc_flags == CAN_CTRLMODE_FD_TDC_MASK) - return -EOPNOTSUPP; - /* If one of the CAN_CTRLMODE_TDC_* flag is set then - * TDC must be set and vice-versa - */ - if (!!tdc_flags != !!data[IFLA_CAN_TDC]) - return -EOPNOTSUPP; - /* If providing TDC parameters, at least TDCO is - * needed. TDCV is needed if and only if - * CAN_CTRLMODE_TDC_MANUAL is set - */ - if (data[IFLA_CAN_TDC]) { - struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; + err = can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); + if (err) + return err; - err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, - data[IFLA_CAN_TDC], - can_tdc_policy, extack); - if (err) - return err; + err = can_validate_databittiming(data, extack, + IFLA_CAN_DATA_BITTIMING, flags); + if (err) + return err; - if (tb_tdc[IFLA_CAN_TDC_TDCV]) { - if (tdc_flags & CAN_CTRLMODE_TDC_AUTO) - return -EOPNOTSUPP; - } else { - if (tdc_flags & CAN_CTRLMODE_TDC_MANUAL) - return -EOPNOTSUPP; - } + return 0; +} - if (!tb_tdc[IFLA_CAN_TDC_TDCO]) - return -EOPNOTSUPP; - } - } +static int can_ctrlmode_changelink(struct net_device *dev, + struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_ctrlmode *cm; + u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing; - if (data[IFLA_CAN_BITTIMING]) { - struct can_bittiming bt; + if (!data[IFLA_CAN_CTRLMODE]) + return 0; - memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - err = can_validate_bittiming(&bt, extack); - if (err) - return err; - } + /* Do not allow changing controller mode while running */ + if (dev->flags & IFF_UP) + return -EBUSY; - if (is_can_fd) { - if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) - return -EOPNOTSUPP; + cm = nla_data(data[IFLA_CAN_CTRLMODE]); + ctrlstatic = can_get_static_ctrlmode(priv); + maskedflags = cm->flags & cm->mask; + notsupp = maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); + ctrlstatic_missing = (maskedflags & ctrlstatic) ^ ctrlstatic; + + if (notsupp) { + NL_SET_ERR_MSG_FMT(extack, + "requested control mode %s not supported", + can_get_ctrlmode_str(notsupp)); + return -EOPNOTSUPP; } - if (data[IFLA_CAN_DATA_BITTIMING] || data[IFLA_CAN_TDC]) { - if (!is_can_fd) - return -EOPNOTSUPP; + /* do not check for static fd-non-iso if 'fd' is disabled */ + if (!(maskedflags & CAN_CTRLMODE_FD)) + ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; + + if (ctrlstatic_missing) { + NL_SET_ERR_MSG_FMT(extack, + "missing required %s static control mode", + can_get_ctrlmode_str(ctrlstatic_missing)); + return -EOPNOTSUPP; } - if (data[IFLA_CAN_DATA_BITTIMING]) { - struct can_bittiming bt; + /* If a top dependency flag is provided, reset all its dependencies */ + if (cm->mask & CAN_CTRLMODE_FD) + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; - memcpy(&bt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(bt)); - err = can_validate_bittiming(&bt, extack); - if (err) - return err; + /* clear bits to be modified and copy the flag values */ + priv->ctrlmode &= ~cm->mask; + priv->ctrlmode |= maskedflags; + + /* Wipe potential leftovers from previous CAN FD config */ + if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { + memset(&priv->fd.data_bittiming, 0, + sizeof(priv->fd.data_bittiming)); + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; + memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } + can_set_default_mtu(dev); + return 0; } -static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla, +static int can_tdc_changelink(struct data_bittiming_params *dbt_params, + const struct nlattr *nla, struct netlink_ext_ack *extack) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; struct can_tdc tdc = { 0 }; - const struct can_tdc_const *tdc_const = priv->fd.tdc_const; + const struct can_tdc_const *tdc_const = dbt_params->tdc_const; int err; - if (!tdc_const || !can_fd_tdc_is_enabled(priv)) + if (!tdc_const) { + NL_SET_ERR_MSG(extack, "The device does not support TDC"); return -EOPNOTSUPP; + } err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla, can_tdc_policy, extack); @@ -179,69 +308,107 @@ static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla, tdc.tdcf = tdcf; } - priv->fd.tdc = tdc; + dbt_params->tdc = tdc; return 0; } -static int can_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[], - struct netlink_ext_ack *extack) +static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[], + bool fd, struct netlink_ext_ack *extack) { + struct nlattr *data_bittiming, *data_tdc; struct can_priv *priv = netdev_priv(dev); - bool fd_tdc_flag_provided = false; + struct data_bittiming_params *dbt_params; + struct can_bittiming dbt; + bool need_tdc_calc = false; + u32 tdc_mask; int err; - /* We need synchronization with dev->stop() */ - ASSERT_RTNL(); + if (fd) { + data_bittiming = data[IFLA_CAN_DATA_BITTIMING]; + data_tdc = data[IFLA_CAN_TDC]; + dbt_params = &priv->fd; + tdc_mask = CAN_CTRLMODE_FD_TDC_MASK; + } else { + return -EOPNOTSUPP; /* Place holder for CAN XL */ + } - if (data[IFLA_CAN_CTRLMODE]) { - struct can_ctrlmode *cm; - u32 ctrlstatic; - u32 maskedflags; + if (!data_bittiming) + return 0; - /* Do not allow changing controller mode while running */ - if (dev->flags & IFF_UP) - return -EBUSY; - cm = nla_data(data[IFLA_CAN_CTRLMODE]); - ctrlstatic = can_get_static_ctrlmode(priv); - maskedflags = cm->flags & cm->mask; + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; - /* check whether provided bits are allowed to be passed */ - if (maskedflags & ~(priv->ctrlmode_supported | ctrlstatic)) - return -EOPNOTSUPP; + /* Calculate bittiming parameters based on data_bittiming_const + * if set, otherwise pass bitrate directly via do_set_bitrate(). + * Bail out if neither is given. + */ + if (!dbt_params->data_bittiming_const && !dbt_params->do_set_data_bittiming && + !dbt_params->data_bitrate_const) + return -EOPNOTSUPP; - /* do not check for static fd-non-iso if 'fd' is disabled */ - if (!(maskedflags & CAN_CTRLMODE_FD)) - ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; + memcpy(&dbt, nla_data(data_bittiming), sizeof(dbt)); + err = can_get_bittiming(dev, &dbt, dbt_params->data_bittiming_const, + dbt_params->data_bitrate_const, + dbt_params->data_bitrate_const_cnt, extack); + if (err) + return err; - /* make sure static options are provided by configuration */ - if ((maskedflags & ctrlstatic) != ctrlstatic) - return -EOPNOTSUPP; + if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) { + NL_SET_ERR_MSG_FMT(extack, + "CAN data bitrate %u bps surpasses transceiver capabilities of %u bps", + dbt.bitrate, priv->bitrate_max); + return -EINVAL; + } - /* clear bits to be modified and copy the flag values */ - priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= maskedflags; + memset(&dbt_params->tdc, 0, sizeof(dbt_params->tdc)); + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); - /* CAN_CTRLMODE_FD can only be set when driver supports FD */ - if (priv->ctrlmode & CAN_CTRLMODE_FD) { - dev->mtu = CANFD_MTU; - } else { - dev->mtu = CAN_MTU; - memset(&priv->fd.data_bittiming, 0, - sizeof(priv->fd.data_bittiming)); - priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; - memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); + need_tdc_calc = !(cm->mask & tdc_mask); + } + if (data_tdc) { + /* TDC parameters are provided: use them */ + err = can_tdc_changelink(dbt_params, data_tdc, extack); + if (err) { + priv->ctrlmode &= ~tdc_mask; + return err; } - - fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; - /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually - * exclusive: make sure to turn the other one off + } else if (need_tdc_calc) { + /* Neither of TDC parameters nor TDC flags are provided: + * do calculation */ - if (fd_tdc_flag_provided) - priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_FD_TDC_MASK; + can_calc_tdco(&dbt_params->tdc, dbt_params->tdc_const, &dbt, + tdc_mask, &priv->ctrlmode, priv->ctrlmode_supported); + } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly + * turned off. TDC is disabled: do nothing + */ + + memcpy(&dbt_params->data_bittiming, &dbt, sizeof(dbt)); + + if (dbt_params->do_set_data_bittiming) { + /* Finally, set the bit-timing registers */ + err = dbt_params->do_set_data_bittiming(dev); + if (err) + return err; } + return 0; +} + +static int can_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + struct can_priv *priv = netdev_priv(dev); + int err; + + /* We need synchronization with dev->stop() */ + ASSERT_RTNL(); + + can_ctrlmode_changelink(dev, data, extack); + if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt; @@ -312,75 +479,21 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], return err; } - if (data[IFLA_CAN_DATA_BITTIMING]) { - struct can_bittiming dbt; - - /* Do not allow changing bittiming while running */ - if (dev->flags & IFF_UP) - return -EBUSY; - - /* Calculate bittiming parameters based on - * data_bittiming_const if set, otherwise pass bitrate - * directly via do_set_bitrate(). Bail out if neither - * is given. - */ - if (!priv->fd.data_bittiming_const && !priv->fd.do_set_data_bittiming && - !priv->fd.data_bitrate_const) - return -EOPNOTSUPP; - - memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), - sizeof(dbt)); - err = can_get_bittiming(dev, &dbt, - priv->fd.data_bittiming_const, - priv->fd.data_bitrate_const, - priv->fd.data_bitrate_const_cnt, - extack); - if (err) - return err; - - if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) { - NL_SET_ERR_MSG_FMT(extack, - "CANFD data bitrate %u bps surpasses transceiver capabilities of %u bps", - dbt.bitrate, priv->bitrate_max); - return -EINVAL; - } - - memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); - if (data[IFLA_CAN_TDC]) { - /* TDC parameters are provided: use them */ - err = can_tdc_changelink(priv, data[IFLA_CAN_TDC], - extack); - if (err) { - priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; - return err; - } - } else if (!fd_tdc_flag_provided) { - /* Neither of TDC parameters nor TDC flags are - * provided: do calculation - */ - can_calc_tdco(&priv->fd.tdc, priv->fd.tdc_const, &dbt, - &priv->ctrlmode, priv->ctrlmode_supported); - } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly - * turned off. TDC is disabled: do nothing - */ - - memcpy(&priv->fd.data_bittiming, &dbt, sizeof(dbt)); - - if (priv->fd.do_set_data_bittiming) { - /* Finally, set the bit-timing registers */ - err = priv->fd.do_set_data_bittiming(dev); - if (err) - return err; - } - } + /* CAN FD */ + err = can_dbt_changelink(dev, data, true, extack); + if (err) + return err; if (data[IFLA_CAN_TERMINATION]) { const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]); const unsigned int num_term = priv->termination_const_cnt; unsigned int i; - if (!priv->do_set_termination) + if (!priv->do_set_termination) { + NL_SET_ERR_MSG(extack, + "Termination is not configurable on this device"); return -EOPNOTSUPP; + } /* check whether given value is supported by the interface */ for (i = 0; i < num_term; i++) { @@ -401,38 +514,55 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], return 0; } -static size_t can_tdc_get_size(const struct net_device *dev) +static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, + u32 tdc_flags) { - struct can_priv *priv = netdev_priv(dev); + bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; size_t size; - if (!priv->fd.tdc_const) + if (!dbt_params->tdc_const) return 0; size = nla_total_size(0); /* nest IFLA_CAN_TDC */ - if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL) { + if (tdc_manual) { size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV_MAX */ } size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO_MAX */ - if (priv->fd.tdc_const->tdcf_max) { + if (dbt_params->tdc_const->tdcf_max) { size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF_MAX */ } - if (can_fd_tdc_is_enabled(priv)) { - if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL || - priv->fd.do_get_auto_tdcv) + if (tdc_flags) { + if (tdc_manual || dbt_params->do_get_auto_tdcv) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */ - if (priv->fd.tdc_const->tdcf_max) + if (dbt_params->tdc_const->tdcf_max) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF */ } return size; } +static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params, + u32 tdc_flags) +{ + size_t size = 0; + + if (dbt_params->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + size += nla_total_size(sizeof(dbt_params->data_bittiming)); + if (dbt_params->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(*dbt_params->data_bittiming_const)); + 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 */ + + return size; +} + static size_t can_ctrlmode_ext_get_size(void) { return nla_total_size(0) + /* nest IFLA_CAN_CTRLMODE_EXT */ @@ -454,10 +584,6 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ size += nla_total_size(sizeof(struct can_berr_counter)); - if (priv->fd.data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ - size += nla_total_size(sizeof(struct can_bittiming)); - if (priv->fd.data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ - size += nla_total_size(sizeof(struct can_bittiming_const)); if (priv->termination_const) { size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */ size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */ @@ -466,31 +592,69 @@ static size_t can_get_size(const struct net_device *dev) if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */ size += nla_total_size(sizeof(*priv->bitrate_const) * priv->bitrate_const_cnt); - if (priv->fd.data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ - size += nla_total_size(sizeof(*priv->fd.data_bitrate_const) * - priv->fd.data_bitrate_const_cnt); size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */ - size += can_tdc_get_size(dev); /* IFLA_CAN_TDC */ 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); + return size; } -static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev) +static int can_bittiming_fill_info(struct sk_buff *skb, int ifla_can_bittiming, + struct can_bittiming *bittiming) +{ + return bittiming->bitrate != CAN_BITRATE_UNSET && + bittiming->bitrate != CAN_BITRATE_UNKNOWN && + nla_put(skb, ifla_can_bittiming, sizeof(*bittiming), bittiming); +} + +static int can_bittiming_const_fill_info(struct sk_buff *skb, + int ifla_can_bittiming_const, + const struct can_bittiming_const *bittiming_const) +{ + return bittiming_const && + nla_put(skb, ifla_can_bittiming_const, + sizeof(*bittiming_const), bittiming_const); +} + +static int can_bitrate_const_fill_info(struct sk_buff *skb, + int ifla_can_bitrate_const, + const u32 *bitrate_const, unsigned int cnt) +{ + return bitrate_const && + nla_put(skb, ifla_can_bitrate_const, + sizeof(*bitrate_const) * cnt, bitrate_const); +} + +static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev, + int ifla_can_tdc) { - struct nlattr *nest; struct can_priv *priv = netdev_priv(dev); - struct can_tdc *tdc = &priv->fd.tdc; - const struct can_tdc_const *tdc_const = priv->fd.tdc_const; + struct data_bittiming_params *dbt_params; + const struct can_tdc_const *tdc_const; + struct can_tdc *tdc; + struct nlattr *nest; + bool tdc_is_enabled, tdc_manual; + + if (ifla_can_tdc == IFLA_CAN_TDC) { + dbt_params = &priv->fd; + tdc_is_enabled = can_fd_tdc_is_enabled(priv); + tdc_manual = priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL; + } else { + return -EOPNOTSUPP; /* Place holder for CAN XL */ + } + tdc_const = dbt_params->tdc_const; + tdc = &dbt_params->tdc; if (!tdc_const) return 0; - nest = nla_nest_start(skb, IFLA_CAN_TDC); + nest = nla_nest_start(skb, ifla_can_tdc); if (!nest) return -EMSGSIZE; - if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL && + if (tdc_manual && (nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MIN, tdc_const->tdcv_min) || nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MAX, tdc_const->tdcv_max))) goto err_cancel; @@ -502,15 +666,15 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MAX, tdc_const->tdcf_max))) goto err_cancel; - if (can_fd_tdc_is_enabled(priv)) { + if (tdc_is_enabled) { u32 tdcv; int err = -EINVAL; - if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) { + if (tdc_manual) { tdcv = tdc->tdcv; err = 0; - } else if (priv->fd.do_get_auto_tdcv) { - err = priv->fd.do_get_auto_tdcv(dev, &tdcv); + } else if (dbt_params->do_get_auto_tdcv) { + err = dbt_params->do_get_auto_tdcv(dev, &tdcv); } if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv)) goto err_cancel; @@ -558,14 +722,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); - if ((priv->bittiming.bitrate != CAN_BITRATE_UNSET && - priv->bittiming.bitrate != CAN_BITRATE_UNKNOWN && - nla_put(skb, IFLA_CAN_BITTIMING, - sizeof(priv->bittiming), &priv->bittiming)) || + if (can_bittiming_fill_info(skb, IFLA_CAN_BITTIMING, + &priv->bittiming) || - (priv->bittiming_const && - nla_put(skb, IFLA_CAN_BITTIMING_CONST, - sizeof(*priv->bittiming_const), priv->bittiming_const)) || + can_bittiming_const_fill_info(skb, IFLA_CAN_BITTIMING_CONST, + priv->bittiming_const) || nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) || nla_put_u32(skb, IFLA_CAN_STATE, state) || @@ -576,14 +737,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) !priv->do_get_berr_counter(dev, &bec) && nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || - (priv->fd.data_bittiming.bitrate && - nla_put(skb, IFLA_CAN_DATA_BITTIMING, - sizeof(priv->fd.data_bittiming), &priv->fd.data_bittiming)) || + can_bittiming_fill_info(skb, IFLA_CAN_DATA_BITTIMING, + &priv->fd.data_bittiming) || - (priv->fd.data_bittiming_const && - nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, - sizeof(*priv->fd.data_bittiming_const), - priv->fd.data_bittiming_const)) || + can_bittiming_const_fill_info(skb, IFLA_CAN_DATA_BITTIMING_CONST, + priv->fd.data_bittiming_const) || (priv->termination_const && (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) || @@ -592,23 +750,19 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) priv->termination_const_cnt, priv->termination_const))) || - (priv->bitrate_const && - nla_put(skb, IFLA_CAN_BITRATE_CONST, - sizeof(*priv->bitrate_const) * - priv->bitrate_const_cnt, - priv->bitrate_const)) || + can_bitrate_const_fill_info(skb, IFLA_CAN_BITRATE_CONST, + priv->bitrate_const, + priv->bitrate_const_cnt) || - (priv->fd.data_bitrate_const && - nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST, - sizeof(*priv->fd.data_bitrate_const) * - priv->fd.data_bitrate_const_cnt, - priv->fd.data_bitrate_const)) || + can_bitrate_const_fill_info(skb, IFLA_CAN_DATA_BITRATE_CONST, + priv->fd.data_bitrate_const, + priv->fd.data_bitrate_const_cnt) || (nla_put(skb, IFLA_CAN_BITRATE_MAX, sizeof(priv->bitrate_max), &priv->bitrate_max)) || - can_tdc_fill_info(skb, dev) || + can_tdc_fill_info(skb, dev, IFLA_CAN_TDC) || can_ctrlmode_ext_fill_info(skb, priv) ) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index fe74dbd2c966..e1d725979685 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2213,11 +2213,9 @@ static int m_can_set_coalesce(struct net_device *dev, cdev->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq; if (cdev->rx_coalesce_usecs_irq) - cdev->irq_timer_wait = - ns_to_ktime(cdev->rx_coalesce_usecs_irq * NSEC_PER_USEC); + cdev->irq_timer_wait = us_to_ktime(cdev->rx_coalesce_usecs_irq); else - cdev->irq_timer_wait = - ns_to_ktime(cdev->tx_coalesce_usecs_irq * NSEC_PER_USEC); + cdev->irq_timer_wait = us_to_ktime(cdev->tx_coalesce_usecs_irq); return 0; } diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 77292afaed22..b5bc80ac7876 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> - * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> * - * Copyright (C) 2016 PEAK System-Technik GmbH + * Copyright (C) 2016-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/can.h> diff --git a/drivers/net/can/peak_canfd/peak_canfd_user.h b/drivers/net/can/peak_canfd/peak_canfd_user.h index a72719dc3b74..60c6542028cf 100644 --- a/drivers/net/can/peak_canfd/peak_canfd_user.h +++ b/drivers/net/can/peak_canfd/peak_canfd_user.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* CAN driver for PEAK System micro-CAN based adapters * - * Copyright (C) 2003-2011 PEAK System-Technik GmbH - * Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #ifndef PEAK_CANFD_USER_H #define PEAK_CANFD_USER_H diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 1df3c4b54f03..93558e33bc02 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> - * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> * * Derived from the PCAN project file driver/src/pcan_pci.c: * - * Copyright (C) 2001-2006 PEAK System-Technik GmbH + * Copyright (C) 2001-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/kernel.h> @@ -19,7 +19,7 @@ #include "peak_canfd_user.h" -MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); +MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>"); MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe/M.2 FD family cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index 64e664f5adcc..5f85f4e27205 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -5,6 +5,8 @@ * Copyright (C) 2013 Renesas Solutions Corp. */ +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> @@ -16,6 +18,7 @@ #include <linux/can/dev.h> #include <linux/clk.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #define RCAR_CAN_DRV_NAME "rcar_can" @@ -92,7 +95,6 @@ struct rcar_can_priv { struct net_device *ndev; struct napi_struct napi; struct rcar_can_regs __iomem *regs; - struct clk *clk; struct clk *can_clk; u32 tx_head; u32 tx_tail; @@ -113,100 +115,102 @@ static const struct can_bittiming_const rcar_can_bittiming_const = { }; /* Control Register bits */ -#define RCAR_CAN_CTLR_BOM (3 << 11) /* Bus-Off Recovery Mode Bits */ -#define RCAR_CAN_CTLR_BOM_ENT (1 << 11) /* Entry to halt mode */ - /* at bus-off entry */ -#define RCAR_CAN_CTLR_SLPM (1 << 10) -#define RCAR_CAN_CTLR_CANM (3 << 8) /* Operating Mode Select Bit */ -#define RCAR_CAN_CTLR_CANM_HALT (1 << 9) -#define RCAR_CAN_CTLR_CANM_RESET (1 << 8) -#define RCAR_CAN_CTLR_CANM_FORCE_RESET (3 << 8) -#define RCAR_CAN_CTLR_MLM (1 << 3) /* Message Lost Mode Select */ -#define RCAR_CAN_CTLR_IDFM (3 << 1) /* ID Format Mode Select Bits */ -#define RCAR_CAN_CTLR_IDFM_MIXED (1 << 2) /* Mixed ID mode */ -#define RCAR_CAN_CTLR_MBM (1 << 0) /* Mailbox Mode select */ +#define RCAR_CAN_CTLR_BOM GENMASK(12, 11) /* Bus-Off Recovery Mode Bits */ +#define RCAR_CAN_CTLR_BOM_ENT 1 /* Entry to halt mode */ + /* at bus-off entry */ +#define RCAR_CAN_CTLR_SLPM BIT(10) /* Sleep Mode */ +#define RCAR_CAN_CTLR_CANM GENMASK(9, 8) /* Operating Mode Select Bit */ +#define RCAR_CAN_CTLR_CANM_OPER 0 /* Operation Mode */ +#define RCAR_CAN_CTLR_CANM_RESET 1 /* Reset Mode */ +#define RCAR_CAN_CTLR_CANM_HALT 2 /* Halt Mode */ +#define RCAR_CAN_CTLR_CANM_FORCE_RESET 3 /* Reset Mode (forcible) */ +#define RCAR_CAN_CTLR_MLM BIT(3) /* Message Lost Mode Select */ +#define RCAR_CAN_CTLR_IDFM GENMASK(2, 1) /* ID Format Mode Select Bits */ +#define RCAR_CAN_CTLR_IDFM_STD 0 /* Standard ID mode */ +#define RCAR_CAN_CTLR_IDFM_EXT 1 /* Extended ID mode */ +#define RCAR_CAN_CTLR_IDFM_MIXED 2 /* Mixed ID mode */ +#define RCAR_CAN_CTLR_MBM BIT(0) /* Mailbox Mode select */ /* Status Register bits */ -#define RCAR_CAN_STR_RSTST (1 << 8) /* Reset Status Bit */ +#define RCAR_CAN_STR_RSTST BIT(8) /* Reset Status Bit */ /* FIFO Received ID Compare Registers 0 and 1 bits */ -#define RCAR_CAN_FIDCR_IDE (1 << 31) /* ID Extension Bit */ -#define RCAR_CAN_FIDCR_RTR (1 << 30) /* Remote Transmission Request Bit */ +#define RCAR_CAN_FIDCR_IDE BIT(31) /* ID Extension Bit */ +#define RCAR_CAN_FIDCR_RTR BIT(30) /* Remote Transmission Request Bit */ /* Receive FIFO Control Register bits */ -#define RCAR_CAN_RFCR_RFEST (1 << 7) /* Receive FIFO Empty Status Flag */ -#define RCAR_CAN_RFCR_RFE (1 << 0) /* Receive FIFO Enable */ +#define RCAR_CAN_RFCR_RFEST BIT(7) /* Receive FIFO Empty Status Flag */ +#define RCAR_CAN_RFCR_RFE BIT(0) /* Receive FIFO Enable */ /* Transmit FIFO Control Register bits */ -#define RCAR_CAN_TFCR_TFUST (7 << 1) /* Transmit FIFO Unsent Message */ - /* Number Status Bits */ -#define RCAR_CAN_TFCR_TFUST_SHIFT 1 /* Offset of Transmit FIFO Unsent */ - /* Message Number Status Bits */ -#define RCAR_CAN_TFCR_TFE (1 << 0) /* Transmit FIFO Enable */ - -#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */ - /* for Rx mailboxes 0-31 */ +#define RCAR_CAN_TFCR_TFUST GENMASK(3, 1) /* Transmit FIFO Unsent Message */ + /* Number Status Bits */ +#define RCAR_CAN_TFCR_TFE BIT(0) /* Transmit FIFO Enable */ + +#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */ + /* for Rx mailboxes 0-31 */ #define RCAR_CAN_N_RX_MKREGS2 8 /* Bit Configuration Register settings */ -#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20) -#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8) -#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4) -#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07) +#define RCAR_CAN_BCR_TSEG1 GENMASK(23, 20) +#define RCAR_CAN_BCR_BRP GENMASK(17, 8) +#define RCAR_CAN_BCR_SJW GENMASK(5, 4) +#define RCAR_CAN_BCR_TSEG2 GENMASK(2, 0) /* Mailbox and Mask Registers bits */ -#define RCAR_CAN_IDE (1 << 31) -#define RCAR_CAN_RTR (1 << 30) -#define RCAR_CAN_SID_SHIFT 18 +#define RCAR_CAN_IDE BIT(31) /* ID Extension */ +#define RCAR_CAN_RTR BIT(30) /* Remote Transmission Request */ +#define RCAR_CAN_SID GENMASK(28, 18) /* Standard ID */ +#define RCAR_CAN_EID GENMASK(28, 0) /* Extended ID */ /* Mailbox Interrupt Enable Register 1 bits */ -#define RCAR_CAN_MIER1_RXFIE (1 << 28) /* Receive FIFO Interrupt Enable */ -#define RCAR_CAN_MIER1_TXFIE (1 << 24) /* Transmit FIFO Interrupt Enable */ +#define RCAR_CAN_MIER1_RXFIE BIT(28) /* Receive FIFO Interrupt Enable */ +#define RCAR_CAN_MIER1_TXFIE BIT(24) /* Transmit FIFO Interrupt Enable */ /* Interrupt Enable Register bits */ -#define RCAR_CAN_IER_ERSIE (1 << 5) /* Error (ERS) Interrupt Enable Bit */ -#define RCAR_CAN_IER_RXFIE (1 << 4) /* Reception FIFO Interrupt */ - /* Enable Bit */ -#define RCAR_CAN_IER_TXFIE (1 << 3) /* Transmission FIFO Interrupt */ - /* Enable Bit */ +#define RCAR_CAN_IER_ERSIE BIT(5) /* Error (ERS) Interrupt Enable Bit */ +#define RCAR_CAN_IER_RXFIE BIT(4) /* Reception FIFO Interrupt */ + /* Enable Bit */ +#define RCAR_CAN_IER_TXFIE BIT(3) /* Transmission FIFO Interrupt */ + /* Enable Bit */ /* Interrupt Status Register bits */ -#define RCAR_CAN_ISR_ERSF (1 << 5) /* Error (ERS) Interrupt Status Bit */ -#define RCAR_CAN_ISR_RXFF (1 << 4) /* Reception FIFO Interrupt */ - /* Status Bit */ -#define RCAR_CAN_ISR_TXFF (1 << 3) /* Transmission FIFO Interrupt */ - /* Status Bit */ +#define RCAR_CAN_ISR_ERSF BIT(5) /* Error (ERS) Interrupt Status Bit */ +#define RCAR_CAN_ISR_RXFF BIT(4) /* Reception FIFO Interrupt */ + /* Status Bit */ +#define RCAR_CAN_ISR_TXFF BIT(3) /* Transmission FIFO Interrupt */ + /* Status Bit */ /* Error Interrupt Enable Register bits */ -#define RCAR_CAN_EIER_BLIE (1 << 7) /* Bus Lock Interrupt Enable */ -#define RCAR_CAN_EIER_OLIE (1 << 6) /* Overload Frame Transmit */ - /* Interrupt Enable */ -#define RCAR_CAN_EIER_ORIE (1 << 5) /* Receive Overrun Interrupt Enable */ -#define RCAR_CAN_EIER_BORIE (1 << 4) /* Bus-Off Recovery Interrupt Enable */ -#define RCAR_CAN_EIER_BOEIE (1 << 3) /* Bus-Off Entry Interrupt Enable */ -#define RCAR_CAN_EIER_EPIE (1 << 2) /* Error Passive Interrupt Enable */ -#define RCAR_CAN_EIER_EWIE (1 << 1) /* Error Warning Interrupt Enable */ -#define RCAR_CAN_EIER_BEIE (1 << 0) /* Bus Error Interrupt Enable */ +#define RCAR_CAN_EIER_BLIE BIT(7) /* Bus Lock Interrupt Enable */ +#define RCAR_CAN_EIER_OLIE BIT(6) /* Overload Frame Transmit */ + /* Interrupt Enable */ +#define RCAR_CAN_EIER_ORIE BIT(5) /* Receive Overrun Interrupt Enable */ +#define RCAR_CAN_EIER_BORIE BIT(4) /* Bus-Off Recovery Interrupt Enable */ +#define RCAR_CAN_EIER_BOEIE BIT(3) /* Bus-Off Entry Interrupt Enable */ +#define RCAR_CAN_EIER_EPIE BIT(2) /* Error Passive Interrupt Enable */ +#define RCAR_CAN_EIER_EWIE BIT(1) /* Error Warning Interrupt Enable */ +#define RCAR_CAN_EIER_BEIE BIT(0) /* Bus Error Interrupt Enable */ /* Error Interrupt Factor Judge Register bits */ -#define RCAR_CAN_EIFR_BLIF (1 << 7) /* Bus Lock Detect Flag */ -#define RCAR_CAN_EIFR_OLIF (1 << 6) /* Overload Frame Transmission */ - /* Detect Flag */ -#define RCAR_CAN_EIFR_ORIF (1 << 5) /* Receive Overrun Detect Flag */ -#define RCAR_CAN_EIFR_BORIF (1 << 4) /* Bus-Off Recovery Detect Flag */ -#define RCAR_CAN_EIFR_BOEIF (1 << 3) /* Bus-Off Entry Detect Flag */ -#define RCAR_CAN_EIFR_EPIF (1 << 2) /* Error Passive Detect Flag */ -#define RCAR_CAN_EIFR_EWIF (1 << 1) /* Error Warning Detect Flag */ -#define RCAR_CAN_EIFR_BEIF (1 << 0) /* Bus Error Detect Flag */ +#define RCAR_CAN_EIFR_BLIF BIT(7) /* Bus Lock Detect Flag */ +#define RCAR_CAN_EIFR_OLIF BIT(6) /* Overload Frame Transmission */ + /* Detect Flag */ +#define RCAR_CAN_EIFR_ORIF BIT(5) /* Receive Overrun Detect Flag */ +#define RCAR_CAN_EIFR_BORIF BIT(4) /* Bus-Off Recovery Detect Flag */ +#define RCAR_CAN_EIFR_BOEIF BIT(3) /* Bus-Off Entry Detect Flag */ +#define RCAR_CAN_EIFR_EPIF BIT(2) /* Error Passive Detect Flag */ +#define RCAR_CAN_EIFR_EWIF BIT(1) /* Error Warning Detect Flag */ +#define RCAR_CAN_EIFR_BEIF BIT(0) /* Bus Error Detect Flag */ /* Error Code Store Register bits */ -#define RCAR_CAN_ECSR_EDPM (1 << 7) /* Error Display Mode Select Bit */ -#define RCAR_CAN_ECSR_ADEF (1 << 6) /* ACK Delimiter Error Flag */ -#define RCAR_CAN_ECSR_BE0F (1 << 5) /* Bit Error (dominant) Flag */ -#define RCAR_CAN_ECSR_BE1F (1 << 4) /* Bit Error (recessive) Flag */ -#define RCAR_CAN_ECSR_CEF (1 << 3) /* CRC Error Flag */ -#define RCAR_CAN_ECSR_AEF (1 << 2) /* ACK Error Flag */ -#define RCAR_CAN_ECSR_FEF (1 << 1) /* Form Error Flag */ -#define RCAR_CAN_ECSR_SEF (1 << 0) /* Stuff Error Flag */ +#define RCAR_CAN_ECSR_EDPM BIT(7) /* Error Display Mode Select Bit */ +#define RCAR_CAN_ECSR_ADEF BIT(6) /* ACK Delimiter Error Flag */ +#define RCAR_CAN_ECSR_BE0F BIT(5) /* Bit Error (dominant) Flag */ +#define RCAR_CAN_ECSR_BE1F BIT(4) /* Bit Error (recessive) Flag */ +#define RCAR_CAN_ECSR_CEF BIT(3) /* CRC Error Flag */ +#define RCAR_CAN_ECSR_AEF BIT(2) /* ACK Error Flag */ +#define RCAR_CAN_ECSR_FEF BIT(1) /* Form Error Flag */ +#define RCAR_CAN_ECSR_SEF BIT(0) /* Stuff Error Flag */ #define RCAR_CAN_NAPI_WEIGHT 4 #define MAX_STR_READS 0x100 @@ -248,35 +252,35 @@ static void rcar_can_error(struct net_device *ndev) if (ecsr & RCAR_CAN_ECSR_ADEF) { netdev_dbg(priv->ndev, "ACK Delimiter Error\n"); tx_errors++; - writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr); if (skb) cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL; } if (ecsr & RCAR_CAN_ECSR_BE0F) { netdev_dbg(priv->ndev, "Bit Error (dominant)\n"); tx_errors++; - writeb(~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr); if (skb) cf->data[2] |= CAN_ERR_PROT_BIT0; } if (ecsr & RCAR_CAN_ECSR_BE1F) { netdev_dbg(priv->ndev, "Bit Error (recessive)\n"); tx_errors++; - writeb(~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr); if (skb) cf->data[2] |= CAN_ERR_PROT_BIT1; } if (ecsr & RCAR_CAN_ECSR_CEF) { netdev_dbg(priv->ndev, "CRC Error\n"); rx_errors++; - writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); if (skb) cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } if (ecsr & RCAR_CAN_ECSR_AEF) { netdev_dbg(priv->ndev, "ACK Error\n"); tx_errors++; - writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); if (skb) { cf->can_id |= CAN_ERR_ACK; cf->data[3] = CAN_ERR_PROT_LOC_ACK; @@ -285,14 +289,14 @@ static void rcar_can_error(struct net_device *ndev) if (ecsr & RCAR_CAN_ECSR_FEF) { netdev_dbg(priv->ndev, "Form Error\n"); rx_errors++; - writeb(~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr); if (skb) cf->data[2] |= CAN_ERR_PROT_FORM; } if (ecsr & RCAR_CAN_ECSR_SEF) { netdev_dbg(priv->ndev, "Stuff Error\n"); rx_errors++; - writeb(~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr); + writeb((u8)~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr); if (skb) cf->data[2] |= CAN_ERR_PROT_STUFF; } @@ -300,14 +304,14 @@ static void rcar_can_error(struct net_device *ndev) priv->can.can_stats.bus_error++; ndev->stats.rx_errors += rx_errors; ndev->stats.tx_errors += tx_errors; - writeb(~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr); } if (eifr & RCAR_CAN_EIFR_EWIF) { netdev_dbg(priv->ndev, "Error warning interrupt\n"); priv->can.state = CAN_STATE_ERROR_WARNING; priv->can.can_stats.error_warning++; /* Clear interrupt condition */ - writeb(~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr); if (skb) cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_WARNING : CAN_ERR_CRTL_RX_WARNING; @@ -317,7 +321,7 @@ static void rcar_can_error(struct net_device *ndev) priv->can.state = CAN_STATE_ERROR_PASSIVE; priv->can.can_stats.error_passive++; /* Clear interrupt condition */ - writeb(~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr); if (skb) cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; @@ -329,7 +333,7 @@ static void rcar_can_error(struct net_device *ndev) writeb(priv->ier, &priv->regs->ier); priv->can.state = CAN_STATE_BUS_OFF; /* Clear interrupt condition */ - writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); priv->can.can_stats.bus_off++; can_bus_off(ndev); if (skb) @@ -343,7 +347,7 @@ static void rcar_can_error(struct net_device *ndev) netdev_dbg(priv->ndev, "Receive overrun error interrupt\n"); ndev->stats.rx_over_errors++; ndev->stats.rx_errors++; - writeb(~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr); if (skb) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; @@ -354,7 +358,7 @@ static void rcar_can_error(struct net_device *ndev) "Overload Frame Transmission error interrupt\n"); ndev->stats.rx_over_errors++; ndev->stats.rx_errors++; - writeb(~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr); + writeb((u8)~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr); if (skb) { cf->can_id |= CAN_ERR_PROT; cf->data[2] |= CAN_ERR_PROT_OVERLOAD; @@ -372,10 +376,9 @@ static void rcar_can_tx_done(struct net_device *ndev) u8 isr; while (1) { - u8 unsent = readb(&priv->regs->tfcr); + u8 unsent = FIELD_GET(RCAR_CAN_TFCR_TFUST, + readb(&priv->regs->tfcr)); - unsent = (unsent & RCAR_CAN_TFCR_TFUST) >> - RCAR_CAN_TFCR_TFUST_SHIFT; if (priv->tx_head - priv->tx_tail <= unsent) break; stats->tx_packets++; @@ -420,15 +423,16 @@ static irqreturn_t rcar_can_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void rcar_can_set_bittiming(struct net_device *dev) +static void rcar_can_set_bittiming(struct net_device *ndev) { - struct rcar_can_priv *priv = netdev_priv(dev); + struct rcar_can_priv *priv = netdev_priv(ndev); struct can_bittiming *bt = &priv->can.bittiming; u32 bcr; - bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) | - RCAR_CAN_BCR_BPR(bt->brp - 1) | RCAR_CAN_BCR_SJW(bt->sjw - 1) | - RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1); + bcr = FIELD_PREP(RCAR_CAN_BCR_TSEG1, bt->phase_seg1 + bt->prop_seg - 1) | + FIELD_PREP(RCAR_CAN_BCR_BRP, bt->brp - 1) | + FIELD_PREP(RCAR_CAN_BCR_SJW, bt->sjw - 1) | + FIELD_PREP(RCAR_CAN_BCR_TSEG2, bt->phase_seg2 - 1); /* Don't overwrite CLKR with 32-bit BCR access; CLKR has 8-bit access. * All the registers are big-endian but they get byte-swapped on 32-bit * read/write (but not on 8-bit, contrary to the manuals)... @@ -452,16 +456,17 @@ static void rcar_can_start(struct net_device *ndev) ctlr &= ~RCAR_CAN_CTLR_SLPM; writew(ctlr, &priv->regs->ctlr); /* Go to reset mode */ - ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_CANM, RCAR_CAN_CTLR_CANM_FORCE_RESET); writew(ctlr, &priv->regs->ctlr); for (i = 0; i < MAX_STR_READS; i++) { if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) break; } rcar_can_set_bittiming(ndev); - ctlr |= RCAR_CAN_CTLR_IDFM_MIXED; /* Select mixed ID mode */ - ctlr |= RCAR_CAN_CTLR_BOM_ENT; /* Entry to halt mode automatically */ - /* at bus-off */ + /* Select mixed ID mode */ + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_IDFM, RCAR_CAN_CTLR_IDFM_MIXED); + /* Entry to halt mode automatically at bus-off */ + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_BOM, RCAR_CAN_CTLR_BOM_ENT); ctlr |= RCAR_CAN_CTLR_MBM; /* Select FIFO mailbox mode */ ctlr |= RCAR_CAN_CTLR_MLM; /* Overrun mode */ writew(ctlr, &priv->regs->ctlr); @@ -491,7 +496,9 @@ static void rcar_can_start(struct net_device *ndev) priv->can.state = CAN_STATE_ERROR_ACTIVE; /* Go to operation mode */ - writew(ctlr & ~RCAR_CAN_CTLR_CANM, &priv->regs->ctlr); + ctlr &= ~RCAR_CAN_CTLR_CANM; + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_CANM, RCAR_CAN_CTLR_CANM_OPER); + writew(ctlr, &priv->regs->ctlr); for (i = 0; i < MAX_STR_READS; i++) { if (!(readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)) break; @@ -506,29 +513,28 @@ static int rcar_can_open(struct net_device *ndev) struct rcar_can_priv *priv = netdev_priv(ndev); int err; - err = clk_prepare_enable(priv->clk); + err = pm_runtime_resume_and_get(ndev->dev.parent); if (err) { - netdev_err(ndev, - "failed to enable peripheral clock, error %d\n", - err); + netdev_err(ndev, "pm_runtime_resume_and_get() failed %pe\n", + ERR_PTR(err)); goto out; } err = clk_prepare_enable(priv->can_clk); if (err) { - netdev_err(ndev, "failed to enable CAN clock, error %d\n", - err); - goto out_clock; + netdev_err(ndev, "failed to enable CAN clock: %pe\n", + ERR_PTR(err)); + goto out_rpm; } err = open_candev(ndev); if (err) { - netdev_err(ndev, "open_candev() failed, error %d\n", err); + netdev_err(ndev, "open_candev() failed %pe\n", ERR_PTR(err)); goto out_can_clock; } napi_enable(&priv->napi); err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); if (err) { - netdev_err(ndev, "request_irq(%d) failed, error %d\n", - ndev->irq, err); + netdev_err(ndev, "request_irq(%d) failed %pe\n", ndev->irq, + ERR_PTR(err)); goto out_close; } rcar_can_start(ndev); @@ -539,8 +545,8 @@ out_close: close_candev(ndev); out_can_clock: clk_disable_unprepare(priv->can_clk); -out_clock: - clk_disable_unprepare(priv->clk); +out_rpm: + pm_runtime_put(ndev->dev.parent); out: return err; } @@ -553,7 +559,7 @@ static void rcar_can_stop(struct net_device *ndev) /* Go to (force) reset mode */ ctlr = readw(&priv->regs->ctlr); - ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_CANM, RCAR_CAN_CTLR_CANM_FORCE_RESET); writew(ctlr, &priv->regs->ctlr); for (i = 0; i < MAX_STR_READS; i++) { if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) @@ -578,7 +584,7 @@ static int rcar_can_close(struct net_device *ndev) free_irq(ndev->irq, ndev); napi_disable(&priv->napi); clk_disable_unprepare(priv->can_clk); - clk_disable_unprepare(priv->clk); + pm_runtime_put(ndev->dev.parent); close_candev(ndev); return 0; } @@ -594,9 +600,10 @@ static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ - data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE; + data = FIELD_PREP(RCAR_CAN_EID, cf->can_id & CAN_EFF_MASK) | + RCAR_CAN_IDE; else /* Standard frame format */ - data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT; + data = FIELD_PREP(RCAR_CAN_SID, cf->can_id & CAN_SFF_MASK); if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */ data |= RCAR_CAN_RTR; @@ -651,9 +658,9 @@ static void rcar_can_rx_pkt(struct rcar_can_priv *priv) data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id); if (data & RCAR_CAN_IDE) - cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; + cf->can_id = FIELD_GET(RCAR_CAN_EID, data) | CAN_EFF_FLAG; else - cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK; + cf->can_id = FIELD_GET(RCAR_CAN_SID, data); dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc); cf->len = can_cc_dlc2len(dlc); @@ -715,18 +722,21 @@ static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode) } } -static int rcar_can_get_berr_counter(const struct net_device *dev, +static int rcar_can_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { - struct rcar_can_priv *priv = netdev_priv(dev); + struct rcar_can_priv *priv = netdev_priv(ndev); int err; - err = clk_prepare_enable(priv->clk); + err = pm_runtime_resume_and_get(ndev->dev.parent); if (err) return err; + bec->txerr = readb(&priv->regs->tecr); bec->rxerr = readb(&priv->regs->recr); - clk_disable_unprepare(priv->clk); + + pm_runtime_put(ndev->dev.parent); + return 0; } @@ -738,6 +748,7 @@ static const char * const clock_names[] = { static int rcar_can_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct rcar_can_priv *priv; struct net_device *ndev; void __iomem *addr; @@ -745,7 +756,7 @@ static int rcar_can_probe(struct platform_device *pdev) int err = -ENODEV; int irq; - of_property_read_u32(pdev->dev.of_node, "renesas,can-clock-select", + of_property_read_u32(dev->of_node, "renesas,can-clock-select", &clock_select); irq = platform_get_irq(pdev, 0); @@ -762,30 +773,21 @@ static int rcar_can_probe(struct platform_device *pdev) ndev = alloc_candev(sizeof(struct rcar_can_priv), RCAR_CAN_FIFO_DEPTH); if (!ndev) { - dev_err(&pdev->dev, "alloc_candev() failed\n"); err = -ENOMEM; goto fail; } priv = netdev_priv(ndev); - priv->clk = devm_clk_get(&pdev->dev, "clkp1"); - if (IS_ERR(priv->clk)) { - err = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n", - err); - goto fail_clk; - } - if (!(BIT(clock_select) & RCAR_SUPPORTED_CLOCKS)) { err = -EINVAL; - dev_err(&pdev->dev, "invalid CAN clock selected\n"); + dev_err(dev, "invalid CAN clock selected\n"); goto fail_clk; } - priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]); + priv->can_clk = devm_clk_get(dev, clock_names[clock_select]); if (IS_ERR(priv->can_clk)) { + dev_err(dev, "cannot get CAN clock: %pe\n", priv->can_clk); err = PTR_ERR(priv->can_clk); - dev_err(&pdev->dev, "cannot get CAN clock, error %d\n", err); goto fail_clk; } @@ -802,21 +804,24 @@ static int rcar_can_probe(struct platform_device *pdev) priv->can.do_get_berr_counter = rcar_can_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; platform_set_drvdata(pdev, ndev); - SET_NETDEV_DEV(ndev, &pdev->dev); + SET_NETDEV_DEV(ndev, dev); netif_napi_add_weight(ndev, &priv->napi, rcar_can_rx_poll, RCAR_CAN_NAPI_WEIGHT); + + pm_runtime_enable(dev); + err = register_candev(ndev); if (err) { - dev_err(&pdev->dev, "register_candev() failed, error %d\n", - err); - goto fail_candev; + dev_err(dev, "register_candev() failed %pe\n", ERR_PTR(err)); + goto fail_rpm; } - dev_info(&pdev->dev, "device registered (IRQ%d)\n", ndev->irq); + dev_info(dev, "device registered (IRQ%d)\n", ndev->irq); return 0; -fail_candev: +fail_rpm: + pm_runtime_disable(dev); netif_napi_del(&priv->napi); fail_clk: free_candev(ndev); @@ -830,6 +835,7 @@ static void rcar_can_remove(struct platform_device *pdev) struct rcar_can_priv *priv = netdev_priv(ndev); unregister_candev(ndev); + pm_runtime_disable(&pdev->dev); netif_napi_del(&priv->napi); free_candev(ndev); } @@ -847,38 +853,32 @@ static int rcar_can_suspend(struct device *dev) netif_device_detach(ndev); ctlr = readw(&priv->regs->ctlr); - ctlr |= RCAR_CAN_CTLR_CANM_HALT; + ctlr |= FIELD_PREP(RCAR_CAN_CTLR_CANM, RCAR_CAN_CTLR_CANM_HALT); writew(ctlr, &priv->regs->ctlr); ctlr |= RCAR_CAN_CTLR_SLPM; writew(ctlr, &priv->regs->ctlr); priv->can.state = CAN_STATE_SLEEPING; - clk_disable(priv->clk); + pm_runtime_put(dev); return 0; } static int rcar_can_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); - struct rcar_can_priv *priv = netdev_priv(ndev); - u16 ctlr; int err; if (!netif_running(ndev)) return 0; - err = clk_enable(priv->clk); + err = pm_runtime_resume_and_get(dev); if (err) { - netdev_err(ndev, "clk_enable() failed, error %d\n", err); + netdev_err(ndev, "pm_runtime_resume_and_get() failed %pe\n", + ERR_PTR(err)); return err; } - ctlr = readw(&priv->regs->ctlr); - ctlr &= ~RCAR_CAN_CTLR_SLPM; - writew(ctlr, &priv->regs->ctlr); - ctlr &= ~RCAR_CAN_CTLR_CANM; - writew(ctlr, &priv->regs->ctlr); - priv->can.state = CAN_STATE_ERROR_ACTIVE; + rcar_can_start(ndev); netif_device_attach(ndev); netif_start_queue(ndev); diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index b3c8c592fb0e..45d36adb51b7 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -103,22 +103,13 @@ /* Channel register bits */ /* RSCFDnCmCFG - Classical CAN only */ -#define RCANFD_CFG_SJW(x) (((x) & 0x3) << 24) -#define RCANFD_CFG_TSEG2(x) (((x) & 0x7) << 20) -#define RCANFD_CFG_TSEG1(x) (((x) & 0xf) << 16) -#define RCANFD_CFG_BRP(x) (((x) & 0x3ff) << 0) +#define RCANFD_CFG_SJW GENMASK(25, 24) +#define RCANFD_CFG_TSEG2 GENMASK(22, 20) +#define RCANFD_CFG_TSEG1 GENMASK(19, 16) +#define RCANFD_CFG_BRP GENMASK(9, 0) /* RSCFDnCFDCmNCFG - CAN FD only */ -#define RCANFD_NCFG_NTSEG2(gpriv, x) \ - (((x) & ((gpriv)->info->nom_bittiming->tseg2_max - 1)) << (gpriv)->info->sh->ntseg2) - -#define RCANFD_NCFG_NTSEG1(gpriv, x) \ - (((x) & ((gpriv)->info->nom_bittiming->tseg1_max - 1)) << (gpriv)->info->sh->ntseg1) - -#define RCANFD_NCFG_NSJW(gpriv, x) \ - (((x) & ((gpriv)->info->nom_bittiming->sjw_max - 1)) << (gpriv)->info->sh->nsjw) - -#define RCANFD_NCFG_NBRP(x) (((x) & 0x3ff) << 0) +#define RCANFD_NCFG_NBRP GENMASK(9, 0) /* RSCFDnCFDCmCTR / RSCFDnCmCTR */ #define RCANFD_CCTR_CTME BIT(24) @@ -178,15 +169,7 @@ #define RCANFD_CERFL_ERR(x) ((x) & (0x7fff)) /* above bits 14:0 */ /* RSCFDnCFDCmDCFG */ -#define RCANFD_DCFG_DSJW(gpriv, x) (((x) & ((gpriv)->info->data_bittiming->sjw_max - 1)) << 24) - -#define RCANFD_DCFG_DTSEG2(gpriv, x) \ - (((x) & ((gpriv)->info->data_bittiming->tseg2_max - 1)) << (gpriv)->info->sh->dtseg2) - -#define RCANFD_DCFG_DTSEG1(gpriv, x) \ - (((x) & ((gpriv)->info->data_bittiming->tseg1_max - 1)) << (gpriv)->info->sh->dtseg1) - -#define RCANFD_DCFG_DBRP(x) (((x) & 0xff) << 0) +#define RCANFD_DCFG_DBRP GENMASK(7, 0) /* RSCFDnCFDCmFDCFG */ #define RCANFD_GEN4_FDCFG_CLOE BIT(30) @@ -823,9 +806,6 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) /* Reset Global error flags */ rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0); - /* Set the controller into appropriate mode */ - rcar_canfd_set_mode(gpriv); - /* Transition all Channels to reset mode */ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { rcar_canfd_clear_bit(gpriv->base, @@ -844,6 +824,10 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) return err; } } + + /* Set the controller into appropriate mode */ + rcar_canfd_set_mode(gpriv); + return 0; } @@ -1388,6 +1372,41 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static inline u32 rcar_canfd_compute_nominal_bit_rate_cfg(struct rcar_canfd_channel *priv, + u16 tseg1, u16 tseg2, u16 sjw, u16 brp) +{ + struct rcar_canfd_global *gpriv = priv->gpriv; + const struct rcar_canfd_hw_info *info = gpriv->info; + u32 ntseg1, ntseg2, nsjw, nbrp; + + if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) { + ntseg1 = (tseg1 & (info->nom_bittiming->tseg1_max - 1)) << info->sh->ntseg1; + ntseg2 = (tseg2 & (info->nom_bittiming->tseg2_max - 1)) << info->sh->ntseg2; + nsjw = (sjw & (info->nom_bittiming->sjw_max - 1)) << info->sh->nsjw; + nbrp = FIELD_PREP(RCANFD_NCFG_NBRP, brp); + } else { + ntseg1 = FIELD_PREP(RCANFD_CFG_TSEG1, tseg1); + ntseg2 = FIELD_PREP(RCANFD_CFG_TSEG2, tseg2); + nsjw = FIELD_PREP(RCANFD_CFG_SJW, sjw); + nbrp = FIELD_PREP(RCANFD_CFG_BRP, brp); + } + + return (ntseg1 | ntseg2 | nsjw | nbrp); +} + +static inline u32 rcar_canfd_compute_data_bit_rate_cfg(const struct rcar_canfd_hw_info *info, + u16 tseg1, u16 tseg2, u16 sjw, u16 brp) +{ + u32 dtseg1, dtseg2, dsjw, dbrp; + + dtseg1 = (tseg1 & (info->data_bittiming->tseg1_max - 1)) << info->sh->dtseg1; + dtseg2 = (tseg2 & (info->data_bittiming->tseg2_max - 1)) << info->sh->dtseg2; + dsjw = (sjw & (info->data_bittiming->sjw_max - 1)) << 24; + dbrp = FIELD_PREP(RCANFD_DCFG_DBRP, brp); + + return (dtseg1 | dtseg2 | dsjw | dbrp); +} + static void rcar_canfd_set_bittiming(struct net_device *ndev) { u32 mask = RCANFD_FDCFG_TDCO | RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC; @@ -1406,15 +1425,7 @@ static void rcar_canfd_set_bittiming(struct net_device *ndev) sjw = bt->sjw - 1; tseg1 = bt->prop_seg + bt->phase_seg1 - 1; tseg2 = bt->phase_seg2 - 1; - - if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) { - cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) | RCANFD_NCFG_NBRP(brp) | - RCANFD_NCFG_NSJW(gpriv, sjw) | RCANFD_NCFG_NTSEG2(gpriv, tseg2)); - } else { - cfg = (RCANFD_CFG_TSEG1(tseg1) | RCANFD_CFG_BRP(brp) | - RCANFD_CFG_SJW(sjw) | RCANFD_CFG_TSEG2(tseg2)); - } - + cfg = rcar_canfd_compute_nominal_bit_rate_cfg(priv, tseg1, tseg2, sjw, brp); rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) @@ -1425,10 +1436,7 @@ static void rcar_canfd_set_bittiming(struct net_device *ndev) sjw = dbt->sjw - 1; tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; tseg2 = dbt->phase_seg2 - 1; - - cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) | - RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2)); - + cfg = rcar_canfd_compute_data_bit_rate_cfg(gpriv->info, tseg1, tseg2, sjw, brp); writel(cfg, &gpriv->fcbase[ch].dcfg); /* Transceiver Delay Compensation */ @@ -1912,7 +1920,10 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, priv->can.fd.do_get_auto_tdcv = rcar_canfd_get_auto_tdcv; } else { /* Controller starts in Classical CAN only mode */ - priv->can.bittiming_const = &rcar_canfd_bittiming_const; + if (gpriv->info->shared_can_regs) + priv->can.bittiming_const = gpriv->info->nom_bittiming; + else + priv->can.bittiming_const = &rcar_canfd_bittiming_const; priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; } diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index da396d641e24..10d88cbda465 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> - * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> * * Derived from the PCAN project file driver/src/pcan_pci.c: * - * Copyright (C) 2001-2006 PEAK System-Technik GmbH + * Copyright (C) 2001-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/kernel.h> @@ -22,7 +22,7 @@ #include "sja1000.h" -MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); +MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>"); MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index ce18e9e56059..e1610b527d13 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> - * * CAN driver for PEAK-System PCAN-PC Card * Derived from the PCAN project file driver/src/pcan_pccard.c - * Copyright (C) 2006-2010 PEAK System-Technik GmbH + * + * Copyright (C) 2006-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/kernel.h> #include <linux/module.h> @@ -19,7 +19,7 @@ #include <linux/can/dev.h> #include "sja1000.h" -MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); +MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>"); MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index 09ae218315d7..6d4b643e135f 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -545,8 +545,6 @@ static int hi3110_stop(struct net_device *net) priv->force_quit = 1; free_irq(spi->irq, priv); - destroy_workqueue(priv->wq); - priv->wq = NULL; mutex_lock(&priv->hi3110_lock); @@ -770,34 +768,23 @@ static int hi3110_open(struct net_device *net) goto out_close; } - priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, - 0); - if (!priv->wq) { - ret = -ENOMEM; - goto out_free_irq; - } - INIT_WORK(&priv->tx_work, hi3110_tx_work_handler); - INIT_WORK(&priv->restart_work, hi3110_restart_work_handler); - ret = hi3110_hw_reset(spi); if (ret) - goto out_free_wq; + goto out_free_irq; ret = hi3110_setup(net); if (ret) - goto out_free_wq; + goto out_free_irq; ret = hi3110_set_normal_mode(spi); if (ret) - goto out_free_wq; + goto out_free_irq; netif_wake_queue(net); mutex_unlock(&priv->hi3110_lock); return 0; - out_free_wq: - destroy_workqueue(priv->wq); out_free_irq: free_irq(spi->irq, priv); hi3110_hw_sleep(spi); @@ -812,6 +799,7 @@ static const struct net_device_ops hi3110_netdev_ops = { .ndo_open = hi3110_open, .ndo_stop = hi3110_stop, .ndo_start_xmit = hi3110_hard_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct ethtool_ops hi3110_ethtool_ops = { @@ -908,6 +896,16 @@ static int hi3110_can_probe(struct spi_device *spi) if (ret) goto out_clk; + priv->wq = alloc_workqueue("hi3110_wq", + WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU, + 0); + if (!priv->wq) { + ret = -ENOMEM; + goto out_clk; + } + INIT_WORK(&priv->tx_work, hi3110_tx_work_handler); + INIT_WORK(&priv->restart_work, hi3110_restart_work_handler); + priv->spi = spi; mutex_init(&priv->hi3110_lock); @@ -943,6 +941,8 @@ static int hi3110_can_probe(struct spi_device *spi) return 0; error_probe: + destroy_workqueue(priv->wq); + priv->wq = NULL; hi3110_power_enable(priv->power, 0); out_clk: @@ -963,6 +963,9 @@ static void hi3110_can_remove(struct spi_device *spi) hi3110_power_enable(priv->power, 0); + destroy_workqueue(priv->wq); + priv->wq = NULL; + clk_disable_unprepare(priv->clk); free_candev(net); diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 313e1d241f01..b797e08499d7 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -1378,7 +1378,8 @@ static int mcp251x_can_probe(struct spi_device *spi) if (ret) goto out_clk; - priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, + priv->wq = alloc_workqueue("mcp251x_wq", + WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!priv->wq) { ret = -ENOMEM; diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 6fcb301ef611..53bfd873de9b 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -768,6 +768,7 @@ static const struct net_device_ops sun4ican_netdev_ops = { .ndo_open = sun4ican_open, .ndo_stop = sun4ican_close, .ndo_start_xmit = sun4ican_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct ethtool_ops sun4ican_ethtool_ops = { diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index a7547a83120e..cf65a90816b9 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -134,6 +134,17 @@ config CAN_MCBA_USB This driver supports the CAN BUS Analyzer interface from Microchip (http://www.microchip.com/development-tools/). +config CAN_NCT6694 + tristate "Nuvoton NCT6694 Socket CANfd support" + depends on MFD_NCT6694 + select CAN_RX_OFFLOAD + help + If you say yes to this option, support will be included for Nuvoton + NCT6694, a USB device to socket CANfd controller. + + This driver can also be built as a module. If so, the module will + be called nct6694_canfd. + config CAN_PEAK_USB tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD" help diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile index 8b11088e9a59..fcafb1ac262e 100644 --- a/drivers/net/can/usb/Makefile +++ b/drivers/net/can/usb/Makefile @@ -11,5 +11,6 @@ obj-$(CONFIG_CAN_F81604) += f81604.o obj-$(CONFIG_CAN_GS_USB) += gs_usb.o obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/ obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o +obj-$(CONFIG_CAN_NCT6694) += nct6694_canfd.o obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/ obj-$(CONFIG_CAN_UCAN) += ucan.o diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 27a3818885c2..9bc1824d7be6 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -9,6 +9,7 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/err.h> #include <linux/ethtool.h> #include <linux/module.h> #include <linux/netdevice.h> @@ -274,6 +275,7 @@ struct esd_usb { int net_count; u32 version; int rxinitdone; + int in_usb_disconnect; void *rxbuf[ESD_USB_MAX_RX_URBS]; dma_addr_t rxbuf_dma[ESD_USB_MAX_RX_URBS]; }; @@ -480,7 +482,7 @@ static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv, static void esd_usb_read_bulk_callback(struct urb *urb) { struct esd_usb *dev = urb->context; - int retval; + int err; int pos = 0; int i; @@ -496,7 +498,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb) default: dev_info(dev->udev->dev.parent, - "Rx URB aborted (%d)\n", urb->status); + "Rx URB aborted (%pe)\n", ERR_PTR(urb->status)); goto resubmit_urb; } @@ -539,15 +541,15 @@ resubmit_urb: urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE, esd_usb_read_bulk_callback, dev); - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval == -ENODEV) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err == -ENODEV) { for (i = 0; i < dev->net_count; i++) { if (dev->nets[i]) netif_device_detach(dev->nets[i]->netdev); } - } else if (retval) { + } else if (err) { dev_err(dev->udev->dev.parent, - "failed resubmitting read bulk urb: %d\n", retval); + "failed resubmitting read bulk urb: %pe\n", ERR_PTR(err)); } } @@ -572,7 +574,7 @@ static void esd_usb_write_bulk_callback(struct urb *urb) return; if (urb->status) - netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status); + netdev_info(netdev, "Tx URB aborted (%pe)\n", ERR_PTR(urb->status)); netif_trans_update(netdev); } @@ -758,7 +760,7 @@ out: if (err == -ENODEV) netif_device_detach(netdev); if (err) - netdev_err(netdev, "couldn't start device: %d\n", err); + netdev_err(netdev, "couldn't start device: %pe\n", ERR_PTR(err)); kfree(msg); return err; @@ -800,7 +802,6 @@ static int esd_usb_open(struct net_device *netdev) /* finally start device */ err = esd_usb_start(priv); if (err) { - netdev_warn(netdev, "couldn't start device: %d\n", err); close_candev(netdev); return err; } @@ -923,7 +924,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, if (err == -ENODEV) netif_device_detach(netdev); else - netdev_warn(netdev, "failed tx_urb %d\n", err); + netdev_warn(netdev, "failed tx_urb %pe\n", ERR_PTR(err)); goto releasebuf; } @@ -947,10 +948,11 @@ nourbmem: return ret; } -static int esd_usb_close(struct net_device *netdev) +/* Stop interface */ +static int esd_usb_stop(struct esd_usb_net_priv *priv) { - struct esd_usb_net_priv *priv = netdev_priv(netdev); union esd_usb_msg *msg; + int err; int i; msg = kmalloc(sizeof(*msg), GFP_KERNEL); @@ -964,8 +966,11 @@ static int esd_usb_close(struct net_device *netdev) msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ for (i = 0; i <= ESD_USB_MAX_ID_SEGMENT; i++) msg->filter.mask[i] = 0; - if (esd_usb_send_msg(priv->usb, msg) < 0) - netdev_err(netdev, "sending idadd message failed\n"); + err = esd_usb_send_msg(priv->usb, msg); + if (err < 0) { + netdev_err(priv->netdev, "sending idadd message failed: %pe\n", ERR_PTR(err)); + goto bail; + } /* set CAN controller to reset mode */ msg->hdr.len = sizeof(struct esd_usb_set_baudrate_msg) / sizeof(u32); /* # of 32bit words */ @@ -973,8 +978,25 @@ static int esd_usb_close(struct net_device *netdev) msg->setbaud.net = priv->index; msg->setbaud.rsvd = 0; msg->setbaud.baud = cpu_to_le32(ESD_USB_NO_BAUDRATE); - if (esd_usb_send_msg(priv->usb, msg) < 0) - netdev_err(netdev, "sending setbaud message failed\n"); + err = esd_usb_send_msg(priv->usb, msg); + if (err < 0) + netdev_err(priv->netdev, "sending setbaud message failed: %pe\n", ERR_PTR(err)); + +bail: + kfree(msg); + + return err; +} + +static int esd_usb_close(struct net_device *netdev) +{ + struct esd_usb_net_priv *priv = netdev_priv(netdev); + int err = 0; + + if (!priv->usb->in_usb_disconnect) { + /* It's moot to try this in usb_disconnect()! */ + err = esd_usb_stop(priv); + } priv->can.state = CAN_STATE_STOPPED; @@ -982,9 +1004,7 @@ static int esd_usb_close(struct net_device *netdev) close_candev(netdev); - kfree(msg); - - return 0; + return err; } static const struct net_device_ops esd_usb_netdev_ops = { @@ -1251,14 +1271,14 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) err = register_candev(netdev); if (err) { - dev_err(&intf->dev, "couldn't register CAN device: %d\n", err); + dev_err(&intf->dev, "couldn't register CAN device: %pe\n", ERR_PTR(err)); free_candev(netdev); err = -ENOMEM; goto done; } dev->nets[index] = priv; - netdev_info(netdev, "device %s registered\n", netdev->name); + netdev_info(netdev, "registered\n"); done: return err; @@ -1354,9 +1374,11 @@ static void esd_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (dev) { + dev->in_usb_disconnect = 1; for (i = 0; i < dev->net_count; i++) { if (dev->nets[i]) { netdev = dev->nets[i]->netdev; + netdev_info(netdev, "unregister\n"); unregister_netdev(netdev); free_candev(netdev); } diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c index db1acf6d504c..adc91873c083 100644 --- a/drivers/net/can/usb/etas_es58x/es58x_core.c +++ b/drivers/net/can/usb/etas_es58x/es58x_core.c @@ -7,7 +7,7 @@ * * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. * Copyright (c) 2020 ETAS K.K.. All rights reserved. - * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> + * Copyright (c) 2020-2025 Vincent Mailhol <mailhol@kernel.org> */ #include <linux/unaligned.h> @@ -1977,6 +1977,7 @@ static const struct net_device_ops es58x_netdev_ops = { .ndo_stop = es58x_stop, .ndo_start_xmit = es58x_start_xmit, .ndo_eth_ioctl = can_eth_ioctl_hwts, + .ndo_change_mtu = can_change_mtu, }; static const struct ethtool_ops es58x_ethtool_ops = { diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 41c0a1c399bf..1f9b915094e6 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -761,6 +761,7 @@ static const struct net_device_ops mcba_netdev_ops = { .ndo_open = mcba_usb_open, .ndo_stop = mcba_usb_close, .ndo_start_xmit = mcba_usb_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct ethtool_ops mcba_ethtool_ops = { diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c new file mode 100644 index 000000000000..8deff16491a1 --- /dev/null +++ b/drivers/net/can/usb/nct6694_canfd.c @@ -0,0 +1,832 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Nuvoton NCT6694 Socket CANfd driver based on USB interface. + * + * Copyright (C) 2025 Nuvoton Technology Corp. + */ + +#include <linux/bitfield.h> +#include <linux/can/dev.h> +#include <linux/can/rx-offload.h> +#include <linux/ethtool.h> +#include <linux/idr.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/mfd/nct6694.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> + +#define DEVICE_NAME "nct6694-canfd" + +/* USB command module type for NCT6694 CANfd controller. + * This defines the module type used for communication with the NCT6694 + * CANfd controller over the USB interface. + */ +#define NCT6694_CANFD_MOD 0x05 + +/* Command 00h - CAN Setting and Initialization */ +#define NCT6694_CANFD_SETTING 0x00 +#define NCT6694_CANFD_SETTING_ACTIVE_CTRL1 BIT(0) +#define NCT6694_CANFD_SETTING_ACTIVE_CTRL2 BIT(1) +#define NCT6694_CANFD_SETTING_ACTIVE_NBTP_DBTP BIT(2) +#define NCT6694_CANFD_SETTING_CTRL1_MON BIT(0) +#define NCT6694_CANFD_SETTING_CTRL1_NISO BIT(1) +#define NCT6694_CANFD_SETTING_CTRL1_LBCK BIT(2) +#define NCT6694_CANFD_SETTING_NBTP_NTSEG2 GENMASK(6, 0) +#define NCT6694_CANFD_SETTING_NBTP_NTSEG1 GENMASK(15, 8) +#define NCT6694_CANFD_SETTING_NBTP_NBRP GENMASK(24, 16) +#define NCT6694_CANFD_SETTING_NBTP_NSJW GENMASK(31, 25) +#define NCT6694_CANFD_SETTING_DBTP_DSJW GENMASK(3, 0) +#define NCT6694_CANFD_SETTING_DBTP_DTSEG2 GENMASK(7, 4) +#define NCT6694_CANFD_SETTING_DBTP_DTSEG1 GENMASK(12, 8) +#define NCT6694_CANFD_SETTING_DBTP_DBRP GENMASK(20, 16) +#define NCT6694_CANFD_SETTING_DBTP_TDC BIT(23) + +/* Command 01h - CAN Information */ +#define NCT6694_CANFD_INFORMATION 0x01 +#define NCT6694_CANFD_INFORMATION_SEL 0x00 + +/* Command 02h - CAN Event */ +#define NCT6694_CANFD_EVENT 0x02 +#define NCT6694_CANFD_EVENT_SEL(idx, mask) \ + ((idx ? 0x80 : 0x00) | ((mask) & 0x7F)) + +#define NCT6694_CANFD_EVENT_MASK GENMASK(5, 0) +#define NCT6694_CANFD_EVT_TX_FIFO_EMPTY BIT(7) /* Read-clear */ +#define NCT6694_CANFD_EVT_RX_DATA_LOST BIT(5) /* Read-clear */ +#define NCT6694_CANFD_EVT_RX_DATA_IN BIT(7) /* Read-clear */ + +/* Command 10h - CAN Deliver */ +#define NCT6694_CANFD_DELIVER 0x10 +#define NCT6694_CANFD_DELIVER_SEL(buf_cnt) \ + ((buf_cnt) & 0xFF) + +/* Command 11h - CAN Receive */ +#define NCT6694_CANFD_RECEIVE 0x11 +#define NCT6694_CANFD_RECEIVE_SEL(idx, buf_cnt) \ + ((idx ? 0x80 : 0x00) | ((buf_cnt) & 0x7F)) + +#define NCT6694_CANFD_FRAME_TAG(idx) (0xC0 | (idx)) +#define NCT6694_CANFD_FRAME_FLAG_EFF BIT(0) +#define NCT6694_CANFD_FRAME_FLAG_RTR BIT(1) +#define NCT6694_CANFD_FRAME_FLAG_FD BIT(2) +#define NCT6694_CANFD_FRAME_FLAG_BRS BIT(3) +#define NCT6694_CANFD_FRAME_FLAG_ERR BIT(4) + +#define NCT6694_NAPI_WEIGHT 32 + +enum nct6694_event_err { + NCT6694_CANFD_EVT_ERR_NO_ERROR = 0, + NCT6694_CANFD_EVT_ERR_CRC_ERROR, + NCT6694_CANFD_EVT_ERR_STUFF_ERROR, + NCT6694_CANFD_EVT_ERR_ACK_ERROR, + NCT6694_CANFD_EVT_ERR_FORM_ERROR, + NCT6694_CANFD_EVT_ERR_BIT_ERROR, + NCT6694_CANFD_EVT_ERR_TIMEOUT_ERROR, + NCT6694_CANFD_EVT_ERR_UNKNOWN_ERROR, +}; + +enum nct6694_event_status { + NCT6694_CANFD_EVT_STS_ERROR_ACTIVE = 0, + NCT6694_CANFD_EVT_STS_ERROR_PASSIVE, + NCT6694_CANFD_EVT_STS_BUS_OFF, + NCT6694_CANFD_EVT_STS_WARNING, +}; + +struct __packed nct6694_canfd_setting { + __le32 nbr; + __le32 dbr; + u8 active; + u8 reserved[3]; + __le16 ctrl1; + __le16 ctrl2; + __le32 nbtp; + __le32 dbtp; +}; + +struct __packed nct6694_canfd_information { + u8 tx_fifo_cnt; + u8 rx_fifo_cnt; + u8 reserved[2]; + __le32 can_clk; +}; + +struct __packed nct6694_canfd_event { + u8 err; + u8 status; + u8 tx_evt; + u8 rx_evt; + u8 rec; + u8 tec; + u8 reserved[2]; +}; + +struct __packed nct6694_canfd_frame { + u8 tag; + u8 flag; + u8 reserved; + u8 length; + __le32 id; + u8 data[CANFD_MAX_DLEN]; +}; + +struct nct6694_canfd_priv { + struct can_priv can; /* must be the first member */ + struct can_rx_offload offload; + struct net_device *ndev; + struct nct6694 *nct6694; + struct workqueue_struct *wq; + struct work_struct tx_work; + struct nct6694_canfd_frame tx; + struct nct6694_canfd_frame rx; + struct nct6694_canfd_event event[2]; + struct can_berr_counter bec; +}; + +static inline struct nct6694_canfd_priv *rx_offload_to_priv(struct can_rx_offload *offload) +{ + return container_of(offload, struct nct6694_canfd_priv, offload); +} + +static const struct can_bittiming_const nct6694_canfd_bittiming_nominal_const = { + .name = DEVICE_NAME, + .tseg1_min = 1, + .tseg1_max = 256, + .tseg2_min = 1, + .tseg2_max = 128, + .sjw_max = 128, + .brp_min = 1, + .brp_max = 512, + .brp_inc = 1, +}; + +static const struct can_bittiming_const nct6694_canfd_bittiming_data_const = { + .name = DEVICE_NAME, + .tseg1_min = 1, + .tseg1_max = 32, + .tseg2_min = 1, + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 32, + .brp_inc = 1, +}; + +static void nct6694_canfd_rx_offload(struct can_rx_offload *offload, + struct sk_buff *skb) +{ + struct nct6694_canfd_priv *priv = rx_offload_to_priv(offload); + int ret; + + ret = can_rx_offload_queue_tail(offload, skb); + if (ret) + priv->ndev->stats.rx_fifo_errors++; +} + +static void nct6694_canfd_handle_lost_msg(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + netdev_dbg(ndev, "RX FIFO overflow, message(s) lost.\n"); + + stats->rx_errors++; + stats->rx_over_errors++; + + skb = alloc_can_err_skb(ndev, &cf); + if (!skb) + return; + + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + + nct6694_canfd_rx_offload(&priv->offload, skb); +} + +static void nct6694_canfd_handle_rx(struct net_device *ndev, u8 rx_evt) +{ + struct net_device_stats *stats = &ndev->stats; + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct nct6694_canfd_frame *frame = &priv->rx; + const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_RECEIVE, + .sel = NCT6694_CANFD_RECEIVE_SEL(ndev->dev_port, 1), + .len = cpu_to_le16(sizeof(*frame)) + }; + struct sk_buff *skb; + int ret; + + ret = nct6694_read_msg(priv->nct6694, &cmd_hd, frame); + if (ret) + return; + + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_FD) { + struct canfd_frame *cfd; + + skb = alloc_canfd_skb(priv->ndev, &cfd); + if (!skb) { + stats->rx_dropped++; + return; + } + + cfd->can_id = le32_to_cpu(frame->id); + cfd->len = canfd_sanitize_len(frame->length); + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_EFF) + cfd->can_id |= CAN_EFF_FLAG; + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_BRS) + cfd->flags |= CANFD_BRS; + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_ERR) + cfd->flags |= CANFD_ESI; + + memcpy(cfd->data, frame->data, cfd->len); + } else { + struct can_frame *cf; + + skb = alloc_can_skb(priv->ndev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + cf->can_id = le32_to_cpu(frame->id); + cf->len = can_cc_dlc2len(frame->length); + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_EFF) + cf->can_id |= CAN_EFF_FLAG; + + if (frame->flag & NCT6694_CANFD_FRAME_FLAG_RTR) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, frame->data, cf->len); + } + + nct6694_canfd_rx_offload(&priv->offload, skb); +} + +static int nct6694_canfd_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + + *bec = priv->bec; + + return 0; +} + +static void nct6694_canfd_handle_state_change(struct net_device *ndev, u8 status) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + enum can_state new_state, rx_state, tx_state; + struct can_berr_counter bec; + struct can_frame *cf; + struct sk_buff *skb; + + nct6694_canfd_get_berr_counter(ndev, &bec); + can_state_get_by_berr_counter(ndev, &bec, &tx_state, &rx_state); + + new_state = max(tx_state, rx_state); + + /* state hasn't changed */ + if (new_state == priv->can.state) + return; + + skb = alloc_can_err_skb(ndev, &cf); + + can_change_state(ndev, cf, tx_state, rx_state); + + if (new_state == CAN_STATE_BUS_OFF) { + can_bus_off(ndev); + } else if (cf) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + } + + if (skb) + nct6694_canfd_rx_offload(&priv->offload, skb); +} + +static void nct6694_canfd_handle_bus_err(struct net_device *ndev, u8 bus_err) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct can_frame *cf; + struct sk_buff *skb; + + priv->can.can_stats.bus_error++; + + skb = alloc_can_err_skb(ndev, &cf); + if (cf) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (bus_err) { + case NCT6694_CANFD_EVT_ERR_CRC_ERROR: + netdev_dbg(ndev, "CRC error\n"); + ndev->stats.rx_errors++; + if (cf) + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + break; + + case NCT6694_CANFD_EVT_ERR_STUFF_ERROR: + netdev_dbg(ndev, "Stuff error\n"); + ndev->stats.rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + + case NCT6694_CANFD_EVT_ERR_ACK_ERROR: + netdev_dbg(ndev, "Ack error\n"); + ndev->stats.tx_errors++; + if (cf) { + cf->can_id |= CAN_ERR_ACK; + cf->data[2] |= CAN_ERR_PROT_TX; + } + break; + + case NCT6694_CANFD_EVT_ERR_FORM_ERROR: + netdev_dbg(ndev, "Form error\n"); + ndev->stats.rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + + case NCT6694_CANFD_EVT_ERR_BIT_ERROR: + netdev_dbg(ndev, "Bit error\n"); + ndev->stats.tx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT; + break; + + default: + break; + } + + if (skb) + nct6694_canfd_rx_offload(&priv->offload, skb); +} + +static void nct6694_canfd_handle_tx(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + + stats->tx_bytes += can_rx_offload_get_echo_skb_queue_tail(&priv->offload, + 0, NULL); + stats->tx_packets++; + netif_wake_queue(ndev); +} + +static irqreturn_t nct6694_canfd_irq(int irq, void *data) +{ + struct net_device *ndev = data; + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct nct6694_canfd_event *event = &priv->event[ndev->dev_port]; + const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_EVENT, + .sel = NCT6694_CANFD_EVENT_SEL(ndev->dev_port, NCT6694_CANFD_EVENT_MASK), + .len = cpu_to_le16(sizeof(priv->event)) + }; + irqreturn_t handled = IRQ_NONE; + int ret; + + ret = nct6694_read_msg(priv->nct6694, &cmd_hd, priv->event); + if (ret < 0) + return handled; + + if (event->rx_evt & NCT6694_CANFD_EVT_RX_DATA_IN) { + nct6694_canfd_handle_rx(ndev, event->rx_evt); + handled = IRQ_HANDLED; + } + + if (event->rx_evt & NCT6694_CANFD_EVT_RX_DATA_LOST) { + nct6694_canfd_handle_lost_msg(ndev); + handled = IRQ_HANDLED; + } + + if (event->status) { + nct6694_canfd_handle_state_change(ndev, event->status); + handled = IRQ_HANDLED; + } + + if (event->err != NCT6694_CANFD_EVT_ERR_NO_ERROR) { + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + nct6694_canfd_handle_bus_err(ndev, event->err); + handled = IRQ_HANDLED; + } + + if (event->tx_evt & NCT6694_CANFD_EVT_TX_FIFO_EMPTY) { + nct6694_canfd_handle_tx(ndev); + handled = IRQ_HANDLED; + } + + if (handled) + can_rx_offload_threaded_irq_finish(&priv->offload); + + priv->bec.rxerr = event->rec; + priv->bec.txerr = event->tec; + + return handled; +} + +static void nct6694_canfd_tx_work(struct work_struct *work) +{ + struct nct6694_canfd_priv *priv = container_of(work, + struct nct6694_canfd_priv, + tx_work); + struct nct6694_canfd_frame *frame = &priv->tx; + struct net_device *ndev = priv->ndev; + struct net_device_stats *stats = &ndev->stats; + struct sk_buff *skb = priv->can.echo_skb[0]; + static const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_DELIVER, + .sel = NCT6694_CANFD_DELIVER_SEL(1), + .len = cpu_to_le16(sizeof(*frame)) + }; + u32 txid; + int err; + + memset(frame, 0, sizeof(*frame)); + + frame->tag = NCT6694_CANFD_FRAME_TAG(ndev->dev_port); + + if (can_is_canfd_skb(skb)) { + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + + if (cfd->flags & CANFD_BRS) + frame->flag |= NCT6694_CANFD_FRAME_FLAG_BRS; + + if (cfd->can_id & CAN_EFF_FLAG) { + txid = cfd->can_id & CAN_EFF_MASK; + frame->flag |= NCT6694_CANFD_FRAME_FLAG_EFF; + } else { + txid = cfd->can_id & CAN_SFF_MASK; + } + frame->flag |= NCT6694_CANFD_FRAME_FLAG_FD; + frame->id = cpu_to_le32(txid); + frame->length = canfd_sanitize_len(cfd->len); + + memcpy(frame->data, cfd->data, frame->length); + } else { + struct can_frame *cf = (struct can_frame *)skb->data; + + if (cf->can_id & CAN_EFF_FLAG) { + txid = cf->can_id & CAN_EFF_MASK; + frame->flag |= NCT6694_CANFD_FRAME_FLAG_EFF; + } else { + txid = cf->can_id & CAN_SFF_MASK; + } + + if (cf->can_id & CAN_RTR_FLAG) + frame->flag |= NCT6694_CANFD_FRAME_FLAG_RTR; + else + memcpy(frame->data, cf->data, cf->len); + + frame->id = cpu_to_le32(txid); + frame->length = cf->len; + } + + err = nct6694_write_msg(priv->nct6694, &cmd_hd, frame); + if (err) { + can_free_echo_skb(ndev, 0, NULL); + stats->tx_dropped++; + stats->tx_errors++; + netif_wake_queue(ndev); + } +} + +static netdev_tx_t nct6694_canfd_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + + if (can_dev_dropped_skb(ndev, skb)) + return NETDEV_TX_OK; + + netif_stop_queue(ndev); + can_put_echo_skb(skb, ndev, 0, 0); + queue_work(priv->wq, &priv->tx_work); + + return NETDEV_TX_OK; +} + +static int nct6694_canfd_start(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + const struct can_bittiming *n_bt = &priv->can.bittiming; + const struct can_bittiming *d_bt = &priv->can.fd.data_bittiming; + struct nct6694_canfd_setting *setting __free(kfree) = NULL; + const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_SETTING, + .sel = ndev->dev_port, + .len = cpu_to_le16(sizeof(*setting)) + }; + u32 en_tdc; + int ret; + + setting = kzalloc(sizeof(*setting), GFP_KERNEL); + if (!setting) + return -ENOMEM; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + setting->ctrl1 |= cpu_to_le16(NCT6694_CANFD_SETTING_CTRL1_MON); + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) + setting->ctrl1 |= cpu_to_le16(NCT6694_CANFD_SETTING_CTRL1_NISO); + + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + setting->ctrl1 |= cpu_to_le16(NCT6694_CANFD_SETTING_CTRL1_LBCK); + + /* Disable clock divider */ + setting->ctrl2 = 0; + + setting->nbtp = cpu_to_le32(FIELD_PREP(NCT6694_CANFD_SETTING_NBTP_NSJW, + n_bt->sjw - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_NBTP_NBRP, + n_bt->brp - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_NBTP_NTSEG2, + n_bt->phase_seg2 - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_NBTP_NTSEG1, + n_bt->prop_seg + n_bt->phase_seg1 - 1)); + + if (d_bt->brp <= 2) + en_tdc = NCT6694_CANFD_SETTING_DBTP_TDC; + else + en_tdc = 0; + + setting->dbtp = cpu_to_le32(FIELD_PREP(NCT6694_CANFD_SETTING_DBTP_DSJW, + d_bt->sjw - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_DBTP_DBRP, + d_bt->brp - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_DBTP_DTSEG2, + d_bt->phase_seg2 - 1) | + FIELD_PREP(NCT6694_CANFD_SETTING_DBTP_DTSEG1, + d_bt->prop_seg + d_bt->phase_seg1 - 1) | + en_tdc); + + setting->active = NCT6694_CANFD_SETTING_ACTIVE_CTRL1 | + NCT6694_CANFD_SETTING_ACTIVE_CTRL2 | + NCT6694_CANFD_SETTING_ACTIVE_NBTP_DBTP; + + ret = nct6694_write_msg(priv->nct6694, &cmd_hd, setting); + if (ret) + return ret; + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + return 0; +} + +static void nct6694_canfd_stop(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + struct nct6694_canfd_setting *setting __free(kfree) = NULL; + const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_SETTING, + .sel = ndev->dev_port, + .len = cpu_to_le16(sizeof(*setting)) + }; + + /* The NCT6694 cannot be stopped. To ensure safe operation and avoid + * interference, the control mode is set to Listen-Only mode. This + * mode allows the device to monitor bus activity without actively + * participating in communication. + */ + setting = kzalloc(sizeof(*setting), GFP_KERNEL); + if (!setting) + return; + + nct6694_read_msg(priv->nct6694, &cmd_hd, setting); + setting->ctrl1 = cpu_to_le16(NCT6694_CANFD_SETTING_CTRL1_MON); + setting->active = NCT6694_CANFD_SETTING_ACTIVE_CTRL1; + nct6694_write_msg(priv->nct6694, &cmd_hd, setting); + + priv->can.state = CAN_STATE_STOPPED; +} + +static int nct6694_canfd_close(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + nct6694_canfd_stop(ndev); + destroy_workqueue(priv->wq); + free_irq(ndev->irq, ndev); + can_rx_offload_disable(&priv->offload); + close_candev(ndev); + return 0; +} + +static int nct6694_canfd_set_mode(struct net_device *ndev, enum can_mode mode) +{ + int ret; + + switch (mode) { + case CAN_MODE_START: + ret = nct6694_canfd_start(ndev); + if (ret) + return ret; + + netif_wake_queue(ndev); + break; + + default: + return -EOPNOTSUPP; + } + + return ret; +} + +static int nct6694_canfd_open(struct net_device *ndev) +{ + struct nct6694_canfd_priv *priv = netdev_priv(ndev); + int ret; + + ret = open_candev(ndev); + if (ret) + return ret; + + can_rx_offload_enable(&priv->offload); + + ret = request_threaded_irq(ndev->irq, NULL, + nct6694_canfd_irq, IRQF_ONESHOT, + "nct6694_canfd", ndev); + if (ret) { + netdev_err(ndev, "Failed to request IRQ\n"); + goto can_rx_offload_disable; + } + + priv->wq = alloc_ordered_workqueue("%s-nct6694_wq", + WQ_FREEZABLE | WQ_MEM_RECLAIM, + ndev->name); + if (!priv->wq) { + ret = -ENOMEM; + goto free_irq; + } + + ret = nct6694_canfd_start(ndev); + if (ret) + goto destroy_wq; + + netif_start_queue(ndev); + + return 0; + +destroy_wq: + destroy_workqueue(priv->wq); +free_irq: + free_irq(ndev->irq, ndev); +can_rx_offload_disable: + can_rx_offload_disable(&priv->offload); + close_candev(ndev); + return ret; +} + +static const struct net_device_ops nct6694_canfd_netdev_ops = { + .ndo_open = nct6694_canfd_open, + .ndo_stop = nct6694_canfd_close, + .ndo_start_xmit = nct6694_canfd_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static const struct ethtool_ops nct6694_canfd_ethtool_ops = { + .get_ts_info = ethtool_op_get_ts_info, +}; + +static int nct6694_canfd_get_clock(struct nct6694_canfd_priv *priv) +{ + struct nct6694_canfd_information *info __free(kfree) = NULL; + static const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_CANFD_MOD, + .cmd = NCT6694_CANFD_INFORMATION, + .sel = NCT6694_CANFD_INFORMATION_SEL, + .len = cpu_to_le16(sizeof(*info)) + }; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = nct6694_read_msg(priv->nct6694, &cmd_hd, info); + if (ret) + return ret; + + return le32_to_cpu(info->can_clk); +} + +static int nct6694_canfd_probe(struct platform_device *pdev) +{ + struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent); + struct nct6694_canfd_priv *priv; + struct net_device *ndev; + int port, irq, ret, can_clk; + + port = ida_alloc(&nct6694->canfd_ida, GFP_KERNEL); + if (port < 0) + return port; + + irq = irq_create_mapping(nct6694->domain, + NCT6694_IRQ_CAN0 + port); + if (!irq) { + ret = -EINVAL; + goto free_ida; + } + + ndev = alloc_candev(sizeof(struct nct6694_canfd_priv), 1); + if (!ndev) { + ret = -ENOMEM; + goto dispose_irq; + } + + ndev->irq = irq; + ndev->flags |= IFF_ECHO; + ndev->dev_port = port; + ndev->netdev_ops = &nct6694_canfd_netdev_ops; + ndev->ethtool_ops = &nct6694_canfd_ethtool_ops; + + priv = netdev_priv(ndev); + priv->nct6694 = nct6694; + priv->ndev = ndev; + + can_clk = nct6694_canfd_get_clock(priv); + if (can_clk < 0) { + ret = dev_err_probe(&pdev->dev, can_clk, + "Failed to get clock\n"); + goto free_candev; + } + + INIT_WORK(&priv->tx_work, nct6694_canfd_tx_work); + + priv->can.clock.freq = can_clk; + priv->can.bittiming_const = &nct6694_canfd_bittiming_nominal_const; + priv->can.fd.data_bittiming_const = &nct6694_canfd_bittiming_data_const; + priv->can.do_set_mode = nct6694_canfd_set_mode; + priv->can.do_get_berr_counter = nct6694_canfd_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_FD_NON_ISO; + + ret = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD); + if (ret) + goto free_candev; + + ret = can_rx_offload_add_manual(ndev, &priv->offload, + NCT6694_NAPI_WEIGHT); + if (ret) { + dev_err_probe(&pdev->dev, ret, "Failed to add rx_offload\n"); + goto free_candev; + } + + platform_set_drvdata(pdev, priv); + SET_NETDEV_DEV(priv->ndev, &pdev->dev); + + ret = register_candev(priv->ndev); + if (ret) + goto rx_offload_del; + + return 0; + +rx_offload_del: + can_rx_offload_del(&priv->offload); +free_candev: + free_candev(ndev); +dispose_irq: + irq_dispose_mapping(irq); +free_ida: + ida_free(&nct6694->canfd_ida, port); + return ret; +} + +static void nct6694_canfd_remove(struct platform_device *pdev) +{ + struct nct6694_canfd_priv *priv = platform_get_drvdata(pdev); + struct nct6694 *nct6694 = priv->nct6694; + struct net_device *ndev = priv->ndev; + int port = ndev->dev_port; + int irq = ndev->irq; + + unregister_candev(ndev); + can_rx_offload_del(&priv->offload); + free_candev(ndev); + irq_dispose_mapping(irq); + ida_free(&nct6694->canfd_ida, port); +} + +static struct platform_driver nct6694_canfd_driver = { + .driver = { + .name = DEVICE_NAME, + }, + .probe = nct6694_canfd_probe, + .remove = nct6694_canfd_remove, +}; + +module_platform_driver(nct6694_canfd_driver); + +MODULE_DESCRIPTION("USB-CAN FD driver for NCT6694"); +MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 6b293a9056c2..9278a1522aae 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -3,8 +3,8 @@ * CAN driver for PEAK System PCAN-USB adapter * Derived from the PCAN project file driver/src/pcan_usb.c * - * Copyright (C) 2003-2010 PEAK System-Technik GmbH - * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> * * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> */ @@ -919,7 +919,7 @@ static int pcan_usb_init(struct peak_usb_device *dev) CAN_CTRLMODE_LOOPBACK; } else { dev_info(dev->netdev->dev.parent, - "Firmware update available. Please contact support@peak-system.com\n"); + "Firmware update available. Please contact support.peak@hms-networks.com\n"); } return 0; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 117637b9b995..c74302ca7cee 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -3,8 +3,8 @@ * CAN driver for PEAK System USB adapters * Derived from the PCAN project file driver/src/pcan_usb_core.c * - * Copyright (C) 2003-2010 PEAK System-Technik GmbH - * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> * * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> */ @@ -24,7 +24,7 @@ #include "pcan_usb_core.h" -MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); +MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>"); MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters"); MODULE_LICENSE("GPL v2"); @@ -111,7 +111,7 @@ void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now) u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1; if (time_ref->ts_dev_2 < time_ref->ts_dev_1) - delta_ts &= (1 << time_ref->adapter->ts_used_bits) - 1; + delta_ts &= (1ULL << time_ref->adapter->ts_used_bits) - 1; time_ref->ts_total += delta_ts; } diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index abab00930b9d..d1c1897d47b9 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -3,8 +3,8 @@ * CAN driver for PEAK System USB adapters * Derived from the PCAN project file driver/src/pcan_usb_core.c * - * Copyright (C) 2003-2010 PEAK System-Technik GmbH - * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> * * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index ebefc274b50a..be84191cde56 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -2,7 +2,8 @@ /* * CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter * - * Copyright (C) 2013-2014 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2013-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/ethtool.h> #include <linux/module.h> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index f736196383ac..7be286293b1a 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -3,8 +3,8 @@ * CAN driver for PEAK System PCAN-USB Pro adapter * Derived from the PCAN project file driver/src/pcan_usbpro.c * - * Copyright (C) 2003-2011 PEAK System-Technik GmbH - * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #include <linux/ethtool.h> #include <linux/module.h> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index 28e740af905d..162c7546d3a8 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -3,8 +3,8 @@ * CAN driver for PEAK System PCAN-USB Pro adapter * Derived from the PCAN project file driver/src/pcan_usbpro_fw.h * - * Copyright (C) 2003-2011 PEAK System-Technik GmbH - * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #ifndef PCAN_USB_PRO_H #define PCAN_USB_PRO_H diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index f67e85807100..fdc662aea279 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -156,7 +156,7 @@ static const struct ethtool_ops vcan_ethtool_ops = { static void vcan_setup(struct net_device *dev) { dev->type = ARPHRD_CAN; - dev->mtu = CANFD_MTU; + dev->mtu = CANXL_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 99a78a757167..b2c19f8c5f8e 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -156,7 +156,7 @@ static void vxcan_setup(struct net_device *dev) struct can_ml_priv *can_ml; dev->type = ARPHRD_CAN; - dev->mtu = CANFD_MTU; + dev->mtu = CANXL_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0; diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 81baec8eb1e5..a25a3ca62c12 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -690,14 +690,6 @@ static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb, dlc |= XCAN_DLCR_EDL_MASK; } - if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) && - (priv->devtype.flags & XCAN_FLAG_TXFEMP)) - can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max, 0); - else - can_put_echo_skb(skb, ndev, 0, 0); - - priv->tx_head++; - priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id); /* If the CAN frame is RTR frame this write triggers transmission * (not on CAN FD) @@ -730,6 +722,14 @@ static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb, data[1]); } } + + if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) && + (priv->devtype.flags & XCAN_FLAG_TXFEMP)) + can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max, 0); + else + can_put_echo_skb(skb, ndev, 0, 0); + + priv->tx_head++; } /** |