diff options
| author | David S. Miller <davem@davemloft.net> | 2017-04-25 10:52:47 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-04-25 10:52:47 -0400 |
| commit | 45a6f3bca64ac8f462a275f351dcc3f032073d92 (patch) | |
| tree | a012e3e981c39e66e6c94c11984533ddb1ae5b38 | |
| parent | 3133822f5ac13b04c2ca46f27cfe74606bbd4a6d (diff) | |
| parent | b655f0e96d4061eac42dea2dccd37a3348d1f3f3 (diff) | |
| download | linux-45a6f3bca64ac8f462a275f351dcc3f032073d92.tar.gz linux-45a6f3bca64ac8f462a275f351dcc3f032073d92.tar.bz2 linux-45a6f3bca64ac8f462a275f351dcc3f032073d92.zip | |
Merge tag 'linux-can-next-for-4.12-20170425' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
Marc Kleine-Budde says:
====================
pull-request: can-next 2017-04-25
this is a pull request of 21 patches for net-next/master.
There are 4 patches by Stephane Grosjean for the PEAK PCAN-PCIe FD
CAN-FD boards. The next 7 patches are by Mario Huettel, which add
support for M_CAN IP version >= v3.1.x to the m_can driver. A patch by
Remigiusz Kołłątaj adds support for the Microchip CAN BUS Analyzer. 8
patches by Oliver Hartkopp complete the initial CAN network namespace
support. Wei Yongjun's patch for the ti_hecc driver fixes the return
value check in the probe function.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
24 files changed, 3888 insertions, 372 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 22570ea3a8d2..ac4ff394bc56 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -9,6 +9,24 @@ config CAN_VCAN This driver can also be built as a module. If so, the module will be called vcan. +config CAN_VXCAN + tristate "Virtual CAN Tunnel (vxcan)" + ---help--- + Similar to the virtual ethernet driver veth, vxcan implements a + local CAN traffic tunnel between two virtual CAN network devices. + When creating a vxcan, two vxcan devices are created as pair. + When one end receives the packet it appears on its pair and vice + versa. The vxcan can be used for cross namespace communication. + + In opposite to vcan loopback devices the vxcan only forwards CAN + frames to its pair and does *not* provide a local echo of sent + CAN frames. To disable a potential echo in af_can.c the vxcan driver + announces IFF_ECHO in the interface flags. To have a clean start + in each namespace the CAN GW hop counter is set to zero. + + This driver can also be built as a module. If so, the module + will be called vxcan. + config CAN_SLCAN tristate "Serial / USB serial CAN Adaptors (slcan)" depends on TTY @@ -142,6 +160,7 @@ 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" +source "drivers/net/can/peak_canfd/Kconfig" source "drivers/net/can/rcar/Kconfig" source "drivers/net/can/sja1000/Kconfig" source "drivers/net/can/softing/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 0da4f2f5c7e3..4aabbee133b8 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_CAN_VCAN) += vcan.o +obj-$(CONFIG_CAN_VXCAN) += vxcan.o obj-$(CONFIG_CAN_SLCAN) += slcan.o obj-$(CONFIG_CAN_DEV) += can-dev.o @@ -26,6 +27,7 @@ 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/ +obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 7a6554efd42b..bf8fdaeb955e 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -23,7 +23,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> - +#include <linux/iopoll.h> #include <linux/can/dev.h> /* napi related */ @@ -37,17 +37,19 @@ enum m_can_reg { M_CAN_CREL = 0x0, M_CAN_ENDN = 0x4, M_CAN_CUST = 0x8, - M_CAN_FBTP = 0xc, + M_CAN_DBTP = 0xc, M_CAN_TEST = 0x10, M_CAN_RWD = 0x14, M_CAN_CCCR = 0x18, - M_CAN_BTP = 0x1c, + M_CAN_NBTP = 0x1c, M_CAN_TSCC = 0x20, M_CAN_TSCV = 0x24, M_CAN_TOCC = 0x28, M_CAN_TOCV = 0x2c, M_CAN_ECR = 0x40, M_CAN_PSR = 0x44, +/* TDCR Register only available for version >=3.1.x */ + M_CAN_TDCR = 0x48, M_CAN_IR = 0x50, M_CAN_IE = 0x54, M_CAN_ILS = 0x58, @@ -105,21 +107,29 @@ enum m_can_mram_cfg { MRAM_CFG_NUM, }; -/* Fast Bit Timing & Prescaler Register (FBTP) */ -#define FBTR_FBRP_MASK 0x1f -#define FBTR_FBRP_SHIFT 16 -#define FBTR_FTSEG1_SHIFT 8 -#define FBTR_FTSEG1_MASK (0xf << FBTR_FTSEG1_SHIFT) -#define FBTR_FTSEG2_SHIFT 4 -#define FBTR_FTSEG2_MASK (0x7 << FBTR_FTSEG2_SHIFT) -#define FBTR_FSJW_SHIFT 0 -#define FBTR_FSJW_MASK 0x3 +/* Core Release Register (CREL) */ +#define CREL_REL_SHIFT 28 +#define CREL_REL_MASK (0xF << CREL_REL_SHIFT) +#define CREL_STEP_SHIFT 24 +#define CREL_STEP_MASK (0xF << CREL_STEP_SHIFT) +#define CREL_SUBSTEP_SHIFT 20 +#define CREL_SUBSTEP_MASK (0xF << CREL_SUBSTEP_SHIFT) + +/* Data Bit Timing & Prescaler Register (DBTP) */ +#define DBTP_TDC BIT(23) +#define DBTP_DBRP_SHIFT 16 +#define DBTP_DBRP_MASK (0x1f << DBTP_DBRP_SHIFT) +#define DBTP_DTSEG1_SHIFT 8 +#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT) +#define DBTP_DTSEG2_SHIFT 4 +#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT) +#define DBTP_DSJW_SHIFT 0 +#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) /* Test Register (TEST) */ -#define TEST_LBCK BIT(4) +#define TEST_LBCK BIT(4) /* CC Control Register(CCCR) */ -#define CCCR_TEST BIT(7) #define CCCR_CMR_MASK 0x3 #define CCCR_CMR_SHIFT 10 #define CCCR_CMR_CANFD 0x1 @@ -130,21 +140,32 @@ enum m_can_mram_cfg { #define CCCR_CME_CAN 0 #define CCCR_CME_CANFD 0x1 #define CCCR_CME_CANFD_BRS 0x2 +#define CCCR_TXP BIT(14) #define CCCR_TEST BIT(7) #define CCCR_MON BIT(5) +#define CCCR_CSR BIT(4) +#define CCCR_CSA BIT(3) +#define CCCR_ASM BIT(2) #define CCCR_CCE BIT(1) #define CCCR_INIT BIT(0) #define CCCR_CANFD 0x10 - -/* Bit Timing & Prescaler Register (BTP) */ -#define BTR_BRP_MASK 0x3ff -#define BTR_BRP_SHIFT 16 -#define BTR_TSEG1_SHIFT 8 -#define BTR_TSEG1_MASK (0x3f << BTR_TSEG1_SHIFT) -#define BTR_TSEG2_SHIFT 4 -#define BTR_TSEG2_MASK (0xf << BTR_TSEG2_SHIFT) -#define BTR_SJW_SHIFT 0 -#define BTR_SJW_MASK 0xf +/* for version >=3.1.x */ +#define CCCR_EFBI BIT(13) +#define CCCR_PXHD BIT(12) +#define CCCR_BRSE BIT(9) +#define CCCR_FDOE BIT(8) +/* only for version >=3.2.x */ +#define CCCR_NISO BIT(15) + +/* Nominal Bit Timing & Prescaler Register (NBTP) */ +#define NBTP_NSJW_SHIFT 25 +#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT) +#define NBTP_NBRP_SHIFT 16 +#define NBTP_NBRP_MASK (0x1ff << NBTP_NBRP_SHIFT) +#define NBTP_NTSEG1_SHIFT 8 +#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT) +#define NBTP_NTSEG2_SHIFT 0 +#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT) /* Error Counter Register(ECR) */ #define ECR_RP BIT(15) @@ -161,6 +182,13 @@ enum m_can_mram_cfg { /* Interrupt Register(IR) */ #define IR_ALL_INT 0xffffffff + +/* Renamed bits for versions > 3.1.x */ +#define IR_ARA BIT(29) +#define IR_PED BIT(28) +#define IR_PEA BIT(27) + +/* Bits for version 3.0.x */ #define IR_STE BIT(31) #define IR_FOE BIT(30) #define IR_ACKE BIT(29) @@ -194,33 +222,40 @@ enum m_can_mram_cfg { #define IR_RF0W BIT(1) #define IR_RF0N BIT(0) #define IR_ERR_STATE (IR_BO | IR_EW | IR_EP) -#define IR_ERR_LEC (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE) -#define IR_ERR_BUS (IR_ERR_LEC | IR_WDI | IR_ELO | IR_BEU | \ + +/* Interrupts for version 3.0.x */ +#define IR_ERR_LEC_30X (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE) +#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \ IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \ IR_RF1L | IR_RF0L) -#define IR_ERR_ALL (IR_ERR_STATE | IR_ERR_BUS) +#define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X) +/* Interrupts for version >= 3.1.x */ +#define IR_ERR_LEC_31X (IR_PED | IR_PEA) +#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \ + IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \ + IR_RF1L | IR_RF0L) +#define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X) /* Interrupt Line Select (ILS) */ #define ILS_ALL_INT0 0x0 #define ILS_ALL_INT1 0xFFFFFFFF /* Interrupt Line Enable (ILE) */ -#define ILE_EINT0 BIT(0) #define ILE_EINT1 BIT(1) +#define ILE_EINT0 BIT(0) /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */ -#define RXFC_FWM_OFF 24 -#define RXFC_FWM_MASK 0x7f -#define RXFC_FWM_1 (1 << RXFC_FWM_OFF) -#define RXFC_FS_OFF 16 -#define RXFC_FS_MASK 0x7f +#define RXFC_FWM_SHIFT 24 +#define RXFC_FWM_MASK (0x7f < RXFC_FWM_SHIFT) +#define RXFC_FS_SHIFT 16 +#define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT) /* Rx FIFO 0/1 Status (RXF0S/RXF1S) */ #define RXFS_RFL BIT(25) #define RXFS_FF BIT(24) -#define RXFS_FPI_OFF 16 +#define RXFS_FPI_SHIFT 16 #define RXFS_FPI_MASK 0x3f0000 -#define RXFS_FGI_OFF 8 +#define RXFS_FGI_SHIFT 8 #define RXFS_FGI_MASK 0x3f00 #define RXFS_FFL_MASK 0x7f @@ -229,23 +264,46 @@ enum m_can_mram_cfg { #define M_CAN_RXESC_64BYTES 0x777 /* Tx Buffer Configuration(TXBC) */ -#define TXBC_NDTB_OFF 16 -#define TXBC_NDTB_MASK 0x3f +#define TXBC_NDTB_SHIFT 16 +#define TXBC_NDTB_MASK (0x3f << TXBC_NDTB_SHIFT) +#define TXBC_TFQS_SHIFT 24 +#define TXBC_TFQS_MASK (0x3f << TXBC_TFQS_SHIFT) + +/* Tx FIFO/Queue Status (TXFQS) */ +#define TXFQS_TFQF BIT(21) +#define TXFQS_TFQPI_SHIFT 16 +#define TXFQS_TFQPI_MASK (0x1f << TXFQS_TFQPI_SHIFT) +#define TXFQS_TFGI_SHIFT 8 +#define TXFQS_TFGI_MASK (0x1f << TXFQS_TFGI_SHIFT) +#define TXFQS_TFFL_SHIFT 0 +#define TXFQS_TFFL_MASK (0x3f << TXFQS_TFFL_SHIFT) /* Tx Buffer Element Size Configuration(TXESC) */ #define TXESC_TBDS_8BYTES 0x0 #define TXESC_TBDS_64BYTES 0x7 -/* Tx Event FIFO Con.guration (TXEFC) */ -#define TXEFC_EFS_OFF 16 -#define TXEFC_EFS_MASK 0x3f +/* Tx Event FIFO Configuration (TXEFC) */ +#define TXEFC_EFS_SHIFT 16 +#define TXEFC_EFS_MASK (0x3f << TXEFC_EFS_SHIFT) + +/* Tx Event FIFO Status (TXEFS) */ +#define TXEFS_TEFL BIT(25) +#define TXEFS_EFF BIT(24) +#define TXEFS_EFGI_SHIFT 8 +#define TXEFS_EFGI_MASK (0x1f << TXEFS_EFGI_SHIFT) +#define TXEFS_EFFL_SHIFT 0 +#define TXEFS_EFFL_MASK (0x3f << TXEFS_EFFL_SHIFT) + +/* Tx Event FIFO Acknowledge (TXEFA) */ +#define TXEFA_EFAI_SHIFT 0 +#define TXEFA_EFAI_MASK (0x1f << TXEFA_EFAI_SHIFT) /* Message RAM Configuration (in bytes) */ #define SIDF_ELEMENT_SIZE 4 #define XIDF_ELEMENT_SIZE 8 #define RXF0_ELEMENT_SIZE 72 #define RXF1_ELEMENT_SIZE 72 -#define RXB_ELEMENT_SIZE 16 +#define RXB_ELEMENT_SIZE 72 #define TXE_ELEMENT_SIZE 8 #define TXB_ELEMENT_SIZE 72 @@ -261,13 +319,25 @@ enum m_can_mram_cfg { #define RX_BUF_RTR BIT(29) /* R1 */ #define RX_BUF_ANMF BIT(31) -#define RX_BUF_EDL BIT(21) +#define RX_BUF_FDF BIT(21) #define RX_BUF_BRS BIT(20) /* Tx Buffer Element */ -/* R0 */ +/* T0 */ +#define TX_BUF_ESI BIT(31) #define TX_BUF_XTD BIT(30) #define TX_BUF_RTR BIT(29) +/* T1 */ +#define TX_BUF_EFC BIT(23) +#define TX_BUF_FDF BIT(21) +#define TX_BUF_BRS BIT(20) +#define TX_BUF_MM_SHIFT 24 +#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT) + +/* Tx event FIFO Element */ +/* E1 */ +#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT +#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) /* address offset and element number for each FIFO/Buffer in the Message RAM */ struct mram_cfg { @@ -285,6 +355,7 @@ struct m_can_priv { struct clk *cclk; void __iomem *base; u32 irqstatus; + int version; /* message ram configuration */ void __iomem *mram_base; @@ -316,6 +387,18 @@ static inline void m_can_fifo_write(const struct m_can_priv *priv, fpi * TXB_ELEMENT_SIZE + offset); } +static inline u32 m_can_txe_fifo_read(const struct m_can_priv *priv, + u32 fgi, + u32 offset) { + return readl(priv->mram_base + priv->mcfg[MRAM_TXE].off + + fgi * TXE_ELEMENT_SIZE + offset); +} + +static inline bool m_can_tx_fifo_full(const struct m_can_priv *priv) +{ + return !!(m_can_read(priv, M_CAN_TXFQS) & TXFQS_TFQF); +} + static inline void m_can_config_endisable(const struct m_can_priv *priv, bool enable) { @@ -349,7 +432,8 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv, static inline void m_can_enable_all_interrupts(const struct m_can_priv *priv) { - m_can_write(priv, M_CAN_ILE, ILE_EINT0 | ILE_EINT1); + /* Only interrupt line 0 is used in this driver */ + m_can_write(priv, M_CAN_ILE, ILE_EINT0); } static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv) @@ -367,9 +451,9 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs) int i; /* calculate the fifo get index for where to read data */ - fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF; + fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_SHIFT; dlc = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC); - if (dlc & RX_BUF_EDL) + if (dlc & RX_BUF_FDF) skb = alloc_canfd_skb(dev, &cf); else skb = alloc_can_skb(dev, (struct can_frame **)&cf); @@ -378,7 +462,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs) return; } - if (dlc & RX_BUF_EDL) + if (dlc & RX_BUF_FDF) cf->len = can_dlc2len((dlc >> 16) & 0x0F); else cf->len = get_can_dlc((dlc >> 16) & 0x0F); @@ -394,7 +478,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs) netdev_dbg(dev, "ESI Error\n"); } - if (!(dlc & RX_BUF_EDL) && (id & RX_BUF_RTR)) { + if (!(dlc & RX_BUF_FDF) && (id & RX_BUF_RTR)) { cf->can_id |= CAN_RTR_FLAG; } else { if (dlc & RX_BUF_BRS) @@ -532,7 +616,7 @@ static int __m_can_get_berr_counter(const struct net_device *dev, ecr = m_can_read(priv, M_CAN_ECR); bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT; - bec->txerr = ecr & ECR_TEC_MASK; + bec->txerr = (ecr & ECR_TEC_MASK) >> ECR_TEC_SHIFT; return 0; } @@ -723,7 +807,7 @@ static int m_can_poll(struct napi_struct *napi, int quota) if (irqstatus & IR_ERR_STATE) work_done += m_can_handle_state_errors(dev, psr); - if (irqstatus & IR_ERR_BUS) + if (irqstatus & IR_ERR_BUS_30X) work_done += m_can_handle_bus_errors(dev, irqstatus, psr); if (irqstatus & IR_RF0N) @@ -738,6 +822,44 @@ end: return work_done; } +static void m_can_echo_tx_event(struct net_device *dev) +{ + u32 txe_count = 0; + u32 m_can_txefs; + u32 fgi = 0; + int i = 0; + unsigned int msg_mark; + + struct m_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + + /* read tx event fifo status */ + m_can_txefs = m_can_read(priv, M_CAN_TXEFS); + + /* Get Tx Event fifo element count */ + txe_count = (m_can_txefs & TXEFS_EFFL_MASK) + >> TXEFS_EFFL_SHIFT; + + /* Get and process all sent elements */ + for (i = 0; i < txe_count; i++) { + /* retrieve get index */ + fgi = (m_can_read(priv, M_CAN_TXEFS) & TXEFS_EFGI_MASK) + >> TXEFS_EFGI_SHIFT; + + /* get message marker */ + msg_mark = (m_can_txe_fifo_read(priv, fgi, 4) & + TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT; + + /* ack txe element */ + m_can_write(priv, M_CAN_TXEFA, (TXEFA_EFAI_MASK & + (fgi << TXEFA_EFAI_SHIFT))); + + /* update stats */ + stats->tx_bytes += can_get_echo_skb(dev, msg_mark); + stats->tx_packets++; + } +} + static irqreturn_t m_can_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; @@ -758,24 +880,35 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) * - state change IRQ * - bus error IRQ and bus error reporting */ - if ((ir & IR_RF0N) || (ir & IR_ERR_ALL)) { + if ((ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) { priv->irqstatus = ir; m_can_disable_all_interrupts(priv); napi_schedule(&priv->napi); } - /* transmission complete interrupt */ - if (ir & IR_TC) { - stats->tx_bytes += can_get_echo_skb(dev, 0); - stats->tx_packets++; - can_led_event(dev, CAN_LED_EVENT_TX); - netif_wake_queue(dev); + if (priv->version == 30) { + if (ir & IR_TC) { + /* Transmission Complete Interrupt*/ + stats->tx_bytes += can_get_echo_skb(dev, 0); + stats->tx_packets++; + can_led_event(dev, CAN_LED_EVENT_TX); + netif_wake_queue(dev); + } + } else { + if (ir & IR_TEFN) { + /* New TX FIFO Element arrived */ + m_can_echo_tx_event(dev); + can_led_event(dev, CAN_LED_EVENT_TX); + if (netif_queue_stopped(dev) && + !m_can_tx_fifo_full(priv)) + netif_wake_queue(dev); + } } return IRQ_HANDLED; } -static const struct can_bittiming_const m_can_bittiming_const = { +static const struct can_bittiming_const m_can_bittiming_const_30X = { .name = KBUILD_MODNAME, .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ .tseg1_max = 64, @@ -787,7 +920,7 @@ static const struct can_bittiming_const m_can_bittiming_const = { .brp_inc = 1, }; -static const struct can_bittiming_const m_can_data_bittiming_const = { +static const struct can_bittiming_const m_can_data_bittiming_const_30X = { .name = KBUILD_MODNAME, .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ .tseg1_max = 16, @@ -799,6 +932,30 @@ static const struct can_bittiming_const m_can_data_bittiming_const = { .brp_inc = 1, }; +static const struct can_bittiming_const m_can_bittiming_const_31X = { + .name = KBUILD_MODNAME, + .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ + .tseg1_max = 256, + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ + .tseg2_max = 128, + .sjw_max = 128, + .brp_min = 1, + .brp_max = 512, + .brp_inc = 1, +}; + +static const struct can_bittiming_const m_can_data_bittiming_const_31X = { + .name = KBUILD_MODNAME, + .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ + .tseg1_max = 32, + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 32, + .brp_inc = 1, +}; + static int m_can_set_bittiming(struct net_device *dev) { struct m_can_priv *priv = netdev_priv(dev); @@ -811,19 +968,19 @@ static int m_can_set_bittiming(struct net_device *dev) sjw = bt->sjw - 1; tseg1 = bt->prop_seg + bt->phase_seg1 - 1; tseg2 = bt->phase_seg2 - 1; - reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) | - (tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT); - m_can_write(priv, M_CAN_BTP, reg_btp); + reg_btp = (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) | + (tseg1 << NBTP_NTSEG1_SHIFT) | (tseg2 << NBTP_NTSEG2_SHIFT); + m_can_write(priv, M_CAN_NBTP, reg_btp); if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { brp = dbt->brp - 1; sjw = dbt->sjw - 1; tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; tseg2 = dbt->phase_seg2 - 1; - reg_btp = (brp << FBTR_FBRP_SHIFT) | (sjw << FBTR_FSJW_SHIFT) | - (tseg1 << FBTR_FTSEG1_SHIFT) | - (tseg2 << FBTR_FTSEG2_SHIFT); - m_can_write(priv, M_CAN_FBTP, reg_btp); + reg_btp = (brp << DBTP_DBRP_SHIFT) | (sjw << DBTP_DSJW_SHIFT) | + (tseg1 << DBTP_DTSEG1_SHIFT) | + (tseg2 << DBTP_DTSEG2_SHIFT); + m_can_write(priv, M_CAN_DBTP, reg_btp); } return 0; @@ -834,6 +991,7 @@ static int m_can_set_bittiming(struct net_device *dev) * - configure rx fifo * - accept non-matching frame into fifo 0 * - configure tx buffer + * - >= v3.1.x: TX FIFO is used * - configure mode * - setup bittiming */ @@ -850,49 +1008,89 @@ static void m_can_chip_config(struct net_device *dev) /* Accept Non-matching Frames Into FIFO 0 */ m_can_write(priv, M_CAN_GFC, 0x0); - /* only support one Tx Buffer currently */ - m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) | - priv->mcfg[MRAM_TXB].off); + if (priv->version == 30) { + /* only support one Tx Buffer currently */ + m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_SHIFT) | + priv->mcfg[MRAM_TXB].off); + } else { + /* TX FIFO is used for newer IP Core versions */ + m_can_write(priv, M_CAN_TXBC, + (priv->mcfg[MRAM_TXB].num << TXBC_TFQS_SHIFT) | + (priv->mcfg[MRAM_TXB].off)); + } /* support 64 bytes payload */ m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_64BYTES); - m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) | - priv->mcfg[MRAM_TXE].off); + /* TX Event FIFO */ + if (priv->version == 30) { + m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_SHIFT) | + priv->mcfg[MRAM_TXE].off); + } else { + /* Full TX Event FIFO is used */ + m_can_write(priv, M_CAN_TXEFC, + ((priv->mcfg[MRAM_TXE].num << TXEFC_EFS_SHIFT) + & TXEFC_EFS_MASK) | + priv->mcfg[MRAM_TXE].off); + } /* rx fifo configuration, blocking mode, fifo size 1 */ m_can_write(priv, M_CAN_RXF0C, - (priv->mcfg[MRAM_RXF0].num << RXFC_FS_OFF) | - RXFC_FWM_1 | priv->mcfg[MRAM_RXF0].off); + (priv->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) | + priv->mcfg[MRAM_RXF0].off); m_can_write(priv, M_CAN_RXF1C, - (priv->mcfg[MRAM_RXF1].num << RXFC_FS_OFF) | - RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off); + (priv->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) | + priv->mcfg[MRAM_RXF1].off); cccr = m_can_read(priv, M_CAN_CCCR); - cccr &= ~(CCCR_TEST | CCCR_MON | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) | - (CCCR_CME_MASK << CCCR_CME_SHIFT)); test = m_can_read(priv, M_CAN_TEST); test &= ~TEST_LBCK; + if (priv->version == 30) { + /* Version 3.0.x */ - if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) - cccr |= CCCR_MON; + cccr &= ~(CCCR_TEST | CCCR_MON | + (CCCR_CMR_MASK << CCCR_CMR_SHIFT) | + (CCCR_CME_MASK << CCCR_CME_SHIFT)); + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) + cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT; + + } else { + /* Version 3.1.x or 3.2.x */ + cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE); + /* Only 3.2.x has NISO Bit implemented */ + if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) + cccr |= CCCR_NISO; + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) + cccr |= (CCCR_BRSE | CCCR_FDOE); + } + + /* Loopback Mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { - cccr |= CCCR_TEST; + cccr |= CCCR_TEST | CCCR_MON; test |= TEST_LBCK; } - if (priv->can.ctrlmode & CAN_CTRLMODE_FD) - cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT; + /* Enable Monitoring (all versions) */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + cccr |= CCCR_MON; + /* Write config */ m_can_write(priv, M_CAN_CCCR, cccr); m_can_write(priv, M_CAN_TEST, test); - /* enable interrupts */ + /* Enable interrupts */ m_can_write(priv, M_CAN_IR, IR_ALL_INT); if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) - m_can_write(priv, M_CAN_IE, IR_ALL_INT & ~IR_ERR_LEC); + if (priv->version == 30) + m_can_write(priv, M_CAN_IE, IR_ALL_INT & + ~(IR_ERR_LEC_30X)); + else + m_can_write(priv, M_CAN_IE, IR_ALL_INT & + ~(IR_ERR_LEC_31X)); else m_can_write(priv, M_CAN_IE, IR_ALL_INT); @@ -936,33 +1134,140 @@ static void free_m_can_dev(struct net_device *dev) free_candev(dev); } -static struct net_device *alloc_m_can_dev(void) +/* Checks core release number of M_CAN + * returns 0 if an unsupported device is detected + * else it returns the release and step coded as: + * return value = 10 * <release> + 1 * <step> + */ +static int m_can_check_core_release(void __iomem *m_can_base) +{ + u32 crel_reg; + u8 rel; + u8 step; + int res; + struct m_can_priv temp_priv = { + .base = m_can_base + }; + + /* Read Core Release Version and split into version number + * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1; + */ + crel_reg = m_can_read(&temp_priv, M_CAN_CREL); + rel = (u8)((crel_reg & CREL_REL_MASK) >> CREL_REL_SHIFT); + step = (u8)((crel_reg & CREL_STEP_MASK) >> CREL_STEP_SHIFT); + + if (rel == 3) { + /* M_CAN v3.x.y: create return value */ + res = 30 + step; + } else { + /* Unsupported M_CAN version */ + res = 0; + } + + return res; +} + +/* Selectable Non ISO support only in version 3.2.x + * This function checks if the bit is writable. + */ +static bool m_can_niso_supported(const struct m_can_priv *priv) +{ + u32 cccr_reg, cccr_poll; + int niso_timeout; + + m_can_config_endisable(priv, true); + cccr_reg = m_can_read(priv, M_CAN_CCCR); + cccr_reg |= CCCR_NISO; + m_can_write(priv, M_CAN_CCCR, cccr_reg); + + niso_timeout = readl_poll_timeout((priv->base + M_CAN_CCCR), cccr_poll, + (cccr_poll == cccr_reg), 0, 10); + + /* Clear NISO */ + cccr_reg &= ~(CCCR_NISO); + m_can_write(priv, M_CAN_CCCR, cccr_reg); + + m_can_config_endisable(priv, false); + + /* return false if time out (-ETIMEDOUT), else return true */ + return !niso_timeout; +} + +static struct net_device *alloc_m_can_dev(struct platform_device *pdev, + void __iomem *addr, u32 tx_fifo_size) { struct net_device *dev; struct m_can_priv *priv; + int m_can_version; + unsigned int echo_buffer_count; + + m_can_version = m_can_check_core_release(addr); + /* return if unsupported version */ + if (!m_can_version) { + dev = NULL; + goto return_dev; + } - dev = alloc_candev(sizeof(*priv), 1); - if (!dev) - return NULL; + /* If version < 3.1.x, then only one echo buffer is used */ + echo_buffer_count = ((m_can_version == 30) + ? 1U + : (unsigned int)tx_fifo_size); + dev = alloc_candev(sizeof(*priv), echo_buffer_count); + if (!dev) { + dev = NULL; + goto return_dev; + } priv = netdev_priv(dev); netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT); + /* Shared properties of all M_CAN versions */ + priv->version = m_can_version; priv->dev = dev; - priv->can.bittiming_const = &m_can_bittiming_const; - priv->can.data_bittiming_const = &m_can_data_bittiming_const; + priv->base = addr; priv->can.do_set_mode = m_can_set_mode; priv->can.do_get_berr_counter = m_can_get_berr_counter; - /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ - can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); - - /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ + /* Set M_CAN supported operations */ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_FD; + /* Set properties depending on M_CAN version */ + switch (priv->version) { + case 30: + /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */ + can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); + priv->can.bittiming_const = &m_can_bittiming_const_30X; + priv->can.data_bittiming_const = + &m_can_data_bittiming_const_30X; + break; + case 31: + /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */ + can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); + priv->can.bittiming_const = &m_can_bittiming_const_31X; + priv->can.data_bittiming_const = + &m_can_data_bittiming_const_31X; + break; + case 32: + priv->can.bittiming_const = &m_can_bittiming_const_31X; + priv->can.data_bittiming_const = + &m_can_data_bittiming_const_31X; + priv->can.ctrlmode_supported |= (m_can_niso_supported(priv) + ? CAN_CTRLMODE_FD_NON_ISO + : 0); + break; + default: + /* Unsupported device: free candev */ + free_m_can_dev(dev); + dev_err(&pdev->dev, "Unsupported version number: %2d", + priv->version); + dev = NULL; + break; + } + +return_dev: return dev; } @@ -1040,19 +1345,34 @@ static int m_can_close(struct net_device *dev) return 0; } +static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) +{ + struct m_can_priv *priv = netdev_priv(dev); + /*get wrap around for loopback skb index */ + unsigned int wrap = priv->can.echo_skb_max; + int next_idx; + + /* calculate next index */ + next_idx = (++putidx >= wrap ? 0 : putidx); + + /* check if occupied */ + return !!priv->can.echo_skb[next_idx]; +} + static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct m_can_priv *priv = netdev_priv(dev); struct canfd_frame *cf = (struct canfd_frame *)skb->data; - u32 id, cccr; + u32 id, cccr, fdflags; int i; + int putidx; if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; |
