Merge git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
authorDavid S. Miller <davem@davemloft.net>
Wed, 26 Oct 2022 12:46:38 +0000 (13:46 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Oct 2022 12:46:38 +0000 (13:46 +0100)
Marc Kleine-Budde says:

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

The first patch is by Daniel S. Trevitz and adds documentation for
switchable termination resistors.

Zhang Changzhong's patch fixes a debug output in the j13939 stack.

Oliver Hartkopp finally removes the pch_can driver, which is
superseded by the generic c_can driver.

Gustavo A. R. Silva replaces a zero-length array with
DECLARE_FLEX_ARRAY() in the ucan driver.

Kees Cook's patch removes a no longer needed silencing of
"-Warray-bounds" warnings for the kvaser_usb driver.

The next 2 patches target the m_can driver. The first is by me cleans
up the LEC error handling, the second is by Vivek Yadav and extends
the LEC error handling to the data phase of CAN-FD frames.

The next 9 patches all target the gs_usb driver. The first 5 patches
are by me and improve the Kconfig prompt and help text, set
netdev->dev_id to distinguish multi CAN channel devices, allow
loopback and listen only at the same time, and clean up the
gs_can_open() function a bit. The remaining 4 patches are by Jeroen
Hofstee and add support for 2 new features: Bus Error Reporting and
Get State.

Jimmy Assarsson and Anssi Hannula contribute 10 patches for the
kvaser_usb driver. They first add Listen Only and Bus Error Reporting
support, handle CMD_ERROR_EVENT errors, improve CAN state handling,
restart events, and configuration of the bit timing parameters.

Another patch by me which fixes the indention in the m_can driver.

A patch by Dongliang Mu cleans up the ucan_disconnect() function in
the ucan driver.

The last patch by Biju Das is for the rcan_canfd driver and cleans up
the reset handling.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
17 files changed:
Documentation/networking/can.rst
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/c_can/Kconfig
drivers/net/can/m_can/m_can.c
drivers/net/can/m_can/m_can.h
drivers/net/can/pch_can.c [deleted file]
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/usb/Kconfig
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb/Makefile
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
drivers/net/can/usb/ucan.c
net/can/j1939/transport.c

index ebc822e..90121de 100644 (file)
@@ -1148,6 +1148,39 @@ tuning on deep embedded systems'. The author is running a MPC603e
 load without any problems ...
 
 
+Switchable Termination Resistors
+--------------------------------
+
+CAN bus requires a specific impedance across the differential pair,
+typically provided by two 120Ohm resistors on the farthest nodes of
+the bus. Some CAN controllers support activating / deactivating a
+termination resistor(s) to provide the correct impedance.
+
+Query the available resistances::
+
+    $ ip -details link show can0
+    ...
+    termination 120 [ 0, 120 ]
+
+Activate the terminating resistor::
+
+    $ ip link set dev can0 type can termination 120
+
+Deactivate the terminating resistor::
+
+    $ ip link set dev can0 type can termination 0
+
+To enable termination resistor support to a can-controller, either
+implement in the controller's struct can-priv::
+
+    termination_const
+    termination_const_cnt
+    do_set_termination
+
+or add gpio control with the device tree entries from
+Documentation/devicetree/bindings/net/can/can-controller.yaml
+
+
 The Virtual CAN Driver (vcan)
 -----------------------------
 
index 3048ad7..cd34e8d 100644 (file)
@@ -198,14 +198,6 @@ config CAN_XILINXCAN
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
          Zynq CANPS IP.
 
-config PCH_CAN
-       tristate "Intel EG20T PCH CAN controller"
-       depends on PCI && (X86_32 || COMPILE_TEST)
-       help
-         This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
-         is an IOH for x86 embedded processor (Intel Atom E6xx series).
-         This driver can access CAN bus.
-
 source "drivers/net/can/c_can/Kconfig"
 source "drivers/net/can/cc770/Kconfig"
 source "drivers/net/can/ctucanfd/Kconfig"
index 61c75ce..52b0f6e 100644 (file)
@@ -30,6 +30,5 @@ obj-$(CONFIG_CAN_SJA1000)     += sja1000/
 obj-$(CONFIG_CAN_SUN4I)                += sun4i_can.o
 obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
 obj-$(CONFIG_CAN_XILINXCAN)    += xilinx_can.o
-obj-$(CONFIG_PCH_CAN)          += pch_can.o
 
 subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
index 9627257..1f0e9ac 100644 (file)
@@ -20,5 +20,6 @@ config CAN_C_CAN_PCI
        depends on PCI
        help
          This driver adds support for the C_CAN/D_CAN chips connected
-         to the PCI bus.
+         to the PCI bus. E.g. for the C_CAN controller IP inside the
+         Intel Atom E6xx series IOH (aka EG20T 'PCH CAN').
 endif
index dcb5825..59deb18 100644 (file)
@@ -156,6 +156,7 @@ enum m_can_reg {
 #define PSR_EW         BIT(6)
 #define PSR_EP         BIT(5)
 #define PSR_LEC_MASK   GENMASK(2, 0)
+#define PSR_DLEC_MASK  GENMASK(10, 8)
 
 /* Interrupt Register (IR) */
 #define IR_ALL_INT     0xffffffff
@@ -209,7 +210,7 @@ enum m_can_reg {
 
 /* Interrupts for version >= 3.1.x */
 #define IR_ERR_LEC_31X (IR_PED | IR_PEA)
-#define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \
+#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \
                         IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
                         IR_RF0L)
 #define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X)
@@ -816,11 +817,9 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
                netdev_err(dev, "Message RAM access failure occurred\n");
 }
 
-static inline bool is_lec_err(u32 psr)
+static inline bool is_lec_err(u8 lec)
 {
-       psr &= LEC_UNUSED;
-
-       return psr && (psr != LEC_UNUSED);
+       return lec != LEC_NO_ERROR && lec != LEC_NO_CHANGE;
 }
 
 static inline bool m_can_is_protocol_err(u32 irqstatus)
@@ -875,9 +874,20 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
                work_done += m_can_handle_lost_msg(dev);
 
        /* handle lec errors on the bus */
-       if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
-           is_lec_err(psr))
-               work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED);
+       if (cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
+               u8 lec = FIELD_GET(PSR_LEC_MASK, psr);
+               u8 dlec = FIELD_GET(PSR_DLEC_MASK, psr);
+
+               if (is_lec_err(lec)) {
+                       netdev_dbg(dev, "Arbitration phase error detected\n");
+                       work_done += m_can_handle_lec_err(dev, lec);
+               }
+               
+               if (is_lec_err(dlec)) {
+                       netdev_dbg(dev, "Data phase error detected\n");
+                       work_done += m_can_handle_lec_err(dev, dlec);
+               }
+       }
 
        /* handle protocol errors in arbitration phase */
        if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
