can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming
[ Upstream commit 39d3df6b0ea80f9b515c632ca07b39b1c156edee ] 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:080f40a6fa
("can: kvaser_usb: Add support for Kvaser CAN/USB devices") Fixes:aec5fb2268
("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>
This commit is contained in:
parent
7482f95315
commit
a2046e5a36
@ -119,9 +119,12 @@ struct kvaser_usb_net_priv {
|
|||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
int channel;
|
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 usb_anchor tx_submitted;
|
||||||
|
|
||||||
|
struct kvaser_usb_busparams busparams_nominal, busparams_data;
|
||||||
|
|
||||||
spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */
|
spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */
|
||||||
int active_tx_contexts;
|
int active_tx_contexts;
|
||||||
struct kvaser_usb_tx_urb_context tx_contexts[];
|
struct kvaser_usb_tx_urb_context tx_contexts[];
|
||||||
@ -131,7 +134,9 @@ struct kvaser_usb_net_priv {
|
|||||||
* struct kvaser_usb_dev_ops - Device specific functions
|
* struct kvaser_usb_dev_ops - Device specific functions
|
||||||
* @dev_set_mode: used for can.do_set_mode
|
* @dev_set_mode: used for can.do_set_mode
|
||||||
* @dev_set_bittiming: used for can.do_set_bittiming
|
* @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_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_get_berr_counter: used for can.do_get_berr_counter
|
||||||
*
|
*
|
||||||
* @dev_setup_endpoints: setup USB in and out endpoints
|
* @dev_setup_endpoints: setup USB in and out endpoints
|
||||||
@ -153,8 +158,12 @@ struct kvaser_usb_net_priv {
|
|||||||
*/
|
*/
|
||||||
struct kvaser_usb_dev_ops {
|
struct kvaser_usb_dev_ops {
|
||||||
int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode);
|
int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode);
|
||||||
int (*dev_set_bittiming)(struct net_device *netdev);
|
int (*dev_set_bittiming)(const struct net_device *netdev,
|
||||||
int (*dev_set_data_bittiming)(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,
|
int (*dev_get_berr_counter)(const struct net_device *netdev,
|
||||||
struct can_berr_counter *bec);
|
struct can_berr_counter *bec);
|
||||||
int (*dev_setup_endpoints)(struct kvaser_usb *dev);
|
int (*dev_setup_endpoints)(struct kvaser_usb *dev);
|
||||||
|
@ -416,10 +416,6 @@ static int kvaser_usb_open(struct net_device *netdev)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = kvaser_usb_setup_rx_urbs(dev);
|
|
||||||
if (err)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
err = ops->dev_set_opt_mode(priv);
|
err = ops->dev_set_opt_mode(priv);
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
@ -510,6 +506,93 @@ static int kvaser_usb_close(struct net_device *netdev)
|
|||||||
return 0;
|
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)
|
static void kvaser_usb_write_bulk_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct kvaser_usb_tx_urb_context *context = urb->context;
|
struct kvaser_usb_tx_urb_context *context = urb->context;
|
||||||
@ -695,6 +778,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
|||||||
init_completion(&priv->start_comp);
|
init_completion(&priv->start_comp);
|
||||||
init_completion(&priv->stop_comp);
|
init_completion(&priv->stop_comp);
|
||||||
init_completion(&priv->flush_comp);
|
init_completion(&priv->flush_comp);
|
||||||
|
init_completion(&priv->get_busparams_comp);
|
||||||
priv->can.ctrlmode_supported = 0;
|
priv->can.ctrlmode_supported = 0;
|
||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
@ -707,7 +791,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
|||||||
priv->can.state = CAN_STATE_STOPPED;
|
priv->can.state = CAN_STATE_STOPPED;
|
||||||
priv->can.clock.freq = dev->cfg->clock.freq;
|
priv->can.clock.freq = dev->cfg->clock.freq;
|
||||||
priv->can.bittiming_const = dev->cfg->bittiming_const;
|
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;
|
priv->can.do_set_mode = ops->dev_set_mode;
|
||||||
if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
|
if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
|
||||||
(priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
|
(priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
|
||||||
@ -719,7 +803,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
|||||||
|
|
||||||
if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
|
if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
|
||||||
priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
|
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;
|
netdev->flags |= IFF_ECHO;
|
||||||
|
@ -43,6 +43,8 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc;
|
|||||||
|
|
||||||
/* Minihydra command IDs */
|
/* Minihydra command IDs */
|
||||||
#define CMD_SET_BUSPARAMS_REQ 16
|
#define CMD_SET_BUSPARAMS_REQ 16
|
||||||
|
#define CMD_GET_BUSPARAMS_REQ 17
|
||||||
|
#define CMD_GET_BUSPARAMS_RESP 18
|
||||||
#define CMD_GET_CHIP_STATE_REQ 19
|
#define CMD_GET_CHIP_STATE_REQ 19
|
||||||
#define CMD_CHIP_STATE_EVENT 20
|
#define CMD_CHIP_STATE_EVENT 20
|
||||||
#define CMD_SET_DRIVERMODE_REQ 21
|
#define CMD_SET_DRIVERMODE_REQ 21
|
||||||
@ -193,13 +195,26 @@ struct kvaser_cmd_chip_state_event {
|
|||||||
#define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO 0x01
|
#define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO 0x01
|
||||||
#define KVASER_USB_HYDRA_BUS_MODE_NONISO 0x02
|
#define KVASER_USB_HYDRA_BUS_MODE_NONISO 0x02
|
||||||
struct kvaser_cmd_set_busparams {
|
struct kvaser_cmd_set_busparams {
|
||||||
struct kvaser_usb_busparams busparams_arb;
|
struct kvaser_usb_busparams busparams_nominal;
|
||||||
u8 reserved0[4];
|
u8 reserved0[4];
|
||||||
struct kvaser_usb_busparams busparams_data;
|
struct kvaser_usb_busparams busparams_data;
|
||||||
u8 canfd_mode;
|
u8 canfd_mode;
|
||||||
u8 reserved1[7];
|
u8 reserved1[7];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* Busparam type */
|
||||||
|
#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN 0x00
|
||||||
|
#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD 0x01
|
||||||
|
struct kvaser_cmd_get_busparams_req {
|
||||||
|
u8 type;
|
||||||
|
u8 reserved[27];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct kvaser_cmd_get_busparams_res {
|
||||||
|
struct kvaser_usb_busparams busparams;
|
||||||
|
u8 reserved[20];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* Ctrl modes */
|
/* Ctrl modes */
|
||||||
#define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01
|
#define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01
|
||||||
#define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02
|
#define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02
|
||||||
@ -270,6 +285,8 @@ struct kvaser_cmd {
|
|||||||
struct kvaser_cmd_error_event error_event;
|
struct kvaser_cmd_error_event error_event;
|
||||||
|
|
||||||
struct kvaser_cmd_set_busparams set_busparams_req;
|
struct kvaser_cmd_set_busparams set_busparams_req;
|
||||||
|
struct kvaser_cmd_get_busparams_req get_busparams_req;
|
||||||
|
struct kvaser_cmd_get_busparams_res get_busparams_res;
|
||||||
|
|
||||||
struct kvaser_cmd_chip_state_event chip_state_event;
|
struct kvaser_cmd_chip_state_event chip_state_event;
|
||||||
|
|
||||||
@ -352,6 +369,10 @@ struct kvaser_cmd_ext {
|
|||||||
} __packed;
|
} __packed;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct kvaser_usb_net_hydra_priv {
|
||||||
|
int pending_get_busparams_type;
|
||||||
|
};
|
||||||
|
|
||||||
static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
|
static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
|
||||||
.name = "kvaser_usb_kcan",
|
.name = "kvaser_usb_kcan",
|
||||||
.tseg1_min = 1,
|
.tseg1_min = 1,
|
||||||
@ -805,6 +826,39 @@ static void kvaser_usb_hydra_flush_queue_reply(const struct kvaser_usb *dev,
|
|||||||
complete(&priv->flush_comp);
|
complete(&priv->flush_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kvaser_usb_hydra_get_busparams_reply(const struct kvaser_usb *dev,
|
||||||
|
const struct kvaser_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct kvaser_usb_net_priv *priv;
|
||||||
|
struct kvaser_usb_net_hydra_priv *hydra;
|
||||||
|
|
||||||
|
priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
|
||||||
|
if (!priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hydra = priv->sub_priv;
|
||||||
|
if (!hydra)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (hydra->pending_get_busparams_type) {
|
||||||
|
case KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN:
|
||||||
|
memcpy(&priv->busparams_nominal, &cmd->get_busparams_res.busparams,
|
||||||
|
sizeof(priv->busparams_nominal));
|
||||||
|
break;
|
||||||
|
case KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD:
|
||||||
|
memcpy(&priv->busparams_data, &cmd->get_busparams_res.busparams,
|
||||||
|
sizeof(priv->busparams_nominal));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_warn(&dev->intf->dev, "Unknown get_busparams_type %d\n",
|
||||||
|
hydra->pending_get_busparams_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hydra->pending_get_busparams_type = -1;
|
||||||
|
|
||||||
|
complete(&priv->get_busparams_comp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv,
|
kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv,
|
||||||
u8 bus_status,
|
u8 bus_status,
|
||||||
@ -1291,6 +1345,10 @@ static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev,
|
|||||||
kvaser_usb_hydra_state_event(dev, cmd);
|
kvaser_usb_hydra_state_event(dev, cmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CMD_GET_BUSPARAMS_RESP:
|
||||||
|
kvaser_usb_hydra_get_busparams_reply(dev, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
case CMD_ERROR_EVENT:
|
case CMD_ERROR_EVENT:
|
||||||
kvaser_usb_hydra_error_event(dev, cmd);
|
kvaser_usb_hydra_error_event(dev, cmd);
|
||||||
break;
|
break;
|
||||||
@ -1491,15 +1549,58 @@ static int kvaser_usb_hydra_set_mode(struct net_device *netdev,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
|
static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
|
||||||
|
int busparams_type)
|
||||||
|
{
|
||||||
|
struct kvaser_usb *dev = priv->dev;
|
||||||
|
struct kvaser_usb_net_hydra_priv *hydra = priv->sub_priv;
|
||||||
|
struct kvaser_cmd *cmd;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!hydra)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||||
|
if (!cmd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd->header.cmd_no = CMD_GET_BUSPARAMS_REQ;
|
||||||
|
kvaser_usb_hydra_set_cmd_dest_he
|
||||||
|
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
||||||
|
kvaser_usb_hydra_set_cmd_transid
|
||||||
|
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||||
|
cmd->get_busparams_req.type = busparams_type;
|
||||||
|
hydra->pending_get_busparams_type = busparams_type;
|
||||||
|
|
||||||
|
reinit_completion(&priv->get_busparams_comp);
|
||||||
|
|
||||||
|
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!wait_for_completion_timeout(&priv->get_busparams_comp,
|
||||||
|
msecs_to_jiffies(KVASER_USB_TIMEOUT)))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvaser_usb_hydra_get_nominal_busparams(struct kvaser_usb_net_priv *priv)
|
||||||
|
{
|
||||||
|
return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvaser_usb_hydra_get_data_busparams(struct kvaser_usb_net_priv *priv)
|
||||||
|
{
|
||||||
|
return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev,
|
||||||
|
const struct kvaser_usb_busparams *busparams)
|
||||||
{
|
{
|
||||||
struct kvaser_cmd *cmd;
|
struct kvaser_cmd *cmd;
|
||||||
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
||||||
struct can_bittiming *bt = &priv->can.bittiming;
|
|
||||||
struct kvaser_usb *dev = priv->dev;
|
struct kvaser_usb *dev = priv->dev;
|
||||||
int tseg1 = bt->prop_seg + bt->phase_seg1;
|
|
||||||
int tseg2 = bt->phase_seg2;
|
|
||||||
int sjw = bt->sjw;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||||
@ -1507,11 +1608,8 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ;
|
cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ;
|
||||||
cmd->set_busparams_req.busparams_arb.bitrate = cpu_to_le32(bt->bitrate);
|
memcpy(&cmd->set_busparams_req.busparams_nominal, busparams,
|
||||||
cmd->set_busparams_req.busparams_arb.sjw = (u8)sjw;
|
sizeof(cmd->set_busparams_req.busparams_nominal));
|
||||||
cmd->set_busparams_req.busparams_arb.tseg1 = (u8)tseg1;
|
|
||||||
cmd->set_busparams_req.busparams_arb.tseg2 = (u8)tseg2;
|
|
||||||
cmd->set_busparams_req.busparams_arb.nsamples = 1;
|
|
||||||
|
|
||||||
kvaser_usb_hydra_set_cmd_dest_he
|
kvaser_usb_hydra_set_cmd_dest_he
|
||||||
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
||||||
@ -1525,15 +1623,12 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev)
|
static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev,
|
||||||
|
const struct kvaser_usb_busparams *busparams)
|
||||||
{
|
{
|
||||||
struct kvaser_cmd *cmd;
|
struct kvaser_cmd *cmd;
|
||||||
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
||||||
struct can_bittiming *dbt = &priv->can.data_bittiming;
|
|
||||||
struct kvaser_usb *dev = priv->dev;
|
struct kvaser_usb *dev = priv->dev;
|
||||||
int tseg1 = dbt->prop_seg + dbt->phase_seg1;
|
|
||||||
int tseg2 = dbt->phase_seg2;
|
|
||||||
int sjw = dbt->sjw;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||||
@ -1541,11 +1636,8 @@ static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ;
|
cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ;
|
||||||
cmd->set_busparams_req.busparams_data.bitrate = cpu_to_le32(dbt->bitrate);
|
memcpy(&cmd->set_busparams_req.busparams_data, busparams,
|
||||||
cmd->set_busparams_req.busparams_data.sjw = (u8)sjw;
|
sizeof(cmd->set_busparams_req.busparams_data));
|
||||||
cmd->set_busparams_req.busparams_data.tseg1 = (u8)tseg1;
|
|
||||||
cmd->set_busparams_req.busparams_data.tseg2 = (u8)tseg2;
|
|
||||||
cmd->set_busparams_req.busparams_data.nsamples = 1;
|
|
||||||
|
|
||||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
|
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
|
||||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
|
if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
|
||||||
@ -1652,6 +1744,19 @@ static int kvaser_usb_hydra_init_card(struct kvaser_usb *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvaser_usb_hydra_init_channel(struct kvaser_usb_net_priv *priv)
|
||||||
|
{
|
||||||
|
struct kvaser_usb_net_hydra_priv *hydra;
|
||||||
|
|
||||||
|
hydra = devm_kzalloc(&priv->dev->intf->dev, sizeof(*hydra), GFP_KERNEL);
|
||||||
|
if (!hydra)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->sub_priv = hydra;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev)
|
static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev)
|
||||||
{
|
{
|
||||||
struct kvaser_cmd cmd;
|
struct kvaser_cmd cmd;
|
||||||
@ -1994,10 +2099,13 @@ kvaser_usb_hydra_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
|
|||||||
const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = {
|
const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = {
|
||||||
.dev_set_mode = kvaser_usb_hydra_set_mode,
|
.dev_set_mode = kvaser_usb_hydra_set_mode,
|
||||||
.dev_set_bittiming = kvaser_usb_hydra_set_bittiming,
|
.dev_set_bittiming = kvaser_usb_hydra_set_bittiming,
|
||||||
|
.dev_get_busparams = kvaser_usb_hydra_get_nominal_busparams,
|
||||||
.dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming,
|
.dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming,
|
||||||
|
.dev_get_data_busparams = kvaser_usb_hydra_get_data_busparams,
|
||||||
.dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter,
|
.dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter,
|
||||||
.dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints,
|
.dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints,
|
||||||
.dev_init_card = kvaser_usb_hydra_init_card,
|
.dev_init_card = kvaser_usb_hydra_init_card,
|
||||||
|
.dev_init_channel = kvaser_usb_hydra_init_channel,
|
||||||
.dev_get_software_info = kvaser_usb_hydra_get_software_info,
|
.dev_get_software_info = kvaser_usb_hydra_get_software_info,
|
||||||
.dev_get_software_details = kvaser_usb_hydra_get_software_details,
|
.dev_get_software_details = kvaser_usb_hydra_get_software_details,
|
||||||
.dev_get_card_info = kvaser_usb_hydra_get_card_info,
|
.dev_get_card_info = kvaser_usb_hydra_get_card_info,
|
||||||
|
@ -56,6 +56,8 @@
|
|||||||
#define CMD_RX_EXT_MESSAGE 14
|
#define CMD_RX_EXT_MESSAGE 14
|
||||||
#define CMD_TX_EXT_MESSAGE 15
|
#define CMD_TX_EXT_MESSAGE 15
|
||||||
#define CMD_SET_BUS_PARAMS 16
|
#define CMD_SET_BUS_PARAMS 16
|
||||||
|
#define CMD_GET_BUS_PARAMS 17
|
||||||
|
#define CMD_GET_BUS_PARAMS_REPLY 18
|
||||||
#define CMD_GET_CHIP_STATE 19
|
#define CMD_GET_CHIP_STATE 19
|
||||||
#define CMD_CHIP_STATE_EVENT 20
|
#define CMD_CHIP_STATE_EVENT 20
|
||||||
#define CMD_SET_CTRL_MODE 21
|
#define CMD_SET_CTRL_MODE 21
|
||||||
@ -375,6 +377,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
|
|||||||
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
|
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
|
||||||
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event),
|
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event),
|
||||||
[CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
|
[CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
|
||||||
|
[CMD_GET_BUS_PARAMS_REPLY] = kvaser_fsize(u.busparams),
|
||||||
[CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
|
[CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
|
||||||
/* ignored events: */
|
/* ignored events: */
|
||||||
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
|
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
|
||||||
@ -1467,6 +1470,25 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
|
|||||||
complete(&priv->stop_comp);
|
complete(&priv->stop_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
|
||||||
|
const struct kvaser_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct kvaser_usb_net_priv *priv;
|
||||||
|
u8 channel = cmd->u.busparams.channel;
|
||||||
|
|
||||||
|
if (channel >= dev->nchannels) {
|
||||||
|
dev_err(&dev->intf->dev,
|
||||||
|
"Invalid channel number (%d)\n", channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = dev->nets[channel];
|
||||||
|
memcpy(&priv->busparams_nominal, &cmd->u.busparams.busparams,
|
||||||
|
sizeof(priv->busparams_nominal));
|
||||||
|
|
||||||
|
complete(&priv->get_busparams_comp);
|
||||||
|
}
|
||||||
|
|
||||||
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
||||||
const struct kvaser_cmd *cmd)
|
const struct kvaser_cmd *cmd)
|
||||||
{
|
{
|
||||||
@ -1509,6 +1531,10 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
|||||||
kvaser_usb_leaf_error_event(dev, cmd);
|
kvaser_usb_leaf_error_event(dev, cmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CMD_GET_BUS_PARAMS_REPLY:
|
||||||
|
kvaser_usb_leaf_get_busparams_reply(dev, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
/* Ignored commands */
|
/* Ignored commands */
|
||||||
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
|
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
|
||||||
if (dev->driver_info->family != KVASER_USBCAN)
|
if (dev->driver_info->family != KVASER_USBCAN)
|
||||||
@ -1683,10 +1709,10 @@ static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv)
|
|||||||
cancel_delayed_work_sync(&leaf->chip_state_req_work);
|
cancel_delayed_work_sync(&leaf->chip_state_req_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
|
static int kvaser_usb_leaf_set_bittiming(const struct net_device *netdev,
|
||||||
|
const struct kvaser_usb_busparams *busparams)
|
||||||
{
|
{
|
||||||
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
||||||
struct can_bittiming *bt = &priv->can.bittiming;
|
|
||||||
struct kvaser_usb *dev = priv->dev;
|
struct kvaser_usb *dev = priv->dev;
|
||||||
struct kvaser_cmd *cmd;
|
struct kvaser_cmd *cmd;
|
||||||
int rc;
|
int rc;
|
||||||
@ -1699,15 +1725,8 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
|
|||||||
cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams);
|
cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams);
|
||||||
cmd->u.busparams.channel = priv->channel;
|
cmd->u.busparams.channel = priv->channel;
|
||||||
cmd->u.busparams.tid = 0xff;
|
cmd->u.busparams.tid = 0xff;
|
||||||
cmd->u.busparams.busparams.bitrate = cpu_to_le32(bt->bitrate);
|
memcpy(&cmd->u.busparams.busparams, busparams,
|
||||||
cmd->u.busparams.busparams.sjw = bt->sjw;
|
sizeof(cmd->u.busparams.busparams));
|
||||||
cmd->u.busparams.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
|
|
||||||
cmd->u.busparams.busparams.tseg2 = bt->phase_seg2;
|
|
||||||
|
|
||||||
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
|
|
||||||
cmd->u.busparams.busparams.nsamples = 3;
|
|
||||||
else
|
|
||||||
cmd->u.busparams.busparams.nsamples = 1;
|
|
||||||
|
|
||||||
rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
|
rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
|
||||||
|
|
||||||
@ -1715,6 +1734,27 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvaser_usb_leaf_get_busparams(struct kvaser_usb_net_priv *priv)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (priv->dev->driver_info->family == KVASER_USBCAN)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
reinit_completion(&priv->get_busparams_comp);
|
||||||
|
|
||||||
|
err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_GET_BUS_PARAMS,
|
||||||
|
priv->channel);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!wait_for_completion_timeout(&priv->get_busparams_comp,
|
||||||
|
msecs_to_jiffies(KVASER_USB_TIMEOUT)))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
|
static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
|
||||||
enum can_mode mode)
|
enum can_mode mode)
|
||||||
{
|
{
|
||||||
@ -1776,7 +1816,9 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
|
|||||||
const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
|
const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
|
||||||
.dev_set_mode = kvaser_usb_leaf_set_mode,
|
.dev_set_mode = kvaser_usb_leaf_set_mode,
|
||||||
.dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
|
.dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
|
||||||
|
.dev_get_busparams = kvaser_usb_leaf_get_busparams,
|
||||||
.dev_set_data_bittiming = NULL,
|
.dev_set_data_bittiming = NULL,
|
||||||
|
.dev_get_data_busparams = NULL,
|
||||||
.dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
|
.dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
|
||||||
.dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
|
.dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
|
||||||
.dev_init_card = kvaser_usb_leaf_init_card,
|
.dev_init_card = kvaser_usb_leaf_init_card,
|
||||||
|
Loading…
Reference in New Issue
Block a user