* [PATCH 1/5] net: can: Sort the Kconfig includes
@ 2016-01-11 18:47 Marek Vasut
2016-01-11 18:48 ` [PATCH 2/5] net: can: Sort the Makefile Marek Vasut
` (3 more replies)
0 siblings, 4 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 18:47 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
Sort the Kconfig includes, no functional change.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
drivers/net/can/Kconfig | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 6d04183..ca49d15 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -147,22 +147,22 @@ config CAN_XILINXCAN
Xilinx CAN driver. This driver supports both soft AXI CAN IP and
Zynq CANPS IP.
-source "drivers/net/can/mscan/Kconfig"
-
-source "drivers/net/can/sja1000/Kconfig"
-
source "drivers/net/can/c_can/Kconfig"
+source "drivers/net/can/cc770/Kconfig"
+
source "drivers/net/can/m_can/Kconfig"
-source "drivers/net/can/cc770/Kconfig"
+source "drivers/net/can/mscan/Kconfig"
+
+source "drivers/net/can/sja1000/Kconfig"
+
+source "drivers/net/can/softing/Kconfig"
source "drivers/net/can/spi/Kconfig"
source "drivers/net/can/usb/Kconfig"
-source "drivers/net/can/softing/Kconfig"
-
endif
config CAN_DEBUG_DEVICES
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/5] net: can: Sort the Makefile
2016-01-11 18:47 [PATCH 1/5] net: can: Sort the Kconfig includes Marek Vasut
@ 2016-01-11 18:48 ` Marek Vasut
2016-01-11 18:48 ` [PATCH 3/5] of: Add vendor prefix for I/F/I Marek Vasut
` (2 subsequent siblings)
3 siblings, 0 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 18:48 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
Just sort the drivers in the Makefile, no functional change.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
drivers/net/can/Makefile | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 1f21cef..4f85c2b 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -14,21 +14,21 @@ obj-y += spi/
obj-y += usb/
obj-y += softing/
-obj-$(CONFIG_CAN_SJA1000) += sja1000/
-obj-$(CONFIG_CAN_MSCAN) += mscan/
-obj-$(CONFIG_CAN_C_CAN) += c_can/
-obj-$(CONFIG_CAN_M_CAN) += m_can/
-obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o
-obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
-obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
+obj-$(CONFIG_CAN_CC770) += cc770/
+obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
-obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
+obj-$(CONFIG_CAN_MSCAN) += mscan/
+obj-$(CONFIG_CAN_M_CAN) += m_can/
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
+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-y += -D__CHECK_ENDIAN__
subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/5] of: Add vendor prefix for I/F/I
2016-01-11 18:47 [PATCH 1/5] net: can: Sort the Kconfig includes Marek Vasut
2016-01-11 18:48 ` [PATCH 2/5] net: can: Sort the Makefile Marek Vasut
@ 2016-01-11 18:48 ` Marek Vasut
2016-01-11 18:48 ` [PATCH 4/5] net: can: ifi: Add DT bindings for ifi,canfd Marek Vasut
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
3 siblings, 0 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 18:48 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
Add vendor prefix for I/F/I, Ingenieurbüro Für IC-Technologie
http://www.ifi-pld.de/
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 55df1d4..e683e61 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -110,6 +110,7 @@ hp Hewlett Packard
i2se I2SE GmbH
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
+ifi Ingenieurburo Fur Ic-Technologie (I/F/I)
iom Iomega Corporation
img Imagination Technologies Ltd.
ingenic Ingenic Semiconductor
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/5] net: can: ifi: Add DT bindings for ifi,canfd
2016-01-11 18:47 [PATCH 1/5] net: can: Sort the Kconfig includes Marek Vasut
2016-01-11 18:48 ` [PATCH 2/5] net: can: Sort the Makefile Marek Vasut
2016-01-11 18:48 ` [PATCH 3/5] of: Add vendor prefix for I/F/I Marek Vasut
@ 2016-01-11 18:48 ` Marek Vasut
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
3 siblings, 0 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 18:48 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
Add device tree bindings for the I/F/I CANFD controller IP core.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
Documentation/devicetree/bindings/net/can/ifi_canfd.txt | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/can/ifi_canfd.txt
diff --git a/Documentation/devicetree/bindings/net/can/ifi_canfd.txt b/Documentation/devicetree/bindings/net/can/ifi_canfd.txt
new file mode 100644
index 0000000..20ea5c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/ifi_canfd.txt
@@ -0,0 +1,15 @@
+IFI CANFD controller
+--------------------
+
+Required properties:
+ - compatible: Should be "ifi,canfd-1.0"
+ - reg: Should contain CAN controller registers location and length
+ - interrupts: Should contain IRQ line for the CAN controller
+
+Example:
+
+ canfd0: canfd@ff220000 {
+ compatible = "ifi,canfd-1.0";
+ reg = <0xff220000 0x00001000>;
+ interrupts = <0 43 0>;
+ };
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-11 18:47 [PATCH 1/5] net: can: Sort the Kconfig includes Marek Vasut
` (2 preceding siblings ...)
2016-01-11 18:48 ` [PATCH 4/5] net: can: ifi: Add DT bindings for ifi,canfd Marek Vasut
@ 2016-01-11 18:48 ` Marek Vasut
2016-01-11 19:29 ` kbuild test robot
` (2 more replies)
3 siblings, 3 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 18:48 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
The patch adds support for IFI CAN/FD controller [1]. This driver
currently supports sending and receiving both standard CAN and new
CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
[1] http://www.ifi-pld.de/IP/CANFD/canfd.html
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
NOTE: The driver is surprisingly similar to m_can, but the register
layout of the IFI core is completely different, so it's clear
that those are two different IP cores.
---
drivers/net/can/Kconfig | 2 +
drivers/net/can/Makefile | 1 +
drivers/net/can/ifi_canfd/Kconfig | 8 +
drivers/net/can/ifi_canfd/Makefile | 5 +
drivers/net/can/ifi_canfd/ifi_canfd.c | 914 ++++++++++++++++++++++++++++++++++
5 files changed, 930 insertions(+)
create mode 100644 drivers/net/can/ifi_canfd/Kconfig
create mode 100644 drivers/net/can/ifi_canfd/Makefile
create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index ca49d15..20be638 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -151,6 +151,8 @@ source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
+source "drivers/net/can/ifi_canfd/Kconfig"
+
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 4f85c2b..e3db0c8 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/
diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
new file mode 100644
index 0000000..9e8934f
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Kconfig
@@ -0,0 +1,8 @@
+config CAN_IFI_CANFD
+ depends on HAS_IOMEM
+ tristate "IFI CAN_FD IP"
+ ---help---
+ This driver adds support for the I/F/I CAN_FD soft IP block
+ connected to the "platform bus" (Linux abstraction for directly
+ to the processor attached devices). The CAN_FD is most often
+ synthesised into an FPGA or CPLD.
diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
new file mode 100644
index 0000000..b229960
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IFI CANFD controller driver.
+#
+
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
new file mode 100644
index 0000000..b1167ff
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -0,0 +1,914 @@
+/*
+ * CAN bus driver for IFI CANFD controller
+ *
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Details about this controller can be found at
+ * http://www.ifi-pld.de/IP/CANFD/canfd.html
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+#define IFI_CANFD_STCMD 0x0
+#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD
+#define IFI_CANFD_STCMD_ENABLE BIT(0)
+#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
+#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
+#define IFI_CANFD_STCMD_BUSOFF BIT(4)
+#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
+#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_NORMAL_MODE BIT(31)
+
+#define IFI_CANFD_RXSTCMD 0x4
+#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0)
+#define IFI_CANFD_RXSTCMD_RESET BIT(7)
+#define IFI_CANFD_RXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_TXSTCMD 0x8
+#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0)
+#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1)
+#define IFI_CANFD_TXSTCMD_RESET BIT(7)
+#define IFI_CANFD_TXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_TXSTCMD_FULL BIT(12)
+#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_INTERRUPT 0xc
+#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
+#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25)
+#define IFI_CANFD_INTERRUPT_SET_IRQ BIT(31)
+
+#define IFI_CANFD_IRQMASK 0x10
+#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
+#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
+#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_IRQMASK_SET_TX BIT(23)
+#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_IRQMASK_SET_RX BIT(31)
+
+#define IFI_CANFD_TIME 0x14
+#define IFI_CANFD_FTIME 0x18
+#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_TDELAY 0x1c
+
+#define IFI_CANFD_ERROR 0x20
+#define IFI_CANFD_ERROR_TX_OFFSET 0
+#define IFI_CANFD_ERROR_TX_MASK 0xff
+#define IFI_CANFD_ERROR_RX_OFFSET 16
+#define IFI_CANFD_ERROR_RX_MASK 0xff
+
+#define IFI_CANFD_ERRCNT 0x24
+
+#define IFI_CANFD_SUSPEND 0x28
+
+#define IFI_CANFD_REPEAT 0x2c
+
+#define IFI_CANFD_TRAFFIC 0x30
+
+#define IFI_CANFD_TSCONTROL 0x34
+
+#define IFI_CANFD_TSC 0x38
+
+#define IFI_CANFD_TST 0x3c
+
+#define IFI_CANFD_RES1 0x40
+
+#define IFI_CANFD_RES2 0x44
+
+#define IFI_CANFD_PAR 0x48
+
+#define IFI_CANFD_CANCLOCK 0x4c
+
+#define IFI_CANFD_SYSCLOCK 0x50
+
+#define IFI_CANFD_VER 0x54
+
+#define IFI_CANFD_IP_ID 0x58
+#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD
+
+#define IFI_CANFD_TEST 0x5c
+
+#define IFI_CANFD_RXFIFO_TS_63_32 0x60
+
+#define IFI_CANFD_RXFIFO_TS_31_0 0x64
+
+#define IFI_CANFD_RXFIFO_DLC 0x68
+#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7)
+#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8
+#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff
+#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_RXFIFO_ID 0x6c
+#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
+
+#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0
+
+#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4
+
+#define IFI_CANFD_TXFIFO_DLC 0xb8
+#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_TXFIFO_ID 0xbc
+#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
+
+#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0)
+#define IFI_CANFD_FILTER_MASK_EXT BIT(29)
+#define IFI_CANFD_FILTER_MASK_EDL BIT(30)
+#define IFI_CANFD_FILTER_MASK_VALID BIT(31)
+
+#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4)
+#define IFI_CANFD_FILTER_IDENT_IDE BIT(29)
+#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30)
+#define IFI_CANFD_FILTER_IDENT_VALID BIT(31)
+
+/* IFI CANFD private data structure */
+struct ifi_canfd_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *ndev;
+ struct device *device;
+ void __iomem *base;
+};
+
+static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 enirq = 0;
+
+ if (enable) {
+ enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
+ IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
+ }
+
+ writel(IFI_CANFD_IRQMASK_SET_ERR |
+ IFI_CANFD_IRQMASK_SET_TS |
+ IFI_CANFD_IRQMASK_SET_TX |
+ IFI_CANFD_IRQMASK_SET_RX | enirq,
+ priv->base + IFI_CANFD_IRQMASK);
+}
+
+static void ifi_canfd_read_fifo(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf;
+ struct sk_buff *skb;
+ const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
+ IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
+ u32 rxdlc, rxid;
+ u32 dlc, id;
+ int i;
+
+ rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ skb = alloc_canfd_skb(ndev, &cf);
+ else
+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
+
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
+ IFI_CANFD_RXFIFO_DLC_DLC_MASK;
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ cf->len = can_dlc2len(dlc);
+ else
+ cf->len = get_can_dlc(dlc);
+
+ rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
+ id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
+ if (id & IFI_CANFD_RXFIFO_ID_IDE)
+ id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
+ else
+ id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
+ cf->can_id = id;
+
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(ndev, "ESI Error\n");
+ }
+
+ if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
+ (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
+ cf->flags |= CANFD_BRS;
+
+ for (i = 0; i < cf->len; i += 4) {
+ *(u32 *)(cf->data + i) =
+ readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
+ }
+ }
+
+ /* Remove the packet from FIFO */
+ writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
+ writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+
+ netif_receive_skb(skb);
+}
+
+static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 pkts = 0;
+ u32 rxst;
+
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
+ netdev_dbg(ndev, "No messages in RX FIFO\n");
+ return 0;
+ }
+
+ for (;;) {
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
+ break;
+ if (quota <= 0)
+ break;
+
+ ifi_canfd_read_fifo(ndev);
+ quota--;
+ pkts++;
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ }
+
+ if (pkts)
+ can_led_event(ndev, CAN_LED_EVENT_RX);
+
+ return pkts;
+}
+
+static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
+
+ stats->rx_errors++;
+ stats->rx_over_errors++;
+
+ skb = alloc_can_err_skb(ndev, &frame);
+ if (unlikely(!skb))
+ return 0;
+
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
+ struct can_berr_counter *bec)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 err;
+
+ err = readl(priv->base + IFI_CANFD_ERROR);
+ bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
+ IFI_CANFD_ERROR_RX_MASK;
+ bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
+ IFI_CANFD_ERROR_TX_MASK;
+
+ return 0;
+}
+
+static int ifi_canfd_handle_state_change(struct net_device *ndev,
+ enum can_state new_state)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct can_berr_counter bec;
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ ifi_canfd_irq_enable(ndev, 0);
+ priv->can.can_stats.bus_off++;
+ can_bus_off(ndev);
+ break;
+ default:
+ break;
+ }
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ ifi_canfd_get_berr_counter(ndev, &bec);
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ cf->can_id |= CAN_ERR_BUSOFF;
+ break;
+ default:
+ break;
+ }
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int work_done = 0;
+ u32 isr;
+
+ /*
+ * The ErrWarn condition is a little special, since the bit is
+ * located in the INTERRUPT register instead of STCMD register.
+ */
+ isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+ if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
+ (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+ /* Clear the interrupt */
+ writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
+ priv->base + IFI_CANFD_INTERRUPT);
+ netdev_dbg(ndev, "Error, entered warning state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_WARNING);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
+ (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+ netdev_dbg(ndev, "Error, entered passive state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_PASSIVE);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
+ (priv->can.state != CAN_STATE_BUS_OFF)) {
+ netdev_dbg(ndev, "Error, entered bus-off state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_BUS_OFF);
+ }
+
+ return work_done;
+}
+
+static int ifi_canfd_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
+ IFI_CANFD_STCMD_BUSOFF;
+ int work_done = 0;
+
+ u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
+ u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
+
+ /* Handle bus state changes */
+ if ((stcmd & stcmd_state_mask) ||
+ ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
+ work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
+
+ /* Handle lost messages on RX */
+ if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
+ work_done += ifi_canfd_handle_lost_msg(ndev);
+
+ /* Handle normal messages on RX */
+ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
+ work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ ifi_canfd_irq_enable(ndev, 1);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)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;
+ 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);
+ u32 isr;
+
+ isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+
+ /* No interrupt */
+ if (isr == 0)
+ return IRQ_NONE;
+
+ /* Clear all pending interrupts but ErrWarn */
+ writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ /* RX IRQ, start NAPI */
+ if (isr & rx_irq_mask) {
+ ifi_canfd_irq_enable(ndev, 0);
+ napi_schedule(&priv->napi);
+ }
+
+ /* TX IRQ */
+ if (isr & tx_irq_mask) {
+ stats->tx_bytes += can_get_echo_skb(ndev, 0);
+ stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+ netif_wake_queue(ndev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const ifi_canfd_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 64,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static const struct can_bittiming_const ifi_canfd_data_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 32,
+ .brp_inc = 1,
+};
+
+static void ifi_canfd_set_bittiming(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(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_NON_ISO) {
+ 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;
+ } else {
+ time_off = IFI_CANFD_TIME_SJW_OFF_ISO;
+ }
+
+ /* Configure bit timing */
+ brp = bt->brp - 1;
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off),
+ priv->base + IFI_CANFD_TIME);
+
+ /* Configure data bit timing */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off) |
+ noniso_arg,
+ priv->base + IFI_CANFD_FTIME);
+}
+
+static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
+ const u32 mask, const u32 ident)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id));
+ writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id));
+}
+
+static void ifi_canfd_set_filters(struct net_device *ndev)
+{
+ /* Receive all CAN frames (standard ID) */
+ ifi_canfd_set_filter(ndev, 0,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID);
+
+ /* Receive all CAN frames (extended ID) */
+ ifi_canfd_set_filter(ndev, 1,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_IDE);
+
+ /* Receive all CANFD frames */
+ ifi_canfd_set_filter(ndev, 2,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EDL |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_CANFD |
+ IFI_CANFD_FILTER_IDENT_IDE);
+}
+
+static void ifi_canfd_start(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 stcmd;
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+ writel(0, priv->base + IFI_CANFD_STCMD);
+
+ ifi_canfd_set_bittiming(ndev);
+ ifi_canfd_set_filters(ndev);
+
+ /* Reset FIFOs */
+ writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
+ writel(0, priv->base + IFI_CANFD_RXSTCMD);
+ writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
+ writel(0, priv->base + IFI_CANFD_TXSTCMD);
+
+ /* Repeat transmission until successful */
+ writel(0, priv->base + IFI_CANFD_REPEAT);
+ writel(0, priv->base + IFI_CANFD_SUSPEND);
+
+ /* Clear all pending interrupts */
+ writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
+
+ stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ stcmd |= IFI_CANFD_STCMD_LOOPBACK;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
+
+ if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)))
+ stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ ifi_canfd_irq_enable(ndev, 1);
+
+ /* Enable controller */
+ writel(stcmd, priv->base + IFI_CANFD_STCMD);
+}
+
+static void ifi_canfd_stop(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+
+ /* Disable all interrupts */
+ ifi_canfd_irq_enable(ndev, 0);
+
+ /* Clear all pending interrupts */
+ writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
+
+ /* Set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ ifi_canfd_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ifi_canfd_open(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int err;
+
+ err = open_candev(ndev);
+ if (err) {
+ netdev_err(ndev, "Failed to open CAN device\n");
+ return err;
+ }
+
+ ifi_canfd_start(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+static int ifi_canfd_close(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+
+ ifi_canfd_stop(ndev);
+
+ close_candev(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ u32 txst, txid;
+ u32 txdlc = 0;
+ int i;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ /* Check if the TX buffer is full */
+ txst = readl(priv->base + IFI_CANFD_TXSTCMD);
+ if (txst & IFI_CANFD_TXSTCMD_FULL) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "BUG! TX FIFO full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ netif_stop_queue(ndev);
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ txid = cf->can_id & CAN_EFF_MASK;
+ txid |= IFI_CANFD_TXFIFO_ID_IDE;
+ } else {
+ txid = cf->can_id & CAN_SFF_MASK;
+ }
+
+ if (priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)) {
+ if (can_is_canfd_skb(skb)) {
+ txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
+ if (cf->flags & CANFD_BRS)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_BRS;
+ }
+ }
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_RTR;
+
+ /* message ram configuration */
+ writel(txid, priv->base + IFI_CANFD_TXFIFO_ID);
+ writel(txdlc, priv->base + IFI_CANFD_TXFIFO_DLC);
+
+ for (i = 0; i < cf->len; i += 4) {
+ writel(*(u32 *)(cf->data + i),
+ priv->base + IFI_CANFD_TXFIFO_DATA + i);
+ }
+
+ writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
+ writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
+
+ can_put_echo_skb(skb, ndev, 0);
+
+ /* Start the transmission */
+ writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ifi_canfd_netdev_ops = {
+ .ndo_open = ifi_canfd_open,
+ .ndo_stop = ifi_canfd_close,
+ .ndo_start_xmit = ifi_canfd_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static int ifi_canfd_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct net_device *ndev;
+ struct ifi_canfd_priv *priv;
+ struct resource *res;
+ void __iomem *addr;
+ int irq, ret;
+ u32 id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(dev, res);
+ irq = platform_get_irq(pdev, 0);
+ if (IS_ERR(addr) || irq < 0)
+ return -EINVAL;
+
+ id = readl(addr + IFI_CANFD_IP_ID);
+ if (id != IFI_CANFD_IP_ID_VALUE) {
+ dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
+ return -EINVAL;
+ }
+
+ ndev = alloc_candev(sizeof(*priv), 1);
+ if (!ndev)
+ return -ENOMEM;
+
+ ndev->irq = irq;
+ ndev->flags |= IFF_ECHO; /* we support local echo */
+ ndev->netdev_ops = &ifi_canfd_netdev_ops;
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->base = addr;
+ priv->device = dev;
+
+ netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ priv->can.clock.freq = readl(addr + IFI_CANFD_SYSCLOCK);
+
+ priv->can.bittiming_const = &ifi_canfd_bittiming_const;
+ priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const;
+ priv->can.do_set_mode = ifi_canfd_set_mode;
+ priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode = CAN_CTRLMODE_FD;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_FD |
+ CAN_CTRLMODE_FD_NON_ISO;
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, dev);
+
+ /* register interrupt handler */
+ ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED,
+ ndev->name, ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "Failed to request interrupt\n");
+ goto err_irq;
+ }
+
+ ret = register_candev(ndev);
+ if (ret) {
+ dev_err(dev, "Failed to register (ret=%d)\n", ret);
+ goto err_reg;
+ }
+
+ devm_can_led_init(ndev);
+
+ dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
+ priv->base, ndev->irq, priv->can.clock.freq);
+
+ return 0;
+
+err_reg:
+ free_irq(ndev->irq, ndev);
+err_irq:
+ free_candev(ndev);
+ return ret;
+}
+
+static int ifi_canfd_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_candev(ndev);
+ platform_set_drvdata(pdev, NULL);
+ free_candev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id ifi_canfd_of_table[] = {
+ { .compatible = "ifi,canfd-1.0", .data = NULL },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ifi_canfd_of_table);
+
+static struct platform_driver ifi_canfd_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = ifi_canfd_of_table,
+ },
+ .probe = ifi_canfd_plat_probe,
+ .remove = ifi_canfd_plat_remove,
+};
+
+module_platform_driver(ifi_canfd_plat_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller");
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
@ 2016-01-11 19:29 ` kbuild test robot
2016-01-11 19:33 ` Marek Vasut
2016-01-12 11:06 ` kbuild test robot
2016-01-12 23:59 ` [PATCH V2 " Marek Vasut
2 siblings, 1 reply; 22+ messages in thread
From: kbuild test robot @ 2016-01-11 19:29 UTC (permalink / raw)
To: Marek Vasut
Cc: kbuild-all, netdev, Marc Kleine-Budde, Oliver Hartkopp,
Marek Vasut, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 2453 bytes --]
Hi Marek,
[auto build test WARNING on net/master]
[also build test WARNING on v4.4 next-20160111]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Marek-Vasut/net-can-Sort-the-Kconfig-includes/20160112-025020
config: x86_64-allmodconfig (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_isr':
>> drivers/net/can/ifi_canfd/ifi_canfd.c:486:27: warning: large integer implicitly truncated to unsigned type [-Woverflow]
const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
^
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_start':
drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: large integer implicitly truncated to unsigned type [-Woverflow]
writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
^
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_stop':
drivers/net/can/ifi_canfd/ifi_canfd.c:675:9: warning: large integer implicitly truncated to unsigned type [-Woverflow]
writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
^
vim +486 drivers/net/can/ifi_canfd/ifi_canfd.c
470 napi_complete(napi);
471 ifi_canfd_irq_enable(ndev, 1);
472 }
473
474 return work_done;
475 }
476
477 static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
478 {
479 struct net_device *ndev = (struct net_device *)dev_id;
480 struct ifi_canfd_priv *priv = netdev_priv(ndev);
481 struct net_device_stats *stats = &ndev->stats;
482 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
483 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
484 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
485 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
> 486 const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
487 IFI_CANFD_INTERRUPT_ERROR_WARNING);
488 u32 isr;
489
490 isr = readl(priv->base + IFI_CANFD_INTERRUPT);
491
492 /* No interrupt */
493 if (isr == 0)
494 return IRQ_NONE;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 51054 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-11 19:29 ` kbuild test robot
@ 2016-01-11 19:33 ` Marek Vasut
0 siblings, 0 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-11 19:33 UTC (permalink / raw)
To: kbuild test robot
Cc: kbuild-all, netdev, Marc Kleine-Budde, Oliver Hartkopp,
Mark Rutland, Wolfgang Grandegger
On Monday, January 11, 2016 at 08:29:28 PM, kbuild test robot wrote:
> Hi Marek,
Hi Robot,
> [auto build test WARNING on net/master]
> [also build test WARNING on v4.4 next-20160111]
> [if your patch is applied to the wrong git tree, please drop us a note to
> help improving the system]
>
> url:
> https://github.com/0day-ci/linux/commits/Marek-Vasut/net-can-Sort-the-Kcon
> fig-includes/20160112-025020 config: x86_64-allmodconfig (attached as
> .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> All warnings (new ones prefixed by >>):
>
> drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_isr':
> >> drivers/net/can/ifi_canfd/ifi_canfd.c:486:27: warning: large integer
> >> implicitly truncated to unsigned type [-Woverflow]
>
> const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
> ^
> drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_start':
> drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: large integer
> implicitly truncated to unsigned type [-Woverflow]
> writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT); ^
> drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_stop':
> drivers/net/can/ifi_canfd/ifi_canfd.c:675:9: warning: large integer
> implicitly truncated to unsigned type [-Woverflow]
> writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT); ^
How did this splat came to be ? I would expect that the expansion goes like
this:
const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
IFI_CANFD_INTERRUPT_ERROR_WARNING);
const u32 clr_irq_mask = ~(BIT(31) | BIT(1));
const u32 clr_irq_mask = ~(0x80000002);
const u32 clr_irq_mask = 0x7ffffffd;
Did I miss something there ?
Thanks!
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
2016-01-11 19:29 ` kbuild test robot
@ 2016-01-12 11:06 ` kbuild test robot
2016-01-12 23:59 ` [PATCH V2 " Marek Vasut
2 siblings, 0 replies; 22+ messages in thread
From: kbuild test robot @ 2016-01-12 11:06 UTC (permalink / raw)
To: Marek Vasut
Cc: kbuild-all, netdev, Marc Kleine-Budde, Oliver Hartkopp,
Marek Vasut, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 3361 bytes --]
Hi Marek,
[auto build test WARNING on net/master]
[also build test WARNING on v4.4 next-20160111]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Marek-Vasut/net-can-Sort-the-Kconfig-includes/20160112-025020
config: ia64-allmodconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=ia64
All warnings (new ones prefixed by >>):
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_isr':
drivers/net/can/ifi_canfd/ifi_canfd.c:486:27: warning: large integer implicitly truncated to unsigned type [-Woverflow]
const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
^
In file included from arch/ia64/include/asm/smp.h:20:0,
from include/linux/smp.h:59,
from include/linux/sched.h:34,
from arch/ia64/include/asm/delay.h:16,
from include/linux/delay.h:14,
from drivers/net/can/ifi_canfd/ifi_canfd.c:15:
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_start':
arch/ia64/include/asm/io.h:394:30: warning: large integer implicitly truncated to unsigned type [-Woverflow]
#define writel(v,a) __writel((v), (a))
^
>> drivers/net/can/ifi_canfd/ifi_canfd.c:640:2: note: in expansion of macro 'writel'
writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
^
drivers/net/can/ifi_canfd/ifi_canfd.c: In function 'ifi_canfd_stop':
arch/ia64/include/asm/io.h:394:30: warning: large integer implicitly truncated to unsigned type [-Woverflow]
#define writel(v,a) __writel((v), (a))
^
drivers/net/can/ifi_canfd/ifi_canfd.c:675:2: note: in expansion of macro 'writel'
writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
^
vim +/writel +640 drivers/net/can/ifi_canfd/ifi_canfd.c
624 writel(0, priv->base + IFI_CANFD_STCMD);
625
626 ifi_canfd_set_bittiming(ndev);
627 ifi_canfd_set_filters(ndev);
628
629 /* Reset FIFOs */
630 writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
631 writel(0, priv->base + IFI_CANFD_RXSTCMD);
632 writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
633 writel(0, priv->base + IFI_CANFD_TXSTCMD);
634
635 /* Repeat transmission until successful */
636 writel(0, priv->base + IFI_CANFD_REPEAT);
637 writel(0, priv->base + IFI_CANFD_SUSPEND);
638
639 /* Clear all pending interrupts */
> 640 writel(~IFI_CANFD_INTERRUPT_SET_IRQ, priv->base + IFI_CANFD_INTERRUPT);
641
642 stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
643
644 if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
645 stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
646
647 if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
648 stcmd |= IFI_CANFD_STCMD_LOOPBACK;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 41724 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
2016-01-11 19:29 ` kbuild test robot
2016-01-12 11:06 ` kbuild test robot
@ 2016-01-12 23:59 ` Marek Vasut
2016-01-20 10:39 ` Marc Kleine-Budde
2 siblings, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-12 23:59 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
The patch adds support for IFI CAN/FD controller [1]. This driver
currently supports sending and receiving both standard CAN and new
CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
[1] http://www.ifi-pld.de/IP/CANFD/canfd.html
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
V2: - Move request_irq()/free_irq() into ifi_canfd_open()/ifi_canfd_close()
just like other drivers do it to prevent crash when reloading module.
- Fix Woverflow complains on x86_64 and itanium, exactly the same way
as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
NOTE: The driver is surprisingly similar to m_can, but the register
layout of the IFI core is completely different, so it's clear
that those are two different IP cores.
---
drivers/net/can/Kconfig | 2 +
drivers/net/can/Makefile | 1 +
drivers/net/can/ifi_canfd/Kconfig | 8 +
drivers/net/can/ifi_canfd/Makefile | 5 +
drivers/net/can/ifi_canfd/ifi_canfd.c | 919 ++++++++++++++++++++++++++++++++++
5 files changed, 935 insertions(+)
create mode 100644 drivers/net/can/ifi_canfd/Kconfig
create mode 100644 drivers/net/can/ifi_canfd/Makefile
create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index ca49d15..20be638 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -151,6 +151,8 @@ source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
+source "drivers/net/can/ifi_canfd/Kconfig"
+
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 4f85c2b..e3db0c8 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/
diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
new file mode 100644
index 0000000..9e8934f
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Kconfig
@@ -0,0 +1,8 @@
+config CAN_IFI_CANFD
+ depends on HAS_IOMEM
+ tristate "IFI CAN_FD IP"
+ ---help---
+ This driver adds support for the I/F/I CAN_FD soft IP block
+ connected to the "platform bus" (Linux abstraction for directly
+ to the processor attached devices). The CAN_FD is most often
+ synthesised into an FPGA or CPLD.
diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
new file mode 100644
index 0000000..b229960
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IFI CANFD controller driver.
+#
+
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
new file mode 100644
index 0000000..094c36b
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -0,0 +1,919 @@
+/*
+ * CAN bus driver for IFI CANFD controller
+ *
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Details about this controller can be found at
+ * http://www.ifi-pld.de/IP/CANFD/canfd.html
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+#define IFI_CANFD_STCMD 0x0
+#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD
+#define IFI_CANFD_STCMD_ENABLE BIT(0)
+#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
+#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
+#define IFI_CANFD_STCMD_BUSOFF BIT(4)
+#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
+#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_NORMAL_MODE BIT(31)
+
+#define IFI_CANFD_RXSTCMD 0x4
+#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0)
+#define IFI_CANFD_RXSTCMD_RESET BIT(7)
+#define IFI_CANFD_RXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_TXSTCMD 0x8
+#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0)
+#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1)
+#define IFI_CANFD_TXSTCMD_RESET BIT(7)
+#define IFI_CANFD_TXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_TXSTCMD_FULL BIT(12)
+#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_INTERRUPT 0xc
+#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
+#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25)
+#define IFI_CANFD_INTERRUPT_SET_IRQ BIT(31)
+
+#define IFI_CANFD_IRQMASK 0x10
+#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
+#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
+#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_IRQMASK_SET_TX BIT(23)
+#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_IRQMASK_SET_RX BIT(31)
+
+#define IFI_CANFD_TIME 0x14
+#define IFI_CANFD_FTIME 0x18
+#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_TDELAY 0x1c
+
+#define IFI_CANFD_ERROR 0x20
+#define IFI_CANFD_ERROR_TX_OFFSET 0
+#define IFI_CANFD_ERROR_TX_MASK 0xff
+#define IFI_CANFD_ERROR_RX_OFFSET 16
+#define IFI_CANFD_ERROR_RX_MASK 0xff
+
+#define IFI_CANFD_ERRCNT 0x24
+
+#define IFI_CANFD_SUSPEND 0x28
+
+#define IFI_CANFD_REPEAT 0x2c
+
+#define IFI_CANFD_TRAFFIC 0x30
+
+#define IFI_CANFD_TSCONTROL 0x34
+
+#define IFI_CANFD_TSC 0x38
+
+#define IFI_CANFD_TST 0x3c
+
+#define IFI_CANFD_RES1 0x40
+
+#define IFI_CANFD_RES2 0x44
+
+#define IFI_CANFD_PAR 0x48
+
+#define IFI_CANFD_CANCLOCK 0x4c
+
+#define IFI_CANFD_SYSCLOCK 0x50
+
+#define IFI_CANFD_VER 0x54
+
+#define IFI_CANFD_IP_ID 0x58
+#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD
+
+#define IFI_CANFD_TEST 0x5c
+
+#define IFI_CANFD_RXFIFO_TS_63_32 0x60
+
+#define IFI_CANFD_RXFIFO_TS_31_0 0x64
+
+#define IFI_CANFD_RXFIFO_DLC 0x68
+#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7)
+#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8
+#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff
+#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_RXFIFO_ID 0x6c
+#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
+
+#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0
+
+#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4
+
+#define IFI_CANFD_TXFIFO_DLC 0xb8
+#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_TXFIFO_ID 0xbc
+#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
+
+#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0)
+#define IFI_CANFD_FILTER_MASK_EXT BIT(29)
+#define IFI_CANFD_FILTER_MASK_EDL BIT(30)
+#define IFI_CANFD_FILTER_MASK_VALID BIT(31)
+
+#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4)
+#define IFI_CANFD_FILTER_IDENT_IDE BIT(29)
+#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30)
+#define IFI_CANFD_FILTER_IDENT_VALID BIT(31)
+
+/* IFI CANFD private data structure */
+struct ifi_canfd_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *ndev;
+ struct device *device;
+ void __iomem *base;
+};
+
+static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 enirq = 0;
+
+ if (enable) {
+ enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
+ IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
+ }
+
+ writel(IFI_CANFD_IRQMASK_SET_ERR |
+ IFI_CANFD_IRQMASK_SET_TS |
+ IFI_CANFD_IRQMASK_SET_TX |
+ IFI_CANFD_IRQMASK_SET_RX | enirq,
+ priv->base + IFI_CANFD_IRQMASK);
+}
+
+static void ifi_canfd_read_fifo(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf;
+ struct sk_buff *skb;
+ const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
+ IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
+ u32 rxdlc, rxid;
+ u32 dlc, id;
+ int i;
+
+ rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ skb = alloc_canfd_skb(ndev, &cf);
+ else
+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
+
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
+ IFI_CANFD_RXFIFO_DLC_DLC_MASK;
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ cf->len = can_dlc2len(dlc);
+ else
+ cf->len = get_can_dlc(dlc);
+
+ rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
+ id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
+ if (id & IFI_CANFD_RXFIFO_ID_IDE)
+ id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
+ else
+ id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
+ cf->can_id = id;
+
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(ndev, "ESI Error\n");
+ }
+
+ if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
+ (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
+ cf->flags |= CANFD_BRS;
+
+ for (i = 0; i < cf->len; i += 4) {
+ *(u32 *)(cf->data + i) =
+ readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
+ }
+ }
+
+ /* Remove the packet from FIFO */
+ writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
+ writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+
+ netif_receive_skb(skb);
+}
+
+static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 pkts = 0;
+ u32 rxst;
+
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
+ netdev_dbg(ndev, "No messages in RX FIFO\n");
+ return 0;
+ }
+
+ for (;;) {
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
+ break;
+ if (quota <= 0)
+ break;
+
+ ifi_canfd_read_fifo(ndev);
+ quota--;
+ pkts++;
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ }
+
+ if (pkts)
+ can_led_event(ndev, CAN_LED_EVENT_RX);
+
+ return pkts;
+}
+
+static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
+
+ stats->rx_errors++;
+ stats->rx_over_errors++;
+
+ skb = alloc_can_err_skb(ndev, &frame);
+ if (unlikely(!skb))
+ return 0;
+
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
+ struct can_berr_counter *bec)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 err;
+
+ err = readl(priv->base + IFI_CANFD_ERROR);
+ bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
+ IFI_CANFD_ERROR_RX_MASK;
+ bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
+ IFI_CANFD_ERROR_TX_MASK;
+
+ return 0;
+}
+
+static int ifi_canfd_handle_state_change(struct net_device *ndev,
+ enum can_state new_state)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct can_berr_counter bec;
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ ifi_canfd_irq_enable(ndev, 0);
+ priv->can.can_stats.bus_off++;
+ can_bus_off(ndev);
+ break;
+ default:
+ break;
+ }
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ ifi_canfd_get_berr_counter(ndev, &bec);
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ cf->can_id |= CAN_ERR_BUSOFF;
+ break;
+ default:
+ break;
+ }
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int work_done = 0;
+ u32 isr;
+
+ /*
+ * The ErrWarn condition is a little special, since the bit is
+ * located in the INTERRUPT register instead of STCMD register.
+ */
+ isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+ if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
+ (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+ /* Clear the interrupt */
+ writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
+ priv->base + IFI_CANFD_INTERRUPT);
+ netdev_dbg(ndev, "Error, entered warning state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_WARNING);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
+ (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+ netdev_dbg(ndev, "Error, entered passive state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_PASSIVE);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
+ (priv->can.state != CAN_STATE_BUS_OFF)) {
+ netdev_dbg(ndev, "Error, entered bus-off state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_BUS_OFF);
+ }
+
+ return work_done;
+}
+
+static int ifi_canfd_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
+ IFI_CANFD_STCMD_BUSOFF;
+ int work_done = 0;
+
+ u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
+ u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
+
+ /* Handle bus state changes */
+ if ((stcmd & stcmd_state_mask) ||
+ ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
+ work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
+
+ /* Handle lost messages on RX */
+ if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
+ work_done += ifi_canfd_handle_lost_msg(ndev);
+
+ /* Handle normal messages on RX */
+ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
+ work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ ifi_canfd_irq_enable(ndev, 1);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)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;
+ const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
+ IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
+ 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);
+
+ /* No interrupt */
+ if (isr == 0)
+ return IRQ_NONE;
+
+ /* Clear all pending interrupts but ErrWarn */
+ writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ /* RX IRQ, start NAPI */
+ if (isr & rx_irq_mask) {
+ ifi_canfd_irq_enable(ndev, 0);
+ napi_schedule(&priv->napi);
+ }
+
+ /* TX IRQ */
+ if (isr & tx_irq_mask) {
+ stats->tx_bytes += can_get_echo_skb(ndev, 0);
+ stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+ netif_wake_queue(ndev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const ifi_canfd_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 64,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static const struct can_bittiming_const ifi_canfd_data_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 32,
+ .brp_inc = 1,
+};
+
+static void ifi_canfd_set_bittiming(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(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_NON_ISO) {
+ 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;
+ } else {
+ time_off = IFI_CANFD_TIME_SJW_OFF_ISO;
+ }
+
+ /* Configure bit timing */
+ brp = bt->brp - 1;
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off),
+ priv->base + IFI_CANFD_TIME);
+
+ /* Configure data bit timing */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off) |
+ noniso_arg,
+ priv->base + IFI_CANFD_FTIME);
+}
+
+static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
+ const u32 mask, const u32 ident)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id));
+ writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id));
+}
+
+static void ifi_canfd_set_filters(struct net_device *ndev)
+{
+ /* Receive all CAN frames (standard ID) */
+ ifi_canfd_set_filter(ndev, 0,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID);
+
+ /* Receive all CAN frames (extended ID) */
+ ifi_canfd_set_filter(ndev, 1,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_IDE);
+
+ /* Receive all CANFD frames */
+ ifi_canfd_set_filter(ndev, 2,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EDL |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_CANFD |
+ IFI_CANFD_FILTER_IDENT_IDE);
+}
+
+static void ifi_canfd_start(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 stcmd;
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+ writel(0, priv->base + IFI_CANFD_STCMD);
+
+ ifi_canfd_set_bittiming(ndev);
+ ifi_canfd_set_filters(ndev);
+
+ /* Reset FIFOs */
+ writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
+ writel(0, priv->base + IFI_CANFD_RXSTCMD);
+ writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
+ writel(0, priv->base + IFI_CANFD_TXSTCMD);
+
+ /* Repeat transmission until successful */
+ writel(0, priv->base + IFI_CANFD_REPEAT);
+ writel(0, priv->base + IFI_CANFD_SUSPEND);
+
+ /* Clear all pending interrupts */
+ writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+ priv->base + IFI_CANFD_INTERRUPT);
+
+ stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ stcmd |= IFI_CANFD_STCMD_LOOPBACK;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
+
+ if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)))
+ stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ ifi_canfd_irq_enable(ndev, 1);
+
+ /* Enable controller */
+ writel(stcmd, priv->base + IFI_CANFD_STCMD);
+}
+
+static void ifi_canfd_stop(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+
+ /* Mask all interrupts */
+ writel(~0, priv->base + IFI_CANFD_IRQMASK);
+
+ /* Clear all pending interrupts */
+ writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+ priv->base + IFI_CANFD_INTERRUPT);
+
+ /* Set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ ifi_canfd_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ifi_canfd_open(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = open_candev(ndev);
+ if (ret) {
+ netdev_err(ndev, "Failed to open CAN device\n");
+ return ret;
+ }
+
+ /* Register interrupt handler */
+ ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED,
+ ndev->name, ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "Failed to request interrupt\n");
+ goto err_irq;
+ }
+
+ ifi_canfd_start(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+err_irq:
+ close_candev(ndev);
+ return ret;
+}
+
+static int ifi_canfd_close(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+
+ ifi_canfd_stop(ndev);
+
+ free_irq(ndev->irq, ndev);
+
+ close_candev(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ u32 txst, txid;
+ u32 txdlc = 0;
+ int i;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ /* Check if the TX buffer is full */
+ txst = readl(priv->base + IFI_CANFD_TXSTCMD);
+ if (txst & IFI_CANFD_TXSTCMD_FULL) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "BUG! TX FIFO full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ netif_stop_queue(ndev);
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ txid = cf->can_id & CAN_EFF_MASK;
+ txid |= IFI_CANFD_TXFIFO_ID_IDE;
+ } else {
+ txid = cf->can_id & CAN_SFF_MASK;
+ }
+
+ if (priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)) {
+ if (can_is_canfd_skb(skb)) {
+ txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
+ if (cf->flags & CANFD_BRS)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_BRS;
+ }
+ }
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_RTR;
+
+ /* message ram configuration */
+ writel(txid, priv->base + IFI_CANFD_TXFIFO_ID);
+ writel(txdlc, priv->base + IFI_CANFD_TXFIFO_DLC);
+
+ for (i = 0; i < cf->len; i += 4) {
+ writel(*(u32 *)(cf->data + i),
+ priv->base + IFI_CANFD_TXFIFO_DATA + i);
+ }
+
+ writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
+ writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
+
+ can_put_echo_skb(skb, ndev, 0);
+
+ /* Start the transmission */
+ writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ifi_canfd_netdev_ops = {
+ .ndo_open = ifi_canfd_open,
+ .ndo_stop = ifi_canfd_close,
+ .ndo_start_xmit = ifi_canfd_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static int ifi_canfd_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct net_device *ndev;
+ struct ifi_canfd_priv *priv;
+ struct resource *res;
+ void __iomem *addr;
+ int irq, ret;
+ u32 id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(dev, res);
+ irq = platform_get_irq(pdev, 0);
+ if (IS_ERR(addr) || irq < 0)
+ return -EINVAL;
+
+ id = readl(addr + IFI_CANFD_IP_ID);
+ if (id != IFI_CANFD_IP_ID_VALUE) {
+ dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
+ return -EINVAL;
+ }
+
+ ndev = alloc_candev(sizeof(*priv), 1);
+ if (!ndev)
+ return -ENOMEM;
+
+ ndev->irq = irq;
+ ndev->flags |= IFF_ECHO; /* we support local echo */
+ ndev->netdev_ops = &ifi_canfd_netdev_ops;
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->base = addr;
+ priv->device = dev;
+
+ netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ priv->can.clock.freq = readl(addr + IFI_CANFD_SYSCLOCK);
+
+ priv->can.bittiming_const = &ifi_canfd_bittiming_const;
+ priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const;
+ priv->can.do_set_mode = ifi_canfd_set_mode;
+ priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode = CAN_CTRLMODE_FD;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_FD |
+ CAN_CTRLMODE_FD_NON_ISO;
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, dev);
+
+ ret = register_candev(ndev);
+ if (ret) {
+ dev_err(dev, "Failed to register (ret=%d)\n", ret);
+ goto err_reg;
+ }
+
+ devm_can_led_init(ndev);
+
+ dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
+ priv->base, ndev->irq, priv->can.clock.freq);
+
+ return 0;
+
+err_reg:
+ free_candev(ndev);
+ return ret;
+}
+
+static int ifi_canfd_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_candev(ndev);
+ platform_set_drvdata(pdev, NULL);
+ free_candev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id ifi_canfd_of_table[] = {
+ { .compatible = "ifi,canfd-1.0", .data = NULL },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ifi_canfd_of_table);
+
+static struct platform_driver ifi_canfd_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = ifi_canfd_of_table,
+ },
+ .probe = ifi_canfd_plat_probe,
+ .remove = ifi_canfd_plat_remove,
+};
+
+module_platform_driver(ifi_canfd_plat_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller");
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-12 23:59 ` [PATCH V2 " Marek Vasut
@ 2016-01-20 10:39 ` Marc Kleine-Budde
2016-01-20 10:54 ` Marc Kleine-Budde
0 siblings, 1 reply; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 10:39 UTC (permalink / raw)
To: Marek Vasut, netdev; +Cc: Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 10351 bytes --]
On 01/13/2016 12:59 AM, Marek Vasut wrote:
> The patch adds support for IFI CAN/FD controller [1]. This driver
> currently supports sending and receiving both standard CAN and new
> CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
>
> [1] http://www.ifi-pld.de/IP/CANFD/canfd.html
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Oliver Hartkopp <socketcan@hartkopp.net>
> Cc: Wolfgang Grandegger <wg@grandegger.com>
> ---
> V2: - Move request_irq()/free_irq() into ifi_canfd_open()/ifi_canfd_close()
> just like other drivers do it to prevent crash when reloading module.
> - Fix Woverflow complains on x86_64 and itanium, exactly the same way
> as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
>
> NOTE: The driver is surprisingly similar to m_can, but the register
> layout of the IFI core is completely different, so it's clear
> that those are two different IP cores.
> ---
> drivers/net/can/Kconfig | 2 +
> drivers/net/can/Makefile | 1 +
> drivers/net/can/ifi_canfd/Kconfig | 8 +
> drivers/net/can/ifi_canfd/Makefile | 5 +
> drivers/net/can/ifi_canfd/ifi_canfd.c | 919 ++++++++++++++++++++++++++++++++++
> 5 files changed, 935 insertions(+)
> create mode 100644 drivers/net/can/ifi_canfd/Kconfig
> create mode 100644 drivers/net/can/ifi_canfd/Makefile
> create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.c
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index ca49d15..20be638 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -151,6 +151,8 @@ source "drivers/net/can/c_can/Kconfig"
>
> source "drivers/net/can/cc770/Kconfig"
>
> +source "drivers/net/can/ifi_canfd/Kconfig"
> +
> source "drivers/net/can/m_can/Kconfig"
>
> source "drivers/net/can/mscan/Kconfig"
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 4f85c2b..e3db0c8 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_CAN_CC770) += cc770/
> obj-$(CONFIG_CAN_C_CAN) += c_can/
> obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
> obj-$(CONFIG_CAN_GRCAN) += grcan.o
> +obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
> obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
> obj-$(CONFIG_CAN_MSCAN) += mscan/
> obj-$(CONFIG_CAN_M_CAN) += m_can/
> diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
> new file mode 100644
> index 0000000..9e8934f
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/Kconfig
> @@ -0,0 +1,8 @@
> +config CAN_IFI_CANFD
> + depends on HAS_IOMEM
> + tristate "IFI CAN_FD IP"
> + ---help---
> + This driver adds support for the I/F/I CAN_FD soft IP block
> + connected to the "platform bus" (Linux abstraction for directly
> + to the processor attached devices). The CAN_FD is most often
> + synthesised into an FPGA or CPLD.
> diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
> new file mode 100644
> index 0000000..b229960
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the IFI CANFD controller driver.
> +#
> +
> +obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
> diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
> new file mode 100644
> index 0000000..094c36b
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
> @@ -0,0 +1,919 @@
> +/*
> + * CAN bus driver for IFI CANFD controller
> + *
> + * Copyright (C) 2016 Marek Vasut <marex@denx.de>
> + *
> + * Details about this controller can be found at
> + * http://www.ifi-pld.de/IP/CANFD/canfd.html
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/can/dev.h>
> +
> +#define IFI_CANFD_STCMD 0x0
> +#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD
> +#define IFI_CANFD_STCMD_ENABLE BIT(0)
> +#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
> +#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
> +#define IFI_CANFD_STCMD_BUSOFF BIT(4)
> +#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
> +#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_NORMAL_MODE BIT(31)
> +
> +#define IFI_CANFD_RXSTCMD 0x4
> +#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0)
> +#define IFI_CANFD_RXSTCMD_RESET BIT(7)
> +#define IFI_CANFD_RXSTCMD_EMPTY BIT(8)
> +#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13)
> +
> +#define IFI_CANFD_TXSTCMD 0x8
> +#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0)
> +#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1)
> +#define IFI_CANFD_TXSTCMD_RESET BIT(7)
> +#define IFI_CANFD_TXSTCMD_EMPTY BIT(8)
> +#define IFI_CANFD_TXSTCMD_FULL BIT(12)
> +#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
> +
> +#define IFI_CANFD_INTERRUPT 0xc
> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
> +#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
> +#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
> +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
> +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25)
> +#define IFI_CANFD_INTERRUPT_SET_IRQ BIT(31)
> +
> +#define IFI_CANFD_IRQMASK 0x10
> +#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
> +#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
> +#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
> +#define IFI_CANFD_IRQMASK_SET_TX BIT(23)
> +#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24)
> +#define IFI_CANFD_IRQMASK_SET_RX BIT(31)
> +
> +#define IFI_CANFD_TIME 0x14
> +#define IFI_CANFD_FTIME 0x18
> +#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_TDELAY 0x1c
> +
> +#define IFI_CANFD_ERROR 0x20
> +#define IFI_CANFD_ERROR_TX_OFFSET 0
> +#define IFI_CANFD_ERROR_TX_MASK 0xff
> +#define IFI_CANFD_ERROR_RX_OFFSET 16
> +#define IFI_CANFD_ERROR_RX_MASK 0xff
> +
> +#define IFI_CANFD_ERRCNT 0x24
> +
> +#define IFI_CANFD_SUSPEND 0x28
> +
> +#define IFI_CANFD_REPEAT 0x2c
> +
> +#define IFI_CANFD_TRAFFIC 0x30
> +
> +#define IFI_CANFD_TSCONTROL 0x34
> +
> +#define IFI_CANFD_TSC 0x38
> +
> +#define IFI_CANFD_TST 0x3c
> +
> +#define IFI_CANFD_RES1 0x40
> +
> +#define IFI_CANFD_RES2 0x44
> +
> +#define IFI_CANFD_PAR 0x48
> +
> +#define IFI_CANFD_CANCLOCK 0x4c
> +
> +#define IFI_CANFD_SYSCLOCK 0x50
> +
> +#define IFI_CANFD_VER 0x54
> +
> +#define IFI_CANFD_IP_ID 0x58
> +#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD
> +
> +#define IFI_CANFD_TEST 0x5c
> +
> +#define IFI_CANFD_RXFIFO_TS_63_32 0x60
> +
> +#define IFI_CANFD_RXFIFO_TS_31_0 0x64
> +
> +#define IFI_CANFD_RXFIFO_DLC 0x68
> +#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0
> +#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf
> +#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4)
> +#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5)
> +#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6)
> +#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7)
> +#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8
> +#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff
> +#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24
> +#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff
> +
> +#define IFI_CANFD_RXFIFO_ID 0x6c
> +#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
> +#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK 0x3ff
> +#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK 0x1fffffff
> +#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
> +
> +#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
> +
> +#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0
> +
> +#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4
> +
> +#define IFI_CANFD_TXFIFO_DLC 0xb8
> +#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0
> +#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf
> +#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4)
> +#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5)
> +#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6)
> +#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24
> +#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff
> +
> +#define IFI_CANFD_TXFIFO_ID 0xbc
> +#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
> +#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK 0x3ff
> +#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK 0x1fffffff
> +#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
> +
> +#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
> +
> +#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0)
> +#define IFI_CANFD_FILTER_MASK_EXT BIT(29)
> +#define IFI_CANFD_FILTER_MASK_EDL BIT(30)
> +#define IFI_CANFD_FILTER_MASK_VALID BIT(31)
> +
> +#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4)
> +#define IFI_CANFD_FILTER_IDENT_IDE BIT(29)
> +#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30)
> +#define IFI_CANFD_FILTER_IDENT_VALID BIT(31)
> +
> +/* IFI CANFD private data structure */
> +struct ifi_canfd_priv {
> + struct can_priv can; /* must be the first member */
> + struct napi_struct napi;
> + struct net_device *ndev;
> + struct device *device;
Nitpick: This variable is write only, correct? I can fix this while
applying the patch.
> + void __iomem *base;
> +};
Otherweise looks good.
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 10:39 ` Marc Kleine-Budde
@ 2016-01-20 10:54 ` Marc Kleine-Budde
2016-01-20 12:58 ` Marek Vasut
0 siblings, 1 reply; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 10:54 UTC (permalink / raw)
To: Marek Vasut, netdev; +Cc: Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 1243 bytes --]
On 01/20/2016 11:39 AM, Marc Kleine-Budde wrote:
>> +/* IFI CANFD private data structure */
>> +struct ifi_canfd_priv {
>> + struct can_priv can; /* must be the first member */
>> + struct napi_struct napi;
>> + struct net_device *ndev;
>> + struct device *device;
>
> Nitpick: This variable is write only, correct? I can fix this while
> applying the patch.
>
>> + void __iomem *base;
>> +};
>
> Otherweise looks good.
Until compiling:
> drivers/net/can/ifi_canfd/ifi_canfd.c:486:40: warning: cast truncates bits from constant value (ffffffff7ffffffd becomes 7ffffffd)
> drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: cast truncates bits from constant value (ffffffff7fffffff becomes 7fffffff)
> drivers/net/can/ifi_canfd/ifi_canfd.c:676:9: warning: cast truncates bits from constant value (ffffffff7fffffff becomes 7fffffff)
target is ARMv5 with gcc version 4.9.2, compiled with C=2 using sparse
v0.5.0.
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 10:54 ` Marc Kleine-Budde
@ 2016-01-20 12:58 ` Marek Vasut
2016-01-20 14:06 ` Marc Kleine-Budde
0 siblings, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 12:58 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
On Wednesday, January 20, 2016 at 11:54:21 AM, Marc Kleine-Budde wrote:
> On 01/20/2016 11:39 AM, Marc Kleine-Budde wrote:
> >> +/* IFI CANFD private data structure */
> >> +struct ifi_canfd_priv {
> >> + struct can_priv can; /* must be the first member */
> >> + struct napi_struct napi;
> >> + struct net_device *ndev;
> >> + struct device *device;
> >
> > Nitpick: This variable is write only, correct? I can fix this while
> > applying the patch.
> >
> >> + void __iomem *base;
> >> +};
> >
> > Otherweise looks good.
It's write-only, yeah. What would you propose to change here ?
> Until compiling:
> > drivers/net/can/ifi_canfd/ifi_canfd.c:486:40: warning: cast truncates
> > bits from constant value (ffffffff7ffffffd becomes 7ffffffd)
> > drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: cast truncates
> > bits from constant value (ffffffff7fffffff becomes 7fffffff)
> > drivers/net/can/ifi_canfd/ifi_canfd.c:676:9: warning: cast truncates
> > bits from constant value (ffffffff7fffffff becomes 7fffffff)
>
> target is ARMv5 with gcc version 4.9.2, compiled with C=2 using sparse
> v0.5.0.
It's again the BIT() macro :-/ Do you have any idea how to fix this please ?
Doing something like u32 foo = ~BIT(31); triggers this splat and I am running
out of ideas how to fix that.
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 12:58 ` Marek Vasut
@ 2016-01-20 14:06 ` Marc Kleine-Budde
2016-01-20 14:25 ` Marek Vasut
2016-01-20 14:33 ` [PATCH V3 " Marek Vasut
0 siblings, 2 replies; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 14:06 UTC (permalink / raw)
To: Marek Vasut; +Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 1862 bytes --]
On 01/20/2016 01:58 PM, Marek Vasut wrote:
> On Wednesday, January 20, 2016 at 11:54:21 AM, Marc Kleine-Budde wrote:
>> On 01/20/2016 11:39 AM, Marc Kleine-Budde wrote:
>>>> +/* IFI CANFD private data structure */
>>>> +struct ifi_canfd_priv {
>>>> + struct can_priv can; /* must be the first member */
>>>> + struct napi_struct napi;
>>>> + struct net_device *ndev;
>>>> + struct device *device;
>>>
>>> Nitpick: This variable is write only, correct? I can fix this while
>>> applying the patch.
>>>
>>>> + void __iomem *base;
>>>> +};
>>>
>>> Otherweise looks good.
>
> It's write-only, yeah. What would you propose to change here ?
Remove it completely. :D
>> Until compiling:
>>> drivers/net/can/ifi_canfd/ifi_canfd.c:486:40: warning: cast truncates
>>> bits from constant value (ffffffff7ffffffd becomes 7ffffffd)
>>> drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: cast truncates
>>> bits from constant value (ffffffff7fffffff becomes 7fffffff)
>>> drivers/net/can/ifi_canfd/ifi_canfd.c:676:9: warning: cast truncates
>>> bits from constant value (ffffffff7fffffff becomes 7fffffff)
>>
>> target is ARMv5 with gcc version 4.9.2, compiled with C=2 using sparse
>> v0.5.0.
>
> It's again the BIT() macro :-/ Do you have any idea how to fix this please ?
> Doing something like u32 foo = ~BIT(31); triggers this splat and I am running
> out of ideas how to fix that.
-#define IFI_CANFD_INTERRUPT_SET_IRQ BIT(31)
+#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31))
...or change the bit to "30" :D
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:06 ` Marc Kleine-Budde
@ 2016-01-20 14:25 ` Marek Vasut
2016-01-23 0:11 ` Rustad, Mark D
2016-01-20 14:33 ` [PATCH V3 " Marek Vasut
1 sibling, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 14:25 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
On Wednesday, January 20, 2016 at 03:06:02 PM, Marc Kleine-Budde wrote:
> On 01/20/2016 01:58 PM, Marek Vasut wrote:
> > On Wednesday, January 20, 2016 at 11:54:21 AM, Marc Kleine-Budde wrote:
> >> On 01/20/2016 11:39 AM, Marc Kleine-Budde wrote:
> >>>> +/* IFI CANFD private data structure */
> >>>> +struct ifi_canfd_priv {
> >>>> + struct can_priv can; /* must be the first member */
> >>>> + struct napi_struct napi;
> >>>> + struct net_device *ndev;
> >>>> + struct device *device;
> >>>
> >>> Nitpick: This variable is write only, correct? I can fix this while
> >>> applying the patch.
> >>>
> >>>> + void __iomem *base;
> >>>> +};
> >>>
> >>> Otherweise looks good.
> >
> > It's write-only, yeah. What would you propose to change here ?
>
> Remove it completely. :D
Erm, right. I see it now, thanks.
> >> Until compiling:
> >>> drivers/net/can/ifi_canfd/ifi_canfd.c:486:40: warning: cast truncates
> >>> bits from constant value (ffffffff7ffffffd becomes 7ffffffd)
> >>> drivers/net/can/ifi_canfd/ifi_canfd.c:640:9: warning: cast truncates
> >>> bits from constant value (ffffffff7fffffff becomes 7fffffff)
> >>> drivers/net/can/ifi_canfd/ifi_canfd.c:676:9: warning: cast truncates
> >>> bits from constant value (ffffffff7fffffff becomes 7fffffff)
> >>
> >> target is ARMv5 with gcc version 4.9.2, compiled with C=2 using sparse
> >> v0.5.0.
> >
> > It's again the BIT() macro :-/ Do you have any idea how to fix this
> > please ? Doing something like u32 foo = ~BIT(31); triggers this splat
> > and I am running out of ideas how to fix that.
>
> -#define IFI_CANFD_INTERRUPT_SET_IRQ BIT(31)
> +#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31))
I see, so adding u32 also here works. I'm starting to wonder if the BIT
macro is really that nice and if I shouldn't just use (1 << n) as usual.
> ...or change the bit to "30" :D
:-)
I will send V3 in a bit.
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:06 ` Marc Kleine-Budde
2016-01-20 14:25 ` Marek Vasut
@ 2016-01-20 14:33 ` Marek Vasut
2016-01-20 14:39 ` Marc Kleine-Budde
1 sibling, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 14:33 UTC (permalink / raw)
To: netdev
Cc: Marc Kleine-Budde, Oliver Hartkopp, Marek Vasut, Mark Rutland,
Wolfgang Grandegger
The patch adds support for IFI CAN/FD controller [1]. This driver
currently supports sending and receiving both standard CAN and new
CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
[1] http://www.ifi-pld.de/IP/CANFD/canfd.html
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Wolfgang Grandegger <wg@grandegger.com>
---
V2: - Move request_irq()/free_irq() into ifi_canfd_open()/ifi_canfd_close()
just like other drivers do it to prevent crash when reloading module.
- Fix Woverflow complains on x86_64 and itanium, exactly the same way
as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
V3: - Hopefully fix all problems with BIT(31) by adding more u32 casts.
- Drop struct device from struct ifi_canfd_priv .
NOTE: The driver is surprisingly similar to m_can, but the register
layout of the IFI core is completely different, so it's clear
that those are two different IP cores.
---
drivers/net/can/Kconfig | 2 +
drivers/net/can/Makefile | 1 +
drivers/net/can/ifi_canfd/Kconfig | 8 +
drivers/net/can/ifi_canfd/Makefile | 5 +
drivers/net/can/ifi_canfd/ifi_canfd.c | 917 ++++++++++++++++++++++++++++++++++
5 files changed, 933 insertions(+)
create mode 100644 drivers/net/can/ifi_canfd/Kconfig
create mode 100644 drivers/net/can/ifi_canfd/Makefile
create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index ca49d15..20be638 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -151,6 +151,8 @@ source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
+source "drivers/net/can/ifi_canfd/Kconfig"
+
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 4f85c2b..e3db0c8 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/
diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
new file mode 100644
index 0000000..9e8934f
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Kconfig
@@ -0,0 +1,8 @@
+config CAN_IFI_CANFD
+ depends on HAS_IOMEM
+ tristate "IFI CAN_FD IP"
+ ---help---
+ This driver adds support for the I/F/I CAN_FD soft IP block
+ connected to the "platform bus" (Linux abstraction for directly
+ to the processor attached devices). The CAN_FD is most often
+ synthesised into an FPGA or CPLD.
diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
new file mode 100644
index 0000000..b229960
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IFI CANFD controller driver.
+#
+
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
new file mode 100644
index 0000000..639868b
--- /dev/null
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -0,0 +1,917 @@
+/*
+ * CAN bus driver for IFI CANFD controller
+ *
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Details about this controller can be found at
+ * http://www.ifi-pld.de/IP/CANFD/canfd.html
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+#define IFI_CANFD_STCMD 0x0
+#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD
+#define IFI_CANFD_STCMD_ENABLE BIT(0)
+#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
+#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
+#define IFI_CANFD_STCMD_BUSOFF BIT(4)
+#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
+#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_NORMAL_MODE ((u32)BIT(31))
+
+#define IFI_CANFD_RXSTCMD 0x4
+#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0)
+#define IFI_CANFD_RXSTCMD_RESET BIT(7)
+#define IFI_CANFD_RXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_TXSTCMD 0x8
+#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0)
+#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1)
+#define IFI_CANFD_TXSTCMD_RESET BIT(7)
+#define IFI_CANFD_TXSTCMD_EMPTY BIT(8)
+#define IFI_CANFD_TXSTCMD_FULL BIT(12)
+#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
+
+#define IFI_CANFD_INTERRUPT 0xc
+#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
+#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25)
+#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31))
+
+#define IFI_CANFD_IRQMASK 0x10
+#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
+#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
+#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
+#define IFI_CANFD_IRQMASK_SET_TX BIT(23)
+#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24)
+#define IFI_CANFD_IRQMASK_SET_RX ((u32)BIT(31))
+
+#define IFI_CANFD_TIME 0x14
+#define IFI_CANFD_FTIME 0x18
+#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_TDELAY 0x1c
+
+#define IFI_CANFD_ERROR 0x20
+#define IFI_CANFD_ERROR_TX_OFFSET 0
+#define IFI_CANFD_ERROR_TX_MASK 0xff
+#define IFI_CANFD_ERROR_RX_OFFSET 16
+#define IFI_CANFD_ERROR_RX_MASK 0xff
+
+#define IFI_CANFD_ERRCNT 0x24
+
+#define IFI_CANFD_SUSPEND 0x28
+
+#define IFI_CANFD_REPEAT 0x2c
+
+#define IFI_CANFD_TRAFFIC 0x30
+
+#define IFI_CANFD_TSCONTROL 0x34
+
+#define IFI_CANFD_TSC 0x38
+
+#define IFI_CANFD_TST 0x3c
+
+#define IFI_CANFD_RES1 0x40
+
+#define IFI_CANFD_RES2 0x44
+
+#define IFI_CANFD_PAR 0x48
+
+#define IFI_CANFD_CANCLOCK 0x4c
+
+#define IFI_CANFD_SYSCLOCK 0x50
+
+#define IFI_CANFD_VER 0x54
+
+#define IFI_CANFD_IP_ID 0x58
+#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD
+
+#define IFI_CANFD_TEST 0x5c
+
+#define IFI_CANFD_RXFIFO_TS_63_32 0x60
+
+#define IFI_CANFD_RXFIFO_TS_31_0 0x64
+
+#define IFI_CANFD_RXFIFO_DLC 0x68
+#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7)
+#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8
+#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff
+#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_RXFIFO_ID 0x6c
+#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
+
+#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0
+
+#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4
+
+#define IFI_CANFD_TXFIFO_DLC 0xb8
+#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0
+#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf
+#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4)
+#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5)
+#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6)
+#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24
+#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff
+
+#define IFI_CANFD_TXFIFO_ID 0xbc
+#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
+#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK 0x3ff
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK 0x1fffffff
+#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
+
+#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
+
+#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0)
+#define IFI_CANFD_FILTER_MASK_EXT BIT(29)
+#define IFI_CANFD_FILTER_MASK_EDL BIT(30)
+#define IFI_CANFD_FILTER_MASK_VALID ((u32)BIT(31))
+
+#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4)
+#define IFI_CANFD_FILTER_IDENT_IDE BIT(29)
+#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30)
+#define IFI_CANFD_FILTER_IDENT_VALID ((u32)BIT(31))
+
+/* IFI CANFD private data structure */
+struct ifi_canfd_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *ndev;
+ void __iomem *base;
+};
+
+static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 enirq = 0;
+
+ if (enable) {
+ enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
+ IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
+ }
+
+ writel(IFI_CANFD_IRQMASK_SET_ERR |
+ IFI_CANFD_IRQMASK_SET_TS |
+ IFI_CANFD_IRQMASK_SET_TX |
+ IFI_CANFD_IRQMASK_SET_RX | enirq,
+ priv->base + IFI_CANFD_IRQMASK);
+}
+
+static void ifi_canfd_read_fifo(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf;
+ struct sk_buff *skb;
+ const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
+ IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
+ u32 rxdlc, rxid;
+ u32 dlc, id;
+ int i;
+
+ rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ skb = alloc_canfd_skb(ndev, &cf);
+ else
+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
+
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
+ IFI_CANFD_RXFIFO_DLC_DLC_MASK;
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+ cf->len = can_dlc2len(dlc);
+ else
+ cf->len = get_can_dlc(dlc);
+
+ rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
+ id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
+ if (id & IFI_CANFD_RXFIFO_ID_IDE)
+ id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
+ else
+ id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
+ cf->can_id = id;
+
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(ndev, "ESI Error\n");
+ }
+
+ if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
+ (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
+ cf->flags |= CANFD_BRS;
+
+ for (i = 0; i < cf->len; i += 4) {
+ *(u32 *)(cf->data + i) =
+ readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
+ }
+ }
+
+ /* Remove the packet from FIFO */
+ writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
+ writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+
+ netif_receive_skb(skb);
+}
+
+static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 pkts = 0;
+ u32 rxst;
+
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
+ netdev_dbg(ndev, "No messages in RX FIFO\n");
+ return 0;
+ }
+
+ for (;;) {
+ if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
+ break;
+ if (quota <= 0)
+ break;
+
+ ifi_canfd_read_fifo(ndev);
+ quota--;
+ pkts++;
+ rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+ }
+
+ if (pkts)
+ can_led_event(ndev, CAN_LED_EVENT_RX);
+
+ return pkts;
+}
+
+static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
+{
+ struct net_device_stats *stats = &ndev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
+
+ stats->rx_errors++;
+ stats->rx_over_errors++;
+
+ skb = alloc_can_err_skb(ndev, &frame);
+ if (unlikely(!skb))
+ return 0;
+
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
+ struct can_berr_counter *bec)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 err;
+
+ err = readl(priv->base + IFI_CANFD_ERROR);
+ bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
+ IFI_CANFD_ERROR_RX_MASK;
+ bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
+ IFI_CANFD_ERROR_TX_MASK;
+
+ return 0;
+}
+
+static int ifi_canfd_handle_state_change(struct net_device *ndev,
+ enum can_state new_state)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct can_berr_counter bec;
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ ifi_canfd_irq_enable(ndev, 0);
+ priv->can.can_stats.bus_off++;
+ can_bus_off(ndev);
+ break;
+ default:
+ break;
+ }
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ ifi_canfd_get_berr_counter(ndev, &bec);
+
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /* error warning state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ /* error passive state */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case CAN_STATE_BUS_OFF:
+ /* bus-off state */
+ cf->can_id |= CAN_ERR_BUSOFF;
+ break;
+ default:
+ break;
+ }
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int work_done = 0;
+ u32 isr;
+
+ /*
+ * The ErrWarn condition is a little special, since the bit is
+ * located in the INTERRUPT register instead of STCMD register.
+ */
+ isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+ if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
+ (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+ /* Clear the interrupt */
+ writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
+ priv->base + IFI_CANFD_INTERRUPT);
+ netdev_dbg(ndev, "Error, entered warning state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_WARNING);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
+ (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+ netdev_dbg(ndev, "Error, entered passive state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_ERROR_PASSIVE);
+ }
+
+ if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
+ (priv->can.state != CAN_STATE_BUS_OFF)) {
+ netdev_dbg(ndev, "Error, entered bus-off state\n");
+ work_done += ifi_canfd_handle_state_change(ndev,
+ CAN_STATE_BUS_OFF);
+ }
+
+ return work_done;
+}
+
+static int ifi_canfd_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
+ IFI_CANFD_STCMD_BUSOFF;
+ int work_done = 0;
+
+ u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
+ u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
+
+ /* Handle bus state changes */
+ if ((stcmd & stcmd_state_mask) ||
+ ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
+ work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
+
+ /* Handle lost messages on RX */
+ if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
+ work_done += ifi_canfd_handle_lost_msg(ndev);
+
+ /* Handle normal messages on RX */
+ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
+ work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ ifi_canfd_irq_enable(ndev, 1);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)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;
+ const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
+ IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
+ 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);
+
+ /* No interrupt */
+ if (isr == 0)
+ return IRQ_NONE;
+
+ /* Clear all pending interrupts but ErrWarn */
+ writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+ /* RX IRQ, start NAPI */
+ if (isr & rx_irq_mask) {
+ ifi_canfd_irq_enable(ndev, 0);
+ napi_schedule(&priv->napi);
+ }
+
+ /* TX IRQ */
+ if (isr & tx_irq_mask) {
+ stats->tx_bytes += can_get_echo_skb(ndev, 0);
+ stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+ netif_wake_queue(ndev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const ifi_canfd_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 64,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static const struct can_bittiming_const ifi_canfd_data_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 32,
+ .brp_inc = 1,
+};
+
+static void ifi_canfd_set_bittiming(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(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_NON_ISO) {
+ 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;
+ } else {
+ time_off = IFI_CANFD_TIME_SJW_OFF_ISO;
+ }
+
+ /* Configure bit timing */
+ brp = bt->brp - 1;
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off),
+ priv->base + IFI_CANFD_TIME);
+
+ /* Configure data bit timing */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
+ writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+ (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+ (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+ (sjw << time_off) |
+ noniso_arg,
+ priv->base + IFI_CANFD_FTIME);
+}
+
+static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
+ const u32 mask, const u32 ident)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id));
+ writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id));
+}
+
+static void ifi_canfd_set_filters(struct net_device *ndev)
+{
+ /* Receive all CAN frames (standard ID) */
+ ifi_canfd_set_filter(ndev, 0,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID);
+
+ /* Receive all CAN frames (extended ID) */
+ ifi_canfd_set_filter(ndev, 1,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_IDE);
+
+ /* Receive all CANFD frames */
+ ifi_canfd_set_filter(ndev, 2,
+ IFI_CANFD_FILTER_MASK_VALID |
+ IFI_CANFD_FILTER_MASK_EDL |
+ IFI_CANFD_FILTER_MASK_EXT,
+ IFI_CANFD_FILTER_IDENT_VALID |
+ IFI_CANFD_FILTER_IDENT_CANFD |
+ IFI_CANFD_FILTER_IDENT_IDE);
+}
+
+static void ifi_canfd_start(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ u32 stcmd;
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+ writel(0, priv->base + IFI_CANFD_STCMD);
+
+ ifi_canfd_set_bittiming(ndev);
+ ifi_canfd_set_filters(ndev);
+
+ /* Reset FIFOs */
+ writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
+ writel(0, priv->base + IFI_CANFD_RXSTCMD);
+ writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
+ writel(0, priv->base + IFI_CANFD_TXSTCMD);
+
+ /* Repeat transmission until successful */
+ writel(0, priv->base + IFI_CANFD_REPEAT);
+ writel(0, priv->base + IFI_CANFD_SUSPEND);
+
+ /* Clear all pending interrupts */
+ writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+ priv->base + IFI_CANFD_INTERRUPT);
+
+ stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ stcmd |= IFI_CANFD_STCMD_LOOPBACK;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
+
+ if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)))
+ stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ ifi_canfd_irq_enable(ndev, 1);
+
+ /* Enable controller */
+ writel(stcmd, priv->base + IFI_CANFD_STCMD);
+}
+
+static void ifi_canfd_stop(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ /* Reset the IP */
+ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+
+ /* Mask all interrupts */
+ writel(~0, priv->base + IFI_CANFD_IRQMASK);
+
+ /* Clear all pending interrupts */
+ writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+ priv->base + IFI_CANFD_INTERRUPT);
+
+ /* Set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ ifi_canfd_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ifi_canfd_open(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = open_candev(ndev);
+ if (ret) {
+ netdev_err(ndev, "Failed to open CAN device\n");
+ return ret;
+ }
+
+ /* Register interrupt handler */
+ ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED,
+ ndev->name, ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "Failed to request interrupt\n");
+ goto err_irq;
+ }
+
+ ifi_canfd_start(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+err_irq:
+ close_candev(ndev);
+ return ret;
+}
+
+static int ifi_canfd_close(struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+
+ ifi_canfd_stop(ndev);
+
+ free_irq(ndev->irq, ndev);
+
+ close_candev(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct ifi_canfd_priv *priv = netdev_priv(ndev);
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ u32 txst, txid;
+ u32 txdlc = 0;
+ int i;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ /* Check if the TX buffer is full */
+ txst = readl(priv->base + IFI_CANFD_TXSTCMD);
+ if (txst & IFI_CANFD_TXSTCMD_FULL) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "BUG! TX FIFO full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ netif_stop_queue(ndev);
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ txid = cf->can_id & CAN_EFF_MASK;
+ txid |= IFI_CANFD_TXFIFO_ID_IDE;
+ } else {
+ txid = cf->can_id & CAN_SFF_MASK;
+ }
+
+ if (priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)) {
+ if (can_is_canfd_skb(skb)) {
+ txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
+ if (cf->flags & CANFD_BRS)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_BRS;
+ }
+ }
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ txdlc |= IFI_CANFD_TXFIFO_DLC_RTR;
+
+ /* message ram configuration */
+ writel(txid, priv->base + IFI_CANFD_TXFIFO_ID);
+ writel(txdlc, priv->base + IFI_CANFD_TXFIFO_DLC);
+
+ for (i = 0; i < cf->len; i += 4) {
+ writel(*(u32 *)(cf->data + i),
+ priv->base + IFI_CANFD_TXFIFO_DATA + i);
+ }
+
+ writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
+ writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
+
+ can_put_echo_skb(skb, ndev, 0);
+
+ /* Start the transmission */
+ writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ifi_canfd_netdev_ops = {
+ .ndo_open = ifi_canfd_open,
+ .ndo_stop = ifi_canfd_close,
+ .ndo_start_xmit = ifi_canfd_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static int ifi_canfd_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct net_device *ndev;
+ struct ifi_canfd_priv *priv;
+ struct resource *res;
+ void __iomem *addr;
+ int irq, ret;
+ u32 id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(dev, res);
+ irq = platform_get_irq(pdev, 0);
+ if (IS_ERR(addr) || irq < 0)
+ return -EINVAL;
+
+ id = readl(addr + IFI_CANFD_IP_ID);
+ if (id != IFI_CANFD_IP_ID_VALUE) {
+ dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
+ return -EINVAL;
+ }
+
+ ndev = alloc_candev(sizeof(*priv), 1);
+ if (!ndev)
+ return -ENOMEM;
+
+ ndev->irq = irq;
+ ndev->flags |= IFF_ECHO; /* we support local echo */
+ ndev->netdev_ops = &ifi_canfd_netdev_ops;
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->base = addr;
+
+ netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ priv->can.clock.freq = readl(addr + IFI_CANFD_SYSCLOCK);
+
+ priv->can.bittiming_const = &ifi_canfd_bittiming_const;
+ priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const;
+ priv->can.do_set_mode = ifi_canfd_set_mode;
+ priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode = CAN_CTRLMODE_FD;
+
+ /* IFI CANFD can do both Bosch FD and ISO FD */
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_FD |
+ CAN_CTRLMODE_FD_NON_ISO;
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, dev);
+
+ ret = register_candev(ndev);
+ if (ret) {
+ dev_err(dev, "Failed to register (ret=%d)\n", ret);
+ goto err_reg;
+ }
+
+ devm_can_led_init(ndev);
+
+ dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
+ priv->base, ndev->irq, priv->can.clock.freq);
+
+ return 0;
+
+err_reg:
+ free_candev(ndev);
+ return ret;
+}
+
+static int ifi_canfd_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_candev(ndev);
+ platform_set_drvdata(pdev, NULL);
+ free_candev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id ifi_canfd_of_table[] = {
+ { .compatible = "ifi,canfd-1.0", .data = NULL },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ifi_canfd_of_table);
+
+static struct platform_driver ifi_canfd_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = ifi_canfd_of_table,
+ },
+ .probe = ifi_canfd_plat_probe,
+ .remove = ifi_canfd_plat_remove,
+};
+
+module_platform_driver(ifi_canfd_plat_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller");
--
2.1.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:33 ` [PATCH V3 " Marek Vasut
@ 2016-01-20 14:39 ` Marc Kleine-Budde
2016-01-20 14:41 ` Marek Vasut
0 siblings, 1 reply; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 14:39 UTC (permalink / raw)
To: Marek Vasut, netdev; +Cc: Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 19868 bytes --]
On 01/20/2016 03:33 PM, Marek Vasut wrote:
> The patch adds support for IFI CAN/FD controller [1]. This driver
> currently supports sending and receiving both standard CAN and new
> CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
>
> [1] http://www.ifi-pld.de/IP/CANFD/canfd.html
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Oliver Hartkopp <socketcan@hartkopp.net>
> Cc: Wolfgang Grandegger <wg@grandegger.com>
> ---
> V2: - Move request_irq()/free_irq() into ifi_canfd_open()/ifi_canfd_close()
> just like other drivers do it to prevent crash when reloading module.
> - Fix Woverflow complains on x86_64 and itanium, exactly the same way
> as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
>
> V3: - Hopefully fix all problems with BIT(31) by adding more u32 casts.
> - Drop struct device from struct ifi_canfd_priv .
>
> NOTE: The driver is surprisingly similar to m_can, but the register
> layout of the IFI core is completely different, so it's clear
> that those are two different IP cores.
> ---
> drivers/net/can/Kconfig | 2 +
> drivers/net/can/Makefile | 1 +
> drivers/net/can/ifi_canfd/Kconfig | 8 +
> drivers/net/can/ifi_canfd/Makefile | 5 +
> drivers/net/can/ifi_canfd/ifi_canfd.c | 917 ++++++++++++++++++++++++++++++++++
> 5 files changed, 933 insertions(+)
> create mode 100644 drivers/net/can/ifi_canfd/Kconfig
> create mode 100644 drivers/net/can/ifi_canfd/Makefile
> create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.c
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index ca49d15..20be638 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -151,6 +151,8 @@ source "drivers/net/can/c_can/Kconfig"
>
> source "drivers/net/can/cc770/Kconfig"
>
> +source "drivers/net/can/ifi_canfd/Kconfig"
> +
> source "drivers/net/can/m_can/Kconfig"
>
> source "drivers/net/can/mscan/Kconfig"
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 4f85c2b..e3db0c8 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_CAN_CC770) += cc770/
> obj-$(CONFIG_CAN_C_CAN) += c_can/
> obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
> obj-$(CONFIG_CAN_GRCAN) += grcan.o
> +obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
> obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
> obj-$(CONFIG_CAN_MSCAN) += mscan/
> obj-$(CONFIG_CAN_M_CAN) += m_can/
> diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
> new file mode 100644
> index 0000000..9e8934f
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/Kconfig
> @@ -0,0 +1,8 @@
> +config CAN_IFI_CANFD
> + depends on HAS_IOMEM
> + tristate "IFI CAN_FD IP"
> + ---help---
> + This driver adds support for the I/F/I CAN_FD soft IP block
> + connected to the "platform bus" (Linux abstraction for directly
> + to the processor attached devices). The CAN_FD is most often
> + synthesised into an FPGA or CPLD.
> diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
> new file mode 100644
> index 0000000..b229960
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the IFI CANFD controller driver.
> +#
> +
> +obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
> diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
> new file mode 100644
> index 0000000..639868b
> --- /dev/null
> +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
> @@ -0,0 +1,917 @@
> +/*
> + * CAN bus driver for IFI CANFD controller
> + *
> + * Copyright (C) 2016 Marek Vasut <marex@denx.de>
> + *
> + * Details about this controller can be found at
> + * http://www.ifi-pld.de/IP/CANFD/canfd.html
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/can/dev.h>
> +
> +#define IFI_CANFD_STCMD 0x0
> +#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD
> +#define IFI_CANFD_STCMD_ENABLE BIT(0)
> +#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
> +#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
> +#define IFI_CANFD_STCMD_BUSOFF BIT(4)
> +#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
> +#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_NORMAL_MODE ((u32)BIT(31))
> +
> +#define IFI_CANFD_RXSTCMD 0x4
> +#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0)
> +#define IFI_CANFD_RXSTCMD_RESET BIT(7)
> +#define IFI_CANFD_RXSTCMD_EMPTY BIT(8)
> +#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13)
> +
> +#define IFI_CANFD_TXSTCMD 0x8
> +#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0)
> +#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1)
> +#define IFI_CANFD_TXSTCMD_RESET BIT(7)
> +#define IFI_CANFD_TXSTCMD_EMPTY BIT(8)
> +#define IFI_CANFD_TXSTCMD_FULL BIT(12)
> +#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
> +
> +#define IFI_CANFD_INTERRUPT 0xc
> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
> +#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
> +#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
> +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
> +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25)
> +#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31))
> +
> +#define IFI_CANFD_IRQMASK 0x10
> +#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
> +#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
> +#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
> +#define IFI_CANFD_IRQMASK_SET_TX BIT(23)
> +#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24)
> +#define IFI_CANFD_IRQMASK_SET_RX ((u32)BIT(31))
> +
> +#define IFI_CANFD_TIME 0x14
> +#define IFI_CANFD_FTIME 0x18
> +#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_TDELAY 0x1c
> +
> +#define IFI_CANFD_ERROR 0x20
> +#define IFI_CANFD_ERROR_TX_OFFSET 0
> +#define IFI_CANFD_ERROR_TX_MASK 0xff
> +#define IFI_CANFD_ERROR_RX_OFFSET 16
> +#define IFI_CANFD_ERROR_RX_MASK 0xff
> +
> +#define IFI_CANFD_ERRCNT 0x24
> +
> +#define IFI_CANFD_SUSPEND 0x28
> +
> +#define IFI_CANFD_REPEAT 0x2c
> +
> +#define IFI_CANFD_TRAFFIC 0x30
> +
> +#define IFI_CANFD_TSCONTROL 0x34
> +
> +#define IFI_CANFD_TSC 0x38
> +
> +#define IFI_CANFD_TST 0x3c
> +
> +#define IFI_CANFD_RES1 0x40
> +
> +#define IFI_CANFD_RES2 0x44
> +
> +#define IFI_CANFD_PAR 0x48
> +
> +#define IFI_CANFD_CANCLOCK 0x4c
> +
> +#define IFI_CANFD_SYSCLOCK 0x50
> +
> +#define IFI_CANFD_VER 0x54
> +
> +#define IFI_CANFD_IP_ID 0x58
> +#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD
> +
> +#define IFI_CANFD_TEST 0x5c
> +
> +#define IFI_CANFD_RXFIFO_TS_63_32 0x60
> +
> +#define IFI_CANFD_RXFIFO_TS_31_0 0x64
> +
> +#define IFI_CANFD_RXFIFO_DLC 0x68
> +#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0
> +#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf
> +#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4)
> +#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5)
> +#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6)
> +#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7)
> +#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8
> +#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff
> +#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24
> +#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff
> +
> +#define IFI_CANFD_RXFIFO_ID 0x6c
> +#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
> +#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK 0x3ff
> +#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK 0x1fffffff
> +#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
> +
> +#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
> +
> +#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0
> +
> +#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4
> +
> +#define IFI_CANFD_TXFIFO_DLC 0xb8
> +#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0
> +#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf
> +#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4)
> +#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5)
> +#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6)
> +#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24
> +#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff
> +
> +#define IFI_CANFD_TXFIFO_ID 0xbc
> +#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
> +#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK 0x3ff
> +#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK 0x1fffffff
> +#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
> +
> +#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
> +
> +#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0)
> +#define IFI_CANFD_FILTER_MASK_EXT BIT(29)
> +#define IFI_CANFD_FILTER_MASK_EDL BIT(30)
> +#define IFI_CANFD_FILTER_MASK_VALID ((u32)BIT(31))
> +
> +#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4)
> +#define IFI_CANFD_FILTER_IDENT_IDE BIT(29)
> +#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30)
> +#define IFI_CANFD_FILTER_IDENT_VALID ((u32)BIT(31))
> +
> +/* IFI CANFD private data structure */
> +struct ifi_canfd_priv {
> + struct can_priv can; /* must be the first member */
> + struct napi_struct napi;
> + struct net_device *ndev;
> + void __iomem *base;
> +};
> +
> +static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
> +{
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + u32 enirq = 0;
> +
> + if (enable) {
> + enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
> + IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
> + }
> +
> + writel(IFI_CANFD_IRQMASK_SET_ERR |
> + IFI_CANFD_IRQMASK_SET_TS |
> + IFI_CANFD_IRQMASK_SET_TX |
> + IFI_CANFD_IRQMASK_SET_RX | enirq,
> + priv->base + IFI_CANFD_IRQMASK);
> +}
> +
> +static void ifi_canfd_read_fifo(struct net_device *ndev)
> +{
> + struct net_device_stats *stats = &ndev->stats;
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + struct canfd_frame *cf;
> + struct sk_buff *skb;
> + const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
> + IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
> + u32 rxdlc, rxid;
> + u32 dlc, id;
> + int i;
> +
> + rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
> + if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
> + skb = alloc_canfd_skb(ndev, &cf);
> + else
> + skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
> +
> + if (!skb) {
> + stats->rx_dropped++;
> + return;
> + }
> +
> + dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
> + IFI_CANFD_RXFIFO_DLC_DLC_MASK;
> + if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
> + cf->len = can_dlc2len(dlc);
> + else
> + cf->len = get_can_dlc(dlc);
> +
> + rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
> + id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
> + if (id & IFI_CANFD_RXFIFO_ID_IDE)
> + id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
> + else
> + id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
> + cf->can_id = id;
> +
> + if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
> + cf->flags |= CANFD_ESI;
> + netdev_dbg(ndev, "ESI Error\n");
> + }
> +
> + if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
> + (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
> + cf->can_id |= CAN_RTR_FLAG;
> + } else {
> + if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
> + cf->flags |= CANFD_BRS;
> +
> + for (i = 0; i < cf->len; i += 4) {
> + *(u32 *)(cf->data + i) =
> + readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
> + }
> + }
> +
> + /* Remove the packet from FIFO */
> + writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
> + writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->len;
> +
> + netif_receive_skb(skb);
> +}
> +
> +static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
> +{
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + u32 pkts = 0;
> + u32 rxst;
> +
> + rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
> + if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
> + netdev_dbg(ndev, "No messages in RX FIFO\n");
> + return 0;
> + }
> +
> + for (;;) {
> + if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
> + break;
> + if (quota <= 0)
> + break;
> +
> + ifi_canfd_read_fifo(ndev);
> + quota--;
> + pkts++;
> + rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
> + }
> +
> + if (pkts)
> + can_led_event(ndev, CAN_LED_EVENT_RX);
> +
> + return pkts;
> +}
> +
> +static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
> +{
> + struct net_device_stats *stats = &ndev->stats;
> + struct sk_buff *skb;
> + struct can_frame *frame;
> +
> + netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
> +
> + stats->rx_errors++;
> + stats->rx_over_errors++;
> +
> + skb = alloc_can_err_skb(ndev, &frame);
> + if (unlikely(!skb))
> + return 0;
> +
> + frame->can_id |= CAN_ERR_CRTL;
> + frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> +
> + netif_receive_skb(skb);
> +
> + return 1;
> +}
> +
> +static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
> + struct can_berr_counter *bec)
> +{
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + u32 err;
> +
> + err = readl(priv->base + IFI_CANFD_ERROR);
> + bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
> + IFI_CANFD_ERROR_RX_MASK;
> + bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
> + IFI_CANFD_ERROR_TX_MASK;
> +
> + return 0;
> +}
> +
> +static int ifi_canfd_handle_state_change(struct net_device *ndev,
> + enum can_state new_state)
> +{
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + struct net_device_stats *stats = &ndev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct can_berr_counter bec;
> +
> + switch (new_state) {
> + case CAN_STATE_ERROR_ACTIVE:
> + /* error warning state */
> + priv->can.can_stats.error_warning++;
> + priv->can.state = CAN_STATE_ERROR_WARNING;
> + break;
> + case CAN_STATE_ERROR_PASSIVE:
> + /* error passive state */
> + priv->can.can_stats.error_passive++;
> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> + break;
> + case CAN_STATE_BUS_OFF:
> + /* bus-off state */
> + priv->can.state = CAN_STATE_BUS_OFF;
> + ifi_canfd_irq_enable(ndev, 0);
> + priv->can.can_stats.bus_off++;
> + can_bus_off(ndev);
> + break;
> + default:
> + break;
> + }
> +
> + /* propagate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(ndev, &cf);
> + if (unlikely(!skb))
> + return 0;
> +
> + ifi_canfd_get_berr_counter(ndev, &bec);
> +
> + switch (new_state) {
> + case CAN_STATE_ERROR_ACTIVE:
> + /* error warning state */
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] = (bec.txerr > bec.rxerr) ?
> + CAN_ERR_CRTL_TX_WARNING :
> + CAN_ERR_CRTL_RX_WARNING;
> + cf->data[6] = bec.txerr;
> + cf->data[7] = bec.rxerr;
> + break;
> + case CAN_STATE_ERROR_PASSIVE:
> + /* error passive state */
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + if (bec.txerr > 127)
> + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> + cf->data[6] = bec.txerr;
> + cf->data[7] = bec.rxerr;
> + break;
> + case CAN_STATE_BUS_OFF:
> + /* bus-off state */
> + cf->can_id |= CAN_ERR_BUSOFF;
> + break;
> + default:
> + break;
> + }
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> + netif_receive_skb(skb);
> +
> + return 1;
> +}
> +
> +static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
> +{
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + int work_done = 0;
> + u32 isr;
> +
> + /*
> + * The ErrWarn condition is a little special, since the bit is
> + * located in the INTERRUPT register instead of STCMD register.
> + */
> + isr = readl(priv->base + IFI_CANFD_INTERRUPT);
> + if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
> + (priv->can.state != CAN_STATE_ERROR_WARNING)) {
> + /* Clear the interrupt */
> + writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
> + priv->base + IFI_CANFD_INTERRUPT);
> + netdev_dbg(ndev, "Error, entered warning state\n");
> + work_done += ifi_canfd_handle_state_change(ndev,
> + CAN_STATE_ERROR_WARNING);
> + }
> +
> + if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
> + (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
> + netdev_dbg(ndev, "Error, entered passive state\n");
> + work_done += ifi_canfd_handle_state_change(ndev,
> + CAN_STATE_ERROR_PASSIVE);
> + }
> +
> + if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
> + (priv->can.state != CAN_STATE_BUS_OFF)) {
> + netdev_dbg(ndev, "Error, entered bus-off state\n");
> + work_done += ifi_canfd_handle_state_change(ndev,
> + CAN_STATE_BUS_OFF);
> + }
> +
> + return work_done;
> +}
> +
> +static int ifi_canfd_poll(struct napi_struct *napi, int quota)
> +{
> + struct net_device *ndev = napi->dev;
> + struct ifi_canfd_priv *priv = netdev_priv(ndev);
> + const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
> + IFI_CANFD_STCMD_BUSOFF;
> + int work_done = 0;
> +
> + u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
> + u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
> +
> + /* Handle bus state changes */
> + if ((stcmd & stcmd_state_mask) ||
> + ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
> + work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
> +
> + /* Handle lost messages on RX */
> + if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
> + work_done += ifi_canfd_handle_lost_msg(ndev);
> +
> + /* Handle normal messages on RX */
> + if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
> + work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
> +
> + if (work_done < quota) {
> + napi_complete(napi);
> + ifi_canfd_irq_enable(ndev, 1);
> + }
> +
> + return work_done;
> +}
> +
> +static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
> +{
> + struct net_device *ndev = (struct net_device *)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;
> + const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
> + IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
> + const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
> + IFI_CANFD_INTERRUPT_ERROR_WARNING));
I've squashed:
>> - const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
>> - IFI_CANFD_INTERRUPT_ERROR_WARNING));
>> + const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
>> + IFI_CANFD_INTERRUPT_ERROR_WARNING);
and the driver compiles without warnings.
Applied to can-next.
thanks,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:39 ` Marc Kleine-Budde
@ 2016-01-20 14:41 ` Marek Vasut
2016-01-20 14:46 ` Marc Kleine-Budde
0 siblings, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 14:41 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
On Wednesday, January 20, 2016 at 03:39:51 PM, Marc Kleine-Budde wrote:
> On 01/20/2016 03:33 PM, Marek Vasut wrote:
> > The patch adds support for IFI CAN/FD controller [1]. This driver
> > currently supports sending and receiving both standard CAN and new
> > CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
> >
> > [1] http://www.ifi-pld.de/IP/CANFD/canfd.html
> >
> > Signed-off-by: Marek Vasut <marex@denx.de>
> > Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > Cc: Oliver Hartkopp <socketcan@hartkopp.net>
> > Cc: Wolfgang Grandegger <wg@grandegger.com>
> > ---
> > V2: - Move request_irq()/free_irq() into
> > ifi_canfd_open()/ifi_canfd_close()
> >
> > just like other drivers do it to prevent crash when reloading
> > module.
> >
> > - Fix Woverflow complains on x86_64 and itanium, exactly the same way
> >
> > as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
> >
> > V3: - Hopefully fix all problems with BIT(31) by adding more u32 casts.
> >
> > - Drop struct device from struct ifi_canfd_priv .
> >
> > NOTE: The driver is surprisingly similar to m_can, but the register
> >
> > layout of the IFI core is completely different, so it's clear
> > that those are two different IP cores.
> >
> > ---
[...]
Hi,
> > +static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
> > +{
> > + struct net_device *ndev = (struct net_device *)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;
> > + const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
> > + IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
> > + const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
> > + IFI_CANFD_INTERRUPT_ERROR_WARNING));
>
> I've squashed:
> >> - const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
> >> -
> >> IFI_CANFD_INTERRUPT_ERROR_WARNING)); + const u32 clr_irq_mask =
> >> ~(IFI_CANFD_INTERRUPT_SET_IRQ | +
> >> IFI_CANFD_INTERRUPT_ERROR_WARNING);
>
> and the driver compiles without warnings.
It doesn't , try with x86_64_defconfig, it will complain with -Woverflow
on gcc 4.9 or newer. That's what the kernel robot complained about in V1
of the patch too.
I'd be happy to be proven wrong though.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:41 ` Marek Vasut
@ 2016-01-20 14:46 ` Marc Kleine-Budde
2016-01-20 15:03 ` Marek Vasut
0 siblings, 1 reply; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 14:46 UTC (permalink / raw)
To: Marek Vasut; +Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 3083 bytes --]
On 01/20/2016 03:41 PM, Marek Vasut wrote:
> On Wednesday, January 20, 2016 at 03:39:51 PM, Marc Kleine-Budde wrote:
>> On 01/20/2016 03:33 PM, Marek Vasut wrote:
>>> The patch adds support for IFI CAN/FD controller [1]. This driver
>>> currently supports sending and receiving both standard CAN and new
>>> CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
>>>
>>> [1] http://www.ifi-pld.de/IP/CANFD/canfd.html
>>>
>>> Signed-off-by: Marek Vasut <marex@denx.de>
>>> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
>>> Cc: Mark Rutland <mark.rutland@arm.com>
>>> Cc: Oliver Hartkopp <socketcan@hartkopp.net>
>>> Cc: Wolfgang Grandegger <wg@grandegger.com>
>>> ---
>>> V2: - Move request_irq()/free_irq() into
>>> ifi_canfd_open()/ifi_canfd_close()
>>>
>>> just like other drivers do it to prevent crash when reloading
>>> module.
>>>
>>> - Fix Woverflow complains on x86_64 and itanium, exactly the same way
>>>
>>> as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
>>>
>>> V3: - Hopefully fix all problems with BIT(31) by adding more u32 casts.
>>>
>>> - Drop struct device from struct ifi_canfd_priv .
>>>
>>> NOTE: The driver is surprisingly similar to m_can, but the register
>>>
>>> layout of the IFI core is completely different, so it's clear
>>> that those are two different IP cores.
>>>
>>> ---
>
> [...]
>
> Hi,
>
>>> +static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
>>> +{
>>> + struct net_device *ndev = (struct net_device *)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;
>>> + const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
>>> + IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
>>> + const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
>>> + IFI_CANFD_INTERRUPT_ERROR_WARNING));
>>
>> I've squashed:
>>>> - const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
>>>> -
>>>> IFI_CANFD_INTERRUPT_ERROR_WARNING)); + const u32 clr_irq_mask =
>>>> ~(IFI_CANFD_INTERRUPT_SET_IRQ | +
>>>> IFI_CANFD_INTERRUPT_ERROR_WARNING);
>>
>> and the driver compiles without warnings.
>
> It doesn't , try with x86_64_defconfig, it will complain with -Woverflow
> on gcc 4.9 or newer. That's what the kernel robot complained about in V1
> of the patch too.
Doh! Right, let's try this:
>> -#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
>> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1))
> I'd be happy to be proven wrong though.
/me too
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:46 ` Marc Kleine-Budde
@ 2016-01-20 15:03 ` Marek Vasut
2016-01-20 15:09 ` Marc Kleine-Budde
0 siblings, 1 reply; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 15:03 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
On Wednesday, January 20, 2016 at 03:46:58 PM, Marc Kleine-Budde wrote:
> On 01/20/2016 03:41 PM, Marek Vasut wrote:
> > On Wednesday, January 20, 2016 at 03:39:51 PM, Marc Kleine-Budde wrote:
> >> On 01/20/2016 03:33 PM, Marek Vasut wrote:
> >>> The patch adds support for IFI CAN/FD controller [1]. This driver
> >>> currently supports sending and receiving both standard CAN and new
> >>> CAN/FD frames. Both ISO and BOSCH variant of CAN/FD is supported.
> >>>
> >>> [1] http://www.ifi-pld.de/IP/CANFD/canfd.html
> >>>
> >>> Signed-off-by: Marek Vasut <marex@denx.de>
> >>> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> >>> Cc: Mark Rutland <mark.rutland@arm.com>
> >>> Cc: Oliver Hartkopp <socketcan@hartkopp.net>
> >>> Cc: Wolfgang Grandegger <wg@grandegger.com>
> >>> ---
> >>> V2: - Move request_irq()/free_irq() into
> >>> ifi_canfd_open()/ifi_canfd_close()
> >>>
> >>> just like other drivers do it to prevent crash when reloading
> >>> module.
> >>>
> >>> - Fix Woverflow complains on x86_64 and itanium, exactly the same
> >>> way
> >>>
> >>> as in commit dec23dca5a9ca4b9eb2fb66926f567889028b904 .
> >>>
> >>> V3: - Hopefully fix all problems with BIT(31) by adding more u32 casts.
> >>>
> >>> - Drop struct device from struct ifi_canfd_priv .
> >>>
> >>> NOTE: The driver is surprisingly similar to m_can, but the register
> >>>
> >>> layout of the IFI core is completely different, so it's clear
> >>> that those are two different IP cores.
> >>>
> >>> ---
> >
> > [...]
> >
> > Hi,
> >
> >>> +static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
> >>> +{
> >>> + struct net_device *ndev = (struct net_device *)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;
> >>> + const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
> >>> + IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
> >>> + const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
> >>> + IFI_CANFD_INTERRUPT_ERROR_WARNING));
> >>
> >> I've squashed:
> >>>> - const u32 clr_irq_mask = (u32)(~(IFI_CANFD_INTERRUPT_SET_IRQ |
> >>>> -
> >>>> IFI_CANFD_INTERRUPT_ERROR_WARNING)); + const u32 clr_irq_mask =
> >>>> ~(IFI_CANFD_INTERRUPT_SET_IRQ | +
> >>>> IFI_CANFD_INTERRUPT_ERROR_WARNING);
> >>
> >> and the driver compiles without warnings.
> >
> > It doesn't , try with x86_64_defconfig, it will complain with -Woverflow
> > on gcc 4.9 or newer. That's what the kernel robot complained about in V1
> > of the patch too.
>
> Doh! Right, let's try this:
> >> -#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
> >> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1))
> >
> > I'd be happy to be proven wrong though.
>
> /me too
I think that will do the trick too. Do you want a V4 patch or will you fix it?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 15:03 ` Marek Vasut
@ 2016-01-20 15:09 ` Marc Kleine-Budde
2016-01-20 15:40 ` Marek Vasut
0 siblings, 1 reply; 22+ messages in thread
From: Marc Kleine-Budde @ 2016-01-20 15:09 UTC (permalink / raw)
To: Marek Vasut; +Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 662 bytes --]
On 01/20/2016 04:03 PM, Marek Vasut wrote:
>>
>> Doh! Right, let's try this:
>>>> -#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
>>>> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1))
>>>
>>> I'd be happy to be proven wrong though.
>>
>> /me too
>
> I think that will do the trick too. Do you want a V4 patch or will you fix it?
I'll fix this.
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 15:09 ` Marc Kleine-Budde
@ 2016-01-20 15:40 ` Marek Vasut
0 siblings, 0 replies; 22+ messages in thread
From: Marek Vasut @ 2016-01-20 15:40 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, Oliver Hartkopp, Mark Rutland, Wolfgang Grandegger
On Wednesday, January 20, 2016 at 04:09:48 PM, Marc Kleine-Budde wrote:
> On 01/20/2016 04:03 PM, Marek Vasut wrote:
> >> Doh! Right, let's try this:
> >>>> -#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
> >>>> +#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1))
> >>>
> >>> I'd be happy to be proven wrong though.
> >>
> >> /me too
> >
> > I think that will do the trick too. Do you want a V4 patch or will you
> > fix it?
>
> I'll fix this.
Thanks :)
Best regards,
Marek Vasut
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V2 5/5] net: can: ifi: Add IFI CANFD IP support
2016-01-20 14:25 ` Marek Vasut
@ 2016-01-23 0:11 ` Rustad, Mark D
0 siblings, 0 replies; 22+ messages in thread
From: Rustad, Mark D @ 2016-01-23 0:11 UTC (permalink / raw)
To: Marek Vasut
Cc: Marc Kleine-Budde, netdev, Oliver Hartkopp, Mark Rutland,
Wolfgang Grandegger
[-- Attachment #1: Type: text/plain, Size: 610 bytes --]
Marek Vasut <marex@denx.de> wrote:
> I see, so adding u32 also here works. I'm starting to wonder if the BIT
> macro is really that nice and if I shouldn't just use (1 << n) as usual.
Actually, (1 << n) is not so good either when n is 31 - it can trigger
overflow warnings since it will be presumed to be a signed value. (1U << n)
should avoid that problem. Unfortunately, BIT() uses 1UL which produces
64-bit values on 64-bit arches. The bit ops are kind of a mess in that way.
It would be nicer if BIT was restricted to int-size values and a new BIT_UL
or something would produce the long values.
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2016-01-23 0:11 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-11 18:47 [PATCH 1/5] net: can: Sort the Kconfig includes Marek Vasut
2016-01-11 18:48 ` [PATCH 2/5] net: can: Sort the Makefile Marek Vasut
2016-01-11 18:48 ` [PATCH 3/5] of: Add vendor prefix for I/F/I Marek Vasut
2016-01-11 18:48 ` [PATCH 4/5] net: can: ifi: Add DT bindings for ifi,canfd Marek Vasut
2016-01-11 18:48 ` [PATCH 5/5] net: can: ifi: Add IFI CANFD IP support Marek Vasut
2016-01-11 19:29 ` kbuild test robot
2016-01-11 19:33 ` Marek Vasut
2016-01-12 11:06 ` kbuild test robot
2016-01-12 23:59 ` [PATCH V2 " Marek Vasut
2016-01-20 10:39 ` Marc Kleine-Budde
2016-01-20 10:54 ` Marc Kleine-Budde
2016-01-20 12:58 ` Marek Vasut
2016-01-20 14:06 ` Marc Kleine-Budde
2016-01-20 14:25 ` Marek Vasut
2016-01-23 0:11 ` Rustad, Mark D
2016-01-20 14:33 ` [PATCH V3 " Marek Vasut
2016-01-20 14:39 ` Marc Kleine-Budde
2016-01-20 14:41 ` Marek Vasut
2016-01-20 14:46 ` Marc Kleine-Budde
2016-01-20 15:03 ` Marek Vasut
2016-01-20 15:09 ` Marc Kleine-Budde
2016-01-20 15:40 ` Marek Vasut
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.