index 4c0267f..52563c0 100644 (file)
@@ -38,7 +38,7 @@ enum m_can_lec_type {
        LEC_BIT1_ERROR,
        LEC_BIT0_ERROR,
        LEC_CRC_ERROR,
-       LEC_UNUSED,
+       LEC_NO_CHANGE,
 };
 
 enum m_can_mram_cfg {
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
deleted file mode 100644 (file)
index 0558ff6..0000000
+++ /dev/null
@@ -1,1249 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 LAPIS SEMICONDUCTOR CO., LTD.
- */
-
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
-
-#define PCH_CTRL_INIT          BIT(0) /* The INIT bit of CANCONT register. */
-#define PCH_CTRL_IE            BIT(1) /* The IE bit of CAN control register */
-#define PCH_CTRL_IE_SIE_EIE    (BIT(3) | BIT(2) | BIT(1))
-#define PCH_CTRL_CCE           BIT(6)
-#define PCH_CTRL_OPT           BIT(7) /* The OPT bit of CANCONT register. */
-#define PCH_OPT_SILENT         BIT(3) /* The Silent bit of CANOPT reg. */
-#define PCH_OPT_LBACK          BIT(4) /* The LoopBack bit of CANOPT reg. */
-
-#define PCH_CMASK_RX_TX_SET    0x00f3
-#define PCH_CMASK_RX_TX_GET    0x0073
-#define PCH_CMASK_ALL          0xff
-#define PCH_CMASK_NEWDAT       BIT(2)
-#define PCH_CMASK_CLRINTPND    BIT(3)
-#define PCH_CMASK_CTRL         BIT(4)
-#define PCH_CMASK_ARB          BIT(5)
-#define PCH_CMASK_MASK         BIT(6)
-#define PCH_CMASK_RDWR         BIT(7)
-#define PCH_IF_MCONT_NEWDAT    BIT(15)
-#define PCH_IF_MCONT_MSGLOST   BIT(14)
-#define PCH_IF_MCONT_INTPND    BIT(13)
-#define PCH_IF_MCONT_UMASK     BIT(12)
-#define PCH_IF_MCONT_TXIE      BIT(11)
-#define PCH_IF_MCONT_RXIE      BIT(10)
-#define PCH_IF_MCONT_RMTEN     BIT(9)
-#define PCH_IF_MCONT_TXRQXT    BIT(8)
-#define PCH_IF_MCONT_EOB       BIT(7)
-#define PCH_IF_MCONT_DLC       (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-#define PCH_MASK2_MDIR_MXTD    (BIT(14) | BIT(15))
-#define PCH_ID2_DIR            BIT(13)
-#define PCH_ID2_XTD            BIT(14)
-#define PCH_ID_MSGVAL          BIT(15)
-#define PCH_IF_CREQ_BUSY       BIT(15)
-
-#define PCH_STATUS_INT         0x8000
-#define PCH_RP                 0x00008000
-#define PCH_REC                        0x00007f00
-#define PCH_TEC                        0x000000ff
-
-#define PCH_TX_OK              BIT(3)
-#define PCH_RX_OK              BIT(4)
-#define PCH_EPASSIV            BIT(5)
-#define PCH_EWARN              BIT(6)
-#define PCH_BUS_OFF            BIT(7)
-
-/* bit position of certain controller bits. */
-#define PCH_BIT_BRP_SHIFT      0
-#define PCH_BIT_SJW_SHIFT      6
-#define PCH_BIT_TSEG1_SHIFT    8
-#define PCH_BIT_TSEG2_SHIFT    12
-#define PCH_BIT_BRPE_BRPE_SHIFT        6
-
-#define PCH_MSK_BITT_BRP       0x3f
-#define PCH_MSK_BRPE_BRPE      0x3c0
-#define PCH_MSK_CTRL_IE_SIE_EIE        0x07
-#define PCH_COUNTER_LIMIT      10
-
-#define PCH_CAN_CLK            50000000        /* 50MHz */
-
-/*
- * Define the number of message object.
- * PCH CAN communications are done via Message RAM.
- * The Message RAM consists of 32 message objects.
- */
-#define PCH_RX_OBJ_NUM         26
-#define PCH_TX_OBJ_NUM         6
-#define PCH_RX_OBJ_START       1
-#define PCH_RX_OBJ_END         PCH_RX_OBJ_NUM
-#define PCH_TX_OBJ_START       (PCH_RX_OBJ_END + 1)
-#define PCH_TX_OBJ_END         (PCH_RX_OBJ_NUM + PCH_TX_OBJ_NUM)
-
-#define PCH_FIFO_THRESH                16
-
-/* TxRqst2 show status of MsgObjNo.17~32 */
-#define PCH_TREQ2_TX_MASK      (((1 << PCH_TX_OBJ_NUM) - 1) <<\
-                                                       (PCH_RX_OBJ_END - 16))
-
-enum pch_ifreg {
-       PCH_RX_IFREG,
-       PCH_TX_IFREG,
-};
-
-enum pch_can_err {
-       PCH_STUF_ERR = 1,
-       PCH_FORM_ERR,
-       PCH_ACK_ERR,
-       PCH_BIT1_ERR,
-       PCH_BIT0_ERR,
-       PCH_CRC_ERR,
-       PCH_LEC_ALL,
-};
-
-enum pch_can_mode {
-       PCH_CAN_ENABLE,
-       PCH_CAN_DISABLE,
-       PCH_CAN_ALL,
-       PCH_CAN_NONE,
-       PCH_CAN_STOP,
-       PCH_CAN_RUN,
-};
-
-struct pch_can_if_regs {
-       u32 creq;
-       u32 cmask;
-       u32 mask1;
-       u32 mask2;
-       u32 id1;
-       u32 id2;
-       u32 mcont;
-       u32 data[4];
-       u32 rsv[13];
-};
-
-struct pch_can_regs {
-       u32 cont;
-       u32 stat;
-       u32 errc;
-       u32 bitt;
-       u32 intr;
-       u32 opt;
-       u32 brpe;
-       u32 reserve;
-       struct pch_can_if_regs ifregs[2]; /* [0]=if1  [1]=if2 */
-       u32 reserve1[8];
-       u32 treq1;
-       u32 treq2;
-       u32 reserve2[6];
-       u32 data1;
-       u32 data2;
-       u32 reserve3[6];
-       u32 canipend1;
-       u32 canipend2;
-       u32 reserve4[6];
-       u32 canmval1;
-       u32 canmval2;
-       u32 reserve5[37];
-       u32 srst;
-};
-
-struct pch_can_priv {
-       struct can_priv can;
-       struct pci_dev *dev;
-       u32 tx_enable[PCH_TX_OBJ_END];
-       u32 rx_enable[PCH_TX_OBJ_END];
-       u32 rx_link[PCH_TX_OBJ_END];
-       u32 int_enables;
-       struct net_device *ndev;
-       struct pch_can_regs __iomem *regs;
-       struct napi_struct napi;
-       int tx_obj;     /* Point next Tx Obj index */
-       int use_msi;
-};
-
-static const struct can_bittiming_const pch_can_bittiming_const = {
-       .name = KBUILD_MODNAME,
-       .tseg1_min = 2,
-       .tseg1_max = 16,
-       .tseg2_min = 1,
-       .tseg2_max = 8,
-       .sjw_max = 4,
-       .brp_min = 1,
-       .brp_max = 1024, /* 6bit + extended 4bit */
-       .brp_inc = 1,
-};
-
-static const struct pci_device_id pch_pci_tbl[] = {
-       {PCI_VENDOR_ID_INTEL, 0x8818, PCI_ANY_ID, PCI_ANY_ID,},
-       {0,}
-};
-MODULE_DEVICE_TABLE(pci, pch_pci_tbl);
-
-static inline void pch_can_bit_set(void __iomem *addr, u32 mask)
-{
-       iowrite32(ioread32(addr) | mask, addr);
-}
-
-static inline void pch_can_bit_clear(void __iomem *addr, u32 mask)
-{
-       iowrite32(ioread32(addr) & ~mask, addr);
-}
-
-static void pch_can_set_run_mode(struct pch_can_priv *priv,
-                                enum pch_can_mode mode)
-{
-       switch (mode) {
-       case PCH_CAN_RUN:
-               pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_INIT);
-               break;
-
-       case PCH_CAN_STOP:
-               pch_can_bit_set(&priv->regs->cont, PCH_CTRL_INIT);
-               break;
-
-       default:
-               netdev_err(priv->ndev, "%s -> Invalid Mode.\n", __func__);
-               break;
-       }
-}
-
-static void pch_can_set_optmode(struct pch_can_priv *priv)
-{
-       u32 reg_val = ioread32(&priv->regs->opt);
-
-       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
-               reg_val |= PCH_OPT_SILENT;
-
-       if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
-               reg_val |= PCH_OPT_LBACK;
-
-       pch_can_bit_set(&priv->regs->cont, PCH_CTRL_OPT);
-       iowrite32(reg_val, &priv->regs->opt);
-}
-
-static void pch_can_rw_msg_obj(void __iomem *creq_addr, u32 num)
-{
-       int counter = PCH_COUNTER_LIMIT;
-       u32 ifx_creq;
-
-       iowrite32(num, creq_addr);
-       while (counter) {
-               ifx_creq = ioread32(creq_addr) & PCH_IF_CREQ_BUSY;
-               if (!ifx_creq)
-                       break;
-               counter--;
-               udelay(1);
-       }
-       if (!counter)
-               pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__);
-}
-
-static void pch_can_set_int_enables(struct pch_can_priv *priv,
-                                   enum pch_can_mode interrupt_no)
-{
-       switch (interrupt_no) {
-       case PCH_CAN_DISABLE:
-               pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE);
-               break;
-
-       case PCH_CAN_ALL:
-               pch_can_bit_set(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
-               break;
-
-       case PCH_CAN_NONE:
-               pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
-               break;
-
-       default:
-               netdev_err(priv->ndev, "Invalid interrupt number.\n");
-               break;
-       }
-}
-
-static void pch_can_set_rxtx(struct pch_can_priv *priv, u32 buff_num,
-                            int set, enum pch_ifreg dir)
-{
-       u32 ie;
-
-       if (dir)
-               ie = PCH_IF_MCONT_TXIE;
-       else
-               ie = PCH_IF_MCONT_RXIE;
-
-       /* Reading the Msg buffer from Message RAM to IF1/2 registers. */
-       iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
-
-       /* Setting the IF1/2MASK1 register to access MsgVal and RxIE bits */
-       iowrite32(PCH_CMASK_RDWR | PCH_CMASK_ARB | PCH_CMASK_CTRL,
-                 &priv->regs->ifregs[dir].cmask);
-
-       if (set) {
-               /* Setting the MsgVal and RxIE/TxIE bits */
-               pch_can_bit_set(&priv->regs->ifregs[dir].mcont, ie);
-               pch_can_bit_set(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL);
-       } else {
-               /* Clearing the MsgVal and RxIE/TxIE bits */
-               pch_can_bit_clear(&priv->regs->ifregs[dir].mcont, ie);
-               pch_can_bit_clear(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL);
-       }
-
-       pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
-}
-
-static void pch_can_set_rx_all(struct pch_can_priv *priv, int set)
-{
-       int i;
-
-       /* Traversing to obtain the object configured as receivers. */
-       for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++)
-               pch_can_set_rxtx(priv, i, set, PCH_RX_IFREG);
-}
-
-static void pch_can_set_tx_all(struct pch_can_priv *priv, int set)
-{
-       int i;
-
-       /* Traversing to obtain the object configured as transmit object. */
-       for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
-               pch_can_set_rxtx(priv, i, set, PCH_TX_IFREG);
-}
-
-static u32 pch_can_int_pending(struct pch_can_priv *priv)
-{
-       return ioread32(&priv->regs->intr) & 0xffff;
-}
-
-static void pch_can_clear_if_buffers(struct pch_can_priv *priv)
-{
-       int i; /* Msg Obj ID (1~32) */
-
-       for (i = PCH_RX_OBJ_START; i <= PCH_TX_OBJ_END; i++) {
-               iowrite32(PCH_CMASK_RX_TX_SET, &priv->regs->ifregs[0].cmask);
-               iowrite32(0xffff, &priv->regs->ifregs[0].mask1);
-               iowrite32(0xffff, &priv->regs->ifregs[0].mask2);
-               iowrite32(0x0, &priv->regs->ifregs[0].id1);
-               iowrite32(0x0, &priv->regs->ifregs[0].id2);
-               iowrite32(0x0, &priv->regs->ifregs[0].mcont);
-               iowrite32(0x0, &priv->regs->ifregs[0].data[0]);
-               iowrite32(0x0, &priv->regs->ifregs[0].data[1]);
-               iowrite32(0x0, &priv->regs->ifregs[0].data[2]);
-               iowrite32(0x0, &priv->regs->ifregs[0].data[3]);
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK |
-                         PCH_CMASK_ARB | PCH_CMASK_CTRL,
-                         &priv->regs->ifregs[0].cmask);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
-       }
-}
-
-static void pch_can_config_rx_tx_buffers(struct pch_can_priv *priv)
-{
-       int i;
-
-       for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
-               iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
-
-               iowrite32(0x0, &priv->regs->ifregs[0].id1);
-               iowrite32(0x0, &priv->regs->ifregs[0].id2);
-
-               pch_can_bit_set(&priv->regs->ifregs[0].mcont,
-                               PCH_IF_MCONT_UMASK);
-
-               /* In case FIFO mode, Last EoB of Rx Obj must be 1 */
-               if (i == PCH_RX_OBJ_END)
-                       pch_can_bit_set(&priv->regs->ifregs[0].mcont,
-                                       PCH_IF_MCONT_EOB);
-               else
-                       pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
-                                         PCH_IF_MCONT_EOB);
-
-               iowrite32(0, &priv->regs->ifregs[0].mask1);
-               pch_can_bit_clear(&priv->regs->ifregs[0].mask2,
-                                 0x1fff | PCH_MASK2_MDIR_MXTD);
-
-               /* Setting CMASK for writing */
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB |
-                         PCH_CMASK_CTRL, &priv->regs->ifregs[0].cmask);
-
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i);
-       }
-
-       for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) {
-               iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[1].cmask);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i);
-
-               /* Resetting DIR bit for reception */
-               iowrite32(0x0, &priv->regs->ifregs[1].id1);
-               iowrite32(PCH_ID2_DIR, &priv->regs->ifregs[1].id2);
-
-               /* Setting EOB bit for transmitter */
-               iowrite32(PCH_IF_MCONT_EOB | PCH_IF_MCONT_UMASK,
-                         &priv->regs->ifregs[1].mcont);
-
-               iowrite32(0, &priv->regs->ifregs[1].mask1);
-               pch_can_bit_clear(&priv->regs->ifregs[1].mask2, 0x1fff);
-
-               /* Setting CMASK for writing */
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB |
-                         PCH_CMASK_CTRL, &priv->regs->ifregs[1].cmask);
-
-               pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i);
-       }
-}
-
-static void pch_can_init(struct pch_can_priv *priv)
-{
-       /* Stopping the Can device. */
-       pch_can_set_run_mode(priv, PCH_CAN_STOP);
-
-       /* Clearing all the message object buffers. */
-       pch_can_clear_if_buffers(priv);
-
-       /* Configuring the respective message object as either rx/tx object. */
-       pch_can_config_rx_tx_buffers(priv);
-
-       /* Enabling the interrupts. */
-       pch_can_set_int_enables(priv, PCH_CAN_ALL);
-}
-
-static void pch_can_release(struct pch_can_priv *priv)
-{
-       /* Stooping the CAN device. */
-       pch_can_set_run_mode(priv, PCH_CAN_STOP);
-
-       /* Disabling the interrupts. */
-       pch_can_set_int_enables(priv, PCH_CAN_NONE);
-
-       /* Disabling all the receive object. */
-       pch_can_set_rx_all(priv, 0);
-
-       /* Disabling all the transmit object. */
-       pch_can_set_tx_all(priv, 0);
-}
-
-/* This function clears interrupt(s) from the CAN device. */
-static void pch_can_int_clr(struct pch_can_priv *priv, u32 mask)
-{
-       /* Clear interrupt for transmit object */
-       if ((mask >= PCH_RX_OBJ_START) && (mask <= PCH_RX_OBJ_END)) {
-               /* Setting CMASK for clearing the reception interrupts. */
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB,
-                         &priv->regs->ifregs[0].cmask);
-
-               /* Clearing the Dir bit. */
-               pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR);
-
-               /* Clearing NewDat & IntPnd */
-               pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
-                                 PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND);
-
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, mask);
-       } else if ((mask >= PCH_TX_OBJ_START) && (mask <= PCH_TX_OBJ_END)) {
-               /*
-                * Setting CMASK for clearing interrupts for frame transmission.
-                */
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB,
-                         &priv->regs->ifregs[1].cmask);
-
-               /* Resetting the ID registers. */
-               pch_can_bit_set(&priv->regs->ifregs[1].id2,
-                              PCH_ID2_DIR | (0x7ff << 2));
-               iowrite32(0x0, &priv->regs->ifregs[1].id1);
-
-               /* Clearing NewDat, TxRqst & IntPnd */
-               pch_can_bit_clear(&priv->regs->ifregs[1].mcont,
-                                 PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND |
-                                 PCH_IF_MCONT_TXRQXT);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, mask);
-       }
-}
-
-static void pch_can_reset(struct pch_can_priv *priv)
-{
-       /* write to sw reset register */
-       iowrite32(1, &priv->regs->srst);
-       iowrite32(0, &priv->regs->srst);
-}
-
-static void pch_can_error(struct net_device *ndev, u32 status)
-{
-       struct sk_buff *skb;
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       struct can_frame *cf;
-       u32 errc, lec;
-       struct net_device_stats *stats = &(priv->ndev->stats);
-       enum can_state state = priv->can.state;
-
-       skb = alloc_can_err_skb(ndev, &cf);
-       if (!skb)
-               return;
-
-       errc = ioread32(&priv->regs->errc);
-       if (status & PCH_BUS_OFF) {
-               pch_can_set_tx_all(priv, 0);
-               pch_can_set_rx_all(priv, 0);
-               state = CAN_STATE_BUS_OFF;
-               cf->can_id |= CAN_ERR_BUSOFF;
-               priv->can.can_stats.bus_off++;
-               can_bus_off(ndev);
-       } else {
-               cf->can_id |= CAN_ERR_CNT;
-               cf->data[6] = errc & PCH_TEC;
-               cf->data[7] = (errc & PCH_REC) >> 8;
-       }
-
-       /* Warning interrupt. */
-       if (status & PCH_EWARN) {
-               state = CAN_STATE_ERROR_WARNING;
-               priv->can.can_stats.error_warning++;
-               cf->can_id |= CAN_ERR_CRTL;
-               if (((errc & PCH_REC) >> 8) > 96)
-                       cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
-               if ((errc & PCH_TEC) > 96)
-                       cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
-               netdev_dbg(ndev,
-                       "%s -> Error Counter is more than 96.\n", __func__);
-       }
-       /* Error passive interrupt. */
-       if (status & PCH_EPASSIV) {
-               priv->can.can_stats.error_passive++;
-               state = CAN_STATE_ERROR_PASSIVE;
-               cf->can_id |= CAN_ERR_CRTL;
-               if (errc & PCH_RP)
-                       cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
-               if ((errc & PCH_TEC) > 127)
-                       cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
-               netdev_dbg(ndev,
-                       "%s -> CAN controller is ERROR PASSIVE .\n", __func__);
-       }
-
-       lec = status & PCH_LEC_ALL;
-       switch (lec) {
-       case PCH_STUF_ERR:
-               cf->data[2] |= CAN_ERR_PROT_STUFF;
-               priv->can.can_stats.bus_error++;
-               stats->rx_errors++;
-               break;
-       case PCH_FORM_ERR:
-               cf->data[2] |= CAN_ERR_PROT_FORM;
-               priv->can.can_stats.bus_error++;
-               stats->rx_errors++;
-               break;
-       case PCH_ACK_ERR:
-               cf->can_id |= CAN_ERR_ACK;
-               priv->can.can_stats.bus_error++;
-               stats->rx_errors++;
-               break;
-       case PCH_BIT1_ERR:
-       case PCH_BIT0_ERR:
-               cf->data[2] |= CAN_ERR_PROT_BIT;
-               priv->can.can_stats.bus_error++;
-               stats->rx_errors++;
-               break;
-       case PCH_CRC_ERR:
-               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
-               priv->can.can_stats.bus_error++;
-               stats->rx_errors++;
-               break;
-       case PCH_LEC_ALL: /* Written by CPU. No error status */
-               break;
-       }
-
-       priv->can.state = state;
-       netif_receive_skb(skb);
-}
-
-static irqreturn_t pch_can_interrupt(int irq, void *dev_id)
-{
-       struct net_device *ndev = (struct net_device *)dev_id;
-       struct pch_can_priv *priv = netdev_priv(ndev);
-
-       if (!pch_can_int_pending(priv))
-               return IRQ_NONE;
-
-       pch_can_set_int_enables(priv, PCH_CAN_NONE);
-       napi_schedule(&priv->napi);
-       return IRQ_HANDLED;
-}
-
-static void pch_fifo_thresh(struct pch_can_priv *priv, int obj_id)
-{
-       if (obj_id < PCH_FIFO_THRESH) {
-               iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL |
-                         PCH_CMASK_ARB, &priv->regs->ifregs[0].cmask);
-
-               /* Clearing the Dir bit. */
-               pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR);
-
-               /* Clearing NewDat & IntPnd */
-               pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
-                                 PCH_IF_MCONT_INTPND);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id);
-       } else if (obj_id > PCH_FIFO_THRESH) {
-               pch_can_int_clr(priv, obj_id);
-       } else if (obj_id == PCH_FIFO_THRESH) {
-               int cnt;
-               for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++)
-                       pch_can_int_clr(priv, cnt + 1);
-       }
-}
-
-static void pch_can_rx_msg_lost(struct net_device *ndev, int obj_id)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       struct net_device_stats *stats = &(priv->ndev->stats);
-       struct sk_buff *skb;
-       struct can_frame *cf;
-
-       netdev_dbg(priv->ndev, "Msg Obj is overwritten.\n");
-       pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
-                         PCH_IF_MCONT_MSGLOST);
-       iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL,
-                 &priv->regs->ifregs[0].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id);
-
-       skb = alloc_can_err_skb(ndev, &cf);
-       if (!skb)
-               return;
-
-       cf->can_id |= CAN_ERR_CRTL;
-       cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-       stats->rx_over_errors++;
-       stats->rx_errors++;
-
-       netif_receive_skb(skb);
-}
-
-static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
-{
-       u32 reg;
-       canid_t id;
-       int rcv_pkts = 0;
-       struct sk_buff *skb;
-       struct can_frame *cf;
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       struct net_device_stats *stats = &(priv->ndev->stats);
-       int i;
-       u32 id2;
-       u16 data_reg;
-
-       do {
-               /* Reading the message object from the Message RAM */
-               iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
-               pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_num);
-
-               /* Reading the MCONT register. */
-               reg = ioread32(&priv->regs->ifregs[0].mcont);
-
-               if (reg & PCH_IF_MCONT_EOB)
-                       break;
-
-               /* If MsgLost bit set. */
-               if (reg & PCH_IF_MCONT_MSGLOST) {
-                       pch_can_rx_msg_lost(ndev, obj_num);
-                       rcv_pkts++;
-                       quota--;
-                       obj_num++;
-                       continue;
-               } else if (!(reg & PCH_IF_MCONT_NEWDAT)) {
-                       obj_num++;
-                       continue;
-               }
-
-               skb = alloc_can_skb(priv->ndev, &cf);
-               if (!skb) {
-                       netdev_err(ndev, "alloc_can_skb Failed\n");
-                       return rcv_pkts;
-               }
-
-               /* Get Received data */
-               id2 = ioread32(&priv->regs->ifregs[0].id2);
-               if (id2 & PCH_ID2_XTD) {
-                       id = (ioread32(&priv->regs->ifregs[0].id1) & 0xffff);
-                       id |= (((id2) & 0x1fff) << 16);
-                       cf->can_id = id | CAN_EFF_FLAG;
-               } else {
-                       id = (id2 >> 2) & CAN_SFF_MASK;
-                       cf->can_id = id;
-               }
-
-               cf->len = can_cc_dlc2len((ioread32(&priv->regs->
-                                                   ifregs[0].mcont)) & 0xF);
-
-               if (id2 & PCH_ID2_DIR) {
-                       cf->can_id |= CAN_RTR_FLAG;
-               } else {
-                       for (i = 0; i < cf->len; i += 2) {
-                               data_reg = ioread16(&priv->regs->ifregs[0].data[i / 2]);
-                               cf->data[i] = data_reg;
-                               cf->data[i + 1] = data_reg >> 8;
-                       }
-
-                       stats->rx_bytes += cf->len;
-               }
-               stats->rx_packets++;
-               rcv_pkts++;
-               quota--;
-               netif_receive_skb(skb);
-
-               pch_fifo_thresh(priv, obj_num);
-               obj_num++;
-       } while (quota > 0);
-
-       return rcv_pkts;
-}
-
-static void pch_can_tx_complete(struct net_device *ndev, u32 int_stat)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       struct net_device_stats *stats = &(priv->ndev->stats);
-
-       stats->tx_bytes += can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1,
-                                           NULL);
-       stats->tx_packets++;
-       iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND,
-                 &priv->regs->ifregs[1].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat);
-       if (int_stat == PCH_TX_OBJ_END)
-               netif_wake_queue(ndev);
-}
-
-static int pch_can_poll(struct napi_struct *napi, int quota)
-{
-       struct net_device *ndev = napi->dev;
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       u32 int_stat;
-       u32 reg_stat;
-       int quota_save = quota;
-
-       int_stat = pch_can_int_pending(priv);
-       if (!int_stat)
-               goto end;
-
-       if (int_stat == PCH_STATUS_INT) {
-               reg_stat = ioread32(&priv->regs->stat);
-
-               if ((reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) &&
-                  ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)) {
-                       pch_can_error(ndev, reg_stat);
-                       quota--;
-               }
-
-               if (reg_stat & (PCH_TX_OK | PCH_RX_OK))
-                       pch_can_bit_clear(&priv->regs->stat,
-                                         reg_stat & (PCH_TX_OK | PCH_RX_OK));
-
-               int_stat = pch_can_int_pending(priv);
-       }
-
-       if (quota == 0)
-               goto end;
-
-       if ((int_stat >= PCH_RX_OBJ_START) && (int_stat <= PCH_RX_OBJ_END)) {
-               quota -= pch_can_rx_normal(ndev, int_stat, quota);
-       } else if ((int_stat >= PCH_TX_OBJ_START) &&
-                  (int_stat <= PCH_TX_OBJ_END)) {
-               /* Handle transmission interrupt */
-               pch_can_tx_complete(ndev, int_stat);
-       }
-
-end:
-       napi_complete(napi);
-       pch_can_set_int_enables(priv, PCH_CAN_ALL);
-
-       return quota_save - quota;
-}
-
-static int pch_set_bittiming(struct net_device *ndev)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       const struct can_bittiming *bt = &priv->can.bittiming;
-       u32 canbit;
-       u32 bepe;
-
-       /* Setting the CCE bit for accessing the Can Timing register. */
-       pch_can_bit_set(&priv->regs->cont, PCH_CTRL_CCE);
-
-       canbit = (bt->brp - 1) & PCH_MSK_BITT_BRP;
-       canbit |= (bt->sjw - 1) << PCH_BIT_SJW_SHIFT;
-       canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << PCH_BIT_TSEG1_SHIFT;
-       canbit |= (bt->phase_seg2 - 1) << PCH_BIT_TSEG2_SHIFT;
-       bepe = ((bt->brp - 1) & PCH_MSK_BRPE_BRPE) >> PCH_BIT_BRPE_BRPE_SHIFT;
-       iowrite32(canbit, &priv->regs->bitt);
-       iowrite32(bepe, &priv->regs->brpe);
-       pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_CCE);
-
-       return 0;
-}
-
-static void pch_can_start(struct net_device *ndev)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-
-       if (priv->can.state != CAN_STATE_STOPPED)
-               pch_can_reset(priv);
-
-       pch_set_bittiming(ndev);
-       pch_can_set_optmode(priv);
-
-       pch_can_set_tx_all(priv, 1);
-       pch_can_set_rx_all(priv, 1);
-
-       /* Setting the CAN to run mode. */
-       pch_can_set_run_mode(priv, PCH_CAN_RUN);
-
-       priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
-       return;
-}
-
-static int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
-{
-       int ret = 0;
-
-       switch (mode) {
-       case CAN_MODE_START:
-               pch_can_start(ndev);
-               netif_wake_queue(ndev);
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       return ret;
-}
-
-static int pch_can_open(struct net_device *ndev)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       int retval;
-
-       /* Registering the interrupt. */
-       retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED,
-                            ndev->name, ndev);
-       if (retval) {
-               netdev_err(ndev, "request_irq failed.\n");
-               goto req_irq_err;
-       }
-
-       /* Open common can device */
-       retval = open_candev(ndev);
-       if (retval) {
-               netdev_err(ndev, "open_candev() failed %d\n", retval);
-               goto err_open_candev;
-       }
-
-       pch_can_init(priv);
-       pch_can_start(ndev);
-       napi_enable(&priv->napi);
-       netif_start_queue(ndev);
-
-       return 0;
-
-err_open_candev:
-       free_irq(priv->dev->irq, ndev);
-req_irq_err:
-       pch_can_release(priv);
-
-       return retval;
-}
-
-static int pch_close(struct net_device *ndev)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-
-       netif_stop_queue(ndev);
-       napi_disable(&priv->napi);
-       pch_can_release(priv);
-       free_irq(priv->dev->irq, ndev);
-       close_candev(ndev);
-       priv->can.state = CAN_STATE_STOPPED;
-       return 0;
-}
-
-static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
-       struct pch_can_priv *priv = netdev_priv(ndev);
-       struct can_frame *cf = (struct can_frame *)skb->data;
-       int tx_obj_no;
-       int i;
-       u32 id2;
-
-       if (can_dropped_invalid_skb(ndev, skb))
-               return NETDEV_TX_OK;
-
-       tx_obj_no = priv->tx_obj;
-       if (priv->tx_obj == PCH_TX_OBJ_END) {
-               if (ioread32(&priv->regs->treq2) & PCH_TREQ2_TX_MASK)
-                       netif_stop_queue(ndev);
-
-               priv->tx_obj = PCH_TX_OBJ_START;
-       } else {
-               priv->tx_obj++;
-       }
-
-       /* Setting the CMASK register. */
-       pch_can_bit_set(&priv->regs->ifregs[1].cmask, PCH_CMASK_ALL);
-
-       /* If ID extended is set. */
-       if (cf->can_id & CAN_EFF_FLAG) {
-               iowrite32(cf->can_id & 0xffff, &priv->regs->ifregs[1].id1);
-               id2 = ((cf->can_id >> 16) & 0x1fff) | PCH_ID2_XTD;
-       } else {
-               iowrite32(0, &priv->regs->ifregs[1].id1);
-               id2 = (cf->can_id & CAN_SFF_MASK) << 2;
-       }
-
-       id2 |= PCH_ID_MSGVAL;
-
-       /* If remote frame has to be transmitted.. */
-       if (!(cf->can_id & CAN_RTR_FLAG))
-               id2 |= PCH_ID2_DIR;
-
-       iowrite32(id2, &priv->regs->ifregs[1].id2);
-
-       /* Copy data to register */
-       for (i = 0; i < cf->len; i += 2) {
-               iowrite16(cf->data[i] | (cf->data[i + 1] << 8),
-                         &priv->regs->ifregs[1].data[i / 2]);
-       }
-
-       can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1, 0);
-
-       /* Set the size of the data. Update if2_mcont */
-       iowrite32(cf->len | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT |
-                 PCH_IF_MCONT_TXIE, &priv->regs->ifregs[1].mcont);
-
-       pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, tx_obj_no);
-
-       return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops pch_can_netdev_ops = {
-       .ndo_open               = pch_can_open,
-       .ndo_stop               = pch_close,
-       .ndo_start_xmit         = pch_xmit,
-       .ndo_change_mtu         = can_change_mtu,
-};
-
-static const struct ethtool_ops pch_can_ethtool_ops = {
-       .get_ts_info = ethtool_op_get_ts_info,
-};
-
-static void pch_can_remove(struct pci_dev *pdev)
-{
-       struct net_device *ndev = pci_get_drvdata(pdev);
-       struct pch_can_priv *priv = netdev_priv(ndev);
-
-       unregister_candev(priv->ndev);
-       if (priv->use_msi)
-               pci_disable_msi(priv->dev);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       pch_can_reset(priv);
-       pci_iounmap(pdev, priv->regs);
-       free_candev(priv->ndev);
-}
-
-static void __maybe_unused pch_can_set_int_custom(struct pch_can_priv *priv)
-{
-       /* Clearing the IE, SIE and EIE bits of Can control register. */
-       pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE);
-
-       /* Appropriately setting them. */
-       pch_can_bit_set(&priv->regs->cont,
-                       ((priv->int_enables & PCH_MSK_CTRL_IE_SIE_EIE) << 1));
-}
-
-/* This function retrieves interrupt enabled for the CAN device. */
-static u32 __maybe_unused pch_can_get_int_enables(struct pch_can_priv *priv)
-{
-       /* Obtaining the status of IE, SIE and EIE interrupt bits. */
-       return (ioread32(&priv->regs->cont) & PCH_CTRL_IE_SIE_EIE) >> 1;
-}
-
-static u32 __maybe_unused pch_can_get_rxtx_ir(struct pch_can_priv *priv,
-                                             u32 buff_num, enum pch_ifreg dir)
-{
-       u32 ie, enable;
-
-       if (dir)
-               ie = PCH_IF_MCONT_RXIE;
-       else
-               ie = PCH_IF_MCONT_TXIE;
-
-       iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num);
-
-       if (((ioread32(&priv->regs->ifregs[dir].id2)) & PCH_ID_MSGVAL) &&
-                       ((ioread32(&priv->regs->ifregs[dir].mcont)) & ie))
-               enable = 1;
-       else
-               enable = 0;
-
-       return enable;
-}
-
-static void __maybe_unused pch_can_set_rx_buffer_link(struct pch_can_priv *priv,
-                                                     u32 buffer_num, int set)
-{
-       iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
-       iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL,
-                 &priv->regs->ifregs[0].cmask);
-       if (set)
-               pch_can_bit_clear(&priv->regs->ifregs[0].mcont,
-                                 PCH_IF_MCONT_EOB);
-       else
-               pch_can_bit_set(&priv->regs->ifregs[0].mcont, PCH_IF_MCONT_EOB);
-
-       pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
-}
-
-static u32 __maybe_unused pch_can_get_rx_buffer_link(struct pch_can_priv *priv,
-                                                    u32 buffer_num)
-{
-       u32 link;
-
-       iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
-       pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num);
-
-       if (ioread32(&priv->regs->ifregs[0].mcont) & PCH_IF_MCONT_EOB)
-               link = 0;
-       else
-               link = 1;
-       return link;
-}
-
-static int __maybe_unused pch_can_get_buffer_status(struct pch_can_priv *priv)
-{
-       return (ioread32(&priv->regs->treq1) & 0xffff) |
-              (ioread32(&priv->regs->treq2) << 16);
-}
-
-static int __maybe_unused pch_can_suspend(struct device *dev_d)
-{
-       int i;
-       u32 buf_stat;   /* Variable for reading the transmit buffer status. */
-       int counter = PCH_COUNTER_LIMIT;
-
-       struct net_device *dev = dev_get_drvdata(dev_d);
-       struct pch_can_priv *priv = netdev_priv(dev);
-
-       /* Stop the CAN controller */
-       pch_can_set_run_mode(priv, PCH_CAN_STOP);
-
-       /* Indicate that we are aboutto/in suspend */
-       priv->can.state = CAN_STATE_STOPPED;
-
-       /* Waiting for all transmission to complete. */
-       while (counter) {
-               buf_stat = pch_can_get_buffer_status(priv);
-               if (!buf_stat)
-                       break;
-               counter--;
-               udelay(1);
-       }
-       if (!counter)
-               dev_err(dev_d, "%s -> Transmission time out.\n", __func__);
-
-       /* Save interrupt configuration and then disable them */
-       priv->int_enables = pch_can_get_int_enables(priv);
-       pch_can_set_int_enables(priv, PCH_CAN_DISABLE);
-
-       /* Save Tx buffer enable state */
-       for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
-               priv->tx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i,
-                                                            PCH_TX_IFREG);
-
-       /* Disable all Transmit buffers */
-       pch_can_set_tx_all(priv, 0);
-
-       /* Save Rx buffer enable state */
-       for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
-               priv->rx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i,
-                                                            PCH_RX_IFREG);
-               priv->rx_link[i - 1] = pch_can_get_rx_buffer_link(priv, i);
-       }
-
-       /* Disable all Receive buffers */
-       pch_can_set_rx_all(priv, 0);
-
-       return 0;
-}
-
-static int __maybe_unused pch_can_resume(struct device *dev_d)
-{
-       int i;
-       struct net_device *dev = dev_get_drvdata(dev_d);
-       struct pch_can_priv *priv = netdev_priv(dev);
-
-       priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
-       /* Disabling all interrupts. */
-       pch_can_set_int_enables(priv, PCH_CAN_DISABLE);
-
-       /* Setting the CAN device in Stop Mode. */
-       pch_can_set_run_mode(priv, PCH_CAN_STOP);
-
-       /* Configuring the transmit and receive buffers. */
-       pch_can_config_rx_tx_buffers(priv);
-
-       /* Restore the CAN state */
-       pch_set_bittiming(dev);
-
-       /* Listen/Active */
-       pch_can_set_optmode(priv);
-
-       /* Enabling the transmit buffer. */
-       for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++)
-               pch_can_set_rxtx(priv, i, priv->tx_enable[i - 1], PCH_TX_IFREG);
-
-       /* Configuring the receive buffer and enabling them. */
-       for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) {
-               /* Restore buffer link */
-               pch_can_set_rx_buffer_link(priv, i, priv->rx_link[i - 1]);
-
-               /* Restore buffer enables */
-               pch_can_set_rxtx(priv, i, priv->rx_enable[i - 1], PCH_RX_IFREG);
-       }
-
-       /* Enable CAN Interrupts */
-       pch_can_set_int_custom(priv);
-
-       /* Restore Run Mode */
-       pch_can_set_run_mode(priv, PCH_CAN_RUN);
-
-       return 0;
-}
-
-static int pch_can_get_berr_counter(const struct net_device *dev,
-                                   struct can_berr_counter *bec)
-{
-       struct pch_can_priv *priv = netdev_priv(dev);
-       u32 errc = ioread32(&priv->regs->errc);
-
-       bec->txerr = errc & PCH_TEC;
-       bec->rxerr = (errc & PCH_REC) >> 8;
-
-       return 0;
-}
-
-static int pch_can_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *id)
-{
-       struct net_device *ndev;
-       struct pch_can_priv *priv;
-       int rc;
-       void __iomem *addr;
-
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               dev_err(&pdev->dev, "Failed pci_enable_device %d\n", rc);
-               goto probe_exit_endev;
-       }
-
-       rc = pci_request_regions(pdev, KBUILD_MODNAME);
-       if (rc) {
-               dev_err(&pdev->dev, "Failed pci_request_regions %d\n", rc);
-               goto probe_exit_pcireq;
-       }
-
-       addr = pci_iomap(pdev, 1, 0);
-       if (!addr) {
-               rc = -EIO;
-               dev_err(&pdev->dev, "Failed pci_iomap\n");
-               goto probe_exit_ipmap;
-       }
-
-       ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_END);
-       if (!ndev) {
-               rc = -ENOMEM;
-               dev_err(&pdev->dev, "Failed alloc_candev\n");
-               goto probe_exit_alloc_candev;
-       }
-
-       priv = netdev_priv(ndev);
-       priv->ndev = ndev;
-       priv->regs = addr;
-       priv->dev = pdev;
-       priv->can.bittiming_const = &pch_can_bittiming_const;
-       priv->can.do_set_mode = pch_can_do_set_mode;
-       priv->can.do_get_berr_counter = pch_can_get_berr_counter;
-       priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
-                                      CAN_CTRLMODE_LOOPBACK;
-       priv->tx_obj = PCH_TX_OBJ_START; /* Point head of Tx Obj */
-
-       ndev->irq = pdev->irq;
-       ndev->flags |= IFF_ECHO;
-
-       pci_set_drvdata(pdev, ndev);
-       SET_NETDEV_DEV(ndev, &pdev->dev);
-       ndev->netdev_ops = &pch_can_netdev_ops;
-       ndev->ethtool_ops = &pch_can_ethtool_ops;
-       priv->can.clock.freq = PCH_CAN_CLK; /* Hz */
-
-       netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END);
-
-       rc = pci_enable_msi(priv->dev);
-       if (rc) {
-               netdev_err(ndev, "PCH CAN opened without MSI\n");
-               priv->use_msi = 0;
-       } else {
-               netdev_err(ndev, "PCH CAN opened with MSI\n");
-               pci_set_master(pdev);
-               priv->use_msi = 1;
-       }
-
-       rc = register_candev(ndev);
-       if (rc) {
-               dev_err(&pdev->dev, "Failed register_candev %d\n", rc);
-               goto probe_exit_reg_candev;
-       }
-
-       return 0;
-
-probe_exit_reg_candev:
-       if (priv->use_msi)
-               pci_disable_msi(priv->dev);
-       free_candev(ndev);
-probe_exit_alloc_candev:
-       pci_iounmap(pdev, addr);
-probe_exit_ipmap:
-       pci_release_regions(pdev);
-probe_exit_pcireq:
-       pci_disable_device(pdev);
-probe_exit_endev:
-       return rc;
-}
-
-static SIMPLE_DEV_PM_OPS(pch_can_pm_ops,
-                        pch_can_suspend,
-                        pch_can_resume);
-
-static struct pci_driver pch_can_pci_driver = {
-       .name = "pch_can",
-       .id_table = pch_pci_tbl,
-       .probe = pch_can_probe,
-       .remove = pch_can_remove,
-       .driver.pm = &pch_can_pm_ops,
-};
-
-module_pci_driver(pch_can_pci_driver);
-
-MODULE_DESCRIPTION("Intel EG20T PCH CAN(Controller Area Network) Driver");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.94");
index 567620d..9a55a54 100644 (file)
@@ -1889,17 +1889,17 @@ static int rcar_canfd_probe(struct platform_device *pdev)
        gpriv->chip_id = chip_id;
        gpriv->max_channels = max_channels;
 
-       if (gpriv->chip_id == RENESAS_RZG2L) {
-               gpriv->rstc1 = devm_reset_control_get_exclusive(&pdev->dev, "rstp_n");
-               if (IS_ERR(gpriv->rstc1))
-                       return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1),
-                                            "failed to get rstp_n\n");
-
-               gpriv->rstc2 = devm_reset_control_get_exclusive(&pdev->dev, "rstc_n");
-               if (IS_ERR(gpriv->rstc2))
-                       return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2),
-                                            "failed to get rstc_n\n");
-       }
+       gpriv->rstc1 = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                                "rstp_n");
+       if (IS_ERR(gpriv->rstc1))
+               return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1),
+                                    "failed to get rstp_n\n");
+
+       gpriv->rstc2 = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                                "rstc_n");
+       if (IS_ERR(gpriv->rstc2))
+               return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2),
+                                    "failed to get rstc_n\n");
 
        /* Peripheral clock */
        gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
index 1218f96..8c6fea6 100644 (file)
@@ -38,10 +38,13 @@ config CAN_ETAS_ES58X
          will be called etas_es58x.
 
 config CAN_GS_USB
-       tristate "Geschwister Schneider UG interfaces"
+       tristate "Geschwister Schneider UG and candleLight compatible interfaces"
        help
