linux-can-fixes-for-5.19-20220704
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEBsvAIBsPu6mG7thcrX5LkNig010FAmLCxswTHG1rbEBwZW5n dXRyb25peC5kZQAKCRCtfkuQ2KDTXR27B/oDW8Z5VKdextQ5vrBmZM0Qo2FhY9Mj fvK+6wzjYYlIXwXonc420CcRldEwlIgGrr41jr27gd04MTz82v12FQh/4je08wlJ WZ/Vhn4AX7HSnNysEOakpEr/LKlm19vWsq0Z9KJpt9JGYKNxzJirvGHYNUop4erC wXEHm31qRnll06I/38FMVUhSiY0K2ZfJRtWX0zopH3Jj7mwcDT8UaGXApEkhUvdS 7JRLsTmMGwAUsYuaoYl+VR186avBpvLHgkYTbZKBvQASd4DZY4LSqBJTpIcbB621 UK8bKIKmhSWOSyU/gnOjD86sacDcyvuKRuLUxYFuGKPyvtuiTYcXRVp9 =Qgal -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-5.19-20220704' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== can 2022-07-04 The 1st patch is by Oliver Hartkopp, targets the BCM CAN protocol and converts a costly synchronize_rcu() to call_rcu() to fix a performance regression. Srinivas Neeli's patch for the xilinx_can driver drops the brp limit down to 1, as only the pre-production silicon have an issue with a brp of 1. The next patch is by Duy Nguyen and fixes the data transmission on R-Car V3U SoCs in the rcar_canfd driver. Rhett Aultman's patch fixes a DMA memory leak in the gs_usb driver. Liang He's patch removes an extra of_node_get() in the grcan driver. The next 2 patches are by me, target the m_can driver and fix the timestamp handling used for peripheral devices like the tcan4x5x. Jimmy Assarsson contributes 3 patches for the kvaser_usb driver and fixes CAN clock and bit timing related issues. The remaining 5 patches target the mcp251xfd driver. Thomas Kopp contributes 2 patches to improve the workaround for broken CRC when reading the TBC register. 3 patches by me add a missing hrtimer_cancel() during the ndo_stop() callback, and fix the reading of the Device ID register. * tag 'linux-can-fixes-for-5.19-20220704' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: mcp251xfd: mcp251xfd_register_get_dev_id(): fix endianness conversion can: mcp251xfd: mcp251xfd_register_get_dev_id(): use correct length to read dev_id can: mcp251xfd: mcp251xfd_stop(): add missing hrtimer_cancel() can: mcp251xfd: mcp251xfd_regmap_crc_read(): update workaround broken CRC on TBC register can: mcp251xfd: mcp251xfd_regmap_crc_read(): improve workaround handling for mcp2517fd can: kvaser_usb: kvaser_usb_leaf: fix bittiming limits can: kvaser_usb: kvaser_usb_leaf: fix CAN clock frequency regression can: kvaser_usb: replace run-time checks with struct kvaser_usb_driver_info can: m_can: m_can_{read_fifo,echo_tx_event}(): shift timestamp to full 32 bits can: m_can: m_can_chip_config(): actually enable internal timestamping can: grcan: grcan_probe(): remove extra of_node_get() can: gs_usb: gs_usb_open/close(): fix memory leak can: rcar_canfd: Fix data transmission failed on R-Car V3U Revert "can: xilinx_can: Limit CANFD brp to 2" can: bcm: use call_rcu() instead of costly synchronize_rcu() ==================== Link: https://lore.kernel.org/r/20220704122613.1551119-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7e8c182c36
@ -1646,7 +1646,6 @@ static int grcan_probe(struct platform_device *ofdev)
|
||||
*/
|
||||
sysid_parent = of_find_node_by_path("/ambapp0");
|
||||
if (sysid_parent) {
|
||||
of_node_get(sysid_parent);
|
||||
err = of_property_read_u32(sysid_parent, "systemid", &sysid);
|
||||
if (!err && ((sysid & GRLIB_VERSION_MASK) >=
|
||||
GRCAN_TXBUG_SAFE_GRLIB_VERSION))
|
||||
|
@ -529,7 +529,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
|
||||
/* acknowledge rx fifo 0 */
|
||||
m_can_write(cdev, M_CAN_RXF0A, fgi);
|
||||
|
||||
timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
|
||||
timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
|
||||
|
||||
m_can_receive_skb(cdev, skb, timestamp);
|
||||
|
||||
@ -1030,7 +1030,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
|
||||
}
|
||||
|
||||
msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
|
||||
timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
|
||||
timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
|
||||
|
||||
/* ack txe element */
|
||||
m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
|
||||
@ -1351,7 +1351,9 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
/* enable internal timestamp generation, with a prescalar of 16. The
|
||||
* prescalar is applied to the nominal bit timing
|
||||
*/
|
||||
m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
|
||||
m_can_write(cdev, M_CAN_TSCC,
|
||||
FIELD_PREP(TSCC_TCP_MASK, 0xf) |
|
||||
FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
|
||||
|
||||
m_can_config_endisable(cdev, false);
|
||||
|
||||
|
@ -1332,7 +1332,10 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
|
||||
cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) |
|
||||
RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
|
||||
|
||||
rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
|
||||
if (is_v3u(gpriv))
|
||||
rcar_canfd_write(priv->base, RCANFD_V3U_DCFG(ch), cfg);
|
||||
else
|
||||
rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
|
||||
netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
|
||||
brp, sjw, tseg1, tseg2);
|
||||
} else {
|
||||
|
@ -12,6 +12,7 @@
|
||||
// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
|
||||
//
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
@ -1650,6 +1651,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
|
||||
netif_stop_queue(ndev);
|
||||
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
|
||||
hrtimer_cancel(&priv->rx_irq_timer);
|
||||
hrtimer_cancel(&priv->tx_irq_timer);
|
||||
mcp251xfd_chip_interrupts_disable(priv);
|
||||
free_irq(ndev->irq, priv);
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
@ -1777,7 +1779,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
|
||||
xfer[0].len = sizeof(buf_tx->cmd);
|
||||
xfer[0].speed_hz = priv->spi_max_speed_hz_slow;
|
||||
xfer[1].rx_buf = buf_rx->data;
|
||||
xfer[1].len = sizeof(dev_id);
|
||||
xfer[1].len = sizeof(*dev_id);
|
||||
xfer[1].speed_hz = priv->spi_max_speed_hz_fast;
|
||||
|
||||
mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID);
|
||||
@ -1786,7 +1788,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
|
||||
if (err)
|
||||
goto out_kfree_buf_tx;
|
||||
|
||||
*dev_id = be32_to_cpup((__be32 *)buf_rx->data);
|
||||
*dev_id = get_unaligned_le32(buf_rx->data);
|
||||
*effective_speed_hz_slow = xfer[0].effective_speed_hz;
|
||||
*effective_speed_hz_fast = xfer[1].effective_speed_hz;
|
||||
|
||||
|
@ -334,19 +334,21 @@ mcp251xfd_regmap_crc_read(void *context,
|
||||
* register. It increments once per SYS clock tick,
|
||||
* which is 20 or 40 MHz.
|
||||
*
|
||||
* Observation shows that if the lowest byte (which is
|
||||
* transferred first on the SPI bus) of that register
|
||||
* is 0x00 or 0x80 the calculated CRC doesn't always
|
||||
* match the transferred one.
|
||||
* Observation on the mcp2518fd shows that if the
|
||||
* lowest byte (which is transferred first on the SPI
|
||||
* bus) of that register is 0x00 or 0x80 the
|
||||
* calculated CRC doesn't always match the transferred
|
||||
* one. On the mcp2517fd this problem is not limited
|
||||
* to the first byte being 0x00 or 0x80.
|
||||
*
|
||||
* If the highest bit in the lowest byte is flipped
|
||||
* the transferred CRC matches the calculated one. We
|
||||
* assume for now the CRC calculation in the chip
|
||||
* works on wrong data and the transferred data is
|
||||
* correct.
|
||||
* assume for now the CRC operates on the correct
|
||||
* data.
|
||||
*/
|
||||
if (reg == MCP251XFD_REG_TBC &&
|
||||
(buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
|
||||
((buf_rx->data[0] & 0xf8) == 0x0 ||
|
||||
(buf_rx->data[0] & 0xf8) == 0x80)) {
|
||||
/* Flip highest bit in lowest byte of le32 */
|
||||
buf_rx->data[0] ^= 0x80;
|
||||
|
||||
@ -356,10 +358,8 @@ mcp251xfd_regmap_crc_read(void *context,
|
||||
val_len);
|
||||
if (!err) {
|
||||
/* If CRC is now correct, assume
|
||||
* transferred data was OK, flip bit
|
||||
* back to original value.
|
||||
* flipped data is OK.
|
||||
*/
|
||||
buf_rx->data[0] ^= 0x80;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -268,6 +268,8 @@ struct gs_can {
|
||||
|
||||
struct usb_anchor tx_submitted;
|
||||
atomic_t active_tx_urbs;
|
||||
void *rxbuf[GS_MAX_RX_URBS];
|
||||
dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
|
||||
};
|
||||
|
||||
/* usb interface struct */
|
||||
@ -742,6 +744,7 @@ static int gs_can_open(struct net_device *netdev)
|
||||
for (i = 0; i < GS_MAX_RX_URBS; i++) {
|
||||
struct urb *urb;
|
||||
u8 *buf;
|
||||
dma_addr_t buf_dma;
|
||||
|
||||
/* alloc rx urb */
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
@ -752,7 +755,7 @@ static int gs_can_open(struct net_device *netdev)
|
||||
buf = usb_alloc_coherent(dev->udev,
|
||||
dev->parent->hf_size_rx,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
&buf_dma);
|
||||
if (!buf) {
|
||||
netdev_err(netdev,
|
||||
"No memory left for USB buffer\n");
|
||||
@ -760,6 +763,8 @@ static int gs_can_open(struct net_device *netdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb->transfer_dma = buf_dma;
|
||||
|
||||
/* fill, anchor, and submit rx urb */
|
||||
usb_fill_bulk_urb(urb,
|
||||
dev->udev,
|
||||
@ -781,10 +786,17 @@ static int gs_can_open(struct net_device *netdev)
|
||||
"usb_submit failed (err=%d)\n", rc);
|
||||
|
||||
usb_unanchor_urb(urb);
|
||||
usb_free_coherent(dev->udev,
|
||||
sizeof(struct gs_host_frame),
|
||||
buf,
|
||||
buf_dma);
|
||||
usb_free_urb(urb);
|
||||
break;
|
||||
}
|
||||
|
||||
dev->rxbuf[i] = buf;
|
||||
dev->rxbuf_dma[i] = buf_dma;
|
||||
|
||||
/* Drop reference,
|
||||
* USB core will take care of freeing it
|
||||
*/
|
||||
@ -842,13 +854,20 @@ static int gs_can_close(struct net_device *netdev)
|
||||
int rc;
|
||||
struct gs_can *dev = netdev_priv(netdev);
|
||||
struct gs_usb *parent = dev->parent;
|
||||
unsigned int i;
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
/* Stop polling */
|
||||
parent->active_channels--;
|
||||
if (!parent->active_channels)
|
||||
if (!parent->active_channels) {
|
||||
usb_kill_anchored_urbs(&parent->rx_submitted);
|
||||
for (i = 0; i < GS_MAX_RX_URBS; i++)
|
||||
usb_free_coherent(dev->udev,
|
||||
sizeof(struct gs_host_frame),
|
||||
dev->rxbuf[i],
|
||||
dev->rxbuf_dma[i]);
|
||||
}
|
||||
|
||||
/* Stop sending URBs */
|
||||
usb_kill_anchored_urbs(&dev->tx_submitted);
|
||||
|
@ -35,9 +35,10 @@
|
||||
#define KVASER_USB_RX_BUFFER_SIZE 3072
|
||||
#define KVASER_USB_MAX_NET_DEVICES 5
|
||||
|
||||
/* USB devices features */
|
||||
#define KVASER_USB_HAS_SILENT_MODE BIT(0)
|
||||
#define KVASER_USB_HAS_TXRX_ERRORS BIT(1)
|
||||
/* Kvaser USB device quirks */
|
||||
#define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0)
|
||||
#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1)
|
||||
#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2)
|
||||
|
||||
/* Device capabilities */
|
||||
#define KVASER_USB_CAP_BERR_CAP 0x01
|
||||
@ -65,12 +66,7 @@ struct kvaser_usb_dev_card_data_hydra {
|
||||
struct kvaser_usb_dev_card_data {
|
||||
u32 ctrlmode_supported;
|
||||
u32 capabilities;
|
||||
union {
|
||||
struct {
|
||||
enum kvaser_usb_leaf_family family;
|
||||
} leaf;
|
||||
struct kvaser_usb_dev_card_data_hydra hydra;
|
||||
};
|
||||
struct kvaser_usb_dev_card_data_hydra hydra;
|
||||
};
|
||||
|
||||
/* Context for an outstanding, not yet ACKed, transmission */
|
||||
@ -83,7 +79,7 @@ struct kvaser_usb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
|
||||
const struct kvaser_usb_dev_ops *ops;
|
||||
const struct kvaser_usb_driver_info *driver_info;
|
||||
const struct kvaser_usb_dev_cfg *cfg;
|
||||
|
||||
struct usb_endpoint_descriptor *bulk_in, *bulk_out;
|
||||
@ -165,6 +161,12 @@ struct kvaser_usb_dev_ops {
|
||||
u16 transid);
|
||||
};
|
||||
|
||||
struct kvaser_usb_driver_info {
|
||||
u32 quirks;
|
||||
enum kvaser_usb_leaf_family family;
|
||||
const struct kvaser_usb_dev_ops *ops;
|
||||
};
|
||||
|
||||
struct kvaser_usb_dev_cfg {
|
||||
const struct can_clock clock;
|
||||
const unsigned int timestamp_freq;
|
||||
@ -184,4 +186,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
|
||||
int len);
|
||||
|
||||
int kvaser_usb_can_rx_over_error(struct net_device *netdev);
|
||||
|
||||
extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
|
||||
|
||||
#endif /* KVASER_USB_H */
|
||||
|
@ -61,8 +61,6 @@
|
||||
#define USB_USBCAN_R_V2_PRODUCT_ID 294
|
||||
#define USB_LEAF_LIGHT_R_V2_PRODUCT_ID 295
|
||||
#define USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID 296
|
||||
#define USB_LEAF_PRODUCT_ID_END \
|
||||
USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID
|
||||
|
||||
/* Kvaser USBCan-II devices product ids */
|
||||
#define USB_USBCAN_REVB_PRODUCT_ID 2
|
||||
@ -89,116 +87,153 @@
|
||||
#define USB_USBCAN_PRO_4HS_PRODUCT_ID 276
|
||||
#define USB_HYBRID_CANLIN_PRODUCT_ID 277
|
||||
#define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278
|
||||
#define USB_HYDRA_PRODUCT_ID_END \
|
||||
USB_HYBRID_PRO_CANLIN_PRODUCT_ID
|
||||
|
||||
static inline bool kvaser_is_leaf(const struct usb_device_id *id)
|
||||
{
|
||||
return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
|
||||
id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
|
||||
(id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
|
||||
id->idProduct <= USB_LEAF_PRODUCT_ID_END);
|
||||
}
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
|
||||
.quirks = 0,
|
||||
.ops = &kvaser_usb_hydra_dev_ops,
|
||||
};
|
||||
|
||||
static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
|
||||
{
|
||||
return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
|
||||
id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
|
||||
}
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
|
||||
.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_QUIRK_HAS_SILENT_MODE,
|
||||
.family = KVASER_USBCAN,
|
||||
.ops = &kvaser_usb_leaf_dev_ops,
|
||||
};
|
||||
|
||||
static inline bool kvaser_is_hydra(const struct usb_device_id *id)
|
||||
{
|
||||
return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
|
||||
id->idProduct <= USB_HYDRA_PRODUCT_ID_END;
|
||||
}
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
|
||||
.quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
|
||||
.family = KVASER_LEAF,
|
||||
.ops = &kvaser_usb_leaf_dev_ops,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
|
||||
.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
|
||||
.family = KVASER_LEAF,
|
||||
.ops = &kvaser_usb_leaf_dev_ops,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
|
||||
.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_QUIRK_HAS_SILENT_MODE |
|
||||
KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
|
||||
.family = KVASER_LEAF,
|
||||
.ops = &kvaser_usb_leaf_dev_ops,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
|
||||
.quirks = 0,
|
||||
.ops = &kvaser_usb_leaf_dev_ops,
|
||||
};
|
||||
|
||||
static const struct usb_device_id kvaser_usb_table[] = {
|
||||
/* Leaf USB product IDs */
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
|
||||
/* Leaf M32C USB product IDs */
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
|
||||
KVASER_USB_HAS_SILENT_MODE },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
|
||||
|
||||
/* Leaf i.MX28 USB product IDs */
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
|
||||
|
||||
/* USBCANII USB product IDs */
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
|
||||
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
|
||||
|
||||
/* Minihydra USB product IDs */
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
|
||||
.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
|
||||
@ -285,6 +320,7 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev)
|
||||
static void kvaser_usb_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct kvaser_usb *dev = urb->context;
|
||||
const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
|
||||
int err;
|
||||
unsigned int i;
|
||||
|
||||
@ -301,8 +337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
|
||||
goto resubmit_urb;
|
||||
}
|
||||
|
||||
dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
|
||||
resubmit_urb:
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
@ -396,6 +432,7 @@ static int kvaser_usb_open(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;
|
||||
int err;
|
||||
|
||||
err = open_candev(netdev);
|
||||
@ -406,11 +443,11 @@ static int kvaser_usb_open(struct net_device *netdev)
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
err = dev->ops->dev_set_opt_mode(priv);
|
||||
err = ops->dev_set_opt_mode(priv);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
err = dev->ops->dev_start_chip(priv);
|
||||
err = ops->dev_start_chip(priv);
|
||||
if (err) {
|
||||
netdev_warn(netdev, "Cannot start device, error %d\n", err);
|
||||
goto error;
|
||||
@ -467,22 +504,23 @@ static int kvaser_usb_close(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;
|
||||
int err;
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
err = dev->ops->dev_flush_queue(priv);
|
||||
err = ops->dev_flush_queue(priv);
|
||||
if (err)
|
||||
netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
|
||||
|
||||
if (dev->ops->dev_reset_chip) {
|
||||
err = dev->ops->dev_reset_chip(dev, priv->channel);
|
||||
if (ops->dev_reset_chip) {
|
||||
err = ops->dev_reset_chip(dev, priv->channel);
|
||||
if (err)
|
||||
netdev_warn(netdev, "Cannot reset card, error %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
err = dev->ops->dev_stop_chip(priv);
|
||||
err = ops->dev_stop_chip(priv);
|
||||
if (err)
|
||||
netdev_warn(netdev, "Cannot stop device, error %d\n", err);
|
||||
|
||||
@ -521,6 +559,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
||||
{
|
||||
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 net_device_stats *stats = &netdev->stats;
|
||||
struct kvaser_usb_tx_urb_context *context = NULL;
|
||||
struct urb *urb;
|
||||
@ -563,8 +602,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
||||
goto freeurb;
|
||||
}
|
||||
|
||||
buf = dev->ops->dev_frame_to_cmd(priv, skb, &cmd_len,
|
||||
context->echo_index);
|
||||
buf = ops->dev_frame_to_cmd(priv, skb, &cmd_len, context->echo_index);
|
||||
if (!buf) {
|
||||
stats->tx_dropped++;
|
||||
dev_kfree_skb(skb);
|
||||
@ -648,15 +686,16 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int kvaser_usb_init_one(struct kvaser_usb *dev,
|
||||
const struct usb_device_id *id, int channel)
|
||||
static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
||||
{
|
||||
struct net_device *netdev;
|
||||
struct kvaser_usb_net_priv *priv;
|
||||
const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
|
||||
const struct kvaser_usb_dev_ops *ops = driver_info->ops;
|
||||
int err;
|
||||
|
||||
if (dev->ops->dev_reset_chip) {
|
||||
err = dev->ops->dev_reset_chip(dev, channel);
|
||||
if (ops->dev_reset_chip) {
|
||||
err = ops->dev_reset_chip(dev, channel);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -685,20 +724,19 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
|
||||
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 = dev->ops->dev_set_bittiming;
|
||||
priv->can.do_set_mode = dev->ops->dev_set_mode;
|
||||
if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
|
||||
priv->can.do_set_bittiming = ops->dev_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))
|
||||
priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
|
||||
if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
|
||||
priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
|
||||
if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
|
||||
|
||||
priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
|
||||
|
||||
if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
|
||||
priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
|
||||
priv->can.do_set_data_bittiming =
|
||||
dev->ops->dev_set_data_bittiming;
|
||||
priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
|
||||
}
|
||||
|
||||
netdev->flags |= IFF_ECHO;
|
||||
@ -729,29 +767,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
|
||||
struct kvaser_usb *dev;
|
||||
int err;
|
||||
int i;
|
||||
const struct kvaser_usb_driver_info *driver_info;
|
||||
const struct kvaser_usb_dev_ops *ops;
|
||||
|
||||
driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
|
||||
if (!driver_info)
|
||||
return -ENODEV;
|
||||
|
||||
dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (kvaser_is_leaf(id)) {
|
||||
dev->card_data.leaf.family = KVASER_LEAF;
|
||||
dev->ops = &kvaser_usb_leaf_dev_ops;
|
||||
} else if (kvaser_is_usbcan(id)) {
|
||||
dev->card_data.leaf.family = KVASER_USBCAN;
|
||||
dev->ops = &kvaser_usb_leaf_dev_ops;
|
||||
} else if (kvaser_is_hydra(id)) {
|
||||
dev->ops = &kvaser_usb_hydra_dev_ops;
|
||||
} else {
|
||||
dev_err(&intf->dev,
|
||||
"Product ID (%d) is not a supported Kvaser USB device\n",
|
||||
id->idProduct);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev->intf = intf;
|
||||
dev->driver_info = driver_info;
|
||||
ops = driver_info->ops;
|
||||
|
||||
err = dev->ops->dev_setup_endpoints(dev);
|
||||
err = ops->dev_setup_endpoints(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev, "Cannot get usb endpoint(s)");
|
||||
return err;
|
||||
@ -765,22 +796,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
|
||||
|
||||
dev->card_data.ctrlmode_supported = 0;
|
||||
dev->card_data.capabilities = 0;
|
||||
err = dev->ops->dev_init_card(dev);
|
||||
err = ops->dev_init_card(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev,
|
||||
"Failed to initialize card, error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dev->ops->dev_get_software_info(dev);
|
||||
err = ops->dev_get_software_info(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev,
|
||||
"Cannot get software info, error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dev->ops->dev_get_software_details) {
|
||||
err = dev->ops->dev_get_software_details(dev);
|
||||
if (ops->dev_get_software_details) {
|
||||
err = ops->dev_get_software_details(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev,
|
||||
"Cannot get software details, error %d\n", err);
|
||||
@ -798,14 +829,14 @@ static int kvaser_usb_probe(struct usb_interface *intf,
|
||||
|
||||
dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
|
||||
|
||||
err = dev->ops->dev_get_card_info(dev);
|
||||
err = ops->dev_get_card_info(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dev->ops->dev_get_capabilities) {
|
||||
err = dev->ops->dev_get_capabilities(dev);
|
||||
if (ops->dev_get_capabilities) {
|
||||
err = ops->dev_get_capabilities(dev);
|
||||
if (err) {
|
||||
dev_err(&intf->dev,
|
||||
"Cannot get capabilities, error %d\n", err);
|
||||
@ -815,7 +846,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->nchannels; i++) {
|
||||
err = kvaser_usb_init_one(dev, id, i);
|
||||
err = kvaser_usb_init_one(dev, i);
|
||||
if (err) {
|
||||
kvaser_usb_remove_interfaces(dev);
|
||||
return err;
|
||||
|
@ -375,7 +375,7 @@ static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
|
||||
const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
|
||||
.name = "kvaser_usb_flex",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
@ -2052,7 +2052,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = {
|
||||
.freq = 24 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt = {
|
||||
|
@ -101,16 +101,6 @@
|
||||
#define USBCAN_ERROR_STATE_RX_ERROR BIT(1)
|
||||
#define USBCAN_ERROR_STATE_BUSERROR BIT(2)
|
||||
|
||||
/* bittiming parameters */
|
||||
#define KVASER_USB_TSEG1_MIN 1
|
||||
#define KVASER_USB_TSEG1_MAX 16
|
||||
#define KVASER_USB_TSEG2_MIN 1
|
||||
#define KVASER_USB_TSEG2_MAX 8
|
||||
#define KVASER_USB_SJW_MAX 4
|
||||
#define KVASER_USB_BRP_MIN 1
|
||||
#define KVASER_USB_BRP_MAX 64
|
||||
#define KVASER_USB_BRP_INC 1
|
||||
|
||||
/* ctrl modes */
|
||||
#define KVASER_CTRL_MODE_NORMAL 1
|
||||
#define KVASER_CTRL_MODE_SILENT 2
|
||||
@ -343,48 +333,68 @@ struct kvaser_usb_err_summary {
|
||||
};
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
|
||||
.name = "kvaser_usb",
|
||||
.tseg1_min = KVASER_USB_TSEG1_MIN,
|
||||
.tseg1_max = KVASER_USB_TSEG1_MAX,
|
||||
.tseg2_min = KVASER_USB_TSEG2_MIN,
|
||||
.tseg2_max = KVASER_USB_TSEG2_MAX,
|
||||
.sjw_max = KVASER_USB_SJW_MAX,
|
||||
.brp_min = KVASER_USB_BRP_MIN,
|
||||
.brp_max = KVASER_USB_BRP_MAX,
|
||||
.brp_inc = KVASER_USB_BRP_INC,
|
||||
static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
|
||||
.name = "kvaser_usb_ucii",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 16,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
|
||||
static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
|
||||
.name = "kvaser_usb_leaf",
|
||||
.tseg1_min = 3,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 2,
|
||||
.brp_max = 128,
|
||||
.brp_inc = 2,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
|
||||
.clock = {
|
||||
.freq = 8 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_leaf_bittiming_const,
|
||||
.bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_leaf_bittiming_const,
|
||||
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
|
||||
.clock = {
|
||||
.freq = 24 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_leaf_bittiming_const,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
|
||||
.clock = {
|
||||
.freq = 32 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.bittiming_const = &kvaser_usb_leaf_bittiming_const,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
static void *
|
||||
@ -404,7 +414,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
|
||||
sizeof(struct kvaser_cmd_tx_can);
|
||||
cmd->u.tx_can.channel = priv->channel;
|
||||
|
||||
switch (dev->card_data.leaf.family) {
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
|
||||
break;
|
||||
@ -524,16 +534,23 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
|
||||
dev->fw_version = le32_to_cpu(softinfo->fw_version);
|
||||
dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
|
||||
|
||||
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
|
||||
break;
|
||||
if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
|
||||
/* Firmware expects bittiming parameters calculated for 16MHz
|
||||
* clock, regardless of the actual clock
|
||||
*/
|
||||
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
|
||||
} else {
|
||||
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,7 +567,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (dev->card_data.leaf.family) {
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
|
||||
break;
|
||||
@ -558,7 +575,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
|
||||
dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
|
||||
dev->max_tx_urbs =
|
||||
le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
|
||||
dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
|
||||
dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -597,7 +614,7 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
|
||||
|
||||
dev->nchannels = cmd.u.cardinfo.nchannels;
|
||||
if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
|
||||
(dev->card_data.leaf.family == KVASER_USBCAN &&
|
||||
(dev->driver_info->family == KVASER_USBCAN &&
|
||||
dev->nchannels > MAX_USBCAN_NET_DEVICES))
|
||||
return -EINVAL;
|
||||
|
||||
@ -730,7 +747,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
|
||||
new_state < CAN_STATE_BUS_OFF)
|
||||
priv->can.can_stats.restarts++;
|
||||
|
||||
switch (dev->card_data.leaf.family) {
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
if (es->leaf.error_factor) {
|
||||
priv->can.can_stats.bus_error++;
|
||||
@ -809,7 +826,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
|
||||
}
|
||||
}
|
||||
|
||||
switch (dev->card_data.leaf.family) {
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
if (es->leaf.error_factor) {
|
||||
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
|
||||
@ -999,7 +1016,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
stats = &priv->netdev->stats;
|
||||
|
||||
if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
|
||||
(dev->card_data.leaf.family == KVASER_LEAF &&
|
||||
(dev->driver_info->family == KVASER_LEAF &&
|
||||
cmd->id == CMD_LEAF_LOG_MESSAGE)) {
|
||||
kvaser_usb_leaf_leaf_rx_error(dev, cmd);
|
||||
return;
|
||||
@ -1015,7 +1032,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->card_data.leaf.family) {
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
rx_data = cmd->u.leaf.rx_can.data;
|
||||
break;
|
||||
@ -1030,7 +1047,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
|
||||
if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
|
||||
CMD_LEAF_LOG_MESSAGE) {
|
||||
cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
|
||||
if (cf->can_id & KVASER_EXTENDED_FRAME)
|
||||
@ -1128,14 +1145,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
||||
break;
|
||||
|
||||
case CMD_LEAF_LOG_MESSAGE:
|
||||
if (dev->card_data.leaf.family != KVASER_LEAF)
|
||||
if (dev->driver_info->family != KVASER_LEAF)
|
||||
goto warn;
|
||||
kvaser_usb_leaf_rx_can_msg(dev, cmd);
|
||||
break;
|
||||
|
||||
case CMD_CHIP_STATE_EVENT:
|
||||
case CMD_CAN_ERROR_EVENT:
|
||||
if (dev->card_data.leaf.family == KVASER_LEAF)
|
||||
if (dev->driver_info->family == KVASER_LEAF)
|
||||
kvaser_usb_leaf_leaf_rx_error(dev, cmd);
|
||||
else
|
||||
kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
|
||||
@ -1147,12 +1164,12 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
||||
|
||||
/* Ignored commands */
|
||||
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
|
||||
if (dev->card_data.leaf.family != KVASER_USBCAN)
|
||||
if (dev->driver_info->family != KVASER_USBCAN)
|
||||
goto warn;
|
||||
break;
|
||||
|
||||
case CMD_FLUSH_QUEUE_REPLY:
|
||||
if (dev->card_data.leaf.family != KVASER_LEAF)
|
||||
if (dev->driver_info->family != KVASER_LEAF)
|
||||
goto warn;
|
||||
break;
|
||||
|
||||
|
@ -258,7 +258,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 128,
|
||||
.sjw_max = 128,
|
||||
.brp_min = 2,
|
||||
.brp_min = 1,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
@ -271,7 +271,7 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 16,
|
||||
.sjw_max = 16,
|
||||
.brp_min = 2,
|
||||
.brp_min = 1,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
|
||||
|
||||
struct bcm_op {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
int ifindex;
|
||||
canid_t can_id;
|
||||
u32 flags;
|
||||
@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bcm_remove_op(struct bcm_op *op)
|
||||
static void bcm_free_op_rcu(struct rcu_head *rcu_head)
|
||||
{
|
||||
hrtimer_cancel(&op->timer);
|
||||
hrtimer_cancel(&op->thrtimer);
|
||||
struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
|
||||
|
||||
if ((op->frames) && (op->frames != &op->sframe))
|
||||
kfree(op->frames);
|
||||
@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op)
|
||||
kfree(op);
|
||||
}
|
||||
|
||||
static void bcm_remove_op(struct bcm_op *op)
|
||||
{
|
||||
hrtimer_cancel(&op->timer);
|
||||
hrtimer_cancel(&op->thrtimer);
|
||||
|
||||
call_rcu(&op->rcu, bcm_free_op_rcu);
|
||||
}
|
||||
|
||||
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
|
||||
{
|
||||
if (op->rx_reg_dev == dev) {
|
||||
@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
|
||||
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
|
||||
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
|
||||
|
||||
/* disable automatic timer on frame reception */
|
||||
op->flags |= RX_NO_AUTOTIMER;
|
||||
|
||||
/*
|
||||
* Don't care if we're bound or not (due to netdev
|
||||
* problems) can_rx_unregister() is always a save
|
||||
@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
|
||||
bcm_rx_handler, op);
|
||||
|
||||
list_del(&op->list);
|
||||
synchronize_rcu();
|
||||
bcm_remove_op(op);
|
||||
return 1; /* done */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user