Skip to content

Commit

Permalink
can: kvaser_usb: Compare requested bittiming parameters with actual p…
Browse files Browse the repository at this point in the history
…arameters in do_set_{,data}_bittiming

[ Upstream commit 39d3df6 ]

The device will respond with a CMD_ERROR_EVENT command, with error_code
KVASER_USB_{LEAF,HYDRA}_ERROR_EVENT_PARAM, if the CMD_SET_BUSPARAMS_REQ
contains invalid bittiming parameters.
However, this command does not contain any channel reference.

To check if the CMD_SET_BUSPARAMS_REQ was successful, redback and compare
the requested bittiming parameters with the device reported parameters.

Fixes: 080f40a ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Fixes: aec5fb2 ("can: kvaser_usb: Add support for Kvaser USB hydra family")
Tested-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Co-developed-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Signed-off-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://lore.kernel.org/all/20221010185237.319219-12-extja@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Jimmy Assarsson authored and gregkh committed Dec 31, 2022
1 parent 70e91dd commit a8e1423
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 41 deletions.
15 changes: 12 additions & 3 deletions drivers/net/can/usb/kvaser_usb/kvaser_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,12 @@ struct kvaser_usb_net_priv {
struct net_device *netdev;
int channel;

struct completion start_comp, stop_comp, flush_comp;
struct completion start_comp, stop_comp, flush_comp,
get_busparams_comp;
struct usb_anchor tx_submitted;

struct kvaser_usb_busparams busparams_nominal, busparams_data;

spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */
int active_tx_contexts;
struct kvaser_usb_tx_urb_context tx_contexts[];
Expand All @@ -131,7 +134,9 @@ struct kvaser_usb_net_priv {
* struct kvaser_usb_dev_ops - Device specific functions
* @dev_set_mode: used for can.do_set_mode
* @dev_set_bittiming: used for can.do_set_bittiming
* @dev_get_busparams: readback arbitration busparams
* @dev_set_data_bittiming: used for can.do_set_data_bittiming
* @dev_get_data_busparams: readback data busparams
* @dev_get_berr_counter: used for can.do_get_berr_counter
*
* @dev_setup_endpoints: setup USB in and out endpoints
Expand All @@ -153,8 +158,12 @@ struct kvaser_usb_net_priv {
*/
struct kvaser_usb_dev_ops {
int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode);
int (*dev_set_bittiming)(struct net_device *netdev);
int (*dev_set_data_bittiming)(struct net_device *netdev);
int (*dev_set_bittiming)(const struct net_device *netdev,
const struct kvaser_usb_busparams *busparams);
int (*dev_get_busparams)(struct kvaser_usb_net_priv *priv);
int (*dev_set_data_bittiming)(const struct net_device *netdev,
const struct kvaser_usb_busparams *busparams);
int (*dev_get_data_busparams)(struct kvaser_usb_net_priv *priv);
int (*dev_get_berr_counter)(const struct net_device *netdev,
struct can_berr_counter *bec);
int (*dev_setup_endpoints)(struct kvaser_usb *dev);
Expand Down
96 changes: 90 additions & 6 deletions drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,6 @@ static int kvaser_usb_open(struct net_device *netdev)
if (err)
return err;

err = kvaser_usb_setup_rx_urbs(dev);
if (err)
goto error;

err = ops->dev_set_opt_mode(priv);
if (err)
goto error;
Expand Down Expand Up @@ -534,6 +530,93 @@ static int kvaser_usb_close(struct net_device *netdev)
return 0;
}

static int kvaser_usb_set_bittiming(struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
struct kvaser_usb *dev = priv->dev;
const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
struct can_bittiming *bt = &priv->can.bittiming;

struct kvaser_usb_busparams busparams;
int tseg1 = bt->prop_seg + bt->phase_seg1;
int tseg2 = bt->phase_seg2;
int sjw = bt->sjw;
int err = -EOPNOTSUPP;

busparams.bitrate = cpu_to_le32(bt->bitrate);
busparams.sjw = (u8)sjw;
busparams.tseg1 = (u8)tseg1;
busparams.tseg2 = (u8)tseg2;
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
busparams.nsamples = 3;
else
busparams.nsamples = 1;

err = ops->dev_set_bittiming(netdev, &busparams);
if (err)
return err;

err = kvaser_usb_setup_rx_urbs(priv->dev);
if (err)
return err;

err = ops->dev_get_busparams(priv);
if (err) {
/* Treat EOPNOTSUPP as success */
if (err == -EOPNOTSUPP)
err = 0;
return err;
}

if (memcmp(&busparams, &priv->busparams_nominal,
sizeof(priv->busparams_nominal)) != 0)
err = -EINVAL;

return err;
}

static int kvaser_usb_set_data_bittiming(struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
struct kvaser_usb *dev = priv->dev;
const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
struct can_bittiming *dbt = &priv->can.data_bittiming;

struct kvaser_usb_busparams busparams;
int tseg1 = dbt->prop_seg + dbt->phase_seg1;
int tseg2 = dbt->phase_seg2;
int sjw = dbt->sjw;
int err;

if (!ops->dev_set_data_bittiming ||
!ops->dev_get_data_busparams)
return -EOPNOTSUPP;

busparams.bitrate = cpu_to_le32(dbt->bitrate);
busparams.sjw = (u8)sjw;
busparams.tseg1 = (u8)tseg1;
busparams.tseg2 = (u8)tseg2;
busparams.nsamples = 1;

err = ops->dev_set_data_bittiming(netdev, &busparams);
if (err)
return err;

err = kvaser_usb_setup_rx_urbs(priv->dev);
if (err)
return err;

err = ops->dev_get_data_busparams(priv);
if (err)
return err;

if (memcmp(&busparams, &priv->busparams_data,
sizeof(priv->busparams_data)) != 0)
err = -EINVAL;

return err;
}

static void kvaser_usb_write_bulk_callback(struct urb *urb)
{
struct kvaser_usb_tx_urb_context *context = urb->context;
Expand Down Expand Up @@ -734,6 +817,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
init_completion(&priv->start_comp);
init_completion(&priv->stop_comp);
init_completion(&priv->flush_comp);
init_completion(&priv->get_busparams_comp);
priv->can.ctrlmode_supported = 0;

priv->dev = dev;
Expand All @@ -746,7 +830,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
priv->can.state = CAN_STATE_STOPPED;
priv->can.clock.freq = dev->cfg->clock.freq;
priv->can.bittiming_const = dev->cfg->bittiming_const;
priv->can.do_set_bittiming = ops->dev_set_bittiming;
priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
priv->can.do_set_mode = ops->dev_set_mode;
if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
(priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
Expand All @@ -758,7 +842,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)

if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
priv->can.do_set_data_bittiming = kvaser_usb_set_data_bittiming;
}

netdev->flags |= IFF_ECHO;
Expand Down

0 comments on commit a8e1423

Please sign in to comment.