-         This driver supports the Geschwister Schneider and bytewerk.org
-         candleLight USB CAN interfaces USB/CAN devices
+         This driver supports the Geschwister Schneider and
+         bytewerk.org candleLight compatible
+         (https://github.com/candle-usb/candleLight_fw) USB/CAN
+         interfaces.
+
          If unsure choose N,
          choose Y for built in support,
          M to compile as module (module will be named: gs_usb).
index f0065d4..ccb1a29 100644 (file)
@@ -66,6 +66,7 @@ enum gs_usb_breq {
        GS_USB_BREQ_BT_CONST_EXT,
        GS_USB_BREQ_SET_TERMINATION,
        GS_USB_BREQ_GET_TERMINATION,
+       GS_USB_BREQ_GET_STATE,
 };
 
 enum gs_can_mode {
@@ -134,6 +135,8 @@ struct gs_device_config {
 /* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */
 /* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */
 /* GS_CAN_FEATURE_TERMINATION BIT(11) */
+#define GS_CAN_MODE_BERR_REPORTING BIT(12)
+/* GS_CAN_FEATURE_GET_STATE BIT(13) */
 
 struct gs_device_mode {
        __le32 mode;
@@ -174,7 +177,9 @@ struct gs_device_termination_state {
 #define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9)
 #define GS_CAN_FEATURE_BT_CONST_EXT BIT(10)
 #define GS_CAN_FEATURE_TERMINATION BIT(11)
-#define GS_CAN_FEATURE_MASK GENMASK(11, 0)
+#define GS_CAN_FEATURE_BERR_REPORTING BIT(12)
+#define GS_CAN_FEATURE_GET_STATE BIT(13)
+#define GS_CAN_FEATURE_MASK GENMASK(13, 0)
 
 /* internal quirks - keep in GS_CAN_FEATURE space for now */
 
@@ -843,8 +848,6 @@ static int gs_can_open(struct net_device *netdev)
 
        ctrlmode = dev->can.ctrlmode;
        if (ctrlmode & CAN_CTRLMODE_FD) {
-               flags |= GS_CAN_MODE_FD;
-
                if (dev->feature & GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX)
                        dev->hf_size_tx = struct_size(hf, canfd_quirk, 1);
                else
@@ -911,25 +914,29 @@ static int gs_can_open(struct net_device *netdev)
        /* flags */
        if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
                flags |= GS_CAN_MODE_LOOP_BACK;
-       else if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+
+       if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
                flags |= GS_CAN_MODE_LISTEN_ONLY;
 
-       /* Controller is not allowed to retry TX
-        * this mode is unavailable on atmels uc3c hardware
-        */
+       if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+               flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
+
        if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
                flags |= GS_CAN_MODE_ONE_SHOT;
 
-       if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
-               flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
+       if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+               flags |= GS_CAN_MODE_BERR_REPORTING;
+
+       if (ctrlmode & CAN_CTRLMODE_FD)
+               flags |= GS_CAN_MODE_FD;
 
        /* if hardware supports timestamps, enable it */
-       if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+       if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) {
                flags |= GS_CAN_MODE_HW_TIMESTAMP;
 
-       /* start polling timestamp */
-       if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+               /* start polling timestamp */
                gs_usb_timestamp_init(dev);
+       }
 
        /* finally start device */
        dev->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -954,6 +961,42 @@ static int gs_can_open(struct net_device *netdev)
        return 0;
 }
 
+static int gs_usb_get_state(const struct net_device *netdev,
+                           struct can_berr_counter *bec,
+                           enum can_state *state)
+{
+       struct gs_can *dev = netdev_priv(netdev);
+       struct gs_device_state ds;
+       int rc;
+
+       rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0,
+                                 GS_USB_BREQ_GET_STATE,
+                                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                                 dev->channel, 0,
+                                 &ds, sizeof(ds),
+                                 USB_CTRL_GET_TIMEOUT,
+                                 GFP_KERNEL);
+       if (rc)
+               return rc;
+
+       if (le32_to_cpu(ds.state) >= CAN_STATE_MAX)
+               return -EOPNOTSUPP;
+
+       *state = le32_to_cpu(ds.state);
+       bec->txerr = le32_to_cpu(ds.txerr);
+       bec->rxerr = le32_to_cpu(ds.rxerr);
+
+       return 0;
+}
+
+static int gs_usb_can_get_berr_counter(const struct net_device *netdev,
+                                      struct can_berr_counter *bec)
+{
+       enum can_state state;
+
+       return gs_usb_get_state(netdev, bec, &state);
+}
+
 static int gs_can_close(struct net_device *netdev)
 {
        int rc;
@@ -1153,6 +1196,7 @@ static struct gs_can *gs_make_candev(unsigned int channel,
        netdev->ethtool_ops = &gs_usb_ethtool_ops;
 
        netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */
+       netdev->dev_id = channel;
 
        /* dev setup */
        strcpy(dev->bt_const.name, KBUILD_MODNAME);
@@ -1224,6 +1268,12 @@ static struct gs_can *gs_make_candev(unsigned int channel,
                }
        }
 
+       if (feature & GS_CAN_FEATURE_BERR_REPORTING)
+               dev->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING;
+
+       if (feature & GS_CAN_FEATURE_GET_STATE)
+               dev->can.do_get_berr_counter = gs_usb_can_get_berr_counter;
+
        /* The CANtact Pro from LinkLayer Labs is based on the
         * LPC54616 ÂµC, which is affected by the NXP LPC USB transfer
         * erratum. However, the current firmware (version 2) doesn't
index b20d951..cf26004 100644 (file)
@@ -1,8 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o
-
-# FIXME: temporarily silence -Warray-bounds on non W=1+ builds
-ifndef KBUILD_EXTRA_WARN
-CFLAGS_kvaser_usb_hydra.o += -Wno-array-bounds
-endif
index f6c0938..ff10b37 100644 (file)
@@ -76,6 +76,14 @@ struct kvaser_usb_tx_urb_context {
        u32 echo_index;
 };
 
+struct kvaser_usb_busparams {
+       __le32 bitrate;
+       u8 tseg1;
+       u8 tseg2;
+       u8 sjw;
+       u8 nsamples;
+} __packed;
+
 struct kvaser_usb {
        struct usb_device *udev;
        struct usb_interface *intf;
@@ -104,13 +112,19 @@ struct kvaser_usb_net_priv {
        struct can_priv can;
        struct can_berr_counter bec;
 
+       /* subdriver-specific data */
+       void *sub_priv;
+
        struct kvaser_usb *dev;
        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[];
@@ -120,11 +134,15 @@ 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
  * @dev_init_card:             initialize card
+ * @dev_init_channel:          initialize channel
+ * @dev_remove_channel:                uninitialize channel
  * @dev_get_software_info:     get software info
  * @dev_get_software_details:  get software details
  * @dev_get_card_info:         get card info
@@ -140,12 +158,18 @@ 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);
        int (*dev_init_card)(struct kvaser_usb *dev);
+       int (*dev_init_channel)(struct kvaser_usb_net_priv *priv);
+       void (*dev_remove_channel)(struct kvaser_usb_net_priv *priv);
        int (*dev_get_software_info)(struct kvaser_usb *dev);
        int (*dev_get_software_details)(struct kvaser_usb *dev);
        int (*dev_get_card_info)(struct kvaser_usb *dev);
index e91648e..989e753 100644 (file)
@@ -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;
@@ -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;
@@ -684,6 +767,7 @@ static const struct ethtool_ops kvaser_usb_ethtool_ops_hwts = {
 
 static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
 {
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int i;
 
        for (i = 0; i < dev->nchannels; i++) {
@@ -699,6 +783,9 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
                if (!dev->nets[i])
                        continue;
 
+               if (ops->dev_remove_channel)
+                       ops->dev_remove_channel(dev->nets[i]);
+
                free_candev(dev->nets[i]->netdev);
        }
 }
@@ -730,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;
@@ -742,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))
@@ -754,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;
@@ -772,17 +860,26 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
 
        dev->nets[channel] = priv;
 
+       if (ops->dev_init_channel) {
+               err = ops->dev_init_channel(priv);
+               if (err)
+                       goto err;
+       }
+
        err = register_candev(netdev);
        if (err) {
                dev_err(&dev->intf->dev, "Failed to register CAN device\n");
-               free_candev(netdev);
-               dev->nets[channel] = NULL;
-               return err;
+               goto err;
        }
 
        netdev_dbg(netdev, "device registered\n");
 
        return 0;
+
+err:
+       free_candev(netdev);
+       dev->nets[channel] = NULL;
+       return err;
 }
 
 static int kvaser_usb_probe(struct usb_interface *intf,
index 7b52fda..bf63d88 100644 (file)
@@ -45,6 +45,8 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt;
 
 /* Minihydra command IDs */
 #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_CHIP_STATE_EVENT                   20
 #define CMD_SET_DRIVERMODE_REQ                 21
@@ -196,21 +198,26 @@ struct kvaser_cmd_chip_state_event {
 #define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO    0x01
 #define KVASER_USB_HYDRA_BUS_MODE_NONISO       0x02
 struct kvaser_cmd_set_busparams {
-       __le32 bitrate;
-       u8 tseg1;
-       u8 tseg2;
-       u8 sjw;
-       u8 nsamples;
+       struct kvaser_usb_busparams busparams_nominal;
        u8 reserved0[4];
-       __le32 bitrate_d;
-       u8 tseg1_d;
-       u8 tseg2_d;
-       u8 sjw_d;
-       u8 nsamples_d;
+       struct kvaser_usb_busparams busparams_data;
        u8 canfd_mode;
        u8 reserved1[7];
 } __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 */
 #define KVASER_USB_HYDRA_CTRLMODE_NORMAL       0x01
 #define KVASER_USB_HYDRA_CTRLMODE_LISTEN       0x02
@@ -281,6 +288,8 @@ struct kvaser_cmd {
                struct kvaser_cmd_error_event error_event;
 
                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;
 
@@ -363,6 +372,10 @@ struct kvaser_cmd_ext {
        } __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 = {
        .name = "kvaser_usb_kcan",
        .tseg1_min = 1,
@@ -840,6 +853,39 @@ static void kvaser_usb_hydra_flush_queue_reply(const struct kvaser_usb *dev,
        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
 kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv,
                                         u8 bus_status,
@@ -1326,6 +1372,10 @@ static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev,
                kvaser_usb_hydra_state_event(dev, cmd);
                break;
 
+       case CMD_GET_BUSPARAMS_RESP:
+               kvaser_usb_hydra_get_busparams_reply(dev, cmd);
+               break;
+
        case CMD_ERROR_EVENT:
                kvaser_usb_hydra_error_event(dev, cmd);
                break;
@@ -1522,15 +1572,58 @@ static int kvaser_usb_hydra_set_mode(struct net_device *netdev,
        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_usb_net_priv *priv = netdev_priv(netdev);
-       struct can_bittiming *bt = &priv->can.bittiming;
        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;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -1538,11 +1631,8 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
                return -ENOMEM;
 
        cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ;
-       cmd->set_busparams_req.bitrate = cpu_to_le32(bt->bitrate);
-       cmd->set_busparams_req.sjw = (u8)sjw;
-       cmd->set_busparams_req.tseg1 = (u8)tseg1;
-       cmd->set_busparams_req.tseg2 = (u8)tseg2;
-       cmd->set_busparams_req.nsamples = 1;
+       memcpy(&cmd->set_busparams_req.busparams_nominal, busparams,
+              sizeof(cmd->set_busparams_req.busparams_nominal));
 
        kvaser_usb_hydra_set_cmd_dest_he
                (cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
@@ -1556,15 +1646,12 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
        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_usb_net_priv *priv = netdev_priv(netdev);
-       struct can_bittiming *dbt = &priv->can.data_bittiming;
        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;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -1572,11 +1659,8 @@ static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev)
                return -ENOMEM;
 
        cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ;
-       cmd->set_busparams_req.bitrate_d = cpu_to_le32(dbt->bitrate);
-       cmd->set_busparams_req.sjw_d = (u8)sjw;
-       cmd->set_busparams_req.tseg1_d = (u8)tseg1;
-       cmd->set_busparams_req.tseg2_d = (u8)tseg2;
-       cmd->set_busparams_req.nsamples_d = 1;
+       memcpy(&cmd->set_busparams_req.busparams_data, busparams,
+              sizeof(cmd->set_busparams_req.busparams_data));
 
        if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
                if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
@@ -1683,6 +1767,19 @@ static int kvaser_usb_hydra_init_card(struct kvaser_usb *dev)
        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)
 {
        struct kvaser_cmd cmd;
@@ -2027,10 +2124,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 = {
        .dev_set_mode = kvaser_usb_hydra_set_mode,
        .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_get_data_busparams = kvaser_usb_hydra_get_data_busparams,
        .dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter,
        .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints,
        .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_details = kvaser_usb_hydra_get_software_details,
        .dev_get_card_info = kvaser_usb_hydra_get_card_info,
index 50f2ac8..5225e2d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/types.h>
 #include <linux/units.h>
 #include <linux/usb.h>
+#include <linux/workqueue.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -56,6 +57,9 @@
 #define CMD_RX_EXT_MESSAGE             14
 #define CMD_TX_EXT_MESSAGE             15
 #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_CHIP_STATE_EVENT           20
 #define CMD_SET_CTRL_MODE              21
 #define CMD_RESET_CHIP                 24
 #define CMD_GET_CARD_INFO_REPLY                35
 #define CMD_GET_SOFTWARE_INFO          38
 #define CMD_GET_SOFTWARE_INFO_REPLY    39
+#define CMD_ERROR_EVENT                        45
 #define CMD_FLUSH_QUEUE                        48
 #define CMD_TX_ACKNOWLEDGE             50
 #define CMD_CAN_ERROR_EVENT            51
 #define CMD_FLUSH_QUEUE_REPLY          68
+#define CMD_GET_CAPABILITIES_REQ       95
+#define CMD_GET_CAPABILITIES_RESP      96
 
 #define CMD_LEAF_LOG_MESSAGE           106
 
@@ -83,6 +90,8 @@
 #define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
 #define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)
 
+#define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12)
+
 /* error factors */
 #define M16C_EF_ACKE                   BIT(0)
 #define M16C_EF_CRCE                   BIT(1)
@@ -157,11 +166,7 @@ struct usbcan_cmd_softinfo {
 struct kvaser_cmd_busparams {
        u8 tid;
        u8 channel;
-       __le32 bitrate;
-       u8 tseg1;
-       u8 tseg2;
-       u8 sjw;
-       u8 no_samp;
+       struct kvaser_usb_busparams busparams;
 } __packed;
 
 struct kvaser_cmd_tx_can {
@@ -230,7 +235,7 @@ struct kvaser_cmd_tx_acknowledge_header {
        u8 tid;
 } __packed;
 
-struct leaf_cmd_error_event {
+struct leaf_cmd_can_error_event {
        u8 tid;
        u8 flags;
        __le16 time[3];
@@ -242,7 +247,7 @@ struct leaf_cmd_error_event {
        u8 error_factor;
 } __packed;
 
-struct usbcan_cmd_error_event {
+struct usbcan_cmd_can_error_event {
        u8 tid;
        u8 padding;
        u8 tx_errors_count_ch0;
@@ -254,6 +259,28 @@ struct usbcan_cmd_error_event {
        __le16 time;
 } __packed;
 
+/* CMD_ERROR_EVENT error codes */
+#define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8
+#define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9
+
+struct leaf_cmd_error_event {
+       u8 tid;
+       u8 error_code;
+       __le16 timestamp[3];
+       __le16 padding;
+       __le16 info1;
+       __le16 info2;
+} __packed;
+
+struct usbcan_cmd_error_event {
+       u8 tid;
+       u8 error_code;
+       __le16 info1;
+       __le16 info2;
+       __le16 timestamp;
+       __le16 padding;
+} __packed;
+
 struct kvaser_cmd_ctrl_mode {
        u8 tid;
        u8 channel;
@@ -278,6 +305,28 @@ struct leaf_cmd_log_message {
        u8 data[8];
 } __packed;
 
+/* Sub commands for cap_req and cap_res */
+#define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02
+#define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05
+struct kvaser_cmd_cap_req {
+       __le16 padding0;
+       __le16 cap_cmd;
+       __le16 padding1;
+       __le16 channel;
+} __packed;
+
+/* Status codes for cap_res */
+#define KVASER_USB_LEAF_CAP_STAT_OK 0x00
+#define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01
+#define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02
+struct kvaser_cmd_cap_res {
+       __le16 padding;
+       __le16 cap_cmd;
+       __le16 status;
+       __le32 mask;
+       __le32 value;
+} __packed;
+
 struct kvaser_cmd {
        u8 len;
        u8 id;
@@ -293,14 +342,18 @@ struct kvaser_cmd {
                        struct leaf_cmd_softinfo softinfo;
                        struct leaf_cmd_rx_can rx_can;
                        struct leaf_cmd_chip_state_event chip_state_event;
-                       struct leaf_cmd_error_event error_event;
+                       struct leaf_cmd_can_error_event can_error_event;
                        struct leaf_cmd_log_message log_message;
+                       struct leaf_cmd_error_event error_event;
+                       struct kvaser_cmd_cap_req cap_req;
+                       struct kvaser_cmd_cap_res cap_res;
                } __packed leaf;
 
                union {
                        struct usbcan_cmd_softinfo softinfo;
                        struct usbcan_cmd_rx_can rx_can;
                        struct usbcan_cmd_chip_state_event chip_state_event;
+                       struct usbcan_cmd_can_error_event can_error_event;
                        struct usbcan_cmd_error_event error_event;
                } __packed usbcan;
 
@@ -323,7 +376,10 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
        [CMD_RX_EXT_MESSAGE]            = kvaser_fsize(u.leaf.rx_can),
        [CMD_LEAF_LOG_MESSAGE]          = kvaser_fsize(u.leaf.log_message),
        [CMD_CHIP_STATE_EVENT]          = kvaser_fsize(u.leaf.chip_state_event),
-       [CMD_CAN_ERROR_EVENT]           = kvaser_fsize(u.leaf.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_BUS_PARAMS_REPLY]      = kvaser_fsize(u.busparams),
+       [CMD_ERROR_EVENT]               = kvaser_fsize(u.leaf.error_event),
        /* ignored events: */
        [CMD_FLUSH_QUEUE_REPLY]         = CMD_SIZE_ANY,
 };
@@ -337,7 +393,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
        [CMD_RX_STD_MESSAGE]            = kvaser_fsize(u.usbcan.rx_can),
        [CMD_RX_EXT_MESSAGE]            = kvaser_fsize(u.usbcan.rx_can),
        [CMD_CHIP_STATE_EVENT]          = kvaser_fsize(u.usbcan.chip_state_event),
-       [CMD_CAN_ERROR_EVENT]           = kvaser_fsize(u.usbcan.error_event),
+       [CMD_CAN_ERROR_EVENT]           = kvaser_fsize(u.usbcan.can_error_event),
+       [CMD_ERROR_EVENT]               = kvaser_fsize(u.usbcan.error_event),
        /* ignored events: */
        [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
 };
@@ -365,6 +422,15 @@ struct kvaser_usb_err_summary {
        };
 };
 
+struct kvaser_usb_net_leaf_priv {
+       struct kvaser_usb_net_priv *net;
+
+       struct delayed_work chip_state_req_work;
+
+       /* started but not reported as bus-on yet */
+       bool joining_bus;
+};
+
 static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
        .name = "kvaser_usb_ucii",
        .tseg1_min = 4,
@@ -606,6 +672,9 @@ 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);
 
+       if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP)
+               dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP;
+
        if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
                /* Firmware expects bittiming parameters calculated for 16MHz
                 * clock, regardless of the actual clock
@@ -693,6 +762,116 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
        return 0;
 }
 
+static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
+                                                u16 cap_cmd_req, u16 *status)
+{
+       struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
+       struct kvaser_cmd *cmd;
+       u32 value = 0;
+       u32 mask = 0;
+       u16 cap_cmd_res;
+       int err;
+       int i;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->id = CMD_GET_CAPABILITIES_REQ;
+       cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
+       cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req);
+
+       err = kvaser_usb_send_cmd(dev, cmd, cmd->len);
+       if (err)
+               goto end;
+
+       err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd);
+       if (err)
+               goto end;
+
+       *status = le16_to_cpu(cmd->u.leaf.cap_res.status);
+
+       if (*status != KVASER_USB_LEAF_CAP_STAT_OK)
+               goto end;
+
+       cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd);
+       switch (cap_cmd_res) {
+       case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+       case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+               value = le32_to_cpu(cmd->u.leaf.cap_res.value);
+               mask = le32_to_cpu(cmd->u.leaf.cap_res.mask);
+               break;
+       default:
+               dev_warn(&dev->intf->dev, "Unknown capability command %u\n",
+                        cap_cmd_res);
+               break;
+       }
+
+       for (i = 0; i < dev->nchannels; i++) {
+               if (BIT(i) & (value & mask)) {
+                       switch (cap_cmd_res) {
+                       case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+                               card_data->ctrlmode_supported |=
+                                               CAN_CTRLMODE_LISTENONLY;
+                               break;
+                       case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+                               card_data->capabilities |=
+                                               KVASER_USB_CAP_BERR_CAP;
+                               break;
+                       }
+               }
+       }
+
+end:
+       kfree(cmd);
+
+       return err;
+}
+
+static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
+{
+       int err;
+       u16 status;
+
+       if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
+               dev_info(&dev->intf->dev,
+                        "No extended capability support. Upgrade device firmware.\n");
+               return 0;
+       }
+
+       err = kvaser_usb_leaf_get_single_capability(dev,
+                                                   KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
+                                                   &status);
+       if (err)
+               return err;
+       if (status)
+               dev_info(&dev->intf->dev,
+                        "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
+                        status);
+
+       err = kvaser_usb_leaf_get_single_capability(dev,
+                                                   KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
+                                                   &status);
+       if (err)
+               return err;
+       if (status)
+               dev_info(&dev->intf->dev,
+                        "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n",
+                        status);
+
+       return 0;
+}
+
+static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
+{
+       int err = 0;
+
+       if (dev->driver_info->family == KVASER_LEAF)
+               err = kvaser_usb_leaf_get_capabilities_leaf(dev);
+
+       return err;
+}
+
 static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
                                           const struct kvaser_cmd *cmd)
 {
@@ -721,7 +900,7 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
        context = &priv->tx_contexts[tid % dev->max_tx_urbs];
 
        /* Sometimes the state change doesn't come after a bus-off event */
-       if (priv->can.restart_ms && priv->can.state >= CAN_STATE_BUS_OFF) {
+       if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) {
                struct sk_buff *skb;
                struct can_frame *cf;
 
@@ -774,11 +953,22 @@ static int kvaser_usb_leaf_simple_cmd_async(struct kvaser_usb_net_priv *priv,
        return err;
 }
 
+static void kvaser_usb_leaf_chip_state_req_work(struct work_struct *work)
+{
+       struct kvaser_usb_net_leaf_priv *leaf =
+               container_of(work, struct kvaser_usb_net_leaf_priv,
+                            chip_state_req_work.work);
+       struct kvaser_usb_net_priv *priv = leaf->net;
+
+       kvaser_usb_leaf_simple_cmd_async(priv, CMD_GET_CHIP_STATE);
+}
+
 static void
 kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
                                        const struct kvaser_usb_err_summary *es,
                                        struct can_frame *cf)
 {
+       struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
        struct kvaser_usb *dev = priv->dev;
        struct net_device_stats *stats = &priv->netdev->stats;
        enum can_state cur_state, new_state, tx_state, rx_state;
@@ -792,20 +982,32 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
                new_state = CAN_STATE_BUS_OFF;
        } else if (es->status & M16C_STATE_BUS_PASSIVE) {
                new_state = CAN_STATE_ERROR_PASSIVE;
-       } else if (es->status & M16C_STATE_BUS_ERROR) {
+       } else if ((es->status & M16C_STATE_BUS_ERROR) &&
+                  cur_state >= CAN_STATE_BUS_OFF) {
                /* Guard against spurious error events after a busoff */
-               if (cur_state < CAN_STATE_BUS_OFF) {
-                       if (es->txerr >= 128 || es->rxerr >= 128)
-                               new_state = CAN_STATE_ERROR_PASSIVE;
-                       else if (es->txerr >= 96 || es->rxerr >= 96)
-                               new_state = CAN_STATE_ERROR_WARNING;
-                       else if (cur_state > CAN_STATE_ERROR_ACTIVE)
-                               new_state = CAN_STATE_ERROR_ACTIVE;
-               }
+       } else if (es->txerr >= 128 || es->rxerr >= 128) {
+               new_state = CAN_STATE_ERROR_PASSIVE;
+       } else if (es->txerr >= 96 || es->rxerr >= 96) {
+               new_state = CAN_STATE_ERROR_WARNING;
+       } else {
+               new_state = CAN_STATE_ERROR_ACTIVE;
        }
 
-       if (!es->status)
-               new_state = CAN_STATE_ERROR_ACTIVE;
+       /* 0bfd:0124 FW 4.18.778 was observed to send the initial
+        * CMD_CHIP_STATE_EVENT after CMD_START_CHIP with M16C_STATE_BUS_OFF
+        * bit set if the channel was bus-off when it was last stopped (even
+        * across chip resets). This bit will clear shortly afterwards, without
+        * triggering a second unsolicited chip state event.
+        * Ignore this initial bus-off.
+        */
+       if (leaf->joining_bus) {
+               if (new_state == CAN_STATE_BUS_OFF) {
+                       netdev_dbg(priv->netdev, "ignoring bus-off during startup");
+                       new_state = cur_state;
+               } else {
+                       leaf->joining_bus = false;
+               }
+       }
 
        if (new_state != cur_state) {
                tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
@@ -815,7 +1017,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
        }
 
        if (priv->can.restart_ms &&
-           cur_state >= CAN_STATE_BUS_OFF &&
+           cur_state == CAN_STATE_BUS_OFF &&
            new_state < CAN_STATE_BUS_OFF)
                priv->can.can_stats.restarts++;
 
@@ -849,6 +1051,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
        struct sk_buff *skb;
        struct net_device_stats *stats;
        struct kvaser_usb_net_priv *priv;
+       struct kvaser_usb_net_leaf_priv *leaf;
        enum can_state old_state, new_state;
 
        if (es->channel >= dev->nchannels) {
@@ -858,8 +1061,13 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
        }
 
        priv = dev->nets[es->channel];
+       leaf = priv->sub_priv;
        stats = &priv->netdev->stats;
 
+       /* Ignore e.g. state change to bus-off reported just after stopping */
+       if (!netif_running(priv->netdev))
+               return;
+
        /* Update all of the CAN interface's state and error counters before
         * trying any memory allocation that can actually fail with -ENOMEM.
         *
@@ -874,6 +1082,17 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
        kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf);
        new_state = priv->can.state;
 
+       /* If there are errors, request status updates periodically as we do
+        * not get automatic notifications of improved state.
+        * Also request updates if we saw a stale BUS_OFF during startup
+        * (joining_bus).
+        */
+       if (new_state < CAN_STATE_BUS_OFF &&
+           (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE ||
+            leaf->joining_bus))
+               schedule_delayed_work(&leaf->chip_state_req_work,
+                                     msecs_to_jiffies(500));
+
        skb = alloc_can_err_skb(priv->netdev, &cf);
        if (!skb) {
                stats->rx_dropped++;
@@ -891,7 +1110,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
                }
 
                if (priv->can.restart_ms &&
-                   old_state >= CAN_STATE_BUS_OFF &&
+                   old_state == CAN_STATE_BUS_OFF &&
                    new_state < CAN_STATE_BUS_OFF) {
                        cf->can_id |= CAN_ERR_RESTARTED;
                        netif_carrier_on(priv->netdev);
@@ -990,11 +1209,11 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev,
 
        case CMD_CAN_ERROR_EVENT:
                es.channel = 0;
-               es.status = cmd->u.usbcan.error_event.status_ch0;
-               es.txerr = cmd->u.usbcan.error_event.tx_errors_count_ch0;
-               es.rxerr = cmd->u.usbcan.error_event.rx_errors_count_ch0;
+               es.status = cmd->u.usbcan.can_error_event.status_ch0;
+               es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0;
+               es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0;
                es.usbcan.other_ch_status =
-                       cmd->u.usbcan.error_event.status_ch1;
+                       cmd->u.usbcan.can_error_event.status_ch1;
                kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
 
                /* The USBCAN firmware supports up to 2 channels.
@@ -1002,13 +1221,13 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev,
                 */
                if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
                        es.channel = 1;
-                       es.status = cmd->u.usbcan.error_event.status_ch1;
+                       es.status = cmd->u.usbcan.can_error_event.status_ch1;
                        es.txerr =
-                               cmd->u.usbcan.error_event.tx_errors_count_ch1;
+                               cmd->u.usbcan.can_error_event.tx_errors_count_ch1;
                        es.rxerr =
-                               cmd->u.usbcan.error_event.rx_errors_count_ch1;
+                               cmd->u.usbcan.can_error_event.rx_errors_count_ch1;
                        es.usbcan.other_ch_status =
-                               cmd->u.usbcan.error_event.status_ch0;
+                               cmd->u.usbcan.can_error_event.status_ch0;
                        kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
                }
                break;
@@ -1025,11 +1244,11 @@ static void kvaser_usb_leaf_leaf_rx_error(const struct kvaser_usb *dev,
 
        switch (cmd->id) {
        case CMD_CAN_ERROR_EVENT:
-               es.channel = cmd->u.leaf.error_event.channel;
-               es.status = cmd->u.leaf.error_event.status;
-               es.txerr = cmd->u.leaf.error_event.tx_errors_count;
-               es.rxerr = cmd->u.leaf.error_event.rx_errors_count;
-               es.leaf.error_factor = cmd->u.leaf.error_event.error_factor;
+               es.channel = cmd->u.leaf.can_error_event.channel;
+               es.status = cmd->u.leaf.can_error_event.status;
+               es.txerr = cmd->u.leaf.can_error_event.tx_errors_count;
+               es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count;
+               es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor;
                break;
        case CMD_LEAF_LOG_MESSAGE:
                es.channel = cmd->u.leaf.log_message.channel;
@@ -1162,6 +1381,74 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
        netif_rx(skb);
 }
 
+static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev,
+                                                 const struct kvaser_cmd *cmd)
+{
+       u16 info1 = 0;
+
+       switch (dev->driver_info->family) {
+       case KVASER_LEAF:
+               info1 = le16_to_cpu(cmd->u.leaf.error_event.info1);
+               break;
+       case KVASER_USBCAN:
+               info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1);
+               break;
+       }
+
+       /* info1 will contain the offending cmd_no */
+       switch (info1) {
+       case CMD_SET_CTRL_MODE:
+               dev_warn(&dev->intf->dev,
+                        "CMD_SET_CTRL_MODE error in parameter\n");
+               break;
+
+       case CMD_SET_BUS_PARAMS:
+               dev_warn(&dev->intf->dev,
+                        "CMD_SET_BUS_PARAMS error in parameter\n");
+               break;
+
+       default:
+               dev_warn(&dev->intf->dev,
+                        "Unhandled parameter error event cmd_no (%u)\n",
+                        info1);
+               break;
+       }
+}
+
+static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev,
+                                       const struct kvaser_cmd *cmd)
+{
+       u8 error_code = 0;
+
+       switch (dev->driver_info->family) {
+       case KVASER_LEAF:
+               error_code = cmd->u.leaf.error_event.error_code;
+               break;
+       case KVASER_USBCAN:
+               error_code = cmd->u.usbcan.error_event.error_code;
+               break;
+       }
+
+       switch (error_code) {
+       case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL:
+               /* Received additional CAN message, when firmware TX queue is
+                * already full. Something is wrong with the driver.
+                * This should never happen!
+                */
+               dev_err(&dev->intf->dev,
+                       "Received error event TX_QUEUE_FULL\n");
+               break;
+       case KVASER_USB_LEAF_ERROR_EVENT_PARAM:
+               kvaser_usb_leaf_error_event_parameter(dev, cmd);
+               break;
+
+       default:
+               dev_warn(&dev->intf->dev,
+                        "Unhandled error event (%d)\n", error_code);
+               break;
+       }
+}
+
 static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev,
                                             const struct kvaser_cmd *cmd)
 {
@@ -1202,6 +1489,25 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
        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,
                                           const struct kvaser_cmd *cmd)
 {
@@ -1240,6 +1546,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
                kvaser_usb_leaf_tx_acknowledge(dev, cmd);
                break;
 
+       case CMD_ERROR_EVENT:
+               kvaser_usb_leaf_error_event(dev, cmd);
+               break;
+
+       case CMD_GET_BUS_PARAMS_REPLY:
+               kvaser_usb_leaf_get_busparams_reply(dev, cmd);
+               break;
+
        /* Ignored commands */
        case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
                if (dev->driver_info->family != KVASER_USBCAN)
@@ -1318,8 +1632,11 @@ static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv)
 
 static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv)
 {
+       struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
        int err;
 
+       leaf->joining_bus = true;
+
        init_completion(&priv->start_comp);
 
        err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP,
@@ -1336,10 +1653,13 @@ static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv)
 
 static int kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv *priv)
 {
+       struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
        int err;
 
        init_completion(&priv->stop_comp);
 
+       cancel_delayed_work(&leaf->chip_state_req_work);
+
        err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP,
                                              priv->channel);
        if (err)
@@ -1386,10 +1706,35 @@ static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev)
        return 0;
 }
 
-static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
+static int kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv *priv)
+{
+       struct kvaser_usb_net_leaf_priv *leaf;
+
+       leaf = devm_kzalloc(&priv->dev->intf->dev, sizeof(*leaf), GFP_KERNEL);
+       if (!leaf)
+               return -ENOMEM;
+
+       leaf->net = priv;
+       INIT_DELAYED_WORK(&leaf->chip_state_req_work,
+                         kvaser_usb_leaf_chip_state_req_work);
+
+       priv->sub_priv = leaf;
+
+       return 0;
+}
+
+static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv)
+{
+       struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
+
+       if (leaf)
+               cancel_delayed_work_sync(&leaf->chip_state_req_work);
+}
+
+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 can_bittiming *bt = &priv->can.bittiming;
        struct kvaser_usb *dev = priv->dev;
        struct kvaser_cmd *cmd;
        int rc;
@@ -1402,15 +1747,8 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
        cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams);
        cmd->u.busparams.channel = priv->channel;
        cmd->u.busparams.tid = 0xff;
-       cmd->u.busparams.bitrate = cpu_to_le32(bt->bitrate);
-       cmd->u.busparams.sjw = bt->sjw;
-       cmd->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
-       cmd->u.busparams.tseg2 = bt->phase_seg2;
-
-       if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
-               cmd->u.busparams.no_samp = 3;
-       else
-               cmd->u.busparams.no_samp = 1;
+       memcpy(&cmd->u.busparams.busparams, busparams,
+              sizeof(cmd->u.busparams.busparams));
 
        rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
 
@@ -1418,16 +1756,40 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
        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,
                                    enum can_mode mode)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+       struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
        int err;
 
        switch (mode) {
        case CAN_MODE_START:
                kvaser_usb_unlink_tx_urbs(priv);
 
+               leaf->joining_bus = true;
+
                err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
                if (err)
                        return err;
@@ -1479,14 +1841,18 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
 const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
        .dev_set_mode = kvaser_usb_leaf_set_mode,
        .dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
+       .dev_get_busparams = kvaser_usb_leaf_get_busparams,
        .dev_set_data_bittiming = NULL,
+       .dev_get_data_busparams = NULL,
        .dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
        .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
        .dev_init_card = kvaser_usb_leaf_init_card,
+       .dev_init_channel = kvaser_usb_leaf_init_channel,
+       .dev_remove_channel = kvaser_usb_leaf_remove_channel,
        .dev_get_software_info = kvaser_usb_leaf_get_software_info,
        .dev_get_software_details = NULL,
        .dev_get_card_info = kvaser_usb_leaf_get_card_info,
-       .dev_get_capabilities = NULL,
+       .dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
        .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
        .dev_start_chip = kvaser_usb_leaf_start_chip,
        .dev_stop_chip = kvaser_usb_leaf_stop_chip,
index 7c35f50..a1734f1 100644 (file)
@@ -245,7 +245,8 @@ struct ucan_message_in {
                /* CAN transmission complete
                 * (type == UCAN_IN_TX_COMPLETE)
                 */
-               struct ucan_tx_complete_entry_t can_tx_complete_msg[0];
+               DECLARE_FLEX_ARRAY(struct ucan_tx_complete_entry_t,
+                                  can_tx_complete_msg);
        } __aligned(0x4) msg;
 } __packed __aligned(0x4);
 
@@ -1581,7 +1582,7 @@ static void ucan_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
 
        if (up) {
-               unregister_netdev(up->netdev);
+               unregister_candev(up->netdev);
                free_candev(up->netdev);
        }
 }
index d7d86c9..6ec48a4 100644 (file)
@@ -985,7 +985,7 @@ static int j1939_session_tx_eoma(struct j1939_session *session)
        /* wait for the EOMA packet to come in */
        j1939_tp_set_rxtimeout(session, 1250);
 
-       netdev_dbg(session->priv->ndev, "%p: 0x%p\n", __func__, session);
+       netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session);
 
        return 0;
 }