Commit 12f241f2 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.16-20211024' of...

Merge tag 'linux-can-next-for-5.16-20211024' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-10-24

this is a pull request of 15 patches for net-next/master.

The first patch is by Thomas Gleixner and makes use of
hrtimer_forward_now() in the CAN broad cast manager (bcm).

The next patch is by me and changes the type of the variables used in
the CAN bit timing calculation can_fixup_bittiming() to unsigned int.

Vincent Mailhol provides 6 patches targeting the CAN device
infrastructure. The CAN-FD specific Transmitter Delay Compensation
(TDC) is updated and configuration via the CAN netlink interface is
added.

Qing Wang's patch updates the at91 and janz-ican3 drivers to use
sysfs_emit() instead of snprintf() in the sysfs show functions.

Geert Uytterhoeven's patch drops the unneeded ARM dependency from the
rar Kconfig.

Cai Huoqing's patch converts the mscan driver to make use of the
dev_err_probe() helper function.

A patch by me against the gsusb driver changes the printf format
strings to use %u to print unsigned values.

Stephane Grosjean's patch updates the peak_usb CAN-FD driver to use
the 64 bit timestamps provided by the hardware.

The last 2 patches target the xilinx_can driver. Michal Simek provides
a patch that removes repeated word from the kernel-doc and Dongliang
Mu's patch removes a redundant netif_napi_del() from the xcan_remove()
function.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 45f850c1 b9b8218b
...@@ -1170,9 +1170,9 @@ static ssize_t mb0_id_show(struct device *dev, ...@@ -1170,9 +1170,9 @@ static ssize_t mb0_id_show(struct device *dev,
struct at91_priv *priv = netdev_priv(to_net_dev(dev)); struct at91_priv *priv = netdev_priv(to_net_dev(dev));
if (priv->mb0_id & CAN_EFF_FLAG) if (priv->mb0_id & CAN_EFF_FLAG)
return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id); return sysfs_emit(buf, "0x%08x\n", priv->mb0_id);
else else
return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id); return sysfs_emit(buf, "0x%03x\n", priv->mb0_id);
} }
static ssize_t mb0_id_store(struct device *dev, static ssize_t mb0_id_store(struct device *dev,
......
...@@ -175,27 +175,29 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -175,27 +175,29 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0; return 0;
} }
void can_calc_tdco(struct net_device *dev) void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
{ const struct can_bittiming *dbt,
struct can_priv *priv = netdev_priv(dev); u32 *ctrlmode, u32 ctrlmode_supported)
const struct can_bittiming *dbt = &priv->data_bittiming;
struct can_tdc *tdc = &priv->tdc;
const struct can_tdc_const *tdc_const = priv->tdc_const;
if (!tdc_const) {
if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
return; return;
*ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter /* As specified in ISO 11898-1 section 11.3.3 "Transmitter
* delay compensation" (TDC) is only applicable if data BRP is * delay compensation" (TDC) is only applicable if data BRP is
* one or two. * one or two.
*/ */
if (dbt->brp == 1 || dbt->brp == 2) { if (dbt->brp == 1 || dbt->brp == 2) {
/* Reuse "normal" sample point and convert it to time quanta */ /* Sample point in clock periods */
u32 sample_point_in_tq = can_bit_time(dbt) * dbt->sample_point / 1000; u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
dbt->phase_seg1) * dbt->brp;
tdc->tdco = min(sample_point_in_tq, tdc_const->tdco_max); if (sample_point_in_tc < tdc_const->tdco_min)
} else { return;
tdc->tdco = 0; tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
} }
} }
#endif /* CONFIG_CAN_CALC_BITTIMING */ #endif /* CONFIG_CAN_CALC_BITTIMING */
...@@ -209,7 +211,7 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -209,7 +211,7 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc) const struct can_bittiming_const *btc)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
int tseg1, alltseg; unsigned int tseg1, alltseg;
u64 brp64; u64 brp64;
tseg1 = bt->prop_seg + bt->phase_seg1; tseg1 = bt->prop_seg + bt->phase_seg1;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
* Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2006 Andrey Volkov, Varma Electronics
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/ */
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -19,6 +20,19 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { ...@@ -19,6 +20,19 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
[IFLA_CAN_TDC] = { .type = NLA_NESTED },
};
static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = {
[IFLA_CAN_TDC_TDCV_MIN] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCV_MAX] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCO_MIN] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCO_MAX] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCF_MIN] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCF_MAX] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCV] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCO] = { .type = NLA_U32 },
[IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 },
}; };
static int can_validate(struct nlattr *tb[], struct nlattr *data[], static int can_validate(struct nlattr *tb[], struct nlattr *data[],
...@@ -30,6 +44,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], ...@@ -30,6 +44,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
* - nominal/arbitration bittiming * - nominal/arbitration bittiming
* - data bittiming * - data bittiming
* - control mode with CAN_CTRLMODE_FD set * - control mode with CAN_CTRLMODE_FD set
* - TDC parameters are coherent (details below)
*/ */
if (!data) if (!data)
...@@ -37,8 +52,43 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], ...@@ -37,8 +52,43 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
if (data[IFLA_CAN_CTRLMODE]) { if (data[IFLA_CAN_CTRLMODE]) {
struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK;
is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */
if (tdc_flags == CAN_CTRLMODE_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];
int err;
err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX,
data[IFLA_CAN_TDC],
can_tdc_policy, extack);
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;
}
if (!tb_tdc[IFLA_CAN_TDC_TDCO])
return -EOPNOTSUPP;
}
} }
if (is_can_fd) { if (is_can_fd) {
...@@ -46,7 +96,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], ...@@ -46,7 +96,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (data[IFLA_CAN_DATA_BITTIMING]) { if (data[IFLA_CAN_DATA_BITTIMING] || data[IFLA_CAN_TDC]) {
if (!is_can_fd) if (!is_can_fd)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -54,11 +104,60 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], ...@@ -54,11 +104,60 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
return 0; return 0;
} }
static int can_tdc_changelink(struct can_priv *priv, 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->tdc_const;
int err;
if (!tdc_const || !can_tdc_is_enabled(priv))
return -EOPNOTSUPP;
err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla,
can_tdc_policy, extack);
if (err)
return err;
if (tb_tdc[IFLA_CAN_TDC_TDCV]) {
u32 tdcv = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCV]);
if (tdcv < tdc_const->tdcv_min || tdcv > tdc_const->tdcv_max)
return -EINVAL;
tdc.tdcv = tdcv;
}
if (tb_tdc[IFLA_CAN_TDC_TDCO]) {
u32 tdco = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCO]);
if (tdco < tdc_const->tdco_min || tdco > tdc_const->tdco_max)
return -EINVAL;
tdc.tdco = tdco;
}
if (tb_tdc[IFLA_CAN_TDC_TDCF]) {
u32 tdcf = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCF]);
if (tdcf < tdc_const->tdcf_min || tdcf > tdc_const->tdcf_max)
return -EINVAL;
tdc.tdcf = tdcf;
}
priv->tdc = tdc;
return 0;
}
static int can_changelink(struct net_device *dev, struct nlattr *tb[], static int can_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[], struct nlattr *data[],
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
u32 tdc_mask = 0;
int err; int err;
/* We need synchronization with dev->stop() */ /* We need synchronization with dev->stop() */
...@@ -138,7 +237,16 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -138,7 +237,16 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
dev->mtu = CAN_MTU; dev->mtu = CAN_MTU;
memset(&priv->data_bittiming, 0, memset(&priv->data_bittiming, 0,
sizeof(priv->data_bittiming)); sizeof(priv->data_bittiming));
priv->ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
memset(&priv->tdc, 0, sizeof(priv->tdc));
} }
tdc_mask = cm->mask & CAN_CTRLMODE_TDC_MASK;
/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually
* exclusive: make sure to turn the other one off
*/
if (tdc_mask)
priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK;
} }
if (data[IFLA_CAN_RESTART_MS]) { if (data[IFLA_CAN_RESTART_MS]) {
...@@ -187,9 +295,26 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -187,9 +295,26 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
return -EINVAL; return -EINVAL;
} }
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); memset(&priv->tdc, 0, sizeof(priv->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_TDC_MASK;
return err;
}
} else if (!tdc_mask) {
/* Neither of TDC parameters nor TDC flags are
* provided: do calculation
*/
can_calc_tdco(&priv->tdc, priv->tdc_const, &priv->data_bittiming,
&priv->ctrlmode, priv->ctrlmode_supported);
} /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
* turned off. TDC is disabled: do nothing
*/
can_calc_tdco(dev); memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
if (priv->do_set_data_bittiming) { if (priv->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */ /* Finally, set the bit-timing registers */
...@@ -226,6 +351,38 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -226,6 +351,38 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
return 0; return 0;
} }
static size_t can_tdc_get_size(const struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
size_t size;
if (!priv->tdc_const)
return 0;
size = nla_total_size(0); /* nest IFLA_CAN_TDC */
if (priv->ctrlmode_supported & CAN_CTRLMODE_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->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_tdc_is_enabled(priv)) {
if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL ||
priv->do_get_auto_tdcv)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
if (priv->tdc_const->tdcf_max)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF */
}
return size;
}
static size_t can_get_size(const struct net_device *dev) static size_t can_get_size(const struct net_device *dev)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
...@@ -257,10 +414,64 @@ static size_t can_get_size(const struct net_device *dev) ...@@ -257,10 +414,64 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(*priv->data_bitrate_const) * size += nla_total_size(sizeof(*priv->data_bitrate_const) *
priv->data_bitrate_const_cnt); priv->data_bitrate_const_cnt);
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */ size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
size += can_tdc_get_size(dev); /* IFLA_CAN_TDC */
return size; return size;
} }
static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
struct nlattr *nest;
struct can_priv *priv = netdev_priv(dev);
struct can_tdc *tdc = &priv->tdc;
const struct can_tdc_const *tdc_const = priv->tdc_const;
if (!tdc_const)
return 0;
nest = nla_nest_start(skb, IFLA_CAN_TDC);
if (!nest)
return -EMSGSIZE;
if (priv->ctrlmode_supported & CAN_CTRLMODE_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;
if (nla_put_u32(skb, IFLA_CAN_TDC_TDCO_MIN, tdc_const->tdco_min) ||
nla_put_u32(skb, IFLA_CAN_TDC_TDCO_MAX, tdc_const->tdco_max))
goto err_cancel;
if (tdc_const->tdcf_max &&
(nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MIN, tdc_const->tdcf_min) ||
nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MAX, tdc_const->tdcf_max)))
goto err_cancel;
if (can_tdc_is_enabled(priv)) {
u32 tdcv;
int err = -EINVAL;
if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) {
tdcv = tdc->tdcv;
err = 0;
} else if (priv->do_get_auto_tdcv) {
err = priv->do_get_auto_tdcv(dev, &tdcv);
}
if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
goto err_cancel;
if (nla_put_u32(skb, IFLA_CAN_TDC_TDCO, tdc->tdco))
goto err_cancel;
if (tdc_const->tdcf_max &&
nla_put_u32(skb, IFLA_CAN_TDC_TDCF, tdc->tdcf))
goto err_cancel;
}
nla_nest_end(skb, nest);
return 0;
err_cancel:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
...@@ -318,7 +529,9 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -318,7 +529,9 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
(nla_put(skb, IFLA_CAN_BITRATE_MAX, (nla_put(skb, IFLA_CAN_BITRATE_MAX,
sizeof(priv->bitrate_max), sizeof(priv->bitrate_max),
&priv->bitrate_max)) &priv->bitrate_max)) ||
(can_tdc_fill_info(skb, dev))
) )
return -EMSGSIZE; return -EMSGSIZE;
......
...@@ -1831,7 +1831,7 @@ static ssize_t termination_show(struct device *dev, ...@@ -1831,7 +1831,7 @@ static ssize_t termination_show(struct device *dev,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
return snprintf(buf, PAGE_SIZE, "%u\n", mod->termination_enabled); return sysfs_emit(buf, "%u\n", mod->termination_enabled);
} }
static ssize_t termination_store(struct device *dev, static ssize_t termination_store(struct device *dev,
......
...@@ -293,10 +293,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev) ...@@ -293,10 +293,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
return -EINVAL; return -EINVAL;
base = of_iomap(np, 0); base = of_iomap(np, 0);
if (!base) { if (!base)
dev_err(&ofdev->dev, "couldn't ioremap\n"); return dev_err_probe(&ofdev->dev, err, "couldn't ioremap\n");
return err;
}
irq = irq_of_parse_and_map(np, 0); irq = irq_of_parse_and_map(np, 0);
if (!irq) { if (!irq) {
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
config CAN_RCAR config CAN_RCAR
tristate "Renesas R-Car and RZ/G CAN controller" tristate "Renesas R-Car and RZ/G CAN controller"
depends on ARCH_RENESAS || ARM || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
help help
Say Y here if you want to use CAN controller found on Renesas R-Car Say Y here if you want to use CAN controller found on Renesas R-Car
or RZ/G SoCs. or RZ/G SoCs.
...@@ -11,7 +11,7 @@ config CAN_RCAR ...@@ -11,7 +11,7 @@ config CAN_RCAR
config CAN_RCAR_CANFD config CAN_RCAR_CANFD
tristate "Renesas R-Car CAN FD controller" tristate "Renesas R-Car CAN FD controller"
depends on ARCH_RENESAS || ARM || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
help help
Say Y here if you want to use CAN FD controller found on Say Y here if you want to use CAN FD controller found on
Renesas R-Car SoCs. The driver puts the controller in CAN FD only Renesas R-Car SoCs. The driver puts the controller in CAN FD only
......
...@@ -428,7 +428,7 @@ static int es58x_fd_enable_channel(struct es58x_priv *priv) ...@@ -428,7 +428,7 @@ static int es58x_fd_enable_channel(struct es58x_priv *priv)
es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming, es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming,
&priv->can.data_bittiming); &priv->can.data_bittiming);
if (priv->can.tdc.tdco) { if (can_tdc_is_enabled(&priv->can)) {
tx_conf_msg.tdc_enabled = 1; tx_conf_msg.tdc_enabled = 1;
tx_conf_msg.tdco = cpu_to_le16(priv->can.tdc.tdco); tx_conf_msg.tdco = cpu_to_le16(priv->can.tdc.tdco);
tx_conf_msg.tdcf = cpu_to_le16(priv->can.tdc.tdcf); tx_conf_msg.tdcf = cpu_to_le16(priv->can.tdc.tdcf);
...@@ -505,8 +505,11 @@ static const struct can_bittiming_const es58x_fd_data_bittiming_const = { ...@@ -505,8 +505,11 @@ static const struct can_bittiming_const es58x_fd_data_bittiming_const = {
* Register" from Microchip. * Register" from Microchip.
*/ */
static const struct can_tdc_const es58x_tdc_const = { static const struct can_tdc_const es58x_tdc_const = {
.tdcv_min = 0,
.tdcv_max = 0, /* Manual mode not supported. */ .tdcv_max = 0, /* Manual mode not supported. */
.tdco_min = 0,
.tdco_max = 127, .tdco_max = 127,
.tdcf_min = 0,
.tdcf_max = 127 .tdcf_max = 127
}; };
...@@ -523,7 +526,7 @@ const struct es58x_parameters es58x_fd_param = { ...@@ -523,7 +526,7 @@ const struct es58x_parameters es58x_fd_param = {
.clock = {.freq = 80 * CAN_MHZ}, .clock = {.freq = 80 * CAN_MHZ},
.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | .ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_TDC_AUTO,
.tx_start_of_frame = 0xCEFA, /* FACE in little endian */ .tx_start_of_frame = 0xCEFA, /* FACE in little endian */
.rx_start_of_frame = 0xFECA, /* CAFE in little endian */ .rx_start_of_frame = 0xFECA, /* CAFE in little endian */
.tx_urb_cmd_max_len = ES58X_FD_TX_URB_CMD_MAX_LEN, .tx_urb_cmd_max_len = ES58X_FD_TX_URB_CMD_MAX_LEN,
......
...@@ -352,7 +352,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) ...@@ -352,7 +352,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
} else { /* echo_id == hf->echo_id */ } else { /* echo_id == hf->echo_id */
if (hf->echo_id >= GS_MAX_TX_URBS) { if (hf->echo_id >= GS_MAX_TX_URBS) {
netdev_err(netdev, netdev_err(netdev,
"Unexpected out of range echo id %d\n", "Unexpected out of range echo id %u\n",
hf->echo_id); hf->echo_id);
goto resubmit_urb; goto resubmit_urb;
} }
...@@ -365,7 +365,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) ...@@ -365,7 +365,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
/* bad devices send bad echo_ids. */ /* bad devices send bad echo_ids. */
if (!txc) { if (!txc) {
netdev_err(netdev, netdev_err(netdev,
"Unexpected unused echo id %d\n", "Unexpected unused echo id %u\n",
hf->echo_id); hf->echo_id);
goto resubmit_urb; goto resubmit_urb;
} }
...@@ -458,7 +458,7 @@ static void gs_usb_xmit_callback(struct urb *urb) ...@@ -458,7 +458,7 @@ static void gs_usb_xmit_callback(struct urb *urb)
struct net_device *netdev = dev->netdev; struct net_device *netdev = dev->netdev;
if (urb->status) if (urb->status)
netdev_info(netdev, "usb xmit fail %d\n", txc->echo_id); netdev_info(netdev, "usb xmit fail %u\n", txc->echo_id);
usb_free_coherent(urb->dev, usb_free_coherent(urb->dev,
urb->transfer_buffer_length, urb->transfer_buffer_length,
...@@ -501,7 +501,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, ...@@ -501,7 +501,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
idx = txc->echo_id; idx = txc->echo_id;
if (idx >= GS_MAX_TX_URBS) { if (idx >= GS_MAX_TX_URBS) {
netdev_err(netdev, "Invalid tx context %d\n", idx); netdev_err(netdev, "Invalid tx context %u\n", idx);
goto badidx; goto badidx;
} }
...@@ -964,11 +964,11 @@ static int gs_usb_probe(struct usb_interface *intf, ...@@ -964,11 +964,11 @@ static int gs_usb_probe(struct usb_interface *intf,
} }
icount = dconf->icount + 1; icount = dconf->icount + 1;
dev_info(&intf->dev, "Configuring for %d interfaces\n", icount); dev_info(&intf->dev, "Configuring for %u interfaces\n", icount);
if (icount > GS_MAX_INTF) { if (icount > GS_MAX_INTF) {
dev_err(&intf->dev, dev_err(&intf->dev,
"Driver cannot handle more that %d CAN interfaces\n", "Driver cannot handle more that %u CAN interfaces\n",
GS_MAX_INTF); GS_MAX_INTF);
kfree(dconf); kfree(dconf);
return -EINVAL; return -EINVAL;
......
...@@ -205,6 +205,19 @@ int peak_usb_netif_rx(struct sk_buff *skb, ...@@ -205,6 +205,19 @@ int peak_usb_netif_rx(struct sk_buff *skb,
return netif_rx(skb); return netif_rx(skb);
} }
/* post received skb with native 64-bit hw timestamp */
int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high)
{
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
u64 ns_ts;
ns_ts = (u64)ts_high << 32 | ts_low;
ns_ts *= NSEC_PER_USEC;
hwts->hwtstamp = ns_to_ktime(ns_ts);
return netif_rx(skb);
}
/* /*
* callback for bulk Rx urb * callback for bulk Rx urb
*/ */
......
...@@ -143,6 +143,7 @@ void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); ...@@ -143,6 +143,7 @@ void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *tv); void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *tv);
int peak_usb_netif_rx(struct sk_buff *skb, int peak_usb_netif_rx(struct sk_buff *skb,
struct peak_time_ref *time_ref, u32 ts_low); struct peak_time_ref *time_ref, u32 ts_low);
int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high);
void peak_usb_async_complete(struct urb *urb); void peak_usb_async_complete(struct urb *urb);
void peak_usb_restart_complete(struct peak_usb_device *dev); void peak_usb_restart_complete(struct peak_usb_device *dev);
......
...@@ -515,7 +515,8 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if, ...@@ -515,7 +515,8 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
netdev->stats.rx_packets++; netdev->stats.rx_packets++;
netdev->stats.rx_bytes += cfd->len; netdev->stats.rx_bytes += cfd->len;
peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(rm->ts_low)); peak_usb_netif_rx_64(skb, le32_to_cpu(rm->ts_low),
le32_to_cpu(rm->ts_high));
return 0; return 0;
} }
...@@ -579,7 +580,8 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if, ...@@ -579,7 +580,8 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
netdev->stats.rx_packets++; netdev->stats.rx_packets++;
netdev->stats.rx_bytes += cf->len; netdev->stats.rx_bytes += cf->len;
peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(sm->ts_low)); peak_usb_netif_rx_64(skb, le32_to_cpu(sm->ts_low),
le32_to_cpu(sm->ts_high));
return 0; return 0;
} }
...@@ -629,7 +631,8 @@ static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if, ...@@ -629,7 +631,8 @@ static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if,
cf->can_id |= CAN_ERR_CRTL; cf->can_id |= CAN_ERR_CRTL;
cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(ov->ts_low)); peak_usb_netif_rx_64(skb, le32_to_cpu(ov->ts_low),
le32_to_cpu(ov->ts_high));
netdev->stats.rx_over_errors++; netdev->stats.rx_over_errors++;
netdev->stats.rx_errors++; netdev->stats.rx_errors++;
......
...@@ -516,8 +516,7 @@ static int xcan_chip_start(struct net_device *ndev) ...@@ -516,8 +516,7 @@ static int xcan_chip_start(struct net_device *ndev)
* @ndev: Pointer to net_device structure * @ndev: Pointer to net_device structure
* @mode: Tells the mode of the driver * @mode: Tells the mode of the driver
* *
* This check the drivers state and calls the * This check the drivers state and calls the corresponding modes to set.
* the corresponding modes to set.
* *
* Return: 0 on success and failure value on error * Return: 0 on success and failure value on error
*/ */
...@@ -982,7 +981,7 @@ static void xcan_update_error_state_after_rxtx(struct net_device *ndev) ...@@ -982,7 +981,7 @@ static void xcan_update_error_state_after_rxtx(struct net_device *ndev)
* @isr: interrupt status register value * @isr: interrupt status register value
* *
* This is the CAN error interrupt and it will * This is the CAN error interrupt and it will
* check the the type of error and forward the error * check the type of error and forward the error
* frame to upper layers. * frame to upper layers.
*/ */
static void xcan_err_interrupt(struct net_device *ndev, u32 isr) static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
...@@ -1844,11 +1843,9 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1844,11 +1843,9 @@ static int xcan_probe(struct platform_device *pdev)
static int xcan_remove(struct platform_device *pdev) static int xcan_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct xcan_priv *priv = netdev_priv(ndev);
unregister_candev(ndev); unregister_candev(ndev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(ndev); free_candev(ndev);
return 0; return 0;
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
/* Megahertz */ /* Megahertz */
#define CAN_MHZ 1000000UL #define CAN_MHZ 1000000UL
#define CAN_CTRLMODE_TDC_MASK \
(CAN_CTRLMODE_TDC_AUTO | CAN_CTRLMODE_TDC_MANUAL)
/* /*
* struct can_tdc - CAN FD Transmission Delay Compensation parameters * struct can_tdc - CAN FD Transmission Delay Compensation parameters
* *
...@@ -28,34 +31,54 @@ ...@@ -28,34 +31,54 @@
* *
* To solve this issue, ISO 11898-1 introduces in section 11.3.3 * To solve this issue, ISO 11898-1 introduces in section 11.3.3
* "Transmitter delay compensation" a SSP (Secondary Sample Point) * "Transmitter delay compensation" a SSP (Secondary Sample Point)
* equal to the distance, in time quanta, from the start of the bit * equal to the distance from the start of the bit time on the TX pin
* time on the TX pin to the actual measurement on the RX pin. * to the actual measurement on the RX pin.
* *
* This structure contains the parameters to calculate that SSP. * This structure contains the parameters to calculate that SSP.
* *
* @tdcv: Transmitter Delay Compensation Value. Distance, in time * -+----------- one bit ----------+-- TX pin
* quanta, from when the bit is sent on the TX pin to when it is * |<--- Sample Point --->|
* received on the RX pin of the transmitter. Possible options:
* *
* 0: automatic mode. The controller dynamically measures @tdcv * --+----------- one bit ----------+-- RX pin
* for each transmitted CAN FD frame. * |<-------- TDCV -------->|
* |<------- TDCO ------->|
* |<----------- Secondary Sample Point ---------->|
* *
* Other values: manual mode. Use the fixed provided value. * To increase precision, contrary to the other bittiming parameters
* which are measured in time quanta, the TDC parameters are measured
* in clock periods (also referred as "minimum time quantum" in ISO
* 11898-1).
* *
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time * @tdcv: Transmitter Delay Compensation Value. The time needed for
* quanta, defining the distance between the start of the bit * the signal to propagate, i.e. the distance, in clock periods,
* reception on the RX pin of the transceiver and the SSP * from the start of the bit on the TX pin to when it is received
* position such that SSP = @tdcv + @tdco. * on the RX pin. @tdcv depends on the controller modes:
*
* CAN_CTRLMODE_TDC_AUTO is set: The transceiver dynamically
* measures @tdcv for each transmitted CAN FD frame and the
* value provided here should be ignored.
*
* CAN_CTRLMODE_TDC_MANUAL is set: use the fixed provided @tdcv
* value.
* *
* If @tdco is zero, then TDC is disabled and both @tdcv and * N.B. CAN_CTRLMODE_TDC_AUTO and CAN_CTRLMODE_TDC_MANUAL are
* @tdcf should be ignored. * mutually exclusive. Only one can be set at a time. If both
* CAN_TDC_CTRLMODE_AUTO and CAN_TDC_CTRLMODE_MANUAL are unset,
* TDC is disabled and all the values of this structure should be
* ignored.
*
* @tdco: Transmitter Delay Compensation Offset. Offset value, in
* clock periods, defining the distance between the start of the
* bit reception on the RX pin of the transceiver and the SSP
* position such that SSP = @tdcv + @tdco.
* *
* @tdcf: Transmitter Delay Compensation Filter window. Defines the * @tdcf: Transmitter Delay Compensation Filter window. Defines the
* minimum value for the SSP position in time quanta. If SSP is * minimum value for the SSP position in clock periods. If the
* less than @tdcf, then no delay compensations occur and the * SSP position is less than @tdcf, then no delay compensations
* normal sampling point is used instead. The feature is enabled * occur and the normal sampling point is used instead. The
* if and only if @tdcv is set to zero (automatic mode) and @tdcf * feature is enabled if and only if @tdcv is set to zero
* is configured to a value greater than @tdco. * (automatic mode) and @tdcf is configured to a value greater
* than @tdco.
*/ */
struct can_tdc { struct can_tdc {
u32 tdcv; u32 tdcv;
...@@ -67,19 +90,32 @@ struct can_tdc { ...@@ -67,19 +90,32 @@ struct can_tdc {
* struct can_tdc_const - CAN hardware-dependent constant for * struct can_tdc_const - CAN hardware-dependent constant for
* Transmission Delay Compensation * Transmission Delay Compensation
* *
* @tdcv_max: Transmitter Delay Compensation Value maximum value. * @tdcv_min: Transmitter Delay Compensation Value minimum value. If
* Should be set to zero if the controller does not support * the controller does not support manual mode for tdcv
* manual mode for tdcv. * (c.f. flag CAN_CTRLMODE_TDC_MANUAL) then this value is
* ignored.
* @tdcv_max: Transmitter Delay Compensation Value maximum value. If
* the controller does not support manual mode for tdcv
* (c.f. flag CAN_CTRLMODE_TDC_MANUAL) then this value is
* ignored.
*
* @tdco_min: Transmitter Delay Compensation Offset minimum value.
* @tdco_max: Transmitter Delay Compensation Offset maximum value. * @tdco_max: Transmitter Delay Compensation Offset maximum value.
* Should not be zero. If the controller does not support TDC, * Should not be zero. If the controller does not support TDC,
* then the pointer to this structure should be NULL. * then the pointer to this structure should be NULL.
*
* @tdcf_min: Transmitter Delay Compensation Filter window minimum
* value. If @tdcf_max is zero, this value is ignored.
* @tdcf_max: Transmitter Delay Compensation Filter window maximum * @tdcf_max: Transmitter Delay Compensation Filter window maximum
* value. Should be set to zero if the controller does not * value. Should be set to zero if the controller does not
* support this feature. * support this feature.
*/ */
struct can_tdc_const { struct can_tdc_const {
u32 tdcv_min;
u32 tdcv_max; u32 tdcv_max;
u32 tdco_min;
u32 tdco_max; u32 tdco_max;
u32 tdcf_min;
u32 tdcf_max; u32 tdcf_max;
}; };
...@@ -87,7 +123,9 @@ struct can_tdc_const { ...@@ -87,7 +123,9 @@ struct can_tdc_const {
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc); const struct can_bittiming_const *btc);
void can_calc_tdco(struct net_device *dev); 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);
#else /* !CONFIG_CAN_CALC_BITTIMING */ #else /* !CONFIG_CAN_CALC_BITTIMING */
static inline int static inline int
can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
...@@ -97,7 +135,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -97,7 +135,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return -EINVAL; return -EINVAL;
} }
static inline void can_calc_tdco(struct net_device *dev) static inline 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)
{ {
} }
#endif /* CONFIG_CAN_CALC_BITTIMING */ #endif /* CONFIG_CAN_CALC_BITTIMING */
......
...@@ -82,6 +82,7 @@ struct can_priv { ...@@ -82,6 +82,7 @@ struct can_priv {
enum can_state *state); enum can_state *state);
int (*do_get_berr_counter)(const struct net_device *dev, int (*do_get_berr_counter)(const struct net_device *dev,
struct can_berr_counter *bec); struct can_berr_counter *bec);
int (*do_get_auto_tdcv)(const struct net_device *dev, u32 *tdcv);
unsigned int echo_skb_max; unsigned int echo_skb_max;
struct sk_buff **echo_skb; struct sk_buff **echo_skb;
...@@ -96,6 +97,39 @@ struct can_priv { ...@@ -96,6 +97,39 @@ struct can_priv {
#endif #endif
}; };
static inline bool can_tdc_is_enabled(const struct can_priv *priv)
{
return !!(priv->ctrlmode & CAN_CTRLMODE_TDC_MASK);
}
/*
* can_get_relative_tdco() - TDCO relative to the sample point
*
* struct can_tdc::tdco represents the absolute offset from TDCV. Some
* controllers use instead an offset relative to the Sample Point (SP)
* such that:
*
* SSP = TDCV + absolute TDCO
* = TDCV + SP + relative TDCO
*
* -+----------- one bit ----------+-- TX pin
* |<--- Sample Point --->|
*
* --+----------- one bit ----------+-- RX pin
* |<-------- TDCV -------->|
* |<------------------------>| absolute TDCO
* |<--- Sample Point --->|
* | |<->| relative TDCO
* |<------------- Secondary Sample Point ------------>|
*/
static inline s32 can_get_relative_tdco(const struct can_priv *priv)
{
const struct can_bittiming *dbt = &priv->data_bittiming;
s32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
dbt->phase_seg1) * dbt->brp;
return (s32)priv->tdc.tdco - sample_point_in_tc;
}
/* helper to define static CAN controller features at device creation time */ /* helper to define static CAN controller features at device creation time */
static inline void can_set_static_ctrlmode(struct net_device *dev, static inline void can_set_static_ctrlmode(struct net_device *dev,
......
...@@ -101,6 +101,8 @@ struct can_ctrlmode { ...@@ -101,6 +101,8 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ #define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ #define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ #define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */
#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */
/* /*
* CAN device statistics * CAN device statistics
...@@ -134,10 +136,35 @@ enum { ...@@ -134,10 +136,35 @@ enum {
IFLA_CAN_BITRATE_CONST, IFLA_CAN_BITRATE_CONST,
IFLA_CAN_DATA_BITRATE_CONST, IFLA_CAN_DATA_BITRATE_CONST,
IFLA_CAN_BITRATE_MAX, IFLA_CAN_BITRATE_MAX,
__IFLA_CAN_MAX IFLA_CAN_TDC,
/* add new constants above here */
__IFLA_CAN_MAX,
IFLA_CAN_MAX = __IFLA_CAN_MAX - 1
}; };
#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1) /*
* CAN FD Transmitter Delay Compensation (TDC)
*
* Please refer to struct can_tdc_const and can_tdc in
* include/linux/can/bittiming.h for further details.
*/
enum {
IFLA_CAN_TDC_UNSPEC,
IFLA_CAN_TDC_TDCV_MIN, /* u32 */
IFLA_CAN_TDC_TDCV_MAX, /* u32 */
IFLA_CAN_TDC_TDCO_MIN, /* u32 */
IFLA_CAN_TDC_TDCO_MAX, /* u32 */
IFLA_CAN_TDC_TDCF_MIN, /* u32 */
IFLA_CAN_TDC_TDCF_MAX, /* u32 */
IFLA_CAN_TDC_TDCV, /* u32 */
IFLA_CAN_TDC_TDCO, /* u32 */
IFLA_CAN_TDC_TDCF, /* u32 */
/* add new constants above here */
__IFLA_CAN_TDC,
IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1
};
/* u16 termination range: 1..65535 Ohms */ /* u16 termination range: 1..65535 Ohms */
#define CAN_TERMINATION_DISABLED 0 #define CAN_TERMINATION_DISABLED 0
......
...@@ -625,7 +625,7 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer) ...@@ -625,7 +625,7 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
if (bcm_rx_thr_flush(op)) { if (bcm_rx_thr_flush(op)) {
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); hrtimer_forward_now(hrtimer, op->kt_ival2);
return HRTIMER_RESTART; return HRTIMER_RESTART;
} else { } else {
/* rearm throttle handling */ /* rearm throttle handling */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment