From 3e51a3356cb2a1a35c07607f93d79484b1496bbf Mon Sep 17 00:00:00 2001 From: Alexander Gerasiov Date: Fri, 1 Apr 2016 19:16:45 +0300 Subject: [PATCH 01/12] can: sja1000: Fix error location forwarding According to SJA1000 documentation the location of error is available regardless of an error type. Therefore it should always be forwarded to SocketCAN. Signed-off-by: Nikita Edward Baruzdin Signed-off-by: Alexander GQ Gerasiov Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 8dda3b703d39..9f107798f904 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -438,6 +438,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + /* set error type */ switch (ecc & ECC_MASK) { case ECC_BIT: cf->data[2] |= CAN_ERR_PROT_BIT; @@ -449,9 +450,12 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[3] = ecc & ECC_SEG; break; } + + /* set error location */ + cf->data[3] = ecc & ECC_SEG; + /* Error occurred during transmission? */ if ((ecc & ECC_DIR) == 0) cf->data[2] |= CAN_ERR_PROT_TX; From 056a7201ac7a659880b43c2e62a5aa85ca06bebf Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Wed, 6 Apr 2016 16:04:32 +0300 Subject: [PATCH 02/12] can: sja1000: plx_pci: Add support for Marathon CAN-bus-PCIe card This patch adds support for the Marathon CAN-bus-PCIe card to the sja1000 driver. For more information see: http://can.marathon.ru/page/devices/can-bus-pcie Signed-off-by: Nikita Edward Baruzdin Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/plx_pci.c | 64 +++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 8836a7485c81..3eb7430dffbf 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -39,6 +39,7 @@ MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with " MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " "Adlink PCI-7841/cPCI-7841 SE, " "Marathon CAN-bus-PCI, " + "Marathon CAN-bus-PCIe, " "TEWS TECHNOLOGIES TPMC810, " "esd CAN-PCI/CPCI/PCI104/200, " "esd CAN-PCI/PMC/266, " @@ -133,6 +134,7 @@ struct plx_pci_card { #define IXXAT_PCI_SUB_SYS_ID 0x2540 #define MARATHON_PCI_DEVICE_ID 0x2715 +#define MARATHON_PCIE_DEVICE_ID 0x3432 #define TEWS_PCI_VENDOR_ID 0x1498 #define TEWS_PCI_DEVICE_ID_TMPC810 0x032A @@ -141,8 +143,9 @@ struct plx_pci_card { #define CTI_PCI_DEVICE_ID_CRG001 0x0900 static void plx_pci_reset_common(struct pci_dev *pdev); -static void plx_pci_reset_marathon(struct pci_dev *pdev); static void plx9056_pci_reset_common(struct pci_dev *pdev); +static void plx_pci_reset_marathon_pci(struct pci_dev *pdev); +static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev); struct plx_pci_channel_map { u32 bar; @@ -215,14 +218,22 @@ static struct plx_pci_card_info plx_pci_card_info_ixxat = { /* based on PLX9050 */ }; -static struct plx_pci_card_info plx_pci_card_info_marathon = { +static struct plx_pci_card_info plx_pci_card_info_marathon_pci = { "Marathon CAN-bus-PCI", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, - &plx_pci_reset_marathon + &plx_pci_reset_marathon_pci /* based on PLX9052 */ }; +static struct plx_pci_card_info plx_pci_card_info_marathon_pcie = { + "Marathon CAN-bus-PCIe", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {3, 0x80, 0x00} }, + &plx_pci_reset_marathon_pcie + /* based on PEX8311 */ +}; + static struct plx_pci_card_info plx_pci_card_info_tews = { "TEWS TECHNOLOGIES TPMC810", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, @@ -316,7 +327,14 @@ static const struct pci_device_id plx_pci_tbl[] = { PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - (kernel_ulong_t)&plx_pci_card_info_marathon + (kernel_ulong_t)&plx_pci_card_info_marathon_pci + }, + { + /* Marathon CAN-bus-PCIe card */ + PCI_VENDOR_ID_PLX, MARATHON_PCIE_DEVICE_ID, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_marathon_pcie }, { /* TEWS TECHNOLOGIES TPMC810 card */ @@ -437,8 +455,8 @@ static void plx9056_pci_reset_common(struct pci_dev *pdev) iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); }; -/* Special reset function for Marathon card */ -static void plx_pci_reset_marathon(struct pci_dev *pdev) +/* Special reset function for Marathon CAN-bus-PCI card */ +static void plx_pci_reset_marathon_pci(struct pci_dev *pdev) { void __iomem *reset_addr; int i; @@ -460,6 +478,34 @@ static void plx_pci_reset_marathon(struct pci_dev *pdev) } } +/* Special reset function for Marathon CAN-bus-PCIe card */ +static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev) +{ + void __iomem *addr; + void __iomem *reset_addr; + int i; + + plx9056_pci_reset_common(pdev); + + for (i = 0; i < 2; i++) { + struct plx_pci_channel_map *chan_map = + &plx_pci_card_info_marathon_pcie.chan_map_tbl[i]; + addr = pci_iomap(pdev, chan_map->bar, chan_map->size); + if (!addr) { + dev_err(&pdev->dev, "Failed to remap reset " + "space %d (BAR%d)\n", i, chan_map->bar); + } else { + /* reset the SJA1000 chip */ + #define MARATHON_PCIE_RESET_OFFSET 32 + reset_addr = addr + chan_map->offset + + MARATHON_PCIE_RESET_OFFSET; + iowrite8(0x1, reset_addr); + udelay(100); + pci_iounmap(pdev, addr); + } + } +} + static void plx_pci_del_card(struct pci_dev *pdev) { struct plx_pci_card *card = pci_get_drvdata(pdev); @@ -486,7 +532,8 @@ static void plx_pci_del_card(struct pci_dev *pdev) * Disable interrupts from PCI-card and disable local * interrupts */ - if (pdev->device != PCI_DEVICE_ID_PLX_9056) + if (pdev->device != PCI_DEVICE_ID_PLX_9056 && + pdev->device != MARATHON_PCIE_DEVICE_ID) iowrite32(0x0, card->conf_addr + PLX_INTCSR); else iowrite32(0x0, card->conf_addr + PLX9056_INTCSR); @@ -619,7 +666,8 @@ static int plx_pci_add_card(struct pci_dev *pdev, * Enable interrupts from PCI-card (PLX90xx) and enable Local_1, * Local_2 interrupts from the SJA1000 chips */ - if (pdev->device != PCI_DEVICE_ID_PLX_9056) { + if (pdev->device != PCI_DEVICE_ID_PLX_9056 && + pdev->device != MARATHON_PCIE_DEVICE_ID) { val = ioread32(card->conf_addr + PLX_INTCSR); if (pdev->subsystem_vendor == PCI_VENDOR_ID_ESDGMBH) val |= PLX_LINT1_EN | PLX_PCI_INT_EN; From b6fd3aba6041922e115bd8e10539b8545f4120ac Mon Sep 17 00:00:00 2001 From: Amitoj Kaur Chawla Date: Fri, 8 Apr 2016 21:02:10 +0530 Subject: [PATCH 03/12] can: mcp251x: Replace create_freezable_workqueue with alloc_workqueue Replace scheduled to be removed create_freezable_workqueue with alloc_workqueue. priv->wq should be explicitly set as freezable to ensure it is frozen in the suspend sequence and work items are drained so that no new work item starts execution until thawed. Thus, use of WQ_FREEZABLE flag here is required. WQ_MEM_RECLAIM flag has been set here to ensure forward progress regardless of memory pressure. The order of execution is not important so set @max_active as 0. Signed-off-by: Amitoj Kaur Chawla Acked-by: Tejun Heo Signed-off-by: Marc Kleine-Budde --- drivers/net/can/spi/mcp251x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 74a7dfecee27..cf36d26ef002 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -961,7 +961,8 @@ static int mcp251x_open(struct net_device *net) goto open_unlock; } - priv->wq = create_freezable_workqueue("mcp251x_wq"); + priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, + 0); INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); From bb208f144cf3f59d8f89a09a80efd04389718907 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 21 Mar 2016 20:18:21 +0100 Subject: [PATCH 04/12] can: fix handling of unmodifiable configuration options As described in 'can: m_can: tag current CAN FD controllers as non-ISO' (6cfda7fbebe) it is possible to define fixed configuration options by setting the according bit in 'ctrlmode' and clear it in 'ctrlmode_supported'. This leads to the incovenience that the fixed configuration bits can not be passed by netlink even when they have the correct values (e.g. non-ISO, FD). This patch fixes that issue and not only allows fixed set bit values to be set again but now requires(!) to provide these fixed values at configuration time. A valid CAN FD configuration consists of a nominal/arbitration bittiming, a data bittiming and a control mode with CAN_CTRLMODE_FD set - which is now enforced by a new can_validate() function. This fix additionally removed the inconsistency that was prohibiting the support of 'CANFD-only' controller drivers, like the RCar CAN FD. For this reason a new helper can_set_static_ctrlmode() has been introduced to provide a proper interface to handle static enabled CAN controller options. Reported-by: Ramesh Shanmugasundaram Signed-off-by: Oliver Hartkopp Reviewed-by: Ramesh Shanmugasundaram Cc: # >= 3.18 Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 56 ++++++++++++++++++++++++++++++++--- drivers/net/can/m_can/m_can.c | 2 +- include/linux/can/dev.h | 22 ++++++++++++-- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 141c2a42d7ed..910c12e2638e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -696,11 +696,17 @@ int can_change_mtu(struct net_device *dev, int new_mtu) /* allow change of MTU according to the CANFD ability of the device */ switch (new_mtu) { case CAN_MTU: + /* 'CANFD-only' controllers can not switch to CAN_MTU */ + if (priv->ctrlmode_static & CAN_CTRLMODE_FD) + return -EINVAL; + priv->ctrlmode &= ~CAN_CTRLMODE_FD; break; case CANFD_MTU: - if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) + /* check for potential CANFD ability */ + if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) && + !(priv->ctrlmode_static & CAN_CTRLMODE_FD)) return -EINVAL; priv->ctrlmode |= CAN_CTRLMODE_FD; @@ -782,6 +788,35 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming_const) }, }; +static int can_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + bool is_can_fd = false; + + /* Make sure that valid CAN FD configurations always consist of + * - nominal/arbitration bittiming + * - data bittiming + * - control mode with CAN_CTRLMODE_FD set + */ + + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); + + is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; + } + + if (is_can_fd) { + if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) + return -EOPNOTSUPP; + } + + if (data[IFLA_CAN_DATA_BITTIMING]) { + if (!is_can_fd || !data[IFLA_CAN_BITTIMING]) + return -EOPNOTSUPP; + } + + return 0; +} + static int can_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { @@ -813,19 +848,31 @@ static int can_changelink(struct net_device *dev, if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm; + u32 ctrlstatic; + u32 maskedflags; /* Do not allow changing controller mode while running */ if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); + ctrlstatic = priv->ctrlmode_static; + maskedflags = cm->flags & cm->mask; - /* check whether changed bits are allowed to be modified */ - if (cm->mask & ~priv->ctrlmode_supported) + /* check whether provided bits are allowed to be passed */ + if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic)) + return -EOPNOTSUPP; + + /* do not check for static fd-non-iso if 'fd' is disabled */ + if (!(maskedflags & CAN_CTRLMODE_FD)) + ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; + + /* make sure static options are provided by configuration */ + if ((maskedflags & ctrlstatic) != ctrlstatic) return -EOPNOTSUPP; /* clear bits to be modified and copy the flag values */ priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= (cm->flags & cm->mask); + priv->ctrlmode |= maskedflags; /* CAN_CTRLMODE_FD can only be set when driver supports FD */ if (priv->ctrlmode & CAN_CTRLMODE_FD) @@ -966,6 +1013,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = { .maxtype = IFLA_CAN_MAX, .policy = can_policy, .setup = can_setup, + .validate = can_validate, .newlink = can_newlink, .changelink = can_changelink, .get_size = can_get_size, diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 39cf911f7a1e..195f15edb32e 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -955,7 +955,7 @@ static struct net_device *alloc_m_can_dev(void) priv->can.do_get_berr_counter = m_can_get_berr_counter; /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ - priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 735f9f8c4e43..5261751f6bd4 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -40,8 +40,11 @@ struct can_priv { struct can_clock clock; enum can_state state; - u32 ctrlmode; - u32 ctrlmode_supported; + + /* CAN controller features - see include/uapi/linux/can/netlink.h */ + u32 ctrlmode; /* current options setting */ + u32 ctrlmode_supported; /* options that can be modified by netlink */ + u32 ctrlmode_static; /* static enabled options for driver/hardware */ int restart_ms; struct timer_list restart_timer; @@ -108,6 +111,21 @@ static inline bool can_is_canfd_skb(const struct sk_buff *skb) return skb->len == CANFD_MTU; } +/* helper to define static CAN controller features at device creation time */ +static inline void can_set_static_ctrlmode(struct net_device *dev, + u32 static_mode) +{ + struct can_priv *priv = netdev_priv(dev); + + /* alloc_candev() succeeded => netdev_priv() is valid at this point */ + priv->ctrlmode = static_mode; + priv->ctrlmode_static = static_mode; + + /* override MTU which was set by default in can_setup()? */ + if (static_mode & CAN_CTRLMODE_FD) + dev->mtu = CANFD_MTU; +} + /* get data length from can_dlc with sanitized can_dlc */ u8 can_dlc2len(u8 can_dlc); From b16e368ed6193d8d1774b4cc874d7892d55c4780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=B6ger?= Date: Fri, 6 May 2016 10:04:37 +0200 Subject: [PATCH 05/12] can: janz-ican3: error handling for CAL/CANopen firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My patch of May 2015 was missing the changed handling of error indications. With CAL/CANopen firmware the NMTS-SlaveEventIndication must be used instead of CAN-EventIndication. An appropriate slave node must be configured to report the errors. In our department (about 15 development systems with Janz ICAN3- modules with firmware 1.48, my system also with firmware ICANOS 1.35) we use the driver with this patch for about one year: no known problems. Signed-off-by: Andreas Gröger Signed-off-by: Marc Kleine-Budde --- drivers/net/can/janz-ican3.c | 104 ++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 9 deletions(-) diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 5d04f5464faf..f13bb8d9bb84 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -84,6 +84,7 @@ #define MSG_COFFREQ 0x42 #define MSG_CONREQ 0x43 #define MSG_CCONFREQ 0x47 +#define MSG_NMTS 0xb0 #define MSG_LMTS 0xb4 /* @@ -130,6 +131,22 @@ #define ICAN3_CAN_DLC_MASK 0x0f +/* Janz ICAN3 NMTS subtypes */ +#define NMTS_CREATE_NODE_REQ 0x0 +#define NMTS_SLAVE_STATE_IND 0x8 +#define NMTS_SLAVE_EVENT_IND 0x9 + +/* Janz ICAN3 LMTS subtypes */ +#define LMTS_BUSON_REQ 0x0 +#define LMTS_BUSOFF_REQ 0x1 +#define LMTS_CAN_CONF_REQ 0x2 + +/* Janz ICAN3 NMTS Event indications */ +#define NE_LOCAL_OCCURRED 0x3 +#define NE_LOCAL_RESOLVED 0x2 +#define NE_REMOTE_OCCURRED 0xc +#define NE_REMOTE_RESOLVED 0x8 + /* * SJA1000 Status and Error Register Definitions * @@ -800,21 +817,41 @@ static int ican3_set_bus_state(struct ican3_dev *mod, bool on) return ican3_send_msg(mod, &msg); } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { + /* bittiming + can-on/off request */ memset(&msg, 0, sizeof(msg)); msg.spec = MSG_LMTS; if (on) { msg.len = cpu_to_le16(4); - msg.data[0] = 0; + msg.data[0] = LMTS_BUSON_REQ; msg.data[1] = 0; msg.data[2] = btr0; msg.data[3] = btr1; } else { msg.len = cpu_to_le16(2); - msg.data[0] = 1; + msg.data[0] = LMTS_BUSOFF_REQ; msg.data[1] = 0; } + res = ican3_send_msg(mod, &msg); + if (res) + return res; - return ican3_send_msg(mod, &msg); + if (on) { + /* create NMT Slave Node for error processing + * class 2 (with error capability, see CiA/DS203-1) + * id 1 + * name locnod1 (must be exactly 7 bytes) + */ + memset(&msg, 0, sizeof(msg)); + msg.spec = MSG_NMTS; + msg.len = cpu_to_le16(11); + msg.data[0] = NMTS_CREATE_NODE_REQ; + msg.data[1] = 0; + msg.data[2] = 2; /* node class */ + msg.data[3] = 1; /* node id */ + strcpy(msg.data + 4, "locnod1"); /* node name */ + return ican3_send_msg(mod, &msg); + } + return 0; } return -ENOTSUPP; } @@ -849,12 +886,23 @@ static int ican3_set_buserror(struct ican3_dev *mod, u8 quota) { struct ican3_msg msg; - memset(&msg, 0, sizeof(msg)); - msg.spec = MSG_CCONFREQ; - msg.len = cpu_to_le16(2); - msg.data[0] = 0x00; - msg.data[1] = quota; - + if (mod->fwtype == ICAN3_FWTYPE_ICANOS) { + memset(&msg, 0, sizeof(msg)); + msg.spec = MSG_CCONFREQ; + msg.len = cpu_to_le16(2); + msg.data[0] = 0x00; + msg.data[1] = quota; + } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { + memset(&msg, 0, sizeof(msg)); + msg.spec = MSG_LMTS; + msg.len = cpu_to_le16(4); + msg.data[0] = LMTS_CAN_CONF_REQ; + msg.data[1] = 0x00; + msg.data[2] = 0x00; + msg.data[3] = quota; + } else { + return -ENOTSUPP; + } return ican3_send_msg(mod, &msg); } @@ -1150,6 +1198,41 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) } } +/* Handle NMTS Slave Event Indication Messages from the firmware */ +static void ican3_handle_nmtsind(struct ican3_dev *mod, struct ican3_msg *msg) +{ + u16 subspec; + + subspec = msg->data[0] + msg->data[1] * 0x100; + if (subspec == NMTS_SLAVE_EVENT_IND) { + switch (msg->data[2]) { + case NE_LOCAL_OCCURRED: + case NE_LOCAL_RESOLVED: + /* now follows the same message as Raw ICANOS CEVTIND + * shift the data at the same place and call this method + */ + le16_add_cpu(&msg->len, -3); + memmove(msg->data, msg->data + 3, le16_to_cpu(msg->len)); + ican3_handle_cevtind(mod, msg); + break; + case NE_REMOTE_OCCURRED: + case NE_REMOTE_RESOLVED: + /* should not occurre, ignore */ + break; + default: + netdev_warn(mod->ndev, "unknown NMTS event indication %x\n", + msg->data[2]); + break; + } + } else if (subspec == NMTS_SLAVE_STATE_IND) { + /* ignore state indications */ + } else { + netdev_warn(mod->ndev, "unhandled NMTS indication %x\n", + subspec); + return; + } +} + static void ican3_handle_unknown_message(struct ican3_dev *mod, struct ican3_msg *msg) { @@ -1179,6 +1262,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) case MSG_INQUIRY: ican3_handle_inquiry(mod, msg); break; + case MSG_NMTS: + ican3_handle_nmtsind(mod, msg); + break; default: ican3_handle_unknown_message(mod, msg); break; From 2fe6c943147c5bb0550f5c3e941de3824986330e Mon Sep 17 00:00:00 2001 From: Maximilian Schneider Date: Mon, 25 Apr 2016 08:54:19 +0000 Subject: [PATCH 06/12] can: gs_usb: modify the usb device table to use only the first usb interface Modified the USB device table to use only the first USB interface, as is the case with GS USB devices. This allows other GS USB compatible devices to be more flexible with their remaining interfaces. Signed-off-by: Maximilian Schneider Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/gs_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index cbc99d5649af..1556d4286235 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -950,7 +950,8 @@ static void gs_usb_disconnect(struct usb_interface *intf) } static const struct usb_device_id gs_usb_table[] = { - {USB_DEVICE(USB_GSUSB_1_VENDOR_ID, USB_GSUSB_1_PRODUCT_ID)}, + { USB_DEVICE_INTERFACE_NUMBER(USB_GSUSB_1_VENDOR_ID, + USB_GSUSB_1_PRODUCT_ID, 0) }, {} /* Terminating entry */ }; From 496c798db0b81af67572a2052ea30504c863235f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:11 +0200 Subject: [PATCH 07/12] can: ifi: Start NAPI poll on bus warning too Start the NAPI polling in case the bus warning interrupt happens, since it is the poll function which checks and reports the warning. Signed-off-by: Marek Vasut Cc: Marc Kleine-Budde Cc: Mark Rutland Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index a1bd54ffd31e..1ad05f1ab942 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -497,7 +497,8 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) struct ifi_canfd_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | - IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER; + IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | + IFI_CANFD_INTERRUPT_ERROR_WARNING; const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ | @@ -513,7 +514,7 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) /* Clear all pending interrupts but ErrWarn */ writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT); - /* RX IRQ, start NAPI */ + /* RX IRQ or bus warning, start NAPI */ if (isr & rx_irq_mask) { ifi_canfd_irq_enable(ndev, 0); napi_schedule(&priv->napi); From be1861320a9ec599b6862ebb71db9bd3ad897150 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:12 +0200 Subject: [PATCH 08/12] can: ifi: Update timing configuration code The updated documentation regarding the IFI CANFD core from April 2016 adds more details regarding the timing calculation. There is no longer any distinction in the timing calculation between CANFD and CAN2.0, but instead there are two timing modes -- 4_12_6_6 and 7_9_8_8 -- where the numbers mean the width in bits of the SJW/Prescaler/TimeA/TimeB fields. The code uses 7_9_8_8 mode, which allows more fine-grained control over the timing. Signed-off-by: Marek Vasut Cc: Marc Kleine-Budde Cc: Mark Rutland Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 54 +++++++++++---------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 1ad05f1ab942..b9efd6ec04c9 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -34,6 +34,7 @@ #define IFI_CANFD_STCMD_LOOPBACK BIT(18) #define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) #define IFI_CANFD_STCMD_ENABLE_ISO BIT(25) +#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING BIT(26) #define IFI_CANFD_STCMD_NORMAL_MODE ((u32)BIT(31)) #define IFI_CANFD_RXSTCMD 0x4 @@ -71,12 +72,12 @@ #define IFI_CANFD_TIME_TIMEB_OFF 0 #define IFI_CANFD_TIME_TIMEA_OFF 8 #define IFI_CANFD_TIME_PRESCALE_OFF 16 -#define IFI_CANFD_TIME_SJW_OFF_ISO 25 -#define IFI_CANFD_TIME_SJW_OFF_BOSCH 28 -#define IFI_CANFD_TIME_SET_SJW_BOSCH BIT(6) -#define IFI_CANFD_TIME_SET_TIMEB_BOSCH BIT(7) -#define IFI_CANFD_TIME_SET_PRESC_BOSCH BIT(14) -#define IFI_CANFD_TIME_SET_TIMEA_BOSCH BIT(15) +#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8 25 +#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6 28 +#define IFI_CANFD_TIME_SET_SJW_4_12_6_6 BIT(6) +#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6 BIT(7) +#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6 BIT(14) +#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6 BIT(15) #define IFI_CANFD_TDELAY 0x1c @@ -534,24 +535,24 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) static const struct can_bittiming_const ifi_canfd_bittiming_const = { .name = KBUILD_MODNAME, .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ - .tseg1_max = 64, + .tseg1_max = 256, .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ - .tseg2_max = 64, - .sjw_max = 16, + .tseg2_max = 256, + .sjw_max = 128, .brp_min = 2, - .brp_max = 256, + .brp_max = 512, .brp_inc = 1, }; static const struct can_bittiming_const ifi_canfd_data_bittiming_const = { .name = KBUILD_MODNAME, .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ - .tseg1_max = 64, + .tseg1_max = 256, .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ - .tseg2_max = 64, - .sjw_max = 16, + .tseg2_max = 256, + .sjw_max = 128, .brp_min = 2, - .brp_max = 256, + .brp_max = 512, .brp_inc = 1, }; @@ -561,19 +562,6 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) const struct can_bittiming *bt = &priv->can.bittiming; const struct can_bittiming *dbt = &priv->can.data_bittiming; u16 brp, sjw, tseg1, tseg2; - u32 noniso_arg = 0; - u32 time_off; - - if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && - !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) { - time_off = IFI_CANFD_TIME_SJW_OFF_ISO; - } else { - noniso_arg = IFI_CANFD_TIME_SET_TIMEB_BOSCH | - IFI_CANFD_TIME_SET_TIMEA_BOSCH | - IFI_CANFD_TIME_SET_PRESC_BOSCH | - IFI_CANFD_TIME_SET_SJW_BOSCH; - time_off = IFI_CANFD_TIME_SJW_OFF_BOSCH; - } /* Configure bit timing */ brp = bt->brp - 2; @@ -583,8 +571,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | (brp << IFI_CANFD_TIME_PRESCALE_OFF) | - (sjw << time_off) | - noniso_arg, + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), priv->base + IFI_CANFD_TIME); /* Configure data bit timing */ @@ -595,8 +582,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | (brp << IFI_CANFD_TIME_PRESCALE_OFF) | - (sjw << time_off) | - noniso_arg, + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), priv->base + IFI_CANFD_FTIME); } @@ -641,7 +627,8 @@ static void ifi_canfd_start(struct net_device *ndev) /* Reset the IP */ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD); - writel(0, priv->base + IFI_CANFD_STCMD); + writel(IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING, + priv->base + IFI_CANFD_STCMD); ifi_canfd_set_bittiming(ndev); ifi_canfd_set_filters(ndev); @@ -660,7 +647,8 @@ static void ifi_canfd_start(struct net_device *ndev) writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ), priv->base + IFI_CANFD_INTERRUPT); - stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE; + stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE | + IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING; if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) stcmd |= IFI_CANFD_STCMD_BUSMONITOR; From 478ad12c9f5a2f5a1d39fc898b098992980d3abc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:13 +0200 Subject: [PATCH 09/12] can: ifi: Unify timing constants There is no distinction between bittiming constants for the slow and fast part of the CANFD operation on this controller, so just use one single bittiming constant set. Signed-off-by: Marek Vasut Cc: Marc Kleine-Budde Cc: Mark Rutland Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index b9efd6ec04c9..30dc3b676627 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -544,18 +544,6 @@ static const struct can_bittiming_const ifi_canfd_bittiming_const = { .brp_inc = 1, }; -static const struct can_bittiming_const ifi_canfd_data_bittiming_const = { - .name = KBUILD_MODNAME, - .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ - .tseg1_max = 256, - .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ - .tseg2_max = 256, - .sjw_max = 128, - .brp_min = 2, - .brp_max = 512, - .brp_inc = 1, -}; - static void ifi_canfd_set_bittiming(struct net_device *ndev) { struct ifi_canfd_priv *priv = netdev_priv(ndev); @@ -866,7 +854,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK); priv->can.bittiming_const = &ifi_canfd_bittiming_const; - priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const; + priv->can.data_bittiming_const = &ifi_canfd_bittiming_const; priv->can.do_set_mode = ifi_canfd_set_mode; priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter; From ca79408986bf250c22f3130c333787ec44c4d103 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:14 +0200 Subject: [PATCH 10/12] can: ifi: Treat CAN_CTRLMODE_FD_NON_ISO correctly The CAN_CTRLMODE_FD flag is set for both ISO and BOSCH CANFD mode, while the CAN_CTRLMODE_FD_NON_ISO is additional flag which is only set for CANFD-BOSCH mode. Fix the handling of the flags to reflect this. Signed-off-by: Marek Vasut Cc: Marc Kleine-Budde Cc: Mark Rutland Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Reviewed-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 30dc3b676627..5bd95dd5cb88 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -644,10 +644,11 @@ static void ifi_canfd_start(struct net_device *ndev) if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) stcmd |= IFI_CANFD_STCMD_LOOPBACK; - if (priv->can.ctrlmode & CAN_CTRLMODE_FD) + if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && + !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) stcmd |= IFI_CANFD_STCMD_ENABLE_ISO; - if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO))) + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD; priv->can.state = CAN_STATE_ERROR_ACTIVE; From 1acd80fb982728b8bf467184d5ec4c5a77a5601b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:15 +0200 Subject: [PATCH 11/12] can: ifi: Increment TX counters only on real transmission Only increment the TX counters in the irq handler if a CAN message was sent. The current code incremented the counters also if the TX FIFO empty interrupt happened, which is incorrect. Signed-off-by: Marek Vasut Cc: Marc Kleine-Budde Cc: Mark Rutland Cc: Oliver Hartkopp Cc: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 5bd95dd5cb88..ba6cd43e1bc6 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -522,13 +522,15 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) } /* TX IRQ */ - if (isr & tx_irq_mask) { + if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) { stats->tx_bytes += can_get_echo_skb(ndev, 0); stats->tx_packets++; can_led_event(ndev, CAN_LED_EVENT_TX); - netif_wake_queue(ndev); } + if (isr & tx_irq_mask) + netif_wake_queue(ndev); + return IRQ_HANDLED; } From 5bbd655a8bd000579d135ddf30660f759db89996 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 8 May 2016 00:34:16 +0200 Subject: [PATCH 12/12] can: ifi: Add more detailed error reporting The updated specification for the IFI CANFD core contains description of more detailed error reporting capability of the core. Implement support for this detailed error reporting. Signed-off-by: Marek Vasut Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 113 ++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index ba6cd43e1bc6..2d1d22eec750 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -52,7 +52,8 @@ #define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) #define IFI_CANFD_INTERRUPT 0xc -#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1)) +#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) +#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) #define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) #define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) #define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24) @@ -103,7 +104,26 @@ #define IFI_CANFD_RES1 0x40 -#define IFI_CANFD_RES2 0x44 +#define IFI_CANFD_ERROR_CTR 0x44 +#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899 +#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0) +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1) +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2) +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3) +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4) +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5) +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6) +#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8) +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9) +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10) +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11) +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12) +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13) +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14) +#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16 +#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0xff +#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30) +#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31)) #define IFI_CANFD_PAR 0x48 @@ -197,6 +217,8 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable) if (enable) { enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER; } writel(IFI_CANFD_IRQMASK_SET_ERR | @@ -335,6 +357,68 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev) return 1; } +static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr) +{ + struct ifi_canfd_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST | + IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST; + + if (!(errctr & errmask)) /* No error happened. */ + return 0; + + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + /* Propagate the error condition to the CAN stack. */ + skb = alloc_can_err_skb(ndev, &cf); + if (unlikely(!skb)) + return 0; + + /* Read the error counter register and check for new errors. */ + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) + cf->data[2] |= CAN_ERR_PROT_OVERLOAD; + + if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) + cf->data[3] = CAN_ERR_PROT_LOC_ACK; + + if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_BIT0; + + if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_BIT1; + + if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_STUFF; + + if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + + if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_FORM; + + /* Reset the error counter, ack the IRQ and re-enable the counter. */ + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_INTERRUPT_ERROR_COUNTER, + priv->base + IFI_CANFD_INTERRUPT); + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); + + return 1; +} + static int ifi_canfd_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { @@ -470,6 +554,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD); + u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); /* Handle bus state changes */ if ((stcmd & stcmd_state_mask) || @@ -480,6 +565,10 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) work_done += ifi_canfd_handle_lost_msg(ndev); + /* Handle lec errors on the bus */ + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + work_done += ifi_canfd_handle_lec_err(ndev, errctr); + /* Handle normal messages on RX */ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done); @@ -499,11 +588,12 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) struct net_device_stats *stats = &ndev->stats; const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | - IFI_CANFD_INTERRUPT_ERROR_WARNING; + IFI_CANFD_INTERRUPT_ERROR_WARNING | + IFI_CANFD_INTERRUPT_ERROR_COUNTER; const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; - const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ | - IFI_CANFD_INTERRUPT_ERROR_WARNING); + const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ | + IFI_CANFD_INTERRUPT_ERROR_WARNING)); u32 isr; isr = readl(priv->base + IFI_CANFD_INTERRUPT); @@ -657,6 +747,12 @@ static void ifi_canfd_start(struct net_device *ndev) ifi_canfd_irq_enable(ndev, 1); + /* Unlock, reset and enable the error counter. */ + writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC, + priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + /* Enable controller */ writel(stcmd, priv->base + IFI_CANFD_STCMD); } @@ -665,6 +761,10 @@ static void ifi_canfd_stop(struct net_device *ndev) { struct ifi_canfd_priv *priv = netdev_priv(ndev); + /* Reset and disable the error counter. */ + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(0, priv->base + IFI_CANFD_ERROR_CTR); + /* Reset the IP */ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD); @@ -868,7 +968,8 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD | - CAN_CTRLMODE_FD_NON_ISO; + CAN_CTRLMODE_FD_NON_ISO | + CAN_CTRLMODE_BERR_REPORTING; platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, dev);