diff options
Diffstat (limited to 'kernel/drivers/net/can')
27 files changed, 1171 insertions, 301 deletions
diff --git a/kernel/drivers/net/can/Kconfig b/kernel/drivers/net/can/Kconfig index e8c96b8e8..6d04183ed 100644 --- a/kernel/drivers/net/can/Kconfig +++ b/kernel/drivers/net/can/Kconfig @@ -129,6 +129,16 @@ config CAN_RCAR To compile this driver as a module, choose M here: the module will be called rcar_can. +config CAN_SUN4I + tristate "Allwinner A10 CAN controller" + depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST + ---help--- + Say Y here if you want to use CAN controller found on Allwinner + A10/A20 SoCs. + + To compile this driver as a module, choose M here: the module will + be called sun4i_can. + config CAN_XILINXCAN tristate "Xilinx CAN" depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST diff --git a/kernel/drivers/net/can/Makefile b/kernel/drivers/net/can/Makefile index c533c62b0..1f21cef1d 100644 --- a/kernel/drivers/net/can/Makefile +++ b/kernel/drivers/net/can/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o obj-$(CONFIG_PCH_CAN) += pch_can.o obj-$(CONFIG_CAN_GRCAN) += grcan.o obj-$(CONFIG_CAN_RCAR) += rcar_can.o +obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o subdir-ccflags-y += -D__CHECK_ENDIAN__ diff --git a/kernel/drivers/net/can/at91_can.c b/kernel/drivers/net/can/at91_can.c index f4e40aa4d..8b3275d77 100644 --- a/kernel/drivers/net/can/at91_can.c +++ b/kernel/drivers/net/can/at91_can.c @@ -8,15 +8,6 @@ * Public License ("GPL") version 2 as distributed in the 'COPYING' * file from the main directory of the linux kernel source. * - * - * Your platform definition file should specify something like: - * - * static struct at91_can_data ek_can_data = { - * transceiver_switch = sam9263ek_transceiver_switch, - * }; - * - * at91_add_device_can(&ek_can_data); - * */ #include <linux/clk.h> @@ -33,7 +24,6 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/types.h> -#include <linux/platform_data/atmel.h> #include <linux/can/dev.h> #include <linux/can/error.h> @@ -324,15 +314,6 @@ static inline u32 at91_can_id_to_reg_mid(canid_t can_id) return reg_mid; } -/* - * Swtich transceiver on or off - */ -static void at91_transceiver_switch(const struct at91_priv *priv, int on) -{ - if (priv->pdata && priv->pdata->transceiver_switch) - priv->pdata->transceiver_switch(on); -} - static void at91_setup_mailboxes(struct net_device *dev) { struct at91_priv *priv = netdev_priv(dev); @@ -416,7 +397,6 @@ static void at91_chip_start(struct net_device *dev) at91_set_bittiming(dev); at91_setup_mailboxes(dev); - at91_transceiver_switch(priv, 1); /* enable chip */ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) @@ -444,7 +424,6 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) reg_mr = at91_read(priv, AT91_MR); at91_write(priv, AT91_MR, reg_mr & ~AT91_MR_CANEN); - at91_transceiver_switch(priv, 0); priv->can.state = state; } @@ -577,10 +556,10 @@ static void at91_rx_overflow_err(struct net_device *dev) cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); } /** @@ -642,10 +621,10 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) } at91_read_mb(dev, mb, cf); - netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); can_led_event(dev, CAN_LED_EVENT_RX); } @@ -802,10 +781,10 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) return 0; at91_poll_err_frame(dev, cf, reg_sr); - netif_receive_skb(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += cf->can_dlc; + netif_receive_skb(skb); return 1; } @@ -1067,10 +1046,10 @@ static void at91_irq_err(struct net_device *dev) return; at91_irq_err_state(dev, cf, new_state); - netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += cf->can_dlc; + netif_rx(skb); priv->can.state = new_state; } diff --git a/kernel/drivers/net/can/bfin_can.c b/kernel/drivers/net/can/bfin_can.c index 27ad312e7..1deb8ff90 100644 --- a/kernel/drivers/net/can/bfin_can.c +++ b/kernel/drivers/net/can/bfin_can.c @@ -424,10 +424,9 @@ static void bfin_can_rx(struct net_device *dev, u16 isrc) cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0; } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) @@ -502,16 +501,13 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) cf->data[2] |= CAN_ERR_PROT_FORM; else if (status & SER) cf->data[2] |= CAN_ERR_PROT_STUFF; - else - cf->data[2] |= CAN_ERR_PROT_UNSPEC; } priv->can.state = state; - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); return 0; } diff --git a/kernel/drivers/net/can/c_can/c_can.c b/kernel/drivers/net/can/c_can/c_can.c index 5d214d135..f91b09428 100644 --- a/kernel/drivers/net/can/c_can/c_can.c +++ b/kernel/drivers/net/can/c_can/c_can.c @@ -962,7 +962,6 @@ static int c_can_handle_bus_err(struct net_device *dev, * type of the last error to occur on the CAN bus */ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; switch (lec_type) { case LEC_STUFF_ERROR: @@ -975,8 +974,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); @@ -988,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; default: break; diff --git a/kernel/drivers/net/can/cc770/cc770.c b/kernel/drivers/net/can/cc770/cc770.c index c11d44984..1e3731305 100644 --- a/kernel/drivers/net/can/cc770/cc770.c +++ b/kernel/drivers/net/can/cc770/cc770.c @@ -504,10 +504,10 @@ static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1) for (i = 0; i < cf->can_dlc; i++) cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]); } - netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } static int cc770_err(struct net_device *dev, u8 status) @@ -578,16 +578,16 @@ static int cc770_err(struct net_device *dev, u8 status) cf->data[2] |= CAN_ERR_PROT_BIT0; break; case STAT_LEC_CRC: - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; } } } - netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); return 0; } diff --git a/kernel/drivers/net/can/dev.c b/kernel/drivers/net/can/dev.c index aede70460..141c2a42d 100644 --- a/kernel/drivers/net/can/dev.c +++ b/kernel/drivers/net/can/dev.c @@ -915,7 +915,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put(skb, IFLA_CAN_BITTIMING_CONST, sizeof(*priv->bittiming_const), priv->bittiming_const)) || - nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) || + nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) || nla_put_u32(skb, IFLA_CAN_STATE, state) || nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) || nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) || diff --git a/kernel/drivers/net/can/flexcan.c b/kernel/drivers/net/can/flexcan.c index ad0a7e8c2..41c0fc9f3 100644 --- a/kernel/drivers/net/can/flexcan.c +++ b/kernel/drivers/net/can/flexcan.c @@ -26,12 +26,8 @@ #include <linux/can/led.h> #include <linux/clk.h> #include <linux/delay.h> -#include <linux/if_arp.h> -#include <linux/if_ether.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/kernel.h> -#include <linux/list.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -63,10 +59,10 @@ #define FLEXCAN_MCR_LPRIO_EN BIT(13) #define FLEXCAN_MCR_AEN BIT(12) #define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f) -#define FLEXCAN_MCR_IDAM_A (0 << 8) -#define FLEXCAN_MCR_IDAM_B (1 << 8) -#define FLEXCAN_MCR_IDAM_C (2 << 8) -#define FLEXCAN_MCR_IDAM_D (3 << 8) +#define FLEXCAN_MCR_IDAM_A (0x0 << 8) +#define FLEXCAN_MCR_IDAM_B (0x1 << 8) +#define FLEXCAN_MCR_IDAM_C (0x2 << 8) +#define FLEXCAN_MCR_IDAM_D (0x3 << 8) /* FLEXCAN control register (CANCTRL) bits */ #define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24) @@ -93,13 +89,13 @@ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE) /* FLEXCAN control register 2 (CTRL2) bits */ -#define FLEXCAN_CRL2_ECRWRE BIT(29) -#define FLEXCAN_CRL2_WRMFRZ BIT(28) -#define FLEXCAN_CRL2_RFFN(x) (((x) & 0x0f) << 24) -#define FLEXCAN_CRL2_TASD(x) (((x) & 0x1f) << 19) -#define FLEXCAN_CRL2_MRP BIT(18) -#define FLEXCAN_CRL2_RRS BIT(17) -#define FLEXCAN_CRL2_EACEN BIT(16) +#define FLEXCAN_CTRL2_ECRWRE BIT(29) +#define FLEXCAN_CTRL2_WRMFRZ BIT(28) +#define FLEXCAN_CTRL2_RFFN(x) (((x) & 0x0f) << 24) +#define FLEXCAN_CTRL2_TASD(x) (((x) & 0x1f) << 19) +#define FLEXCAN_CTRL2_MRP BIT(18) +#define FLEXCAN_CTRL2_RRS BIT(17) +#define FLEXCAN_CTRL2_EACEN BIT(16) /* FLEXCAN memory error control register (MECR) bits */ #define FLEXCAN_MECR_ECRWRDIS BIT(31) @@ -158,11 +154,10 @@ FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID)) /* FLEXCAN message buffers */ -#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24) #define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24) #define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24) #define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24) -#define FLEXCAN_MB_CODE_RX_OVERRRUN (0x6 << 24) +#define FLEXCAN_MB_CODE_RX_OVERRUN (0x6 << 24) #define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24) #define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24) @@ -176,28 +171,25 @@ #define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16) #define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff) -#define FLEXCAN_MB_CODE_MASK (0xf0ffffff) +#define FLEXCAN_TIMEOUT_US (50) -#define FLEXCAN_TIMEOUT_US (50) - -/* - * FLEXCAN hardware feature flags +/* FLEXCAN hardware feature flags * * Below is some version info we got: - * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err - * Filter? connected? detection - * MX25 FlexCAN2 03.00.00.00 no no no - * MX28 FlexCAN2 03.00.04.00 yes yes no - * MX35 FlexCAN2 03.00.00.00 no no no - * MX53 FlexCAN2 03.00.00.00 yes no no - * MX6s FlexCAN3 10.00.12.00 yes yes no - * VF610 FlexCAN3 ? no yes yes + * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err RTR re- + * Filter? connected? detection ception in MB + * MX25 FlexCAN2 03.00.00.00 no no no no + * MX28 FlexCAN2 03.00.04.00 yes yes no no + * MX35 FlexCAN2 03.00.00.00 no no no no + * MX53 FlexCAN2 03.00.00.00 yes no no no + * MX6s FlexCAN3 10.00.12.00 yes yes no yes + * VF610 FlexCAN3 ? no yes yes yes? * * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. */ -#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */ -#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */ -#define FLEXCAN_HAS_MECR_FEATURES BIT(3) /* Memory error detection */ +#define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */ +#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */ +#define FLEXCAN_QUIRK_DISABLE_MECR BIT(3) /* Disble Memory error detection */ /* Structure of the message buffer */ struct flexcan_mb { @@ -221,7 +213,7 @@ struct flexcan_regs { u32 imask1; /* 0x28 */ u32 iflag2; /* 0x2c */ u32 iflag1; /* 0x30 */ - u32 crl2; /* 0x34 */ + u32 ctrl2; /* 0x34 */ u32 esr2; /* 0x38 */ u32 imeur; /* 0x3c */ u32 lrfr; /* 0x40 */ @@ -229,7 +221,17 @@ struct flexcan_regs { u32 rxfgmask; /* 0x48 */ u32 rxfir; /* 0x4c */ u32 _reserved3[12]; /* 0x50 */ - struct flexcan_mb cantxfg[64]; /* 0x80 */ + struct flexcan_mb mb[64]; /* 0x80 */ + /* FIFO-mode: + * MB + * 0x080...0x08f 0 RX message buffer + * 0x090...0x0df 1-5 reserverd + * 0x0e0...0x0ff 6-7 8 entry ID table + * (mx25, mx28, mx35, mx53) + * 0x0e0...0x2df 6-7..37 8..128 entry ID table + * size conf'ed via ctrl2::RFFN + * (mx6, vf610) + */ u32 _reserved4[408]; u32 mecr; /* 0xae0 */ u32 erriar; /* 0xae4 */ @@ -242,14 +244,14 @@ struct flexcan_regs { }; struct flexcan_devtype_data { - u32 features; /* hardware controller features */ + u32 quirks; /* quirks needed for different IP cores */ }; struct flexcan_priv { struct can_priv can; struct napi_struct napi; - void __iomem *base; + struct flexcan_regs __iomem *regs; u32 reg_esr; u32 reg_ctrl_default; @@ -261,14 +263,17 @@ struct flexcan_priv { }; static struct flexcan_devtype_data fsl_p1010_devtype_data = { - .features = FLEXCAN_HAS_BROKEN_ERR_STATE, + .quirks = FLEXCAN_QUIRK_BROKEN_ERR_STATE, }; + static struct flexcan_devtype_data fsl_imx28_devtype_data; + static struct flexcan_devtype_data fsl_imx6q_devtype_data = { - .features = FLEXCAN_HAS_V10_FEATURES, + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG, }; + static struct flexcan_devtype_data fsl_vf610_devtype_data = { - .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_MECR_FEATURES, + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR, }; static const struct can_bittiming_const flexcan_bittiming_const = { @@ -283,11 +288,10 @@ static const struct can_bittiming_const flexcan_bittiming_const = { .brp_inc = 1, }; -/* - * Abstract off the read/write for arm versus ppc. This +/* Abstract off the read/write for arm versus ppc. This * assumes that PPC uses big-endian registers and everything * else uses little-endian registers, independent of CPU - * endianess. + * endianness. */ #if defined(CONFIG_PPC) static inline u32 flexcan_read(void __iomem *addr) @@ -336,7 +340,7 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, static int flexcan_chip_enable(struct flexcan_priv *priv) { - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; @@ -355,7 +359,7 @@ static int flexcan_chip_enable(struct flexcan_priv *priv) static int flexcan_chip_disable(struct flexcan_priv *priv) { - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; @@ -374,7 +378,7 @@ static int flexcan_chip_disable(struct flexcan_priv *priv) static int flexcan_chip_freeze(struct flexcan_priv *priv) { - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate; u32 reg; @@ -393,7 +397,7 @@ static int flexcan_chip_freeze(struct flexcan_priv *priv) static int flexcan_chip_unfreeze(struct flexcan_priv *priv) { - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; @@ -412,7 +416,7 @@ static int flexcan_chip_unfreeze(struct flexcan_priv *priv) static int flexcan_chip_softreset(struct flexcan_priv *priv) { - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); @@ -425,12 +429,11 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv) return 0; } - static int __flexcan_get_berr_counter(const struct net_device *dev, struct can_berr_counter *bec) { const struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; u32 reg = flexcan_read(®s->ecr); bec->txerr = (reg >> 0) & 0xff; @@ -465,10 +468,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev, static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; struct can_frame *cf = (struct can_frame *)skb->data; u32 can_id; - u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16); + u32 data; + u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16); if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; @@ -486,26 +490,26 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) ctrl |= FLEXCAN_MB_CNT_RTR; if (cf->can_dlc > 0) { - u32 data = be32_to_cpup((__be32 *)&cf->data[0]); - flexcan_write(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[0]); + data = be32_to_cpup((__be32 *)&cf->data[0]); + flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[0]); } if (cf->can_dlc > 3) { - u32 data = be32_to_cpup((__be32 *)&cf->data[4]); - flexcan_write(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[1]); + data = be32_to_cpup((__be32 *)&cf->data[4]); + flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[1]); } can_put_echo_skb(skb, dev, 0); - flexcan_write(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id); - flexcan_write(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); + flexcan_write(can_id, ®s->mb[FLEXCAN_TX_BUF_ID].can_id); + flexcan_write(ctrl, ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl); /* Errata ERR005829 step8: * Write twice INACTIVE(0x8) code to first MB. */ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); + ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl); flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); + ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl); return NETDEV_TX_OK; } @@ -531,13 +535,13 @@ static void do_bus_err(struct net_device *dev, if (reg_esr & FLEXCAN_ESR_ACK_ERR) { netdev_dbg(dev, "ACK_ERR irq\n"); cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; tx_errors = 1; } if (reg_esr & FLEXCAN_ESR_CRC_ERR) { netdev_dbg(dev, "CRC_ERR irq\n"); cf->data[2] |= CAN_ERR_PROT_BIT; - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; rx_errors = 1; } if (reg_esr & FLEXCAN_ESR_FRM_ERR) { @@ -568,10 +572,10 @@ static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr) return 0; do_bus_err(dev, cf, reg_esr); - netif_receive_skb(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += cf->can_dlc; + netif_receive_skb(skb); return 1; } @@ -588,14 +592,14 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ? - CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; + CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ? - CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; + CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; new_state = max(tx_state, rx_state); } else { __flexcan_get_berr_counter(dev, &bec); new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ? - CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF; + CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF; rx_state = bec.rxerr >= bec.txerr ? new_state : 0; tx_state = bec.rxerr <= bec.txerr ? new_state : 0; } @@ -613,10 +617,9 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) if (unlikely(new_state == CAN_STATE_BUS_OFF)) can_bus_off(dev); - netif_receive_skb(skb); - dev->stats.rx_packets++; dev->stats.rx_bytes += cf->can_dlc; + netif_receive_skb(skb); return 1; } @@ -625,8 +628,8 @@ static void flexcan_read_fifo(const struct net_device *dev, struct can_frame *cf) { const struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; - struct flexcan_mb __iomem *mb = ®s->cantxfg[0]; + struct flexcan_regs __iomem *regs = priv->regs; + struct flexcan_mb __iomem *mb = ®s->mb[0]; u32 reg_ctrl, reg_id; reg_ctrl = flexcan_read(&mb->can_ctrl); @@ -661,10 +664,10 @@ static int flexcan_read_frame(struct net_device *dev) } flexcan_read_fifo(dev, cf); - netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); can_led_event(dev, CAN_LED_EVENT_RX); @@ -675,12 +678,11 @@ static int flexcan_poll(struct napi_struct *napi, int quota) { struct net_device *dev = napi->dev; const struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; u32 reg_iflag1, reg_esr; int work_done = 0; - /* - * The error bits are cleared on read, + /* The error bits are cleared on read, * use saved value from irq handler. */ reg_esr = flexcan_read(®s->esr) | priv->reg_esr; @@ -715,17 +717,17 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) struct net_device *dev = dev_id; struct net_device_stats *stats = &dev->stats; struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; u32 reg_iflag1, reg_esr; reg_iflag1 = flexcan_read(®s->iflag1); reg_esr = flexcan_read(®s->esr); + /* ACK all bus error and state change IRQ sources */ if (reg_esr & FLEXCAN_ESR_ALL_INT) flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr); - /* - * schedule NAPI in case of: + /* schedule NAPI in case of: * - rx IRQ * - state change IRQ * - bus error IRQ and bus error reporting is activated @@ -733,15 +735,14 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) || (reg_esr & FLEXCAN_ESR_ERR_STATE) || flexcan_has_and_handle_berr(priv, reg_esr)) { - /* - * The error bits are cleared on read, + /* The error bits are cleared on read, * save them for later use. */ priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS; flexcan_write(FLEXCAN_IFLAG_DEFAULT & - ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->imask1); + ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->imask1); flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, - ®s->ctrl); + ®s->ctrl); napi_schedule(&priv->napi); } @@ -757,9 +758,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) stats->tx_bytes += can_get_echo_skb(dev, 0); stats->tx_packets++; can_led_event(dev, CAN_LED_EVENT_TX); - /* after sending a RTR frame mailbox is in RX mode */ + + /* after sending a RTR frame MB is in RX mode */ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); + ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl); flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1); netif_wake_queue(dev); } @@ -771,7 +773,7 @@ static void flexcan_set_bittiming(struct net_device *dev) { const struct flexcan_priv *priv = netdev_priv(dev); const struct can_bittiming *bt = &priv->can.bittiming; - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; u32 reg; reg = flexcan_read(®s->ctrl); @@ -797,7 +799,7 @@ static void flexcan_set_bittiming(struct net_device *dev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) reg |= FLEXCAN_CTRL_SMP; - netdev_info(dev, "writing ctrl=0x%08x\n", reg); + netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); flexcan_write(reg, ®s->ctrl); /* print chip status */ @@ -805,8 +807,7 @@ static void flexcan_set_bittiming(struct net_device *dev) flexcan_read(®s->mcr), flexcan_read(®s->ctrl)); } -/* - * flexcan_chip_start +/* flexcan_chip_start * * this functions is entered with clocks enabled * @@ -814,8 +815,8 @@ static void flexcan_set_bittiming(struct net_device *dev) static int flexcan_chip_start(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; - u32 reg_mcr, reg_ctrl, reg_crl2, reg_mecr; + struct flexcan_regs __iomem *regs = priv->regs; + u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; int err, i; /* enable module */ @@ -830,29 +831,26 @@ static int flexcan_chip_start(struct net_device *dev) flexcan_set_bittiming(dev); - /* - * MCR + /* MCR * * enable freeze * enable fifo * halt now * only supervisor access * enable warning int - * choose format C * disable local echo - * + * choose format C + * set max mailbox number */ reg_mcr = flexcan_read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT | - FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | - FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS | - FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID); + FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | + FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID); netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); flexcan_write(reg_mcr, ®s->mcr); - /* - * CTRL + /* CTRL * * disable timer sync feature * @@ -867,12 +865,12 @@ static int flexcan_chip_start(struct net_device *dev) reg_ctrl &= ~FLEXCAN_CTRL_TSYN; reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF | FLEXCAN_CTRL_ERR_STATE; - /* - * enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK), + + /* enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK), * on most Flexcan cores, too. Otherwise we don't get * any error warning or passive interrupts. */ - if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE || + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_ERR_STATE || priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; else @@ -880,53 +878,53 @@ static int flexcan_chip_start(struct net_device *dev) /* save for later use */ priv->reg_ctrl_default = reg_ctrl; + /* leave interrupts disabled for now */ + reg_ctrl &= ~FLEXCAN_CTRL_ERR_ALL; netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); flexcan_write(reg_ctrl, ®s->ctrl); /* clear and invalidate all mailboxes first */ - for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->cantxfg); i++) { + for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->mb); i++) { flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE, - ®s->cantxfg[i].can_ctrl); + ®s->mb[i].can_ctrl); } /* Errata ERR005829: mark first TX mailbox as INACTIVE */ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); + ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl); /* mark TX mailbox as INACTIVE */ flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); + ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl); /* acceptance mask/acceptance code (accept everything) */ flexcan_write(0x0, ®s->rxgmask); flexcan_write(0x0, ®s->rx14mask); flexcan_write(0x0, ®s->rx15mask); - if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) flexcan_write(0x0, ®s->rxfgmask); - /* - * On Vybrid, disable memory error detection interrupts + /* On Vybrid, disable memory error detection interrupts * and freeze mode. * This also works around errata e5295 which generates * false positive memory errors and put the device in * freeze mode. */ - if (priv->devtype_data->features & FLEXCAN_HAS_MECR_FEATURES) { - /* - * Follow the protocol as described in "Detection + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) { + /* Follow the protocol as described in "Detection * and Correction of Memory Errors" to write to * MECR register */ - reg_crl2 = flexcan_read(®s->crl2); - reg_crl2 |= FLEXCAN_CRL2_ECRWRE; - flexcan_write(reg_crl2, ®s->crl2); + reg_ctrl2 = flexcan_read(®s->ctrl2); + reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE; + flexcan_write(reg_ctrl2, ®s->ctrl2); reg_mecr = flexcan_read(®s->mecr); reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; flexcan_write(reg_mecr, ®s->mecr); reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | - FLEXCAN_MECR_FANCEI_MSK); + FLEXCAN_MECR_FANCEI_MSK); flexcan_write(reg_mecr, ®s->mecr); } @@ -941,8 +939,11 @@ static int flexcan_chip_start(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; - /* enable FIFO interrupts */ + /* enable interrupts atomically */ + disable_irq(dev->irq); + flexcan_write(priv->reg_ctrl_default, ®s->ctrl); flexcan_write(FLEXCAN_IFLAG_DEFAULT, ®s->imask1); + enable_irq(dev->irq); /* print chip status */ netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__, @@ -957,16 +958,14 @@ static int flexcan_chip_start(struct net_device *dev) return err; } -/* - * flexcan_chip_stop +/* flexcan_chip_stop * * this functions is entered with clocks enabled - * */ static void flexcan_chip_stop(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; /* freeze + disable module */ flexcan_chip_freeze(priv); @@ -979,8 +978,6 @@ static void flexcan_chip_stop(struct net_device *dev) flexcan_transceiver_disable(priv); priv->can.state = CAN_STATE_STOPPED; - - return; } static int flexcan_open(struct net_device *dev) @@ -1077,7 +1074,7 @@ static const struct net_device_ops flexcan_netdev_ops = { static int register_flexcandev(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->base; + struct flexcan_regs __iomem *regs = priv->regs; u32 reg, err; err = clk_prepare_enable(priv->clk_ipg); @@ -1106,8 +1103,7 @@ static int register_flexcandev(struct net_device *dev) FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV; flexcan_write(reg, ®s->mcr); - /* - * Currently we only support newer versions of this core + /* Currently we only support newer versions of this core * featuring a RX FIFO. Older cores found on some Coldfire * derivates are not yet supported. */ @@ -1160,7 +1156,7 @@ static int flexcan_probe(struct platform_device *pdev) struct regulator *reg_xceiver; struct resource *mem; struct clk *clk_ipg = NULL, *clk_per = NULL; - void __iomem *base; + struct flexcan_regs __iomem *regs; int err, irq; u32 clock_freq = 0; @@ -1172,7 +1168,7 @@ static int flexcan_probe(struct platform_device *pdev) if (pdev->dev.of_node) of_property_read_u32(pdev->dev.of_node, - "clock-frequency", &clock_freq); + "clock-frequency", &clock_freq); if (!clock_freq) { clk_ipg = devm_clk_get(&pdev->dev, "ipg"); @@ -1194,9 +1190,9 @@ static int flexcan_probe(struct platform_device *pdev) if (irq <= 0) return -ENODEV; - base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(base)) - return PTR_ERR(base); + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) + return PTR_ERR(regs); of_id = of_match_device(flexcan_of_match, &pdev->dev); if (of_id) { @@ -1224,12 +1220,11 @@ static int flexcan_probe(struct platform_device *pdev) priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_BERR_REPORTING; - priv->base = base; + priv->regs = regs; priv->clk_ipg = clk_ipg; priv->clk_per = clk_per; priv->pdata = dev_get_platdata(&pdev->dev); priv->devtype_data = devtype_data; - priv->reg_xceiver = reg_xceiver; netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); @@ -1246,7 +1241,7 @@ static int flexcan_probe(struct platform_device *pdev) devm_can_led_init(dev); dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", - priv->base, dev->irq); + priv->regs, dev->irq); return 0; diff --git a/kernel/drivers/net/can/grcan.c b/kernel/drivers/net/can/grcan.c index e3d7e22a4..db9538d4b 100644 --- a/kernel/drivers/net/can/grcan.c +++ b/kernel/drivers/net/can/grcan.c @@ -1216,11 +1216,12 @@ static int grcan_receive(struct net_device *dev, int budget) cf->data[i] = (u8)(slot[j] >> shift); } } - netif_receive_skb(skb); /* Update statistics and read pointer */ stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); + rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size); } diff --git a/kernel/drivers/net/can/janz-ican3.c b/kernel/drivers/net/can/janz-ican3.c index 4dd183a36..5d04f5464 100644 --- a/kernel/drivers/net/can/janz-ican3.c +++ b/kernel/drivers/net/can/janz-ican3.c @@ -40,6 +40,7 @@ #define MSYNC_PEER 0x00 /* ICAN only */ #define MSYNC_LOCL 0x01 /* host only */ #define TARGET_RUNNING 0x02 +#define FIRMWARE_STAMP 0x60 /* big endian firmware stamp */ #define MSYNC_RB0 0x01 #define MSYNC_RB1 0x02 @@ -83,6 +84,7 @@ #define MSG_COFFREQ 0x42 #define MSG_CONREQ 0x43 #define MSG_CCONFREQ 0x47 +#define MSG_LMTS 0xb4 /* * Janz ICAN3 CAN Inquiry Message Types @@ -165,6 +167,12 @@ /* SJA1000 Clock Input */ #define ICAN3_CAN_CLOCK 8000000 +/* Janz ICAN3 firmware types */ +enum ican3_fwtype { + ICAN3_FWTYPE_ICANOS, + ICAN3_FWTYPE_CAL_CANOPEN, +}; + /* Driver Name */ #define DRV_NAME "janz-ican3" @@ -215,6 +223,10 @@ struct ican3_dev { struct completion buserror_comp; struct can_berr_counter bec; + /* firmware type */ + enum ican3_fwtype fwtype; + char fwinfo[32]; + /* old and new style host interface */ unsigned int iftype; @@ -750,13 +762,61 @@ static int ican3_set_id_filter(struct ican3_dev *mod, bool accept) */ static int ican3_set_bus_state(struct ican3_dev *mod, bool on) { + struct can_bittiming *bt = &mod->can.bittiming; struct ican3_msg msg; + u8 btr0, btr1; + int res; - memset(&msg, 0, sizeof(msg)); - msg.spec = on ? MSG_CONREQ : MSG_COFFREQ; - msg.len = cpu_to_le16(0); + /* This algorithm was stolen from drivers/net/can/sja1000/sja1000.c */ + /* The bittiming register command for the ICAN3 just sets the bit timing */ + /* registers on the SJA1000 chip directly */ + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | + (((bt->phase_seg2 - 1) & 0x7) << 4); + if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + btr1 |= 0x80; - return ican3_send_msg(mod, &msg); + if (mod->fwtype == ICAN3_FWTYPE_ICANOS) { + if (on) { + /* set bittiming */ + memset(&msg, 0, sizeof(msg)); + msg.spec = MSG_CBTRREQ; + msg.len = cpu_to_le16(4); + msg.data[0] = 0x00; + msg.data[1] = 0x00; + msg.data[2] = btr0; + msg.data[3] = btr1; + + res = ican3_send_msg(mod, &msg); + if (res) + return res; + } + + /* can-on/off request */ + memset(&msg, 0, sizeof(msg)); + msg.spec = on ? MSG_CONREQ : MSG_COFFREQ; + msg.len = cpu_to_le16(0); + + return ican3_send_msg(mod, &msg); + + } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) { + memset(&msg, 0, sizeof(msg)); + msg.spec = MSG_LMTS; + if (on) { + msg.len = cpu_to_le16(4); + msg.data[0] = 0; + msg.data[1] = 0; + msg.data[2] = btr0; + msg.data[3] = btr1; + } else { + msg.len = cpu_to_le16(2); + msg.data[0] = 1; + msg.data[1] = 0; + } + + return ican3_send_msg(mod, &msg); + } + return -ENOTSUPP; } static int ican3_set_termination(struct ican3_dev *mod, bool on) @@ -1036,7 +1096,6 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & ECC_SEG; break; } @@ -1402,7 +1461,7 @@ static int ican3_reset_module(struct ican3_dev *mod) return 0; msleep(10); - } while (time_before(jiffies, start + HZ / 4)); + } while (time_before(jiffies, start + HZ / 2)); netdev_err(mod->ndev, "failed to reset CAN module\n"); return -ETIMEDOUT; @@ -1427,6 +1486,17 @@ static int ican3_startup_module(struct ican3_dev *mod) return ret; } + /* detect firmware */ + memcpy_fromio(mod->fwinfo, mod->dpm + FIRMWARE_STAMP, sizeof(mod->fwinfo) - 1); + if (strncmp(mod->fwinfo, "JANZ-ICAN3", 10)) { + netdev_err(mod->ndev, "ICAN3 not detected (found %s)\n", mod->fwinfo); + return -ENODEV; + } + if (strstr(mod->fwinfo, "CAL/CANopen")) + mod->fwtype = ICAN3_FWTYPE_CAL_CANOPEN; + else + mod->fwtype = ICAN3_FWTYPE_ICANOS; + /* re-enable interrupts so we can send messages */ iowrite8(1 << mod->num, &mod->ctrl->int_enable); @@ -1615,36 +1685,6 @@ static const struct can_bittiming_const ican3_bittiming_const = { .brp_inc = 1, }; -/* - * This routine was stolen from drivers/net/can/sja1000/sja1000.c - * - * The bittiming register command for the ICAN3 just sets the bit timing - * registers on the SJA1000 chip directly - */ -static int ican3_set_bittiming(struct net_device *ndev) -{ - struct ican3_dev *mod = netdev_priv(ndev); - struct can_bittiming *bt = &mod->can.bittiming; - struct ican3_msg msg; - u8 btr0, btr1; - - btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); - btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | - (((bt->phase_seg2 - 1) & 0x7) << 4); - if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) - btr1 |= 0x80; - - memset(&msg, 0, sizeof(msg)); - msg.spec = MSG_CBTRREQ; - msg.len = cpu_to_le16(4); - msg.data[0] = 0x00; - msg.data[1] = 0x00; - msg.data[2] = btr0; - msg.data[3] = btr1; - - return ican3_send_msg(mod, &msg); -} - static int ican3_set_mode(struct net_device *ndev, enum can_mode mode) { struct ican3_dev *mod = netdev_priv(ndev); @@ -1730,11 +1770,22 @@ static ssize_t ican3_sysfs_set_term(struct device *dev, return count; } +static ssize_t ican3_sysfs_show_fwinfo(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ican3_dev *mod = netdev_priv(to_net_dev(dev)); + + return scnprintf(buf, PAGE_SIZE, "%s\n", mod->fwinfo); +} + static DEVICE_ATTR(termination, S_IWUSR | S_IRUGO, ican3_sysfs_show_term, ican3_sysfs_set_term); +static DEVICE_ATTR(fwinfo, S_IRUSR | S_IRUGO, ican3_sysfs_show_fwinfo, NULL); static struct attribute *ican3_sysfs_attrs[] = { &dev_attr_termination.attr, + &dev_attr_fwinfo.attr, NULL, }; @@ -1794,7 +1845,6 @@ static int ican3_probe(struct platform_device *pdev) mod->can.clock.freq = ICAN3_CAN_CLOCK; mod->can.bittiming_const = &ican3_bittiming_const; - mod->can.do_set_bittiming = ican3_set_bittiming; mod->can.do_set_mode = ican3_set_mode; mod->can.do_get_berr_counter = ican3_get_berr_counter; mod->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES @@ -1866,7 +1916,7 @@ static int ican3_probe(struct platform_device *pdev) goto out_free_irq; } - dev_info(dev, "module %d: registered CAN device\n", pdata->modno); + netdev_info(mod->ndev, "module %d: registered CAN device\n", pdata->modno); return 0; out_free_irq: diff --git a/kernel/drivers/net/can/m_can/m_can.c b/kernel/drivers/net/can/m_can/m_can.c index ef655177b..39cf911f7 100644 --- a/kernel/drivers/net/can/m_can/m_can.c +++ b/kernel/drivers/net/can/m_can/m_can.c @@ -487,7 +487,6 @@ static int m_can_handle_lec_err(struct net_device *dev, * type of the last error to occur on the CAN bus */ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; switch (lec_type) { case LEC_STUFF_ERROR: @@ -500,8 +499,7 @@ static int m_can_handle_lec_err(struct net_device *dev, break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); @@ -513,8 +511,7 @@ static int m_can_handle_lec_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; default: break; diff --git a/kernel/drivers/net/can/pch_can.c b/kernel/drivers/net/can/pch_can.c index e187ca783..c1317889d 100644 --- a/kernel/drivers/net/can/pch_can.c +++ b/kernel/drivers/net/can/pch_can.c @@ -559,8 +559,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) stats->rx_errors++; break; case PCH_CRC_ERR: - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; priv->can.can_stats.bus_error++; stats->rx_errors++; break; diff --git a/kernel/drivers/net/can/rcar_can.c b/kernel/drivers/net/can/rcar_can.c index 2f9ebad4f..bc46be395 100644 --- a/kernel/drivers/net/can/rcar_can.c +++ b/kernel/drivers/net/can/rcar_can.c @@ -241,17 +241,16 @@ static void rcar_can_error(struct net_device *ndev) u8 ecsr; netdev_dbg(priv->ndev, "Bus error interrupt:\n"); - if (skb) { + if (skb) cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_UNSPEC; - } + ecsr = readb(&priv->regs->ecsr); if (ecsr & RCAR_CAN_ECSR_ADEF) { netdev_dbg(priv->ndev, "ACK Delimiter Error\n"); tx_errors++; writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr); if (skb) - cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL; } if (ecsr & RCAR_CAN_ECSR_BE0F) { netdev_dbg(priv->ndev, "Bit Error (dominant)\n"); @@ -272,7 +271,7 @@ static void rcar_can_error(struct net_device *ndev) rx_errors++; writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); if (skb) - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } if (ecsr & RCAR_CAN_ECSR_AEF) { netdev_dbg(priv->ndev, "ACK Error\n"); @@ -280,7 +279,7 @@ static void rcar_can_error(struct net_device *ndev) writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); if (skb) { cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } if (ecsr & RCAR_CAN_ECSR_FEF) { @@ -508,7 +507,8 @@ static int rcar_can_open(struct net_device *ndev) err = clk_prepare_enable(priv->clk); if (err) { - netdev_err(ndev, "failed to enable periperal clock, error %d\n", + netdev_err(ndev, + "failed to enable peripheral clock, error %d\n", err); goto out; } @@ -526,7 +526,8 @@ static int rcar_can_open(struct net_device *ndev) napi_enable(&priv->napi); err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); if (err) { - netdev_err(ndev, "error requesting interrupt %d\n", ndev->irq); + netdev_err(ndev, "request_irq(%d) failed, error %d\n", + ndev->irq, err); goto out_close; } can_led_event(ndev, CAN_LED_EVENT_OPEN); @@ -783,7 +784,8 @@ static int rcar_can_probe(struct platform_device *pdev) priv->clk = devm_clk_get(&pdev->dev, "clkp1"); if (IS_ERR(priv->clk)) { err = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err); + dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n", + err); goto fail_clk; } @@ -795,7 +797,7 @@ static int rcar_can_probe(struct platform_device *pdev) priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]); if (IS_ERR(priv->can_clk)) { err = PTR_ERR(priv->can_clk); - dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err); + dev_err(&pdev->dev, "cannot get CAN clock, error %d\n", err); goto fail_clk; } diff --git a/kernel/drivers/net/can/sja1000/peak_pci.c b/kernel/drivers/net/can/sja1000/peak_pci.c index e5fac3680..131026fbc 100644 --- a/kernel/drivers/net/can/sja1000/peak_pci.c +++ b/kernel/drivers/net/can/sja1000/peak_pci.c @@ -87,6 +87,7 @@ static const struct pci_device_id peak_pci_tbl[] = { {PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PEAK_PCI_VENDOR_ID, PEAK_CPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PEAK_PCI_VENDOR_ID, PEAK_PCIE_OEM_ID, PCI_ANY_ID, PCI_ANY_ID,}, #ifdef CONFIG_CAN_PEAK_PCIEC {PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PEAK_PCI_VENDOR_ID, PEAK_PCIEC34_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, diff --git a/kernel/drivers/net/can/sja1000/sja1000.c b/kernel/drivers/net/can/sja1000/sja1000.c index 32bd7f451..8dda3b703 100644 --- a/kernel/drivers/net/can/sja1000/sja1000.c +++ b/kernel/drivers/net/can/sja1000/sja1000.c @@ -218,6 +218,9 @@ static void sja1000_start(struct net_device *dev) priv->write_reg(priv, SJA1000_RXERR, 0x0); priv->read_reg(priv, SJA1000_ECC); + /* clear interrupt flags */ + priv->read_reg(priv, SJA1000_IR); + /* leave reset mode */ set_normal_mode(dev); } @@ -377,10 +380,9 @@ static void sja1000_rx(struct net_device *dev) /* release receive buffer */ sja1000_write_cmdreg(priv, CMD_RRB); - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); can_led_event(dev, CAN_LED_EVENT_RX); } @@ -447,7 +449,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & ECC_SEG; break; } @@ -484,10 +485,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) can_bus_off(dev); } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); return 0; } diff --git a/kernel/drivers/net/can/slcan.c b/kernel/drivers/net/can/slcan.c index a23a7af8e..9a3f15cb7 100644 --- a/kernel/drivers/net/can/slcan.c +++ b/kernel/drivers/net/can/slcan.c @@ -218,10 +218,10 @@ static void slc_bump(struct slcan *sl) memcpy(skb_put(skb, sizeof(struct can_frame)), &cf, sizeof(struct can_frame)); - netif_rx_ni(skb); sl->dev->stats.rx_packets++; sl->dev->stats.rx_bytes += cf.can_dlc; + netif_rx_ni(skb); } /* parse tty input stream */ diff --git a/kernel/drivers/net/can/spi/mcp251x.c b/kernel/drivers/net/can/spi/mcp251x.c index 34c625ea2..575790e8a 100644 --- a/kernel/drivers/net/can/spi/mcp251x.c +++ b/kernel/drivers/net/can/spi/mcp251x.c @@ -190,10 +190,11 @@ #define RXBEID0_OFF 4 #define RXBDLC_OFF 5 #define RXBDAT_OFF 6 -#define RXFSIDH(n) ((n) * 4) -#define RXFSIDL(n) ((n) * 4 + 1) -#define RXFEID8(n) ((n) * 4 + 2) -#define RXFEID0(n) ((n) * 4 + 3) +#define RXFSID(n) ((n < 3) ? 0 : 4) +#define RXFSIDH(n) ((n) * 4 + RXFSID(n)) +#define RXFSIDL(n) ((n) * 4 + 1 + RXFSID(n)) +#define RXFEID8(n) ((n) * 4 + 2 + RXFSID(n)) +#define RXFEID0(n) ((n) * 4 + 3 + RXFSID(n)) #define RXMSIDH(n) ((n) * 4 + 0x20) #define RXMSIDL(n) ((n) * 4 + 0x21) #define RXMEID8(n) ((n) * 4 + 0x22) @@ -1085,8 +1086,8 @@ static int mcp251x_can_probe(struct spi_device *spi) if (ret) goto out_clk; - priv->power = devm_regulator_get(&spi->dev, "vdd"); - priv->transceiver = devm_regulator_get(&spi->dev, "xceiver"); + priv->power = devm_regulator_get_optional(&spi->dev, "vdd"); + priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver"); if ((PTR_ERR(priv->power) == -EPROBE_DEFER) || (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) { ret = -EPROBE_DEFER; @@ -1242,7 +1243,6 @@ static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend, static struct spi_driver mcp251x_can_driver = { .driver = { .name = DEVICE_NAME, - .owner = THIS_MODULE, .of_match_table = mcp251x_of_match, .pm = &mcp251x_can_pm_ops, }, diff --git a/kernel/drivers/net/can/sun4i_can.c b/kernel/drivers/net/can/sun4i_can.c new file mode 100644 index 000000000..68ef0a4cd --- /dev/null +++ b/kernel/drivers/net/can/sun4i_can.c @@ -0,0 +1,856 @@ +/* + * sun4i_can.c - CAN bus controller driver for Allwinner SUN4I&SUN7I based SoCs + * + * Copyright (C) 2013 Peter Chen + * Copyright (C) 2015 Gerhard Bertelsmann + * All rights reserved. + * + * Parts of this software are based on (derived from) the SJA1000 code by: + * Copyright (C) 2014 Oliver Hartkopp <oliver.hartkopp@volkswagen.de> + * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> + * Copyright (C) 2002-2007 Volkswagen Group Electronic Research + * Copyright (C) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include <linux/netdevice.h> +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/can/led.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#define DRV_NAME "sun4i_can" + +/* Registers address (physical base address 0x01C2BC00) */ +#define SUN4I_REG_MSEL_ADDR 0x0000 /* CAN Mode Select */ +#define SUN4I_REG_CMD_ADDR 0x0004 /* CAN Command */ +#define SUN4I_REG_STA_ADDR 0x0008 /* CAN Status */ +#define SUN4I_REG_INT_ADDR 0x000c /* CAN Interrupt Flag */ +#define SUN4I_REG_INTEN_ADDR 0x0010 /* CAN Interrupt Enable */ +#define SUN4I_REG_BTIME_ADDR 0x0014 /* CAN Bus Timing 0 */ +#define SUN4I_REG_TEWL_ADDR 0x0018 /* CAN Tx Error Warning Limit */ +#define SUN4I_REG_ERRC_ADDR 0x001c /* CAN Error Counter */ +#define SUN4I_REG_RMCNT_ADDR 0x0020 /* CAN Receive Message Counter */ +#define SUN4I_REG_RBUFSA_ADDR 0x0024 /* CAN Receive Buffer Start Address */ +#define SUN4I_REG_BUF0_ADDR 0x0040 /* CAN Tx/Rx Buffer 0 */ +#define SUN4I_REG_BUF1_ADDR 0x0044 /* CAN Tx/Rx Buffer 1 */ +#define SUN4I_REG_BUF2_ADDR 0x0048 /* CAN Tx/Rx Buffer 2 */ +#define SUN4I_REG_BUF3_ADDR 0x004c /* CAN Tx/Rx Buffer 3 */ +#define SUN4I_REG_BUF4_ADDR 0x0050 /* CAN Tx/Rx Buffer 4 */ +#define SUN4I_REG_BUF5_ADDR 0x0054 /* CAN Tx/Rx Buffer 5 */ +#define SUN4I_REG_BUF6_ADDR 0x0058 /* CAN Tx/Rx Buffer 6 */ +#define SUN4I_REG_BUF7_ADDR 0x005c /* CAN Tx/Rx Buffer 7 */ +#define SUN4I_REG_BUF8_ADDR 0x0060 /* CAN Tx/Rx Buffer 8 */ +#define SUN4I_REG_BUF9_ADDR 0x0064 /* CAN Tx/Rx Buffer 9 */ +#define SUN4I_REG_BUF10_ADDR 0x0068 /* CAN Tx/Rx Buffer 10 */ +#define SUN4I_REG_BUF11_ADDR 0x006c /* CAN Tx/Rx Buffer 11 */ +#define SUN4I_REG_BUF12_ADDR 0x0070 /* CAN Tx/Rx Buffer 12 */ +#define SUN4I_REG_ACPC_ADDR 0x0040 /* CAN Acceptance Code 0 */ +#define SUN4I_REG_ACPM_ADDR 0x0044 /* CAN Acceptance Mask 0 */ +#define SUN4I_REG_RBUF_RBACK_START_ADDR 0x0180 /* CAN transmit buffer start */ +#define SUN4I_REG_RBUF_RBACK_END_ADDR 0x01b0 /* CAN transmit buffer end */ + +/* Controller Register Description */ + +/* mode select register (r/w) + * offset:0x0000 default:0x0000_0001 + */ +#define SUN4I_MSEL_SLEEP_MODE (0x01 << 4) /* write in reset mode */ +#define SUN4I_MSEL_WAKE_UP (0x00 << 4) +#define SUN4I_MSEL_SINGLE_FILTER (0x01 << 3) /* write in reset mode */ +#define SUN4I_MSEL_DUAL_FILTERS (0x00 << 3) +#define SUN4I_MSEL_LOOPBACK_MODE BIT(2) +#define SUN4I_MSEL_LISTEN_ONLY_MODE BIT(1) +#define SUN4I_MSEL_RESET_MODE BIT(0) + +/* command register (w) + * offset:0x0004 default:0x0000_0000 + */ +#define SUN4I_CMD_BUS_OFF_REQ BIT(5) +#define SUN4I_CMD_SELF_RCV_REQ BIT(4) +#define SUN4I_CMD_CLEAR_OR_FLAG BIT(3) +#define SUN4I_CMD_RELEASE_RBUF BIT(2) +#define SUN4I_CMD_ABORT_REQ BIT(1) +#define SUN4I_CMD_TRANS_REQ BIT(0) + +/* status register (r) + * offset:0x0008 default:0x0000_003c + */ +#define SUN4I_STA_BIT_ERR (0x00 << 22) +#define SUN4I_STA_FORM_ERR (0x01 << 22) +#define SUN4I_STA_STUFF_ERR (0x02 << 22) +#define SUN4I_STA_OTHER_ERR (0x03 << 22) +#define SUN4I_STA_MASK_ERR (0x03 << 22) +#define SUN4I_STA_ERR_DIR BIT(21) +#define SUN4I_STA_ERR_SEG_CODE (0x1f << 16) +#define SUN4I_STA_START (0x03 << 16) +#define SUN4I_STA_ID28_21 (0x02 << 16) +#define SUN4I_STA_ID20_18 (0x06 << 16) +#define SUN4I_STA_SRTR (0x04 << 16) +#define SUN4I_STA_IDE (0x05 << 16) +#define SUN4I_STA_ID17_13 (0x07 << 16) +#define SUN4I_STA_ID12_5 (0x0f << 16) +#define SUN4I_STA_ID4_0 (0x0e << 16) +#define SUN4I_STA_RTR (0x0c << 16) +#define SUN4I_STA_RB1 (0x0d << 16) +#define SUN4I_STA_RB0 (0x09 << 16) +#define SUN4I_STA_DLEN (0x0b << 16) +#define SUN4I_STA_DATA_FIELD (0x0a << 16) +#define SUN4I_STA_CRC_SEQUENCE (0x08 << 16) +#define SUN4I_STA_CRC_DELIMITER (0x18 << 16) +#define SUN4I_STA_ACK (0x19 << 16) +#define SUN4I_STA_ACK_DELIMITER (0x1b << 16) +#define SUN4I_STA_END (0x1a << 16) +#define SUN4I_STA_INTERMISSION (0x12 << 16) +#define SUN4I_STA_ACTIVE_ERROR (0x11 << 16) +#define SUN4I_STA_PASSIVE_ERROR (0x16 << 16) +#define SUN4I_STA_TOLERATE_DOMINANT_BITS (0x13 << 16) +#define SUN4I_STA_ERROR_DELIMITER (0x17 << 16) +#define SUN4I_STA_OVERLOAD (0x1c << 16) +#define SUN4I_STA_BUS_OFF BIT(7) +#define SUN4I_STA_ERR_STA BIT(6) +#define SUN4I_STA_TRANS_BUSY BIT(5) +#define SUN4I_STA_RCV_BUSY BIT(4) +#define SUN4I_STA_TRANS_OVER BIT(3) +#define SUN4I_STA_TBUF_RDY BIT(2) +#define SUN4I_STA_DATA_ORUN BIT(1) +#define SUN4I_STA_RBUF_RDY BIT(0) + +/* interrupt register (r) + * offset:0x000c default:0x0000_0000 + */ +#define SUN4I_INT_BUS_ERR BIT(7) +#define SUN4I_INT_ARB_LOST BIT(6) +#define SUN4I_INT_ERR_PASSIVE BIT(5) +#define SUN4I_INT_WAKEUP BIT(4) +#define SUN4I_INT_DATA_OR BIT(3) +#define SUN4I_INT_ERR_WRN BIT(2) +#define SUN4I_INT_TBUF_VLD BIT(1) +#define SUN4I_INT_RBUF_VLD BIT(0) + +/* interrupt enable register (r/w) + * offset:0x0010 default:0x0000_0000 + */ +#define SUN4I_INTEN_BERR BIT(7) +#define SUN4I_INTEN_ARB_LOST BIT(6) +#define SUN4I_INTEN_ERR_PASSIVE BIT(5) +#define SUN4I_INTEN_WAKEUP BIT(4) +#define SUN4I_INTEN_OR BIT(3) +#define SUN4I_INTEN_ERR_WRN BIT(2) +#define SUN4I_INTEN_TX BIT(1) +#define SUN4I_INTEN_RX BIT(0) + +/* error code */ +#define SUN4I_ERR_INRCV (0x1 << 5) +#define SUN4I_ERR_INTRANS (0x0 << 5) + +/* filter mode */ +#define SUN4I_FILTER_CLOSE 0 +#define SUN4I_SINGLE_FLTER_MODE 1 +#define SUN4I_DUAL_FILTER_MODE 2 + +/* message buffer flags */ +#define SUN4I_MSG_EFF_FLAG BIT(7) +#define SUN4I_MSG_RTR_FLAG BIT(6) + +/* max. number of interrupts handled in ISR */ +#define SUN4I_CAN_MAX_IRQ 20 +#define SUN4I_MODE_MAX_RETRIES 100 + +struct sun4ican_priv { + struct can_priv can; + void __iomem *base; + struct clk *clk; + spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */ +}; + +static const struct can_bittiming_const sun4ican_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 64, + .brp_inc = 1, +}; + +static void sun4i_can_write_cmdreg(struct sun4ican_priv *priv, u8 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->cmdreg_lock, flags); + writel(val, priv->base + SUN4I_REG_CMD_ADDR); + spin_unlock_irqrestore(&priv->cmdreg_lock, flags); +} + +static int set_normal_mode(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + int retry = SUN4I_MODE_MAX_RETRIES; + u32 mod_reg_val = 0; + + do { + mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); + mod_reg_val &= ~SUN4I_MSEL_RESET_MODE; + writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); + } while (retry-- && (mod_reg_val & SUN4I_MSEL_RESET_MODE)); + + if (readl(priv->base + SUN4I_REG_MSEL_ADDR) & SUN4I_MSEL_RESET_MODE) { + netdev_err(dev, + "setting controller into normal mode failed!\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int set_reset_mode(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + int retry = SUN4I_MODE_MAX_RETRIES; + u32 mod_reg_val = 0; + + do { + mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); + mod_reg_val |= SUN4I_MSEL_RESET_MODE; + writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); + } while (retry-- && !(mod_reg_val & SUN4I_MSEL_RESET_MODE)); + + if (!(readl(priv->base + SUN4I_REG_MSEL_ADDR) & + SUN4I_MSEL_RESET_MODE)) { + netdev_err(dev, "setting controller into reset mode failed!\n"); + return -ETIMEDOUT; + } + + return 0; +} + +/* bittiming is called in reset_mode only */ +static int sun4ican_set_bittiming(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + u32 cfg; + + cfg = ((bt->brp - 1) & 0x3FF) | + (((bt->sjw - 1) & 0x3) << 14) | + (((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) << 16) | + (((bt->phase_seg2 - 1) & 0x7) << 20); + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + cfg |= 0x800000; + + netdev_dbg(dev, "setting BITTIMING=0x%08x\n", cfg); + writel(cfg, priv->base + SUN4I_REG_BTIME_ADDR); + + return 0; +} + +static int sun4ican_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + u32 errors; + int err; + + err = clk_prepare_enable(priv->clk); + if (err) { + netdev_err(dev, "could not enable clock\n"); + return err; + } + + errors = readl(priv->base + SUN4I_REG_ERRC_ADDR); + + bec->txerr = errors & 0xFF; + bec->rxerr = (errors >> 16) & 0xFF; + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int sun4i_can_start(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + int err; + u32 mod_reg_val; + + /* we need to enter the reset mode */ + err = set_reset_mode(dev); + if (err) { + netdev_err(dev, "could not enter reset mode\n"); + return err; + } + + /* set filters - we accept all */ + writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR); + writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR); + + /* clear error counters and error code capture */ + writel(0, priv->base + SUN4I_REG_ERRC_ADDR); + + /* enable interrupts */ + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + writel(0xFF, priv->base + SUN4I_REG_INTEN_ADDR); + else + writel(0xFF & ~SUN4I_INTEN_BERR, + priv->base + SUN4I_REG_INTEN_ADDR); + + /* enter the selected mode */ + mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); + if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) + mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE; + else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE; + writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); + + err = sun4ican_set_bittiming(dev); + if (err) + return err; + + /* we are ready to enter the normal mode */ + err = set_normal_mode(dev); + if (err) { + netdev_err(dev, "could not enter normal mode\n"); + return err; + } + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + return 0; +} + +static int sun4i_can_stop(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + int err; + + priv->can.state = CAN_STATE_STOPPED; + /* we need to enter reset mode */ + err = set_reset_mode(dev); + if (err) { + netdev_err(dev, "could not enter reset mode\n"); + return err; + } + + /* disable all interrupts */ + writel(0, priv->base + SUN4I_REG_INTEN_ADDR); + + return 0; +} + +static int sun4ican_set_mode(struct net_device *dev, enum can_mode mode) +{ + int err; + + switch (mode) { + case CAN_MODE_START: + err = sun4i_can_start(dev); + if (err) { + netdev_err(dev, "starting CAN controller failed!\n"); + return err; + } + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* transmit a CAN message + * message layout in the sk_buff should be like this: + * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 + * [ can_id ] [flags] [len] [can data (up to 8 bytes] + */ +static int sun4ican_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + struct can_frame *cf = (struct can_frame *)skb->data; + u8 dlc; + u32 dreg, msg_flag_n; + canid_t id; + int i; + + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + + netif_stop_queue(dev); + + id = cf->can_id; + dlc = cf->can_dlc; + msg_flag_n = dlc; + + if (id & CAN_RTR_FLAG) + msg_flag_n |= SUN4I_MSG_RTR_FLAG; + + if (id & CAN_EFF_FLAG) { + msg_flag_n |= SUN4I_MSG_EFF_FLAG; + dreg = SUN4I_REG_BUF5_ADDR; + writel((id >> 21) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR); + writel((id >> 13) & 0xFF, priv->base + SUN4I_REG_BUF2_ADDR); + writel((id >> 5) & 0xFF, priv->base + SUN4I_REG_BUF3_ADDR); + writel((id << 3) & 0xF8, priv->base + SUN4I_REG_BUF4_ADDR); + } else { + dreg = SUN4I_REG_BUF3_ADDR; + writel((id >> 3) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR); + writel((id << 5) & 0xE0, priv->base + SUN4I_REG_BUF2_ADDR); + } + + for (i = 0; i < dlc; i++) + writel(cf->data[i], priv->base + (dreg + i * 4)); + + writel(msg_flag_n, priv->base + SUN4I_REG_BUF0_ADDR); + + can_put_echo_skb(skb, dev, 0); + + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + sun4i_can_write_cmdreg(priv, SUN4I_CMD_SELF_RCV_REQ); + else + sun4i_can_write_cmdreg(priv, SUN4I_CMD_TRANS_REQ); + + return NETDEV_TX_OK; +} + +static void sun4i_can_rx(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u8 fi; + u32 dreg; + canid_t id; + int i; + + /* create zero'ed CAN frame buffer */ + skb = alloc_can_skb(dev, &cf); + if (!skb) + return; + + fi = readl(priv->base + SUN4I_REG_BUF0_ADDR); + cf->can_dlc = get_can_dlc(fi & 0x0F); + if (fi & SUN4I_MSG_EFF_FLAG) { + dreg = SUN4I_REG_BUF5_ADDR; + id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 21) | + (readl(priv->base + SUN4I_REG_BUF2_ADDR) << 13) | + (readl(priv->base + SUN4I_REG_BUF3_ADDR) << 5) | + ((readl(priv->base + SUN4I_REG_BUF4_ADDR) >> 3) & 0x1f); + id |= CAN_EFF_FLAG; + } else { + dreg = SUN4I_REG_BUF3_ADDR; + id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 3) | + ((readl(priv->base + SUN4I_REG_BUF2_ADDR) >> 5) & 0x7); + } + + /* remote frame ? */ + if (fi & SUN4I_MSG_RTR_FLAG) + id |= CAN_RTR_FLAG; + else + for (i = 0; i < cf->can_dlc; i++) + cf->data[i] = readl(priv->base + dreg + i * 4); + + cf->can_id = id; + + sun4i_can_write_cmdreg(priv, SUN4I_CMD_RELEASE_RBUF); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + + can_led_event(dev, CAN_LED_EVENT_RX); +} + +static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + enum can_state state = priv->can.state; + enum can_state rx_state, tx_state; + unsigned int rxerr, txerr, errc; + u32 ecc, alc; + + /* we don't skip if alloc fails because we want the stats anyhow */ + skb = alloc_can_err_skb(dev, &cf); + + errc = readl(priv->base + SUN4I_REG_ERRC_ADDR); + rxerr = (errc >> 16) & 0xFF; + txerr = errc & 0xFF; + + if (skb) { + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + + if (isrc & SUN4I_INT_DATA_OR) { + /* data overrun interrupt */ + netdev_dbg(dev, "data overrun interrupt\n"); + if (likely(skb)) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + } + stats->rx_over_errors++; + stats->rx_errors++; + /* clear bit */ + sun4i_can_write_cmdreg(priv, SUN4I_CMD_CLEAR_OR_FLAG); + } + if (isrc & SUN4I_INT_ERR_WRN) { + /* error warning interrupt */ + netdev_dbg(dev, "error warning interrupt\n"); + + if (status & SUN4I_STA_BUS_OFF) + state = CAN_STATE_BUS_OFF; + else if (status & SUN4I_STA_ERR_STA) + state = CAN_STATE_ERROR_WARNING; + else + state = CAN_STATE_ERROR_ACTIVE; + } + if (isrc & SUN4I_INT_BUS_ERR) { + /* bus error interrupt */ + netdev_dbg(dev, "bus error interrupt\n"); + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + if (likely(skb)) { + ecc = readl(priv->base + SUN4I_REG_STA_ADDR); + + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (ecc & SUN4I_STA_MASK_ERR) { + case SUN4I_STA_BIT_ERR: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case SUN4I_STA_FORM_ERR: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case SUN4I_STA_STUFF_ERR: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE) + >> 16; + break; + } + /* error occurred during transmission? */ + if ((ecc & SUN4I_STA_ERR_DIR) == 0) + cf->data[2] |= CAN_ERR_PROT_TX; + } + } + if (isrc & SUN4I_INT_ERR_PASSIVE) { + /* error passive interrupt */ + netdev_dbg(dev, "error passive interrupt\n"); + if (state == CAN_STATE_ERROR_PASSIVE) + state = CAN_STATE_ERROR_WARNING; + else + state = CAN_STATE_ERROR_PASSIVE; + } + if (isrc & SUN4I_INT_ARB_LOST) { + /* arbitration lost interrupt */ + netdev_dbg(dev, "arbitration lost interrupt\n"); + alc = readl(priv->base + SUN4I_REG_STA_ADDR); + priv->can.can_stats.arbitration_lost++; + stats->tx_errors++; + if (likely(skb)) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = (alc >> 8) & 0x1f; + } + } + + if (state != priv->can.state) { + tx_state = txerr >= rxerr ? state : 0; + rx_state = txerr <= rxerr ? state : 0; + + if (likely(skb)) + can_change_state(dev, cf, tx_state, rx_state); + else + priv->can.state = state; + if (state == CAN_STATE_BUS_OFF) + can_bus_off(dev); + } + + if (likely(skb)) { + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } else { + return -ENOMEM; + } + + return 0; +} + +static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct sun4ican_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + u8 isrc, status; + int n = 0; + + while ((isrc = readl(priv->base + SUN4I_REG_INT_ADDR)) && + (n < SUN4I_CAN_MAX_IRQ)) { + n++; + status = readl(priv->base + SUN4I_REG_STA_ADDR); + + if (isrc & SUN4I_INT_WAKEUP) + netdev_warn(dev, "wakeup interrupt\n"); + + if (isrc & SUN4I_INT_TBUF_VLD) { + /* transmission complete interrupt */ + stats->tx_bytes += + readl(priv->base + + SUN4I_REG_RBUF_RBACK_START_ADDR) & 0xf; + stats->tx_packets++; + can_get_echo_skb(dev, 0); + netif_wake_queue(dev); + can_led_event(dev, CAN_LED_EVENT_TX); + } + if (isrc & SUN4I_INT_RBUF_VLD) { + /* receive interrupt */ + while (status & SUN4I_STA_RBUF_RDY) { + /* RX buffer is not empty */ + sun4i_can_rx(dev); + status = readl(priv->base + SUN4I_REG_STA_ADDR); + } + } + if (isrc & + (SUN4I_INT_DATA_OR | SUN4I_INT_ERR_WRN | SUN4I_INT_BUS_ERR | + SUN4I_INT_ERR_PASSIVE | SUN4I_INT_ARB_LOST)) { + /* error interrupt */ + if (sun4i_can_err(dev, isrc, status)) + netdev_err(dev, "can't allocate buffer - clearing pending interrupts\n"); + } + /* clear interrupts */ + writel(isrc, priv->base + SUN4I_REG_INT_ADDR); + readl(priv->base + SUN4I_REG_INT_ADDR); + } + if (n >= SUN4I_CAN_MAX_IRQ) + netdev_dbg(dev, "%d messages handled in ISR", n); + + return (n) ? IRQ_HANDLED : IRQ_NONE; +} + +static int sun4ican_open(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + int err; + + /* common open */ + err = open_candev(dev); + if (err) + return err; + + /* register interrupt handler */ + err = request_irq(dev->irq, sun4i_can_interrupt, 0, dev->name, dev); + if (err) { + netdev_err(dev, "request_irq err: %d\n", err); + goto exit_irq; + } + + /* turn on clocking for CAN peripheral block */ + err = clk_prepare_enable(priv->clk); + if (err) { + netdev_err(dev, "could not enable CAN peripheral clock\n"); + goto exit_clock; + } + + err = sun4i_can_start(dev); + if (err) { + netdev_err(dev, "could not start CAN peripheral\n"); + goto exit_can_start; + } + + can_led_event(dev, CAN_LED_EVENT_OPEN); + netif_start_queue(dev); + + return 0; + +exit_can_start: + clk_disable_unprepare(priv->clk); +exit_clock: + free_irq(dev->irq, dev); +exit_irq: + close_candev(dev); + return err; +} + +static int sun4ican_close(struct net_device *dev) +{ + struct sun4ican_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + sun4i_can_stop(dev); + clk_disable_unprepare(priv->clk); + + free_irq(dev->irq, dev); + close_candev(dev); + can_led_event(dev, CAN_LED_EVENT_STOP); + + return 0; +} + +static const struct net_device_ops sun4ican_netdev_ops = { + .ndo_open = sun4ican_open, + .ndo_stop = sun4ican_close, + .ndo_start_xmit = sun4ican_start_xmit, +}; + +static const struct of_device_id sun4ican_of_match[] = { + {.compatible = "allwinner,sun4i-a10-can"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, sun4ican_of_match); + +static int sun4ican_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + unregister_netdev(dev); + free_candev(dev); + + return 0; +} + +static int sun4ican_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *mem; + struct clk *clk; + void __iomem *addr; + int err, irq; + struct net_device *dev; + struct sun4ican_priv *priv; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to request clock\n"); + err = -ENODEV; + goto exit; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "could not get a valid irq\n"); + err = -ENODEV; + goto exit; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(addr)) { + err = -EBUSY; + goto exit; + } + + dev = alloc_candev(sizeof(struct sun4ican_priv), 1); + if (!dev) { + dev_err(&pdev->dev, + "could not allocate memory for CAN device\n"); + err = -ENOMEM; + goto exit; + } + + dev->netdev_ops = &sun4ican_netdev_ops; + dev->irq = irq; + dev->flags |= IFF_ECHO; + + priv = netdev_priv(dev); + priv->can.clock.freq = clk_get_rate(clk); + priv->can.bittiming_const = &sun4ican_bittiming_const; + priv->can.do_set_mode = sun4ican_set_mode; + priv->can.do_get_berr_counter = sun4ican_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_PRESUME_ACK | + CAN_CTRLMODE_3_SAMPLES; + priv->base = addr; + priv->clk = clk; + spin_lock_init(&priv->cmdreg_lock); + + platform_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + err = register_candev(dev); + if (err) { + dev_err(&pdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free; + } + devm_can_led_init(dev); + + dev_info(&pdev->dev, "device registered (base=%p, irq=%d)\n", + priv->base, dev->irq); + + return 0; + +exit_free: + free_candev(dev); +exit: + return err; +} + +static struct platform_driver sun4i_can_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = sun4ican_of_match, + }, + .probe = sun4ican_probe, + .remove = sun4ican_remove, +}; + +module_platform_driver(sun4i_can_driver); + +MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>"); +MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20)"); diff --git a/kernel/drivers/net/can/ti_hecc.c b/kernel/drivers/net/can/ti_hecc.c index e95a9e1a8..680d1ff07 100644 --- a/kernel/drivers/net/can/ti_hecc.c +++ b/kernel/drivers/net/can/ti_hecc.c @@ -722,7 +722,6 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, if (err_status & HECC_BUS_ERROR) { ++priv->can.can_stats.bus_error; cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; if (err_status & HECC_CANES_FE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE); cf->data[2] |= CAN_ERR_PROT_FORM; @@ -737,19 +736,17 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, } if (err_status & HECC_CANES_CRCE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE); - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } if (err_status & HECC_CANES_ACKE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); - cf->data[3] |= CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } - netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); return 0; } diff --git a/kernel/drivers/net/can/usb/ems_usb.c b/kernel/drivers/net/can/usb/ems_usb.c index 866bac0ae..eb7192fab 100644 --- a/kernel/drivers/net/can/usb/ems_usb.c +++ b/kernel/drivers/net/can/usb/ems_usb.c @@ -117,6 +117,9 @@ MODULE_LICENSE("GPL v2"); */ #define EMS_USB_ARM7_CLOCK 8000000 +#define CPC_TX_QUEUE_TRIGGER_LOW 25 +#define CPC_TX_QUEUE_TRIGGER_HIGH 35 + /* * CAN-Message representation in a CPC_MSG. Message object type is * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or @@ -278,6 +281,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) switch (urb->status) { case 0: dev->free_slots = dev->intr_in_buffer[1]; + if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){ + if (netif_queue_stopped(netdev)){ + netif_wake_queue(netdev); + } + } break; case -ECONNRESET: /* unlink */ @@ -324,10 +332,9 @@ static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg) cf->data[i] = msg->msg.can_msg.msg[i]; } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) @@ -378,7 +385,6 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & SJA1000_ECC_SEG; break; } @@ -400,10 +406,9 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) stats->rx_errors++; } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } /* @@ -529,8 +534,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb) /* Release context */ context->echo_index = MAX_TX_URBS; - if (netif_queue_stopped(netdev)) - netif_wake_queue(netdev); } /* @@ -590,7 +593,7 @@ static int ems_usb_start(struct ems_usb *dev) int err, i; dev->intr_in_buffer[0] = 0; - dev->free_slots = 15; /* initial size */ + dev->free_slots = 50; /* initial size */ for (i = 0; i < MAX_RX_URBS; i++) { struct urb *urb = NULL; @@ -838,7 +841,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne /* Slow down tx path */ if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || - dev->free_slots < 5) { + dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) { netif_stop_queue(netdev); } } diff --git a/kernel/drivers/net/can/usb/esd_usb2.c b/kernel/drivers/net/can/usb/esd_usb2.c index 411c1af92..113e64fcd 100644 --- a/kernel/drivers/net/can/usb/esd_usb2.c +++ b/kernel/drivers/net/can/usb/esd_usb2.c @@ -282,7 +282,6 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & SJA1000_ECC_SEG; break; } @@ -301,13 +300,12 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, cf->data[7] = rxerr; } - netif_rx(skb); - priv->bec.txerr = txerr; priv->bec.rxerr = rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } } @@ -347,10 +345,9 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv, cf->data[i] = msg->msg.rx.data[i]; } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } return; diff --git a/kernel/drivers/net/can/usb/gs_usb.c b/kernel/drivers/net/can/usb/gs_usb.c index 8b4d3e687..cbc99d564 100644 --- a/kernel/drivers/net/can/usb/gs_usb.c +++ b/kernel/drivers/net/can/usb/gs_usb.c @@ -162,7 +162,7 @@ struct gs_can { struct can_bittiming_const bt_const; unsigned int channel; /* channel number */ - /* This lock prevents a race condition between xmit and recieve. */ + /* This lock prevents a race condition between xmit and receive. */ spinlock_t tx_ctx_lock; struct gs_tx_context tx_context[GS_MAX_TX_URBS]; @@ -274,7 +274,7 @@ static void gs_update_state(struct gs_can *dev, struct can_frame *cf) } } -static void gs_usb_recieve_bulk_callback(struct urb *urb) +static void gs_usb_receive_bulk_callback(struct urb *urb) { struct gs_usb *usbcan = urb->context; struct gs_can *dev; @@ -376,7 +376,7 @@ static void gs_usb_recieve_bulk_callback(struct urb *urb) usb_rcvbulkpipe(usbcan->udev, GSUSB_ENDPOINT_IN), hf, sizeof(struct gs_host_frame), - gs_usb_recieve_bulk_callback, + gs_usb_receive_bulk_callback, usbcan ); @@ -605,7 +605,7 @@ static int gs_can_open(struct net_device *netdev) GSUSB_ENDPOINT_IN), buf, sizeof(struct gs_host_frame), - gs_usb_recieve_bulk_callback, + gs_usb_receive_bulk_callback, parent); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface static void gs_destroy_candev(struct gs_can *dev) { unregister_candev(dev->netdev); - free_candev(dev->netdev); usb_kill_anchored_urbs(&dev->tx_submitted); - kfree(dev); + free_candev(dev->netdev); } static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * for (i = 0; i < icount; i++) { dev->canch[i] = gs_make_candev(i, intf); if (IS_ERR_OR_NULL(dev->canch[i])) { + /* save error code to return later */ + rc = PTR_ERR(dev->canch[i]); + /* on failure destroy previously created candevs */ icount = i; - for (i = 0; i < icount; i++) { + for (i = 0; i < icount; i++) gs_destroy_candev(dev->canch[i]); - dev->canch[i] = NULL; - } + + usb_kill_anchored_urbs(&dev->rx_submitted); kfree(dev); return rc; } @@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf) return; } - for (i = 0; i < GS_MAX_INTF; i++) { - struct gs_can *can = dev->canch[i]; - - if (!can) - continue; - - gs_destroy_candev(can); - } + for (i = 0; i < GS_MAX_INTF; i++) + if (dev->canch[i]) + gs_destroy_candev(dev->canch[i]); usb_kill_anchored_urbs(&dev->rx_submitted); + kfree(dev); } static const struct usb_device_id gs_usb_table[] = { diff --git a/kernel/drivers/net/can/usb/kvaser_usb.c b/kernel/drivers/net/can/usb/kvaser_usb.c index 8b17a9065..022bfa13e 100644 --- a/kernel/drivers/net/can/usb/kvaser_usb.c +++ b/kernel/drivers/net/can/usb/kvaser_usb.c @@ -944,10 +944,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; if (es->leaf.error_factor & M16C_EF_ACKE) - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; if (es->leaf.error_factor & M16C_EF_CRCE) - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; if (es->leaf.error_factor & M16C_EF_FORME) cf->data[2] |= CAN_ERR_PROT_FORM; if (es->leaf.error_factor & M16C_EF_STFE) diff --git a/kernel/drivers/net/can/usb/peak_usb/pcan_usb.c b/kernel/drivers/net/can/usb/peak_usb/pcan_usb.c index edfec540c..838545ce4 100644 --- a/kernel/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/kernel/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -526,9 +526,9 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, hwts->hwtstamp = timeval_to_ktime(tv); } - netif_rx(skb); mc->netdev->stats.rx_packets++; mc->netdev->stats.rx_bytes += cf->can_dlc; + netif_rx(skb); return 0; } @@ -659,12 +659,11 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) hwts = skb_hwtstamps(skb); hwts->hwtstamp = timeval_to_ktime(tv); - /* push the skb */ - netif_rx(skb); - /* update statistics */ mc->netdev->stats.rx_packets++; mc->netdev->stats.rx_bytes += cf->can_dlc; + /* push the skb */ + netif_rx(skb); return 0; diff --git a/kernel/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/kernel/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index a5ad2e6aa..bbdd6058c 100644 --- a/kernel/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/kernel/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -553,9 +553,9 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, hwts = skb_hwtstamps(skb); hwts->hwtstamp = timeval_to_ktime(tv); - netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += can_frame->can_dlc; + netif_rx(skb); return 0; } @@ -670,9 +670,9 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); hwts = skb_hwtstamps(skb); hwts->hwtstamp = timeval_to_ktime(tv); - netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += can_frame->can_dlc; + netif_rx(skb); return 0; } diff --git a/kernel/drivers/net/can/usb/usb_8dev.c b/kernel/drivers/net/can/usb/usb_8dev.c index dd52c7a4c..a731720f1 100644 --- a/kernel/drivers/net/can/usb/usb_8dev.c +++ b/kernel/drivers/net/can/usb/usb_8dev.c @@ -401,9 +401,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, tx_errors = 1; break; case USB_8DEV_STATUSMSG_CRC: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; rx_errors = 1; break; case USB_8DEV_STATUSMSG_BIT0: @@ -461,10 +459,9 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, priv->bec.txerr = txerr; priv->bec.rxerr = rxerr; - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } /* Read data and status frames */ @@ -494,10 +491,9 @@ static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv, else memcpy(cf->data, msg->data, cf->can_dlc); - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); can_led_event(priv->netdev, CAN_LED_EVENT_RX); } else { diff --git a/kernel/drivers/net/can/xilinx_can.c b/kernel/drivers/net/can/xilinx_can.c index fc55e8e03..51670b322 100644 --- a/kernel/drivers/net/can/xilinx_can.c +++ b/kernel/drivers/net/can/xilinx_can.c @@ -608,17 +608,15 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) /* Check for error interrupt */ if (isr & XCAN_IXR_ERROR_MASK) { - if (skb) { + if (skb) cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; - } /* Check for Ack error interrupt */ if (err_status & XCAN_ESR_ACKER_MASK) { stats->tx_errors++; if (skb) { cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } @@ -654,8 +652,7 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) stats->rx_errors++; if (skb) { cf->can_id |= CAN_ERR_PROT; - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } } priv->can.can_stats.bus_error++; |