diff options
Diffstat (limited to 'drivers/net/can')
62 files changed, 10326 insertions, 2056 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index bb709fd6699..41688229c57 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -1,9 +1,7 @@ menu "CAN Device Drivers" - depends on CAN config CAN_VCAN tristate "Virtual Local CAN Interface (vcan)" - depends on CAN ---help--- Similar to the network loopback devices, vcan offers a virtual local CAN interface. @@ -13,7 +11,7 @@ config CAN_VCAN config CAN_SLCAN tristate "Serial / USB serial CAN Adaptors (slcan)" - depends on CAN + depends on TTY ---help--- CAN driver for several 'low cost' CAN interfaces that are attached via serial lines or via USB-to-serial adapters using the LAWICEL @@ -33,16 +31,16 @@ config CAN_SLCAN config CAN_DEV tristate "Platform CAN drivers with Netlink support" - depends on CAN default y ---help--- Enables the common framework for platform CAN drivers with Netlink support. This is the standard library for CAN drivers. If unsure, say Y. +if CAN_DEV + config CAN_CALC_BITTIMING bool "CAN bit-timing calculation" - depends on CAN_DEV default y ---help--- If enabled, CAN bit-timing parameters will be calculated for the @@ -54,28 +52,33 @@ config CAN_CALC_BITTIMING arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". If unsure, say Y. +config CAN_LEDS + bool "Enable LED triggers for Netlink based drivers" + depends on LEDS_CLASS + select LEDS_TRIGGERS + ---help--- + This option adds two LED triggers for packet receive and transmit + events on each supported CAN device. + + Say Y here if you are working on a system with led-class supported + LEDs and you want to use them as canbus activity indicators. + config CAN_AT91 tristate "Atmel AT91 onchip CAN controller" - depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5) + depends on ARCH_AT91 || COMPILE_TEST ---help--- This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 and AT91SAM9X5 processors. config CAN_TI_HECC - depends on CAN_DEV && ARCH_OMAP3 + depends on ARM tristate "TI High End CAN Controller" ---help--- Driver for TI HECC (High End CAN Controller) module found on many TI devices. The device specifications are available from www.ti.com -config CAN_MCP251X - tristate "Microchip MCP251x SPI CAN controllers" - depends on CAN_DEV && SPI && HAS_DMA - ---help--- - Driver for the Microchip MCP251x SPI CAN controllers. - config CAN_BFIN - depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x) + depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x tristate "Analog Devices Blackfin on-chip CAN" ---help--- Driver for the Analog Devices Blackfin on-chip CAN controllers @@ -85,7 +88,7 @@ config CAN_BFIN config CAN_JANZ_ICAN3 tristate "Janz VMOD-ICAN3 Intelligent CAN controller" - depends on CAN_DEV && MFD_JANZ_CMODIO + depends on MFD_JANZ_CMODIO ---help--- Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which connects to a MODULbus carrier board. @@ -93,23 +96,47 @@ config CAN_JANZ_ICAN3 This driver can also be built as a module. If so, the module will be called janz-ican3.ko. -config HAVE_CAN_FLEXCAN - bool - config CAN_FLEXCAN tristate "Support for Freescale FLEXCAN based chips" - depends on CAN_DEV && HAVE_CAN_FLEXCAN + depends on ARM || PPC ---help--- Say Y here if you want to support for Freescale FlexCAN. config PCH_CAN tristate "Intel EG20T PCH CAN controller" - depends on CAN_DEV && PCI + depends on PCI && (X86_32 || COMPILE_TEST) ---help--- This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which is an IOH for x86 embedded processor (Intel Atom E6xx series). This driver can access CAN bus. +config CAN_GRCAN + tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" + depends on OF + ---help--- + Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. + Note that the driver supports little endian, even though little + endian syntheses of the cores would need some modifications on + the hardware level to work. + +config CAN_RCAR + tristate "Renesas R-Car CAN controller" + depends on ARM + ---help--- + Say Y here if you want to use CAN controller found on Renesas R-Car + SoCs. + + To compile this driver as a module, choose M here: the module will + be called rcar_can. + +config CAN_XILINXCAN + tristate "Xilinx CAN" + depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST + depends on COMMON_CLK && HAS_IOMEM + ---help--- + Xilinx CAN driver. This driver supports both soft AXI CAN IP and + Zynq CANPS IP. + source "drivers/net/can/mscan/Kconfig" source "drivers/net/can/sja1000/Kconfig" @@ -118,13 +145,16 @@ source "drivers/net/can/c_can/Kconfig" source "drivers/net/can/cc770/Kconfig" +source "drivers/net/can/spi/Kconfig" + source "drivers/net/can/usb/Kconfig" source "drivers/net/can/softing/Kconfig" +endif + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" - depends on CAN ---help--- Say Y here if you want the CAN device drivers to produce a bunch of debug messages to the system log. Select this if you are having diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 938be37b670..1697f22353a 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -8,6 +8,9 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o obj-$(CONFIG_CAN_DEV) += can-dev.o can-dev-y := dev.o +can-dev-$(CONFIG_CAN_LEDS) += led.o + +obj-y += spi/ obj-y += usb/ obj-y += softing/ @@ -17,10 +20,12 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/ obj-$(CONFIG_CAN_CC770) += cc770/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o -obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o 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_XILINXCAN) += xilinx_can.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index fcff73a73b1..f07fa89b5fd 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -22,22 +22,22 @@ #include <linux/clk.h> #include <linux/errno.h> #include <linux/if_arp.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/netdevice.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/rtnetlink.h> #include <linux/skbuff.h> #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> - -#include <mach/board.h> +#include <linux/can/led.h> #define AT91_MB_MASK(i) ((1 << (i)) - 1) @@ -155,19 +155,20 @@ struct at91_priv { canid_t mb0_id; }; -static const struct at91_devtype_data at91_devtype_data[] __devinitconst = { - [AT91_DEVTYPE_SAM9263] = { - .rx_first = 1, - .rx_split = 8, - .rx_last = 11, - .tx_shift = 2, - }, - [AT91_DEVTYPE_SAM9X5] = { - .rx_first = 0, - .rx_split = 4, - .rx_last = 5, - .tx_shift = 1, - }, +static const struct at91_devtype_data at91_at91sam9263_data = { + .rx_first = 1, + .rx_split = 8, + .rx_last = 11, + .tx_shift = 2, + .type = AT91_DEVTYPE_SAM9263, +}; + +static const struct at91_devtype_data at91_at91sam9x5_data = { + .rx_first = 0, + .rx_split = 4, + .rx_last = 5, + .tx_shift = 1, + .type = AT91_DEVTYPE_SAM9X5, }; static const struct can_bittiming_const at91_bittiming_const = { @@ -419,7 +420,11 @@ static void at91_chip_start(struct net_device *dev) at91_transceiver_switch(priv, 1); /* enable chip */ - at91_write(priv, AT91_MR, AT91_MR_CANEN); + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + reg_mr = AT91_MR_CANEN | AT91_MR_ABM; + else + reg_mr = AT91_MR_CANEN; + at91_write(priv, AT91_MR, reg_mr); priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -642,6 +647,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + + can_led_event(dev, CAN_LED_EVENT_RX); } /** @@ -876,6 +883,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ can_get_echo_skb(dev, mb - get_mb_tx_first(priv)); dev->stats.tx_packets++; + can_led_event(dev, CAN_LED_EVENT_TX); } } @@ -1129,6 +1137,8 @@ static int at91_open(struct net_device *dev) goto out_close; } + can_led_event(dev, CAN_LED_EVENT_OPEN); + /* start chip and queuing */ at91_chip_start(dev); napi_enable(&priv->napi); @@ -1160,6 +1170,8 @@ static int at91_close(struct net_device *dev) close_candev(dev); + can_led_event(dev, CAN_LED_EVENT_STOP); + return 0; } @@ -1182,6 +1194,7 @@ static const struct net_device_ops at91_netdev_ops = { .ndo_open = at91_open, .ndo_stop = at91_close, .ndo_start_xmit = at91_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static ssize_t at91_sysfs_show_mb0_id(struct device *dev, @@ -1211,7 +1224,7 @@ static ssize_t at91_sysfs_set_mb0_id(struct device *dev, goto out; } - err = strict_strtoul(buf, 0, &can_id); + err = kstrtoul(buf, 0, &can_id); if (err) { ret = err; goto out; @@ -1242,10 +1255,40 @@ static struct attribute_group at91_sysfs_attr_group = { .attrs = at91_sysfs_attrs, }; -static int __devinit at91_can_probe(struct platform_device *pdev) +#if defined(CONFIG_OF) +static const struct of_device_id at91_can_dt_ids[] = { + { + .compatible = "atmel,at91sam9x5-can", + .data = &at91_at91sam9x5_data, + }, { + .compatible = "atmel,at91sam9263-can", + .data = &at91_at91sam9263_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, at91_can_dt_ids); +#endif + +static const struct at91_devtype_data *at91_can_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + + match = of_match_node(at91_can_dt_ids, pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "no matching node found in dtb\n"); + return NULL; + } + return (const struct at91_devtype_data *)match->data; + } + return (const struct at91_devtype_data *) + platform_get_device_id(pdev)->driver_data; +} + +static int at91_can_probe(struct platform_device *pdev) { const struct at91_devtype_data *devtype_data; - enum at91_devtype devtype; struct net_device *dev; struct at91_priv *priv; struct resource *res; @@ -1253,8 +1296,12 @@ static int __devinit at91_can_probe(struct platform_device *pdev) void __iomem *addr; int err, irq; - devtype = pdev->id_entry->driver_data; - devtype_data = &at91_devtype_data[devtype]; + devtype_data = at91_can_get_driver_data(pdev); + if (!devtype_data) { + dev_err(&pdev->dev, "no driver data\n"); + err = -ENODEV; + goto exit; + } clk = clk_get(&pdev->dev, "can_clk"); if (IS_ERR(clk)) { @@ -1299,13 +1346,13 @@ static int __devinit at91_can_probe(struct platform_device *pdev) priv->can.bittiming_const = &at91_bittiming_const; priv->can.do_set_mode = at91_set_mode; priv->can.do_get_berr_counter = at91_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_LISTENONLY; priv->dev = dev; priv->reg_base = addr; priv->devtype_data = *devtype_data; - priv->devtype_data.type = devtype; priv->clk = clk; - priv->pdata = pdev->dev.platform_data; + priv->pdata = dev_get_platdata(&pdev->dev); priv->mb0_id = 0x7ff; netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); @@ -1313,7 +1360,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) if (at91_is_sam9263(priv)) dev->sysfs_groups[0] = &at91_sysfs_attr_group; - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_candev(dev); @@ -1322,6 +1369,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev) goto exit_free; } + devm_can_led_init(dev); + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", priv->reg_base, dev->irq); @@ -1339,7 +1388,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) return err; } -static int __devexit at91_can_remove(struct platform_device *pdev) +static int at91_can_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct at91_priv *priv = netdev_priv(dev); @@ -1347,8 +1396,6 @@ static int __devexit at91_can_remove(struct platform_device *pdev) unregister_netdev(dev); - platform_set_drvdata(pdev, NULL); - iounmap(priv->reg_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1363,22 +1410,24 @@ static int __devexit at91_can_remove(struct platform_device *pdev) static const struct platform_device_id at91_can_id_table[] = { { - .name = "at91_can", - .driver_data = AT91_DEVTYPE_SAM9263, - }, { .name = "at91sam9x5_can", - .driver_data = AT91_DEVTYPE_SAM9X5, + .driver_data = (kernel_ulong_t)&at91_at91sam9x5_data, + }, { + .name = "at91_can", + .driver_data = (kernel_ulong_t)&at91_at91sam9263_data, }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(platform, at91_can_id_table); static struct platform_driver at91_can_driver = { .probe = at91_can_probe, - .remove = __devexit_p(at91_can_remove), + .remove = at91_can_remove, .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_can_dt_ids), }, .id_table = at91_can_id_table, }; diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index f2d6d258a28..543ecceb33e 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -9,7 +9,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/interrupt.h> @@ -412,7 +411,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) return 0; } -irqreturn_t bfin_can_interrupt(int irq, void *dev_id) +static irqreturn_t bfin_can_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct bfin_can_priv *priv = netdev_priv(dev); @@ -504,7 +503,7 @@ static int bfin_can_close(struct net_device *dev) return 0; } -struct net_device *alloc_bfin_candev(void) +static struct net_device *alloc_bfin_candev(void) { struct net_device *dev; struct bfin_can_priv *priv; @@ -529,9 +528,10 @@ static const struct net_device_ops bfin_can_netdev_ops = { .ndo_open = bfin_can_open, .ndo_stop = bfin_can_close, .ndo_start_xmit = bfin_can_start_xmit, + .ndo_change_mtu = can_change_mtu, }; -static int __devinit bfin_can_probe(struct platform_device *pdev) +static int bfin_can_probe(struct platform_device *pdev) { int err; struct net_device *dev; @@ -539,7 +539,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev) struct resource *res_mem, *rx_irq, *tx_irq, *err_irq; unsigned short *pdata; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data provided!\n"); err = -EINVAL; @@ -580,7 +580,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev) priv->pin_list = pdata; priv->can.clock.freq = get_sclk(); - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->flags |= IFF_ECHO; /* we support local echo */ @@ -611,9 +611,9 @@ exit: return err; } -static int __devexit bfin_can_remove(struct platform_device *pdev) +static int bfin_can_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct resource *res; @@ -621,8 +621,6 @@ static int __devexit bfin_can_remove(struct platform_device *pdev) unregister_candev(dev); - dev_set_drvdata(&pdev->dev, NULL); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); @@ -635,7 +633,7 @@ static int __devexit bfin_can_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct bfin_can_regs __iomem *reg = priv->membase; int timeout = BFIN_CAN_TIMEOUT; @@ -658,7 +656,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) static int bfin_can_resume(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct bfin_can_regs __iomem *reg = priv->membase; @@ -677,7 +675,7 @@ static int bfin_can_resume(struct platform_device *pdev) static struct platform_driver bfin_can_driver = { .probe = bfin_can_probe, - .remove = __devexit_p(bfin_can_remove), + .remove = bfin_can_remove, .suspend = bfin_can_suspend, .resume = bfin_can_resume, .driver = { @@ -691,3 +689,4 @@ module_platform_driver(bfin_can_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blackfin on-chip CAN netdevice driver"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig index 3b83bafcd94..61ffc12d8fd 100644 --- a/drivers/net/can/c_can/Kconfig +++ b/drivers/net/can/c_can/Kconfig @@ -1,6 +1,6 @@ menuconfig CAN_C_CAN tristate "Bosch C_CAN/D_CAN devices" - depends on CAN_DEV && HAS_IOMEM + depends on HAS_IOMEM if CAN_C_CAN diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index e5180dfddba..8e78bb48f5a 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -39,6 +39,7 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/can/led.h> #include "c_can.h" @@ -59,6 +60,8 @@ #define CONTROL_IE BIT(1) #define CONTROL_INIT BIT(0) +#define CONTROL_IRQMSK (CONTROL_EIE | CONTROL_IE | CONTROL_SIE) + /* test register */ #define TEST_RX BIT(7) #define TEST_TX1 BIT(6) @@ -107,21 +110,38 @@ #define IF_COMM_CONTROL BIT(4) #define IF_COMM_CLR_INT_PND BIT(3) #define IF_COMM_TXRQST BIT(2) +#define IF_COMM_CLR_NEWDAT IF_COMM_TXRQST #define IF_COMM_DATAA BIT(1) #define IF_COMM_DATAB BIT(0) -#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \ - IF_COMM_CONTROL | IF_COMM_TXRQST | \ - IF_COMM_DATAA | IF_COMM_DATAB) + +/* TX buffer setup */ +#define IF_COMM_TX (IF_COMM_ARB | IF_COMM_CONTROL | \ + IF_COMM_TXRQST | \ + IF_COMM_DATAA | IF_COMM_DATAB) + +/* For the low buffers we clear the interrupt bit, but keep newdat */ +#define IF_COMM_RCV_LOW (IF_COMM_MASK | IF_COMM_ARB | \ + IF_COMM_CONTROL | IF_COMM_CLR_INT_PND | \ + IF_COMM_DATAA | IF_COMM_DATAB) + +/* For the high buffers we clear the interrupt bit and newdat */ +#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT) + + +/* Receive setup of message objects */ +#define IF_COMM_RCV_SETUP (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL) + +/* Invalidation of message objects */ +#define IF_COMM_INVAL (IF_COMM_ARB | IF_COMM_CONTROL) /* IFx arbitration */ -#define IF_ARB_MSGVAL BIT(15) -#define IF_ARB_MSGXTD BIT(14) -#define IF_ARB_TRANSMIT BIT(13) +#define IF_ARB_MSGVAL BIT(31) +#define IF_ARB_MSGXTD BIT(30) +#define IF_ARB_TRANSMIT BIT(29) /* IFx message control */ #define IF_MCONT_NEWDAT BIT(15) #define IF_MCONT_MSGLST BIT(14) -#define IF_MCONT_CLR_MSGLST (0 << 14) #define IF_MCONT_INTPND BIT(13) #define IF_MCONT_UMASK BIT(12) #define IF_MCONT_TXIE BIT(11) @@ -131,39 +151,16 @@ #define IF_MCONT_EOB BIT(7) #define IF_MCONT_DLC_MASK 0xf -/* - * IFx register masks: - * allow easy operation on 16-bit registers when the - * argument is 32-bit instead - */ -#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF) -#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16) - -/* message object split */ -#define C_CAN_NO_OF_OBJECTS 32 -#define C_CAN_MSG_OBJ_RX_NUM 16 -#define C_CAN_MSG_OBJ_TX_NUM 16 - -#define C_CAN_MSG_OBJ_RX_FIRST 1 -#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \ - C_CAN_MSG_OBJ_RX_NUM - 1) - -#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1) -#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \ - C_CAN_MSG_OBJ_TX_NUM - 1) - -#define C_CAN_MSG_OBJ_RX_SPLIT 9 -#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1) - -#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1) -#define RECEIVE_OBJECT_BITS 0x0000ffff +#define IF_MCONT_RCV (IF_MCONT_RXIE | IF_MCONT_UMASK) +#define IF_MCONT_RCV_EOB (IF_MCONT_RCV | IF_MCONT_EOB) -/* status interrupt */ -#define STATUS_INTERRUPT 0x8000 +#define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB) -/* global interrupt masks */ -#define ENABLE_ALL_INTERRUPTS 1 -#define DISABLE_ALL_INTERRUPTS 0 +/* + * Use IF1 for RX and IF2 for TX + */ +#define IF_RX 0 +#define IF_TX 1 /* minimum timeout for checking BUSY status */ #define MIN_TIMEOUT_VALUE 6 @@ -184,6 +181,7 @@ enum c_can_lec_type { LEC_BIT0_ERROR, LEC_CRC_ERROR, LEC_UNUSED, + LEC_MASK = LEC_UNUSED, }; /* @@ -233,210 +231,155 @@ static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv) pm_runtime_put_sync(priv->device); } -static inline int get_tx_next_msg_obj(const struct c_can_priv *priv) -{ - return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) + - C_CAN_MSG_OBJ_TX_FIRST; -} - -static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv) +static inline void c_can_reset_ram(const struct c_can_priv *priv, bool enable) { - return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) + - C_CAN_MSG_OBJ_TX_FIRST; + if (priv->raminit) + priv->raminit(priv, enable); } -static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index) +static void c_can_irq_control(struct c_can_priv *priv, bool enable) { - u32 val = priv->read_reg(priv, index); - val |= ((u32) priv->read_reg(priv, index + 1)) << 16; - return val; -} - -static void c_can_enable_all_interrupts(struct c_can_priv *priv, - int enable) -{ - unsigned int cntrl_save = priv->read_reg(priv, - C_CAN_CTRL_REG); + u32 ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; if (enable) - cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE); - else - cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE); + ctrl |= CONTROL_IRQMSK; - priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save); + priv->write_reg(priv, C_CAN_CTRL_REG, ctrl); } -static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface) +static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj) { - int count = MIN_TIMEOUT_VALUE; + struct c_can_priv *priv = netdev_priv(dev); + int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface); + + priv->write_reg32(priv, reg, (cmd << 16) | obj); - while (count && priv->read_reg(priv, - C_CAN_IFACE(COMREQ_REG, iface)) & - IF_COMR_BUSY) { - count--; + for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) { + if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY)) + return; udelay(1); } + netdev_err(dev, "Updating object timed out\n"); - if (!count) - return 1; +} - return 0; +static inline void c_can_object_get(struct net_device *dev, int iface, + u32 obj, u32 cmd) +{ + c_can_obj_update(dev, iface, cmd, obj); } -static inline void c_can_object_get(struct net_device *dev, - int iface, int objno, int mask) +static inline void c_can_object_put(struct net_device *dev, int iface, + u32 obj, u32 cmd) { - struct c_can_priv *priv = netdev_priv(dev); + c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj); +} - /* - * As per specs, after writting the message object number in the - * IF command request register the transfer b/w interface - * register and message RAM must be complete in 6 CAN-CLK - * period. - */ - priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface), - IFX_WRITE_LOW_16BIT(mask)); - priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface), - IFX_WRITE_LOW_16BIT(objno)); +/* + * Note: According to documentation clearing TXIE while MSGVAL is set + * is not allowed, but works nicely on C/DCAN. And that lowers the I/O + * load significantly. + */ +static void c_can_inval_tx_object(struct net_device *dev, int iface, int obj) +{ + struct c_can_priv *priv = netdev_priv(dev); - if (c_can_msg_obj_is_busy(priv, iface)) - netdev_err(dev, "timed out in object get\n"); + priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0); + c_can_object_put(dev, iface, obj, IF_COMM_INVAL); } -static inline void c_can_object_put(struct net_device *dev, - int iface, int objno, int mask) +static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj) { struct c_can_priv *priv = netdev_priv(dev); - /* - * As per specs, after writting the message object number in the - * IF command request register the transfer b/w interface - * register and message RAM must be complete in 6 CAN-CLK - * period. - */ - priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface), - (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask))); - priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface), - IFX_WRITE_LOW_16BIT(objno)); - - if (c_can_msg_obj_is_busy(priv, iface)) - netdev_err(dev, "timed out in object put\n"); + priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0); + priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0); + c_can_inval_tx_object(dev, iface, obj); } -static void c_can_write_msg_object(struct net_device *dev, - int iface, struct can_frame *frame, int objno) +static void c_can_setup_tx_object(struct net_device *dev, int iface, + struct can_frame *frame, int idx) { - int i; - u16 flags = 0; - unsigned int id; struct c_can_priv *priv = netdev_priv(dev); - - if (!(frame->can_id & CAN_RTR_FLAG)) - flags |= IF_ARB_TRANSMIT; + u16 ctrl = IF_MCONT_TX | frame->can_dlc; + bool rtr = frame->can_id & CAN_RTR_FLAG; + u32 arb = IF_ARB_MSGVAL; + int i; if (frame->can_id & CAN_EFF_FLAG) { - id = frame->can_id & CAN_EFF_MASK; - flags |= IF_ARB_MSGXTD; - } else - id = ((frame->can_id & CAN_SFF_MASK) << 18); + arb |= frame->can_id & CAN_EFF_MASK; + arb |= IF_ARB_MSGXTD; + } else { + arb |= (frame->can_id & CAN_SFF_MASK) << 18; + } - flags |= IF_ARB_MSGVAL; + if (!rtr) + arb |= IF_ARB_TRANSMIT; - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), - IFX_WRITE_LOW_16BIT(id)); - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags | - IFX_WRITE_HIGH_16BIT(id)); + /* + * If we change the DIR bit, we need to invalidate the buffer + * first, i.e. clear the MSGVAL flag in the arbiter. + */ + if (rtr != (bool)test_bit(idx, &priv->tx_dir)) { + u32 obj = idx + C_CAN_MSG_OBJ_TX_FIRST; - for (i = 0; i < frame->can_dlc; i += 2) { - priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2, - frame->data[i] | (frame->data[i + 1] << 8)); + c_can_inval_msg_object(dev, iface, obj); + change_bit(idx, &priv->tx_dir); } - /* enable interrupt for this message object */ - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), - IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB | - frame->can_dlc); - c_can_object_put(dev, iface, objno, IF_COMM_ALL); -} + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), arb); -static inline void c_can_mark_rx_msg_obj(struct net_device *dev, - int iface, int ctrl_mask, - int obj) -{ - struct c_can_priv *priv = netdev_priv(dev); - - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), - ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND)); - c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); + priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); + for (i = 0; i < frame->can_dlc; i += 2) { + priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2, + frame->data[i] | (frame->data[i + 1] << 8)); + } } static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev, - int iface, - int ctrl_mask) + int iface) { int i; - struct c_can_priv *priv = netdev_priv(dev); - for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) { - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), - ctrl_mask & ~(IF_MCONT_MSGLST | - IF_MCONT_INTPND | IF_MCONT_NEWDAT)); - c_can_object_put(dev, iface, i, IF_COMM_CONTROL); - } + for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) + c_can_object_get(dev, iface, i, IF_COMM_CLR_NEWDAT); } -static inline void c_can_activate_rx_msg_obj(struct net_device *dev, - int iface, int ctrl_mask, - int obj) +static int c_can_handle_lost_msg_obj(struct net_device *dev, + int iface, int objno, u32 ctrl) { - struct c_can_priv *priv = netdev_priv(dev); - - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), - ctrl_mask & ~(IF_MCONT_MSGLST | - IF_MCONT_INTPND | IF_MCONT_NEWDAT)); - c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); -} - -static void c_can_handle_lost_msg_obj(struct net_device *dev, - int iface, int objno) -{ - struct c_can_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - struct sk_buff *skb; + struct c_can_priv *priv = netdev_priv(dev); struct can_frame *frame; + struct sk_buff *skb; - netdev_err(dev, "msg lost in buffer %d\n", objno); - - c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); - - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), - IF_MCONT_CLR_MSGLST); + ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT); + priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); + c_can_object_put(dev, iface, objno, IF_COMM_CONTROL); - c_can_object_put(dev, 0, objno, IF_COMM_CONTROL); + stats->rx_errors++; + stats->rx_over_errors++; /* create an error msg */ skb = alloc_can_err_skb(dev, &frame); if (unlikely(!skb)) - return; + return 0; frame->can_id |= CAN_ERR_CRTL; frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - stats->rx_errors++; - stats->rx_over_errors++; netif_receive_skb(skb); + return 1; } -static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) +static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl) { - u16 flags, data; - int i; - unsigned int val; - struct c_can_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - struct sk_buff *skb; + struct c_can_priv *priv = netdev_priv(dev); struct can_frame *frame; + struct sk_buff *skb; + u32 arb, data; skb = alloc_can_skb(dev, &frame); if (!skb) { @@ -446,113 +389,98 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) frame->can_dlc = get_can_dlc(ctrl & 0x0F); - flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface)); - val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) | - (flags << 16); + arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface)); - if (flags & IF_ARB_MSGXTD) - frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG; + if (arb & IF_ARB_MSGXTD) + frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG; else - frame->can_id = (val >> 18) & CAN_SFF_MASK; + frame->can_id = (arb >> 18) & CAN_SFF_MASK; - if (flags & IF_ARB_TRANSMIT) + if (arb & IF_ARB_TRANSMIT) { frame->can_id |= CAN_RTR_FLAG; - else { - for (i = 0; i < frame->can_dlc; i += 2) { - data = priv->read_reg(priv, - C_CAN_IFACE(DATA1_REG, iface) + i / 2); + } else { + int i, dreg = C_CAN_IFACE(DATA1_REG, iface); + + for (i = 0; i < frame->can_dlc; i += 2, dreg ++) { + data = priv->read_reg(priv, dreg); frame->data[i] = data; frame->data[i + 1] = data >> 8; } } - netif_receive_skb(skb); - stats->rx_packets++; stats->rx_bytes += frame->can_dlc; + netif_receive_skb(skb); return 0; } static void c_can_setup_receive_object(struct net_device *dev, int iface, - int objno, unsigned int mask, - unsigned int id, unsigned int mcont) + u32 obj, u32 mask, u32 id, u32 mcont) { struct c_can_priv *priv = netdev_priv(dev); - priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), - IFX_WRITE_LOW_16BIT(mask)); - priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), - IFX_WRITE_HIGH_16BIT(mask)); + mask |= BIT(29); + priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask); - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), - IFX_WRITE_LOW_16BIT(id)); - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), - (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id))); + id |= IF_ARB_MSGVAL; + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont); - c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); - - netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, - c_can_read_reg32(priv, C_CAN_MSGVAL1_REG)); -} - -static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno) -{ - struct c_can_priv *priv = netdev_priv(dev); - - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0); - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0); - priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0); - - c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL); - - netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, - c_can_read_reg32(priv, C_CAN_MSGVAL1_REG)); -} - -static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno) -{ - int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG); - - /* - * as transmission request register's bit n-1 corresponds to - * message object n, we need to handle the same properly. - */ - if (val & (1 << (objno - 1))) - return 1; - - return 0; + c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP); } static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, - struct net_device *dev) + struct net_device *dev) { - u32 msg_obj_no; - struct c_can_priv *priv = netdev_priv(dev); struct can_frame *frame = (struct can_frame *)skb->data; + struct c_can_priv *priv = netdev_priv(dev); + u32 idx, obj; if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; - - msg_obj_no = get_tx_next_msg_obj(priv); - - /* prepare message object for transmission */ - c_can_write_msg_object(dev, 0, frame, msg_obj_no); - can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); - /* - * we have to stop the queue in case of a wrap around or - * if the next TX message object is still in use + * This is not a FIFO. C/D_CAN sends out the buffers + * prioritized. The lowest buffer number wins. */ - priv->tx_next++; - if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) || - (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0) + idx = fls(atomic_read(&priv->tx_active)); + obj = idx + C_CAN_MSG_OBJ_TX_FIRST; + + /* If this is the last buffer, stop the xmit queue */ + if (idx == C_CAN_MSG_OBJ_TX_NUM - 1) netif_stop_queue(dev); + /* + * Store the message in the interface so we can call + * can_put_echo_skb(). We must do this before we enable + * transmit as we might race against do_tx(). + */ + c_can_setup_tx_object(dev, IF_TX, frame, idx); + priv->dlc[idx] = frame->can_dlc; + can_put_echo_skb(skb, dev, idx); + + /* Update the active bits */ + atomic_add((1 << idx), &priv->tx_active); + /* Start transmission */ + c_can_object_put(dev, IF_TX, obj, IF_COMM_TX); return NETDEV_TX_OK; } +static int c_can_wait_for_ctrl_init(struct net_device *dev, + struct c_can_priv *priv, u32 init) +{ + int retry = 0; + + while (init != (priv->read_reg(priv, C_CAN_CTRL_REG) & CONTROL_INIT)) { + udelay(10); + if (retry++ > 1000) { + netdev_err(dev, "CCTRL: set CONTROL_INIT failed\n"); + return -EIO; + } + } + return 0; +} + static int c_can_set_bittiming(struct net_device *dev) { unsigned int reg_btr, reg_brpe, ctrl_save; @@ -560,6 +488,7 @@ static int c_can_set_bittiming(struct net_device *dev) u32 ten_bit_brp; struct c_can_priv *priv = netdev_priv(dev); const struct can_bittiming *bt = &priv->can.bittiming; + int res; /* c_can provides a 6-bit brp and 4-bit brpe fields */ ten_bit_brp = bt->brp - 1; @@ -577,13 +506,17 @@ static int c_can_set_bittiming(struct net_device *dev) "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe); ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG); - priv->write_reg(priv, C_CAN_CTRL_REG, - ctrl_save | CONTROL_CCE | CONTROL_INIT); + ctrl_save &= ~CONTROL_INIT; + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT); + res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT); + if (res) + return res; + priv->write_reg(priv, C_CAN_BTR_REG, reg_btr); priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe); priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save); - return 0; + return c_can_wait_for_ctrl_init(dev, priv, 0); } /* @@ -601,15 +534,14 @@ static void c_can_configure_msg_objects(struct net_device *dev) /* first invalidate all message objects */ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++) - c_can_inval_msg_object(dev, 0, i); + c_can_inval_msg_object(dev, IF_RX, i); /* setup receive message objects */ for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++) - c_can_setup_receive_object(dev, 0, i, 0, 0, - (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB); + c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV); - c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0, - IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK); + c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0, + IF_MCONT_RCV_EOB); } /* @@ -618,35 +550,27 @@ static void c_can_configure_msg_objects(struct net_device *dev) * - set operating mode * - configure message objects */ -static void c_can_chip_config(struct net_device *dev) +static int c_can_chip_config(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); /* enable automatic retransmission */ - priv->write_reg(priv, C_CAN_CTRL_REG, - CONTROL_ENABLE_AR); + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR); if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) && (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) { /* loopback + silent mode : useful for hot self-test */ - priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | - CONTROL_SIE | CONTROL_IE | CONTROL_TEST); - priv->write_reg(priv, C_CAN_TEST_REG, - TEST_LBACK | TEST_SILENT); + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST); + priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT); } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { /* loopback mode : useful for self-test function */ - priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | - CONTROL_SIE | CONTROL_IE | CONTROL_TEST); + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST); priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK); } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { /* silent mode : bus-monitoring mode */ - priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | - CONTROL_SIE | CONTROL_IE | CONTROL_TEST); + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST); priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT); - } else - /* normal mode*/ - priv->write_reg(priv, C_CAN_CTRL_REG, - CONTROL_EIE | CONTROL_SIE | CONTROL_IE); + } /* configure message objects */ c_can_configure_msg_objects(dev); @@ -654,43 +578,54 @@ static void c_can_chip_config(struct net_device *dev) /* set a `lec` value so that we can check for updates later */ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); + /* Clear all internal status */ + atomic_set(&priv->tx_active, 0); + priv->rxmasked = 0; + priv->tx_dir = 0; + /* set bittiming params */ - c_can_set_bittiming(dev); + return c_can_set_bittiming(dev); } -static void c_can_start(struct net_device *dev) +static int c_can_start(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); + int err; /* basic c_can configuration */ - c_can_chip_config(dev); + err = c_can_chip_config(dev); + if (err) + return err; - priv->can.state = CAN_STATE_ERROR_ACTIVE; + /* Setup the command for new messages */ + priv->comm_rcv_high = priv->type != BOSCH_D_CAN ? + IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH; - /* reset tx helper pointers */ - priv->tx_next = priv->tx_echo = 0; + priv->can.state = CAN_STATE_ERROR_ACTIVE; - /* enable status change, error and module interrupts */ - c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); + return 0; } static void c_can_stop(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); - /* disable all interrupts */ - c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); - - /* set the state as STOPPED */ + c_can_irq_control(priv, false); priv->can.state = CAN_STATE_STOPPED; } static int c_can_set_mode(struct net_device *dev, enum can_mode mode) { + struct c_can_priv *priv = netdev_priv(dev); + int err; + switch (mode) { case CAN_MODE_START: - c_can_start(dev); + err = c_can_start(dev); + if (err) + return err; netif_wake_queue(dev); + c_can_irq_control(priv, true); break; default: return -EOPNOTSUPP; @@ -699,62 +634,153 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode) return 0; } -static int c_can_get_berr_counter(const struct net_device *dev, - struct can_berr_counter *bec) +static int __c_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) { unsigned int reg_err_counter; struct c_can_priv *priv = netdev_priv(dev); - c_can_pm_runtime_get_sync(priv); - reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG); bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >> ERR_CNT_REC_SHIFT; bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK; + return 0; +} + +static int c_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct c_can_priv *priv = netdev_priv(dev); + int err; + + c_can_pm_runtime_get_sync(priv); + err = __c_can_get_berr_counter(dev, bec); c_can_pm_runtime_put_sync(priv); - return 0; + return err; } -/* - * theory of operation: - * - * priv->tx_echo holds the number of the oldest can_frame put for - * transmission into the hardware, but not yet ACKed by the CAN tx - * complete IRQ. - * - * We iterate from priv->tx_echo to priv->tx_next and check if the - * packet has been transmitted, echo it back to the CAN framework. - * If we discover a not yet transmitted packet, stop looking for more. - */ static void c_can_do_tx(struct net_device *dev) { - u32 val; - u32 msg_obj_no; struct c_can_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; + u32 idx, obj, pkts = 0, bytes = 0, pend, clr; + + clr = pend = priv->read_reg(priv, C_CAN_INTPND2_REG); + + while ((idx = ffs(pend))) { + idx--; + pend &= ~(1 << idx); + obj = idx + C_CAN_MSG_OBJ_TX_FIRST; + c_can_inval_tx_object(dev, IF_RX, obj); + can_get_echo_skb(dev, idx); + bytes += priv->dlc[idx]; + pkts++; + } - for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { - msg_obj_no = get_tx_echo_msg_obj(priv); - val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG); - if (!(val & (1 << (msg_obj_no - 1)))) { - can_get_echo_skb(dev, - msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); - stats->tx_bytes += priv->read_reg(priv, - C_CAN_IFACE(MSGCTRL_REG, 0)) - & IF_MCONT_DLC_MASK; - stats->tx_packets++; - c_can_inval_msg_object(dev, 0, msg_obj_no); - } else { - break; + /* Clear the bits in the tx_active mask */ + atomic_sub(clr, &priv->tx_active); + + if (clr & (1 << (C_CAN_MSG_OBJ_TX_NUM - 1))) + netif_wake_queue(dev); + + if (pkts) { + stats->tx_bytes += bytes; + stats->tx_packets += pkts; + can_led_event(dev, CAN_LED_EVENT_TX); + } +} + +/* + * If we have a gap in the pending bits, that means we either + * raced with the hardware or failed to readout all upper + * objects in the last run due to quota limit. + */ +static u32 c_can_adjust_pending(u32 pend) +{ + u32 weight, lasts; + + if (pend == RECEIVE_OBJECT_BITS) + return pend; + + /* + * If the last set bit is larger than the number of pending + * bits we have a gap. + */ + weight = hweight32(pend); + lasts = fls(pend); + + /* If the bits are linear, nothing to do */ + if (lasts == weight) + return pend; + + /* + * Find the first set bit after the gap. We walk backwards + * from the last set bit. + */ + for (lasts--; pend & (1 << (lasts - 1)); lasts--); + + return pend & ~((1 << lasts) - 1); +} + +static inline void c_can_rx_object_get(struct net_device *dev, + struct c_can_priv *priv, u32 obj) +{ + c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high); +} + +static inline void c_can_rx_finalize(struct net_device *dev, + struct c_can_priv *priv, u32 obj) +{ + if (priv->type != BOSCH_D_CAN) + c_can_object_get(dev, IF_RX, obj, IF_COMM_CLR_NEWDAT); +} + +static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, + u32 pend, int quota) +{ + u32 pkts = 0, ctrl, obj; + + while ((obj = ffs(pend)) && quota > 0) { + pend &= ~BIT(obj - 1); + + c_can_rx_object_get(dev, priv, obj); + ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX)); + + if (ctrl & IF_MCONT_MSGLST) { + int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl); + + pkts += n; + quota -= n; + continue; } + + /* + * This really should not happen, but this covers some + * odd HW behaviour. Do not remove that unless you + * want to brick your machine. + */ + if (!(ctrl & IF_MCONT_NEWDAT)) + continue; + + /* read the data from the message object */ + c_can_read_msg_object(dev, IF_RX, ctrl); + + c_can_rx_finalize(dev, priv, obj); + + pkts++; + quota--; } - /* restart queue if wrap-up or if queue stalled on last pkt */ - if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) || - ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0)) - netif_wake_queue(dev); + return pkts; +} + +static inline u32 c_can_get_pending(struct c_can_priv *priv) +{ + u32 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG); + + return pend; } /* @@ -766,80 +792,47 @@ static void c_can_do_tx(struct net_device *dev) * has arrived. To work-around this issue, we keep two groups of message * objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT. * - * To ensure in-order frame reception we use the following - * approach while re-activating a message object to receive further - * frames: - * - if the current message object number is lower than - * C_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing - * the INTPND bit. - * - if the current message object number is equal to - * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower - * receive message objects. - * - if the current message object number is greater than - * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of - * only this message object. + * We clear the newdat bit right away. + * + * This can result in packet reordering when the readout is slow. */ static int c_can_do_rx_poll(struct net_device *dev, int quota) { - u32 num_rx_pkts = 0; - unsigned int msg_obj, msg_ctrl_save; struct c_can_priv *priv = netdev_priv(dev); - u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG); + u32 pkts = 0, pend = 0, toread, n; - for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST; - msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0; - val = c_can_read_reg32(priv, C_CAN_INTPND1_REG), - msg_obj++) { - /* - * as interrupt pending register's bit n-1 corresponds to - * message object n, we need to handle the same properly. - */ - if (val & (1 << (msg_obj - 1))) { - c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL & - ~IF_COMM_TXRQST); - msg_ctrl_save = priv->read_reg(priv, - C_CAN_IFACE(MSGCTRL_REG, 0)); - - if (msg_ctrl_save & IF_MCONT_EOB) - return num_rx_pkts; - - if (msg_ctrl_save & IF_MCONT_MSGLST) { - c_can_handle_lost_msg_obj(dev, 0, msg_obj); - num_rx_pkts++; - quota--; - continue; - } - - if (!(msg_ctrl_save & IF_MCONT_NEWDAT)) - continue; - - /* read the data from the message object */ - c_can_read_msg_object(dev, 0, msg_ctrl_save); - - if (msg_obj < C_CAN_MSG_RX_LOW_LAST) - c_can_mark_rx_msg_obj(dev, 0, - msg_ctrl_save, msg_obj); - else if (msg_obj > C_CAN_MSG_RX_LOW_LAST) - /* activate this msg obj */ - c_can_activate_rx_msg_obj(dev, 0, - msg_ctrl_save, msg_obj); - else if (msg_obj == C_CAN_MSG_RX_LOW_LAST) - /* activate all lower message objects */ - c_can_activate_all_lower_rx_msg_obj(dev, - 0, msg_ctrl_save); - - num_rx_pkts++; - quota--; + /* + * It is faster to read only one 16bit register. This is only possible + * for a maximum number of 16 objects. + */ + BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16, + "Implementation does not support more message objects than 16"); + + while (quota > 0) { + if (!pend) { + pend = c_can_get_pending(priv); + if (!pend) + break; + /* + * If the pending field has a gap, handle the + * bits above the gap first. + */ + toread = c_can_adjust_pending(pend); + } else { + toread = pend; } + /* Remove the bits from pend */ + pend &= ~toread; + /* Read the objects */ + n = c_can_read_objects(dev, priv, toread, quota); + pkts += n; + quota -= n; } - return num_rx_pkts; -} + if (pkts) + can_led_event(dev, CAN_LED_EVENT_RX); -static inline int c_can_has_and_handle_berr(struct c_can_priv *priv) -{ - return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && - (priv->current_status & LEC_UNUSED); + return pkts; } static int c_can_handle_state_change(struct net_device *dev, @@ -853,12 +846,32 @@ static int c_can_handle_state_change(struct net_device *dev, struct sk_buff *skb; struct can_berr_counter bec; + switch (error_type) { + case C_CAN_ERROR_WARNING: + /* error warning state */ + priv->can.can_stats.error_warning++; + priv->can.state = CAN_STATE_ERROR_WARNING; + break; + case C_CAN_ERROR_PASSIVE: + /* error passive state */ + priv->can.can_stats.error_passive++; + priv->can.state = CAN_STATE_ERROR_PASSIVE; + break; + case C_CAN_BUS_OFF: + /* bus-off state */ + priv->can.state = CAN_STATE_BUS_OFF; + can_bus_off(dev); + break; + default: + break; + } + /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) return 0; - c_can_get_berr_counter(dev, &bec); + __c_can_get_berr_counter(dev, &bec); reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG); rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >> ERR_CNT_RP_SHIFT; @@ -866,8 +879,6 @@ static int c_can_handle_state_change(struct net_device *dev, switch (error_type) { case C_CAN_ERROR_WARNING: /* error warning state */ - priv->can.can_stats.error_warning++; - priv->can.state = CAN_STATE_ERROR_WARNING; cf->can_id |= CAN_ERR_CRTL; cf->data[1] = (bec.txerr > bec.rxerr) ? CAN_ERR_CRTL_TX_WARNING : @@ -878,8 +889,6 @@ static int c_can_handle_state_change(struct net_device *dev, break; case C_CAN_ERROR_PASSIVE: /* error passive state */ - priv->can.can_stats.error_passive++; - priv->can.state = CAN_STATE_ERROR_PASSIVE; cf->can_id |= CAN_ERR_CRTL; if (rx_err_passive) cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; @@ -891,22 +900,16 @@ static int c_can_handle_state_change(struct net_device *dev, break; case C_CAN_BUS_OFF: /* bus-off state */ - priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; - /* - * disable all interrupts in bus-off mode to ensure that - * the CPU is not hogged down - */ - c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); can_bus_off(dev); break; default: break; } - netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); return 1; } @@ -927,6 +930,13 @@ static int c_can_handle_bus_err(struct net_device *dev, if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR) return 0; + if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) + return 0; + + /* common for all type of bus errors */ + priv->can.can_stats.bus_error++; + stats->rx_errors++; + /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) @@ -936,10 +946,6 @@ static int c_can_handle_bus_err(struct net_device *dev, * check for 'last error code' which tells us the * type of the last error to occur on the CAN bus */ - - /* common for all type of bus errors */ - priv->can.can_stats.bus_error++; - stats->rx_errors++; cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; cf->data[2] |= CAN_ERR_PROT_UNSPEC; @@ -954,7 +960,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[2] |= (CAN_ERR_PROT_LOC_ACK | + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | CAN_ERR_PROT_LOC_ACK_DEL); break; case LEC_BIT1_ERROR: @@ -967,102 +973,71 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL); break; default: break; } - /* set a `lec` value so that we can check for updates later */ - priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); - - netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; - + netif_receive_skb(skb); return 1; } static int c_can_poll(struct napi_struct *napi, int quota) { - u16 irqstatus; - int lec_type = 0; - int work_done = 0; struct net_device *dev = napi->dev; struct c_can_priv *priv = netdev_priv(dev); + u16 curr, last = priv->last_status; + int work_done = 0; - irqstatus = priv->irqstatus; - if (!irqstatus) - goto end; + priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); + /* Ack status on C_CAN. D_CAN is self clearing */ + if (priv->type != BOSCH_D_CAN) + priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); - /* status events have the highest priority */ - if (irqstatus == STATUS_INTERRUPT) { - priv->current_status = priv->read_reg(priv, - C_CAN_STS_REG); - - /* handle Tx/Rx events */ - if (priv->current_status & STATUS_TXOK) - priv->write_reg(priv, C_CAN_STS_REG, - priv->current_status & ~STATUS_TXOK); - - if (priv->current_status & STATUS_RXOK) - priv->write_reg(priv, C_CAN_STS_REG, - priv->current_status & ~STATUS_RXOK); - - /* handle state changes */ - if ((priv->current_status & STATUS_EWARN) && - (!(priv->last_status & STATUS_EWARN))) { - netdev_dbg(dev, "entered error warning state\n"); - work_done += c_can_handle_state_change(dev, - C_CAN_ERROR_WARNING); - } - if ((priv->current_status & STATUS_EPASS) && - (!(priv->last_status & STATUS_EPASS))) { - netdev_dbg(dev, "entered error passive state\n"); - work_done += c_can_handle_state_change(dev, - C_CAN_ERROR_PASSIVE); - } - if ((priv->current_status & STATUS_BOFF) && - (!(priv->last_status & STATUS_BOFF))) { - netdev_dbg(dev, "entered bus off state\n"); - work_done += c_can_handle_state_change(dev, - C_CAN_BUS_OFF); - } + /* handle state changes */ + if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) { + netdev_dbg(dev, "entered error warning state\n"); + work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING); + } - /* handle bus recovery events */ - if ((!(priv->current_status & STATUS_BOFF)) && - (priv->last_status & STATUS_BOFF)) { - netdev_dbg(dev, "left bus off state\n"); - priv->can.state = CAN_STATE_ERROR_ACTIVE; - } - if ((!(priv->current_status & STATUS_EPASS)) && - (priv->last_status & STATUS_EPASS)) { - netdev_dbg(dev, "left error passive state\n"); - priv->can.state = CAN_STATE_ERROR_ACTIVE; - } + if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) { + netdev_dbg(dev, "entered error passive state\n"); + work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE); + } - priv->last_status = priv->current_status; - - /* handle lec errors on the bus */ - lec_type = c_can_has_and_handle_berr(priv); - if (lec_type) - work_done += c_can_handle_bus_err(dev, lec_type); - } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) && - (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) { - /* handle events corresponding to receive message objects */ - work_done += c_can_do_rx_poll(dev, (quota - work_done)); - } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) && - (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) { - /* handle events corresponding to transmit message objects */ - c_can_do_tx(dev); + if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) { + netdev_dbg(dev, "entered bus off state\n"); + work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF); + goto end; } + /* handle bus recovery events */ + if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) { + netdev_dbg(dev, "left bus off state\n"); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } + if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) { + netdev_dbg(dev, "left error passive state\n"); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } + + /* handle lec errors on the bus */ + work_done += c_can_handle_bus_err(dev, curr & LEC_MASK); + + /* Handle Tx/Rx events. We do this unconditionally */ + work_done += c_can_do_rx_poll(dev, (quota - work_done)); + c_can_do_tx(dev); + end: if (work_done < quota) { napi_complete(napi); - /* enable all IRQs */ - c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); + /* enable all IRQs if we are not in bus off state */ + if (priv->can.state != CAN_STATE_BUS_OFF) + c_can_irq_control(priv, true); } return work_done; @@ -1073,12 +1048,11 @@ static irqreturn_t c_can_isr(int irq, void *dev_id) struct net_device *dev = (struct net_device *)dev_id; struct c_can_priv *priv = netdev_priv(dev); - priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG); - if (!priv->irqstatus) + if (!priv->read_reg(priv, C_CAN_INT_REG)) return IRQ_NONE; /* disable all interrupts and schedule the NAPI */ - c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); + c_can_irq_control(priv, false); napi_schedule(&priv->napi); return IRQ_HANDLED; @@ -1090,6 +1064,7 @@ static int c_can_open(struct net_device *dev) struct c_can_priv *priv = netdev_priv(dev); c_can_pm_runtime_get_sync(priv); + c_can_reset_ram(priv, true); /* open the can device */ err = open_candev(dev); @@ -1106,18 +1081,26 @@ static int c_can_open(struct net_device *dev) goto exit_irq_fail; } - napi_enable(&priv->napi); - /* start the c_can controller */ - c_can_start(dev); + err = c_can_start(dev); + if (err) + goto exit_start_fail; + can_led_event(dev, CAN_LED_EVENT_OPEN); + + napi_enable(&priv->napi); + /* enable status change, error and module interrupts */ + c_can_irq_control(priv, true); netif_start_queue(dev); return 0; +exit_start_fail: + free_irq(dev->irq, dev); exit_irq_fail: close_candev(dev); exit_open_fail: + c_can_reset_ram(priv, false); c_can_pm_runtime_put_sync(priv); return err; } @@ -1131,8 +1114,12 @@ static int c_can_close(struct net_device *dev) c_can_stop(dev); free_irq(dev->irq, dev); close_candev(dev); + + c_can_reset_ram(priv, false); c_can_pm_runtime_put_sync(priv); + can_led_event(dev, CAN_LED_EVENT_STOP); + return 0; } @@ -1188,6 +1175,7 @@ int c_can_power_down(struct net_device *dev) c_can_stop(dev); + c_can_reset_ram(priv, false); c_can_pm_runtime_put_sync(priv); return 0; @@ -1199,6 +1187,7 @@ int c_can_power_up(struct net_device *dev) u32 val; unsigned long time_out; struct c_can_priv *priv = netdev_priv(dev); + int ret; if (!(dev->flags & IFF_UP)) return 0; @@ -1206,6 +1195,7 @@ int c_can_power_up(struct net_device *dev) WARN_ON(priv->type != BOSCH_D_CAN); c_can_pm_runtime_get_sync(priv); + c_can_reset_ram(priv, true); /* Clear PDR and INIT bits */ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG); @@ -1224,15 +1214,20 @@ int c_can_power_up(struct net_device *dev) if (time_after(jiffies, time_out)) return -ETIMEDOUT; - c_can_start(dev); + ret = c_can_start(dev); + if (!ret) + c_can_irq_control(priv, true); - return 0; + return ret; } EXPORT_SYMBOL_GPL(c_can_power_up); #endif void free_c_can_dev(struct net_device *dev) { + struct c_can_priv *priv = netdev_priv(dev); + + netif_napi_del(&priv->napi); free_candev(dev); } EXPORT_SYMBOL_GPL(free_c_can_dev); @@ -1241,6 +1236,7 @@ static const struct net_device_ops c_can_netdev_ops = { .ndo_open = c_can_open, .ndo_stop = c_can_close, .ndo_start_xmit = c_can_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_c_can_dev(struct net_device *dev) @@ -1256,6 +1252,8 @@ int register_c_can_dev(struct net_device *dev) err = register_candev(dev); if (err) c_can_pm_runtime_disable(priv); + else + devm_can_led_init(dev); return err; } diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index e5ed41dafa1..99ad1aa576b 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -22,6 +22,23 @@ #ifndef C_CAN_H #define C_CAN_H +/* message object split */ +#define C_CAN_NO_OF_OBJECTS 32 +#define C_CAN_MSG_OBJ_RX_NUM 16 +#define C_CAN_MSG_OBJ_TX_NUM 16 + +#define C_CAN_MSG_OBJ_RX_FIRST 1 +#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \ + C_CAN_MSG_OBJ_RX_NUM - 1) + +#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1) +#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \ + C_CAN_MSG_OBJ_TX_NUM - 1) + +#define C_CAN_MSG_OBJ_RX_SPLIT 9 +#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1) +#define RECEIVE_OBJECT_BITS 0x0000ffff + enum reg { C_CAN_CTRL_REG = 0, C_CAN_CTRL_EX_REG, @@ -61,6 +78,7 @@ enum reg { C_CAN_INTPND2_REG, C_CAN_MSGVAL1_REG, C_CAN_MSGVAL2_REG, + C_CAN_FUNCTION_REG, }; static const u16 reg_map_c_can[] = { @@ -112,6 +130,7 @@ static const u16 reg_map_d_can[] = { [C_CAN_BRPEXT_REG] = 0x0E, [C_CAN_INT_REG] = 0x10, [C_CAN_TEST_REG] = 0x14, + [C_CAN_FUNCTION_REG] = 0x18, [C_CAN_TXRQST1_REG] = 0x88, [C_CAN_TXRQST2_REG] = 0x8A, [C_CAN_NEWDAT1_REG] = 0x9C, @@ -156,19 +175,23 @@ struct c_can_priv { struct napi_struct napi; struct net_device *dev; struct device *device; - int tx_object; - int current_status; + atomic_t tx_active; + unsigned long tx_dir; int last_status; - u16 (*read_reg) (struct c_can_priv *priv, enum reg index); - void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val); + u16 (*read_reg) (const struct c_can_priv *priv, enum reg index); + void (*write_reg) (const struct c_can_priv *priv, enum reg index, u16 val); + u32 (*read_reg32) (const struct c_can_priv *priv, enum reg index); + void (*write_reg32) (const struct c_can_priv *priv, enum reg index, u32 val); void __iomem *base; const u16 *regs; - unsigned long irq_flags; /* for request_irq() */ - unsigned int tx_next; - unsigned int tx_echo; void *priv; /* for board-specific data */ - u16 irqstatus; enum c_can_dev_id type; + u32 __iomem *raminit_ctrlreg; + int instance; + void (*raminit) (const struct c_can_priv *priv, bool enable); + u32 comm_rcv_high; + u32 rxmasked; + u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; }; struct net_device *alloc_c_can_dev(void); diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c index 3d7830bcd2b..5d11e0e4225 100644 --- a/drivers/net/can/c_can/c_can_pci.c +++ b/drivers/net/can/c_can/c_can_pci.c @@ -19,9 +19,13 @@ #include "c_can.h" +#define PCI_DEVICE_ID_PCH_CAN 0x8818 +#define PCH_PCI_SOFT_RESET 0x01fc + enum c_can_pci_reg_align { C_CAN_REG_ALIGN_16, C_CAN_REG_ALIGN_32, + C_CAN_REG_32, }; struct c_can_pci_data { @@ -31,6 +35,10 @@ struct c_can_pci_data { enum c_can_pci_reg_align reg_align; /* Set the frequency */ unsigned int freq; + /* PCI bar number */ + int bar; + /* Callback for reset */ + void (*init)(const struct c_can_priv *priv, bool enable); }; /* @@ -39,32 +47,72 @@ struct c_can_pci_data { * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * Handle the same by providing a common read/write interface. */ -static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv, +static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv, enum reg index) { return readw(priv->base + priv->regs[index]); } -static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv, +static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv, enum reg index, u16 val) { writew(val, priv->base + priv->regs[index]); } -static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv, +static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv, enum reg index) { return readw(priv->base + 2 * priv->regs[index]); } -static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv, +static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv, enum reg index, u16 val) { writew(val, priv->base + 2 * priv->regs[index]); } -static int __devinit c_can_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static u16 c_can_pci_read_reg_32bit(const struct c_can_priv *priv, + enum reg index) +{ + return (u16)ioread32(priv->base + 2 * priv->regs[index]); +} + +static void c_can_pci_write_reg_32bit(const struct c_can_priv *priv, + enum reg index, u16 val) +{ + iowrite32((u32)val, priv->base + 2 * priv->regs[index]); +} + +static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index) +{ + u32 val; + + val = priv->read_reg(priv, index); + val |= ((u32) priv->read_reg(priv, index + 1)) << 16; + + return val; +} + +static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index, + u32 val) +{ + priv->write_reg(priv, index + 1, val >> 16); + priv->write_reg(priv, index, val); +} + +static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable) +{ + if (enable) { + u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET; + + /* write to sw reset register */ + iowrite32(1, addr); + iowrite32(0, addr); + } +} + +static int c_can_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data; struct c_can_priv *priv; @@ -84,10 +132,14 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev, goto out_disable_device; } - pci_set_master(pdev); - pci_enable_msi(pdev); + ret = pci_enable_msi(pdev); + if (!ret) { + dev_info(&pdev->dev, "MSI enabled\n"); + pci_set_master(pdev); + } - addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + addr = pci_iomap(pdev, c_can_pci_data->bar, + pci_resource_len(pdev, c_can_pci_data->bar)); if (!addr) { dev_err(&pdev->dev, "device has no PCI memory resources, " @@ -132,6 +184,8 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev, goto out_free_c_can; } + priv->type = c_can_pci_data->type; + /* Configure access to registers */ switch (c_can_pci_data->reg_align) { case C_CAN_REG_ALIGN_32: @@ -142,10 +196,18 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev, priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; break; + case C_CAN_REG_32: + priv->read_reg = c_can_pci_read_reg_32bit; + priv->write_reg = c_can_pci_write_reg_32bit; + break; default: ret = -EINVAL; goto out_free_c_can; } + priv->read_reg32 = c_can_pci_read_reg32; + priv->write_reg32 = c_can_pci_write_reg32; + + priv->raminit = c_can_pci_data->init; ret = register_c_can_dev(dev); if (ret) { @@ -160,7 +222,6 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev, return 0; out_free_c_can: - pci_set_drvdata(pdev, NULL); free_c_can_dev(dev); out_iounmap: pci_iounmap(pdev, addr); @@ -174,14 +235,13 @@ out: return ret; } -static void __devexit c_can_pci_remove(struct pci_dev *pdev) +static void c_can_pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct c_can_priv *priv = netdev_priv(dev); unregister_c_can_dev(dev); - pci_set_drvdata(pdev, NULL); free_c_can_dev(dev); pci_iounmap(pdev, priv->base); @@ -195,6 +255,15 @@ static struct c_can_pci_data c_can_sta2x11= { .type = BOSCH_C_CAN, .reg_align = C_CAN_REG_ALIGN_32, .freq = 52000000, /* 52 Mhz */ + .bar = 0, +}; + +static struct c_can_pci_data c_can_pch = { + .type = BOSCH_C_CAN, + .reg_align = C_CAN_REG_32, + .freq = 50000000, /* 50 MHz */ + .init = c_can_pci_reset_pch, + .bar = 1, }; #define C_CAN_ID(_vend, _dev, _driverdata) { \ @@ -204,13 +273,15 @@ static struct c_can_pci_data c_can_sta2x11= { static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, c_can_sta2x11), + C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN, + c_can_pch), {}, }; static struct pci_driver c_can_pci_driver = { .name = KBUILD_MODNAME, .id_table = c_can_pci_tbl, .probe = c_can_pci_probe, - .remove = __devexit_p(c_can_pci_remove), + .remove = c_can_pci_remove, }; module_pci_driver(c_can_pci_driver); diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index ee1416132ab..12430be6448 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -32,42 +32,133 @@ #include <linux/clk.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/pinctrl/consumer.h> #include <linux/can/dev.h> #include "c_can.h" +#define CAN_RAMINIT_START_MASK(i) (0x001 << (i)) +#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i)) +#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i)) +#define DCAN_RAM_INIT_BIT (1 << 3) +static DEFINE_SPINLOCK(raminit_lock); /* * 16-bit c_can registers can be arranged differently in the memory * architecture of different implementations. For example: 16-bit * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * Handle the same by providing a common read/write interface. */ -static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv, +static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv, enum reg index) { return readw(priv->base + priv->regs[index]); } -static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv, +static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv, enum reg index, u16 val) { writew(val, priv->base + priv->regs[index]); } -static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv, +static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv, enum reg index) { return readw(priv->base + 2 * priv->regs[index]); } -static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv, +static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv, enum reg index, u16 val) { writew(val, priv->base + 2 * priv->regs[index]); } +static void c_can_hw_raminit_wait_ti(const struct c_can_priv *priv, u32 mask, + u32 val) +{ + /* We look only at the bits of our instance. */ + val &= mask; + while ((readl(priv->raminit_ctrlreg) & mask) != val) + udelay(1); +} + +static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable) +{ + u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance); + u32 ctrl; + + spin_lock(&raminit_lock); + + ctrl = readl(priv->raminit_ctrlreg); + /* We clear the done and start bit first. The start bit is + * looking at the 0 -> transition, but is not self clearing; + * And we clear the init done bit as well. + */ + ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance); + ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); + writel(ctrl, priv->raminit_ctrlreg); + ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance); + c_can_hw_raminit_wait_ti(priv, ctrl, mask); + + if (enable) { + /* Set start bit and wait for the done bit. */ + ctrl |= CAN_RAMINIT_START_MASK(priv->instance); + writel(ctrl, priv->raminit_ctrlreg); + ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance); + c_can_hw_raminit_wait_ti(priv, ctrl, mask); + } + spin_unlock(&raminit_lock); +} + +static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index) +{ + u32 val; + + val = priv->read_reg(priv, index); + val |= ((u32) priv->read_reg(priv, index + 1)) << 16; + + return val; +} + +static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, + u32 val) +{ + priv->write_reg(priv, index + 1, val >> 16); + priv->write_reg(priv, index, val); +} + +static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index) +{ + return readl(priv->base + priv->regs[index]); +} + +static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, + u32 val) +{ + writel(val, priv->base + priv->regs[index]); +} + +static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask) +{ + while (priv->read_reg32(priv, C_CAN_FUNCTION_REG) & mask) + udelay(1); +} + +static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) +{ + u32 ctrl; + + ctrl = priv->read_reg32(priv, C_CAN_FUNCTION_REG); + ctrl &= ~DCAN_RAM_INIT_BIT; + priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl); + c_can_hw_raminit_wait(priv, ctrl); + + if (enable) { + ctrl |= DCAN_RAM_INIT_BIT; + priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl); + c_can_hw_raminit_wait(priv, ctrl); + } +} + static struct platform_device_id c_can_id_table[] = { [BOSCH_C_CAN_PLATFORM] = { .name = KBUILD_MODNAME, @@ -83,14 +174,16 @@ static struct platform_device_id c_can_id_table[] = { }, { } }; +MODULE_DEVICE_TABLE(platform, c_can_id_table); static const struct of_device_id c_can_of_table[] = { { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] }, { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, c_can_of_table); -static int __devinit c_can_plat_probe(struct platform_device *pdev) +static int c_can_plat_probe(struct platform_device *pdev) { int ret; void __iomem *addr; @@ -98,8 +191,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) struct c_can_priv *priv; const struct of_device_id *match; const struct platform_device_id *id; - struct pinctrl *pinctrl; - struct resource *mem; + struct resource *mem, *res; int irq; struct clk *clk; @@ -115,11 +207,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) id = platform_get_device_id(pdev); } - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, - "failed to configure pins from driver\n"); - /* get the appropriate clk */ clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { @@ -165,11 +252,15 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) case IORESOURCE_MEM_32BIT: priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; + priv->read_reg32 = c_can_plat_read_reg32; + priv->write_reg32 = c_can_plat_write_reg32; break; case IORESOURCE_MEM_16BIT: default: priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; + priv->read_reg32 = c_can_plat_read_reg32; + priv->write_reg32 = c_can_plat_write_reg32; break; } break; @@ -178,6 +269,30 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; + priv->read_reg32 = d_can_plat_read_reg32; + priv->write_reg32 = d_can_plat_write_reg32; + + if (pdev->dev.of_node) + priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can"); + else + priv->instance = pdev->id; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + /* Not all D_CAN modules have a separate register for the D_CAN + * RAM initialization. Use default RAM init bit in D_CAN module + * if not specified in DT. + */ + if (!res) { + priv->raminit = c_can_hw_raminit; + break; + } + + priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0) + dev_info(&pdev->dev, "control memory is not used for raminit\n"); + else + priv->raminit = c_can_hw_raminit_ti; break; default: ret = -EINVAL; @@ -206,7 +321,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) return 0; exit_free_device: - platform_set_drvdata(pdev, NULL); free_c_can_dev(dev); exit_iounmap: iounmap(addr); @@ -220,14 +334,13 @@ exit: return ret; } -static int __devexit c_can_plat_remove(struct platform_device *pdev) +static int c_can_plat_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct c_can_priv *priv = netdev_priv(dev); struct resource *mem; unregister_c_can_dev(dev); - platform_set_drvdata(pdev, NULL); free_c_can_dev(dev); iounmap(priv->base); @@ -303,10 +416,10 @@ static struct platform_driver c_can_plat_driver = { .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, - .of_match_table = of_match_ptr(c_can_of_table), + .of_match_table = c_can_of_table, }, .probe = c_can_plat_probe, - .remove = __devexit_p(c_can_plat_remove), + .remove = c_can_plat_remove, .suspend = c_can_suspend, .resume = c_can_resume, .id_table = c_can_id_table, diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig index 22c07a8c8b4..6a9a5ba7922 100644 --- a/drivers/net/can/cc770/Kconfig +++ b/drivers/net/can/cc770/Kconfig @@ -1,6 +1,6 @@ menuconfig CAN_CC770 tristate "Bosch CC770 and Intel AN82527 devices" - depends on CAN_DEV && HAS_IOMEM + depends on HAS_IOMEM if CAN_CC770 diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 0f12abf6591..d8379278d64 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -823,6 +823,7 @@ static const struct net_device_ops cc770_netdev_ops = { .ndo_open = cc770_open, .ndo_stop = cc770_close, .ndo_start_xmit = cc770_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_cc770dev(struct net_device *dev) diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c index 9f3a25ccd66..87a47c0cfd4 100644 --- a/drivers/net/can/cc770/cc770_isa.c +++ b/drivers/net/can/cc770/cc770_isa.c @@ -75,12 +75,12 @@ MODULE_LICENSE("GPL v2"); static unsigned long port[MAXDEV]; static unsigned long mem[MAXDEV]; -static int __devinitdata irq[MAXDEV]; -static int __devinitdata clk[MAXDEV]; -static u8 __devinitdata cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; -static u8 __devinitdata cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; -static u8 __devinitdata bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; -static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static int irq[MAXDEV]; +static int clk[MAXDEV]; +static u8 cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; +static u8 cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; +static u8 bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; +static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; module_param_array(port, ulong, NULL, S_IRUGO); MODULE_PARM_DESC(port, "I/O port number"); @@ -166,7 +166,7 @@ static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv, spin_unlock_irqrestore(&cc770_isa_port_lock, flags); } -static int __devinit cc770_isa_probe(struct platform_device *pdev) +static int cc770_isa_probe(struct platform_device *pdev) { struct net_device *dev; struct cc770_priv *priv; @@ -265,7 +265,7 @@ static int __devinit cc770_isa_probe(struct platform_device *pdev) else priv->clkout = COR_DEFAULT; - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_cc770dev(dev); @@ -291,14 +291,13 @@ static int __devinit cc770_isa_probe(struct platform_device *pdev) return err; } -static int __devexit cc770_isa_remove(struct platform_device *pdev) +static int cc770_isa_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct cc770_priv *priv = netdev_priv(dev); int idx = pdev->id; unregister_cc770dev(dev); - dev_set_drvdata(&pdev->dev, NULL); if (mem[idx]) { iounmap(priv->reg_base); @@ -316,7 +315,7 @@ static int __devexit cc770_isa_remove(struct platform_device *pdev) static struct platform_driver cc770_isa_driver = { .probe = cc770_isa_probe, - .remove = __devexit_p(cc770_isa_remove), + .remove = cc770_isa_remove, .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c index 688371cda37..ad76734b3ec 100644 --- a/drivers/net/can/cc770/cc770_platform.c +++ b/drivers/net/can/cc770/cc770_platform.c @@ -60,6 +60,7 @@ MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); #define CC770_PLATFORM_CAN_CLOCK 16000000 @@ -74,8 +75,8 @@ static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg, iowrite8(val, priv->reg_base + reg); } -static int __devinit cc770_get_of_node_data(struct platform_device *pdev, - struct cc770_priv *priv) +static int cc770_get_of_node_data(struct platform_device *pdev, + struct cc770_priv *priv) { struct device_node *np = pdev->dev.of_node; const u32 *prop; @@ -147,11 +148,11 @@ static int __devinit cc770_get_of_node_data(struct platform_device *pdev, return 0; } -static int __devinit cc770_get_platform_data(struct platform_device *pdev, - struct cc770_priv *priv) +static int cc770_get_platform_data(struct platform_device *pdev, + struct cc770_priv *priv) { - struct cc770_platform_data *pdata = pdev->dev.platform_data; + struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev); priv->can.clock.freq = pdata->osc_freq; if (priv->cpu_interface & CPUIF_DSC) @@ -163,7 +164,7 @@ static int __devinit cc770_get_platform_data(struct platform_device *pdev, return 0; } -static int __devinit cc770_platform_probe(struct platform_device *pdev) +static int cc770_platform_probe(struct platform_device *pdev) { struct net_device *dev; struct cc770_priv *priv; @@ -202,7 +203,7 @@ static int __devinit cc770_platform_probe(struct platform_device *pdev) if (pdev->dev.of_node) err = cc770_get_of_node_data(pdev, priv); - else if (pdev->dev.platform_data) + else if (dev_get_platdata(&pdev->dev)) err = cc770_get_platform_data(pdev, priv); else err = -ENODEV; @@ -215,7 +216,7 @@ static int __devinit cc770_platform_probe(struct platform_device *pdev) priv->reg_base, dev->irq, priv->can.clock.freq, priv->cpu_interface, priv->bus_config, priv->clkout); - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_cc770dev(dev); @@ -237,9 +238,9 @@ exit_release_mem: return err; } -static int __devexit cc770_platform_remove(struct platform_device *pdev) +static int cc770_platform_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct cc770_priv *priv = netdev_priv(dev); struct resource *mem; @@ -253,11 +254,12 @@ static int __devexit cc770_platform_remove(struct platform_device *pdev) return 0; } -static struct of_device_id __devinitdata cc770_platform_table[] = { +static struct of_device_id cc770_platform_table[] = { {.compatible = "bosch,cc770"}, /* CC770 from Bosch */ {.compatible = "intc,82527"}, /* AN82527 from Intel CP */ {}, }; +MODULE_DEVICE_TABLE(of, cc770_platform_table); static struct platform_driver cc770_platform_driver = { .driver = { @@ -266,7 +268,7 @@ static struct platform_driver cc770_platform_driver = { .of_match_table = cc770_platform_table, }, .probe = cc770_platform_probe, - .remove = __devexit_p(cc770_platform_remove), + .remove = cc770_platform_remove, }; module_platform_driver(cc770_platform_driver); diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 963e2ccd10d..e318e87e2bf 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> @@ -24,7 +23,9 @@ #include <linux/if_arp.h> #include <linux/can.h> #include <linux/can/dev.h> +#include <linux/can/skb.h> #include <linux/can/netlink.h> +#include <linux/can/led.h> #include <net/rtnetlink.h> #define MOD_DESC "CAN device driver interface" @@ -98,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc, return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); } -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; long rate, best_rate = 0; long best_error = 1000000000, error = 0; int best_tseg = 0, best_brp = 0, brp = 0; @@ -109,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) int spt_error = 1000, spt = 0, sampl_pt; u64 v64; - if (!priv->bittiming_const) - return -ENOTSUPP; - /* Use CIA recommended sample points */ if (bt->sample_point) { sampl_pt = bt->sample_point; @@ -203,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } #else /* !CONFIG_CAN_CALC_BITTIMING */ -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { netdev_err(dev, "bit-timing calculation not available\n"); return -EINVAL; @@ -216,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) * prescaler value brp. You can find more information in the header * file linux/can/netlink.h. */ -static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; int tseg1, alltseg; u64 brp64; - if (!priv->bittiming_const) - return -ENOTSUPP; - tseg1 = bt->prop_seg + bt->phase_seg1; if (!bt->sjw) bt->sjw = 1; @@ -253,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } -static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { - struct can_priv *priv = netdev_priv(dev); int err; /* Check if the CAN device has bit-timing parameters */ - if (priv->bittiming_const) { + if (!btc) + return -EOPNOTSUPP; - /* Non-expert mode? Check if the bitrate has been pre-defined */ - if (!bt->tq) - /* Determine bit-timing parameters */ - err = can_calc_bittiming(dev, bt); - else - /* Check bit-timing params and calculate proper brp */ - err = can_fixup_bittiming(dev, bt); - if (err) - return err; - } + /* + * Depending on the given can_bittiming parameter structure the CAN + * timing parameters are calculated based on the provided bitrate OR + * alternatively the CAN timing parameters (tq, prop_seg, etc.) are + * provided directly which are then checked and fixed up. + */ + if (!bt->tq && bt->bitrate) + err = can_calc_bittiming(dev, bt, btc); + else if (bt->tq && !bt->bitrate) + err = can_fixup_bittiming(dev, bt, btc); + else + err = -EINVAL; - return 0; + return err; } /* @@ -316,28 +315,20 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, BUG_ON(idx >= priv->echo_skb_max); /* check flag whether this packet has to be looped back */ - if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { + if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK || + (skb->protocol != htons(ETH_P_CAN) && + skb->protocol != htons(ETH_P_CANFD))) { kfree_skb(skb); return; } if (!priv->echo_skb[idx]) { - struct sock *srcsk = skb->sk; - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else - skb_orphan(skb); - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* make settings for echo to reduce code in irq context */ - skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; skb->dev = dev; @@ -501,13 +492,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; - skb = netdev_alloc_skb(dev, sizeof(struct can_frame)); + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + + sizeof(struct can_frame)); if (unlikely(!skb)) return NULL; skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame)); @@ -515,6 +511,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) } EXPORT_SYMBOL_GPL(alloc_can_skb); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd) +{ + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + + sizeof(struct canfd_frame)); + if (unlikely(!skb)) + return NULL; + + skb->protocol = htons(ETH_P_CANFD); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + + *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); + memset(*cfd, 0, sizeof(struct canfd_frame)); + + return skb; +} +EXPORT_SYMBOL_GPL(alloc_canfd_skb); + struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; @@ -575,6 +595,39 @@ void free_candev(struct net_device *dev) EXPORT_SYMBOL_GPL(free_candev); /* + * changing MTU and control mode for CAN/CANFD devices + */ +int can_change_mtu(struct net_device *dev, int new_mtu) +{ + struct can_priv *priv = netdev_priv(dev); + + /* Do not allow changing the MTU while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + + /* allow change of MTU according to the CANFD ability of the device */ + switch (new_mtu) { + case CAN_MTU: + priv->ctrlmode &= ~CAN_CTRLMODE_FD; + break; + + case CANFD_MTU: + if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) + return -EINVAL; + + priv->ctrlmode |= CAN_CTRLMODE_FD; + break; + + default: + return -EINVAL; + } + + dev->mtu = new_mtu; + return 0; +} +EXPORT_SYMBOL_GPL(can_change_mtu); + +/* * Common open function when the device gets opened. * * This function should be called in the open function of the device @@ -584,11 +637,19 @@ int open_candev(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - if (!priv->bittiming.tq && !priv->bittiming.bitrate) { + if (!priv->bittiming.bitrate) { netdev_err(dev, "bit-timing not yet defined\n"); return -EINVAL; } + /* For CAN FD the data bitrate has to be >= the arbitration bitrate */ + if ((priv->ctrlmode & CAN_CTRLMODE_FD) && + (!priv->data_bittiming.bitrate || + (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) { + netdev_err(dev, "incorrect/missing data bit-timing\n"); + return -EINVAL; + } + /* Switch carrier on if device was stopped while in bus-off state */ if (!netif_carrier_ok(dev)) netif_carrier_on(dev); @@ -609,8 +670,7 @@ void close_candev(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - if (del_timer_sync(&priv->restart_timer)) - dev_put(dev); + del_timer_sync(&priv->restart_timer); can_flush_echo_skb(dev); } EXPORT_SYMBOL_GPL(close_candev); @@ -628,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, + [IFLA_CAN_DATA_BITTIMING] + = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_DATA_BITTIMING_CONST] + = { .len = sizeof(struct can_bittiming_const) }, }; static int can_changelink(struct net_device *dev, @@ -639,19 +703,6 @@ static int can_changelink(struct net_device *dev, /* We need synchronization with dev->stop() */ ASSERT_RTNL(); - if (data[IFLA_CAN_CTRLMODE]) { - struct can_ctrlmode *cm; - - /* Do not allow changing controller mode while running */ - if (dev->flags & IFF_UP) - return -EBUSY; - cm = nla_data(data[IFLA_CAN_CTRLMODE]); - if (cm->flags & ~priv->ctrlmode_supported) - return -EOPNOTSUPP; - priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= cm->flags; - } - if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt; @@ -659,9 +710,7 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) - return -EINVAL; - err = can_get_bittiming(dev, &bt); + err = can_get_bittiming(dev, &bt, priv->bittiming_const); if (err) return err; memcpy(&priv->bittiming, &bt, sizeof(bt)); @@ -674,6 +723,25 @@ static int can_changelink(struct net_device *dev, } } + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm; + + /* Do not allow changing controller mode while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + cm = nla_data(data[IFLA_CAN_CTRLMODE]); + if (cm->flags & ~priv->ctrlmode_supported) + return -EOPNOTSUPP; + priv->ctrlmode &= ~cm->mask; + priv->ctrlmode |= cm->flags; + + /* CAN_CTRLMODE_FD can only be set when driver supports FD */ + if (priv->ctrlmode & CAN_CTRLMODE_FD) + dev->mtu = CANFD_MTU; + else + dev->mtu = CAN_MTU; + } + if (data[IFLA_CAN_RESTART_MS]) { /* Do not allow changing restart delay while running */ if (dev->flags & IFF_UP) @@ -690,23 +758,49 @@ static int can_changelink(struct net_device *dev, return err; } + if (data[IFLA_CAN_DATA_BITTIMING]) { + struct can_bittiming dbt; + + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), + sizeof(dbt)); + err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const); + if (err) + return err; + memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); + + if (priv->do_set_data_bittiming) { + /* Finally, set the bit-timing registers */ + err = priv->do_set_data_bittiming(dev); + if (err) + return err; + } + } + return 0; } static size_t can_get_size(const struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - size_t size; - - size = nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */ - size += sizeof(struct can_ctrlmode); /* IFLA_CAN_CTRLMODE */ - size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ - size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */ - size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */ - if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ - size += sizeof(struct can_berr_counter); - if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */ - size += sizeof(struct can_bittiming_const); + size_t size = 0; + + if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); + if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */ + size += nla_total_size(sizeof(struct can_bittiming_const)); + size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */ + size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */ + size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */ + size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ + if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ + size += nla_total_size(sizeof(struct can_berr_counter)); + if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); + if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(struct can_bittiming_const)); return size; } @@ -720,23 +814,35 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); - if (nla_put_u32(skb, IFLA_CAN_STATE, state) || + + if ((priv->bittiming.bitrate && + nla_put(skb, IFLA_CAN_BITTIMING, + sizeof(priv->bittiming), &priv->bittiming)) || + + (priv->bittiming_const && + 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_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) || - nla_put(skb, IFLA_CAN_BITTIMING, - sizeof(priv->bittiming), &priv->bittiming) || - nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) || + (priv->do_get_berr_counter && !priv->do_get_berr_counter(dev, &bec) && nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || - (priv->bittiming_const && - nla_put(skb, IFLA_CAN_BITTIMING_CONST, - sizeof(*priv->bittiming_const), priv->bittiming_const))) - goto nla_put_failure; - return 0; -nla_put_failure: - return -EMSGSIZE; + (priv->data_bittiming.bitrate && + nla_put(skb, IFLA_CAN_DATA_BITTIMING, + sizeof(priv->data_bittiming), &priv->data_bittiming)) || + + (priv->data_bittiming_const && + nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, + sizeof(*priv->data_bittiming_const), + priv->data_bittiming_const))) + return -EMSGSIZE; + + return 0; } static size_t can_get_xstats_size(const struct net_device *dev) @@ -795,10 +901,25 @@ void unregister_candev(struct net_device *dev) } EXPORT_SYMBOL_GPL(unregister_candev); +/* + * Test if a network device is a candev based device + * and return the can_priv* if so. + */ +struct can_priv *safe_candev_priv(struct net_device *dev) +{ + if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops)) + return NULL; + + return netdev_priv(dev); +} +EXPORT_SYMBOL_GPL(safe_candev_priv); + static __init int can_dev_init(void) { int err; + can_led_notifier_init(); + err = rtnl_link_register(&can_link_ops); if (!err) printk(KERN_INFO MOD_DESC "\n"); @@ -810,6 +931,8 @@ module_init(can_dev_init); static __exit void can_dev_exit(void) { rtnl_link_unregister(&can_link_ops); + + can_led_notifier_exit(); } module_exit(can_dev_exit); diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index c78ecfca1e4..f425ec2c783 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -23,7 +23,7 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> -#include <linux/can/platform/flexcan.h> +#include <linux/can/led.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/if_arp.h> @@ -36,7 +36,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/pinctrl/consumer.h> +#include <linux/regulator/consumer.h> #define DRV_NAME "flexcan" @@ -62,7 +62,7 @@ #define FLEXCAN_MCR_BCC BIT(16) #define FLEXCAN_MCR_LPRIO_EN BIT(13) #define FLEXCAN_MCR_AEN BIT(12) -#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf) +#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x1f) #define FLEXCAN_MCR_IDAM_A (0 << 8) #define FLEXCAN_MCR_IDAM_B (1 << 8) #define FLEXCAN_MCR_IDAM_C (2 << 8) @@ -144,9 +144,24 @@ #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) -/* FLEXCAN hardware feature flags */ +#define FLEXCAN_TIMEOUT_US (50) + +/* + * FLEXCAN hardware feature flags + * + * Below is some version info we got: + * SOC Version IP-Version Glitch- [TR]WRN_INT + * Filter? connected? + * MX25 FlexCAN2 03.00.00.00 no no + * MX28 FlexCAN2 03.00.04.00 yes yes + * MX35 FlexCAN2 03.00.00.00 no no + * MX53 FlexCAN2 03.00.00.00 yes no + * MX6s FlexCAN3 10.00.12.00 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) /* Broken error state handling */ +#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */ /* Structure of the message buffer */ struct flexcan_mb { @@ -198,6 +213,7 @@ struct flexcan_priv { struct clk *clk_per; struct flexcan_platform_data *pdata; const struct flexcan_devtype_data *devtype_data; + struct regulator *reg_xceiver; }; static struct flexcan_devtype_data fsl_p1010_devtype_data = { @@ -205,7 +221,7 @@ static struct flexcan_devtype_data fsl_p1010_devtype_data = { }; static struct flexcan_devtype_data fsl_imx28_devtype_data; static struct flexcan_devtype_data fsl_imx6q_devtype_data = { - .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_BROKEN_ERR_STATE, + .features = FLEXCAN_HAS_V10_FEATURES, }; static const struct can_bittiming_const flexcan_bittiming_const = { @@ -221,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = { }; /* - * Abstract off the read/write for arm versus ppc. + * 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. */ -#if defined(__BIG_ENDIAN) +#if defined(CONFIG_PPC) static inline u32 flexcan_read(void __iomem *addr) { return in_be32(addr); @@ -245,13 +264,20 @@ static inline void flexcan_write(u32 val, void __iomem *addr) } #endif -/* - * Swtich transceiver on or off - */ -static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on) +static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) { - if (priv->pdata && priv->pdata->transceiver_switch) - priv->pdata->transceiver_switch(on); + if (!priv->reg_xceiver) + return 0; + + return regulator_enable(priv->reg_xceiver); +} + +static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv) +{ + if (!priv->reg_xceiver) + return 0; + + return regulator_disable(priv->reg_xceiver); } static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, @@ -261,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, (reg_esr & FLEXCAN_ESR_ERR_BUS); } -static inline void flexcan_chip_enable(struct flexcan_priv *priv) +static int flexcan_chip_enable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg &= ~FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); - udelay(10); + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK) + return -ETIMEDOUT; + + return 0; } -static inline void flexcan_chip_disable(struct flexcan_priv *priv) +static int flexcan_chip_disable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg |= FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); + + while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_freeze(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate; + u32 reg; + + reg = flexcan_read(®s->mcr); + reg |= FLEXCAN_MCR_HALT; + flexcan_write(reg, ®s->mcr); + + while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + usleep_range(100, 200); + + if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_unfreeze(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; + u32 reg; + + reg = flexcan_read(®s->mcr); + reg &= ~FLEXCAN_MCR_HALT; + flexcan_write(reg, ®s->mcr); + + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_softreset(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; + + flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST) + return -ETIMEDOUT; + + return 0; } static int flexcan_get_berr_counter(const struct net_device *dev, @@ -551,6 +646,8 @@ static int flexcan_read_frame(struct net_device *dev) stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + can_led_event(dev, CAN_LED_EVENT_RX); + return 1; } @@ -639,6 +736,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) { stats->tx_bytes += can_get_echo_skb(dev, 0); stats->tx_packets++; + can_led_event(dev, CAN_LED_EVENT_TX); flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1); netif_wake_queue(dev); } @@ -694,24 +792,18 @@ static int flexcan_chip_start(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->base; - unsigned int i; int err; u32 reg_mcr, reg_ctrl; /* enable module */ - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + return err; /* soft reset */ - flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); - udelay(10); - - reg_mcr = flexcan_read(®s->mcr); - if (reg_mcr & FLEXCAN_MCR_SOFTRST) { - netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n", - reg_mcr); - err = -ENODEV; - goto out; - } + err = flexcan_chip_softreset(priv); + if (err) + goto out_chip_disable; flexcan_set_bittiming(dev); @@ -728,9 +820,11 @@ static int flexcan_chip_start(struct net_device *dev) * */ 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_IDAM_C | FLEXCAN_MCR_SRX_DIS | + FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID); netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); flexcan_write(reg_mcr, ®s->mcr); @@ -764,16 +858,9 @@ static int flexcan_chip_start(struct net_device *dev) netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); flexcan_write(reg_ctrl, ®s->ctrl); - for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) { - flexcan_write(0, ®s->cantxfg[i].can_ctrl); - flexcan_write(0, ®s->cantxfg[i].can_id); - flexcan_write(0, ®s->cantxfg[i].data[0]); - flexcan_write(0, ®s->cantxfg[i].data[1]); - - /* put MB into rx queue */ - flexcan_write(FLEXCAN_MB_CNT_CODE(0x4), - ®s->cantxfg[i].can_ctrl); - } + /* Abort any pending TX, mark Mailbox as INACTIVE */ + flexcan_write(FLEXCAN_MB_CNT_CODE(0x4), + ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); /* acceptance mask/acceptance code (accept everything) */ flexcan_write(0x0, ®s->rxgmask); @@ -783,12 +870,14 @@ static int flexcan_chip_start(struct net_device *dev) if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) flexcan_write(0x0, ®s->rxfgmask); - flexcan_transceiver_switch(priv, 1); + err = flexcan_transceiver_enable(priv); + if (err) + goto out_chip_disable; /* synchronize with the can bus */ - reg_mcr = flexcan_read(®s->mcr); - reg_mcr &= ~FLEXCAN_MCR_HALT; - flexcan_write(reg_mcr, ®s->mcr); + err = flexcan_chip_unfreeze(priv); + if (err) + goto out_transceiver_disable; priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -801,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev) return 0; - out: + out_transceiver_disable: + flexcan_transceiver_disable(priv); + out_chip_disable: flexcan_chip_disable(priv); return err; } @@ -816,17 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->base; - u32 reg; + + /* freeze + disable module */ + flexcan_chip_freeze(priv); + flexcan_chip_disable(priv); /* Disable all interrupts */ flexcan_write(0, ®s->imask1); + flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, + ®s->ctrl); - /* Disable + halt module */ - reg = flexcan_read(®s->mcr); - reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; - flexcan_write(reg, ®s->mcr); - - flexcan_transceiver_switch(priv, 0); + flexcan_transceiver_disable(priv); priv->can.state = CAN_STATE_STOPPED; return; @@ -837,12 +928,17 @@ static int flexcan_open(struct net_device *dev) struct flexcan_priv *priv = netdev_priv(dev); int err; - clk_prepare_enable(priv->clk_ipg); - clk_prepare_enable(priv->clk_per); + err = clk_prepare_enable(priv->clk_ipg); + if (err) + return err; + + err = clk_prepare_enable(priv->clk_per); + if (err) + goto out_disable_ipg; err = open_candev(dev); if (err) - goto out; + goto out_disable_per; err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev); if (err) @@ -851,16 +947,22 @@ static int flexcan_open(struct net_device *dev) /* start chip and queuing */ err = flexcan_chip_start(dev); if (err) - goto out_close; + goto out_free_irq; + + can_led_event(dev, CAN_LED_EVENT_OPEN); + napi_enable(&priv->napi); netif_start_queue(dev); return 0; + out_free_irq: + free_irq(dev->irq, dev); out_close: close_candev(dev); - out: + out_disable_per: clk_disable_unprepare(priv->clk_per); + out_disable_ipg: clk_disable_unprepare(priv->clk_ipg); return err; @@ -880,6 +982,8 @@ static int flexcan_close(struct net_device *dev) close_candev(dev); + can_led_event(dev, CAN_LED_EVENT_STOP); + return 0; } @@ -907,24 +1011,34 @@ static const struct net_device_ops flexcan_netdev_ops = { .ndo_open = flexcan_open, .ndo_stop = flexcan_close, .ndo_start_xmit = flexcan_start_xmit, + .ndo_change_mtu = can_change_mtu, }; -static int __devinit register_flexcandev(struct net_device *dev) +static int register_flexcandev(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->base; u32 reg, err; - clk_prepare_enable(priv->clk_ipg); - clk_prepare_enable(priv->clk_per); + err = clk_prepare_enable(priv->clk_ipg); + if (err) + return err; + + err = clk_prepare_enable(priv->clk_per); + if (err) + goto out_disable_ipg; /* select "bus clock", chip must be disabled */ - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + goto out_disable_per; reg = flexcan_read(®s->ctrl); reg |= FLEXCAN_CTRL_CLK_SRC; flexcan_write(reg, ®s->ctrl); - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + goto out_chip_disable; /* set freeze, halt and activate FIFO, restrict register access */ reg = flexcan_read(®s->mcr); @@ -941,38 +1055,42 @@ static int __devinit register_flexcandev(struct net_device *dev) if (!(reg & FLEXCAN_MCR_FEN)) { netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); err = -ENODEV; - goto out; + goto out_chip_disable; } err = register_candev(dev); - out: /* disable core and turn off clocks */ + out_chip_disable: flexcan_chip_disable(priv); + out_disable_per: clk_disable_unprepare(priv->clk_per); + out_disable_ipg: clk_disable_unprepare(priv->clk_ipg); return err; } -static void __devexit unregister_flexcandev(struct net_device *dev) +static void unregister_flexcandev(struct net_device *dev) { unregister_candev(dev); } static const struct of_device_id flexcan_of_match[] = { - { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, - { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, + { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, + { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, flexcan_of_match); static const struct platform_device_id flexcan_id_table[] = { { .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(platform, flexcan_id_table); -static int __devinit flexcan_probe(struct platform_device *pdev) +static int flexcan_probe(struct platform_device *pdev) { const struct of_device_id *of_id; const struct flexcan_devtype_data *devtype_data; @@ -980,16 +1098,10 @@ static int __devinit flexcan_probe(struct platform_device *pdev) struct flexcan_priv *priv; struct resource *mem; struct clk *clk_ipg = NULL, *clk_per = NULL; - struct pinctrl *pinctrl; void __iomem *base; - resource_size_t mem_size; int err, irq; u32 clock_freq = 0; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - return PTR_ERR(pinctrl); - if (pdev->dev.of_node) of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clock_freq); @@ -998,55 +1110,40 @@ static int __devinit flexcan_probe(struct platform_device *pdev) clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(clk_ipg)) { dev_err(&pdev->dev, "no ipg clock defined\n"); - err = PTR_ERR(clk_ipg); - goto failed_clock; + return PTR_ERR(clk_ipg); } - clock_freq = clk_get_rate(clk_ipg); clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(clk_per)) { dev_err(&pdev->dev, "no per clock defined\n"); - err = PTR_ERR(clk_per); - goto failed_clock; + return PTR_ERR(clk_per); } + clock_freq = clk_get_rate(clk_per); } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!mem || irq <= 0) { - err = -ENODEV; - goto failed_get; - } - - mem_size = resource_size(mem); - if (!request_mem_region(mem->start, mem_size, pdev->name)) { - err = -EBUSY; - goto failed_get; - } + if (irq <= 0) + return -ENODEV; - base = ioremap(mem->start, mem_size); - if (!base) { - err = -ENOMEM; - goto failed_map; - } - - dev = alloc_candev(sizeof(struct flexcan_priv), 1); - if (!dev) { - err = -ENOMEM; - goto failed_alloc; - } + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); of_id = of_match_device(flexcan_of_match, &pdev->dev); if (of_id) { devtype_data = of_id->data; - } else if (pdev->id_entry->driver_data) { + } else if (platform_get_device_id(pdev)->driver_data) { devtype_data = (struct flexcan_devtype_data *) - pdev->id_entry->driver_data; + platform_get_device_id(pdev)->driver_data; } else { - err = -ENODEV; - goto failed_devtype; + return -ENODEV; } + dev = alloc_candev(sizeof(struct flexcan_priv), 1); + if (!dev) + return -ENOMEM; + dev->netdev_ops = &flexcan_netdev_ops; dev->irq = irq; dev->flags |= IFF_ECHO; @@ -1063,12 +1160,16 @@ static int __devinit flexcan_probe(struct platform_device *pdev) priv->dev = dev; priv->clk_ipg = clk_ipg; priv->clk_per = clk_per; - priv->pdata = pdev->dev.platform_data; + priv->pdata = dev_get_platdata(&pdev->dev); priv->devtype_data = devtype_data; + priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); + if (IS_ERR(priv->reg_xceiver)) + priv->reg_xceiver = NULL; + netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_flexcandev(dev); @@ -1077,48 +1178,39 @@ static int __devinit flexcan_probe(struct platform_device *pdev) goto failed_register; } + devm_can_led_init(dev); + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", priv->base, dev->irq); return 0; failed_register: - failed_devtype: free_candev(dev); - failed_alloc: - iounmap(base); - failed_map: - release_mem_region(mem->start, mem_size); - failed_get: - failed_clock: return err; } -static int __devexit flexcan_remove(struct platform_device *pdev) +static int flexcan_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct flexcan_priv *priv = netdev_priv(dev); - struct resource *mem; unregister_flexcandev(dev); - platform_set_drvdata(pdev, NULL); - iounmap(priv->base); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); - + netif_napi_del(&priv->napi); free_candev(dev); return 0; } -#ifdef CONFIG_PM -static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) +static int __maybe_unused flexcan_suspend(struct device *device) { - struct net_device *dev = platform_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); + int err; - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + return err; if (netif_running(dev)) { netif_stop_queue(dev); @@ -1129,9 +1221,9 @@ static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int flexcan_resume(struct platform_device *pdev) +static int __maybe_unused flexcan_resume(struct device *device) { - struct net_device *dev = platform_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -1139,25 +1231,20 @@ static int flexcan_resume(struct platform_device *pdev) netif_device_attach(dev); netif_start_queue(dev); } - flexcan_chip_enable(priv); - - return 0; + return flexcan_chip_enable(priv); } -#else -#define flexcan_suspend NULL -#define flexcan_resume NULL -#endif + +static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume); static struct platform_driver flexcan_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .pm = &flexcan_pm_ops, .of_match_table = flexcan_of_match, }, .probe = flexcan_probe, - .remove = __devexit_p(flexcan_remove), - .suspend = flexcan_suspend, - .resume = flexcan_resume, + .remove = flexcan_remove, .id_table = flexcan_id_table, }; diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c new file mode 100644 index 00000000000..3fd9fd942c6 --- /dev/null +++ b/drivers/net/can/grcan.c @@ -0,0 +1,1752 @@ +/* + * Socket CAN driver for Aeroflex Gaisler GRCAN and GRHCAN. + * + * 2012 (c) Aeroflex Gaisler AB + * + * This driver supports GRCAN and GRHCAN CAN controllers available in the GRLIB + * VHDL IP core library. + * + * Full documentation of the GRCAN core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * See "Documentation/devicetree/bindings/net/can/grcan.txt" for information on + * open firmware properties. + * + * See "Documentation/ABI/testing/sysfs-class-net-grcan" for information on the + * sysfs interface. + * + * See "Documentation/kernel-parameters.txt" for information on the module + * parameters. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: Andreas Larsson <andreas@gaisler.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/can/dev.h> +#include <linux/spinlock.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> + +#include <linux/dma-mapping.h> + +#define DRV_NAME "grcan" + +#define GRCAN_NAPI_WEIGHT 32 + +#define GRCAN_RESERVE_SIZE(slot1, slot2) (((slot2) - (slot1)) / 4 - 1) + +struct grcan_registers { + u32 conf; /* 0x00 */ + u32 stat; /* 0x04 */ + u32 ctrl; /* 0x08 */ + u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)]; + u32 smask; /* 0x18 - CanMASK */ + u32 scode; /* 0x1c - CanCODE */ + u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)]; + u32 pimsr; /* 0x100 */ + u32 pimr; /* 0x104 */ + u32 pisr; /* 0x108 */ + u32 pir; /* 0x10C */ + u32 imr; /* 0x110 */ + u32 picr; /* 0x114 */ + u32 __reserved3[GRCAN_RESERVE_SIZE(0x114, 0x200)]; + u32 txctrl; /* 0x200 */ + u32 txaddr; /* 0x204 */ + u32 txsize; /* 0x208 */ + u32 txwr; /* 0x20C */ + u32 txrd; /* 0x210 */ + u32 txirq; /* 0x214 */ + u32 __reserved4[GRCAN_RESERVE_SIZE(0x214, 0x300)]; + u32 rxctrl; /* 0x300 */ + u32 rxaddr; /* 0x304 */ + u32 rxsize; /* 0x308 */ + u32 rxwr; /* 0x30C */ + u32 rxrd; /* 0x310 */ + u32 rxirq; /* 0x314 */ + u32 rxmask; /* 0x318 */ + u32 rxcode; /* 0x31C */ +}; + +#define GRCAN_CONF_ABORT 0x00000001 +#define GRCAN_CONF_ENABLE0 0x00000002 +#define GRCAN_CONF_ENABLE1 0x00000004 +#define GRCAN_CONF_SELECT 0x00000008 +#define GRCAN_CONF_SILENT 0x00000010 +#define GRCAN_CONF_SAM 0x00000020 /* Available in some hardware */ +#define GRCAN_CONF_BPR 0x00000300 /* Note: not BRP */ +#define GRCAN_CONF_RSJ 0x00007000 +#define GRCAN_CONF_PS1 0x00f00000 +#define GRCAN_CONF_PS2 0x000f0000 +#define GRCAN_CONF_SCALER 0xff000000 +#define GRCAN_CONF_OPERATION \ + (GRCAN_CONF_ABORT | GRCAN_CONF_ENABLE0 | GRCAN_CONF_ENABLE1 \ + | GRCAN_CONF_SELECT | GRCAN_CONF_SILENT | GRCAN_CONF_SAM) +#define GRCAN_CONF_TIMING \ + (GRCAN_CONF_BPR | GRCAN_CONF_RSJ | GRCAN_CONF_PS1 \ + | GRCAN_CONF_PS2 | GRCAN_CONF_SCALER) + +#define GRCAN_CONF_RSJ_MIN 1 +#define GRCAN_CONF_RSJ_MAX 4 +#define GRCAN_CONF_PS1_MIN 1 +#define GRCAN_CONF_PS1_MAX 15 +#define GRCAN_CONF_PS2_MIN 2 +#define GRCAN_CONF_PS2_MAX 8 +#define GRCAN_CONF_SCALER_MIN 0 +#define GRCAN_CONF_SCALER_MAX 255 +#define GRCAN_CONF_SCALER_INC 1 + +#define GRCAN_CONF_BPR_BIT 8 +#define GRCAN_CONF_RSJ_BIT 12 +#define GRCAN_CONF_PS1_BIT 20 +#define GRCAN_CONF_PS2_BIT 16 +#define GRCAN_CONF_SCALER_BIT 24 + +#define GRCAN_STAT_PASS 0x000001 +#define GRCAN_STAT_OFF 0x000002 +#define GRCAN_STAT_OR 0x000004 +#define GRCAN_STAT_AHBERR 0x000008 +#define GRCAN_STAT_ACTIVE 0x000010 +#define GRCAN_STAT_RXERRCNT 0x00ff00 +#define GRCAN_STAT_TXERRCNT 0xff0000 + +#define GRCAN_STAT_ERRCTR_RELATED (GRCAN_STAT_PASS | GRCAN_STAT_OFF) + +#define GRCAN_STAT_RXERRCNT_BIT 8 +#define GRCAN_STAT_TXERRCNT_BIT 16 + +#define GRCAN_STAT_ERRCNT_WARNING_LIMIT 96 +#define GRCAN_STAT_ERRCNT_PASSIVE_LIMIT 127 + +#define GRCAN_CTRL_RESET 0x2 +#define GRCAN_CTRL_ENABLE 0x1 + +#define GRCAN_TXCTRL_ENABLE 0x1 +#define GRCAN_TXCTRL_ONGOING 0x2 +#define GRCAN_TXCTRL_SINGLE 0x4 + +#define GRCAN_RXCTRL_ENABLE 0x1 +#define GRCAN_RXCTRL_ONGOING 0x2 + +/* Relative offset of IRQ sources to AMBA Plug&Play */ +#define GRCAN_IRQIX_IRQ 0 +#define GRCAN_IRQIX_TXSYNC 1 +#define GRCAN_IRQIX_RXSYNC 2 + +#define GRCAN_IRQ_PASS 0x00001 +#define GRCAN_IRQ_OFF 0x00002 +#define GRCAN_IRQ_OR 0x00004 +#define GRCAN_IRQ_RXAHBERR 0x00008 +#define GRCAN_IRQ_TXAHBERR 0x00010 +#define GRCAN_IRQ_RXIRQ 0x00020 +#define GRCAN_IRQ_TXIRQ 0x00040 +#define GRCAN_IRQ_RXFULL 0x00080 +#define GRCAN_IRQ_TXEMPTY 0x00100 +#define GRCAN_IRQ_RX 0x00200 +#define GRCAN_IRQ_TX 0x00400 +#define GRCAN_IRQ_RXSYNC 0x00800 +#define GRCAN_IRQ_TXSYNC 0x01000 +#define GRCAN_IRQ_RXERRCTR 0x02000 +#define GRCAN_IRQ_TXERRCTR 0x04000 +#define GRCAN_IRQ_RXMISS 0x08000 +#define GRCAN_IRQ_TXLOSS 0x10000 + +#define GRCAN_IRQ_NONE 0 +#define GRCAN_IRQ_ALL \ + (GRCAN_IRQ_PASS | GRCAN_IRQ_OFF | GRCAN_IRQ_OR \ + | GRCAN_IRQ_RXAHBERR | GRCAN_IRQ_TXAHBERR \ + | GRCAN_IRQ_RXIRQ | GRCAN_IRQ_TXIRQ \ + | GRCAN_IRQ_RXFULL | GRCAN_IRQ_TXEMPTY \ + | GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_RXSYNC \ + | GRCAN_IRQ_TXSYNC | GRCAN_IRQ_RXERRCTR \ + | GRCAN_IRQ_TXERRCTR | GRCAN_IRQ_RXMISS \ + | GRCAN_IRQ_TXLOSS) + +#define GRCAN_IRQ_ERRCTR_RELATED (GRCAN_IRQ_RXERRCTR | GRCAN_IRQ_TXERRCTR \ + | GRCAN_IRQ_PASS | GRCAN_IRQ_OFF) +#define GRCAN_IRQ_ERRORS (GRCAN_IRQ_ERRCTR_RELATED | GRCAN_IRQ_OR \ + | GRCAN_IRQ_TXAHBERR | GRCAN_IRQ_RXAHBERR \ + | GRCAN_IRQ_TXLOSS) +#define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS) + +#define GRCAN_MSG_SIZE 16 + +#define GRCAN_MSG_IDE 0x80000000 +#define GRCAN_MSG_RTR 0x40000000 +#define GRCAN_MSG_BID 0x1ffc0000 +#define GRCAN_MSG_EID 0x1fffffff +#define GRCAN_MSG_IDE_BIT 31 +#define GRCAN_MSG_RTR_BIT 30 +#define GRCAN_MSG_BID_BIT 18 +#define GRCAN_MSG_EID_BIT 0 + +#define GRCAN_MSG_DLC 0xf0000000 +#define GRCAN_MSG_TXERRC 0x00ff0000 +#define GRCAN_MSG_RXERRC 0x0000ff00 +#define GRCAN_MSG_DLC_BIT 28 +#define GRCAN_MSG_TXERRC_BIT 16 +#define GRCAN_MSG_RXERRC_BIT 8 +#define GRCAN_MSG_AHBERR 0x00000008 +#define GRCAN_MSG_OR 0x00000004 +#define GRCAN_MSG_OFF 0x00000002 +#define GRCAN_MSG_PASS 0x00000001 + +#define GRCAN_MSG_DATA_SLOT_INDEX(i) (2 + (i) / 4) +#define GRCAN_MSG_DATA_SHIFT(i) ((3 - (i) % 4) * 8) + +#define GRCAN_BUFFER_ALIGNMENT 1024 +#define GRCAN_DEFAULT_BUFFER_SIZE 1024 +#define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0 + +#define GRCAN_INVALID_BUFFER_SIZE(s) \ + ((s) == 0 || ((s) & ~GRCAN_VALID_TR_SIZE_MASK)) + +#if GRCAN_INVALID_BUFFER_SIZE(GRCAN_DEFAULT_BUFFER_SIZE) +#error "Invalid default buffer size" +#endif + +struct grcan_dma_buffer { + size_t size; + void *buf; + dma_addr_t handle; +}; + +struct grcan_dma { + size_t base_size; + void *base_buf; + dma_addr_t base_handle; + struct grcan_dma_buffer tx; + struct grcan_dma_buffer rx; +}; + +/* GRCAN configuration parameters */ +struct grcan_device_config { + unsigned short enable0; + unsigned short enable1; + unsigned short select; + unsigned int txsize; + unsigned int rxsize; +}; + +#define GRCAN_DEFAULT_DEVICE_CONFIG { \ + .enable0 = 0, \ + .enable1 = 0, \ + .select = 0, \ + .txsize = GRCAN_DEFAULT_BUFFER_SIZE, \ + .rxsize = GRCAN_DEFAULT_BUFFER_SIZE, \ + } + +#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 0x4100 +#define GRLIB_VERSION_MASK 0xffff + +/* GRCAN private data structure */ +struct grcan_priv { + struct can_priv can; /* must be the first member */ + struct net_device *dev; + struct napi_struct napi; + + struct grcan_registers __iomem *regs; /* ioremap'ed registers */ + struct grcan_device_config config; + struct grcan_dma dma; + + struct sk_buff **echo_skb; /* We allocate this on our own */ + u8 *txdlc; /* Length of queued frames */ + + /* The echo skb pointer, pointing into echo_skb and indicating which + * frames can be echoed back. See the "Notes on the tx cyclic buffer + * handling"-comment for grcan_start_xmit for more details. + */ + u32 eskbp; + + /* Lock for controlling changes to the netif tx queue state, accesses to + * the echo_skb pointer eskbp and for making sure that a running reset + * and/or a close of the interface is done without interference from + * other parts of the code. + * + * The echo_skb pointer, eskbp, should only be accessed under this lock + * as it can be changed in several places and together with decisions on + * whether to wake up the tx queue. + * + * The tx queue must never be woken up if there is a running reset or + * close in progress. + * + * A running reset (see below on need_txbug_workaround) should never be + * done if the interface is closing down and several running resets + * should never be scheduled simultaneously. + */ + spinlock_t lock; + + /* Whether a workaround is needed due to a bug in older hardware. In + * this case, the driver both tries to prevent the bug from being + * triggered and recovers, if the bug nevertheless happens, by doing a + * running reset. A running reset, resets the device and continues from + * where it were without being noticeable from outside the driver (apart + * from slight delays). + */ + bool need_txbug_workaround; + + /* To trigger initization of running reset and to trigger running reset + * respectively in the case of a hanged device due to a txbug. + */ + struct timer_list hang_timer; + struct timer_list rr_timer; + + /* To avoid waking up the netif queue and restarting timers + * when a reset is scheduled or when closing of the device is + * undergoing + */ + bool resetting; + bool closing; +}; + +/* Wait time for a short wait for ongoing to clear */ +#define GRCAN_SHORTWAIT_USECS 10 + +/* Limit on the number of transmitted bits of an eff frame according to the CAN + * specification: 1 bit start of frame, 32 bits arbitration field, 6 bits + * control field, 8 bytes data field, 16 bits crc field, 2 bits ACK field and 7 + * bits end of frame + */ +#define GRCAN_EFF_FRAME_MAX_BITS (1+32+6+8*8+16+2+7) + +#if defined(__BIG_ENDIAN) +static inline u32 grcan_read_reg(u32 __iomem *reg) +{ + return ioread32be(reg); +} + +static inline void grcan_write_reg(u32 __iomem *reg, u32 val) +{ + iowrite32be(val, reg); +} +#else +static inline u32 grcan_read_reg(u32 __iomem *reg) +{ + return ioread32(reg); +} + +static inline void grcan_write_reg(u32 __iomem *reg, u32 val) +{ + iowrite32(val, reg); +} +#endif + +static inline void grcan_clear_bits(u32 __iomem *reg, u32 mask) +{ + grcan_write_reg(reg, grcan_read_reg(reg) & ~mask); +} + +static inline void grcan_set_bits(u32 __iomem *reg, u32 mask) +{ + grcan_write_reg(reg, grcan_read_reg(reg) | mask); +} + +static inline u32 grcan_read_bits(u32 __iomem *reg, u32 mask) +{ + return grcan_read_reg(reg) & mask; +} + +static inline void grcan_write_bits(u32 __iomem *reg, u32 value, u32 mask) +{ + u32 old = grcan_read_reg(reg); + + grcan_write_reg(reg, (old & ~mask) | (value & mask)); +} + +/* a and b should both be in [0,size] and a == b == size should not hold */ +static inline u32 grcan_ring_add(u32 a, u32 b, u32 size) +{ + u32 sum = a + b; + + if (sum < size) + return sum; + else + return sum - size; +} + +/* a and b should both be in [0,size) */ +static inline u32 grcan_ring_sub(u32 a, u32 b, u32 size) +{ + return grcan_ring_add(a, size - b, size); +} + +/* Available slots for new transmissions */ +static inline u32 grcan_txspace(size_t txsize, u32 txwr, u32 eskbp) +{ + u32 slots = txsize / GRCAN_MSG_SIZE - 1; + u32 used = grcan_ring_sub(txwr, eskbp, txsize) / GRCAN_MSG_SIZE; + + return slots - used; +} + +/* Configuration parameters that can be set via module parameters */ +static struct grcan_device_config grcan_module_config = + GRCAN_DEFAULT_DEVICE_CONFIG; + +static const struct can_bittiming_const grcan_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = GRCAN_CONF_PS1_MIN + 1, + .tseg1_max = GRCAN_CONF_PS1_MAX + 1, + .tseg2_min = GRCAN_CONF_PS2_MIN, + .tseg2_max = GRCAN_CONF_PS2_MAX, + .sjw_max = GRCAN_CONF_RSJ_MAX, + .brp_min = GRCAN_CONF_SCALER_MIN + 1, + .brp_max = GRCAN_CONF_SCALER_MAX + 1, + .brp_inc = GRCAN_CONF_SCALER_INC, +}; + +static int grcan_set_bittiming(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct can_bittiming *bt = &priv->can.bittiming; + u32 timing = 0; + int bpr, rsj, ps1, ps2, scaler; + + /* Should never happen - function will not be called when + * device is up + */ + if (grcan_read_bits(®s->ctrl, GRCAN_CTRL_ENABLE)) + return -EBUSY; + + bpr = 0; /* Note bpr and brp are different concepts */ + rsj = bt->sjw; + ps1 = (bt->prop_seg + bt->phase_seg1) - 1; /* tseg1 - 1 */ + ps2 = bt->phase_seg2; + scaler = (bt->brp - 1); + netdev_dbg(dev, "Request for BPR=%d, RSJ=%d, PS1=%d, PS2=%d, SCALER=%d", + bpr, rsj, ps1, ps2, scaler); + if (!(ps1 > ps2)) { + netdev_err(dev, "PS1 > PS2 must hold: PS1=%d, PS2=%d\n", + ps1, ps2); + return -EINVAL; + } + if (!(ps2 >= rsj)) { + netdev_err(dev, "PS2 >= RSJ must hold: PS2=%d, RSJ=%d\n", + ps2, rsj); + return -EINVAL; + } + + timing |= (bpr << GRCAN_CONF_BPR_BIT) & GRCAN_CONF_BPR; + timing |= (rsj << GRCAN_CONF_RSJ_BIT) & GRCAN_CONF_RSJ; + timing |= (ps1 << GRCAN_CONF_PS1_BIT) & GRCAN_CONF_PS1; + timing |= (ps2 << GRCAN_CONF_PS2_BIT) & GRCAN_CONF_PS2; + timing |= (scaler << GRCAN_CONF_SCALER_BIT) & GRCAN_CONF_SCALER; + netdev_info(dev, "setting timing=0x%x\n", timing); + grcan_write_bits(®s->conf, timing, GRCAN_CONF_TIMING); + + return 0; +} + +static int grcan_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + u32 status = grcan_read_reg(®s->stat); + + bec->txerr = (status & GRCAN_STAT_TXERRCNT) >> GRCAN_STAT_TXERRCNT_BIT; + bec->rxerr = (status & GRCAN_STAT_RXERRCNT) >> GRCAN_STAT_RXERRCNT_BIT; + return 0; +} + +static int grcan_poll(struct napi_struct *napi, int budget); + +/* Reset device, but keep configuration information */ +static void grcan_reset(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + u32 config = grcan_read_reg(®s->conf); + + grcan_set_bits(®s->ctrl, GRCAN_CTRL_RESET); + grcan_write_reg(®s->conf, config); + + priv->eskbp = grcan_read_reg(®s->txrd); + priv->can.state = CAN_STATE_STOPPED; + + /* Turn off hardware filtering - regs->rxcode set to 0 by reset */ + grcan_write_reg(®s->rxmask, 0); +} + +/* stop device without changing any configurations */ +static void grcan_stop_hardware(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + + grcan_write_reg(®s->imr, GRCAN_IRQ_NONE); + grcan_clear_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE); + grcan_clear_bits(®s->rxctrl, GRCAN_RXCTRL_ENABLE); + grcan_clear_bits(®s->ctrl, GRCAN_CTRL_ENABLE); +} + +/* Let priv->eskbp catch up to regs->txrd and echo back the skbs if echo + * is true and free them otherwise. + * + * If budget is >= 0, stop after handling at most budget skbs. Otherwise, + * continue until priv->eskbp catches up to regs->txrd. + * + * priv->lock *must* be held when calling this function + */ +static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + struct net_device_stats *stats = &dev->stats; + int i, work_done; + + /* Updates to priv->eskbp and wake-ups of the queue needs to + * be atomic towards the reads of priv->eskbp and shut-downs + * of the queue in grcan_start_xmit. + */ + u32 txrd = grcan_read_reg(®s->txrd); + + for (work_done = 0; work_done < budget || budget < 0; work_done++) { + if (priv->eskbp == txrd) + break; + i = priv->eskbp / GRCAN_MSG_SIZE; + if (echo) { + /* Normal echo of messages */ + stats->tx_packets++; + stats->tx_bytes += priv->txdlc[i]; + priv->txdlc[i] = 0; + can_get_echo_skb(dev, i); + } else { + /* For cleanup of untransmitted messages */ + can_free_echo_skb(dev, i); + } + + priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE, + dma->tx.size); + txrd = grcan_read_reg(®s->txrd); + } + return work_done; +} + +static void grcan_lost_one_shot_frame(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + u32 txrd; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + catch_up_echo_skb(dev, -1, true); + + if (unlikely(grcan_read_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE))) { + /* Should never happen */ + netdev_err(dev, "TXCTRL enabled at TXLOSS in one shot mode\n"); + } else { + /* By the time an GRCAN_IRQ_TXLOSS is generated in + * one-shot mode there is no problem in writing + * to TXRD even in versions of the hardware in + * which GRCAN_TXCTRL_ONGOING is not cleared properly + * in one-shot mode. + */ + + /* Skip message and discard echo-skb */ + txrd = grcan_read_reg(®s->txrd); + txrd = grcan_ring_add(txrd, GRCAN_MSG_SIZE, dma->tx.size); + grcan_write_reg(®s->txrd, txrd); + catch_up_echo_skb(dev, -1, false); + + if (!priv->resetting && !priv->closing && + !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) { + netif_wake_queue(dev); + grcan_set_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE); + } + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void grcan_err(struct net_device *dev, u32 sources, u32 status) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + struct net_device_stats *stats = &dev->stats; + struct can_frame cf; + + /* Zero potential error_frame */ + memset(&cf, 0, sizeof(cf)); + + /* Message lost interrupt. This might be due to arbitration error, but + * is also triggered when there is no one else on the can bus or when + * there is a problem with the hardware interface or the bus itself. As + * arbitration errors can not be singled out, no error frames are + * generated reporting this event as an arbitration error. + */ + if (sources & GRCAN_IRQ_TXLOSS) { + /* Take care of failed one-shot transmit */ + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) + grcan_lost_one_shot_frame(dev); + + /* Stop printing as soon as error passive or bus off is in + * effect to limit the amount of txloss debug printouts. + */ + if (!(status & GRCAN_STAT_ERRCTR_RELATED)) { + netdev_dbg(dev, "tx message lost\n"); + stats->tx_errors++; + } + } + + /* Conditions dealing with the error counters. There is no interrupt for + * error warning, but there are interrupts for increases of the error + * counters. + */ + if ((sources & GRCAN_IRQ_ERRCTR_RELATED) || + (status & GRCAN_STAT_ERRCTR_RELATED)) { + enum can_state state = priv->can.state; + enum can_state oldstate = state; + u32 txerr = (status & GRCAN_STAT_TXERRCNT) + >> GRCAN_STAT_TXERRCNT_BIT; + u32 rxerr = (status & GRCAN_STAT_RXERRCNT) + >> GRCAN_STAT_RXERRCNT_BIT; + + /* Figure out current state */ + if (status & GRCAN_STAT_OFF) { + state = CAN_STATE_BUS_OFF; + } else if (status & GRCAN_STAT_PASS) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT || + rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + + /* Handle and report state changes */ + if (state != oldstate) { + switch (state) { + case CAN_STATE_BUS_OFF: + netdev_dbg(dev, "bus-off\n"); + netif_carrier_off(dev); + priv->can.can_stats.bus_off++; + + /* Prevent the hardware from recovering from bus + * off on its own if restart is disabled. + */ + if (!priv->can.restart_ms) + grcan_stop_hardware(dev); + + cf.can_id |= CAN_ERR_BUSOFF; + break; + + case CAN_STATE_ERROR_PASSIVE: + netdev_dbg(dev, "Error passive condition\n"); + priv->can.can_stats.error_passive++; + + cf.can_id |= CAN_ERR_CRTL; + if (txerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT) + cf.data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + if (rxerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT) + cf.data[1] |= CAN_ERR_CRTL_RX_PASSIVE; + break; + + case CAN_STATE_ERROR_WARNING: + netdev_dbg(dev, "Error warning condition\n"); + priv->can.can_stats.error_warning++; + + cf.can_id |= CAN_ERR_CRTL; + if (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT) + cf.data[1] |= CAN_ERR_CRTL_TX_WARNING; + if (rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT) + cf.data[1] |= CAN_ERR_CRTL_RX_WARNING; + break; + + case CAN_STATE_ERROR_ACTIVE: + netdev_dbg(dev, "Error active condition\n"); + cf.can_id |= CAN_ERR_CRTL; + break; + + default: + /* There are no others at this point */ + break; + } + cf.data[6] = txerr; + cf.data[7] = rxerr; + priv->can.state = state; + } + + /* Report automatic restarts */ + if (priv->can.restart_ms && oldstate == CAN_STATE_BUS_OFF) { + unsigned long flags; + + cf.can_id |= CAN_ERR_RESTARTED; + netdev_dbg(dev, "restarted\n"); + priv->can.can_stats.restarts++; + netif_carrier_on(dev); + + spin_lock_irqsave(&priv->lock, flags); + + if (!priv->resetting && !priv->closing) { + u32 txwr = grcan_read_reg(®s->txwr); + + if (grcan_txspace(dma->tx.size, txwr, + priv->eskbp)) + netif_wake_queue(dev); + } + + spin_unlock_irqrestore(&priv->lock, flags); + } + } + + /* Data overrun interrupt */ + if ((sources & GRCAN_IRQ_OR) || (status & GRCAN_STAT_OR)) { + netdev_dbg(dev, "got data overrun interrupt\n"); + stats->rx_over_errors++; + stats->rx_errors++; + + cf.can_id |= CAN_ERR_CRTL; + cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + } + + /* AHB bus error interrupts (not CAN bus errors) - shut down the + * device. + */ + if (sources & (GRCAN_IRQ_TXAHBERR | GRCAN_IRQ_RXAHBERR) || + (status & GRCAN_STAT_AHBERR)) { + char *txrx = ""; + unsigned long flags; + + if (sources & GRCAN_IRQ_TXAHBERR) { + txrx = "on tx "; + stats->tx_errors++; + } else if (sources & GRCAN_IRQ_RXAHBERR) { + txrx = "on rx "; + stats->rx_errors++; + } + netdev_err(dev, "Fatal AHB buss error %s- halting device\n", + txrx); + + spin_lock_irqsave(&priv->lock, flags); + + /* Prevent anything to be enabled again and halt device */ + priv->closing = true; + netif_stop_queue(dev); + grcan_stop_hardware(dev); + priv->can.state = CAN_STATE_STOPPED; + + spin_unlock_irqrestore(&priv->lock, flags); + } + + /* Pass on error frame if something to report, + * i.e. id contains some information + */ + if (cf.can_id) { + struct can_frame *skb_cf; + struct sk_buff *skb = alloc_can_err_skb(dev, &skb_cf); + + if (skb == NULL) { + netdev_dbg(dev, "could not allocate error frame\n"); + return; + } + skb_cf->can_id |= cf.can_id; + memcpy(skb_cf->data, cf.data, sizeof(cf.data)); + + netif_rx(skb); + } +} + +static irqreturn_t grcan_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + u32 sources, status; + + /* Find out the source */ + sources = grcan_read_reg(®s->pimsr); + if (!sources) + return IRQ_NONE; + grcan_write_reg(®s->picr, sources); + status = grcan_read_reg(®s->stat); + + /* If we got TX progress, the device has not hanged, + * so disable the hang timer + */ + if (priv->need_txbug_workaround && + (sources & (GRCAN_IRQ_TX | GRCAN_IRQ_TXLOSS))) { + del_timer(&priv->hang_timer); + } + + /* Frame(s) received or transmitted */ + if (sources & (GRCAN_IRQ_TX | GRCAN_IRQ_RX)) { + /* Disable tx/rx interrupts and schedule poll(). No need for + * locking as interference from a running reset at worst leads + * to an extra interrupt. + */ + grcan_clear_bits(®s->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX); + napi_schedule(&priv->napi); + } + + /* (Potential) error conditions to take care of */ + if (sources & GRCAN_IRQ_ERRORS) + grcan_err(dev, sources, status); + + return IRQ_HANDLED; +} + +/* Reset device and restart operations from where they were. + * + * This assumes that RXCTRL & RXCTRL is properly disabled and that RX + * is not ONGOING (TX might be stuck in ONGOING due to a harwrware bug + * for single shot) + */ +static void grcan_running_reset(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + unsigned long flags; + + /* This temporarily messes with eskbp, so we need to lock + * priv->lock + */ + spin_lock_irqsave(&priv->lock, flags); + + priv->resetting = false; + del_timer(&priv->hang_timer); + del_timer(&priv->rr_timer); + + if (!priv->closing) { + /* Save and reset - config register preserved by grcan_reset */ + u32 imr = grcan_read_reg(®s->imr); + + u32 txaddr = grcan_read_reg(®s->txaddr); + u32 txsize = grcan_read_reg(®s->txsize); + u32 txwr = grcan_read_reg(®s->txwr); + u32 txrd = grcan_read_reg(®s->txrd); + u32 eskbp = priv->eskbp; + + u32 rxaddr = grcan_read_reg(®s->rxaddr); + u32 rxsize = grcan_read_reg(®s->rxsize); + u32 rxwr = grcan_read_reg(®s->rxwr); + u32 rxrd = grcan_read_reg(®s->rxrd); + + grcan_reset(dev); + + /* Restore */ + grcan_write_reg(®s->txaddr, txaddr); + grcan_write_reg(®s->txsize, txsize); + grcan_write_reg(®s->txwr, txwr); + grcan_write_reg(®s->txrd, txrd); + priv->eskbp = eskbp; + + grcan_write_reg(®s->rxaddr, rxaddr); + grcan_write_reg(®s->rxsize, rxsize); + grcan_write_reg(®s->rxwr, rxwr); + grcan_write_reg(®s->rxrd, rxrd); + + /* Turn on device again */ + grcan_write_reg(®s->imr, imr); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + grcan_write_reg(®s->txctrl, GRCAN_TXCTRL_ENABLE + | (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT + ? GRCAN_TXCTRL_SINGLE : 0)); + grcan_write_reg(®s->rxctrl, GRCAN_RXCTRL_ENABLE); + grcan_write_reg(®s->ctrl, GRCAN_CTRL_ENABLE); + + /* Start queue if there is size and listen-onle mode is not + * enabled + */ + if (grcan_txspace(priv->dma.tx.size, txwr, priv->eskbp) && + !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) + netif_wake_queue(dev); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + netdev_err(dev, "Device reset and restored\n"); +} + +/* Waiting time in usecs corresponding to the transmission of three maximum + * sized can frames in the given bitrate (in bits/sec). Waiting for this amount + * of time makes sure that the can controller have time to finish sending or + * receiving a frame with a good margin. + * + * usecs/sec * number of frames * bits/frame / bits/sec + */ +static inline u32 grcan_ongoing_wait_usecs(__u32 bitrate) +{ + return 1000000 * 3 * GRCAN_EFF_FRAME_MAX_BITS / bitrate; +} + +/* Set timer so that it will not fire until after a period in which the can + * controller have a good margin to finish transmitting a frame unless it has + * hanged + */ +static inline void grcan_reset_timer(struct timer_list *timer, __u32 bitrate) +{ + u32 wait_jiffies = usecs_to_jiffies(grcan_ongoing_wait_usecs(bitrate)); + + mod_timer(timer, jiffies + wait_jiffies); +} + +/* Disable channels and schedule a running reset */ +static void grcan_initiate_running_reset(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + unsigned long flags; + + netdev_err(dev, "Device seems hanged - reset scheduled\n"); + + spin_lock_irqsave(&priv->lock, flags); + + /* The main body of this function must never be executed again + * until after an execution of grcan_running_reset + */ + if (!priv->resetting && !priv->closing) { + priv->resetting = true; + netif_stop_queue(dev); + grcan_clear_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE); + grcan_clear_bits(®s->rxctrl, GRCAN_RXCTRL_ENABLE); + grcan_reset_timer(&priv->rr_timer, priv->can.bittiming.bitrate); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void grcan_free_dma_buffers(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_dma *dma = &priv->dma; + + dma_free_coherent(&dev->dev, dma->base_size, dma->base_buf, + dma->base_handle); + memset(dma, 0, sizeof(*dma)); +} + +static int grcan_allocate_dma_buffers(struct net_device *dev, + size_t tsize, size_t rsize) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_dma *dma = &priv->dma; + struct grcan_dma_buffer *large = rsize > tsize ? &dma->rx : &dma->tx; + struct grcan_dma_buffer *small = rsize > tsize ? &dma->tx : &dma->rx; + size_t shift; + + /* Need a whole number of GRCAN_BUFFER_ALIGNMENT for the large, + * i.e. first buffer + */ + size_t maxs = max(tsize, rsize); + size_t lsize = ALIGN(maxs, GRCAN_BUFFER_ALIGNMENT); + + /* Put the small buffer after that */ + size_t ssize = min(tsize, rsize); + + /* Extra GRCAN_BUFFER_ALIGNMENT to allow for alignment */ + dma->base_size = lsize + ssize + GRCAN_BUFFER_ALIGNMENT; + dma->base_buf = dma_alloc_coherent(&dev->dev, + dma->base_size, + &dma->base_handle, + GFP_KERNEL); + + if (!dma->base_buf) + return -ENOMEM; + + dma->tx.size = tsize; + dma->rx.size = rsize; + + large->handle = ALIGN(dma->base_handle, GRCAN_BUFFER_ALIGNMENT); + small->handle = large->handle + lsize; + shift = large->handle - dma->base_handle; + + large->buf = dma->base_buf + shift; + small->buf = large->buf + lsize; + + return 0; +} + +/* priv->lock *must* be held when calling this function */ +static int grcan_start(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + u32 confop, txctrl; + + grcan_reset(dev); + + grcan_write_reg(®s->txaddr, priv->dma.tx.handle); + grcan_write_reg(®s->txsize, priv->dma.tx.size); + /* regs->txwr, regs->txrd and priv->eskbp already set to 0 by reset */ + + grcan_write_reg(®s->rxaddr, priv->dma.rx.handle); + grcan_write_reg(®s->rxsize, priv->dma.rx.size); + /* regs->rxwr and regs->rxrd already set to 0 by reset */ + + /* Enable interrupts */ + grcan_read_reg(®s->pir); + grcan_write_reg(®s->imr, GRCAN_IRQ_DEFAULT); + + /* Enable interfaces, channels and device */ + confop = GRCAN_CONF_ABORT + | (priv->config.enable0 ? GRCAN_CONF_ENABLE0 : 0) + | (priv->config.enable1 ? GRCAN_CONF_ENABLE1 : 0) + | (priv->config.select ? GRCAN_CONF_SELECT : 0) + | (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY ? + GRCAN_CONF_SILENT : 0) + | (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ? + GRCAN_CONF_SAM : 0); + grcan_write_bits(®s->conf, confop, GRCAN_CONF_OPERATION); + txctrl = GRCAN_TXCTRL_ENABLE + | (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT + ? GRCAN_TXCTRL_SINGLE : 0); + grcan_write_reg(®s->txctrl, txctrl); + grcan_write_reg(®s->rxctrl, GRCAN_RXCTRL_ENABLE); + grcan_write_reg(®s->ctrl, GRCAN_CTRL_ENABLE); + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + return 0; +} + +static int grcan_set_mode(struct net_device *dev, enum can_mode mode) +{ + struct grcan_priv *priv = netdev_priv(dev); + unsigned long flags; + int err = 0; + + if (mode == CAN_MODE_START) { + /* This might be called to restart the device to recover from + * bus off errors + */ + spin_lock_irqsave(&priv->lock, flags); + if (priv->closing || priv->resetting) { + err = -EBUSY; + } else { + netdev_info(dev, "Restarting device\n"); + grcan_start(dev); + if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) + netif_wake_queue(dev); + } + spin_unlock_irqrestore(&priv->lock, flags); + return err; + } + return -EOPNOTSUPP; +} + +static int grcan_open(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_dma *dma = &priv->dma; + unsigned long flags; + int err; + + /* Allocate memory */ + err = grcan_allocate_dma_buffers(dev, priv->config.txsize, + priv->config.rxsize); + if (err) { + netdev_err(dev, "could not allocate DMA buffers\n"); + return err; + } + + priv->echo_skb = kzalloc(dma->tx.size * sizeof(*priv->echo_skb), + GFP_KERNEL); + if (!priv->echo_skb) { + err = -ENOMEM; + goto exit_free_dma_buffers; + } + priv->can.echo_skb_max = dma->tx.size; + priv->can.echo_skb = priv->echo_skb; + + priv->txdlc = kzalloc(dma->tx.size * sizeof(*priv->txdlc), GFP_KERNEL); + if (!priv->txdlc) { + err = -ENOMEM; + goto exit_free_echo_skb; + } + + /* Get can device up */ + err = open_candev(dev); + if (err) + goto exit_free_txdlc; + + err = request_irq(dev->irq, grcan_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) + goto exit_close_candev; + + spin_lock_irqsave(&priv->lock, flags); + + napi_enable(&priv->napi); + grcan_start(dev); + if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) + netif_start_queue(dev); + priv->resetting = false; + priv->closing = false; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; + +exit_close_candev: + close_candev(dev); +exit_free_txdlc: + kfree(priv->txdlc); +exit_free_echo_skb: + kfree(priv->echo_skb); +exit_free_dma_buffers: + grcan_free_dma_buffers(dev); + return err; +} + +static int grcan_close(struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + unsigned long flags; + + napi_disable(&priv->napi); + + spin_lock_irqsave(&priv->lock, flags); + + priv->closing = true; + if (priv->need_txbug_workaround) { + del_timer_sync(&priv->hang_timer); + del_timer_sync(&priv->rr_timer); + } + netif_stop_queue(dev); + grcan_stop_hardware(dev); + priv->can.state = CAN_STATE_STOPPED; + + spin_unlock_irqrestore(&priv->lock, flags); + + free_irq(dev->irq, dev); + close_candev(dev); + + grcan_free_dma_buffers(dev); + priv->can.echo_skb_max = 0; + priv->can.echo_skb = NULL; + kfree(priv->echo_skb); + kfree(priv->txdlc); + + return 0; +} + +static int grcan_transmit_catch_up(struct net_device *dev, int budget) +{ + struct grcan_priv *priv = netdev_priv(dev); + unsigned long flags; + int work_done; + + spin_lock_irqsave(&priv->lock, flags); + + work_done = catch_up_echo_skb(dev, budget, true); + if (work_done) { + if (!priv->resetting && !priv->closing && + !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) + netif_wake_queue(dev); + + /* With napi we don't get TX interrupts for a while, + * so prevent a running reset while catching up + */ + if (priv->need_txbug_workaround) + del_timer(&priv->hang_timer); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return work_done; +} + +static int grcan_receive(struct net_device *dev, int budget) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 wr, rd, startrd; + u32 *slot; + u32 i, rtr, eff, j, shift; + int work_done = 0; + + rd = grcan_read_reg(®s->rxrd); + startrd = rd; + for (work_done = 0; work_done < budget; work_done++) { + /* Check for packet to receive */ + wr = grcan_read_reg(®s->rxwr); + if (rd == wr) + break; + + /* Take care of packet */ + skb = alloc_can_skb(dev, &cf); + if (skb == NULL) { + netdev_err(dev, + "dropping frame: skb allocation failed\n"); + stats->rx_dropped++; + continue; + } + + slot = dma->rx.buf + rd; + eff = slot[0] & GRCAN_MSG_IDE; + rtr = slot[0] & GRCAN_MSG_RTR; + if (eff) { + cf->can_id = ((slot[0] & GRCAN_MSG_EID) + >> GRCAN_MSG_EID_BIT); + cf->can_id |= CAN_EFF_FLAG; + } else { + cf->can_id = ((slot[0] & GRCAN_MSG_BID) + >> GRCAN_MSG_BID_BIT); + } + cf->can_dlc = get_can_dlc((slot[1] & GRCAN_MSG_DLC) + >> GRCAN_MSG_DLC_BIT); + if (rtr) { + cf->can_id |= CAN_RTR_FLAG; + } else { + for (i = 0; i < cf->can_dlc; i++) { + j = GRCAN_MSG_DATA_SLOT_INDEX(i); + shift = GRCAN_MSG_DATA_SHIFT(i); + 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; + rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size); + } + + /* Make sure everything is read before allowing hardware to + * use the memory + */ + mb(); + + /* Update read pointer - no need to check for ongoing */ + if (likely(rd != startrd)) + grcan_write_reg(®s->rxrd, rd); + + return work_done; +} + +static int grcan_poll(struct napi_struct *napi, int budget) +{ + struct grcan_priv *priv = container_of(napi, struct grcan_priv, napi); + struct net_device *dev = priv->dev; + struct grcan_registers __iomem *regs = priv->regs; + unsigned long flags; + int tx_work_done, rx_work_done; + int rx_budget = budget / 2; + int tx_budget = budget - rx_budget; + + /* Half of the budget for receiveing messages */ + rx_work_done = grcan_receive(dev, rx_budget); + + /* Half of the budget for transmitting messages as that can trigger echo + * frames being received + */ + tx_work_done = grcan_transmit_catch_up(dev, tx_budget); + + if (rx_work_done < rx_budget && tx_work_done < tx_budget) { + napi_complete(napi); + + /* Guarantee no interference with a running reset that otherwise + * could turn off interrupts. + */ + spin_lock_irqsave(&priv->lock, flags); + + /* Enable tx and rx interrupts again. No need to check + * priv->closing as napi_disable in grcan_close is waiting for + * scheduled napi calls to finish. + */ + grcan_set_bits(®s->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX); + + spin_unlock_irqrestore(&priv->lock, flags); + } + + return rx_work_done + tx_work_done; +} + +/* Work tx bug by waiting while for the risky situation to clear. If that fails, + * drop a frame in one-shot mode or indicate a busy device otherwise. + * + * Returns 0 on successful wait. Otherwise it sets *netdev_tx_status to the + * value that should be returned by grcan_start_xmit when aborting the xmit. + */ +static int grcan_txbug_workaround(struct net_device *dev, struct sk_buff *skb, + u32 txwr, u32 oneshotmode, + netdev_tx_t *netdev_tx_status) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + int i; + unsigned long flags; + + /* Wait a while for ongoing to be cleared or read pointer to catch up to + * write pointer. The latter is needed due to a bug in older versions of + * GRCAN in which ONGOING is not cleared properly one-shot mode when a + * transmission fails. + */ + for (i = 0; i < GRCAN_SHORTWAIT_USECS; i++) { + udelay(1); + if (!grcan_read_bits(®s->txctrl, GRCAN_TXCTRL_ONGOING) || + grcan_read_reg(®s->txrd) == txwr) { + return 0; + } + } + + /* Clean up, in case the situation was not resolved */ + spin_lock_irqsave(&priv->lock, flags); + if (!priv->resetting && !priv->closing) { + /* Queue might have been stopped earlier in grcan_start_xmit */ + if (grcan_txspace(dma->tx.size, txwr, priv->eskbp)) + netif_wake_queue(dev); + /* Set a timer to resolve a hanged tx controller */ + if (!timer_pending(&priv->hang_timer)) + grcan_reset_timer(&priv->hang_timer, + priv->can.bittiming.bitrate); + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (oneshotmode) { + /* In one-shot mode we should never end up here because + * then the interrupt handler increases txrd on TXLOSS, + * but it is consistent with one-shot mode to drop the + * frame in this case. + */ + kfree_skb(skb); + *netdev_tx_status = NETDEV_TX_OK; + } else { + /* In normal mode the socket-can transmission queue get + * to keep the frame so that it can be retransmitted + * later + */ + *netdev_tx_status = NETDEV_TX_BUSY; + } + return -EBUSY; +} + +/* Notes on the tx cyclic buffer handling: + * + * regs->txwr - the next slot for the driver to put data to be sent + * regs->txrd - the next slot for the device to read data + * priv->eskbp - the next slot for the driver to call can_put_echo_skb for + * + * grcan_start_xmit can enter more messages as long as regs->txwr does + * not reach priv->eskbp (within 1 message gap) + * + * The device sends messages until regs->txrd reaches regs->txwr + * + * The interrupt calls handler calls can_put_echo_skb until + * priv->eskbp reaches regs->txrd + */ +static netdev_tx_t grcan_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct grcan_priv *priv = netdev_priv(dev); + struct grcan_registers __iomem *regs = priv->regs; + struct grcan_dma *dma = &priv->dma; + struct can_frame *cf = (struct can_frame *)skb->data; + u32 id, txwr, txrd, space, txctrl; + int slotindex; + u32 *slot; + u32 i, rtr, eff, dlc, tmp, err; + int j, shift; + unsigned long flags; + u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT; + + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + + /* Trying to transmit in silent mode will generate error interrupts, but + * this should never happen - the queue should not have been started. + */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + return NETDEV_TX_BUSY; + + /* Reads of priv->eskbp and shut-downs of the queue needs to + * be atomic towards the updates to priv->eskbp and wake-ups + * of the queue in the interrupt handler. + */ + spin_lock_irqsave(&priv->lock, flags); + + txwr = grcan_read_reg(®s->txwr); + space = grcan_txspace(dma->tx.size, txwr, priv->eskbp); + + slotindex = txwr / GRCAN_MSG_SIZE; + slot = dma->tx.buf + txwr; + + if (unlikely(space == 1)) + netif_stop_queue(dev); + + spin_unlock_irqrestore(&priv->lock, flags); + /* End of critical section*/ + + /* This should never happen. If circular buffer is full, the + * netif_stop_queue should have been stopped already. + */ + if (unlikely(!space)) { + netdev_err(dev, "No buffer space, but queue is non-stopped.\n"); + return NETDEV_TX_BUSY; + } + + /* Convert and write CAN message to DMA buffer */ + eff = cf->can_id & CAN_EFF_FLAG; + rtr = cf->can_id & CAN_RTR_FLAG; + id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK); + dlc = cf->can_dlc; + if (eff) + tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID; + else + tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID; + slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp; + + slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC); + slot[2] = 0; + slot[3] = 0; + for (i = 0; i < dlc; i++) { + j = GRCAN_MSG_DATA_SLOT_INDEX(i); + shift = GRCAN_MSG_DATA_SHIFT(i); + slot[j] |= cf->data[i] << shift; + } + + /* Checking that channel has not been disabled. These cases + * should never happen + */ + txctrl = grcan_read_reg(®s->txctrl); + if (!(txctrl & GRCAN_TXCTRL_ENABLE)) + netdev_err(dev, "tx channel spuriously disabled\n"); + + if (oneshotmode && !(txctrl & GRCAN_TXCTRL_SINGLE)) + netdev_err(dev, "one-shot mode spuriously disabled\n"); + + /* Bug workaround for old version of grcan where updating txwr + * in the same clock cycle as the controller updates txrd to + * the current txwr could hang the can controller + */ + if (priv->need_txbug_workaround) { + txrd = grcan_read_reg(®s->txrd); + if (unlikely(grcan_ring_sub(txwr, txrd, dma->tx.size) == 1)) { + netdev_tx_t txstatus; + + err = grcan_txbug_workaround(dev, skb, txwr, + oneshotmode, &txstatus); + if (err) + return txstatus; + } + } + + /* Prepare skb for echoing. This must be after the bug workaround above + * as ownership of the skb is passed on by calling can_put_echo_skb. + * Returning NETDEV_TX_BUSY or accessing skb or cf after a call to + * can_put_echo_skb would be an error unless other measures are + * taken. + */ + priv->txdlc[slotindex] = cf->can_dlc; /* Store dlc for statistics */ + can_put_echo_skb(skb, dev, slotindex); + + /* Make sure everything is written before allowing hardware to + * read from the memory + */ + wmb(); + + /* Update write pointer to start transmission */ + grcan_write_reg(®s->txwr, + grcan_ring_add(txwr, GRCAN_MSG_SIZE, dma->tx.size)); + + return NETDEV_TX_OK; +} + +/* ========== Setting up sysfs interface and module parameters ========== */ + +#define GRCAN_NOT_BOOL(unsigned_val) ((unsigned_val) > 1) + +#define GRCAN_MODULE_PARAM(name, mtype, valcheckf, desc) \ + static void grcan_sanitize_##name(struct platform_device *pd) \ + { \ + struct grcan_device_config grcan_default_config \ + = GRCAN_DEFAULT_DEVICE_CONFIG; \ + if (valcheckf(grcan_module_config.name)) { \ + dev_err(&pd->dev, \ + "Invalid module parameter value for " \ + #name " - setting default\n"); \ + grcan_module_config.name = \ + grcan_default_config.name; \ + } \ + } \ + module_param_named(name, grcan_module_config.name, \ + mtype, S_IRUGO); \ + MODULE_PARM_DESC(name, desc) + +#define GRCAN_CONFIG_ATTR(name, desc) \ + static ssize_t grcan_store_##name(struct device *sdev, \ + struct device_attribute *att, \ + const char *buf, \ + size_t count) \ + { \ + struct net_device *dev = to_net_dev(sdev); \ + struct grcan_priv *priv = netdev_priv(dev); \ + u8 val; \ + int ret; \ + if (dev->flags & IFF_UP) \ + return -EBUSY; \ + ret = kstrtou8(buf, 0, &val); \ + if (ret < 0 || val > 1) \ + return -EINVAL; \ + priv->config.name = val; \ + return count; \ + } \ + static ssize_t grcan_show_##name(struct device *sdev, \ + struct device_attribute *att, \ + char *buf) \ + { \ + struct net_device *dev = to_net_dev(sdev); \ + struct grcan_priv *priv = netdev_priv(dev); \ + return sprintf(buf, "%d\n", priv->config.name); \ + } \ + static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \ + grcan_show_##name, \ + grcan_store_##name); \ + GRCAN_MODULE_PARAM(name, ushort, GRCAN_NOT_BOOL, desc) + +/* The following configuration options are made available both via module + * parameters and writable sysfs files. See the chapter about GRCAN in the + * documentation for the GRLIB VHDL library for further details. + */ +GRCAN_CONFIG_ATTR(enable0, + "Configuration of physical interface 0. Determines\n" \ + "the \"Enable 0\" bit of the configuration register.\n" \ + "Format: 0 | 1\nDefault: 0\n"); + +GRCAN_CONFIG_ATTR(enable1, + "Configuration of physical interface 1. Determines\n" \ + "the \"Enable 1\" bit of the configuration register.\n" \ + "Format: 0 | 1\nDefault: 0\n"); + +GRCAN_CONFIG_ATTR(select, + "Select which physical interface to use.\n" \ + "Format: 0 | 1\nDefault: 0\n"); + +/* The tx and rx buffer size configuration options are only available via module + * parameters. + */ +GRCAN_MODULE_PARAM(txsize, uint, GRCAN_INVALID_BUFFER_SIZE, + "Sets the size of the tx buffer.\n" \ + "Format: <unsigned int> where (txsize & ~0x1fffc0) == 0\n" \ + "Default: 1024\n"); +GRCAN_MODULE_PARAM(rxsize, uint, GRCAN_INVALID_BUFFER_SIZE, + "Sets the size of the rx buffer.\n" \ + "Format: <unsigned int> where (size & ~0x1fffc0) == 0\n" \ + "Default: 1024\n"); + +/* Function that makes sure that configuration done using + * module parameters are set to valid values + */ +static void grcan_sanitize_module_config(struct platform_device *ofdev) +{ + grcan_sanitize_enable0(ofdev); + grcan_sanitize_enable1(ofdev); + grcan_sanitize_select(ofdev); + grcan_sanitize_txsize(ofdev); + grcan_sanitize_rxsize(ofdev); +} + +static const struct attribute *const sysfs_grcan_attrs[] = { + /* Config attrs */ + &dev_attr_enable0.attr, + &dev_attr_enable1.attr, + &dev_attr_select.attr, + NULL, +}; + +static const struct attribute_group sysfs_grcan_group = { + .name = "grcan", + .attrs = (struct attribute **)sysfs_grcan_attrs, +}; + +/* ========== Setting up the driver ========== */ + +static const struct net_device_ops grcan_netdev_ops = { + .ndo_open = grcan_open, + .ndo_stop = grcan_close, + .ndo_start_xmit = grcan_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static int grcan_setup_netdev(struct platform_device *ofdev, + void __iomem *base, + int irq, u32 ambafreq, bool txbug) +{ + struct net_device *dev; + struct grcan_priv *priv; + struct grcan_registers __iomem *regs; + int err; + + dev = alloc_candev(sizeof(struct grcan_priv), 0); + if (!dev) + return -ENOMEM; + + dev->irq = irq; + dev->flags |= IFF_ECHO; + dev->netdev_ops = &grcan_netdev_ops; + dev->sysfs_groups[0] = &sysfs_grcan_group; + + priv = netdev_priv(dev); + memcpy(&priv->config, &grcan_module_config, + sizeof(struct grcan_device_config)); + priv->dev = dev; + priv->regs = base; + priv->can.bittiming_const = &grcan_bittiming_const; + priv->can.do_set_bittiming = grcan_set_bittiming; + priv->can.do_set_mode = grcan_set_mode; + priv->can.do_get_berr_counter = grcan_get_berr_counter; + priv->can.clock.freq = ambafreq; + priv->can.ctrlmode_supported = + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT; + priv->need_txbug_workaround = txbug; + + /* Discover if triple sampling is supported by hardware */ + regs = priv->regs; + grcan_set_bits(®s->ctrl, GRCAN_CTRL_RESET); + grcan_set_bits(®s->conf, GRCAN_CONF_SAM); + if (grcan_read_bits(®s->conf, GRCAN_CONF_SAM)) { + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + dev_dbg(&ofdev->dev, "Hardware supports triple-sampling\n"); + } + + spin_lock_init(&priv->lock); + + if (priv->need_txbug_workaround) { + init_timer(&priv->rr_timer); + priv->rr_timer.function = grcan_running_reset; + priv->rr_timer.data = (unsigned long)dev; + + init_timer(&priv->hang_timer); + priv->hang_timer.function = grcan_initiate_running_reset; + priv->hang_timer.data = (unsigned long)dev; + } + + netif_napi_add(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT); + + SET_NETDEV_DEV(dev, &ofdev->dev); + dev_info(&ofdev->dev, "regs=0x%p, irq=%d, clock=%d\n", + priv->regs, dev->irq, priv->can.clock.freq); + + err = register_candev(dev); + if (err) + goto exit_free_candev; + + platform_set_drvdata(ofdev, dev); + + /* Reset device to allow bit-timing to be set. No need to call + * grcan_reset at this stage. That is done in grcan_open. + */ + grcan_write_reg(®s->ctrl, GRCAN_CTRL_RESET); + + return 0; +exit_free_candev: + free_candev(dev); + return err; +} + +static int grcan_probe(struct platform_device *ofdev) +{ + struct device_node *np = ofdev->dev.of_node; + struct resource *res; + u32 sysid, ambafreq; + int irq, err; + void __iomem *base; + bool txbug = true; + + /* Compare GRLIB version number with the first that does not + * have the tx bug (see start_xmit) + */ + err = of_property_read_u32(np, "systemid", &sysid); + if (!err && ((sysid & GRLIB_VERSION_MASK) + >= GRCAN_TXBUG_SAFE_GRLIB_VERSION)) + txbug = false; + + err = of_property_read_u32(np, "freq", &ambafreq); + if (err) { + dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n"); + goto exit_error; + } + + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(base)) { + err = PTR_ERR(base); + goto exit_error; + } + + irq = irq_of_parse_and_map(np, GRCAN_IRQIX_IRQ); + if (!irq) { + dev_err(&ofdev->dev, "no irq found\n"); + err = -ENODEV; + goto exit_error; + } + + grcan_sanitize_module_config(ofdev); + + err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug); + if (err) + goto exit_dispose_irq; + + return 0; + +exit_dispose_irq: + irq_dispose_mapping(irq); +exit_error: + dev_err(&ofdev->dev, + "%s socket CAN driver initialization failed with error %d\n", + DRV_NAME, err); + return err; +} + +static int grcan_remove(struct platform_device *ofdev) +{ + struct net_device *dev = platform_get_drvdata(ofdev); + struct grcan_priv *priv = netdev_priv(dev); + + unregister_candev(dev); /* Will in turn call grcan_close */ + + irq_dispose_mapping(dev->irq); + netif_napi_del(&priv->napi); + free_candev(dev); + + return 0; +} + +static struct of_device_id grcan_match[] = { + {.name = "GAISLER_GRCAN"}, + {.name = "01_03d"}, + {.name = "GAISLER_GRHCAN"}, + {.name = "01_034"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, grcan_match); + +static struct platform_driver grcan_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = grcan_match, + }, + .probe = grcan_probe, + .remove = grcan_remove, +}; + +module_platform_driver(grcan_driver); + +MODULE_AUTHOR("Aeroflex Gaisler AB."); +MODULE_DESCRIPTION("Socket CAN driver for Aeroflex Gaisler GRCAN"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 7edadee487b..2382c04dc78 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/platform_device.h> @@ -19,6 +18,7 @@ #include <linux/netdevice.h> #include <linux/can.h> #include <linux/can/dev.h> +#include <linux/can/skb.h> #include <linux/can/error.h> #include <linux/mfd/janz.h> @@ -198,9 +198,6 @@ struct ican3_dev { struct net_device *ndev; struct napi_struct napi; - /* Device for printing */ - struct device *dev; - /* module number */ unsigned int num; @@ -295,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_RB_MASK) == 0x00) { - dev_dbg(mod->dev, "no mbox for reading\n"); + netdev_dbg(mod->ndev, "no mbox for reading\n"); return -ENOMEM; } @@ -340,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) { - dev_err(mod->dev, "no mbox for writing\n"); + netdev_err(mod->ndev, "no mbox for writing\n"); return -ENOMEM; } @@ -365,7 +362,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) * ICAN3 "new-style" Host Interface Setup */ -static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod) +static void ican3_init_new_host_interface(struct ican3_dev *mod) { struct ican3_new_desc desc; unsigned long flags; @@ -444,7 +441,7 @@ static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod) * ICAN3 Fast Host Interface Setup */ -static void __devinit ican3_init_fast_host_interface(struct ican3_dev *mod) +static void ican3_init_fast_host_interface(struct ican3_dev *mod) { struct ican3_fast_desc desc; unsigned long flags; @@ -542,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no free buffers\n", __func__); + netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__); return -ENOMEM; } @@ -573,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__); + netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__); return -ENOMEM; } @@ -631,7 +628,7 @@ static int ican3_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) * Quick Pre-constructed Messages */ -static int __devinit ican3_msg_connect(struct ican3_dev *mod) +static int ican3_msg_connect(struct ican3_dev *mod) { struct ican3_msg msg; @@ -642,7 +639,7 @@ static int __devinit ican3_msg_connect(struct ican3_dev *mod) return ican3_send_msg(mod, &msg); } -static int __devexit ican3_msg_disconnect(struct ican3_dev *mod) +static int ican3_msg_disconnect(struct ican3_dev *mod) { struct ican3_msg msg; @@ -653,7 +650,7 @@ static int __devexit ican3_msg_disconnect(struct ican3_dev *mod) return ican3_send_msg(mod, &msg); } -static int __devinit ican3_msg_newhostif(struct ican3_dev *mod) +static int ican3_msg_newhostif(struct ican3_dev *mod) { struct ican3_msg msg; int ret; @@ -674,7 +671,7 @@ static int __devinit ican3_msg_newhostif(struct ican3_dev *mod) return 0; } -static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod) +static int ican3_msg_fasthostif(struct ican3_dev *mod) { struct ican3_msg msg; unsigned int addr; @@ -707,7 +704,7 @@ static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod) * Setup the CAN filter to either accept or reject all * messages from the CAN bus. */ -static int __devinit ican3_set_id_filter(struct ican3_dev *mod, bool accept) +static int ican3_set_id_filter(struct ican3_dev *mod, bool accept) { struct ican3_msg msg; int ret; @@ -883,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod, */ static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data); + netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data); } static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) @@ -899,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) * error frame for userspace */ if (msg->spec == MSG_MSGLOST) { - dev_err(mod->dev, "lost %d control messages\n", msg->data[0]); + netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]); return; } @@ -939,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* we can only handle the SJA1000 part */ if (msg->data[1] != CEVTIND_CHIP_SJA1000) { - dev_err(mod->dev, "unable to handle errors on non-SJA1000\n"); + netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n"); return -ENODEV; } /* check the message length for sanity */ if (le16_to_cpu(msg->len) < 6) { - dev_err(mod->dev, "error message too short\n"); + netdev_err(mod->ndev, "error message too short\n"); return -EINVAL; } @@ -967,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ if (isrc == CEVTIND_BEI) { int ret; - dev_dbg(mod->dev, "bus error interrupt\n"); + netdev_dbg(mod->ndev, "bus error interrupt\n"); /* TX error */ if (!(ecc & ECC_DIR)) { @@ -983,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to re-enable bus-error\n"); + netdev_err(mod->ndev, "unable to re-enable bus-error\n"); return ret; } @@ -998,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* data overrun interrupt */ if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) { - dev_dbg(mod->dev, "data overrun interrupt\n"); + netdev_dbg(mod->ndev, "data overrun interrupt\n"); cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; @@ -1007,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* error warning + passive interrupt */ if (isrc == CEVTIND_EI) { - dev_dbg(mod->dev, "error warning + passive interrupt\n"); + netdev_dbg(mod->ndev, "error warning + passive interrupt\n"); if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; @@ -1088,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) complete(&mod->termination_comp); break; default: - dev_err(mod->dev, "received an unknown inquiry response\n"); + netdev_err(mod->ndev, "received an unknown inquiry response\n"); break; } } @@ -1096,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) static void ican3_handle_unknown_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n", + netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n", msg->spec, le16_to_cpu(msg->len)); } @@ -1105,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod, */ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, + netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, mod->num, msg->spec, le16_to_cpu(msg->len)); switch (msg->spec) { @@ -1134,20 +1131,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) */ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) { - struct sock *srcsk = skb->sk; - - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else { - skb_orphan(skb); - } - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* save this skb for tx interrupt echo handling */ skb_queue_tail(&mod->echoq, skb); @@ -1323,7 +1309,7 @@ static int ican3_napi(struct napi_struct *napi, int budget) /* process all communication messages */ while (true) { - struct ican3_msg msg; + struct ican3_msg uninitialized_var(msg); ret = ican3_recv_msg(mod, &msg); if (ret) break; @@ -1417,11 +1403,11 @@ static int ican3_reset_module(struct ican3_dev *mod) msleep(10); } while (time_before(jiffies, start + HZ / 4)); - dev_err(mod->dev, "failed to reset CAN module\n"); + netdev_err(mod->ndev, "failed to reset CAN module\n"); return -ETIMEDOUT; } -static void __devexit ican3_shutdown_module(struct ican3_dev *mod) +static void ican3_shutdown_module(struct ican3_dev *mod) { ican3_msg_disconnect(mod); ican3_reset_module(mod); @@ -1430,13 +1416,13 @@ static void __devexit ican3_shutdown_module(struct ican3_dev *mod) /* * Startup an ICAN module, bringing it into fast mode */ -static int __devinit ican3_startup_module(struct ican3_dev *mod) +static int ican3_startup_module(struct ican3_dev *mod) { int ret; ret = ican3_reset_module(mod); if (ret) { - dev_err(mod->dev, "unable to reset module\n"); + netdev_err(mod->ndev, "unable to reset module\n"); return ret; } @@ -1445,41 +1431,41 @@ static int __devinit ican3_startup_module(struct ican3_dev *mod) ret = ican3_msg_connect(mod); if (ret) { - dev_err(mod->dev, "unable to connect to module\n"); + netdev_err(mod->ndev, "unable to connect to module\n"); return ret; } ican3_init_new_host_interface(mod); ret = ican3_msg_newhostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to new-style interface\n"); + netdev_err(mod->ndev, "unable to switch to new-style interface\n"); return ret; } /* default to "termination on" */ ret = ican3_set_termination(mod, true); if (ret) { - dev_err(mod->dev, "unable to enable termination\n"); + netdev_err(mod->ndev, "unable to enable termination\n"); return ret; } /* default to "bus errors enabled" */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to set bus-error\n"); + netdev_err(mod->ndev, "unable to set bus-error\n"); return ret; } ican3_init_fast_host_interface(mod); ret = ican3_msg_fasthostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to fast host interface\n"); + netdev_err(mod->ndev, "unable to switch to fast host interface\n"); return ret; } ret = ican3_set_id_filter(mod, true); if (ret) { - dev_err(mod->dev, "unable to set acceptance filter\n"); + netdev_err(mod->ndev, "unable to set acceptance filter\n"); return ret; } @@ -1498,14 +1484,14 @@ static int ican3_open(struct net_device *ndev) /* open the CAN layer */ ret = open_candev(ndev); if (ret) { - dev_err(mod->dev, "unable to start CAN layer\n"); + netdev_err(mod->ndev, "unable to start CAN layer\n"); return ret; } /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(mod->ndev, "unable to set bus-on\n"); close_candev(ndev); return ret; } @@ -1529,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev) /* bring the bus offline, stop receiving packets */ ret = ican3_set_bus_state(mod, false); if (ret) { - dev_err(mod->dev, "unable to set bus-off\n"); + netdev_err(mod->ndev, "unable to set bus-off\n"); return ret; } @@ -1556,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev) /* check that we can actually transmit */ if (!ican3_txok(mod)) { - dev_err(mod->dev, "BUG: no free descriptors\n"); + netdev_err(mod->ndev, "BUG: no free descriptors\n"); spin_unlock_irqrestore(&mod->lock, flags); return NETDEV_TX_BUSY; } @@ -1608,6 +1594,7 @@ static const struct net_device_ops ican3_netdev_ops = { .ndo_open = ican3_open, .ndo_stop = ican3_stop, .ndo_start_xmit = ican3_xmit, + .ndo_change_mtu = can_change_mtu, }; /* @@ -1668,7 +1655,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode) /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(ndev, "unable to set bus-on\n"); return ret; } @@ -1692,8 +1679,8 @@ static int ican3_get_berr_counter(const struct net_device *ndev, return ret; ret = wait_for_completion_timeout(&mod->buserror_comp, HZ); - if (ret <= 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + if (ret == 0) { + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1718,8 +1705,8 @@ static ssize_t ican3_sysfs_show_term(struct device *dev, return ret; ret = wait_for_completion_timeout(&mod->termination_comp, HZ); - if (ret <= 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + if (ret == 0) { + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1734,7 +1721,7 @@ static ssize_t ican3_sysfs_set_term(struct device *dev, unsigned long enable; int ret; - if (strict_strtoul(buf, 0, &enable)) + if (kstrtoul(buf, 0, &enable)) return -EINVAL; ret = ican3_set_termination(mod, enable); @@ -1760,7 +1747,7 @@ static struct attribute_group ican3_sysfs_attr_group = { * PCI Subsystem */ -static int __devinit ican3_probe(struct platform_device *pdev) +static int ican3_probe(struct platform_device *pdev) { struct janz_platform_data *pdata; struct net_device *ndev; @@ -1769,7 +1756,7 @@ static int __devinit ican3_probe(struct platform_device *pdev) struct device *dev; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) return -ENXIO; @@ -1789,7 +1776,6 @@ static int __devinit ican3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); mod = netdev_priv(ndev); mod->ndev = ndev; - mod->dev = &pdev->dev; mod->num = pdata->modno; netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS); skb_queue_head_init(&mod->echoq); @@ -1898,7 +1884,7 @@ out_return: return ret; } -static int __devexit ican3_remove(struct platform_device *pdev) +static int ican3_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct ican3_dev *mod = netdev_priv(ndev); @@ -1927,7 +1913,7 @@ static struct platform_driver ican3_driver = { .owner = THIS_MODULE, }, .probe = ican3_probe, - .remove = __devexit_p(ican3_remove), + .remove = ican3_remove, }; module_platform_driver(ican3_driver); diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c new file mode 100644 index 00000000000..ab7f1b01be4 --- /dev/null +++ b/drivers/net/can/led.c @@ -0,0 +1,127 @@ +/* + * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> + * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/can/dev.h> + +#include <linux/can/led.h> + +static unsigned long led_delay = 50; +module_param(led_delay, ulong, 0644); +MODULE_PARM_DESC(led_delay, + "blink delay time for activity leds (msecs, default: 50)."); + +/* Trigger a LED event in response to a CAN device event */ +void can_led_event(struct net_device *netdev, enum can_led_event event) +{ + struct can_priv *priv = netdev_priv(netdev); + + switch (event) { + case CAN_LED_EVENT_OPEN: + led_trigger_event(priv->tx_led_trig, LED_FULL); + led_trigger_event(priv->rx_led_trig, LED_FULL); + break; + case CAN_LED_EVENT_STOP: + led_trigger_event(priv->tx_led_trig, LED_OFF); + led_trigger_event(priv->rx_led_trig, LED_OFF); + break; + case CAN_LED_EVENT_TX: + if (led_delay) + led_trigger_blink_oneshot(priv->tx_led_trig, + &led_delay, &led_delay, 1); + break; + case CAN_LED_EVENT_RX: + if (led_delay) + led_trigger_blink_oneshot(priv->rx_led_trig, + &led_delay, &led_delay, 1); + break; + } +} +EXPORT_SYMBOL_GPL(can_led_event); + +static void can_led_release(struct device *gendev, void *res) +{ + struct can_priv *priv = netdev_priv(to_net_dev(gendev)); + + led_trigger_unregister_simple(priv->tx_led_trig); + led_trigger_unregister_simple(priv->rx_led_trig); +} + +/* Register CAN LED triggers for a CAN device + * + * This is normally called from a driver's probe function + */ +void devm_can_led_init(struct net_device *netdev) +{ + struct can_priv *priv = netdev_priv(netdev); + void *res; + + res = devres_alloc(can_led_release, 0, GFP_KERNEL); + if (!res) { + netdev_err(netdev, "cannot register LED triggers\n"); + return; + } + + snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name), + "%s-tx", netdev->name); + snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name), + "%s-rx", netdev->name); + + led_trigger_register_simple(priv->tx_led_trig_name, + &priv->tx_led_trig); + led_trigger_register_simple(priv->rx_led_trig_name, + &priv->rx_led_trig); + + devres_add(&netdev->dev, res); +} +EXPORT_SYMBOL_GPL(devm_can_led_init); + +/* NETDEV rename notifier to rename the associated led triggers too */ +static int can_led_notifier(struct notifier_block *nb, unsigned long msg, + void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct can_priv *priv = safe_candev_priv(netdev); + char name[CAN_LED_NAME_SZ]; + + if (!priv) + return NOTIFY_DONE; + + if (!priv->tx_led_trig || !priv->rx_led_trig) + return NOTIFY_DONE; + + if (msg == NETDEV_CHANGENAME) { + snprintf(name, sizeof(name), "%s-tx", netdev->name); + led_trigger_rename_static(name, priv->tx_led_trig); + + snprintf(name, sizeof(name), "%s-rx", netdev->name); + led_trigger_rename_static(name, priv->rx_led_trig); + } + + return NOTIFY_DONE; +} + +/* notifier block for netdevice event */ +static struct notifier_block can_netdev_notifier __read_mostly = { + .notifier_call = can_led_notifier, +}; + +int __init can_led_notifier_init(void) +{ + return register_netdevice_notifier(&can_netdev_notifier); +} + +void __exit can_led_notifier_exit(void) +{ + unregister_netdevice_notifier(&can_netdev_notifier); +} diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig index d38706958af..81c71171949 100644 --- a/drivers/net/can/mscan/Kconfig +++ b/drivers/net/can/mscan/Kconfig @@ -1,5 +1,5 @@ config CAN_MSCAN - depends on CAN_DEV && (PPC || M68K) + depends on PPC tristate "Support for Freescale MSCAN based chips" ---help--- The Motorola Scalable Controller Area Network (MSCAN) definition diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 799c354083c..44725296f72 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -40,17 +39,17 @@ struct mpc5xxx_can_data { unsigned int type; u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name, int *mscan_clksrc); + void (*put_clock)(struct platform_device *ofdev); }; #ifdef CONFIG_PPC_MPC52xx -static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = { +static struct of_device_id mpc52xx_cdm_ids[] = { { .compatible = "fsl,mpc5200-cdm", }, {} }; -static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev, - const char *clock_name, - int *mscan_clksrc) +static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, + const char *clock_name, int *mscan_clksrc) { unsigned int pvr; struct mpc52xx_cdm __iomem *cdm; @@ -101,154 +100,190 @@ static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev, return freq; } #else /* !CONFIG_PPC_MPC52xx */ -static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev, - const char *clock_name, - int *mscan_clksrc) +static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, + const char *clock_name, int *mscan_clksrc) { return 0; } #endif /* CONFIG_PPC_MPC52xx */ #ifdef CONFIG_PPC_MPC512x -struct mpc512x_clockctl { - u32 spmr; /* System PLL Mode Reg */ - u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ - u32 scfr1; /* System Clk Freq Reg 1 */ - u32 scfr2; /* System Clk Freq Reg 2 */ - u32 reserved; - u32 bcr; /* Bread Crumb Reg */ - u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */ - u32 spccr; /* SPDIF Clk Ctrl Reg */ - u32 cccr; /* CFM Clk Ctrl Reg */ - u32 dccr; /* DIU Clk Cnfg Reg */ - u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */ -}; - -static struct of_device_id __devinitdata mpc512x_clock_ids[] = { - { .compatible = "fsl,mpc5121-clock", }, - {} -}; - -static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, - const char *clock_name, - int *mscan_clksrc) +static u32 mpc512x_can_get_clock(struct platform_device *ofdev, + const char *clock_source, int *mscan_clksrc) { - struct mpc512x_clockctl __iomem *clockctl; - struct device_node *np_clock; - struct clk *sys_clk, *ref_clk; - int plen, clockidx, clocksrc = -1; - u32 sys_freq, val, clockdiv = 1, freq = 0; - const u32 *pval; - - np_clock = of_find_matching_node(NULL, mpc512x_clock_ids); - if (!np_clock) { - dev_err(&ofdev->dev, "couldn't find clock node\n"); - return 0; + struct device_node *np; + u32 clockdiv; + enum { + CLK_FROM_AUTO, + CLK_FROM_IPS, + CLK_FROM_SYS, + CLK_FROM_REF, + } clk_from; + struct clk *clk_in, *clk_can; + unsigned long freq_calc; + struct mscan_priv *priv; + struct clk *clk_ipg; + + /* the caller passed in the clock source spec that was read from + * the device tree, get the optional clock divider as well + */ + np = ofdev->dev.of_node; + clockdiv = 1; + of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv); + dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n", + clock_source ? clock_source : "<NULL>", clockdiv); + + /* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to + * get set, and the 'ips' clock is the input to the MSCAN + * component + * + * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC] + * bit needs to get cleared, an optional clock-divider may have + * been specified (the default value is 1), the appropriate + * MSCAN related MCLK is the input to the MSCAN component + * + * in the absence of a clock-source spec, first an optimal clock + * gets determined based on the 'sys' clock, if that fails the + * 'ref' clock is used + */ + clk_from = CLK_FROM_AUTO; + if (clock_source) { + /* interpret the device tree's spec for the clock source */ + if (!strcmp(clock_source, "ip")) + clk_from = CLK_FROM_IPS; + else if (!strcmp(clock_source, "sys")) + clk_from = CLK_FROM_SYS; + else if (!strcmp(clock_source, "ref")) + clk_from = CLK_FROM_REF; + else + goto err_invalid; + dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from); } - clockctl = of_iomap(np_clock, 0); - if (!clockctl) { - dev_err(&ofdev->dev, "couldn't map clock registers\n"); - goto exit_put; + if (clk_from == CLK_FROM_AUTO) { + /* no spec so far, try the 'sys' clock; round to the + * next MHz and see if we can get a multiple of 16MHz + */ + dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n"); + clk_in = devm_clk_get(&ofdev->dev, "sys"); + if (IS_ERR(clk_in)) + goto err_notavail; + freq_calc = clk_get_rate(clk_in); + freq_calc += 499999; + freq_calc /= 1000000; + freq_calc *= 1000000; + if ((freq_calc % 16000000) == 0) { + clk_from = CLK_FROM_SYS; + clockdiv = freq_calc / 16000000; + dev_dbg(&ofdev->dev, + "clk fit, sys[%lu] div[%d] freq[%lu]\n", + freq_calc, clockdiv, freq_calc / clockdiv); + } + } + if (clk_from == CLK_FROM_AUTO) { + /* no spec so far, use the 'ref' clock */ + dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n"); + clk_in = devm_clk_get(&ofdev->dev, "ref"); + if (IS_ERR(clk_in)) + goto err_notavail; + clk_from = CLK_FROM_REF; + freq_calc = clk_get_rate(clk_in); + dev_dbg(&ofdev->dev, + "clk fit, ref[%lu] (no div) freq[%lu]\n", + freq_calc, freq_calc); } - /* Determine the MSCAN device index from the physical address */ - pval = of_get_property(ofdev->dev.of_node, "reg", &plen); - BUG_ON(!pval || plen < sizeof(*pval)); - clockidx = (*pval & 0x80) ? 1 : 0; - if (*pval & 0x2000) - clockidx += 2; - - /* - * Clock source and divider selection: 3 different clock sources - * can be selected: "ip", "ref" or "sys". For the latter two, a - * clock divider can be defined as well. If the clock source is - * not specified by the device tree, we first try to find an - * optimal CAN source clock based on the system clock. If that - * is not posslible, the reference clock will be used. + /* select IPS or MCLK as the MSCAN input (returned to the caller), + * setup the MCLK mux source and rate if applicable, apply the + * optionally specified or derived above divider, and determine + * the actual resulting clock rate to return to the caller */ - if (clock_name && !strcmp(clock_name, "ip")) { + switch (clk_from) { + case CLK_FROM_IPS: + clk_can = devm_clk_get(&ofdev->dev, "ips"); + if (IS_ERR(clk_can)) + goto err_notavail; + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); + priv->clk_can = clk_can; + freq_calc = clk_get_rate(clk_can); *mscan_clksrc = MSCAN_CLKSRC_IPS; - freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node); - } else { + dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n", + *mscan_clksrc, freq_calc); + break; + case CLK_FROM_SYS: + case CLK_FROM_REF: + clk_can = devm_clk_get(&ofdev->dev, "mclk"); + if (IS_ERR(clk_can)) + goto err_notavail; + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); + priv->clk_can = clk_can; + if (clk_from == CLK_FROM_SYS) + clk_in = devm_clk_get(&ofdev->dev, "sys"); + if (clk_from == CLK_FROM_REF) + clk_in = devm_clk_get(&ofdev->dev, "ref"); + if (IS_ERR(clk_in)) + goto err_notavail; + clk_set_parent(clk_can, clk_in); + freq_calc = clk_get_rate(clk_in); + freq_calc /= clockdiv; + clk_set_rate(clk_can, freq_calc); + freq_calc = clk_get_rate(clk_can); *mscan_clksrc = MSCAN_CLKSRC_BUS; - - pval = of_get_property(ofdev->dev.of_node, - "fsl,mscan-clock-divider", &plen); - if (pval && plen == sizeof(*pval)) - clockdiv = *pval; - if (!clockdiv) - clockdiv = 1; - - if (!clock_name || !strcmp(clock_name, "sys")) { - sys_clk = clk_get(&ofdev->dev, "sys_clk"); - if (IS_ERR(sys_clk)) { - dev_err(&ofdev->dev, "couldn't get sys_clk\n"); - goto exit_unmap; - } - /* Get and round up/down sys clock rate */ - sys_freq = 1000000 * - ((clk_get_rate(sys_clk) + 499999) / 1000000); - - if (!clock_name) { - /* A multiple of 16 MHz would be optimal */ - if ((sys_freq % 16000000) == 0) { - clocksrc = 0; - clockdiv = sys_freq / 16000000; - freq = sys_freq / clockdiv; - } - } else { - clocksrc = 0; - freq = sys_freq / clockdiv; - } - } - - if (clocksrc < 0) { - ref_clk = clk_get(&ofdev->dev, "ref_clk"); - if (IS_ERR(ref_clk)) { - dev_err(&ofdev->dev, "couldn't get ref_clk\n"); - goto exit_unmap; - } - clocksrc = 1; - freq = clk_get_rate(ref_clk) / clockdiv; - } + dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n", + *mscan_clksrc, freq_calc); + break; + default: + goto err_invalid; } - /* Disable clock */ - out_be32(&clockctl->mccr[clockidx], 0x0); - if (clocksrc >= 0) { - /* Set source and divider */ - val = (clocksrc << 14) | ((clockdiv - 1) << 17); - out_be32(&clockctl->mccr[clockidx], val); - /* Enable clock */ - out_be32(&clockctl->mccr[clockidx], val | 0x10000); - } + /* the above clk_can item is used for the bitrate, access to + * the peripheral's register set needs the clk_ipg item + */ + clk_ipg = devm_clk_get(&ofdev->dev, "ipg"); + if (IS_ERR(clk_ipg)) + goto err_notavail_ipg; + if (clk_prepare_enable(clk_ipg)) + goto err_notavail_ipg; + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); + priv->clk_ipg = clk_ipg; + + /* return the determined clock source rate */ + return freq_calc; + +err_invalid: + dev_err(&ofdev->dev, "invalid clock source specification\n"); + /* clock source rate could not get determined */ + return 0; - /* Enable MSCAN clock domain */ - val = in_be32(&clockctl->sccr[1]); - if (!(val & (1 << 25))) - out_be32(&clockctl->sccr[1], val | (1 << 25)); +err_notavail: + dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n"); + /* clock source rate could not get determined */ + return 0; - dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n", - *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" : - clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv); +err_notavail_ipg: + dev_err(&ofdev->dev, "cannot acquire or setup register clock\n"); + /* clock source rate could not get determined */ + return 0; +} -exit_unmap: - iounmap(clockctl); -exit_put: - of_node_put(np_clock); - return freq; +static void mpc512x_can_put_clock(struct platform_device *ofdev) +{ + struct mscan_priv *priv; + + priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); + if (priv->clk_ipg) + clk_disable_unprepare(priv->clk_ipg); } #else /* !CONFIG_PPC_MPC512x */ -static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, - const char *clock_name, - int *mscan_clksrc) +static u32 mpc512x_can_get_clock(struct platform_device *ofdev, + const char *clock_name, int *mscan_clksrc) { return 0; } +#define mpc512x_can_put_clock NULL #endif /* CONFIG_PPC_MPC512x */ static const struct of_device_id mpc5xxx_can_table[]; -static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) +static int mpc5xxx_can_probe(struct platform_device *ofdev) { const struct of_device_id *match; const struct mpc5xxx_can_data *data; @@ -281,6 +316,8 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) dev = alloc_mscandev(); if (!dev) goto exit_dispose_irq; + platform_set_drvdata(ofdev, dev); + SET_NETDEV_DEV(dev, &ofdev->dev); priv = netdev_priv(dev); priv->reg_base = base; @@ -297,8 +334,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) goto exit_free_mscan; } - SET_NETDEV_DEV(dev, &ofdev->dev); - err = register_mscandev(dev, mscan_clksrc); if (err) { dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", @@ -306,8 +341,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) goto exit_free_mscan; } - dev_set_drvdata(&ofdev->dev, dev); - dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n", priv->reg_base, dev->irq, priv->can.clock.freq); @@ -323,14 +356,19 @@ exit_unmap_mem: return err; } -static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev) +static int mpc5xxx_can_remove(struct platform_device *ofdev) { - struct net_device *dev = dev_get_drvdata(&ofdev->dev); + const struct of_device_id *match; + const struct mpc5xxx_can_data *data; + struct net_device *dev = platform_get_drvdata(ofdev); struct mscan_priv *priv = netdev_priv(dev); - dev_set_drvdata(&ofdev->dev, NULL); + match = of_match_device(mpc5xxx_can_table, &ofdev->dev); + data = match ? match->data : NULL; unregister_mscandev(dev); + if (data && data->put_clock) + data->put_clock(ofdev); iounmap(priv->reg_base); irq_dispose_mapping(dev->irq); free_candev(dev); @@ -342,7 +380,7 @@ static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev) static struct mscan_regs saved_regs; static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state) { - struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = platform_get_drvdata(ofdev); struct mscan_priv *priv = netdev_priv(dev); struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; @@ -353,7 +391,7 @@ static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state static int mpc5xxx_can_resume(struct platform_device *ofdev) { - struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = platform_get_drvdata(ofdev); struct mscan_priv *priv = netdev_priv(dev); struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; @@ -380,22 +418,25 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev) } #endif -static const struct mpc5xxx_can_data __devinitconst mpc5200_can_data = { +static const struct mpc5xxx_can_data mpc5200_can_data = { .type = MSCAN_TYPE_MPC5200, .get_clock = mpc52xx_can_get_clock, + /* .put_clock not applicable */ }; -static const struct mpc5xxx_can_data __devinitconst mpc5121_can_data = { +static const struct mpc5xxx_can_data mpc5121_can_data = { .type = MSCAN_TYPE_MPC5121, .get_clock = mpc512x_can_get_clock, + .put_clock = mpc512x_can_put_clock, }; -static const struct of_device_id __devinitconst mpc5xxx_can_table[] = { +static const struct of_device_id mpc5xxx_can_table[] = { { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, }, /* Note that only MPC5121 Rev. 2 (and later) is supported */ { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, }, {}, }; +MODULE_DEVICE_TABLE(of, mpc5xxx_can_table); static struct platform_driver mpc5xxx_can_driver = { .driver = { @@ -404,7 +445,7 @@ static struct platform_driver mpc5xxx_can_driver = { .of_match_table = mpc5xxx_can_table, }, .probe = mpc5xxx_can_probe, - .remove = __devexit_p(mpc5xxx_can_remove), + .remove = mpc5xxx_can_remove, #ifdef CONFIG_PM .suspend = mpc5xxx_can_suspend, .resume = mpc5xxx_can_resume, diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 2b104d5f422..e0c9be5e2ab 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -517,12 +516,8 @@ static irqreturn_t mscan_isr(int irq, void *dev_id) static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode) { - struct mscan_priv *priv = netdev_priv(dev); int ret = 0; - if (!priv->open_time) - return -EINVAL; - switch (mode) { case CAN_MODE_START: ret = mscan_restart(dev); @@ -577,10 +572,21 @@ static int mscan_open(struct net_device *dev) struct mscan_priv *priv = netdev_priv(dev); struct mscan_regs __iomem *regs = priv->reg_base; + if (priv->clk_ipg) { + ret = clk_prepare_enable(priv->clk_ipg); + if (ret) + goto exit_retcode; + } + if (priv->clk_can) { + ret = clk_prepare_enable(priv->clk_can); + if (ret) + goto exit_dis_ipg_clock; + } + /* common open */ ret = open_candev(dev); if (ret) - return ret; + goto exit_dis_can_clock; napi_enable(&priv->napi); @@ -590,8 +596,6 @@ static int mscan_open(struct net_device *dev) goto exit_napi_disable; } - priv->open_time = jiffies; - if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) setbits8(®s->canctl1, MSCAN_LISTEN); else @@ -606,11 +610,17 @@ static int mscan_open(struct net_device *dev) return 0; exit_free_irq: - priv->open_time = 0; free_irq(dev->irq, dev); exit_napi_disable: napi_disable(&priv->napi); close_candev(dev); +exit_dis_can_clock: + if (priv->clk_can) + clk_disable_unprepare(priv->clk_can); +exit_dis_ipg_clock: + if (priv->clk_ipg) + clk_disable_unprepare(priv->clk_ipg); +exit_retcode: return ret; } @@ -627,15 +637,20 @@ static int mscan_close(struct net_device *dev) mscan_set_mode(dev, MSCAN_INIT_MODE); close_candev(dev); free_irq(dev->irq, dev); - priv->open_time = 0; + + if (priv->clk_can) + clk_disable_unprepare(priv->clk_can); + if (priv->clk_ipg) + clk_disable_unprepare(priv->clk_ipg); return 0; } static const struct net_device_ops mscan_netdev_ops = { - .ndo_open = mscan_open, - .ndo_stop = mscan_close, - .ndo_start_xmit = mscan_start_xmit, + .ndo_open = mscan_open, + .ndo_stop = mscan_close, + .ndo_start_xmit = mscan_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_mscandev(struct net_device *dev, int mscan_clksrc) diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h index b43e9f5d326..ad8e08f9c49 100644 --- a/drivers/net/can/mscan/mscan.h +++ b/drivers/net/can/mscan/mscan.h @@ -14,13 +14,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSCAN_H__ #define __MSCAN_H__ +#include <linux/clk.h> #include <linux/types.h> /* MSCAN control register 0 (CANCTL0) bits */ @@ -281,9 +281,10 @@ struct tx_queue_entry { struct mscan_priv { struct can_priv can; /* must be the first member */ unsigned int type; /* MSCAN type variants */ - long open_time; unsigned long flags; void __iomem *reg_base; /* ioremap'ed address to registers */ + struct clk *clk_ipg; /* clock for registers */ + struct clk *clk_can; /* clock for bitrates */ u8 shadow_statflg; u8 shadow_canrier; u8 cur_pri; @@ -295,8 +296,8 @@ struct mscan_priv { struct napi_struct napi; }; -extern struct net_device *alloc_mscandev(void); -extern int register_mscandev(struct net_device *dev, int mscan_clksrc); -extern void unregister_mscandev(struct net_device *dev); +struct net_device *alloc_mscandev(void); +int register_mscandev(struct net_device *dev, int mscan_clksrc); +void unregister_mscandev(struct net_device *dev); #endif /* __MSCAN_H__ */ diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 48b3d62b34c..6472562efed 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/interrupt.h> @@ -22,7 +21,6 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/errno.h> @@ -560,7 +558,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) stats->rx_errors++; break; case PCH_CRC_ERR: - cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL; priv->can.can_stats.bus_error++; stats->rx_errors++; @@ -952,9 +950,10 @@ static const struct net_device_ops pch_can_netdev_ops = { .ndo_open = pch_can_open, .ndo_stop = pch_close, .ndo_start_xmit = pch_xmit, + .ndo_change_mtu = can_change_mtu, }; -static void __devexit pch_can_remove(struct pci_dev *pdev) +static void pch_can_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); struct pch_can_priv *priv = netdev_priv(ndev); @@ -964,7 +963,6 @@ static void __devexit pch_can_remove(struct pci_dev *pdev) pci_disable_msi(priv->dev); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); pch_can_reset(priv); pci_iounmap(pdev, priv->regs); free_candev(priv->ndev); @@ -1178,7 +1176,7 @@ static int pch_can_get_berr_counter(const struct net_device *dev, return 0; } -static int __devinit pch_can_probe(struct pci_dev *pdev, +static int pch_can_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; @@ -1269,7 +1267,7 @@ static struct pci_driver pch_can_pci_driver = { .name = "pch_can", .id_table = pch_pci_tbl, .probe = pch_can_probe, - .remove = __devexit_p(pch_can_remove), + .remove = pch_can_remove, .suspend = pch_can_suspend, .resume = pch_can_resume, }; diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c new file mode 100644 index 00000000000..5268d216ecf --- /dev/null +++ b/drivers/net/can/rcar_can.c @@ -0,0 +1,876 @@ +/* Renesas R-Car CAN device driver + * + * Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com> + * Copyright (C) 2013 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/can/led.h> +#include <linux/can/dev.h> +#include <linux/clk.h> +#include <linux/can/platform/rcar_can.h> + +#define RCAR_CAN_DRV_NAME "rcar_can" + +/* Mailbox configuration: + * mailbox 60 - 63 - Rx FIFO mailboxes + * mailbox 56 - 59 - Tx FIFO mailboxes + * non-FIFO mailboxes are not used + */ +#define RCAR_CAN_N_MBX 64 /* Number of mailboxes in non-FIFO mode */ +#define RCAR_CAN_RX_FIFO_MBX 60 /* Mailbox - window to Rx FIFO */ +#define RCAR_CAN_TX_FIFO_MBX 56 /* Mailbox - window to Tx FIFO */ +#define RCAR_CAN_FIFO_DEPTH 4 + +/* Mailbox registers structure */ +struct rcar_can_mbox_regs { + u32 id; /* IDE and RTR bits, SID and EID */ + u8 stub; /* Not used */ + u8 dlc; /* Data Length Code - bits [0..3] */ + u8 data[8]; /* Data Bytes */ + u8 tsh; /* Time Stamp Higher Byte */ + u8 tsl; /* Time Stamp Lower Byte */ +}; + +struct rcar_can_regs { + struct rcar_can_mbox_regs mb[RCAR_CAN_N_MBX]; /* Mailbox registers */ + u32 mkr_2_9[8]; /* Mask Registers 2-9 */ + u32 fidcr[2]; /* FIFO Received ID Compare Register */ + u32 mkivlr1; /* Mask Invalid Register 1 */ + u32 mier1; /* Mailbox Interrupt Enable Register 1 */ + u32 mkr_0_1[2]; /* Mask Registers 0-1 */ + u32 mkivlr0; /* Mask Invalid Register 0*/ + u32 mier0; /* Mailbox Interrupt Enable Register 0 */ + u8 pad_440[0x3c0]; + u8 mctl[64]; /* Message Control Registers */ + u16 ctlr; /* Control Register */ + u16 str; /* Status register */ + u8 bcr[3]; /* Bit Configuration Register */ + u8 clkr; /* Clock Select Register */ + u8 rfcr; /* Receive FIFO Control Register */ + u8 rfpcr; /* Receive FIFO Pointer Control Register */ + u8 tfcr; /* Transmit FIFO Control Register */ + u8 tfpcr; /* Transmit FIFO Pointer Control Register */ + u8 eier; /* Error Interrupt Enable Register */ + u8 eifr; /* Error Interrupt Factor Judge Register */ + u8 recr; /* Receive Error Count Register */ + u8 tecr; /* Transmit Error Count Register */ + u8 ecsr; /* Error Code Store Register */ + u8 cssr; /* Channel Search Support Register */ + u8 mssr; /* Mailbox Search Status Register */ + u8 msmr; /* Mailbox Search Mode Register */ + u16 tsr; /* Time Stamp Register */ + u8 afsr; /* Acceptance Filter Support Register */ + u8 pad_857; + u8 tcr; /* Test Control Register */ + u8 pad_859[7]; + u8 ier; /* Interrupt Enable Register */ + u8 isr; /* Interrupt Status Register */ + u8 pad_862; + u8 mbsmr; /* Mailbox Search Mask Register */ +}; + +struct rcar_can_priv { + struct can_priv can; /* Must be the first member! */ + struct net_device *ndev; + struct napi_struct napi; + struct rcar_can_regs __iomem *regs; + struct clk *clk; + u8 tx_dlc[RCAR_CAN_FIFO_DEPTH]; + u32 tx_head; + u32 tx_tail; + u8 clock_select; + u8 ier; +}; + +static const struct can_bittiming_const rcar_can_bittiming_const = { + .name = RCAR_CAN_DRV_NAME, + .tseg1_min = 4, + .tseg1_max = 16, + .tseg2_min = 2, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, +}; + +/* Control Register bits */ +#define RCAR_CAN_CTLR_BOM (3 << 11) /* Bus-Off Recovery Mode Bits */ +#define RCAR_CAN_CTLR_BOM_ENT (1 << 11) /* Entry to halt mode */ + /* at bus-off entry */ +#define RCAR_CAN_CTLR_SLPM (1 << 10) +#define RCAR_CAN_CTLR_CANM (3 << 8) /* Operating Mode Select Bit */ +#define RCAR_CAN_CTLR_CANM_HALT (1 << 9) +#define RCAR_CAN_CTLR_CANM_RESET (1 << 8) +#define RCAR_CAN_CTLR_CANM_FORCE_RESET (3 << 8) +#define RCAR_CAN_CTLR_MLM (1 << 3) /* Message Lost Mode Select */ +#define RCAR_CAN_CTLR_IDFM (3 << 1) /* ID Format Mode Select Bits */ +#define RCAR_CAN_CTLR_IDFM_MIXED (1 << 2) /* Mixed ID mode */ +#define RCAR_CAN_CTLR_MBM (1 << 0) /* Mailbox Mode select */ + +/* Status Register bits */ +#define RCAR_CAN_STR_RSTST (1 << 8) /* Reset Status Bit */ + +/* FIFO Received ID Compare Registers 0 and 1 bits */ +#define RCAR_CAN_FIDCR_IDE (1 << 31) /* ID Extension Bit */ +#define RCAR_CAN_FIDCR_RTR (1 << 30) /* Remote Transmission Request Bit */ + +/* Receive FIFO Control Register bits */ +#define RCAR_CAN_RFCR_RFEST (1 << 7) /* Receive FIFO Empty Status Flag */ +#define RCAR_CAN_RFCR_RFE (1 << 0) /* Receive FIFO Enable */ + +/* Transmit FIFO Control Register bits */ +#define RCAR_CAN_TFCR_TFUST (7 << 1) /* Transmit FIFO Unsent Message */ + /* Number Status Bits */ +#define RCAR_CAN_TFCR_TFUST_SHIFT 1 /* Offset of Transmit FIFO Unsent */ + /* Message Number Status Bits */ +#define RCAR_CAN_TFCR_TFE (1 << 0) /* Transmit FIFO Enable */ + +#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */ + /* for Rx mailboxes 0-31 */ +#define RCAR_CAN_N_RX_MKREGS2 8 + +/* Bit Configuration Register settings */ +#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20) +#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8) +#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4) +#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07) + +/* Mailbox and Mask Registers bits */ +#define RCAR_CAN_IDE (1 << 31) +#define RCAR_CAN_RTR (1 << 30) +#define RCAR_CAN_SID_SHIFT 18 + +/* Mailbox Interrupt Enable Register 1 bits */ +#define RCAR_CAN_MIER1_RXFIE (1 << 28) /* Receive FIFO Interrupt Enable */ +#define RCAR_CAN_MIER1_TXFIE (1 << 24) /* Transmit FIFO Interrupt Enable */ + +/* Interrupt Enable Register bits */ +#define RCAR_CAN_IER_ERSIE (1 << 5) /* Error (ERS) Interrupt Enable Bit */ +#define RCAR_CAN_IER_RXFIE (1 << 4) /* Reception FIFO Interrupt */ + /* Enable Bit */ +#define RCAR_CAN_IER_TXFIE (1 << 3) /* Transmission FIFO Interrupt */ + /* Enable Bit */ +/* Interrupt Status Register bits */ +#define RCAR_CAN_ISR_ERSF (1 << 5) /* Error (ERS) Interrupt Status Bit */ +#define RCAR_CAN_ISR_RXFF (1 << 4) /* Reception FIFO Interrupt */ + /* Status Bit */ +#define RCAR_CAN_ISR_TXFF (1 << 3) /* Transmission FIFO Interrupt */ + /* Status Bit */ + +/* Error Interrupt Enable Register bits */ +#define RCAR_CAN_EIER_BLIE (1 << 7) /* Bus Lock Interrupt Enable */ +#define RCAR_CAN_EIER_OLIE (1 << 6) /* Overload Frame Transmit */ + /* Interrupt Enable */ +#define RCAR_CAN_EIER_ORIE (1 << 5) /* Receive Overrun Interrupt Enable */ +#define RCAR_CAN_EIER_BORIE (1 << 4) /* Bus-Off Recovery Interrupt Enable */ +#define RCAR_CAN_EIER_BOEIE (1 << 3) /* Bus-Off Entry Interrupt Enable */ +#define RCAR_CAN_EIER_EPIE (1 << 2) /* Error Passive Interrupt Enable */ +#define RCAR_CAN_EIER_EWIE (1 << 1) /* Error Warning Interrupt Enable */ +#define RCAR_CAN_EIER_BEIE (1 << 0) /* Bus Error Interrupt Enable */ + +/* Error Interrupt Factor Judge Register bits */ +#define RCAR_CAN_EIFR_BLIF (1 << 7) /* Bus Lock Detect Flag */ +#define RCAR_CAN_EIFR_OLIF (1 << 6) /* Overload Frame Transmission */ + /* Detect Flag */ +#define RCAR_CAN_EIFR_ORIF (1 << 5) /* Receive Overrun Detect Flag */ +#define RCAR_CAN_EIFR_BORIF (1 << 4) /* Bus-Off Recovery Detect Flag */ +#define RCAR_CAN_EIFR_BOEIF (1 << 3) /* Bus-Off Entry Detect Flag */ +#define RCAR_CAN_EIFR_EPIF (1 << 2) /* Error Passive Detect Flag */ +#define RCAR_CAN_EIFR_EWIF (1 << 1) /* Error Warning Detect Flag */ +#define RCAR_CAN_EIFR_BEIF (1 << 0) /* Bus Error Detect Flag */ + +/* Error Code Store Register bits */ +#define RCAR_CAN_ECSR_EDPM (1 << 7) /* Error Display Mode Select Bit */ +#define RCAR_CAN_ECSR_ADEF (1 << 6) /* ACK Delimiter Error Flag */ +#define RCAR_CAN_ECSR_BE0F (1 << 5) /* Bit Error (dominant) Flag */ +#define RCAR_CAN_ECSR_BE1F (1 << 4) /* Bit Error (recessive) Flag */ +#define RCAR_CAN_ECSR_CEF (1 << 3) /* CRC Error Flag */ +#define RCAR_CAN_ECSR_AEF (1 << 2) /* ACK Error Flag */ +#define RCAR_CAN_ECSR_FEF (1 << 1) /* Form Error Flag */ +#define RCAR_CAN_ECSR_SEF (1 << 0) /* Stuff Error Flag */ + +#define RCAR_CAN_NAPI_WEIGHT 4 +#define MAX_STR_READS 0x100 + +static void tx_failure_cleanup(struct net_device *ndev) +{ + int i; + + for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++) + can_free_echo_skb(ndev, i); +} + +static void rcar_can_error(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u8 eifr, txerr = 0, rxerr = 0; + + /* Propagate the error condition to the CAN stack */ + skb = alloc_can_err_skb(ndev, &cf); + + eifr = readb(&priv->regs->eifr); + if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) { + txerr = readb(&priv->regs->tecr); + rxerr = readb(&priv->regs->recr); + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + } + if (eifr & RCAR_CAN_EIFR_BEIF) { + int rx_errors = 0, tx_errors = 0; + u8 ecsr; + + netdev_dbg(priv->ndev, "Bus error interrupt:\n"); + 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; + } + if (ecsr & RCAR_CAN_ECSR_BE0F) { + netdev_dbg(priv->ndev, "Bit Error (dominant)\n"); + tx_errors++; + writeb(~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr); + if (skb) + cf->data[2] |= CAN_ERR_PROT_BIT0; + } + if (ecsr & RCAR_CAN_ECSR_BE1F) { + netdev_dbg(priv->ndev, "Bit Error (recessive)\n"); + tx_errors++; + writeb(~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr); + if (skb) + cf->data[2] |= CAN_ERR_PROT_BIT1; + } + if (ecsr & RCAR_CAN_ECSR_CEF) { + netdev_dbg(priv->ndev, "CRC Error\n"); + rx_errors++; + writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); + if (skb) + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + } + if (ecsr & RCAR_CAN_ECSR_AEF) { + netdev_dbg(priv->ndev, "ACK Error\n"); + tx_errors++; + writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); + if (skb) { + cf->can_id |= CAN_ERR_ACK; + cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + } + } + if (ecsr & RCAR_CAN_ECSR_FEF) { + netdev_dbg(priv->ndev, "Form Error\n"); + rx_errors++; + writeb(~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr); + if (skb) + cf->data[2] |= CAN_ERR_PROT_FORM; + } + if (ecsr & RCAR_CAN_ECSR_SEF) { + netdev_dbg(priv->ndev, "Stuff Error\n"); + rx_errors++; + writeb(~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr); + if (skb) + cf->data[2] |= CAN_ERR_PROT_STUFF; + } + + priv->can.can_stats.bus_error++; + ndev->stats.rx_errors += rx_errors; + ndev->stats.tx_errors += tx_errors; + writeb(~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr); + } + if (eifr & RCAR_CAN_EIFR_EWIF) { + netdev_dbg(priv->ndev, "Error warning interrupt\n"); + priv->can.state = CAN_STATE_ERROR_WARNING; + priv->can.can_stats.error_warning++; + /* Clear interrupt condition */ + writeb(~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr); + if (skb) + cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + } + if (eifr & RCAR_CAN_EIFR_EPIF) { + netdev_dbg(priv->ndev, "Error passive interrupt\n"); + priv->can.state = CAN_STATE_ERROR_PASSIVE; + priv->can.can_stats.error_passive++; + /* Clear interrupt condition */ + writeb(~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr); + if (skb) + cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_PASSIVE : + CAN_ERR_CRTL_RX_PASSIVE; + } + if (eifr & RCAR_CAN_EIFR_BOEIF) { + netdev_dbg(priv->ndev, "Bus-off entry interrupt\n"); + tx_failure_cleanup(ndev); + priv->ier = RCAR_CAN_IER_ERSIE; + writeb(priv->ier, &priv->regs->ier); + priv->can.state = CAN_STATE_BUS_OFF; + /* Clear interrupt condition */ + writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); + can_bus_off(ndev); + if (skb) + cf->can_id |= CAN_ERR_BUSOFF; + } + if (eifr & RCAR_CAN_EIFR_ORIF) { + netdev_dbg(priv->ndev, "Receive overrun error interrupt\n"); + ndev->stats.rx_over_errors++; + ndev->stats.rx_errors++; + writeb(~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr); + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + } + } + if (eifr & RCAR_CAN_EIFR_OLIF) { + netdev_dbg(priv->ndev, + "Overload Frame Transmission error interrupt\n"); + ndev->stats.rx_over_errors++; + ndev->stats.rx_errors++; + writeb(~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr); + if (skb) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] |= CAN_ERR_PROT_OVERLOAD; + } + } + + if (skb) { + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } +} + +static void rcar_can_tx_done(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + u8 isr; + + while (1) { + u8 unsent = readb(&priv->regs->tfcr); + + unsent = (unsent & RCAR_CAN_TFCR_TFUST) >> + RCAR_CAN_TFCR_TFUST_SHIFT; + if (priv->tx_head - priv->tx_tail <= unsent) + break; + stats->tx_packets++; + stats->tx_bytes += priv->tx_dlc[priv->tx_tail % + RCAR_CAN_FIFO_DEPTH]; + priv->tx_dlc[priv->tx_tail % RCAR_CAN_FIFO_DEPTH] = 0; + can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH); + priv->tx_tail++; + netif_wake_queue(ndev); + } + /* Clear interrupt */ + isr = readb(&priv->regs->isr); + writeb(isr & ~RCAR_CAN_ISR_TXFF, &priv->regs->isr); + can_led_event(ndev, CAN_LED_EVENT_TX); +} + +static irqreturn_t rcar_can_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct rcar_can_priv *priv = netdev_priv(ndev); + u8 isr; + + isr = readb(&priv->regs->isr); + if (!(isr & priv->ier)) + return IRQ_NONE; + + if (isr & RCAR_CAN_ISR_ERSF) + rcar_can_error(ndev); + + if (isr & RCAR_CAN_ISR_TXFF) + rcar_can_tx_done(ndev); + + if (isr & RCAR_CAN_ISR_RXFF) { + if (napi_schedule_prep(&priv->napi)) { + /* Disable Rx FIFO interrupts */ + priv->ier &= ~RCAR_CAN_IER_RXFIE; + writeb(priv->ier, &priv->regs->ier); + __napi_schedule(&priv->napi); + } + } + + return IRQ_HANDLED; +} + +static void rcar_can_set_bittiming(struct net_device *dev) +{ + struct rcar_can_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + u32 bcr; + + bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) | + RCAR_CAN_BCR_BPR(bt->brp - 1) | RCAR_CAN_BCR_SJW(bt->sjw - 1) | + RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1); + /* Don't overwrite CLKR with 32-bit BCR access; CLKR has 8-bit access. + * All the registers are big-endian but they get byte-swapped on 32-bit + * read/write (but not on 8-bit, contrary to the manuals)... + */ + writel((bcr << 8) | priv->clock_select, &priv->regs->bcr); +} + +static void rcar_can_start(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + u16 ctlr; + int i; + + /* Set controller to known mode: + * - FIFO mailbox mode + * - accept all messages + * - overrun mode + * CAN is in sleep mode after MCU hardware or software reset. + */ + ctlr = readw(&priv->regs->ctlr); + ctlr &= ~RCAR_CAN_CTLR_SLPM; + writew(ctlr, &priv->regs->ctlr); + /* Go to reset mode */ + ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; + writew(ctlr, &priv->regs->ctlr); + for (i = 0; i < MAX_STR_READS; i++) { + if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) + break; + } + rcar_can_set_bittiming(ndev); + ctlr |= RCAR_CAN_CTLR_IDFM_MIXED; /* Select mixed ID mode */ + ctlr |= RCAR_CAN_CTLR_BOM_ENT; /* Entry to halt mode automatically */ + /* at bus-off */ + ctlr |= RCAR_CAN_CTLR_MBM; /* Select FIFO mailbox mode */ + ctlr |= RCAR_CAN_CTLR_MLM; /* Overrun mode */ + writew(ctlr, &priv->regs->ctlr); + + /* Accept all SID and EID */ + writel(0, &priv->regs->mkr_2_9[6]); + writel(0, &priv->regs->mkr_2_9[7]); + /* In FIFO mailbox mode, write "0" to bits 24 to 31 */ + writel(0, &priv->regs->mkivlr1); + /* Accept all frames */ + writel(0, &priv->regs->fidcr[0]); + writel(RCAR_CAN_FIDCR_IDE | RCAR_CAN_FIDCR_RTR, &priv->regs->fidcr[1]); + /* Enable and configure FIFO mailbox interrupts */ + writel(RCAR_CAN_MIER1_RXFIE | RCAR_CAN_MIER1_TXFIE, &priv->regs->mier1); + + priv->ier = RCAR_CAN_IER_ERSIE | RCAR_CAN_IER_RXFIE | + RCAR_CAN_IER_TXFIE; + writeb(priv->ier, &priv->regs->ier); + + /* Accumulate error codes */ + writeb(RCAR_CAN_ECSR_EDPM, &priv->regs->ecsr); + /* Enable error interrupts */ + writeb(RCAR_CAN_EIER_EWIE | RCAR_CAN_EIER_EPIE | RCAR_CAN_EIER_BOEIE | + (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING ? + RCAR_CAN_EIER_BEIE : 0) | RCAR_CAN_EIER_ORIE | + RCAR_CAN_EIER_OLIE, &priv->regs->eier); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + /* Go to operation mode */ + writew(ctlr & ~RCAR_CAN_CTLR_CANM, &priv->regs->ctlr); + for (i = 0; i < MAX_STR_READS; i++) { + if (!(readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)) + break; + } + /* Enable Rx and Tx FIFO */ + writeb(RCAR_CAN_RFCR_RFE, &priv->regs->rfcr); + writeb(RCAR_CAN_TFCR_TFE, &priv->regs->tfcr); +} + +static int rcar_can_open(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + int err; + + err = clk_prepare_enable(priv->clk); + if (err) { + netdev_err(ndev, "clk_prepare_enable() failed, error %d\n", + err); + goto out; + } + err = open_candev(ndev); + if (err) { + netdev_err(ndev, "open_candev() failed, error %d\n", err); + goto out_clock; + } + napi_enable(&priv->napi); + err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); + if (err) { + netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq); + goto out_close; + } + can_led_event(ndev, CAN_LED_EVENT_OPEN); + rcar_can_start(ndev); + netif_start_queue(ndev); + return 0; +out_close: + napi_disable(&priv->napi); + close_candev(ndev); +out_clock: + clk_disable_unprepare(priv->clk); +out: + return err; +} + +static void rcar_can_stop(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + u16 ctlr; + int i; + + /* Go to (force) reset mode */ + ctlr = readw(&priv->regs->ctlr); + ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; + writew(ctlr, &priv->regs->ctlr); + for (i = 0; i < MAX_STR_READS; i++) { + if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) + break; + } + writel(0, &priv->regs->mier0); + writel(0, &priv->regs->mier1); + writeb(0, &priv->regs->ier); + writeb(0, &priv->regs->eier); + /* Go to sleep mode */ + ctlr |= RCAR_CAN_CTLR_SLPM; + writew(ctlr, &priv->regs->ctlr); + priv->can.state = CAN_STATE_STOPPED; +} + +static int rcar_can_close(struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + rcar_can_stop(ndev); + free_irq(ndev->irq, ndev); + napi_disable(&priv->napi); + clk_disable_unprepare(priv->clk); + close_candev(ndev); + can_led_event(ndev, CAN_LED_EVENT_STOP); + return 0; +} + +static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct rcar_can_priv *priv = netdev_priv(ndev); + struct can_frame *cf = (struct can_frame *)skb->data; + u32 data, i; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + + if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ + data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE; + else /* Standard frame format */ + data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT; + + if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */ + data |= RCAR_CAN_RTR; + } else { + for (i = 0; i < cf->can_dlc; i++) + writeb(cf->data[i], + &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].data[i]); + } + + writel(data, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].id); + + writeb(cf->can_dlc, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc); + + priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->can_dlc; + can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH); + priv->tx_head++; + /* Start Tx: write 0xff to the TFPCR register to increment + * the CPU-side pointer for the transmit FIFO to the next + * mailbox location + */ + writeb(0xff, &priv->regs->tfpcr); + /* Stop the queue if we've filled all FIFO entries */ + if (priv->tx_head - priv->tx_tail >= RCAR_CAN_FIFO_DEPTH) + netif_stop_queue(ndev); + + return NETDEV_TX_OK; +} + +static const struct net_device_ops rcar_can_netdev_ops = { + .ndo_open = rcar_can_open, + .ndo_stop = rcar_can_close, + .ndo_start_xmit = rcar_can_start_xmit, +}; + +static void rcar_can_rx_pkt(struct rcar_can_priv *priv) +{ + struct net_device_stats *stats = &priv->ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 data; + u8 dlc; + + skb = alloc_can_skb(priv->ndev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id); + if (data & RCAR_CAN_IDE) + cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK; + + dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc); + cf->can_dlc = get_can_dlc(dlc); + if (data & RCAR_CAN_RTR) { + cf->can_id |= CAN_RTR_FLAG; + } else { + for (dlc = 0; dlc < cf->can_dlc; dlc++) + cf->data[dlc] = + readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]); + } + + can_led_event(priv->ndev, CAN_LED_EVENT_RX); + + stats->rx_bytes += cf->can_dlc; + stats->rx_packets++; + netif_receive_skb(skb); +} + +static int rcar_can_rx_poll(struct napi_struct *napi, int quota) +{ + struct rcar_can_priv *priv = container_of(napi, + struct rcar_can_priv, napi); + int num_pkts; + + for (num_pkts = 0; num_pkts < quota; num_pkts++) { + u8 rfcr, isr; + + isr = readb(&priv->regs->isr); + /* Clear interrupt bit */ + if (isr & RCAR_CAN_ISR_RXFF) + writeb(isr & ~RCAR_CAN_ISR_RXFF, &priv->regs->isr); + rfcr = readb(&priv->regs->rfcr); + if (rfcr & RCAR_CAN_RFCR_RFEST) + break; + rcar_can_rx_pkt(priv); + /* Write 0xff to the RFPCR register to increment + * the CPU-side pointer for the receive FIFO + * to the next mailbox location + */ + writeb(0xff, &priv->regs->rfpcr); + } + /* All packets processed */ + if (num_pkts < quota) { + napi_complete(napi); + priv->ier |= RCAR_CAN_IER_RXFIE; + writeb(priv->ier, &priv->regs->ier); + } + return num_pkts; +} + +static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode) +{ + switch (mode) { + case CAN_MODE_START: + rcar_can_start(ndev); + netif_wake_queue(ndev); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int rcar_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct rcar_can_priv *priv = netdev_priv(dev); + int err; + + err = clk_prepare_enable(priv->clk); + if (err) + return err; + bec->txerr = readb(&priv->regs->tecr); + bec->rxerr = readb(&priv->regs->recr); + clk_disable_unprepare(priv->clk); + return 0; +} + +static int rcar_can_probe(struct platform_device *pdev) +{ + struct rcar_can_platform_data *pdata; + struct rcar_can_priv *priv; + struct net_device *ndev; + struct resource *mem; + void __iomem *addr; + int err = -ENODEV; + int irq; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "No platform data provided!\n"); + goto fail; + } + + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(&pdev->dev, "No IRQ resource\n"); + goto fail; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(addr)) { + err = PTR_ERR(addr); + goto fail; + } + + ndev = alloc_candev(sizeof(struct rcar_can_priv), RCAR_CAN_FIFO_DEPTH); + if (!ndev) { + dev_err(&pdev->dev, "alloc_candev() failed\n"); + err = -ENOMEM; + goto fail; + } + + priv = netdev_priv(ndev); + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + err = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "cannot get clock: %d\n", err); + goto fail_clk; + } + + ndev->netdev_ops = &rcar_can_netdev_ops; + ndev->irq = irq; + ndev->flags |= IFF_ECHO; + priv->ndev = ndev; + priv->regs = addr; + priv->clock_select = pdata->clock_select; + priv->can.clock.freq = clk_get_rate(priv->clk); + priv->can.bittiming_const = &rcar_can_bittiming_const; + priv->can.do_set_mode = rcar_can_do_set_mode; + priv->can.do_get_berr_counter = rcar_can_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + + netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll, + RCAR_CAN_NAPI_WEIGHT); + err = register_candev(ndev); + if (err) { + dev_err(&pdev->dev, "register_candev() failed, error %d\n", + err); + goto fail_candev; + } + + devm_can_led_init(ndev); + + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", + priv->regs, ndev->irq); + + return 0; +fail_candev: + netif_napi_del(&priv->napi); +fail_clk: + free_candev(ndev); +fail: + return err; +} + +static int rcar_can_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct rcar_can_priv *priv = netdev_priv(ndev); + + unregister_candev(ndev); + netif_napi_del(&priv->napi); + free_candev(ndev); + return 0; +} + +static int __maybe_unused rcar_can_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rcar_can_priv *priv = netdev_priv(ndev); + u16 ctlr; + + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + } + ctlr = readw(&priv->regs->ctlr); + ctlr |= RCAR_CAN_CTLR_CANM_HALT; + writew(ctlr, &priv->regs->ctlr); + ctlr |= RCAR_CAN_CTLR_SLPM; + writew(ctlr, &priv->regs->ctlr); + priv->can.state = CAN_STATE_SLEEPING; + + clk_disable(priv->clk); + return 0; +} + +static int __maybe_unused rcar_can_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rcar_can_priv *priv = netdev_priv(ndev); + u16 ctlr; + int err; + + err = clk_enable(priv->clk); + if (err) { + netdev_err(ndev, "clk_enable() failed, error %d\n", err); + return err; + } + + ctlr = readw(&priv->regs->ctlr); + ctlr &= ~RCAR_CAN_CTLR_SLPM; + writew(ctlr, &priv->regs->ctlr); + ctlr &= ~RCAR_CAN_CTLR_CANM; + writew(ctlr, &priv->regs->ctlr); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + if (netif_running(ndev)) { + netif_device_attach(ndev); + netif_start_queue(ndev); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume); + +static struct platform_driver rcar_can_driver = { + .driver = { + .name = RCAR_CAN_DRV_NAME, + .owner = THIS_MODULE, + .pm = &rcar_can_pm_ops, + }, + .probe = rcar_can_probe, + .remove = rcar_can_remove, +}; + +module_platform_driver(rcar_can_driver); + +MODULE_AUTHOR("Cogent Embedded, Inc."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC"); +MODULE_ALIAS("platform:" RCAR_CAN_DRV_NAME); diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 03df9a8f2bb..1e65cb6c259 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -1,6 +1,6 @@ menuconfig CAN_SJA1000 tristate "Philips/NXP SJA1000 devices" - depends on CAN_DEV && HAS_IOMEM + depends on HAS_IOMEM if CAN_SJA1000 @@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM the "platform bus" (Linux abstraction for directly to the processor attached devices). Which can be found on various boards from Phytec (http://www.phytec.de) like the PCM027, - PCM038. - -config CAN_SJA1000_OF_PLATFORM - tristate "Generic OF Platform Bus based SJA1000 driver" - depends on PPC_OF - ---help--- - This driver adds support for the SJA1000 chips connected to - the OpenFirmware "platform bus" found on embedded systems with - OpenFirmware bindings, e.g. if you have a PowerPC based system - you may want to enable this option. + PCM038. It also provides the OpenFirmware "platform bus" found + on embedded systems with OpenFirmware bindings, e.g. if you + have a PowerPC based system you may want to enable this option. config CAN_EMS_PCMCIA tristate "EMS CPC-CARD Card" @@ -46,6 +39,7 @@ config CAN_EMS_PCI config CAN_PEAK_PCMCIA tristate "PEAK PCAN-PC Card" depends on PCMCIA + depends on HAS_IOPORT_MAP ---help--- This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels) from PEAK-System (http://www.peak-system.com). To compile this @@ -93,16 +87,17 @@ config CAN_PLX_PCI - Marathon CAN-bus-PCI card (http://www.marathon.ru/) - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) - IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/) + - Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.com) config CAN_TSCAN1 tristate "TS-CAN1 PC104 boards" depends on ISA help - This driver is for Technologic Systems' TSCAN-1 PC104 boards. - http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1 - The driver supports multiple boards and automatically configures them: - PLD IO base addresses are read from jumpers JP1 and JP2, - IRQ numbers are read from jumpers JP4 and JP5, - SJA1000 IO base addresses are chosen heuristically (first that works). + This driver is for Technologic Systems' TSCAN-1 PC104 boards. + http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1 + The driver supports multiple boards and automatically configures them: + PLD IO base addresses are read from jumpers JP1 and JP2, + IRQ numbers are read from jumpers JP4 and JP5, + SJA1000 IO base addresses are chosen heuristically (first that works). endif diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index b3d05cbfec3..531d5fcc97e 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o -obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 5c6d412bafb..fd13dbf07d9 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -168,12 +167,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv) unsigned char res; /* Make sure SJA1000 is in reset mode */ - priv->write_reg(priv, REG_MOD, 1); + priv->write_reg(priv, SJA1000_MOD, 1); - priv->write_reg(priv, REG_CDR, CDR_PELICAN); + priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN); /* read reset-values */ - res = priv->read_reg(priv, REG_CDR); + res = priv->read_reg(priv, SJA1000_CDR); if (res == CDR_PELICAN) return 1; @@ -207,7 +206,6 @@ static void ems_pci_del_card(struct pci_dev *pdev) kfree(card); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } static void ems_pci_card_reset(struct ems_pci_card *card) @@ -220,8 +218,8 @@ static void ems_pci_card_reset(struct ems_pci_card *card) * Probe PCI device for EMS CAN signature and register each available * CAN channel to SJA1000 Socket-CAN subsystem. */ -static int __devinit ems_pci_add_card(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int ems_pci_add_card(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct sja1000_priv *priv; struct net_device *dev; @@ -238,7 +236,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, /* Allocating card structures to hold addresses, ... */ card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL); if (card == NULL) { - dev_err(&pdev->dev, "Unable to allocate memory\n"); pci_disable_device(pdev); return -ENOMEM; } @@ -326,6 +323,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, priv->cdr = EMS_PCI_CDR; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; if (card->version == 1) /* reset int flag of pita */ diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c index 075a5457a19..381de998d2f 100644 --- a/drivers/net/can/sja1000/ems_pcmcia.c +++ b/drivers/net/can/sja1000/ems_pcmcia.c @@ -126,11 +126,11 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id) static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv) { /* Make sure SJA1000 is in reset mode */ - ems_pcmcia_write_reg(priv, REG_MOD, 1); - ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN); + ems_pcmcia_write_reg(priv, SJA1000_MOD, 1); + ems_pcmcia_write_reg(priv, SJA1000_CDR, CDR_PELICAN); /* read reset-values */ - if (ems_pcmcia_read_reg(priv, REG_CDR) == CDR_PELICAN) + if (ems_pcmcia_read_reg(priv, SJA1000_CDR) == CDR_PELICAN) return 1; return 0; @@ -166,8 +166,7 @@ static void ems_pcmcia_del_card(struct pcmcia_device *pdev) * Probe PCI device for EMS CAN signature and register each available * CAN channel to SJA1000 Socket-CAN subsystem. */ -static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev, - unsigned long base) +static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base) { struct sja1000_priv *priv; struct net_device *dev; @@ -212,6 +211,7 @@ static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev, priv = netdev_priv(dev); priv->priv = card; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; priv->irq_flags = IRQF_SHARED; dev->irq = pdev->irq; @@ -256,7 +256,7 @@ failure_cleanup: /* * Setup PCMCIA socket and probe for EMS CPC-CARD */ -static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev) +static int ems_pcmcia_probe(struct pcmcia_device *dev) { int csval; @@ -317,15 +317,4 @@ static struct pcmcia_driver ems_pcmcia_driver = { .remove = ems_pcmcia_remove, .id_table = ems_pcmcia_tbl, }; - -static int __init ems_pcmcia_init(void) -{ - return pcmcia_register_driver(&ems_pcmcia_driver); -} -module_init(ems_pcmcia_init); - -static void __exit ems_pcmcia_exit(void) -{ - pcmcia_unregister_driver(&ems_pcmcia_driver); -} -module_exit(ems_pcmcia_exit); +module_pcmcia_driver(ems_pcmcia_driver); diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 23ed6ea4c7c..23b8e1324e2 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -26,8 +26,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -159,9 +158,9 @@ static int number_of_sja1000_chip(void __iomem *base_addr) for (i = 0; i < MAX_NO_OF_CHANNELS; i++) { /* reset chip */ iowrite8(MOD_RM, base_addr + - (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD); status = ioread8(base_addr + - (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD); /* check reset bit */ if (!(status & MOD_RM)) break; @@ -271,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, priv->reg_base, board->conf_addr, dev->irq); SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = channel; /* Register SJA1000 device */ err = register_sja1000dev(dev); @@ -290,8 +290,8 @@ failure: return err; } -static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int kvaser_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { int err; struct net_device *master_dev = NULL; @@ -379,7 +379,7 @@ failure: } -static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev) +static void kvaser_pci_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -387,14 +387,13 @@ static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } static struct pci_driver kvaser_pci_driver = { .name = DRV_NAME, .id_table = kvaser_pci_tbl, .probe = kvaser_pci_init_one, - .remove = __devexit_p(kvaser_pci_remove_one), + .remove = kvaser_pci_remove_one, }; module_pci_driver(kvaser_pci_driver); diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index f5b82aeb254..564933ae218 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -30,9 +30,10 @@ #include "sja1000.h" -MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); +MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards"); MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards"); +MODULE_SUPPORTED_DEVICE("PEAK PCAN miniPCIe/cPCI PC/104+ PCI/104e CAN Cards"); MODULE_LICENSE("GPL v2"); #define DRV_NAME "peak_pci" @@ -64,7 +65,11 @@ struct peak_pci_chan { #define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */ #define PEAK_PCIEC_DEVICE_ID 0x0002 /* for ExpressCard slot cards */ #define PEAK_PCIE_DEVICE_ID 0x0003 /* for nextgen PCIe slot cards */ -#define PEAK_MPCI_DEVICE_ID 0x0008 /* The miniPCI slot cards */ +#define PEAK_CPCI_DEVICE_ID 0x0004 /* for nextgen cPCI slot cards */ +#define PEAK_MPCI_DEVICE_ID 0x0005 /* for nextgen miniPCI slot cards */ +#define PEAK_PC_104P_DEVICE_ID 0x0006 /* PCAN-PC/104+ cards */ +#define PEAK_PCI_104E_DEVICE_ID 0x0007 /* PCAN-PCI/104 Express cards */ +#define PEAK_MPCIE_DEVICE_ID 0x0008 /* The miniPCIe slot cards */ #define PEAK_PCI_CHAN_MAX 4 @@ -76,6 +81,10 @@ static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = { {PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {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,}, #ifdef CONFIG_CAN_PEAK_PCIEC {PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, #endif @@ -330,8 +339,7 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s) */ static void peak_pciec_start_led_work(struct peak_pciec_card *card) { - if (!delayed_work_pending(&card->led_work)) - schedule_delayed_work(&card->led_work, HZ); + schedule_delayed_work(&card->led_work, HZ); } /* @@ -394,7 +402,7 @@ static void peak_pciec_write_reg(const struct sja1000_priv *priv, int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE; /* sja1000 register changes control the leds state */ - if (port == REG_MOD) + if (port == SJA1000_MOD) switch (val) { case MOD_RM: /* Reset Mode: set led on */ @@ -442,11 +450,8 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev) } else { /* create the bit banging I2C adapter structure */ card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL); - if (!card) { - dev_err(&pdev->dev, - "failed allocating memory for i2c chip\n"); + if (!card) return -ENOMEM; - } card->cfg_base = chan->cfg_base; card->reg_base = priv->reg_base; @@ -542,12 +547,11 @@ static void peak_pci_post_irq(const struct sja1000_priv *priv) writew(chan->icr_mask, chan->cfg_base + PITA_ICR); } -static int __devinit peak_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct sja1000_priv *priv; struct peak_pci_chan *chan; - struct net_device *dev; + struct net_device *dev, *prev_dev; void __iomem *cfg_base, *reg_base; u16 sub_sys_id, icr; int i, err, channels; @@ -638,6 +642,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev, icr |= chan->icr_mask; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; /* Create chain of SJA1000 devices */ chan->prev_dev = pci_get_drvdata(pdev); @@ -683,11 +688,13 @@ failure_remove_channels: writew(0x0, cfg_base + PITA_ICR + 2); chan = NULL; - for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) { - unregister_sja1000dev(dev); - free_sja1000dev(dev); + for (dev = pci_get_drvdata(pdev); dev; dev = prev_dev) { priv = netdev_priv(dev); chan = priv->priv; + prev_dev = chan->prev_dev; + + unregister_sja1000dev(dev); + free_sja1000dev(dev); } /* free any PCIeC resources too */ @@ -708,7 +715,7 @@ failure_disable_pci: return err; } -static void __devexit peak_pci_remove(struct pci_dev *pdev) +static void peak_pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); /* Last device */ struct sja1000_priv *priv = netdev_priv(dev); @@ -721,10 +728,12 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev) /* Loop over all registered devices */ while (1) { + struct net_device *prev_dev = chan->prev_dev; + dev_info(&pdev->dev, "removing device %s\n", dev->name); unregister_sja1000dev(dev); free_sja1000dev(dev); - dev = chan->prev_dev; + dev = prev_dev; if (!dev) { /* do that only for first channel */ @@ -740,15 +749,13 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev) pci_iounmap(pdev, cfg_base); pci_release_regions(pdev); pci_disable_device(pdev); - - pci_set_drvdata(pdev, NULL); } static struct pci_driver peak_pci_driver = { .name = DRV_NAME, .id_table = peak_pci_tbl, .probe = peak_pci_probe, - .remove = __devexit_p(peak_pci_remove), + .remove = peak_pci_remove, }; module_pci_driver(peak_pci_driver); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index 272a85f32b1..dd56133cc46 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -196,7 +196,7 @@ static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v) int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE; /* sja1000 register changes control the leds state */ - if (port == REG_MOD) + if (port == SJA1000_MOD) switch (v) { case MOD_RM: /* Reset Mode: set led on */ @@ -509,11 +509,11 @@ static void pcan_free_channels(struct pcan_pccard *card) static inline int pcan_channel_present(struct sja1000_priv *priv) { /* make sure SJA1000 is in reset mode */ - pcan_write_canreg(priv, REG_MOD, 1); - pcan_write_canreg(priv, REG_CDR, CDR_PELICAN); + pcan_write_canreg(priv, SJA1000_MOD, 1); + pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN); /* read reset-values */ - if (pcan_read_canreg(priv, REG_CDR) == CDR_PELICAN) + if (pcan_read_canreg(priv, SJA1000_CDR) == CDR_PELICAN) return 1; return 0; @@ -550,6 +550,7 @@ static int pcan_add_channels(struct pcan_pccard *card) priv = netdev_priv(netdev); priv->priv = card; SET_NETDEV_DEV(netdev, &pdev->dev); + netdev->dev_id = i; priv->irq_flags = IRQF_SHARED; netdev->irq = pdev->irq; @@ -632,7 +633,7 @@ static void pcan_free(struct pcmcia_device *pdev) /* * setup PCMCIA socket and probe for PEAK-System PC-CARD */ -static int __devinit pcan_probe(struct pcmcia_device *pdev) +static int pcan_probe(struct pcmcia_device *pdev) { struct pcan_pccard *card; int err; @@ -660,7 +661,6 @@ static int __devinit pcan_probe(struct pcmcia_device *pdev) card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL); if (!card) { - dev_err(&pdev->dev, "couldn't allocate card memory\n"); err = -ENOMEM; goto probe_err_2; } @@ -741,15 +741,4 @@ static struct pcmcia_driver pcan_driver = { .remove = pcan_remove, .id_table = pcan_table, }; - -static int __init pcan_init(void) -{ - return pcmcia_register_driver(&pcan_driver); -} -module_init(pcan_init); - -static void __exit pcan_exit(void) -{ - pcmcia_unregister_driver(&pcan_driver); -} -module_exit(pcan_exit); +module_pcmcia_driver(pcan_driver); diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 8bc95982840..ec39b7cb228 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -44,7 +43,9 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " "esd CAN-PCI/CPCI/PCI104/200, " "esd CAN-PCI/PMC/266, " "esd CAN-PCIe/2000, " - "IXXAT PC-I 04/PCI") + "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), " + "IXXAT PC-I 04/PCI, " + "ELCUS CAN-200-PCI") MODULE_LICENSE("GPL v2"); #define PLX_PCI_MAX_CHAN 2 @@ -122,6 +123,11 @@ struct plx_pci_card { #define ESD_PCI_SUB_SYS_ID_PCIE2000 0x0200 #define ESD_PCI_SUB_SYS_ID_PCI104200 0x0501 +#define CAN200PCI_DEVICE_ID 0x9030 +#define CAN200PCI_VENDOR_ID 0x10b5 +#define CAN200PCI_SUB_DEVICE_ID 0x0301 +#define CAN200PCI_SUB_VENDOR_ID 0xe1c5 + #define IXXAT_PCI_VENDOR_ID 0x10b5 #define IXXAT_PCI_DEVICE_ID 0x9050 #define IXXAT_PCI_SUB_SYS_ID 0x2540 @@ -131,6 +137,9 @@ struct plx_pci_card { #define TEWS_PCI_VENDOR_ID 0x1498 #define TEWS_PCI_DEVICE_ID_TMPC810 0x032A +#define CTI_PCI_VENDOR_ID 0x12c4 +#define CTI_PCI_DEVICE_ID_CRG001 0x0900 + static void plx_pci_reset_common(struct pci_dev *pdev); static void plx_pci_reset_marathon(struct pci_dev *pdev); static void plx9056_pci_reset_common(struct pci_dev *pdev); @@ -158,7 +167,7 @@ struct plx_pci_card_info { void (*reset_func)(struct pci_dev *pdev); }; -static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_adlink = { "Adlink PCI-7841/cPCI-7841", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, @@ -166,7 +175,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = { /* based on PLX9052 */ }; -static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_adlink_se = { "Adlink PCI-7841/cPCI-7841 SE", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, @@ -174,7 +183,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = { /* based on PLX9052 */ }; -static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_esd200 = { "esd CAN-PCI/CPCI/PCI104/200", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, @@ -182,7 +191,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = { /* based on PLX9030/9050 */ }; -static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_esd266 = { "esd CAN-PCI/PMC/266", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, @@ -190,7 +199,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = { /* based on PLX9056 */ }; -static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_esd2000 = { "esd CAN-PCIe/2000", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, @@ -198,7 +207,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = { /* based on PEX8311 */ }; -static struct plx_pci_card_info plx_pci_card_info_ixxat __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_ixxat = { "IXXAT PC-I 04/PCI", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x200, 0x80} }, @@ -206,7 +215,7 @@ static struct plx_pci_card_info plx_pci_card_info_ixxat __devinitdata = { /* based on PLX9050 */ }; -static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_marathon = { "Marathon CAN-bus-PCI", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, @@ -214,7 +223,7 @@ static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = { /* based on PLX9052 */ }; -static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = { +static struct plx_pci_card_info plx_pci_card_info_tews = { "TEWS TECHNOLOGIES TPMC810", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} }, @@ -222,6 +231,22 @@ static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = { /* based on PLX9030 */ }; +static struct plx_pci_card_info plx_pci_card_info_cti = { + "Connect Tech Inc. CANpro/104-Plus Opto (CRG001)", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} }, + &plx_pci_reset_common + /* based on PLX9030 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_elcus = { + "Eclus CAN-200-PCI", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} }, + &plx_pci_reset_common + /* based on PLX9030 */ +}; + static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { { /* Adlink PCI-7841/cPCI-7841 */ @@ -300,6 +325,20 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { 0, 0, (kernel_ulong_t)&plx_pci_card_info_tews }, + { + /* Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + CTI_PCI_VENDOR_ID, CTI_PCI_DEVICE_ID_CRG001, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_cti + }, + { + /* Elcus CAN-200-PCI */ + CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID, + CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_elcus + }, { 0,} }; MODULE_DEVICE_TABLE(pci, plx_pci_tbl); @@ -329,20 +368,20 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) */ if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) == REG_CR_BASICCAN_INITIAL && - (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) && - (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL)) + (priv->read_reg(priv, SJA1000_SR) == REG_SR_BASICCAN_INITIAL) && + (priv->read_reg(priv, SJA1000_IR) == REG_IR_BASICCAN_INITIAL)) flag = 1; /* Bring the SJA1000 into the PeliCAN mode*/ - priv->write_reg(priv, REG_CDR, CDR_PELICAN); + priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN); /* * Check registers after reset in the PeliCAN mode. * See states on p. 23 of the Datasheet. */ - if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL && - priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL && - priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL) + if (priv->read_reg(priv, SJA1000_MOD) == REG_MOD_PELICAN_INITIAL && + priv->read_reg(priv, SJA1000_SR) == REG_SR_PELICAN_INITIAL && + priv->read_reg(priv, SJA1000_IR) == REG_IR_PELICAN_INITIAL) return flag; return 0; @@ -458,15 +497,14 @@ static void plx_pci_del_card(struct pci_dev *pdev) kfree(card); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } /* * Probe PLX90xx based device for the SJA1000 chips and register each * available CAN channel to SJA1000 Socket-CAN subsystem. */ -static int __devinit plx_pci_add_card(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int plx_pci_add_card(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct sja1000_priv *priv; struct net_device *dev; @@ -489,7 +527,6 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev, /* Allocate card structures to hold addresses, ... */ card = kzalloc(sizeof(*card), GFP_KERNEL); if (!card) { - dev_err(&pdev->dev, "Unable to allocate memory\n"); pci_disable_device(pdev); return -ENOMEM; } @@ -550,6 +587,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev, priv->cdr = ci->cdr; SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = i; /* Register SJA1000 device */ err = register_sja1000dev(dev); diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 25011dbe1b9..f31499a32d7 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -60,6 +60,7 @@ #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/can/led.h> #include "sja1000.h" @@ -90,14 +91,14 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val) * the write_reg() operation - especially on SMP systems. */ spin_lock_irqsave(&priv->cmdreg_lock, flags); - priv->write_reg(priv, REG_CMR, val); - priv->read_reg(priv, REG_SR); + priv->write_reg(priv, SJA1000_CMR, val); + priv->read_reg(priv, SJA1000_SR); spin_unlock_irqrestore(&priv->cmdreg_lock, flags); } static int sja1000_is_absent(struct sja1000_priv *priv) { - return (priv->read_reg(priv, REG_MOD) == 0xFF); + return (priv->read_reg(priv, SJA1000_MOD) == 0xFF); } static int sja1000_probe_chip(struct net_device *dev) @@ -105,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); if (priv->reg_base && sja1000_is_absent(priv)) { - printk(KERN_INFO "%s: probing @0x%lX failed\n", - DRV_NAME, dev->base_addr); + netdev_err(dev, "probing failed\n"); return 0; } return -1; @@ -115,11 +115,11 @@ static int sja1000_probe_chip(struct net_device *dev) static void set_reset_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(priv, REG_MOD); + unsigned char status = priv->read_reg(priv, SJA1000_MOD); int i; /* disable interrupts */ - priv->write_reg(priv, REG_IER, IRQ_OFF); + priv->write_reg(priv, SJA1000_IER, IRQ_OFF); for (i = 0; i < 100; i++) { /* check reset bit */ @@ -128,9 +128,10 @@ static void set_reset_mode(struct net_device *dev) return; } - priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */ + /* reset chip */ + priv->write_reg(priv, SJA1000_MOD, MOD_RM); udelay(10); - status = priv->read_reg(priv, REG_MOD); + status = priv->read_reg(priv, SJA1000_MOD); } netdev_err(dev, "setting SJA1000 into reset mode failed!\n"); @@ -139,7 +140,7 @@ static void set_reset_mode(struct net_device *dev) static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(priv, REG_MOD); + unsigned char status = priv->read_reg(priv, SJA1000_MOD); int i; for (i = 0; i < 100; i++) { @@ -148,22 +149,22 @@ static void set_normal_mode(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; /* enable interrupts */ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) - priv->write_reg(priv, REG_IER, IRQ_ALL); + priv->write_reg(priv, SJA1000_IER, IRQ_ALL); else - priv->write_reg(priv, REG_IER, + priv->write_reg(priv, SJA1000_IER, IRQ_ALL & ~IRQ_BEI); return; } /* set chip to normal mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) - priv->write_reg(priv, REG_MOD, MOD_LOM); + priv->write_reg(priv, SJA1000_MOD, MOD_LOM); else - priv->write_reg(priv, REG_MOD, 0x00); + priv->write_reg(priv, SJA1000_MOD, 0x00); udelay(10); - status = priv->read_reg(priv, REG_MOD); + status = priv->read_reg(priv, SJA1000_MOD); } netdev_err(dev, "setting SJA1000 into normal mode failed!\n"); @@ -178,9 +179,9 @@ static void sja1000_start(struct net_device *dev) set_reset_mode(dev); /* Clear error counters and error code capture */ - priv->write_reg(priv, REG_TXERR, 0x0); - priv->write_reg(priv, REG_RXERR, 0x0); - priv->read_reg(priv, REG_ECC); + priv->write_reg(priv, SJA1000_TXERR, 0x0); + priv->write_reg(priv, SJA1000_RXERR, 0x0); + priv->read_reg(priv, SJA1000_ECC); /* leave reset mode */ set_normal_mode(dev); @@ -188,11 +189,6 @@ static void sja1000_start(struct net_device *dev) static int sja1000_set_mode(struct net_device *dev, enum can_mode mode) { - struct sja1000_priv *priv = netdev_priv(dev); - - if (!priv->open_time) - return -EINVAL; - switch (mode) { case CAN_MODE_START: sja1000_start(dev); @@ -221,8 +217,8 @@ static int sja1000_set_bittiming(struct net_device *dev) netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); - priv->write_reg(priv, REG_BTR0, btr0); - priv->write_reg(priv, REG_BTR1, btr1); + priv->write_reg(priv, SJA1000_BTR0, btr0); + priv->write_reg(priv, SJA1000_BTR1, btr1); return 0; } @@ -232,8 +228,8 @@ static int sja1000_get_berr_counter(const struct net_device *dev, { struct sja1000_priv *priv = netdev_priv(dev); - bec->txerr = priv->read_reg(priv, REG_TXERR); - bec->rxerr = priv->read_reg(priv, REG_RXERR); + bec->txerr = priv->read_reg(priv, SJA1000_TXERR); + bec->rxerr = priv->read_reg(priv, SJA1000_RXERR); return 0; } @@ -251,20 +247,20 @@ static void chipset_init(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); /* set clock divider and output control register */ - priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN); + priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN); /* set acceptance filter (accept all) */ - priv->write_reg(priv, REG_ACCC0, 0x00); - priv->write_reg(priv, REG_ACCC1, 0x00); - priv->write_reg(priv, REG_ACCC2, 0x00); - priv->write_reg(priv, REG_ACCC3, 0x00); + priv->write_reg(priv, SJA1000_ACCC0, 0x00); + priv->write_reg(priv, SJA1000_ACCC1, 0x00); + priv->write_reg(priv, SJA1000_ACCC2, 0x00); + priv->write_reg(priv, SJA1000_ACCC3, 0x00); - priv->write_reg(priv, REG_ACCM0, 0xFF); - priv->write_reg(priv, REG_ACCM1, 0xFF); - priv->write_reg(priv, REG_ACCM2, 0xFF); - priv->write_reg(priv, REG_ACCM3, 0xFF); + priv->write_reg(priv, SJA1000_ACCM0, 0xFF); + priv->write_reg(priv, SJA1000_ACCM1, 0xFF); + priv->write_reg(priv, SJA1000_ACCM2, 0xFF); + priv->write_reg(priv, SJA1000_ACCM3, 0xFF); - priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL); + priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL); } /* @@ -293,21 +289,21 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, id = cf->can_id; if (id & CAN_RTR_FLAG) - fi |= FI_RTR; + fi |= SJA1000_FI_RTR; if (id & CAN_EFF_FLAG) { - fi |= FI_FF; - dreg = EFF_BUF; - priv->write_reg(priv, REG_FI, fi); - priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); - priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8)); - priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5); - priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3); + fi |= SJA1000_FI_FF; + dreg = SJA1000_EFF_BUF; + priv->write_reg(priv, SJA1000_FI, fi); + priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> 21); + priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> 13); + priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << 3); } else { - dreg = SFF_BUF; - priv->write_reg(priv, REG_FI, fi); - priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3); - priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5); + dreg = SJA1000_SFF_BUF; + priv->write_reg(priv, SJA1000_FI, fi); + priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(priv, SJA1000_ID2, (id & 0x00000007) << 5); } for (i = 0; i < dlc; i++) @@ -339,25 +335,25 @@ static void sja1000_rx(struct net_device *dev) if (skb == NULL) return; - fi = priv->read_reg(priv, REG_FI); + fi = priv->read_reg(priv, SJA1000_FI); - if (fi & FI_FF) { + if (fi & SJA1000_FI_FF) { /* extended frame format (EFF) */ - dreg = EFF_BUF; - id = (priv->read_reg(priv, REG_ID1) << (5 + 16)) - | (priv->read_reg(priv, REG_ID2) << (5 + 8)) - | (priv->read_reg(priv, REG_ID3) << 5) - | (priv->read_reg(priv, REG_ID4) >> 3); + dreg = SJA1000_EFF_BUF; + id = (priv->read_reg(priv, SJA1000_ID1) << 21) + | (priv->read_reg(priv, SJA1000_ID2) << 13) + | (priv->read_reg(priv, SJA1000_ID3) << 5) + | (priv->read_reg(priv, SJA1000_ID4) >> 3); id |= CAN_EFF_FLAG; } else { /* standard frame format (SFF) */ - dreg = SFF_BUF; - id = (priv->read_reg(priv, REG_ID1) << 3) - | (priv->read_reg(priv, REG_ID2) >> 5); + dreg = SJA1000_SFF_BUF; + id = (priv->read_reg(priv, SJA1000_ID1) << 3) + | (priv->read_reg(priv, SJA1000_ID2) >> 5); } cf->can_dlc = get_can_dlc(fi & 0x0F); - if (fi & FI_RTR) { + if (fi & SJA1000_FI_RTR) { id |= CAN_RTR_FLAG; } else { for (i = 0; i < cf->can_dlc; i++) @@ -373,6 +369,8 @@ static void sja1000_rx(struct net_device *dev) stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + + can_led_event(dev, CAN_LED_EVENT_RX); } static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) @@ -416,7 +414,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) priv->can.can_stats.bus_error++; stats->rx_errors++; - ecc = priv->read_reg(priv, REG_ECC); + ecc = priv->read_reg(priv, SJA1000_ECC); cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -450,7 +448,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_ALI) { /* arbitration lost interrupt */ netdev_dbg(dev, "arbitration lost interrupt\n"); - alc = priv->read_reg(priv, REG_ALC); + alc = priv->read_reg(priv, SJA1000_ALC); priv->can.can_stats.arbitration_lost++; stats->tx_errors++; cf->can_id |= CAN_ERR_LOSTARB; @@ -459,8 +457,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { - uint8_t rxerr = priv->read_reg(priv, REG_RXERR); - uint8_t txerr = priv->read_reg(priv, REG_TXERR); + uint8_t rxerr = priv->read_reg(priv, SJA1000_RXERR); + uint8_t txerr = priv->read_reg(priv, SJA1000_TXERR); cf->can_id |= CAN_ERR_CRTL; if (state == CAN_STATE_ERROR_WARNING) { priv->can.can_stats.error_warning++; @@ -495,19 +493,20 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) uint8_t isrc, status; int n = 0; - /* Shared interrupts and IRQ off? */ - if (priv->read_reg(priv, REG_IER) == IRQ_OFF) - return IRQ_NONE; - if (priv->pre_irq) priv->pre_irq(priv); - while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { - n++; - status = priv->read_reg(priv, REG_SR); + /* Shared interrupts and IRQ off? */ + if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF) + goto out; + + while ((isrc = priv->read_reg(priv, SJA1000_IR)) && + (n < SJA1000_MAX_IRQ)) { + + status = priv->read_reg(priv, SJA1000_SR); /* check for absent controller due to hw unplug */ if (status == 0xFF && sja1000_is_absent(priv)) - return IRQ_NONE; + goto out; if (isrc & IRQ_WUI) netdev_warn(dev, "wakeup interrupt\n"); @@ -521,20 +520,21 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) } else { /* transmission complete */ stats->tx_bytes += - priv->read_reg(priv, REG_FI) & 0xf; + priv->read_reg(priv, SJA1000_FI) & 0xf; stats->tx_packets++; can_get_echo_skb(dev, 0); } netif_wake_queue(dev); + can_led_event(dev, CAN_LED_EVENT_TX); } if (isrc & IRQ_RI) { /* receive interrupt */ while (status & SR_RBS) { sja1000_rx(dev); - status = priv->read_reg(priv, REG_SR); + status = priv->read_reg(priv, SJA1000_SR); /* check for absent controller */ if (status == 0xFF && sja1000_is_absent(priv)) - return IRQ_NONE; + goto out; } } if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { @@ -542,8 +542,9 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) if (sja1000_err(dev, isrc, status)) break; } + n++; } - +out: if (priv->post_irq) priv->post_irq(priv); @@ -579,7 +580,8 @@ static int sja1000_open(struct net_device *dev) /* init and start chi */ sja1000_start(dev); - priv->open_time = jiffies; + + can_led_event(dev, CAN_LED_EVENT_OPEN); netif_start_queue(dev); @@ -598,7 +600,7 @@ static int sja1000_close(struct net_device *dev) close_candev(dev); - priv->open_time = 0; + can_led_event(dev, CAN_LED_EVENT_STOP); return 0; } @@ -640,13 +642,16 @@ void free_sja1000dev(struct net_device *dev) EXPORT_SYMBOL_GPL(free_sja1000dev); static const struct net_device_ops sja1000_netdev_ops = { - .ndo_open = sja1000_open, - .ndo_stop = sja1000_close, - .ndo_start_xmit = sja1000_start_xmit, + .ndo_open = sja1000_open, + .ndo_stop = sja1000_close, + .ndo_start_xmit = sja1000_start_xmit, + .ndo_change_mtu = can_change_mtu, }; int register_sja1000dev(struct net_device *dev) { + int ret; + if (!sja1000_probe_chip(dev)) return -ENODEV; @@ -656,7 +661,12 @@ int register_sja1000dev(struct net_device *dev) set_reset_mode(dev); chipset_init(dev); - return register_candev(dev); + ret = register_candev(dev); + + if (!ret) + devm_can_led_init(dev); + + return ret; } EXPORT_SYMBOL_GPL(register_sja1000dev); diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index 23fff06875f..9d46398f815 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -54,46 +54,46 @@ #define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */ /* SJA1000 registers - manual section 6.4 (Pelican Mode) */ -#define REG_MOD 0x00 -#define REG_CMR 0x01 -#define REG_SR 0x02 -#define REG_IR 0x03 -#define REG_IER 0x04 -#define REG_ALC 0x0B -#define REG_ECC 0x0C -#define REG_EWL 0x0D -#define REG_RXERR 0x0E -#define REG_TXERR 0x0F -#define REG_ACCC0 0x10 -#define REG_ACCC1 0x11 -#define REG_ACCC2 0x12 -#define REG_ACCC3 0x13 -#define REG_ACCM0 0x14 -#define REG_ACCM1 0x15 -#define REG_ACCM2 0x16 -#define REG_ACCM3 0x17 -#define REG_RMC 0x1D -#define REG_RBSA 0x1E +#define SJA1000_MOD 0x00 +#define SJA1000_CMR 0x01 +#define SJA1000_SR 0x02 +#define SJA1000_IR 0x03 +#define SJA1000_IER 0x04 +#define SJA1000_ALC 0x0B +#define SJA1000_ECC 0x0C +#define SJA1000_EWL 0x0D +#define SJA1000_RXERR 0x0E +#define SJA1000_TXERR 0x0F +#define SJA1000_ACCC0 0x10 +#define SJA1000_ACCC1 0x11 +#define SJA1000_ACCC2 0x12 +#define SJA1000_ACCC3 0x13 +#define SJA1000_ACCM0 0x14 +#define SJA1000_ACCM1 0x15 +#define SJA1000_ACCM2 0x16 +#define SJA1000_ACCM3 0x17 +#define SJA1000_RMC 0x1D +#define SJA1000_RBSA 0x1E /* Common registers - manual section 6.5 */ -#define REG_BTR0 0x06 -#define REG_BTR1 0x07 -#define REG_OCR 0x08 -#define REG_CDR 0x1F +#define SJA1000_BTR0 0x06 +#define SJA1000_BTR1 0x07 +#define SJA1000_OCR 0x08 +#define SJA1000_CDR 0x1F -#define REG_FI 0x10 -#define SFF_BUF 0x13 -#define EFF_BUF 0x15 +#define SJA1000_FI 0x10 +#define SJA1000_SFF_BUF 0x13 +#define SJA1000_EFF_BUF 0x15 -#define FI_FF 0x80 -#define FI_RTR 0x40 +#define SJA1000_FI_FF 0x80 +#define SJA1000_FI_RTR 0x40 -#define REG_ID1 0x11 -#define REG_ID2 0x12 -#define REG_ID3 0x13 -#define REG_ID4 0x14 +#define SJA1000_ID1 0x11 +#define SJA1000_ID2 0x12 +#define SJA1000_ID3 0x13 +#define SJA1000_ID4 0x14 -#define CAN_RAM 0x20 +#define SJA1000_CAN_RAM 0x20 /* mode register */ #define MOD_RM 0x01 @@ -152,7 +152,6 @@ */ struct sja1000_priv { struct can_priv can; /* must be the first member */ - int open_time; struct sk_buff *echo_skb; /* the lower-layer is responsible for appropriate locking */ diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c index 90c5c2dfd2f..014695d7e6a 100644 --- a/drivers/net/can/sja1000/sja1000_isa.c +++ b/drivers/net/can/sja1000/sja1000_isa.c @@ -11,8 +11,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -42,11 +41,12 @@ MODULE_LICENSE("GPL v2"); static unsigned long port[MAXDEV]; static unsigned long mem[MAXDEV]; -static int __devinitdata irq[MAXDEV]; -static int __devinitdata clk[MAXDEV]; -static unsigned char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; -static unsigned char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; -static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static int irq[MAXDEV]; +static int clk[MAXDEV]; +static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; +static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff}; +static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static spinlock_t indirect_lock[MAXDEV]; /* lock for indirect access mode */ module_param_array(port, ulong, NULL, S_IRUGO); MODULE_PARM_DESC(port, "I/O port number"); @@ -102,22 +102,29 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv, static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv, int reg) { - unsigned long base = (unsigned long)priv->reg_base; + unsigned long flags, base = (unsigned long)priv->reg_base; + u8 readval; + spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags); outb(reg, base); - return inb(base + 1); + readval = inb(base + 1); + spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags); + + return readval; } static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv, int reg, u8 val) { - unsigned long base = (unsigned long)priv->reg_base; + unsigned long flags, base = (unsigned long)priv->reg_base; + spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags); outb(reg, base); outb(val, base + 1); + spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags); } -static int __devinit sja1000_isa_probe(struct platform_device *pdev) +static int sja1000_isa_probe(struct platform_device *pdev) { struct net_device *dev; struct sja1000_priv *priv; @@ -170,6 +177,7 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev) if (iosize == SJA1000_IOSIZE_INDIRECT) { priv->read_reg = sja1000_isa_port_read_reg_indirect; priv->write_reg = sja1000_isa_port_write_reg_indirect; + spin_lock_init(&indirect_lock[idx]); } else { priv->read_reg = sja1000_isa_port_read_reg; priv->write_reg = sja1000_isa_port_write_reg; @@ -197,8 +205,9 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev) else priv->cdr = CDR_DEFAULT; - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); + dev->dev_id = idx; err = register_sja1000dev(dev); if (err) { @@ -223,14 +232,13 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev) return err; } -static int __devexit sja1000_isa_remove(struct platform_device *pdev) +static int sja1000_isa_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct sja1000_priv *priv = netdev_priv(dev); int idx = pdev->id; unregister_sja1000dev(dev); - dev_set_drvdata(&pdev->dev, NULL); if (mem[idx]) { iounmap(priv->reg_base); @@ -248,7 +256,7 @@ static int __devexit sja1000_isa_remove(struct platform_device *pdev) static struct platform_driver sja1000_isa_driver = { .probe = sja1000_isa_probe, - .remove = __devexit_p(sja1000_isa_remove), + .remove = sja1000_isa_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c deleted file mode 100644 index f2683eb6a3d..00000000000 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus - * - * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* This is a generic driver for SJA1000 chips on the OpenFirmware platform - * bus found on embedded PowerPC systems. You need a SJA1000 CAN node - * definition in your flattened device tree source (DTS) file similar to: - * - * can@3,100 { - * compatible = "nxp,sja1000"; - * reg = <3 0x100 0x80>; - * interrupts = <2 0>; - * interrupt-parent = <&mpic>; - * nxp,external-clock-frequency = <16000000>; - * }; - * - * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further - * information. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/netdevice.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/can/dev.h> - -#include <linux/of_platform.h> -#include <asm/prom.h> - -#include "sja1000.h" - -#define DRV_NAME "sja1000_of_platform" - -MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); -MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); -MODULE_LICENSE("GPL v2"); - -#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) - -#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN -#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) - -static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) -{ - return in_8(priv->reg_base + reg); -} - -static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, - int reg, u8 val) -{ - out_8(priv->reg_base + reg, val); -} - -static int __devexit sja1000_ofp_remove(struct platform_device *ofdev) -{ - struct net_device *dev = dev_get_drvdata(&ofdev->dev); - struct sja1000_priv *priv = netdev_priv(dev); - struct device_node *np = ofdev->dev.of_node; - struct resource res; - - dev_set_drvdata(&ofdev->dev, NULL); - - unregister_sja1000dev(dev); - free_sja1000dev(dev); - iounmap(priv->reg_base); - irq_dispose_mapping(dev->irq); - - of_address_to_resource(np, 0, &res); - release_mem_region(res.start, resource_size(&res)); - - return 0; -} - -static int __devinit sja1000_ofp_probe(struct platform_device *ofdev) -{ - struct device_node *np = ofdev->dev.of_node; - struct net_device *dev; - struct sja1000_priv *priv; - struct resource res; - const u32 *prop; - int err, irq, res_size, prop_size; - void __iomem *base; - - err = of_address_to_resource(np, 0, &res); - if (err) { - dev_err(&ofdev->dev, "invalid address\n"); - return err; - } - - res_size = resource_size(&res); - - if (!request_mem_region(res.start, res_size, DRV_NAME)) { - dev_err(&ofdev->dev, "couldn't request %pR\n", &res); - return -EBUSY; - } - - base = ioremap_nocache(res.start, res_size); - if (!base) { - dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res); - err = -ENOMEM; - goto exit_release_mem; - } - - irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { - dev_err(&ofdev->dev, "no irq found\n"); - err = -ENODEV; - goto exit_unmap_mem; - } - - dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_dispose_irq; - } - - priv = netdev_priv(dev); - - priv->read_reg = sja1000_ofp_read_reg; - priv->write_reg = sja1000_ofp_write_reg; - - prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); - if (prop && (prop_size == sizeof(u32))) - priv->can.clock.freq = *prop / 2; - else - priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ - - prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); - if (prop && (prop_size == sizeof(u32))) - priv->ocr |= *prop & OCR_MODE_MASK; - else - priv->ocr |= OCR_MODE_NORMAL; /* default */ - - prop = of_get_property(np, "nxp,tx-output-config", &prop_size); - if (prop && (prop_size == sizeof(u32))) - priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; - else - priv->ocr |= OCR_TX0_PULLDOWN; /* default */ - - prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); - if (prop && (prop_size == sizeof(u32)) && *prop) { - u32 divider = priv->can.clock.freq * 2 / *prop; - - if (divider > 1) - priv->cdr |= divider / 2 - 1; - else - priv->cdr |= CDR_CLKOUT_MASK; - } else { - priv->cdr |= CDR_CLK_OFF; /* default */ - } - - prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); - if (!prop) - priv->cdr |= CDR_CBP; /* default */ - - priv->irq_flags = IRQF_SHARED; - priv->reg_base = base; - - dev->irq = irq; - - dev_info(&ofdev->dev, - "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", - priv->reg_base, dev->irq, priv->can.clock.freq, - priv->ocr, priv->cdr); - - dev_set_drvdata(&ofdev->dev, dev); - SET_NETDEV_DEV(dev, &ofdev->dev); - - err = register_sja1000dev(dev); - if (err) { - dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", - DRV_NAME, err); - goto exit_free_sja1000; - } - - return 0; - -exit_free_sja1000: - free_sja1000dev(dev); -exit_dispose_irq: - irq_dispose_mapping(irq); -exit_unmap_mem: - iounmap(base); -exit_release_mem: - release_mem_region(res.start, res_size); - - return err; -} - -static struct of_device_id __devinitdata sja1000_ofp_table[] = { - {.compatible = "nxp,sja1000"}, - {}, -}; -MODULE_DEVICE_TABLE(of, sja1000_ofp_table); - -static struct platform_driver sja1000_ofp_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .of_match_table = sja1000_ofp_table, - }, - .probe = sja1000_ofp_probe, - .remove = __devexit_p(sja1000_ofp_remove), -}; - -module_platform_driver(sja1000_ofp_driver); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 662c5f7eb0c..95a844a7ee7 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -12,8 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -27,13 +26,18 @@ #include <linux/can/dev.h> #include <linux/can/platform/sja1000.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include "sja1000.h" #define DRV_NAME "sja1000_platform" +#define SP_CAN_CLOCK (16000000 / 2) MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); +MODULE_ALIAS("platform:" DRV_NAME); MODULE_LICENSE("GPL v2"); static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) @@ -66,59 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) iowrite8(val, priv->reg_base + reg * 4); } -static int sp_probe(struct platform_device *pdev) +static void sp_populate(struct sja1000_priv *priv, + struct sja1000_platform_data *pdata, + unsigned long resource_mem_flags) { - int err; - void __iomem *addr; - struct net_device *dev; - struct sja1000_priv *priv; - struct resource *res_mem, *res_irq; - struct sja1000_platform_data *pdata; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "No platform data provided!\n"); - err = -ENODEV; - goto exit; - } - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_mem || !res_irq) { - err = -ENODEV; - goto exit; - } - - if (!request_mem_region(res_mem->start, resource_size(res_mem), - DRV_NAME)) { - err = -EBUSY; - goto exit; - } - - addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); - if (!addr) { - err = -ENOMEM; - goto exit_release; - } - - dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_iounmap; - } - priv = netdev_priv(dev); - - dev->irq = res_irq->start; - priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; - if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) - priv->irq_flags |= IRQF_SHARED; - priv->reg_base = addr; /* The CAN clock frequency is half the oscillator clock frequency */ priv->can.clock.freq = pdata->osc_freq / 2; priv->ocr = pdata->ocr; priv->cdr = pdata->cdr; - switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { + switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) { case IORESOURCE_MEM_32BIT: priv->read_reg = sp_read_reg32; priv->write_reg = sp_write_reg32; @@ -133,8 +94,126 @@ static int sp_probe(struct platform_device *pdev) priv->write_reg = sp_write_reg8; break; } +} + +static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) +{ + int err; + u32 prop; + + err = of_property_read_u32(of, "reg-io-width", &prop); + if (err) + prop = 1; /* 8 bit is default */ + + switch (prop) { + case 4: + priv->read_reg = sp_read_reg32; + priv->write_reg = sp_write_reg32; + break; + case 2: + priv->read_reg = sp_read_reg16; + priv->write_reg = sp_write_reg16; + break; + case 1: /* fallthrough */ + default: + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + } - dev_set_drvdata(&pdev->dev, dev); + err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop); + if (!err) + priv->can.clock.freq = prop / 2; + else + priv->can.clock.freq = SP_CAN_CLOCK; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-mode", &prop); + if (!err) + priv->ocr |= prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-config", &prop); + if (!err) + priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop); + if (!err && prop) { + u32 divider = priv->can.clock.freq * 2 / prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + if (!of_property_read_bool(of, "nxp,no-comparator-bypass")) + priv->cdr |= CDR_CBP; /* default */ +} + +static int sp_probe(struct platform_device *pdev) +{ + int err, irq = 0; + void __iomem *addr; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource *res_mem, *res_irq = NULL; + struct sja1000_platform_data *pdata; + struct device_node *of = pdev->dev.of_node; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata && !of) { + dev_err(&pdev->dev, "No platform data provided!\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + if (!devm_request_mem_region(&pdev->dev, res_mem->start, + resource_size(res_mem), DRV_NAME)) + return -EBUSY; + + addr = devm_ioremap_nocache(&pdev->dev, res_mem->start, + resource_size(res_mem)); + if (!addr) + return -ENOMEM; + + if (of) + irq = irq_of_parse_and_map(of, 0); + else + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!irq && !res_irq) + return -ENODEV; + + dev = alloc_sja1000dev(0); + if (!dev) + return -ENOMEM; + priv = netdev_priv(dev); + + if (res_irq) { + irq = res_irq->start; + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + priv->irq_flags |= IRQF_SHARED; + } else { + priv->irq_flags = IRQF_SHARED; + } + + dev->irq = irq; + priv->reg_base = addr; + + if (of) + sp_populate_of(priv, of); + else + sp_populate(priv, pdata, res_mem->flags); + + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_sja1000dev(dev); @@ -150,40 +229,32 @@ static int sp_probe(struct platform_device *pdev) exit_free: free_sja1000dev(dev); - exit_iounmap: - iounmap(addr); - exit_release: - release_mem_region(res_mem->start, resource_size(res_mem)); - exit: return err; } static int sp_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); - struct sja1000_priv *priv = netdev_priv(dev); - struct resource *res; + struct net_device *dev = platform_get_drvdata(pdev); unregister_sja1000dev(dev); - dev_set_drvdata(&pdev->dev, NULL); - - if (priv->reg_base) - iounmap(priv->reg_base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - free_sja1000dev(dev); return 0; } +static struct of_device_id sp_of_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sp_of_table); + static struct platform_driver sp_driver = { .probe = sp_probe, .remove = sp_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = sp_of_table, }, }; diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c index 9756099a883..76513dd780c 100644 --- a/drivers/net/can/sja1000/tscan1.c +++ b/drivers/net/can/sja1000/tscan1.c @@ -71,7 +71,7 @@ MODULE_LICENSE("GPL"); #define TSCAN1_SJA1000_XTAL 16000000 /* SJA1000 IO base addresses */ -static const unsigned short tscan1_sja1000_addresses[] __devinitconst = { +static const unsigned short tscan1_sja1000_addresses[] = { 0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320 }; @@ -88,7 +88,7 @@ static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val) } /* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */ -static int __devinit tscan1_probe(struct device *dev, unsigned id) +static int tscan1_probe(struct device *dev, unsigned id) { struct net_device *netdev; struct sja1000_priv *priv; @@ -171,7 +171,7 @@ static int __devinit tscan1_probe(struct device *dev, unsigned id) return -ENXIO; } -static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/) +static int tscan1_remove(struct device *dev, unsigned id /*unused*/) { struct net_device *netdev; struct sja1000_priv *priv; @@ -197,7 +197,7 @@ static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/) static struct isa_driver tscan1_isa_driver = { .probe = tscan1_probe, - .remove = __devexit_p(tscan1_remove), + .remove = tscan1_remove, .driver = { .name = "tscan1", }, diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index adc3708d882..ea4d4f1a641 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -18,9 +18,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307. You can also get it - * at http://www.gnu.org/licenses/gpl.html + * with this program; if not, see http://www.gnu.org/licenses/gpl.html * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -54,7 +52,9 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/workqueue.h> #include <linux/can.h> +#include <linux/can/skb.h> static __initconst const char banner[] = KERN_INFO "slcan: serial line CAN interface driver\n"; @@ -75,6 +75,10 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces"); /* maximum rx buffer len: extended CAN frame with timestamp */ #define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1) +#define SLC_CMD_LEN 1 +#define SLC_SFF_ID_LEN 3 +#define SLC_EFF_ID_LEN 8 + struct slcan { int magic; @@ -82,6 +86,7 @@ struct slcan { struct tty_struct *tty; /* ptr to TTY structure */ struct net_device *dev; /* easy for intr handling */ spinlock_t lock; + struct work_struct tx_work; /* Flushes transmit buffer */ /* These are pointers to the malloc()ed frame buffers. */ unsigned char rbuff[SLC_MTU]; /* receiver buffer */ @@ -141,50 +146,67 @@ static void slc_bump(struct slcan *sl) { struct sk_buff *skb; struct can_frame cf; - int i, dlc_pos, tmp; - unsigned long ultmp; - char cmd = sl->rbuff[0]; - - if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R')) + int i, tmp; + u32 tmpid; + char *cmd = sl->rbuff; + + cf.can_id = 0; + + switch (*cmd) { + case 'r': + cf.can_id = CAN_RTR_FLAG; + /* fallthrough */ + case 't': + /* store dlc ASCII value and terminate SFF CAN ID string */ + cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN]; + sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0; + /* point to payload data behind the dlc */ + cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1; + break; + case 'R': + cf.can_id = CAN_RTR_FLAG; + /* fallthrough */ + case 'T': + cf.can_id |= CAN_EFF_FLAG; + /* store dlc ASCII value and terminate EFF CAN ID string */ + cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN]; + sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0; + /* point to payload data behind the dlc */ + cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1; + break; + default: return; + } - if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */ - dlc_pos = 4; /* dlc position tiiid */ - else - dlc_pos = 9; /* dlc position Tiiiiiiiid */ - - if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9'))) + if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid)) return; - cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */ + cf.can_id |= tmpid; - sl->rbuff[dlc_pos] = 0; /* terminate can_id string */ - - if (strict_strtoul(sl->rbuff+1, 16, &ultmp)) + /* get can_dlc from sanitized ASCII value */ + if (cf.can_dlc >= '0' && cf.can_dlc < '9') + cf.can_dlc -= '0'; + else return; - cf.can_id = ultmp; - - if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */ - cf.can_id |= CAN_EFF_FLAG; - - if ((cmd | 0x20) == 'r') /* RTR frame */ - cf.can_id |= CAN_RTR_FLAG; - *(u64 *) (&cf.data) = 0; /* clear payload */ - for (i = 0, dlc_pos++; i < cf.can_dlc; i++) { - tmp = hex_to_bin(sl->rbuff[dlc_pos++]); - if (tmp < 0) - return; - cf.data[i] = (tmp << 4); - tmp = hex_to_bin(sl->rbuff[dlc_pos++]); - if (tmp < 0) - return; - cf.data[i] |= tmp; + /* RTR frames may have a dlc > 0 but they never have any data bytes */ + if (!(cf.can_id & CAN_RTR_FLAG)) { + for (i = 0; i < cf.can_dlc; i++) { + tmp = hex_to_bin(*cmd++); + if (tmp < 0) + return; + cf.data[i] = (tmp << 4); + tmp = hex_to_bin(*cmd++); + if (tmp < 0) + return; + cf.data[i] |= tmp; + } } - skb = dev_alloc_skb(sizeof(struct can_frame)); + skb = dev_alloc_skb(sizeof(struct can_frame) + + sizeof(struct can_skb_priv)); if (!skb) return; @@ -192,6 +214,10 @@ static void slc_bump(struct slcan *sl) skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = sl->dev->ifindex; + memcpy(skb_put(skb, sizeof(struct can_frame)), &cf, sizeof(struct can_frame)); netif_rx_ni(skb); @@ -203,7 +229,6 @@ static void slc_bump(struct slcan *sl) /* parse tty input stream */ static void slcan_unesc(struct slcan *sl, unsigned char s) { - if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 4)) { @@ -230,27 +255,46 @@ static void slcan_unesc(struct slcan *sl, unsigned char s) /* Encapsulate one can_frame and stuff into a TTY queue. */ static void slc_encaps(struct slcan *sl, struct can_frame *cf) { - int actual, idx, i; - char cmd; + int actual, i; + unsigned char *pos; + unsigned char *endpos; + canid_t id = cf->can_id; + + pos = sl->xbuff; if (cf->can_id & CAN_RTR_FLAG) - cmd = 'R'; /* becomes 'r' in standard frame format */ + *pos = 'R'; /* becomes 'r' in standard frame format (SFF) */ else - cmd = 'T'; /* becomes 't' in standard frame format */ + *pos = 'T'; /* becomes 't' in standard frame format (SSF) */ - if (cf->can_id & CAN_EFF_FLAG) - sprintf(sl->xbuff, "%c%08X%d", cmd, - cf->can_id & CAN_EFF_MASK, cf->can_dlc); - else - sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20, - cf->can_id & CAN_SFF_MASK, cf->can_dlc); + /* determine number of chars for the CAN-identifier */ + if (cf->can_id & CAN_EFF_FLAG) { + id &= CAN_EFF_MASK; + endpos = pos + SLC_EFF_ID_LEN; + } else { + *pos |= 0x20; /* convert R/T to lower case for SFF */ + id &= CAN_SFF_MASK; + endpos = pos + SLC_SFF_ID_LEN; + } - idx = strlen(sl->xbuff); + /* build 3 (SFF) or 8 (EFF) digit CAN identifier */ + pos++; + while (endpos >= pos) { + *endpos-- = hex_asc_upper[id & 0xf]; + id >>= 4; + } - for (i = 0; i < cf->can_dlc; i++) - sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]); + pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN; - strcat(sl->xbuff, "\r"); /* add terminating character */ + *pos++ = cf->can_dlc + '0'; + + /* RTR frames may have a dlc > 0 but they never have any data bytes */ + if (!(cf->can_id & CAN_RTR_FLAG)) { + for (i = 0; i < cf->can_dlc; i++) + pos = hex_byte_pack_upper(pos, cf->data[i]); + } + + *pos++ = '\r'; /* Order of next two lines is *very* important. * When we are sending a little amount of data, @@ -261,37 +305,50 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf) * 14 Oct 1994 Dmitry Gorodchanin. */ set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); - actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff)); - sl->xleft = strlen(sl->xbuff) - actual; + actual = sl->tty->ops->write(sl->tty, sl->xbuff, pos - sl->xbuff); + sl->xleft = (pos - sl->xbuff) - actual; sl->xhead = sl->xbuff + actual; sl->dev->stats.tx_bytes += cf->can_dlc; } -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void slcan_write_wakeup(struct tty_struct *tty) +/* Write out any remaining transmit buffer. Scheduled when tty is writable */ +static void slcan_transmit(struct work_struct *work) { + struct slcan *sl = container_of(work, struct slcan, tx_work); int actual; - struct slcan *sl = (struct slcan *) tty->disc_data; + spin_lock_bh(&sl->lock); /* First make sure we're connected. */ - if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) + if (!sl->tty || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) { + spin_unlock_bh(&sl->lock); return; + } if (sl->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->dev->stats.tx_packets++; - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + spin_unlock_bh(&sl->lock); netif_wake_queue(sl->dev); return; } - actual = tty->ops->write(tty, sl->xhead, sl->xleft); + actual = sl->tty->ops->write(sl->tty, sl->xhead, sl->xleft); sl->xleft -= actual; sl->xhead += actual; + spin_unlock_bh(&sl->lock); +} + +/* + * Called by the driver when there's room for more data. + * Schedule the transmit. + */ +static void slcan_write_wakeup(struct tty_struct *tty) +{ + struct slcan *sl = tty->disc_data; + + schedule_work(&sl->tx_work); } /* Send a can_frame to a TTY queue. */ @@ -366,10 +423,16 @@ static void slc_free_netdev(struct net_device *dev) slcan_devs[i] = NULL; } +static int slcan_change_mtu(struct net_device *dev, int new_mtu) +{ + return -EINVAL; +} + static const struct net_device_ops slc_netdev_ops = { .ndo_open = slc_open, .ndo_stop = slc_close, .ndo_start_xmit = slc_xmit, + .ndo_change_mtu = slcan_change_mtu, }; static void slc_setup(struct net_device *dev) @@ -477,6 +540,7 @@ static struct slcan *slc_alloc(dev_t line) sl->magic = SLCAN_MAGIC; sl->dev = dev; spin_lock_init(&sl->lock); + INIT_WORK(&sl->tx_work, slcan_transmit); slcan_devs[i] = dev; return sl; @@ -575,8 +639,12 @@ static void slcan_close(struct tty_struct *tty) if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty) return; + spin_lock_bh(&sl->lock); tty->disc_data = NULL; sl->tty = NULL; + spin_unlock_bh(&sl->lock); + + flush_work(&sl->tx_work); /* Flush network side */ unregister_netdev(sl->dev); diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig index 5de46a9a77b..96b6fe158b5 100644 --- a/drivers/net/can/softing/Kconfig +++ b/drivers/net/can/softing/Kconfig @@ -1,6 +1,6 @@ config CAN_SOFTING tristate "Softing Gmbh CAN generic support" - depends on CAN_DEV && HAS_IOMEM + depends on HAS_IOMEM ---help--- Support for CAN cards from Softing Gmbh & some cards from Vector Gmbh. diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h index afd7d85b691..35f062282db 100644 --- a/drivers/net/can/softing/softing.h +++ b/drivers/net/can/softing/softing.h @@ -71,34 +71,34 @@ struct softing { } id; }; -extern int softing_default_output(struct net_device *netdev); +int softing_default_output(struct net_device *netdev); -extern ktime_t softing_raw2ktime(struct softing *card, u32 raw); +ktime_t softing_raw2ktime(struct softing *card, u32 raw); -extern int softing_chip_poweron(struct softing *card); +int softing_chip_poweron(struct softing *card); -extern int softing_bootloader_command(struct softing *card, int16_t cmd, - const char *msg); +int softing_bootloader_command(struct softing *card, int16_t cmd, + const char *msg); /* Load firmware after reset */ -extern int softing_load_fw(const char *file, struct softing *card, - __iomem uint8_t *virt, unsigned int size, int offset); +int softing_load_fw(const char *file, struct softing *card, + __iomem uint8_t *virt, unsigned int size, int offset); /* Load final application firmware after bootloader */ -extern int softing_load_app_fw(const char *file, struct softing *card); +int softing_load_app_fw(const char *file, struct softing *card); /* * enable or disable irq * only called with fw.lock locked */ -extern int softing_enable_irq(struct softing *card, int enable); +int softing_enable_irq(struct softing *card, int enable); /* start/stop 1 bus on card */ -extern int softing_startstop(struct net_device *netdev, int up); +int softing_startstop(struct net_device *netdev, int up); /* netif_rx() */ -extern int softing_netdev_rx(struct net_device *netdev, - const struct can_frame *msg, ktime_t ktime); +int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg, + ktime_t ktime); /* SOFTING DPRAM mappings */ #define DPRAM_RX 0x0000 diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c index c0e1b1eb87a..cdc0c7433a4 100644 --- a/drivers/net/can/softing/softing_cs.c +++ b/drivers/net/can/softing/softing_cs.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> @@ -27,7 +26,7 @@ #include "softing_platform.h" static int softingcs_index; -static spinlock_t softingcs_index_lock; +static DEFINE_SPINLOCK(softingcs_index_lock); static int softingcs_reset(struct platform_device *pdev, int v); static int softingcs_enable_irq(struct platform_device *pdev, int v); @@ -159,7 +158,7 @@ MODULE_FIRMWARE(fw_dir "bcard2.bin"); MODULE_FIRMWARE(fw_dir "ldcard2.bin"); MODULE_FIRMWARE(fw_dir "cancrd2.bin"); -static __devinit const struct softing_platform_data +static const struct softing_platform_data *softingcs_find_platform_data(unsigned int manf, unsigned int prod) { const struct softing_platform_data *lp; @@ -193,8 +192,7 @@ static int softingcs_enable_irq(struct platform_device *pdev, int v) /* * pcmcia check */ -static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia, - void *priv_data) +static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data) { struct softing_platform_data *pdat = priv_data; struct resource *pres; @@ -215,7 +213,7 @@ static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia, return pcmcia_request_window(pcmcia, pres, memspeed); } -static __devexit void softingcs_remove(struct pcmcia_device *pcmcia) +static void softingcs_remove(struct pcmcia_device *pcmcia) { struct platform_device *pdev = pcmcia->priv; @@ -235,7 +233,7 @@ static void softingcs_pdev_release(struct device *dev) kfree(pdev); } -static __devinit int softingcs_probe(struct pcmcia_device *pcmcia) +static int softingcs_probe(struct pcmcia_device *pcmcia) { int ret; struct platform_device *pdev; @@ -338,22 +336,10 @@ static struct pcmcia_driver softingcs_driver = { .name = "softingcs", .id_table = softingcs_ids, .probe = softingcs_probe, - .remove = __devexit_p(softingcs_remove), + .remove = softingcs_remove, }; -static int __init softingcs_start(void) -{ - spin_lock_init(&softingcs_index_lock); - return pcmcia_register_driver(&softingcs_driver); -} - -static void __exit softingcs_stop(void) -{ - pcmcia_unregister_driver(&softingcs_driver); -} - -module_init(softingcs_start); -module_exit(softingcs_stop); +module_pcmcia_driver(softingcs_driver); MODULE_DESCRIPTION("softing CANcard driver" ", links PCMCIA card to softing driver"); diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c index b595d3422b9..52fe50725d7 100644 --- a/drivers/net/can/softing/softing_fw.c +++ b/drivers/net/can/softing/softing_fw.c @@ -13,8 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/firmware.h> diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index f2a221e7b96..bacd236ce30 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -13,12 +13,10 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <asm/io.h> @@ -478,7 +476,7 @@ static void softing_card_shutdown(struct softing *card) mutex_unlock(&card->fw.lock); } -static __devinit int softing_card_boot(struct softing *card) +static int softing_card_boot(struct softing *card) { int ret, j; static const uint8_t stream[] = { @@ -558,15 +556,6 @@ failed: /* * netdev sysfs */ -static ssize_t show_channel(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - struct softing_priv *priv = netdev2softing(ndev); - - return sprintf(buf, "%i\n", priv->index); -} - static ssize_t show_chip(struct device *dev, struct device_attribute *attr, char *buf) { @@ -594,7 +583,7 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr, unsigned long val; int ret; - ret = strict_strtoul(buf, 0, &val); + ret = kstrtoul(buf, 0, &val); if (ret < 0) return ret; val &= 0xFF; @@ -611,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr, return count; } -static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL); static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output); static const struct attribute *const netdev_sysfs_attrs[] = { - &dev_attr_channel.attr, &dev_attr_chip.attr, &dev_attr_output.attr, NULL, @@ -630,6 +617,7 @@ static const struct net_device_ops softing_netdev_ops = { .ndo_open = softing_netdev_open, .ndo_stop = softing_netdev_stop, .ndo_start_xmit = softing_netdev_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const softing_btr_const = { @@ -645,8 +633,8 @@ static const struct can_bittiming_const softing_btr_const = { }; -static __devinit struct net_device *softing_netdev_create(struct softing *card, - uint16_t chip_id) +static struct net_device *softing_netdev_create(struct softing *card, + uint16_t chip_id) { struct net_device *netdev; struct softing_priv *priv; @@ -676,21 +664,24 @@ static __devinit struct net_device *softing_netdev_create(struct softing *card, return netdev; } -static __devinit int softing_netdev_register(struct net_device *netdev) +static int softing_netdev_register(struct net_device *netdev) { int ret; - netdev->sysfs_groups[0] = &netdev_sysfs_group; ret = register_candev(netdev); if (ret) { dev_alert(&netdev->dev, "register failed\n"); return ret; } + if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0) + netdev_alert(netdev, "sysfs group failed\n"); + return 0; } static void softing_netdev_cleanup(struct net_device *netdev) { + sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group); unregister_candev(netdev); free_candev(netdev); } @@ -722,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version); DEV_ATTR_RO_STR(hardware, pdat->name); DEV_ATTR_RO(hardware_version, id.hw_version); DEV_ATTR_RO(license, id.license); -DEV_ATTR_RO(frequency, id.freq); -DEV_ATTR_RO(txpending, tx.pending); static struct attribute *softing_pdev_attrs[] = { &dev_attr_serial.attr, @@ -732,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = { &dev_attr_hardware.attr, &dev_attr_hardware_version.attr, &dev_attr_license.attr, - &dev_attr_frequency.attr, - &dev_attr_txpending.attr, NULL, }; @@ -745,7 +732,7 @@ static const struct attribute_group softing_pdev_group = { /* * platform driver */ -static __devexit int softing_pdev_remove(struct platform_device *pdev) +static int softing_pdev_remove(struct platform_device *pdev) { struct softing *card = platform_get_drvdata(pdev); int j; @@ -766,9 +753,9 @@ static __devexit int softing_pdev_remove(struct platform_device *pdev) return 0; } -static __devinit int softing_pdev_probe(struct platform_device *pdev) +static int softing_pdev_probe(struct platform_device *pdev) { - const struct softing_platform_data *pdat = pdev->dev.platform_data; + const struct softing_platform_data *pdat = dev_get_platdata(&pdev->dev); struct softing *card; struct net_device *netdev; struct softing_priv *priv; @@ -834,6 +821,7 @@ static __devinit int softing_pdev_probe(struct platform_device *pdev) ret = -ENOMEM; goto netdev_failed; } + netdev->dev_id = j; priv = netdev_priv(card->net[j]); priv->index = j; ret = softing_netdev_register(netdev); @@ -871,7 +859,7 @@ static struct platform_driver softing_driver = { .owner = THIS_MODULE, }, .probe = softing_pdev_probe, - .remove = __devexit_p(softing_pdev_remove), + .remove = softing_pdev_remove, }; module_platform_driver(softing_driver); diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig new file mode 100644 index 00000000000..148cae5871a --- /dev/null +++ b/drivers/net/can/spi/Kconfig @@ -0,0 +1,10 @@ +menu "CAN SPI interfaces" + depends on SPI + +config CAN_MCP251X + tristate "Microchip MCP251x SPI CAN controllers" + depends on HAS_DMA + ---help--- + Driver for the Microchip MCP251x SPI CAN controllers. + +endmenu diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile new file mode 100644 index 00000000000..90bcacffbc6 --- /dev/null +++ b/drivers/net/can/spi/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Linux Controller Area Network SPI drivers. +# + + +obj-$(CONFIG_CAN_MCP251X) += mcp251x.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 26e7129332a..5df239e6881 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -28,8 +28,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * * * @@ -37,9 +36,6 @@ * * static struct mcp251x_platform_data mcp251x_info = { * .oscillator_frequency = 8000000, - * .board_specific_setup = &mcp251x_setup, - * .power_enable = mcp251x_power_enable, - * .transceiver_enable = NULL, * }; * * static struct spi_board_info spi_board_info[] = { @@ -60,7 +56,9 @@ #include <linux/can/core.h> #include <linux/can/dev.h> +#include <linux/can/led.h> #include <linux/can/platform/mcp251x.h> +#include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/device.h> @@ -71,10 +69,13 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/uaccess.h> +#include <linux/regulator/consumer.h> /* SPI interface instruction set */ #define INSTRUCTION_WRITE 0x02 @@ -213,6 +214,8 @@ #define TX_ECHO_SKB_MAX 1 +#define MCP251X_OST_DELAY_MS (5) + #define DEVICE_NAME "mcp251x" static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */ @@ -263,12 +266,15 @@ struct mcp251x_priv { #define AFTER_SUSPEND_POWER 4 #define AFTER_SUSPEND_RESTART 8 int restart_tx; + struct regulator *power; + struct regulator *transceiver; + struct clk *clk; }; #define MCP251X_IS(_model) \ static inline int mcp251x_is_##_model(struct spi_device *spi) \ { \ - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \ + struct mcp251x_priv *priv = spi_get_drvdata(spi); \ return priv->model == CAN_MCP251X_MCP##_model; \ } @@ -304,7 +310,7 @@ static void mcp251x_clean(struct net_device *net) */ static int mcp251x_spi_trans(struct spi_device *spi, int len) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); struct spi_transfer t = { .tx_buf = priv->spi_tx_buf, .rx_buf = priv->spi_rx_buf, @@ -332,7 +338,7 @@ static int mcp251x_spi_trans(struct spi_device *spi, int len) static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); u8 val = 0; priv->spi_tx_buf[0] = INSTRUCTION_READ; @@ -347,7 +353,7 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg) static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg, uint8_t *v1, uint8_t *v2) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); priv->spi_tx_buf[0] = INSTRUCTION_READ; priv->spi_tx_buf[1] = reg; @@ -360,7 +366,7 @@ static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg, static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); priv->spi_tx_buf[0] = INSTRUCTION_WRITE; priv->spi_tx_buf[1] = reg; @@ -372,7 +378,7 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val) static void mcp251x_write_bits(struct spi_device *spi, u8 reg, u8 mask, uint8_t val) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY; priv->spi_tx_buf[1] = reg; @@ -385,7 +391,7 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg, static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, int len, int tx_buf_idx) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); if (mcp251x_is_2510(spi)) { int i; @@ -402,7 +408,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, int tx_buf_idx) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); u32 sid, eid, exide, rtr; u8 buf[SPI_TRANSFER_BUF_LEN]; @@ -433,7 +439,7 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame, static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, int buf_idx) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); if (mcp251x_is_2510(spi)) { int i, len; @@ -453,7 +459,7 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); struct sk_buff *skb; struct can_frame *frame; u8 buf[SPI_TRANSFER_BUF_LEN]; @@ -494,6 +500,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) priv->net->stats.rx_packets++; priv->net->stats.rx_bytes += frame->can_dlc; + + can_led_event(priv->net, CAN_LED_EVENT_RX); + netif_rx_ni(skb); } @@ -546,7 +555,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode) static int mcp251x_set_normal_mode(struct spi_device *spi) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); unsigned long timeout; /* Enable interrupts */ @@ -594,10 +603,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net) (bt->prop_seg - 1)); mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (bt->phase_seg2 - 1)); - dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", - mcp251x_read_reg(spi, CNF1), - mcp251x_read_reg(spi, CNF2), - mcp251x_read_reg(spi, CNF3)); + dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", + mcp251x_read_reg(spi, CNF1), + mcp251x_read_reg(spi, CNF2), + mcp251x_read_reg(spi, CNF3)); return 0; } @@ -616,63 +625,67 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, static int mcp251x_hw_reset(struct spi_device *spi) { - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); + u8 reg; int ret; - unsigned long timeout; + + /* Wait for oscillator startup timer after power up */ + mdelay(MCP251X_OST_DELAY_MS); priv->spi_tx_buf[0] = INSTRUCTION_RESET; - ret = spi_write(spi, priv->spi_tx_buf, 1); - if (ret) { - dev_err(&spi->dev, "reset failed: ret = %d\n", ret); - return -EIO; - } + ret = mcp251x_spi_trans(spi, 1); + if (ret) + return ret; + + /* Wait for oscillator startup timer after reset */ + mdelay(MCP251X_OST_DELAY_MS); + + reg = mcp251x_read_reg(spi, CANSTAT); + if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF) + return -ENODEV; - /* Wait for reset to finish */ - timeout = jiffies + HZ; - mdelay(10); - while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) - != CANCTRL_REQOP_CONF) { - schedule(); - if (time_after(jiffies, timeout)) { - dev_err(&spi->dev, "MCP251x didn't" - " enter in conf mode after reset\n"); - return -EBUSY; - } - } return 0; } static int mcp251x_hw_probe(struct spi_device *spi) { - int st1, st2; + u8 ctrl; + int ret; - mcp251x_hw_reset(spi); + ret = mcp251x_hw_reset(spi); + if (ret) + return ret; - /* - * Please note that these are "magic values" based on after - * reset defaults taken from data sheet which allows us to see - * if we really have a chip on the bus (we avoid common all - * zeroes or all ones situations) - */ - st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE; - st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17; + ctrl = mcp251x_read_reg(spi, CANCTRL); - dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2); + dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl); - /* Check for power up default values */ - return (st1 == 0x80 && st2 == 0x07) ? 1 : 0; + /* Check for power up default value */ + if ((ctrl & 0x17) != 0x07) + return -ENODEV; + + return 0; +} + +static int mcp251x_power_enable(struct regulator *reg, int enable) +{ + if (IS_ERR_OR_NULL(reg)) + return 0; + + if (enable) + return regulator_enable(reg); + else + return regulator_disable(reg); } static void mcp251x_open_clean(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); struct spi_device *spi = priv->spi; - struct mcp251x_platform_data *pdata = spi->dev.platform_data; free_irq(spi->irq, priv); mcp251x_hw_sleep(spi); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); + mcp251x_power_enable(priv->transceiver, 0); close_candev(net); } @@ -680,7 +693,6 @@ static int mcp251x_stop(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); struct spi_device *spi = priv->spi; - struct mcp251x_platform_data *pdata = spi->dev.platform_data; close_candev(net); @@ -700,13 +712,14 @@ static int mcp251x_stop(struct net_device *net) mcp251x_hw_sleep(spi); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); + mcp251x_power_enable(priv->transceiver, 0); priv->can.state = CAN_STATE_STOPPED; mutex_unlock(&priv->mcp_lock); + can_led_event(net, CAN_LED_EVENT_STOP); + return 0; } @@ -760,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) mutex_lock(&priv->mcp_lock); if (priv->after_suspend) { - mdelay(10); mcp251x_hw_reset(spi); mcp251x_setup(net, priv, spi); if (priv->after_suspend & AFTER_SUSPEND_RESTART) { @@ -905,6 +917,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) if (intf & CANINTF_TX) { net->stats.tx_packets++; net->stats.tx_bytes += priv->tx_len - 1; + can_led_event(net, CAN_LED_EVENT_TX); if (priv->tx_len) { can_get_echo_skb(net, 0); priv->tx_len = 0; @@ -921,7 +934,7 @@ static int mcp251x_open(struct net_device *net) { struct mcp251x_priv *priv = netdev_priv(net); struct spi_device *spi = priv->spi; - struct mcp251x_platform_data *pdata = spi->dev.platform_data; + unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING; int ret; ret = open_candev(net); @@ -931,20 +944,17 @@ static int mcp251x_open(struct net_device *net) } mutex_lock(&priv->mcp_lock); - if (pdata->transceiver_enable) - pdata->transceiver_enable(1); + mcp251x_power_enable(priv->transceiver, 1); priv->force_quit = 0; priv->tx_skb = NULL; priv->tx_len = 0; ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist, - pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, - DEVICE_NAME, priv); + flags | IRQF_ONESHOT, DEVICE_NAME, priv); if (ret) { dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); + mcp251x_power_enable(priv->transceiver, 0); close_candev(net); goto open_unlock; } @@ -968,6 +978,9 @@ static int mcp251x_open(struct net_device *net) mcp251x_open_clean(net); goto open_unlock; } + + can_led_event(net, CAN_LED_EVENT_OPEN); + netif_wake_queue(net); open_unlock: @@ -979,24 +992,68 @@ static const struct net_device_ops mcp251x_netdev_ops = { .ndo_open = mcp251x_open, .ndo_stop = mcp251x_stop, .ndo_start_xmit = mcp251x_hard_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static const struct of_device_id mcp251x_of_match[] = { + { + .compatible = "microchip,mcp2510", + .data = (void *)CAN_MCP251X_MCP2510, + }, + { + .compatible = "microchip,mcp2515", + .data = (void *)CAN_MCP251X_MCP2515, + }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp251x_of_match); + +static const struct spi_device_id mcp251x_id_table[] = { + { + .name = "mcp2510", + .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2510, + }, + { + .name = "mcp2515", + .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515, + }, + { } }; +MODULE_DEVICE_TABLE(spi, mcp251x_id_table); -static int __devinit mcp251x_can_probe(struct spi_device *spi) +static int mcp251x_can_probe(struct spi_device *spi) { + const struct of_device_id *of_id = of_match_device(mcp251x_of_match, + &spi->dev); + struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev); struct net_device *net; struct mcp251x_priv *priv; - struct mcp251x_platform_data *pdata = spi->dev.platform_data; - int ret = -ENODEV; + struct clk *clk; + int freq, ret; + + clk = devm_clk_get(&spi->dev, NULL); + if (IS_ERR(clk)) { + if (pdata) + freq = pdata->oscillator_frequency; + else + return PTR_ERR(clk); + } else { + freq = clk_get_rate(clk); + } - if (!pdata) - /* Platform data is required for osc freq */ - goto error_out; + /* Sanity check */ + if (freq < 1000000 || freq > 25000000) + return -ERANGE; /* Allocate can/net device */ net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX); - if (!net) { - ret = -ENOMEM; - goto error_alloc; + if (!net) + return -ENOMEM; + + if (!IS_ERR(clk)) { + ret = clk_prepare_enable(clk); + if (ret) + goto out_free; } net->netdev_ops = &mcp251x_netdev_ops; @@ -1005,12 +1062,39 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) priv = netdev_priv(net); priv->can.bittiming_const = &mcp251x_bittiming_const; priv->can.do_set_mode = mcp251x_do_set_mode; - priv->can.clock.freq = pdata->oscillator_frequency / 2; + priv->can.clock.freq = freq / 2; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; - priv->model = spi_get_device_id(spi)->driver_data; + if (of_id) + priv->model = (enum mcp251x_model)of_id->data; + else + priv->model = spi_get_device_id(spi)->driver_data; priv->net = net; - dev_set_drvdata(&spi->dev, priv); + priv->clk = clk; + + spi_set_drvdata(spi, priv); + + /* Configure the SPI bus */ + spi->bits_per_word = 8; + if (mcp251x_is_2510(spi)) + spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000; + else + spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000; + ret = spi_setup(spi); + if (ret) + goto out_clk; + + priv->power = devm_regulator_get(&spi->dev, "vdd"); + priv->transceiver = devm_regulator_get(&spi->dev, "xceiver"); + if ((PTR_ERR(priv->power) == -EPROBE_DEFER) || + (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) { + ret = -EPROBE_DEFER; + goto out_clk; + } + + ret = mcp251x_power_enable(priv->power, 1); + if (ret) + goto out_clk; priv->spi = spi; mutex_init(&priv->mcp_lock); @@ -1040,94 +1124,79 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) /* Allocate non-DMA buffers */ if (!mcp251x_enable_dma) { - priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL); + priv->spi_tx_buf = devm_kzalloc(&spi->dev, SPI_TRANSFER_BUF_LEN, + GFP_KERNEL); if (!priv->spi_tx_buf) { ret = -ENOMEM; - goto error_tx_buf; + goto error_probe; } - priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL); + priv->spi_rx_buf = devm_kzalloc(&spi->dev, SPI_TRANSFER_BUF_LEN, + GFP_KERNEL); if (!priv->spi_rx_buf) { ret = -ENOMEM; - goto error_rx_buf; + goto error_probe; } } - if (pdata->power_enable) - pdata->power_enable(1); - - /* Call out to platform specific setup */ - if (pdata->board_specific_setup) - pdata->board_specific_setup(spi); - SET_NETDEV_DEV(net, &spi->dev); - /* Configure the SPI bus */ - spi->mode = SPI_MODE_0; - spi->bits_per_word = 8; - spi_setup(spi); - /* Here is OK to not lock the MCP, no one knows about it yet */ - if (!mcp251x_hw_probe(spi)) { - dev_info(&spi->dev, "Probe failed\n"); + ret = mcp251x_hw_probe(spi); + if (ret) goto error_probe; - } - mcp251x_hw_sleep(spi); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); + mcp251x_hw_sleep(spi); ret = register_candev(net); - if (!ret) { - dev_info(&spi->dev, "probed\n"); - return ret; - } + if (ret) + goto error_probe; + + devm_can_led_init(net); + + return 0; + error_probe: - if (!mcp251x_enable_dma) - kfree(priv->spi_rx_buf); -error_rx_buf: - if (!mcp251x_enable_dma) - kfree(priv->spi_tx_buf); -error_tx_buf: - free_candev(net); if (mcp251x_enable_dma) dma_free_coherent(&spi->dev, PAGE_SIZE, priv->spi_tx_buf, priv->spi_tx_dma); -error_alloc: - if (pdata->power_enable) - pdata->power_enable(0); - dev_err(&spi->dev, "probe failed\n"); -error_out: + mcp251x_power_enable(priv->power, 0); + +out_clk: + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); + +out_free: + free_candev(net); + return ret; } -static int __devexit mcp251x_can_remove(struct spi_device *spi) +static int mcp251x_can_remove(struct spi_device *spi) { - struct mcp251x_platform_data *pdata = spi->dev.platform_data; - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); struct net_device *net = priv->net; unregister_candev(net); - free_candev(net); if (mcp251x_enable_dma) { dma_free_coherent(&spi->dev, PAGE_SIZE, priv->spi_tx_buf, priv->spi_tx_dma); - } else { - kfree(priv->spi_tx_buf); - kfree(priv->spi_rx_buf); } - if (pdata->power_enable) - pdata->power_enable(0); + mcp251x_power_enable(priv->power, 0); + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + + free_candev(net); return 0; } -#ifdef CONFIG_PM -static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state) +static int __maybe_unused mcp251x_can_suspend(struct device *dev) { - struct mcp251x_platform_data *pdata = spi->dev.platform_data; - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); struct net_device *net = priv->net; priv->force_quit = 1; @@ -1140,33 +1209,31 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state) netif_device_detach(net); mcp251x_hw_sleep(spi); - if (pdata->transceiver_enable) - pdata->transceiver_enable(0); + mcp251x_power_enable(priv->transceiver, 0); priv->after_suspend = AFTER_SUSPEND_UP; } else { priv->after_suspend = AFTER_SUSPEND_DOWN; } - if (pdata->power_enable) { - pdata->power_enable(0); + if (!IS_ERR_OR_NULL(priv->power)) { + regulator_disable(priv->power); priv->after_suspend |= AFTER_SUSPEND_POWER; } return 0; } -static int mcp251x_can_resume(struct spi_device *spi) +static int __maybe_unused mcp251x_can_resume(struct device *dev) { - struct mcp251x_platform_data *pdata = spi->dev.platform_data; - struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct mcp251x_priv *priv = spi_get_drvdata(spi); if (priv->after_suspend & AFTER_SUSPEND_POWER) { - pdata->power_enable(1); + mcp251x_power_enable(priv->power, 1); queue_work(priv->wq, &priv->restart_work); } else { if (priv->after_suspend & AFTER_SUSPEND_UP) { - if (pdata->transceiver_enable) - pdata->transceiver_enable(1); + mcp251x_power_enable(priv->transceiver, 1); queue_work(priv->wq, &priv->restart_work); } else { priv->after_suspend = 0; @@ -1176,45 +1243,22 @@ static int mcp251x_can_resume(struct spi_device *spi) enable_irq(spi->irq); return 0; } -#else -#define mcp251x_can_suspend NULL -#define mcp251x_can_resume NULL -#endif - -static const struct spi_device_id mcp251x_id_table[] = { - { "mcp2510", CAN_MCP251X_MCP2510 }, - { "mcp2515", CAN_MCP251X_MCP2515 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, mcp251x_id_table); +static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend, + mcp251x_can_resume); static struct spi_driver mcp251x_can_driver = { .driver = { .name = DEVICE_NAME, - .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = mcp251x_of_match, + .pm = &mcp251x_can_pm_ops, }, - .id_table = mcp251x_id_table, .probe = mcp251x_can_probe, - .remove = __devexit_p(mcp251x_can_remove), - .suspend = mcp251x_can_suspend, - .resume = mcp251x_can_resume, + .remove = mcp251x_can_remove, }; - -static int __init mcp251x_can_init(void) -{ - return spi_register_driver(&mcp251x_can_driver); -} - -static void __exit mcp251x_can_exit(void) -{ - spi_unregister_driver(&mcp251x_can_driver); -} - -module_init(mcp251x_can_init); -module_exit(mcp251x_can_exit); +module_spi_driver(mcp251x_can_driver); MODULE_AUTHOR("Chris Elston <celston@katalix.com>, " "Christian Pellegrin <chripell@evolware.org>"); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 9ded21e79db..258b9c4856e 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -37,7 +37,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/interrupt.h> @@ -50,6 +49,7 @@ #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/can/led.h> #include <linux/can/platform/ti_hecc.h> #define DRV_NAME "ti_hecc" @@ -285,15 +285,6 @@ static inline u32 hecc_get_bit(struct ti_hecc_priv *priv, int reg, u32 bit_mask) return (hecc_read(priv, reg) & bit_mask) ? 1 : 0; } -static int ti_hecc_get_state(const struct net_device *ndev, - enum can_state *state) -{ - struct ti_hecc_priv *priv = netdev_priv(ndev); - - *state = priv->can.state; - return 0; -} - static int ti_hecc_set_btc(struct ti_hecc_priv *priv) { struct can_bittiming *bit_timing = &priv->can.bittiming; @@ -526,10 +517,10 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) data = (cf->can_id & CAN_SFF_MASK) << 18; hecc_write_mbx(priv, mbxno, HECC_CANMID, data); hecc_write_mbx(priv, mbxno, HECC_CANMDL, - be32_to_cpu(*(u32 *)(cf->data))); + be32_to_cpu(*(__be32 *)(cf->data))); if (cf->can_dlc > 4) hecc_write_mbx(priv, mbxno, HECC_CANMDH, - be32_to_cpu(*(u32 *)(cf->data + 4))); + be32_to_cpu(*(__be32 *)(cf->data + 4))); else *(u32 *)(cf->data + 4) = 0; can_put_echo_skb(skb, ndev, mbxno); @@ -577,12 +568,10 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) cf->can_id |= CAN_RTR_FLAG; cf->can_dlc = get_can_dlc(data & 0xF); data = hecc_read_mbx(priv, mbxno, HECC_CANMDL); - *(u32 *)(cf->data) = cpu_to_be32(data); + *(__be32 *)(cf->data) = cpu_to_be32(data); if (cf->can_dlc > 4) { data = hecc_read_mbx(priv, mbxno, HECC_CANMDH); - *(u32 *)(cf->data + 4) = cpu_to_be32(data); - } else { - *(u32 *)(cf->data + 4) = 0; + *(__be32 *)(cf->data + 4) = cpu_to_be32(data); } spin_lock_irqsave(&priv->mbx_lock, flags); hecc_clear_bit(priv, HECC_CANME, mbx_mask); @@ -593,6 +582,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) spin_unlock_irqrestore(&priv->mbx_lock, flags); stats->rx_bytes += cf->can_dlc; + can_led_event(priv->ndev, CAN_LED_EVENT_RX); netif_receive_skb(skb); stats->rx_packets++; @@ -746,12 +736,12 @@ 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[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL; } if (err_status & HECC_CANES_ACKE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); - cf->data[2] |= CAN_ERR_PROT_LOC_ACK | + cf->data[3] |= CAN_ERR_PROT_LOC_ACK | CAN_ERR_PROT_LOC_ACK_DEL; } } @@ -796,6 +786,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) stats->tx_bytes += hecc_read_mbx(priv, mbxno, HECC_CANMCF) & 0xF; stats->tx_packets++; + can_led_event(ndev, CAN_LED_EVENT_TX); can_get_echo_skb(ndev, mbxno); --priv->tx_tail; } @@ -851,6 +842,8 @@ static int ti_hecc_open(struct net_device *ndev) return err; } + can_led_event(ndev, CAN_LED_EVENT_OPEN); + ti_hecc_start(ndev); napi_enable(&priv->napi); netif_start_queue(ndev); @@ -869,6 +862,8 @@ static int ti_hecc_close(struct net_device *ndev) close_candev(ndev); ti_hecc_transceiver_switch(priv, 0); + can_led_event(ndev, CAN_LED_EVENT_STOP); + return 0; } @@ -876,6 +871,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = { .ndo_open = ti_hecc_open, .ndo_stop = ti_hecc_close, .ndo_start_xmit = ti_hecc_xmit, + .ndo_change_mtu = can_change_mtu, }; static int ti_hecc_probe(struct platform_device *pdev) @@ -887,7 +883,7 @@ static int ti_hecc_probe(struct platform_device *pdev) void __iomem *addr; int err = -ENODEV; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data\n"); goto probe_exit; @@ -933,7 +929,6 @@ static int ti_hecc_probe(struct platform_device *pdev) priv->can.bittiming_const = &ti_hecc_bittiming_const; priv->can.do_set_mode = ti_hecc_do_set_mode; - priv->can.do_get_state = ti_hecc_get_state; priv->can.do_get_berr_counter = ti_hecc_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; @@ -961,6 +956,9 @@ static int ti_hecc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "register_candev() failed\n"); goto probe_exit_clk; } + + devm_can_led_init(ndev); + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", priv->base, (u32) ndev->irq); @@ -978,7 +976,7 @@ probe_exit: return err; } -static int __devexit ti_hecc_remove(struct platform_device *pdev) +static int ti_hecc_remove(struct platform_device *pdev) { struct resource *res; struct net_device *ndev = platform_get_drvdata(pdev); @@ -991,7 +989,6 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev) iounmap(priv->base); release_mem_region(res->start, resource_size(res)); free_candev(ndev); - platform_set_drvdata(pdev, NULL); return 0; } @@ -1045,7 +1042,7 @@ static struct platform_driver ti_hecc_driver = { .owner = THIS_MODULE, }, .probe = ti_hecc_probe, - .remove = __devexit_p(ti_hecc_remove), + .remove = ti_hecc_remove, .suspend = ti_hecc_suspend, .resume = ti_hecc_resume, }; @@ -1055,3 +1052,4 @@ module_platform_driver(ti_hecc_driver); MODULE_AUTHOR("Anant Gole <anantgole@ti.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION(DRV_DESC); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index 0a6876841c2..a77db919363 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -1,5 +1,5 @@ menu "CAN USB interfaces" - depends on USB && CAN_DEV + depends on USB config CAN_EMS_USB tristate "EMS CPC-USB/ARM7 CAN/USB interface" @@ -13,10 +13,55 @@ config CAN_ESD_USB2 This driver supports the CAN-USB/2 interface from esd electronic system design gmbh (http://www.esd.eu). +config CAN_GS_USB + tristate "Geschwister Schneider UG interfaces" + ---help--- + This driver supports the Geschwister Schneider USB/CAN devices. + If unsure choose N, + choose Y for built in support, + M to compile as module (module will be named: gs_usb). + +config CAN_KVASER_USB + tristate "Kvaser CAN/USB interface" + ---help--- + This driver adds support for Kvaser CAN/USB devices like Kvaser + Leaf Light. + + The driver provides support for the following devices: + - Kvaser Leaf Light + - Kvaser Leaf Professional HS + - Kvaser Leaf SemiPro HS + - Kvaser Leaf Professional LS + - Kvaser Leaf Professional SWC + - Kvaser Leaf Professional LIN + - Kvaser Leaf SemiPro LS + - Kvaser Leaf SemiPro SWC + - Kvaser Memorator II HS/HS + - Kvaser USBcan Professional HS/HS + - Kvaser Leaf Light GI + - Kvaser Leaf Professional HS (OBD-II connector) + - Kvaser Memorator Professional HS/LS + - Kvaser Leaf Light "China" + - Kvaser BlackBird SemiPro + - Kvaser USBcan R + - Kvaser Leaf Light v2 + - Kvaser Mini PCI Express HS + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called kvaser_usb. + config CAN_PEAK_USB tristate "PEAK PCAN-USB/USB Pro interfaces" ---help--- This driver supports the PCAN-USB and PCAN-USB Pro adapters from PEAK-System Technik (http://www.peak-system.com). +config CAN_8DEV_USB + tristate "8 devices USB2CAN interface" + ---help--- + This driver supports the USB2CAN interface + from 8 devices (http://www.8devices.com). + endmenu diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile index da6d1d3b296..7b9a393b1ac 100644 --- a/drivers/net/can/usb/Makefile +++ b/drivers/net/can/usb/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o +obj-$(CONFIG_CAN_GS_USB) += gs_usb.o +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/ +obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 086fa321677..00f2534dde7 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -16,7 +16,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <linux/init.h> #include <linux/signal.h> #include <linux/slab.h> #include <linux/module.h> @@ -245,7 +244,6 @@ struct ems_tx_urb_context { struct ems_usb { struct can_priv can; /* must be the first member */ - int open_time; struct sk_buff *echo_skb[MAX_TX_URBS]; @@ -626,6 +624,7 @@ static int ems_usb_start(struct ems_usb *dev) usb_unanchor_urb(urb); usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma); + usb_free_urb(urb); break; } @@ -728,7 +727,6 @@ static int ems_usb_open(struct net_device *netdev) return err; } - dev->open_time = jiffies; netif_start_queue(netdev); @@ -800,8 +798,8 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne * allowed (MAX_TX_URBS). */ if (!context) { - usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); + usb_free_urb(urb); netdev_warn(netdev, "couldn't find free context\n"); @@ -878,8 +876,6 @@ static int ems_usb_close(struct net_device *netdev) close_candev(netdev); - dev->open_time = 0; - return 0; } @@ -887,6 +883,7 @@ static const struct net_device_ops ems_usb_netdev_ops = { .ndo_open = ems_usb_open, .ndo_stop = ems_usb_close, .ndo_start_xmit = ems_usb_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const ems_usb_bittiming_const = { @@ -905,9 +902,6 @@ static int ems_usb_set_mode(struct net_device *netdev, enum can_mode mode) { struct ems_usb *dev = netdev_priv(netdev); - if (!dev->open_time) - return -EINVAL; - switch (mode) { case CAN_MODE_START: if (ems_usb_write_mode(dev, SJA1000_MOD_NORMAL)) @@ -1021,17 +1015,13 @@ static int ems_usb_probe(struct usb_interface *intf, } dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL); - if (!dev->intr_in_buffer) { - dev_err(&intf->dev, "Couldn't alloc Intr buffer\n"); + if (!dev->intr_in_buffer) goto cleanup_intr_urb; - } dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE + sizeof(struct ems_cpc_msg), GFP_KERNEL); - if (!dev->tx_msg_buffer) { - dev_err(&intf->dev, "Couldn't alloc Tx buffer\n"); + if (!dev->tx_msg_buffer) goto cleanup_intr_in_buffer; - } usb_set_intfdata(intf, dev); diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index bd36e551717..b7c9e8b1146 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -1,7 +1,7 @@ /* - * CAN driver for esd CAN-USB/2 + * CAN driver for esd CAN-USB/2 and CAN-USB/Micro * - * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh + * Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published @@ -16,7 +16,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <linux/init.h> #include <linux/signal.h> #include <linux/slab.h> #include <linux/module.h> @@ -28,14 +27,16 @@ #include <linux/can/error.h> MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>"); -MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces"); +MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces"); MODULE_LICENSE("GPL v2"); /* Define these values to match your devices */ #define USB_ESDGMBH_VENDOR_ID 0x0ab4 #define USB_CANUSB2_PRODUCT_ID 0x0010 +#define USB_CANUSBM_PRODUCT_ID 0x0011 #define ESD_USB2_CAN_CLOCK 60000000 +#define ESD_USBM_CAN_CLOCK 36000000 #define ESD_USB2_MAX_NETS 2 /* USB2 commands */ @@ -69,6 +70,7 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB2_TSEG2_SHIFT 20 #define ESD_USB2_SJW_MAX 4 #define ESD_USB2_SJW_SHIFT 14 +#define ESD_USBM_SJW_SHIFT 24 #define ESD_USB2_BRP_MIN 1 #define ESD_USB2_BRP_MAX 1024 #define ESD_USB2_BRP_INC 1 @@ -183,6 +185,7 @@ struct __attribute__ ((packed)) esd_usb2_msg { static struct usb_device_id esd_usb2_table[] = { {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, {} }; MODULE_DEVICE_TABLE(usb, esd_usb2_table); @@ -213,7 +216,6 @@ struct esd_usb2_net_priv { struct usb_anchor tx_submitted; struct esd_tx_urb_context tx_contexts[MAX_TX_URBS]; - int open_time; struct esd_usb2 *usb2; struct net_device *netdev; int index; @@ -409,10 +411,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb) switch (msg->msg.hdr.cmd) { case CMD_CAN_RX: + if (msg->msg.rx.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg); break; case CMD_CAN_TX: + if (msg->msg.txdone.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net], msg); break; @@ -609,9 +621,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv) { struct esd_usb2 *dev = priv->usb2; struct net_device *netdev = priv->netdev; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int err, i; + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto out; + } + /* * Enable all IDs * The IDADD message takes up to 64 32 bit bitmasks (2048 bits). @@ -625,33 +643,32 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv) * the number of the starting bitmask (0..64) to the filter.option * field followed by only some bitmasks. */ - msg.msg.hdr.cmd = CMD_IDADD; - msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; - msg.msg.filter.net = priv->index; - msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ + msg->msg.hdr.cmd = CMD_IDADD; + msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->msg.filter.net = priv->index; + msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ for (i = 0; i < ESD_MAX_ID_SEGMENT; i++) - msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff); + msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff); /* enable 29bit extended IDs */ - msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); + msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); - err = esd_usb2_send_msg(dev, &msg); + err = esd_usb2_send_msg(dev, msg); if (err) - goto failed; + goto out; err = esd_usb2_setup_rx_urbs(dev); if (err) - goto failed; + goto out; priv->can.state = CAN_STATE_ERROR_ACTIVE; - return 0; - -failed: +out: if (err == -ENODEV) netif_device_detach(netdev); + if (err) + netdev_err(netdev, "couldn't start device: %d\n", err); - netdev_err(netdev, "couldn't start device: %d\n", err); - + kfree(msg); return err; } @@ -691,8 +708,6 @@ static int esd_usb2_open(struct net_device *netdev) return err; } - priv->open_time = jiffies; - netif_start_queue(netdev); return 0; @@ -832,26 +847,30 @@ nourbmem: static int esd_usb2_close(struct net_device *netdev) { struct esd_usb2_net_priv *priv = netdev_priv(netdev); - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int i; + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + /* Disable all IDs (see esd_usb2_start()) */ - msg.msg.hdr.cmd = CMD_IDADD; - msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; - msg.msg.filter.net = priv->index; - msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ + msg->msg.hdr.cmd = CMD_IDADD; + msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->msg.filter.net = priv->index; + msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++) - msg.msg.filter.mask[i] = 0; - if (esd_usb2_send_msg(priv->usb2, &msg) < 0) + msg->msg.filter.mask[i] = 0; + if (esd_usb2_send_msg(priv->usb2, msg) < 0) netdev_err(netdev, "sending idadd message failed\n"); /* set CAN controller to reset mode */ - msg.msg.hdr.len = 2; - msg.msg.hdr.cmd = CMD_SETBAUD; - msg.msg.setbaud.net = priv->index; - msg.msg.setbaud.rsvd = 0; - msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); - if (esd_usb2_send_msg(priv->usb2, &msg) < 0) + msg->msg.hdr.len = 2; + msg->msg.hdr.cmd = CMD_SETBAUD; + msg->msg.setbaud.net = priv->index; + msg->msg.setbaud.rsvd = 0; + msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); + if (esd_usb2_send_msg(priv->usb2, msg) < 0) netdev_err(netdev, "sending setbaud message failed\n"); priv->can.state = CAN_STATE_STOPPED; @@ -860,7 +879,7 @@ static int esd_usb2_close(struct net_device *netdev) close_candev(netdev); - priv->open_time = 0; + kfree(msg); return 0; } @@ -869,6 +888,7 @@ static const struct net_device_ops esd_usb2_netdev_ops = { .ndo_open = esd_usb2_open, .ndo_stop = esd_usb2_close, .ndo_start_xmit = esd_usb2_start_xmit, + .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const esd_usb2_bittiming_const = { @@ -887,13 +907,25 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) { struct esd_usb2_net_priv *priv = netdev_priv(netdev); struct can_bittiming *bt = &priv->can.bittiming; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; + int err; u32 canbtr; + int sjw_shift; canbtr = ESD_USB2_UBR; + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + canbtr |= ESD_USB2_LOM; + canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1); + + if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) == + USB_CANUSBM_PRODUCT_ID) + sjw_shift = ESD_USBM_SJW_SHIFT; + else + sjw_shift = ESD_USB2_SJW_SHIFT; + canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1)) - << ESD_USB2_SJW_SHIFT; + << sjw_shift; canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1) & (ESD_USB2_TSEG1_MAX - 1)) << ESD_USB2_TSEG1_SHIFT; @@ -902,15 +934,22 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) canbtr |= ESD_USB2_3_SAMPLES; - msg.msg.hdr.len = 2; - msg.msg.hdr.cmd = CMD_SETBAUD; - msg.msg.setbaud.net = priv->index; - msg.msg.setbaud.rsvd = 0; - msg.msg.setbaud.baud = cpu_to_le32(canbtr); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->msg.hdr.len = 2; + msg->msg.hdr.cmd = CMD_SETBAUD; + msg->msg.setbaud.net = priv->index; + msg->msg.setbaud.rsvd = 0; + msg->msg.setbaud.baud = cpu_to_le32(canbtr); netdev_info(netdev, "setting BTR=%#x\n", canbtr); - return esd_usb2_send_msg(priv->usb2, &msg); + err = esd_usb2_send_msg(priv->usb2, msg); + + kfree(msg); + return err; } static int esd_usb2_get_berr_counter(const struct net_device *netdev, @@ -926,11 +965,6 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev, static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode) { - struct esd_usb2_net_priv *priv = netdev_priv(netdev); - - if (!priv->open_time) - return -EINVAL; - switch (mode) { case CAN_MODE_START: netif_wake_queue(netdev); @@ -971,18 +1005,27 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index) priv->index = index; priv->can.state = CAN_STATE_STOPPED; - priv->can.clock.freq = ESD_USB2_CAN_CLOCK; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY; + + if (le16_to_cpu(dev->udev->descriptor.idProduct) == + USB_CANUSBM_PRODUCT_ID) + priv->can.clock.freq = ESD_USBM_CAN_CLOCK; + else { + priv->can.clock.freq = ESD_USB2_CAN_CLOCK; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + } + priv->can.bittiming_const = &esd_usb2_bittiming_const; priv->can.do_set_bittiming = esd_usb2_set_bittiming; priv->can.do_set_mode = esd_usb2_set_mode; priv->can.do_get_berr_counter = esd_usb2_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->netdev_ops = &esd_usb2_netdev_ops; SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = index; err = register_candev(netdev); if (err) { @@ -1009,7 +1052,7 @@ static int esd_usb2_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct esd_usb2 *dev; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int i, err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1024,27 +1067,33 @@ static int esd_usb2_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto free_msg; + } + /* query number of CAN interfaces (nets) */ - msg.msg.hdr.cmd = CMD_VERSION; - msg.msg.hdr.len = 2; - msg.msg.version.rsvd = 0; - msg.msg.version.flags = 0; - msg.msg.version.drv_version = 0; + msg->msg.hdr.cmd = CMD_VERSION; + msg->msg.hdr.len = 2; + msg->msg.version.rsvd = 0; + msg->msg.version.flags = 0; + msg->msg.version.drv_version = 0; - err = esd_usb2_send_msg(dev, &msg); + err = esd_usb2_send_msg(dev, msg); if (err < 0) { dev_err(&intf->dev, "sending version message failed\n"); - goto free_dev; + goto free_msg; } - err = esd_usb2_wait_msg(dev, &msg); + err = esd_usb2_wait_msg(dev, msg); if (err < 0) { dev_err(&intf->dev, "no version message answer\n"); - goto free_dev; + goto free_msg; } - dev->net_count = (int)msg.msg.version_reply.nets; - dev->version = le32_to_cpu(msg.msg.version_reply.version); + dev->net_count = (int)msg->msg.version_reply.nets; + dev->version = le32_to_cpu(msg->msg.version_reply.version); if (device_create_file(&intf->dev, &dev_attr_firmware)) dev_err(&intf->dev, @@ -1062,10 +1111,10 @@ static int esd_usb2_probe(struct usb_interface *intf, for (i = 0; i < dev->net_count; i++) esd_usb2_probe_one_net(intf, i); - return 0; - -free_dev: - kfree(dev); +free_msg: + kfree(msg); + if (err) + kfree(dev); done: return err; } diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c new file mode 100644 index 00000000000..04b0f84612f --- /dev/null +++ b/drivers/net/can/usb/gs_usb.c @@ -0,0 +1,971 @@ +/* CAN driver for Geschwister Schneider USB/CAN devices. + * + * Copyright (C) 2013 Geschwister Schneider Technologie-, + * Entwicklungs- und Vertriebs UG (Haftungsbeschränkt). + * + * Many thanks to all socketcan devs! + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +/* Device specific constants */ +#define USB_GSUSB_1_VENDOR_ID 0x1d50 +#define USB_GSUSB_1_PRODUCT_ID 0x606f + +#define GSUSB_ENDPOINT_IN 1 +#define GSUSB_ENDPOINT_OUT 2 + +/* Device specific constants */ +enum gs_usb_breq { + GS_USB_BREQ_HOST_FORMAT = 0, + GS_USB_BREQ_BITTIMING, + GS_USB_BREQ_MODE, + GS_USB_BREQ_BERR, + GS_USB_BREQ_BT_CONST, + GS_USB_BREQ_DEVICE_CONFIG +}; + +enum gs_can_mode { + /* reset a channel. turns it off */ + GS_CAN_MODE_RESET = 0, + /* starts a channel */ + GS_CAN_MODE_START +}; + +enum gs_can_state { + GS_CAN_STATE_ERROR_ACTIVE = 0, + GS_CAN_STATE_ERROR_WARNING, + GS_CAN_STATE_ERROR_PASSIVE, + GS_CAN_STATE_BUS_OFF, + GS_CAN_STATE_STOPPED, + GS_CAN_STATE_SLEEPING +}; + +/* data types passed between host and device */ +struct gs_host_config { + u32 byte_order; +} __packed; +/* All data exchanged between host and device is exchanged in host byte order, + * thanks to the struct gs_host_config byte_order member, which is sent first + * to indicate the desired byte order. + */ + +struct gs_device_config { + u8 reserved1; + u8 reserved2; + u8 reserved3; + u8 icount; + u32 sw_version; + u32 hw_version; +} __packed; + +#define GS_CAN_MODE_NORMAL 0 +#define GS_CAN_MODE_LISTEN_ONLY (1<<0) +#define GS_CAN_MODE_LOOP_BACK (1<<1) +#define GS_CAN_MODE_TRIPLE_SAMPLE (1<<2) +#define GS_CAN_MODE_ONE_SHOT (1<<3) + +struct gs_device_mode { + u32 mode; + u32 flags; +} __packed; + +struct gs_device_state { + u32 state; + u32 rxerr; + u32 txerr; +} __packed; + +struct gs_device_bittiming { + u32 prop_seg; + u32 phase_seg1; + u32 phase_seg2; + u32 sjw; + u32 brp; +} __packed; + +#define GS_CAN_FEATURE_LISTEN_ONLY (1<<0) +#define GS_CAN_FEATURE_LOOP_BACK (1<<1) +#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1<<2) +#define GS_CAN_FEATURE_ONE_SHOT (1<<3) + +struct gs_device_bt_const { + u32 feature; + u32 fclk_can; + u32 tseg1_min; + u32 tseg1_max; + u32 tseg2_min; + u32 tseg2_max; + u32 sjw_max; + u32 brp_min; + u32 brp_max; + u32 brp_inc; +} __packed; + +#define GS_CAN_FLAG_OVERFLOW 1 + +struct gs_host_frame { + u32 echo_id; + u32 can_id; + + u8 can_dlc; + u8 channel; + u8 flags; + u8 reserved; + + u8 data[8]; +} __packed; +/* The GS USB devices make use of the same flags and masks as in + * linux/can.h and linux/can/error.h, and no additional mapping is necessary. + */ + +/* Only send a max of GS_MAX_TX_URBS frames per channel at a time. */ +#define GS_MAX_TX_URBS 10 +/* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */ +#define GS_MAX_RX_URBS 30 +/* Maximum number of interfaces the driver supports per device. + * Current hardware only supports 2 interfaces. The future may vary. + */ +#define GS_MAX_INTF 2 + +struct gs_tx_context { + struct gs_can *dev; + unsigned int echo_id; +}; + +struct gs_can { + struct can_priv can; /* must be the first member */ + + struct gs_usb *parent; + + struct net_device *netdev; + struct usb_device *udev; + struct usb_interface *iface; + + struct can_bittiming_const bt_const; + unsigned int channel; /* channel number */ + + /* This lock prevents a race condition between xmit and recieve. */ + spinlock_t tx_ctx_lock; + struct gs_tx_context tx_context[GS_MAX_TX_URBS]; + + struct usb_anchor tx_submitted; + atomic_t active_tx_urbs; +}; + +/* usb interface struct */ +struct gs_usb { + struct gs_can *canch[GS_MAX_INTF]; + struct usb_anchor rx_submitted; + atomic_t active_channels; + struct usb_device *udev; +}; + +/* 'allocate' a tx context. + * returns a valid tx context or NULL if there is no space. + */ +static struct gs_tx_context *gs_alloc_tx_context(struct gs_can *dev) +{ + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->tx_ctx_lock, flags); + + for (; i < GS_MAX_TX_URBS; i++) { + if (dev->tx_context[i].echo_id == GS_MAX_TX_URBS) { + dev->tx_context[i].echo_id = i; + spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); + return &dev->tx_context[i]; + } + } + + spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); + return NULL; +} + +/* releases a tx context + */ +static void gs_free_tx_context(struct gs_tx_context *txc) +{ + txc->echo_id = GS_MAX_TX_URBS; +} + +/* Get a tx context by id. + */ +static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev, unsigned int id) +{ + unsigned long flags; + + if (id < GS_MAX_TX_URBS) { + spin_lock_irqsave(&dev->tx_ctx_lock, flags); + if (dev->tx_context[id].echo_id == id) { + spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); + return &dev->tx_context[id]; + } + spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); + } + return NULL; +} + +static int gs_cmd_reset(struct gs_usb *gsusb, struct gs_can *gsdev) +{ + struct gs_device_mode *dm; + struct usb_interface *intf = gsdev->iface; + int rc; + + dm = kzalloc(sizeof(*dm), GFP_KERNEL); + if (!dm) + return -ENOMEM; + + dm->mode = GS_CAN_MODE_RESET; + + rc = usb_control_msg(interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + GS_USB_BREQ_MODE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + gsdev->channel, + 0, + dm, + sizeof(*dm), + 1000); + + return rc; +} + +static void gs_update_state(struct gs_can *dev, struct can_frame *cf) +{ + struct can_device_stats *can_stats = &dev->can.can_stats; + + if (cf->can_id & CAN_ERR_RESTARTED) { + dev->can.state = CAN_STATE_ERROR_ACTIVE; + can_stats->restarts++; + } else if (cf->can_id & CAN_ERR_BUSOFF) { + dev->can.state = CAN_STATE_BUS_OFF; + can_stats->bus_off++; + } else if (cf->can_id & CAN_ERR_CRTL) { + if ((cf->data[1] & CAN_ERR_CRTL_TX_WARNING) || + (cf->data[1] & CAN_ERR_CRTL_RX_WARNING)) { + dev->can.state = CAN_STATE_ERROR_WARNING; + can_stats->error_warning++; + } else if ((cf->data[1] & CAN_ERR_CRTL_TX_PASSIVE) || + (cf->data[1] & CAN_ERR_CRTL_RX_PASSIVE)) { + dev->can.state = CAN_STATE_ERROR_PASSIVE; + can_stats->error_passive++; + } else { + dev->can.state = CAN_STATE_ERROR_ACTIVE; + } + } +} + +static void gs_usb_recieve_bulk_callback(struct urb *urb) +{ + struct gs_usb *usbcan = urb->context; + struct gs_can *dev; + struct net_device *netdev; + int rc; + struct net_device_stats *stats; + struct gs_host_frame *hf = urb->transfer_buffer; + struct gs_tx_context *txc; + struct can_frame *cf; + struct sk_buff *skb; + + BUG_ON(!usbcan); + + switch (urb->status) { + case 0: /* success */ + break; + case -ENOENT: + case -ESHUTDOWN: + return; + default: + /* do not resubmit aborted urbs. eg: when device goes down */ + return; + } + + /* device reports out of range channel id */ + if (hf->channel >= GS_MAX_INTF) + goto resubmit_urb; + + dev = usbcan->canch[hf->channel]; + + netdev = dev->netdev; + stats = &netdev->stats; + + if (!netif_device_present(netdev)) + return; + + if (hf->echo_id == -1) { /* normal rx */ + skb = alloc_can_skb(dev->netdev, &cf); + if (!skb) + return; + + cf->can_id = hf->can_id; + + cf->can_dlc = get_can_dlc(hf->can_dlc); + memcpy(cf->data, hf->data, 8); + + /* ERROR frames tell us information about the controller */ + if (hf->can_id & CAN_ERR_FLAG) + gs_update_state(dev, cf); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += hf->can_dlc; + + netif_rx(skb); + } else { /* echo_id == hf->echo_id */ + if (hf->echo_id >= GS_MAX_TX_URBS) { + netdev_err(netdev, + "Unexpected out of range echo id %d\n", + hf->echo_id); + goto resubmit_urb; + } + + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += hf->can_dlc; + + txc = gs_get_tx_context(dev, hf->echo_id); + + /* bad devices send bad echo_ids. */ + if (!txc) { + netdev_err(netdev, + "Unexpected unused echo id %d\n", + hf->echo_id); + goto resubmit_urb; + } + + can_get_echo_skb(netdev, hf->echo_id); + + gs_free_tx_context(txc); + + netif_wake_queue(netdev); + } + + if (hf->flags & GS_CAN_FLAG_OVERFLOW) { + skb = alloc_can_err_skb(netdev, &cf); + if (!skb) + goto resubmit_urb; + + cf->can_id |= CAN_ERR_CRTL; + cf->can_dlc = CAN_ERR_DLC; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_over_errors++; + stats->rx_errors++; + netif_rx(skb); + } + + resubmit_urb: + usb_fill_bulk_urb(urb, + usbcan->udev, + usb_rcvbulkpipe(usbcan->udev, GSUSB_ENDPOINT_IN), + hf, + sizeof(struct gs_host_frame), + gs_usb_recieve_bulk_callback, + usbcan + ); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + + /* USB failure take down all interfaces */ + if (rc == -ENODEV) { + for (rc = 0; rc < GS_MAX_INTF; rc++) { + if (usbcan->canch[rc]) + netif_device_detach(usbcan->canch[rc]->netdev); + } + } +} + +static int gs_usb_set_bittiming(struct net_device *netdev) +{ + struct gs_can *dev = netdev_priv(netdev); + struct can_bittiming *bt = &dev->can.bittiming; + struct usb_interface *intf = dev->iface; + int rc; + struct gs_device_bittiming *dbt; + + dbt = kmalloc(sizeof(*dbt), GFP_KERNEL); + if (!dbt) + return -ENOMEM; + + dbt->prop_seg = bt->prop_seg; + dbt->phase_seg1 = bt->phase_seg1; + dbt->phase_seg2 = bt->phase_seg2; + dbt->sjw = bt->sjw; + dbt->brp = bt->brp; + + /* request bit timings */ + rc = usb_control_msg(interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + GS_USB_BREQ_BITTIMING, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + dev->channel, + 0, + dbt, + sizeof(*dbt), + 1000); + + kfree(dbt); + + if (rc < 0) + dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)", + rc); + + return rc; +} + +static void gs_usb_xmit_callback(struct urb *urb) +{ + struct gs_tx_context *txc = urb->context; + struct gs_can *dev = txc->dev; + struct net_device *netdev = dev->netdev; + + if (urb->status) + netdev_info(netdev, "usb xmit fail %d\n", txc->echo_id); + + usb_free_coherent(urb->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + + atomic_dec(&dev->active_tx_urbs); + + if (!netif_device_present(netdev)) + return; + + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); +} + +static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct gs_can *dev = netdev_priv(netdev); + struct net_device_stats *stats = &dev->netdev->stats; + struct urb *urb; + struct gs_host_frame *hf; + struct can_frame *cf; + int rc; + unsigned int idx; + struct gs_tx_context *txc; + + if (can_dropped_invalid_skb(netdev, skb)) + return NETDEV_TX_OK; + + /* find an empty context to keep track of transmission */ + txc = gs_alloc_tx_context(dev); + if (!txc) + return NETDEV_TX_BUSY; + + /* create a URB, and a buffer for it */ + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + netdev_err(netdev, "No memory left for URB\n"); + goto nomem_urb; + } + + hf = usb_alloc_coherent(dev->udev, sizeof(*hf), GFP_ATOMIC, + &urb->transfer_dma); + if (!hf) { + netdev_err(netdev, "No memory left for USB buffer\n"); + goto nomem_hf; + } + + idx = txc->echo_id; + + if (idx >= GS_MAX_TX_URBS) { + netdev_err(netdev, "Invalid tx context %d\n", idx); + goto badidx; + } + + hf->echo_id = idx; + hf->channel = dev->channel; + + cf = (struct can_frame *)skb->data; + + hf->can_id = cf->can_id; + hf->can_dlc = cf->can_dlc; + memcpy(hf->data, cf->data, cf->can_dlc); + + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, GSUSB_ENDPOINT_OUT), + hf, + sizeof(*hf), + gs_usb_xmit_callback, + txc); + + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &dev->tx_submitted); + + can_put_echo_skb(skb, netdev, idx); + + atomic_inc(&dev->active_tx_urbs); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(rc)) { /* usb send failed */ + atomic_dec(&dev->active_tx_urbs); + + can_free_echo_skb(netdev, idx); + gs_free_tx_context(txc); + + usb_unanchor_urb(urb); + usb_free_coherent(dev->udev, + sizeof(*hf), + hf, + urb->transfer_dma); + + + if (rc == -ENODEV) { + netif_device_detach(netdev); + } else { + netdev_err(netdev, "usb_submit failed (err=%d)\n", rc); + stats->tx_dropped++; + } + } else { + /* Slow down tx path */ + if (atomic_read(&dev->active_tx_urbs) >= GS_MAX_TX_URBS) + netif_stop_queue(netdev); + } + + /* let usb core take care of this urb */ + usb_free_urb(urb); + + return NETDEV_TX_OK; + + badidx: + usb_free_coherent(dev->udev, + sizeof(*hf), + hf, + urb->transfer_dma); + nomem_hf: + usb_free_urb(urb); + + nomem_urb: + gs_free_tx_context(txc); + dev_kfree_skb(skb); + stats->tx_dropped++; + return NETDEV_TX_OK; +} + +static int gs_can_open(struct net_device *netdev) +{ + struct gs_can *dev = netdev_priv(netdev); + struct gs_usb *parent = dev->parent; + int rc, i; + struct gs_device_mode *dm; + u32 ctrlmode; + + rc = open_candev(netdev); + if (rc) + return rc; + + if (atomic_add_return(1, &parent->active_channels) == 1) { + for (i = 0; i < GS_MAX_RX_URBS; i++) { + struct urb *urb; + u8 *buf; + + /* alloc rx urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + netdev_err(netdev, + "No memory left for URB\n"); + return -ENOMEM; + } + + /* alloc rx buffer */ + buf = usb_alloc_coherent(dev->udev, + sizeof(struct gs_host_frame), + GFP_KERNEL, + &urb->transfer_dma); + if (!buf) { + netdev_err(netdev, + "No memory left for USB buffer\n"); + usb_free_urb(urb); + return -ENOMEM; + } + + /* fill, anchor, and submit rx urb */ + usb_fill_bulk_urb(urb, + dev->udev, + usb_rcvbulkpipe(dev->udev, + GSUSB_ENDPOINT_IN), + buf, + sizeof(struct gs_host_frame), + gs_usb_recieve_bulk_callback, + parent); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_anchor_urb(urb, &parent->rx_submitted); + + rc = usb_submit_urb(urb, GFP_KERNEL); + if (rc) { + if (rc == -ENODEV) + netif_device_detach(dev->netdev); + + netdev_err(netdev, + "usb_submit failed (err=%d)\n", + rc); + + usb_unanchor_urb(urb); + break; + } + + /* Drop reference, + * USB core will take care of freeing it + */ + usb_free_urb(urb); + } + } + + dm = kmalloc(sizeof(*dm), GFP_KERNEL); + if (!dm) + return -ENOMEM; + + /* flags */ + ctrlmode = dev->can.ctrlmode; + dm->flags = 0; + + if (ctrlmode & CAN_CTRLMODE_LOOPBACK) + dm->flags |= GS_CAN_MODE_LOOP_BACK; + else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) + dm->flags |= GS_CAN_MODE_LISTEN_ONLY; + + /* Controller is not allowed to retry TX + * this mode is unavailable on atmels uc3c hardware + */ + if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) + dm->flags |= GS_CAN_MODE_ONE_SHOT; + + if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) + dm->flags |= GS_CAN_MODE_TRIPLE_SAMPLE; + + /* finally start device */ + dm->mode = GS_CAN_MODE_START; + rc = usb_control_msg(interface_to_usbdev(dev->iface), + usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0), + GS_USB_BREQ_MODE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + dev->channel, + 0, + dm, + sizeof(*dm), + 1000); + + if (rc < 0) { + netdev_err(netdev, "Couldn't start device (err=%d)\n", rc); + kfree(dm); + return rc; + } + + kfree(dm); + + dev->can.state = CAN_STATE_ERROR_ACTIVE; + + if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) + netif_start_queue(netdev); + + return 0; +} + +static int gs_can_close(struct net_device *netdev) +{ + int rc; + struct gs_can *dev = netdev_priv(netdev); + struct gs_usb *parent = dev->parent; + + netif_stop_queue(netdev); + + /* Stop polling */ + if (atomic_dec_and_test(&parent->active_channels)) + usb_kill_anchored_urbs(&parent->rx_submitted); + + /* Stop sending URBs */ + usb_kill_anchored_urbs(&dev->tx_submitted); + atomic_set(&dev->active_tx_urbs, 0); + + /* reset the device */ + rc = gs_cmd_reset(parent, dev); + if (rc < 0) + netdev_warn(netdev, "Couldn't shutdown device (err=%d)", rc); + + /* reset tx contexts */ + for (rc = 0; rc < GS_MAX_TX_URBS; rc++) { + dev->tx_context[rc].dev = dev; + dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; + } + + /* close the netdev */ + close_candev(netdev); + + return 0; +} + +static const struct net_device_ops gs_usb_netdev_ops = { + .ndo_open = gs_can_open, + .ndo_stop = gs_can_close, + .ndo_start_xmit = gs_can_start_xmit, +}; + +static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf) +{ + struct gs_can *dev; + struct net_device *netdev; + int rc; + struct gs_device_bt_const *bt_const; + + bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL); + if (!bt_const) + return ERR_PTR(-ENOMEM); + + /* fetch bit timing constants */ + rc = usb_control_msg(interface_to_usbdev(intf), + usb_rcvctrlpipe(interface_to_usbdev(intf), 0), + GS_USB_BREQ_BT_CONST, + USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + channel, + 0, + bt_const, + sizeof(*bt_const), + 1000); + + if (rc < 0) { + dev_err(&intf->dev, + "Couldn't get bit timing const for channel (err=%d)\n", + rc); + kfree(bt_const); + return ERR_PTR(rc); + } + + /* create netdev */ + netdev = alloc_candev(sizeof(struct gs_can), GS_MAX_TX_URBS); + if (!netdev) { + dev_err(&intf->dev, "Couldn't allocate candev\n"); + kfree(bt_const); + return ERR_PTR(-ENOMEM); + } + + dev = netdev_priv(netdev); + + netdev->netdev_ops = &gs_usb_netdev_ops; + + netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ + + /* dev settup */ + strcpy(dev->bt_const.name, "gs_usb"); + dev->bt_const.tseg1_min = bt_const->tseg1_min; + dev->bt_const.tseg1_max = bt_const->tseg1_max; + dev->bt_const.tseg2_min = bt_const->tseg2_min; + dev->bt_const.tseg2_max = bt_const->tseg2_max; + dev->bt_const.sjw_max = bt_const->sjw_max; + dev->bt_const.brp_min = bt_const->brp_min; + dev->bt_const.brp_max = bt_const->brp_max; + dev->bt_const.brp_inc = bt_const->brp_inc; + + dev->udev = interface_to_usbdev(intf); + dev->iface = intf; + dev->netdev = netdev; + dev->channel = channel; + + init_usb_anchor(&dev->tx_submitted); + atomic_set(&dev->active_tx_urbs, 0); + spin_lock_init(&dev->tx_ctx_lock); + for (rc = 0; rc < GS_MAX_TX_URBS; rc++) { + dev->tx_context[rc].dev = dev; + dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; + } + + /* can settup */ + dev->can.state = CAN_STATE_STOPPED; + dev->can.clock.freq = bt_const->fclk_can; + dev->can.bittiming_const = &dev->bt_const; + dev->can.do_set_bittiming = gs_usb_set_bittiming; + + dev->can.ctrlmode_supported = 0; + + if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY) + dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY; + + if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK) + dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK; + + if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE) + dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + + if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT) + dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; + + kfree(bt_const); + + SET_NETDEV_DEV(netdev, &intf->dev); + + rc = register_candev(dev->netdev); + if (rc) { + free_candev(dev->netdev); + dev_err(&intf->dev, "Couldn't register candev (err=%d)\n", rc); + return ERR_PTR(rc); + } + + return dev; +} + +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); +} + +static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct gs_usb *dev; + int rc = -ENOMEM; + unsigned int icount, i; + struct gs_host_config *hconf; + struct gs_device_config *dconf; + + hconf = kmalloc(sizeof(*hconf), GFP_KERNEL); + if (!hconf) + return -ENOMEM; + + hconf->byte_order = 0x0000beef; + + /* send host config */ + rc = usb_control_msg(interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + GS_USB_BREQ_HOST_FORMAT, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 1, + intf->altsetting[0].desc.bInterfaceNumber, + hconf, + sizeof(*hconf), + 1000); + + kfree(hconf); + + if (rc < 0) { + dev_err(&intf->dev, "Couldn't send data format (err=%d)\n", + rc); + return rc; + } + + dconf = kmalloc(sizeof(*dconf), GFP_KERNEL); + if (!dconf) + return -ENOMEM; + + /* read device config */ + rc = usb_control_msg(interface_to_usbdev(intf), + usb_rcvctrlpipe(interface_to_usbdev(intf), 0), + GS_USB_BREQ_DEVICE_CONFIG, + USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 1, + intf->altsetting[0].desc.bInterfaceNumber, + dconf, + sizeof(*dconf), + 1000); + if (rc < 0) { + dev_err(&intf->dev, "Couldn't get device config: (err=%d)\n", + rc); + + kfree(dconf); + + return rc; + } + + icount = dconf->icount+1; + + kfree(dconf); + + dev_info(&intf->dev, "Configuring for %d interfaces\n", icount); + + if (icount > GS_MAX_INTF) { + dev_err(&intf->dev, + "Driver cannot handle more that %d CAN interfaces\n", + GS_MAX_INTF); + return -EINVAL; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + init_usb_anchor(&dev->rx_submitted); + + atomic_set(&dev->active_channels, 0); + + usb_set_intfdata(intf, dev); + dev->udev = interface_to_usbdev(intf); + + for (i = 0; i < icount; i++) { + dev->canch[i] = gs_make_candev(i, intf); + if (IS_ERR_OR_NULL(dev->canch[i])) { + /* on failure destroy previously created candevs */ + icount = i; + for (i = 0; i < icount; i++) { + gs_destroy_candev(dev->canch[i]); + dev->canch[i] = NULL; + } + kfree(dev); + return rc; + } + dev->canch[i]->parent = dev; + } + + return 0; +} + +static void gs_usb_disconnect(struct usb_interface *intf) +{ + unsigned i; + struct gs_usb *dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + if (!dev) { + dev_err(&intf->dev, "Disconnect (nodata)\n"); + return; + } + + for (i = 0; i < GS_MAX_INTF; i++) { + struct gs_can *can = dev->canch[i]; + + if (!can) + continue; + + gs_destroy_candev(can); + } + + usb_kill_anchored_urbs(&dev->rx_submitted); +} + +static const struct usb_device_id gs_usb_table[] = { + {USB_DEVICE(USB_GSUSB_1_VENDOR_ID, USB_GSUSB_1_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, gs_usb_table); + +static struct usb_driver gs_usb_driver = { + .name = "gs_usb", + .probe = gs_usb_probe, + .disconnect = gs_usb_disconnect, + .id_table = gs_usb_table, +}; + +module_usb_driver(gs_usb_driver); + +MODULE_AUTHOR("Maximilian Schneider <mws@schneidersoft.net>"); +MODULE_DESCRIPTION( +"Socket CAN device driver for Geschwister Schneider Technologie-, " +"Entwicklungs- und Vertriebs UG. USB2.0 to CAN interfaces."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c new file mode 100644 index 00000000000..541fb7a0562 --- /dev/null +++ b/drivers/net/can/usb/kvaser_usb.c @@ -0,0 +1,1665 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * Parts of this driver are based on the following: + * - Kvaser linux leaf driver (version 4.78) + * - CAN driver for esd CAN-USB/2 + * + * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. + * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh + * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be> + */ + +#include <linux/completion.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#define MAX_TX_URBS 16 +#define MAX_RX_URBS 4 +#define START_TIMEOUT 1000 /* msecs */ +#define STOP_TIMEOUT 1000 /* msecs */ +#define USB_SEND_TIMEOUT 1000 /* msecs */ +#define USB_RECV_TIMEOUT 1000 /* msecs */ +#define RX_BUFFER_SIZE 3072 +#define CAN_USB_CLOCK 8000000 +#define MAX_NET_DEVICES 3 + +/* Kvaser USB devices */ +#define KVASER_VENDOR_ID 0x0bfd +#define USB_LEAF_DEVEL_PRODUCT_ID 10 +#define USB_LEAF_LITE_PRODUCT_ID 11 +#define USB_LEAF_PRO_PRODUCT_ID 12 +#define USB_LEAF_SPRO_PRODUCT_ID 14 +#define USB_LEAF_PRO_LS_PRODUCT_ID 15 +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16 +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17 +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18 +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19 +#define USB_MEMO2_DEVEL_PRODUCT_ID 22 +#define USB_MEMO2_HSHS_PRODUCT_ID 23 +#define USB_UPRO_HSHS_PRODUCT_ID 24 +#define USB_LEAF_LITE_GI_PRODUCT_ID 25 +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26 +#define USB_MEMO2_HSLS_PRODUCT_ID 27 +#define USB_LEAF_LITE_CH_PRODUCT_ID 28 +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29 +#define USB_OEM_MERCURY_PRODUCT_ID 34 +#define USB_OEM_LEAF_PRODUCT_ID 35 +#define USB_CAN_R_PRODUCT_ID 39 +#define USB_LEAF_LITE_V2_PRODUCT_ID 288 +#define USB_MINI_PCIE_HS_PRODUCT_ID 289 + +/* USB devices features */ +#define KVASER_HAS_SILENT_MODE BIT(0) +#define KVASER_HAS_TXRX_ERRORS BIT(1) + +/* Message header size */ +#define MSG_HEADER_LEN 2 + +/* Can message flags */ +#define MSG_FLAG_ERROR_FRAME BIT(0) +#define MSG_FLAG_OVERRUN BIT(1) +#define MSG_FLAG_NERR BIT(2) +#define MSG_FLAG_WAKEUP BIT(3) +#define MSG_FLAG_REMOTE_FRAME BIT(4) +#define MSG_FLAG_RESERVED BIT(5) +#define MSG_FLAG_TX_ACK BIT(6) +#define MSG_FLAG_TX_REQUEST BIT(7) + +/* Can states */ +#define M16C_STATE_BUS_RESET BIT(0) +#define M16C_STATE_BUS_ERROR BIT(4) +#define M16C_STATE_BUS_PASSIVE BIT(5) +#define M16C_STATE_BUS_OFF BIT(6) + +/* Can msg ids */ +#define CMD_RX_STD_MESSAGE 12 +#define CMD_TX_STD_MESSAGE 13 +#define CMD_RX_EXT_MESSAGE 14 +#define CMD_TX_EXT_MESSAGE 15 +#define CMD_SET_BUS_PARAMS 16 +#define CMD_GET_BUS_PARAMS 17 +#define CMD_GET_BUS_PARAMS_REPLY 18 +#define CMD_GET_CHIP_STATE 19 +#define CMD_CHIP_STATE_EVENT 20 +#define CMD_SET_CTRL_MODE 21 +#define CMD_GET_CTRL_MODE 22 +#define CMD_GET_CTRL_MODE_REPLY 23 +#define CMD_RESET_CHIP 24 +#define CMD_RESET_CARD 25 +#define CMD_START_CHIP 26 +#define CMD_START_CHIP_REPLY 27 +#define CMD_STOP_CHIP 28 +#define CMD_STOP_CHIP_REPLY 29 +#define CMD_GET_CARD_INFO2 32 +#define CMD_GET_CARD_INFO 34 +#define CMD_GET_CARD_INFO_REPLY 35 +#define CMD_GET_SOFTWARE_INFO 38 +#define CMD_GET_SOFTWARE_INFO_REPLY 39 +#define CMD_ERROR_EVENT 45 +#define CMD_FLUSH_QUEUE 48 +#define CMD_RESET_ERROR_COUNTER 49 +#define CMD_TX_ACKNOWLEDGE 50 +#define CMD_CAN_ERROR_EVENT 51 +#define CMD_USB_THROTTLE 77 +#define CMD_LOG_MESSAGE 106 + +/* error factors */ +#define M16C_EF_ACKE BIT(0) +#define M16C_EF_CRCE BIT(1) +#define M16C_EF_FORME BIT(2) +#define M16C_EF_STFE BIT(3) +#define M16C_EF_BITE0 BIT(4) +#define M16C_EF_BITE1 BIT(5) +#define M16C_EF_RCVE BIT(6) +#define M16C_EF_TRE BIT(7) + +/* bittiming parameters */ +#define KVASER_USB_TSEG1_MIN 1 +#define KVASER_USB_TSEG1_MAX 16 +#define KVASER_USB_TSEG2_MIN 1 +#define KVASER_USB_TSEG2_MAX 8 +#define KVASER_USB_SJW_MAX 4 +#define KVASER_USB_BRP_MIN 1 +#define KVASER_USB_BRP_MAX 64 +#define KVASER_USB_BRP_INC 1 + +/* ctrl modes */ +#define KVASER_CTRL_MODE_NORMAL 1 +#define KVASER_CTRL_MODE_SILENT 2 +#define KVASER_CTRL_MODE_SELFRECEPTION 3 +#define KVASER_CTRL_MODE_OFF 4 + +/* log message */ +#define KVASER_EXTENDED_FRAME BIT(31) + +struct kvaser_msg_simple { + u8 tid; + u8 channel; +} __packed; + +struct kvaser_msg_cardinfo { + u8 tid; + u8 nchannels; + __le32 serial_number; + __le32 padding; + __le32 clock_resolution; + __le32 mfgdate; + u8 ean[8]; + u8 hw_revision; + u8 usb_hs_mode; + __le16 padding2; +} __packed; + +struct kvaser_msg_cardinfo2 { + u8 tid; + u8 channel; + u8 pcb_id[24]; + __le32 oem_unlock_code; +} __packed; + +struct kvaser_msg_softinfo { + u8 tid; + u8 channel; + __le32 sw_options; + __le32 fw_version; + __le16 max_outstanding_tx; + __le16 padding[9]; +} __packed; + +struct kvaser_msg_busparams { + u8 tid; + u8 channel; + __le32 bitrate; + u8 tseg1; + u8 tseg2; + u8 sjw; + u8 no_samp; +} __packed; + +struct kvaser_msg_tx_can { + u8 channel; + u8 tid; + u8 msg[14]; + u8 padding; + u8 flags; +} __packed; + +struct kvaser_msg_rx_can { + u8 channel; + u8 flag; + __le16 time[3]; + u8 msg[14]; +} __packed; + +struct kvaser_msg_chip_state_event { + u8 tid; + u8 channel; + __le16 time[3]; + u8 tx_errors_count; + u8 rx_errors_count; + u8 status; + u8 padding[3]; +} __packed; + +struct kvaser_msg_tx_acknowledge { + u8 channel; + u8 tid; + __le16 time[3]; + u8 flags; + u8 time_offset; +} __packed; + +struct kvaser_msg_error_event { + u8 tid; + u8 flags; + __le16 time[3]; + u8 channel; + u8 padding; + u8 tx_errors_count; + u8 rx_errors_count; + u8 status; + u8 error_factor; +} __packed; + +struct kvaser_msg_ctrl_mode { + u8 tid; + u8 channel; + u8 ctrl_mode; + u8 padding[3]; +} __packed; + +struct kvaser_msg_flush_queue { + u8 tid; + u8 channel; + u8 flags; + u8 padding[3]; +} __packed; + +struct kvaser_msg_log_message { + u8 channel; + u8 flags; + __le16 time[3]; + u8 dlc; + u8 time_offset; + __le32 id; + u8 data[8]; +} __packed; + +struct kvaser_msg { + u8 len; + u8 id; + union { + struct kvaser_msg_simple simple; + struct kvaser_msg_cardinfo cardinfo; + struct kvaser_msg_cardinfo2 cardinfo2; + struct kvaser_msg_softinfo softinfo; + struct kvaser_msg_busparams busparams; + struct kvaser_msg_tx_can tx_can; + struct kvaser_msg_rx_can rx_can; + struct kvaser_msg_chip_state_event chip_state_event; + struct kvaser_msg_tx_acknowledge tx_acknowledge; + struct kvaser_msg_error_event error_event; + struct kvaser_msg_ctrl_mode ctrl_mode; + struct kvaser_msg_flush_queue flush_queue; + struct kvaser_msg_log_message log_message; + } u; +} __packed; + +struct kvaser_usb_tx_urb_context { + struct kvaser_usb_net_priv *priv; + u32 echo_index; + int dlc; +}; + +struct kvaser_usb { + struct usb_device *udev; + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES]; + + struct usb_endpoint_descriptor *bulk_in, *bulk_out; + struct usb_anchor rx_submitted; + + u32 fw_version; + unsigned int nchannels; + + bool rxinitdone; + void *rxbuf[MAX_RX_URBS]; + dma_addr_t rxbuf_dma[MAX_RX_URBS]; +}; + +struct kvaser_usb_net_priv { + struct can_priv can; + + atomic_t active_tx_urbs; + struct usb_anchor tx_submitted; + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS]; + + struct completion start_comp, stop_comp; + + struct kvaser_usb *dev; + struct net_device *netdev; + int channel; + + struct can_berr_counter bec; +}; + +static const struct usb_device_id kvaser_usb_table[] = { + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS | + KVASER_HAS_SILENT_MODE }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + { } +}; +MODULE_DEVICE_TABLE(usb, kvaser_usb_table); + +static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev, + struct kvaser_msg *msg) +{ + int actual_len; + + return usb_bulk_msg(dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out->bEndpointAddress), + msg, msg->len, &actual_len, + USB_SEND_TIMEOUT); +} + +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, + struct kvaser_msg *msg) +{ + struct kvaser_msg *tmp; + void *buf; + int actual_len; + int err; + int pos; + unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT); + + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + do { + err = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in->bEndpointAddress), + buf, RX_BUFFER_SIZE, &actual_len, + USB_RECV_TIMEOUT); + if (err < 0) + goto end; + + pos = 0; + while (pos <= actual_len - MSG_HEADER_LEN) { + tmp = buf + pos; + + if (!tmp->len) + break; + + if (pos + tmp->len > actual_len) { + dev_err(dev->udev->dev.parent, + "Format error\n"); + break; + } + + if (tmp->id == id) { + memcpy(msg, tmp, tmp->len); + goto end; + } + + pos += tmp->len; + } + } while (time_before(jiffies, to)); + + err = -EINVAL; + +end: + kfree(buf); + + return err; +} + +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev, + u8 msg_id, int channel) +{ + struct kvaser_msg *msg; + int rc; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->id = msg_id; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple); + msg->u.simple.channel = channel; + msg->u.simple.tid = 0xff; + + rc = kvaser_usb_send_msg(dev, msg); + + kfree(msg); + return rc; +} + +static int kvaser_usb_get_software_info(struct kvaser_usb *dev) +{ + struct kvaser_msg msg; + int err; + + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0); + if (err) + return err; + + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg); + if (err) + return err; + + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version); + + return 0; +} + +static int kvaser_usb_get_card_info(struct kvaser_usb *dev) +{ + struct kvaser_msg msg; + int err; + + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0); + if (err) + return err; + + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg); + if (err) + return err; + + dev->nchannels = msg.u.cardinfo.nchannels; + if (dev->nchannels > MAX_NET_DEVICES) + return -EINVAL; + + return 0; +} + +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct net_device_stats *stats; + struct kvaser_usb_tx_urb_context *context; + struct kvaser_usb_net_priv *priv; + struct sk_buff *skb; + struct can_frame *cf; + u8 channel = msg->u.tx_acknowledge.channel; + u8 tid = msg->u.tx_acknowledge.tid; + + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + + if (!netif_device_present(priv->netdev)) + return; + + stats = &priv->netdev->stats; + + context = &priv->tx_contexts[tid % MAX_TX_URBS]; + + /* Sometimes the state change doesn't come after a bus-off event */ + if (priv->can.restart_ms && + (priv->can.state >= CAN_STATE_BUS_OFF)) { + skb = alloc_can_err_skb(priv->netdev, &cf); + if (skb) { + cf->can_id |= CAN_ERR_RESTARTED; + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + } else { + netdev_err(priv->netdev, + "No memory left for err_skb\n"); + } + + priv->can.can_stats.restarts++; + netif_carrier_on(priv->netdev); + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } + + stats->tx_packets++; + stats->tx_bytes += context->dlc; + can_get_echo_skb(priv->netdev, context->echo_index); + + context->echo_index = MAX_TX_URBS; + atomic_dec(&priv->active_tx_urbs); + + netif_wake_queue(priv->netdev); +} + +static void kvaser_usb_simple_msg_callback(struct urb *urb) +{ + struct net_device *netdev = urb->context; + + kfree(urb->transfer_buffer); + + if (urb->status) + netdev_warn(netdev, "urb status received: %d\n", + urb->status); +} + +static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv, + u8 msg_id) +{ + struct kvaser_usb *dev = priv->dev; + struct net_device *netdev = priv->netdev; + struct kvaser_msg *msg; + struct urb *urb; + void *buf; + int err; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + netdev_err(netdev, "No memory left for URBs\n"); + return -ENOMEM; + } + + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); + if (!buf) { + usb_free_urb(urb); + return -ENOMEM; + } + + msg = (struct kvaser_msg *)buf; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple); + msg->id = msg_id; + msg->u.simple.channel = priv->channel; + + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out->bEndpointAddress), + buf, msg->len, + kvaser_usb_simple_msg_callback, priv); + usb_anchor_urb(urb, &priv->tx_submitted); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + netdev_err(netdev, "Error transmitting URB\n"); + usb_unanchor_urb(urb); + usb_free_urb(urb); + kfree(buf); + return err; + } + + usb_free_urb(urb); + + return 0; +} + +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) +{ + int i; + + usb_kill_anchored_urbs(&priv->tx_submitted); + atomic_set(&priv->active_tx_urbs, 0); + + for (i = 0; i < MAX_TX_URBS; i++) + priv->tx_contexts[i].echo_index = MAX_TX_URBS; +} + +static void kvaser_usb_rx_error(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct net_device_stats *stats; + struct kvaser_usb_net_priv *priv; + unsigned int new_state; + u8 channel, status, txerr, rxerr, error_factor; + + switch (msg->id) { + case CMD_CAN_ERROR_EVENT: + channel = msg->u.error_event.channel; + status = msg->u.error_event.status; + txerr = msg->u.error_event.tx_errors_count; + rxerr = msg->u.error_event.rx_errors_count; + error_factor = msg->u.error_event.error_factor; + break; + case CMD_LOG_MESSAGE: + channel = msg->u.log_message.channel; + status = msg->u.log_message.data[0]; + txerr = msg->u.log_message.data[2]; + rxerr = msg->u.log_message.data[3]; + error_factor = msg->u.log_message.data[1]; + break; + case CMD_CHIP_STATE_EVENT: + channel = msg->u.chip_state_event.channel; + status = msg->u.chip_state_event.status; + txerr = msg->u.chip_state_event.tx_errors_count; + rxerr = msg->u.chip_state_event.rx_errors_count; + error_factor = 0; + break; + default: + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", + msg->id); + return; + } + + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + stats = &priv->netdev->stats; + + if (status & M16C_STATE_BUS_RESET) { + kvaser_usb_unlink_tx_urbs(priv); + return; + } + + skb = alloc_can_err_skb(priv->netdev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + new_state = priv->can.state; + + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); + + if (status & M16C_STATE_BUS_OFF) { + cf->can_id |= CAN_ERR_BUSOFF; + + priv->can.can_stats.bus_off++; + if (!priv->can.restart_ms) + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); + + netif_carrier_off(priv->netdev); + + new_state = CAN_STATE_BUS_OFF; + } else if (status & M16C_STATE_BUS_PASSIVE) { + if (priv->can.state != CAN_STATE_ERROR_PASSIVE) { + cf->can_id |= CAN_ERR_CRTL; + + if (txerr || rxerr) + cf->data[1] = (txerr > rxerr) + ? CAN_ERR_CRTL_TX_PASSIVE + : CAN_ERR_CRTL_RX_PASSIVE; + else + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | + CAN_ERR_CRTL_RX_PASSIVE; + + priv->can.can_stats.error_passive++; + } + + new_state = CAN_STATE_ERROR_PASSIVE; + } + + if (status == M16C_STATE_BUS_ERROR) { + if ((priv->can.state < CAN_STATE_ERROR_WARNING) && + ((txerr >= 96) || (rxerr >= 96))) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (txerr > rxerr) + ? CAN_ERR_CRTL_TX_WARNING + : CAN_ERR_CRTL_RX_WARNING; + + priv->can.can_stats.error_warning++; + new_state = CAN_STATE_ERROR_WARNING; + } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_ACTIVE; + + new_state = CAN_STATE_ERROR_ACTIVE; + } + } + + if (!status) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_ACTIVE; + + new_state = CAN_STATE_ERROR_ACTIVE; + } + + if (priv->can.restart_ms && + (priv->can.state >= CAN_STATE_BUS_OFF) && + (new_state < CAN_STATE_BUS_OFF)) { + cf->can_id |= CAN_ERR_RESTARTED; + netif_carrier_on(priv->netdev); + + priv->can.can_stats.restarts++; + } + + if (error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; + + if (error_factor & M16C_EF_ACKE) + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); + if (error_factor & M16C_EF_CRCE) + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + CAN_ERR_PROT_LOC_CRC_DEL); + if (error_factor & M16C_EF_FORME) + cf->data[2] |= CAN_ERR_PROT_FORM; + if (error_factor & M16C_EF_STFE) + cf->data[2] |= CAN_ERR_PROT_STUFF; + if (error_factor & M16C_EF_BITE0) + cf->data[2] |= CAN_ERR_PROT_BIT0; + if (error_factor & M16C_EF_BITE1) + cf->data[2] |= CAN_ERR_PROT_BIT1; + if (error_factor & M16C_EF_TRE) + cf->data[2] |= CAN_ERR_PROT_TX; + } + + cf->data[6] = txerr; + cf->data[7] = rxerr; + + priv->bec.txerr = txerr; + priv->bec.rxerr = rxerr; + + priv->can.state = new_state; + + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +} + +static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, + const struct kvaser_msg *msg) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct net_device_stats *stats = &priv->netdev->stats; + + if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | + MSG_FLAG_NERR)) { + netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n", + msg->u.rx_can.flag); + + stats->rx_errors++; + return; + } + + if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) { + skb = alloc_can_err_skb(priv->netdev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + + stats->rx_over_errors++; + stats->rx_errors++; + + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + } +} + +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_net_priv *priv; + struct can_frame *cf; + struct sk_buff *skb; + struct net_device_stats *stats; + u8 channel = msg->u.rx_can.channel; + + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + stats = &priv->netdev->stats; + + if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) && + (msg->id == CMD_LOG_MESSAGE)) { + kvaser_usb_rx_error(dev, msg); + return; + } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | + MSG_FLAG_NERR | + MSG_FLAG_OVERRUN)) { + kvaser_usb_rx_can_err(priv, msg); + return; + } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) { + netdev_warn(priv->netdev, + "Unhandled frame (flags: 0x%02x)", + msg->u.rx_can.flag); + return; + } + + skb = alloc_can_skb(priv->netdev, &cf); + if (!skb) { + stats->tx_dropped++; + return; + } + + if (msg->id == CMD_LOG_MESSAGE) { + cf->can_id = le32_to_cpu(msg->u.log_message.id); + if (cf->can_id & KVASER_EXTENDED_FRAME) + cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; + else + cf->can_id &= CAN_SFF_MASK; + + cf->can_dlc = get_can_dlc(msg->u.log_message.dlc); + + if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, &msg->u.log_message.data, + cf->can_dlc); + } else { + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | + (msg->u.rx_can.msg[1] & 0x3f); + + if (msg->id == CMD_RX_EXT_MESSAGE) { + cf->can_id <<= 18; + cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | + ((msg->u.rx_can.msg[3] & 0xff) << 6) | + (msg->u.rx_can.msg[4] & 0x3f); + cf->can_id |= CAN_EFF_FLAG; + } + + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, &msg->u.rx_can.msg[6], + cf->can_dlc); + } + + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +} + +static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_net_priv *priv; + u8 channel = msg->u.simple.channel; + + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + + if (completion_done(&priv->start_comp) && + netif_queue_stopped(priv->netdev)) { + netif_wake_queue(priv->netdev); + } else { + netif_start_queue(priv->netdev); + complete(&priv->start_comp); + } +} + +static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_net_priv *priv; + u8 channel = msg->u.simple.channel; + + if (channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", channel); + return; + } + + priv = dev->nets[channel]; + + complete(&priv->stop_comp); +} + +static void kvaser_usb_handle_message(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + switch (msg->id) { + case CMD_START_CHIP_REPLY: + kvaser_usb_start_chip_reply(dev, msg); + break; + + case CMD_STOP_CHIP_REPLY: + kvaser_usb_stop_chip_reply(dev, msg); + break; + + case CMD_RX_STD_MESSAGE: + case CMD_RX_EXT_MESSAGE: + case CMD_LOG_MESSAGE: + kvaser_usb_rx_can_msg(dev, msg); + break; + + case CMD_CHIP_STATE_EVENT: + case CMD_CAN_ERROR_EVENT: + kvaser_usb_rx_error(dev, msg); + break; + + case CMD_TX_ACKNOWLEDGE: + kvaser_usb_tx_acknowledge(dev, msg); + break; + + default: + dev_warn(dev->udev->dev.parent, + "Unhandled message (%d)\n", msg->id); + break; + } +} + +static void kvaser_usb_read_bulk_callback(struct urb *urb) +{ + struct kvaser_usb *dev = urb->context; + struct kvaser_msg *msg; + int pos = 0; + int err, i; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ESHUTDOWN: + return; + default: + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n", + urb->status); + goto resubmit_urb; + } + + while (pos <= urb->actual_length - MSG_HEADER_LEN) { + msg = urb->transfer_buffer + pos; + + if (!msg->len) + break; + + if (pos + msg->len > urb->actual_length) { + dev_err(dev->udev->dev.parent, "Format error\n"); + break; + } + + kvaser_usb_handle_message(dev, msg); + + pos += msg->len; + } + +resubmit_urb: + usb_fill_bulk_urb(urb, dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in->bEndpointAddress), + urb->transfer_buffer, RX_BUFFER_SIZE, + kvaser_usb_read_bulk_callback, dev); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err == -ENODEV) { + for (i = 0; i < dev->nchannels; i++) { + if (!dev->nets[i]) + continue; + + netif_device_detach(dev->nets[i]->netdev); + } + } else if (err) { + dev_err(dev->udev->dev.parent, + "Failed resubmitting read bulk urb: %d\n", err); + } + + return; +} + +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev) +{ + int i, err = 0; + + if (dev->rxinitdone) + return 0; + + for (i = 0; i < MAX_RX_URBS; i++) { + struct urb *urb = NULL; + u8 *buf = NULL; + dma_addr_t buf_dma; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_warn(dev->udev->dev.parent, + "No memory left for URBs\n"); + err = -ENOMEM; + break; + } + + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, + GFP_KERNEL, &buf_dma); + if (!buf) { + dev_warn(dev->udev->dev.parent, + "No memory left for USB buffer\n"); + usb_free_urb(urb); + err = -ENOMEM; + break; + } + + usb_fill_bulk_urb(urb, dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in->bEndpointAddress), + buf, RX_BUFFER_SIZE, + kvaser_usb_read_bulk_callback, + dev); + urb->transfer_dma = buf_dma; + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &dev->rx_submitted); + + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + usb_unanchor_urb(urb); + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, + buf_dma); + usb_free_urb(urb); + break; + } + + dev->rxbuf[i] = buf; + dev->rxbuf_dma[i] = buf_dma; + + usb_free_urb(urb); + } + + if (i == 0) { + dev_warn(dev->udev->dev.parent, + "Cannot setup read URBs, error %d\n", err); + return err; + } else if (i < MAX_RX_URBS) { + dev_warn(dev->udev->dev.parent, + "RX performances may be slow\n"); + } + + dev->rxinitdone = true; + + return 0; +} + +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv) +{ + struct kvaser_msg *msg; + int rc; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->id = CMD_SET_CTRL_MODE; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_ctrl_mode); + msg->u.ctrl_mode.tid = 0xff; + msg->u.ctrl_mode.channel = priv->channel; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT; + else + msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL; + + rc = kvaser_usb_send_msg(priv->dev, msg); + + kfree(msg); + return rc; +} + +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv) +{ + int err; + + init_completion(&priv->start_comp); + + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP, + priv->channel); + if (err) + return err; + + if (!wait_for_completion_timeout(&priv->start_comp, + msecs_to_jiffies(START_TIMEOUT))) + return -ETIMEDOUT; + + return 0; +} + +static int kvaser_usb_open(struct net_device *netdev) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + struct kvaser_usb *dev = priv->dev; + int err; + + err = open_candev(netdev); + if (err) + return err; + + err = kvaser_usb_setup_rx_urbs(dev); + if (err) + goto error; + + err = kvaser_usb_set_opt_mode(priv); + if (err) + goto error; + + err = kvaser_usb_start_chip(priv); + if (err) { + netdev_warn(netdev, "Cannot start device, error %d\n", err); + goto error; + } + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + return 0; + +error: + close_candev(netdev); + return err; +} + +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) +{ + int i; + + usb_kill_anchored_urbs(&dev->rx_submitted); + + for (i = 0; i < MAX_RX_URBS; i++) + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, + dev->rxbuf[i], + dev->rxbuf_dma[i]); + + for (i = 0; i < MAX_NET_DEVICES; i++) { + struct kvaser_usb_net_priv *priv = dev->nets[i]; + + if (priv) + kvaser_usb_unlink_tx_urbs(priv); + } +} + +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv) +{ + int err; + + init_completion(&priv->stop_comp); + + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP, + priv->channel); + if (err) + return err; + + if (!wait_for_completion_timeout(&priv->stop_comp, + msecs_to_jiffies(STOP_TIMEOUT))) + return -ETIMEDOUT; + + return 0; +} + +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv) +{ + struct kvaser_msg *msg; + int rc; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->id = CMD_FLUSH_QUEUE; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_flush_queue); + msg->u.flush_queue.channel = priv->channel; + msg->u.flush_queue.flags = 0x00; + + rc = kvaser_usb_send_msg(priv->dev, msg); + + kfree(msg); + return rc; +} + +static int kvaser_usb_close(struct net_device *netdev) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + struct kvaser_usb *dev = priv->dev; + int err; + + netif_stop_queue(netdev); + + err = kvaser_usb_flush_queue(priv); + if (err) + netdev_warn(netdev, "Cannot flush queue, error %d\n", err); + + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel)) + netdev_warn(netdev, "Cannot reset card, error %d\n", err); + + err = kvaser_usb_stop_chip(priv); + if (err) + netdev_warn(netdev, "Cannot stop device, error %d\n", err); + + priv->can.state = CAN_STATE_STOPPED; + close_candev(priv->netdev); + + return 0; +} + +static void kvaser_usb_write_bulk_callback(struct urb *urb) +{ + struct kvaser_usb_tx_urb_context *context = urb->context; + struct kvaser_usb_net_priv *priv; + struct net_device *netdev; + + if (WARN_ON(!context)) + return; + + priv = context->priv; + netdev = priv->netdev; + + kfree(urb->transfer_buffer); + + if (!netif_device_present(netdev)) + return; + + if (urb->status) + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status); +} + +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + struct kvaser_usb *dev = priv->dev; + struct net_device_stats *stats = &netdev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + struct kvaser_usb_tx_urb_context *context = NULL; + struct urb *urb; + void *buf; + struct kvaser_msg *msg; + int i, err; + int ret = NETDEV_TX_OK; + + if (can_dropped_invalid_skb(netdev, skb)) + return NETDEV_TX_OK; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + netdev_err(netdev, "No memory left for URBs\n"); + stats->tx_dropped++; + goto nourbmem; + } + + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); + if (!buf) { + stats->tx_dropped++; + goto nobufmem; + } + + msg = buf; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can); + msg->u.tx_can.flags = 0; + msg->u.tx_can.channel = priv->channel; + + if (cf->can_id & CAN_EFF_FLAG) { + msg->id = CMD_TX_EXT_MESSAGE; + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f; + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f; + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f; + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff; + msg->u.tx_can.msg[4] = cf->can_id & 0x3f; + } else { + msg->id = CMD_TX_STD_MESSAGE; + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f; + msg->u.tx_can.msg[1] = cf->can_id & 0x3f; + } + + msg->u.tx_can.msg[5] = cf->can_dlc; + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc); + + if (cf->can_id & CAN_RTR_FLAG) + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME; + + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { + context = &priv->tx_contexts[i]; + break; + } + } + + if (!context) { + netdev_warn(netdev, "cannot find free context\n"); + ret = NETDEV_TX_BUSY; + goto releasebuf; + } + + context->priv = priv; + context->echo_index = i; + context->dlc = cf->can_dlc; + + msg->u.tx_can.tid = context->echo_index; + + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out->bEndpointAddress), + buf, msg->len, + kvaser_usb_write_bulk_callback, context); + usb_anchor_urb(urb, &priv->tx_submitted); + + can_put_echo_skb(skb, netdev, context->echo_index); + + atomic_inc(&priv->active_tx_urbs); + + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) + netif_stop_queue(netdev); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) { + can_free_echo_skb(netdev, context->echo_index); + + skb = NULL; /* set to NULL to avoid double free in + * dev_kfree_skb(skb) */ + + atomic_dec(&priv->active_tx_urbs); + usb_unanchor_urb(urb); + + stats->tx_dropped++; + + if (err == -ENODEV) + netif_device_detach(netdev); + else + netdev_warn(netdev, "Failed tx_urb %d\n", err); + + goto releasebuf; + } + + usb_free_urb(urb); + + return NETDEV_TX_OK; + +releasebuf: + kfree(buf); +nobufmem: + usb_free_urb(urb); +nourbmem: + dev_kfree_skb(skb); + return ret; +} + +static const struct net_device_ops kvaser_usb_netdev_ops = { + .ndo_open = kvaser_usb_open, + .ndo_stop = kvaser_usb_close, + .ndo_start_xmit = kvaser_usb_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static const struct can_bittiming_const kvaser_usb_bittiming_const = { + .name = "kvaser_usb", + .tseg1_min = KVASER_USB_TSEG1_MIN, + .tseg1_max = KVASER_USB_TSEG1_MAX, + .tseg2_min = KVASER_USB_TSEG2_MIN, + .tseg2_max = KVASER_USB_TSEG2_MAX, + .sjw_max = KVASER_USB_SJW_MAX, + .brp_min = KVASER_USB_BRP_MIN, + .brp_max = KVASER_USB_BRP_MAX, + .brp_inc = KVASER_USB_BRP_INC, +}; + +static int kvaser_usb_set_bittiming(struct net_device *netdev) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + struct can_bittiming *bt = &priv->can.bittiming; + struct kvaser_usb *dev = priv->dev; + struct kvaser_msg *msg; + int rc; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->id = CMD_SET_BUS_PARAMS; + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_busparams); + msg->u.busparams.channel = priv->channel; + msg->u.busparams.tid = 0xff; + msg->u.busparams.bitrate = cpu_to_le32(bt->bitrate); + msg->u.busparams.sjw = bt->sjw; + msg->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1; + msg->u.busparams.tseg2 = bt->phase_seg2; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + msg->u.busparams.no_samp = 3; + else + msg->u.busparams.no_samp = 1; + + rc = kvaser_usb_send_msg(dev, msg); + + kfree(msg); + return rc; +} + +static int kvaser_usb_set_mode(struct net_device *netdev, + enum can_mode mode) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + int err; + + switch (mode) { + case CAN_MODE_START: + err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP); + if (err) + return err; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int kvaser_usb_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + + *bec = priv->bec; + + return 0; +} + +static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) +{ + int i; + + for (i = 0; i < dev->nchannels; i++) { + if (!dev->nets[i]) + continue; + + unregister_netdev(dev->nets[i]->netdev); + } + + kvaser_usb_unlink_all_urbs(dev); + + for (i = 0; i < dev->nchannels; i++) { + if (!dev->nets[i]) + continue; + + free_candev(dev->nets[i]->netdev); + } +} + +static int kvaser_usb_init_one(struct usb_interface *intf, + const struct usb_device_id *id, int channel) +{ + struct kvaser_usb *dev = usb_get_intfdata(intf); + struct net_device *netdev; + struct kvaser_usb_net_priv *priv; + int i, err; + + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); + if (!netdev) { + dev_err(&intf->dev, "Cannot alloc candev\n"); + return -ENOMEM; + } + + priv = netdev_priv(netdev); + + init_completion(&priv->start_comp); + init_completion(&priv->stop_comp); + + init_usb_anchor(&priv->tx_submitted); + atomic_set(&priv->active_tx_urbs, 0); + + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) + priv->tx_contexts[i].echo_index = MAX_TX_URBS; + + priv->dev = dev; + priv->netdev = netdev; + priv->channel = channel; + + priv->can.state = CAN_STATE_STOPPED; + priv->can.clock.freq = CAN_USB_CLOCK; + priv->can.bittiming_const = &kvaser_usb_bittiming_const; + priv->can.do_set_bittiming = kvaser_usb_set_bittiming; + priv->can.do_set_mode = kvaser_usb_set_mode; + if (id->driver_info & KVASER_HAS_TXRX_ERRORS) + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + if (id->driver_info & KVASER_HAS_SILENT_MODE) + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY; + + netdev->flags |= IFF_ECHO; + + netdev->netdev_ops = &kvaser_usb_netdev_ops; + + SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = channel; + + dev->nets[channel] = priv; + + err = register_candev(netdev); + if (err) { + dev_err(&intf->dev, "Failed to register can device\n"); + free_candev(netdev); + dev->nets[channel] = NULL; + return err; + } + + netdev_dbg(netdev, "device registered\n"); + + return 0; +} + +static int kvaser_usb_get_endpoints(const struct usb_interface *intf, + struct usb_endpoint_descriptor **in, + struct usb_endpoint_descriptor **out) +{ + const struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i; + + iface_desc = &intf->altsetting[0]; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!*in && usb_endpoint_is_bulk_in(endpoint)) + *in = endpoint; + + if (!*out && usb_endpoint_is_bulk_out(endpoint)) + *out = endpoint; + + /* use first bulk endpoint for in and out */ + if (*in && *out) + return 0; + } + + return -ENODEV; +} + +static int kvaser_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct kvaser_usb *dev; + int err = -ENOMEM; + int i; + + dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out); + if (err) { + dev_err(&intf->dev, "Cannot get usb endpoint(s)"); + return err; + } + + dev->udev = interface_to_usbdev(intf); + + init_usb_anchor(&dev->rx_submitted); + + usb_set_intfdata(intf, dev); + + for (i = 0; i < MAX_NET_DEVICES; i++) + kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i); + + err = kvaser_usb_get_software_info(dev); + if (err) { + dev_err(&intf->dev, + "Cannot get software infos, error %d\n", err); + return err; + } + + err = kvaser_usb_get_card_info(dev); + if (err) { + dev_err(&intf->dev, + "Cannot get card infos, error %d\n", err); + return err; + } + + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", + ((dev->fw_version >> 24) & 0xff), + ((dev->fw_version >> 16) & 0xff), + (dev->fw_version & 0xffff)); + + for (i = 0; i < dev->nchannels; i++) { + err = kvaser_usb_init_one(intf, id, i); + if (err) { + kvaser_usb_remove_interfaces(dev); + return err; + } + } + + return 0; +} + +static void kvaser_usb_disconnect(struct usb_interface *intf) +{ + struct kvaser_usb *dev = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (!dev) + return; + + kvaser_usb_remove_interfaces(dev); +} + +static struct usb_driver kvaser_usb_driver = { + .name = "kvaser_usb", + .probe = kvaser_usb_probe, + .disconnect = kvaser_usb_disconnect, + .id_table = kvaser_usb_table, +}; + +module_usb_driver(kvaser_usb_driver); + +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); +MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 86f26a1ede4..925ab8ec932 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, mc->pdev->dev.can.state = new_state; if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts->hwtstamp = timeval_to_ktime(tv); } netif_rx(skb); @@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) struct sk_buff *skb; struct can_frame *cf; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(mc->netdev, &cf); if (!skb) @@ -646,13 +649,14 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) if ((mc->ptr + rec_len) > mc->end) goto decode_failed; - memcpy(cf->data, mc->ptr, rec_len); + memcpy(cf->data, mc->ptr, cf->can_dlc); mc->ptr += rec_len; } /* convert timestamp into kernel time */ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); /* push the skb */ netif_rx(skb); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index c4643c400d4..644e6ab8a48 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -386,7 +386,6 @@ static int peak_usb_start(struct peak_usb_device *dev) buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL); if (!buf) { - netdev_err(netdev, "No memory left for USB buffer\n"); usb_free_urb(urb); err = -ENOMEM; break; @@ -442,7 +441,6 @@ static int peak_usb_start(struct peak_usb_device *dev) buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL); if (!buf) { - netdev_err(netdev, "No memory left for USB buffer\n"); usb_free_urb(urb); err = -ENOMEM; break; @@ -465,7 +463,7 @@ static int peak_usb_start(struct peak_usb_device *dev) if (i < PCAN_USB_MAX_TX_URBS) { if (i == 0) { netdev_err(netdev, "couldn't setup any tx URB\n"); - return err; + goto err_tx; } netdev_warn(netdev, "tx performance may be slow\n"); @@ -474,7 +472,7 @@ static int peak_usb_start(struct peak_usb_device *dev) if (dev->adapter->dev_start) { err = dev->adapter->dev_start(dev); if (err) - goto failed; + goto err_adapter; } dev->state |= PCAN_USB_STATE_STARTED; @@ -483,19 +481,26 @@ static int peak_usb_start(struct peak_usb_device *dev) if (dev->adapter->dev_set_bus) { err = dev->adapter->dev_set_bus(dev, 1); if (err) - goto failed; + goto err_adapter; } dev->can.state = CAN_STATE_ERROR_ACTIVE; return 0; -failed: +err_adapter: if (err == -ENODEV) netif_device_detach(dev->netdev); netdev_warn(netdev, "couldn't submit control: %d\n", err); + for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { + usb_free_urb(dev->tx_contexts[i].urb); + dev->tx_contexts[i].urb = NULL; + } +err_tx: + usb_kill_anchored_urbs(&dev->rx_submitted); + return err; } @@ -520,7 +525,6 @@ static int peak_usb_ndo_open(struct net_device *netdev) return err; } - dev->open_time = jiffies; netif_start_queue(netdev); return 0; @@ -576,7 +580,6 @@ static int peak_usb_ndo_stop(struct net_device *netdev) close_candev(netdev); - dev->open_time = 0; dev->can.state = CAN_STATE_STOPPED; /* can set bus off now */ @@ -636,7 +639,6 @@ static int peak_usb_restart(struct peak_usb_device *dev) /* also allocate enough space for the commands to send */ buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC); if (!buf) { - netdev_err(dev->netdev, "no memory left for async cmd\n"); usb_free_urb(urb); return -ENOMEM; } @@ -661,9 +663,6 @@ static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode) struct peak_usb_device *dev = netdev_priv(netdev); int err = 0; - if (!dev->open_time) - return -EINVAL; - switch (mode) { case CAN_MODE_START: err = peak_usb_restart(dev); @@ -703,6 +702,7 @@ static const struct net_device_ops peak_usb_netdev_ops = { .ndo_open = peak_usb_ndo_open, .ndo_stop = peak_usb_ndo_stop, .ndo_start_xmit = peak_usb_ndo_start_xmit, + .ndo_change_mtu = can_change_mtu, }; /* @@ -734,8 +734,6 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, /* allocate a buffer large enough to send commands */ dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); if (!dev->cmd_buf) { - dev_err(&intf->dev, "%s: couldn't alloc cmd buffer\n", - PCAN_USB_DRIVER_NAME); err = -ENOMEM; goto lbl_set_intf_data; } @@ -772,6 +770,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, usb_set_intfdata(intf, dev); SET_NETDEV_DEV(netdev, &intf->dev); + netdev->dev_id = ctrl_idx; err = register_candev(netdev); if (err) { diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index c8e5e91d7cb..073b47ff8ee 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -104,7 +104,6 @@ struct peak_usb_device { struct can_priv can; struct peak_usb_adapter *adapter; unsigned int ctrl_idx; - int open_time; u32 state; struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS]; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index e1626d92511..263dd921edc 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -504,15 +504,24 @@ static int pcan_usb_pro_restart_async(struct peak_usb_device *dev, return usb_submit_urb(urb, GFP_ATOMIC); } -static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) +static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) { - u8 buffer[16]; + u8 *buffer; + int err; + + buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; buffer[0] = 0; buffer[1] = !!loaded; - pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT, - PCAN_USBPRO_FCT_DRVLD, buffer, sizeof(buffer)); + err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT, + PCAN_USBPRO_FCT_DRVLD, buffer, + PCAN_USBPRO_FCT_DRVLD_REQ_LEN); + kfree(buffer); + + return err; } static inline @@ -532,6 +541,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, struct can_frame *can_frame; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(netdev, &can_frame); if (!skb) @@ -549,7 +559,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, memcpy(can_frame->data, rx->data, can_frame->can_dlc); peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; @@ -570,6 +581,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, u8 err_mask = 0; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; /* nothing should be sent while in BUS_OFF state */ if (dev->can.state == CAN_STATE_BUS_OFF) @@ -664,7 +676,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, dev->can.state = new_state; peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); - skb->tstamp = timeval_to_ktime(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; @@ -847,21 +860,24 @@ static int pcan_usb_pro_stop(struct peak_usb_device *dev) */ static int pcan_usb_pro_init(struct peak_usb_device *dev) { - struct pcan_usb_pro_interface *usb_if; struct pcan_usb_pro_device *pdev = container_of(dev, struct pcan_usb_pro_device, dev); + struct pcan_usb_pro_interface *usb_if = NULL; + struct pcan_usb_pro_fwinfo *fi = NULL; + struct pcan_usb_pro_blinfo *bi = NULL; + int err; /* do this for 1st channel only */ if (!dev->prev_siblings) { - struct pcan_usb_pro_fwinfo fi; - struct pcan_usb_pro_blinfo bi; - int err; - /* allocate netdevices common structure attached to first one */ usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface), GFP_KERNEL); - if (!usb_if) - return -ENOMEM; + fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL); + bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL); + if (!usb_if || !fi || !bi) { + err = -ENOMEM; + goto err_out; + } /* number of ts msgs to ignore before taking one into account */ usb_if->cm_ignore_count = 5; @@ -873,34 +889,34 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) */ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, PCAN_USBPRO_INFO_FW, - &fi, sizeof(fi)); + fi, sizeof(*fi)); if (err) { - kfree(usb_if); dev_err(dev->netdev->dev.parent, "unable to read %s firmware info (err %d)\n", pcan_usb_pro.name, err); - return err; + goto err_out; } err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, PCAN_USBPRO_INFO_BL, - &bi, sizeof(bi)); + bi, sizeof(*bi)); if (err) { - kfree(usb_if); dev_err(dev->netdev->dev.parent, "unable to read %s bootloader info (err %d)\n", pcan_usb_pro.name, err); - return err; + goto err_out; } + /* tell the device the can driver is running */ + err = pcan_usb_pro_drv_loaded(dev, 1); + if (err) + goto err_out; + dev_info(dev->netdev->dev.parent, "PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n", pcan_usb_pro.name, - bi.hw_rev, bi.serial_num_hi, bi.serial_num_lo, + bi->hw_rev, bi->serial_num_hi, bi->serial_num_lo, pcan_usb_pro.ctrl_count); - - /* tell the device the can driver is running */ - pcan_usb_pro_drv_loaded(dev, 1); } else { usb_if = pcan_usb_pro_dev_if(dev->prev_siblings); } @@ -911,7 +927,17 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) /* set LED in default state (end of init phase) */ pcan_usb_pro_set_led(dev, 0, 1); + kfree(bi); + kfree(fi); + return 0; + + err_out: + kfree(bi); + kfree(fi); + kfree(usb_if); + + return err; } static void pcan_usb_pro_exit(struct peak_usb_device *dev) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index a869918c562..32275af547e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -29,6 +29,7 @@ /* Vendor Request value for XXX_FCT */ #define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */ +#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16 /* PCAN_USBPRO_INFO_BL vendor request record type */ struct __packed pcan_usb_pro_blinfo { diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c new file mode 100644 index 00000000000..ef674ecb82f --- /dev/null +++ b/drivers/net/can/usb/usb_8dev.c @@ -0,0 +1,1035 @@ +/* + * CAN driver for "8 devices" USB2CAN converter + * + * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. + * + * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c + * and drivers/net/can/usb/esd_usb2.c + * + * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de) + * for testing and fixing this driver. Also many thanks to "8 devices", + * who were very cooperative and answered my questions. + */ + +#include <linux/signal.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/can/led.h> + +/* driver constants */ +#define MAX_RX_URBS 20 +#define MAX_TX_URBS 20 +#define RX_BUFFER_SIZE 64 + +/* vendor and product id */ +#define USB_8DEV_VENDOR_ID 0x0483 +#define USB_8DEV_PRODUCT_ID 0x1234 + +/* endpoints */ +enum usb_8dev_endpoint { + USB_8DEV_ENDP_DATA_RX = 1, + USB_8DEV_ENDP_DATA_TX, + USB_8DEV_ENDP_CMD_RX, + USB_8DEV_ENDP_CMD_TX +}; + +/* device CAN clock */ +#define USB_8DEV_ABP_CLOCK 32000000 + +/* setup flags */ +#define USB_8DEV_SILENT 0x01 +#define USB_8DEV_LOOPBACK 0x02 +#define USB_8DEV_DISABLE_AUTO_RESTRANS 0x04 +#define USB_8DEV_STATUS_FRAME 0x08 + +/* commands */ +enum usb_8dev_cmd { + USB_8DEV_RESET = 1, + USB_8DEV_OPEN, + USB_8DEV_CLOSE, + USB_8DEV_SET_SPEED, + USB_8DEV_SET_MASK_FILTER, + USB_8DEV_GET_STATUS, + USB_8DEV_GET_STATISTICS, + USB_8DEV_GET_SERIAL, + USB_8DEV_GET_SOFTW_VER, + USB_8DEV_GET_HARDW_VER, + USB_8DEV_RESET_TIMESTAMP, + USB_8DEV_GET_SOFTW_HARDW_VER +}; + +/* command options */ +#define USB_8DEV_BAUD_MANUAL 0x09 +#define USB_8DEV_CMD_START 0x11 +#define USB_8DEV_CMD_END 0x22 + +#define USB_8DEV_CMD_SUCCESS 0 +#define USB_8DEV_CMD_ERROR 255 + +#define USB_8DEV_CMD_TIMEOUT 1000 + +/* frames */ +#define USB_8DEV_DATA_START 0x55 +#define USB_8DEV_DATA_END 0xAA + +#define USB_8DEV_TYPE_CAN_FRAME 0 +#define USB_8DEV_TYPE_ERROR_FRAME 3 + +#define USB_8DEV_EXTID 0x01 +#define USB_8DEV_RTR 0x02 +#define USB_8DEV_ERR_FLAG 0x04 + +/* status */ +#define USB_8DEV_STATUSMSG_OK 0x00 /* Normal condition. */ +#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occured when sending */ +#define USB_8DEV_STATUSMSG_BUSLIGHT 0x02 /* Error counter has reached 96 */ +#define USB_8DEV_STATUSMSG_BUSHEAVY 0x03 /* Error count. has reached 128 */ +#define USB_8DEV_STATUSMSG_BUSOFF 0x04 /* Device is in BUSOFF */ +#define USB_8DEV_STATUSMSG_STUFF 0x20 /* Stuff Error */ +#define USB_8DEV_STATUSMSG_FORM 0x21 /* Form Error */ +#define USB_8DEV_STATUSMSG_ACK 0x23 /* Ack Error */ +#define USB_8DEV_STATUSMSG_BIT0 0x24 /* Bit1 Error */ +#define USB_8DEV_STATUSMSG_BIT1 0x25 /* Bit0 Error */ +#define USB_8DEV_STATUSMSG_CRC 0x27 /* CRC Error */ + +#define USB_8DEV_RP_MASK 0x7F /* Mask for Receive Error Bit */ + + +/* table of devices that work with this driver */ +static const struct usb_device_id usb_8dev_table[] = { + { USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, usb_8dev_table); + +struct usb_8dev_tx_urb_context { + struct usb_8dev_priv *priv; + + u32 echo_index; + u8 dlc; +}; + +/* Structure to hold all of our device specific stuff */ +struct usb_8dev_priv { + struct can_priv can; /* must be the first member */ + + struct sk_buff *echo_skb[MAX_TX_URBS]; + + struct usb_device *udev; + struct net_device *netdev; + + atomic_t active_tx_urbs; + struct usb_anchor tx_submitted; + struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS]; + + struct usb_anchor rx_submitted; + + struct can_berr_counter bec; + + u8 *cmd_msg_buffer; + + struct mutex usb_8dev_cmd_lock; + +}; + +/* tx frame */ +struct __packed usb_8dev_tx_msg { + u8 begin; + u8 flags; /* RTR and EXT_ID flag */ + __be32 id; /* upper 3 bits not used */ + u8 dlc; /* data length code 0-8 bytes */ + u8 data[8]; /* 64-bit data */ + u8 end; +}; + +/* rx frame */ +struct __packed usb_8dev_rx_msg { + u8 begin; + u8 type; /* frame type */ + u8 flags; /* RTR and EXT_ID flag */ + __be32 id; /* upper 3 bits not used */ + u8 dlc; /* data length code 0-8 bytes */ + u8 data[8]; /* 64-bit data */ + __be32 timestamp; /* 32-bit timestamp */ + u8 end; +}; + +/* command frame */ +struct __packed usb_8dev_cmd_msg { + u8 begin; + u8 channel; /* unkown - always 0 */ + u8 command; /* command to execute */ + u8 opt1; /* optional parameter / return value */ + u8 opt2; /* optional parameter 2 */ + u8 data[10]; /* optional parameter and data */ + u8 end; +}; + +static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size) +{ + int actual_length; + + return usb_bulk_msg(priv->udev, + usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX), + msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT); +} + +static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size, + int *actual_length) +{ + return usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX), + msg, size, actual_length, USB_8DEV_CMD_TIMEOUT); +} + +/* Send command to device and receive result. + * Command was successful when opt1 = 0. + */ +static int usb_8dev_send_cmd(struct usb_8dev_priv *priv, + struct usb_8dev_cmd_msg *out, + struct usb_8dev_cmd_msg *in) +{ + int err; + int num_bytes_read; + struct net_device *netdev; + + netdev = priv->netdev; + + out->begin = USB_8DEV_CMD_START; + out->end = USB_8DEV_CMD_END; + + mutex_lock(&priv->usb_8dev_cmd_lock); + + memcpy(priv->cmd_msg_buffer, out, + sizeof(struct usb_8dev_cmd_msg)); + + err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer, + sizeof(struct usb_8dev_cmd_msg)); + if (err < 0) { + netdev_err(netdev, "sending command message failed\n"); + goto failed; + } + + err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer, + sizeof(struct usb_8dev_cmd_msg), + &num_bytes_read); + if (err < 0) { + netdev_err(netdev, "no command message answer\n"); + goto failed; + } + + memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg)); + + if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END || + num_bytes_read != 16 || in->opt1 != 0) + err = -EPROTO; + +failed: + mutex_unlock(&priv->usb_8dev_cmd_lock); + return err; +} + +/* Send open command to device */ +static int usb_8dev_cmd_open(struct usb_8dev_priv *priv) +{ + struct can_bittiming *bt = &priv->can.bittiming; + struct usb_8dev_cmd_msg outmsg; + struct usb_8dev_cmd_msg inmsg; + u32 ctrlmode = priv->can.ctrlmode; + u32 flags = USB_8DEV_STATUS_FRAME; + __be32 beflags; + __be16 bebrp; + + memset(&outmsg, 0, sizeof(outmsg)); + outmsg.command = USB_8DEV_OPEN; + outmsg.opt1 = USB_8DEV_BAUD_MANUAL; + outmsg.data[0] = bt->prop_seg + bt->phase_seg1; + outmsg.data[1] = bt->phase_seg2; + outmsg.data[2] = bt->sjw; + + /* BRP */ + bebrp = cpu_to_be16((u16)bt->brp); + memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp)); + + /* flags */ + if (ctrlmode & CAN_CTRLMODE_LOOPBACK) + flags |= USB_8DEV_LOOPBACK; + if (ctrlmode & CAN_CTRLMODE_LISTENONLY) + flags |= USB_8DEV_SILENT; + if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) + flags |= USB_8DEV_DISABLE_AUTO_RESTRANS; + + beflags = cpu_to_be32(flags); + memcpy(&outmsg.data[5], &beflags, sizeof(beflags)); + + return usb_8dev_send_cmd(priv, &outmsg, &inmsg); +} + +/* Send close command to device */ +static int usb_8dev_cmd_close(struct usb_8dev_priv *priv) +{ + struct usb_8dev_cmd_msg inmsg; + struct usb_8dev_cmd_msg outmsg = { + .channel = 0, + .command = USB_8DEV_CLOSE, + .opt1 = 0, + .opt2 = 0 + }; + + return usb_8dev_send_cmd(priv, &outmsg, &inmsg); +} + +/* Get firmware and hardware version */ +static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res) +{ + struct usb_8dev_cmd_msg inmsg; + struct usb_8dev_cmd_msg outmsg = { + .channel = 0, + .command = USB_8DEV_GET_SOFTW_HARDW_VER, + .opt1 = 0, + .opt2 = 0 + }; + + int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg); + if (err) + return err; + + *res = be32_to_cpup((__be32 *)inmsg.data); + + return err; +} + +/* Set network device mode + * + * Maybe we should leave this function empty, because the device + * set mode variable with open command. + */ +static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode) +{ + struct usb_8dev_priv *priv = netdev_priv(netdev); + int err = 0; + + switch (mode) { + case CAN_MODE_START: + err = usb_8dev_cmd_open(priv); + if (err) + netdev_warn(netdev, "couldn't start device"); + break; + + default: + return -EOPNOTSUPP; + } + + return err; +} + +/* Read error/status frames */ +static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, + struct usb_8dev_rx_msg *msg) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct net_device_stats *stats = &priv->netdev->stats; + + /* Error message: + * byte 0: Status + * byte 1: bit 7: Receive Passive + * byte 1: bit 0-6: Receive Error Counter + * byte 2: Transmit Error Counter + * byte 3: Always 0 (maybe reserved for future use) + */ + + u8 state = msg->data[0]; + u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK; + u8 txerr = msg->data[2]; + int rx_errors = 0; + int tx_errors = 0; + + skb = alloc_can_err_skb(priv->netdev, &cf); + if (!skb) + return; + + switch (state) { + case USB_8DEV_STATUSMSG_OK: + priv->can.state = CAN_STATE_ERROR_ACTIVE; + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_ACTIVE; + break; + case USB_8DEV_STATUSMSG_BUSOFF: + priv->can.state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + can_bus_off(priv->netdev); + break; + case USB_8DEV_STATUSMSG_OVERRUN: + case USB_8DEV_STATUSMSG_BUSLIGHT: + case USB_8DEV_STATUSMSG_BUSHEAVY: + cf->can_id |= CAN_ERR_CRTL; + break; + default: + priv->can.state = CAN_STATE_ERROR_WARNING; + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + priv->can.can_stats.bus_error++; + break; + } + + switch (state) { + case USB_8DEV_STATUSMSG_OK: + case USB_8DEV_STATUSMSG_BUSOFF: + break; + case USB_8DEV_STATUSMSG_ACK: + cf->can_id |= CAN_ERR_ACK; + 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; + rx_errors = 1; + break; + case USB_8DEV_STATUSMSG_BIT0: + cf->data[2] |= CAN_ERR_PROT_BIT0; + tx_errors = 1; + break; + case USB_8DEV_STATUSMSG_BIT1: + cf->data[2] |= CAN_ERR_PROT_BIT1; + tx_errors = 1; + break; + case USB_8DEV_STATUSMSG_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + rx_errors = 1; + break; + case USB_8DEV_STATUSMSG_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + rx_errors = 1; + break; + case USB_8DEV_STATUSMSG_OVERRUN: + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_over_errors++; + rx_errors = 1; + break; + case USB_8DEV_STATUSMSG_BUSLIGHT: + priv->can.state = CAN_STATE_ERROR_WARNING; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + priv->can.can_stats.error_warning++; + break; + case USB_8DEV_STATUSMSG_BUSHEAVY: + priv->can.state = CAN_STATE_ERROR_PASSIVE; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_PASSIVE : + CAN_ERR_CRTL_RX_PASSIVE; + priv->can.can_stats.error_passive++; + break; + default: + netdev_warn(priv->netdev, + "Unknown status/error message (%d)\n", state); + break; + } + + if (tx_errors) { + cf->data[2] |= CAN_ERR_PROT_TX; + stats->tx_errors++; + } + + if (rx_errors) + stats->rx_errors++; + + cf->data[6] = txerr; + cf->data[7] = rxerr; + + priv->bec.txerr = txerr; + priv->bec.rxerr = rxerr; + + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +} + +/* Read data and status frames */ +static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv, + struct usb_8dev_rx_msg *msg) +{ + struct can_frame *cf; + struct sk_buff *skb; + struct net_device_stats *stats = &priv->netdev->stats; + + if (msg->type == USB_8DEV_TYPE_ERROR_FRAME && + msg->flags == USB_8DEV_ERR_FLAG) { + usb_8dev_rx_err_msg(priv, msg); + } else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) { + skb = alloc_can_skb(priv->netdev, &cf); + if (!skb) + return; + + cf->can_id = be32_to_cpu(msg->id); + cf->can_dlc = get_can_dlc(msg->dlc & 0xF); + + if (msg->flags & USB_8DEV_EXTID) + cf->can_id |= CAN_EFF_FLAG; + + if (msg->flags & USB_8DEV_RTR) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, msg->data, cf->can_dlc); + + netif_rx(skb); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + can_led_event(priv->netdev, CAN_LED_EVENT_RX); + } else { + netdev_warn(priv->netdev, "frame type %d unknown", + msg->type); + } + +} + +/* Callback for reading data from device + * + * Check urb status, call read function and resubmit urb read operation. + */ +static void usb_8dev_read_bulk_callback(struct urb *urb) +{ + struct usb_8dev_priv *priv = urb->context; + struct net_device *netdev; + int retval; + int pos = 0; + + netdev = priv->netdev; + + if (!netif_device_present(netdev)) + return; + + switch (urb->status) { + case 0: /* success */ + break; + + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + netdev_info(netdev, "Rx URB aborted (%d)\n", + urb->status); + goto resubmit_urb; + } + + while (pos < urb->actual_length) { + struct usb_8dev_rx_msg *msg; + + if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) { + netdev_err(priv->netdev, "format error\n"); + break; + } + + msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos); + usb_8dev_rx_can_msg(priv, msg); + + pos += sizeof(struct usb_8dev_rx_msg); + } + +resubmit_urb: + usb_fill_bulk_urb(urb, priv->udev, + usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX), + urb->transfer_buffer, RX_BUFFER_SIZE, + usb_8dev_read_bulk_callback, priv); + + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval == -ENODEV) + netif_device_detach(netdev); + else if (retval) + netdev_err(netdev, + "failed resubmitting read bulk urb: %d\n", retval); +} + +/* Callback handler for write operations + * + * Free allocated buffers, check transmit status and + * calculate statistic. + */ +static void usb_8dev_write_bulk_callback(struct urb *urb) +{ + struct usb_8dev_tx_urb_context *context = urb->context; + struct usb_8dev_priv *priv; + struct net_device *netdev; + + BUG_ON(!context); + + priv = context->priv; + netdev = priv->netdev; + + /* free up our allocated buffer */ + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + + atomic_dec(&priv->active_tx_urbs); + + if (!netif_device_present(netdev)) + return; + + if (urb->status) + netdev_info(netdev, "Tx URB aborted (%d)\n", + urb->status); + + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += context->dlc; + + can_get_echo_skb(netdev, context->echo_index); + + can_led_event(netdev, CAN_LED_EVENT_TX); + + /* Release context */ + context->echo_index = MAX_TX_URBS; + + netif_wake_queue(netdev); +} + +/* Send data to device */ +static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct usb_8dev_priv *priv = netdev_priv(netdev); + struct net_device_stats *stats = &netdev->stats; + struct can_frame *cf = (struct can_frame *) skb->data; + struct usb_8dev_tx_msg *msg; + struct urb *urb; + struct usb_8dev_tx_urb_context *context = NULL; + u8 *buf; + int i, err; + size_t size = sizeof(struct usb_8dev_tx_msg); + + if (can_dropped_invalid_skb(netdev, skb)) + return NETDEV_TX_OK; + + /* create a URB, and a buffer for it, and copy the data to the URB */ + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + netdev_err(netdev, "No memory left for URBs\n"); + goto nomem; + } + + buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC, + &urb->transfer_dma); + if (!buf) { + netdev_err(netdev, "No memory left for USB buffer\n"); + goto nomembuf; + } + + memset(buf, 0, size); + + msg = (struct usb_8dev_tx_msg *)buf; + msg->begin = USB_8DEV_DATA_START; + msg->flags = 0x00; + + if (cf->can_id & CAN_RTR_FLAG) + msg->flags |= USB_8DEV_RTR; + + if (cf->can_id & CAN_EFF_FLAG) + msg->flags |= USB_8DEV_EXTID; + + msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK); + msg->dlc = cf->can_dlc; + memcpy(msg->data, cf->data, cf->can_dlc); + msg->end = USB_8DEV_DATA_END; + + for (i = 0; i < MAX_TX_URBS; i++) { + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { + context = &priv->tx_contexts[i]; + break; + } + } + + /* May never happen! When this happens we'd more URBs in flight as + * allowed (MAX_TX_URBS). + */ + if (!context) + goto nofreecontext; + + context->priv = priv; + context->echo_index = i; + context->dlc = cf->can_dlc; + + usb_fill_bulk_urb(urb, priv->udev, + usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX), + buf, size, usb_8dev_write_bulk_callback, context); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &priv->tx_submitted); + + can_put_echo_skb(skb, netdev, context->echo_index); + + atomic_inc(&priv->active_tx_urbs); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) + goto failed; + else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) + /* Slow down tx path */ + netif_stop_queue(netdev); + + /* Release our reference to this URB, the USB core will eventually free + * it entirely. + */ + usb_free_urb(urb); + + return NETDEV_TX_OK; + +nofreecontext: + usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + usb_free_urb(urb); + + netdev_warn(netdev, "couldn't find free context"); + + return NETDEV_TX_BUSY; + +failed: + can_free_echo_skb(netdev, context->echo_index); + + usb_unanchor_urb(urb); + usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + + atomic_dec(&priv->active_tx_urbs); + + if (err == -ENODEV) + netif_device_detach(netdev); + else + netdev_warn(netdev, "failed tx_urb %d\n", err); + +nomembuf: + usb_free_urb(urb); + +nomem: + dev_kfree_skb(skb); + stats->tx_dropped++; + + return NETDEV_TX_OK; +} + +static int usb_8dev_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct usb_8dev_priv *priv = netdev_priv(netdev); + + bec->txerr = priv->bec.txerr; + bec->rxerr = priv->bec.rxerr; + + return 0; +} + +/* Start USB device */ +static int usb_8dev_start(struct usb_8dev_priv *priv) +{ + struct net_device *netdev = priv->netdev; + int err, i; + + for (i = 0; i < MAX_RX_URBS; i++) { + struct urb *urb = NULL; + u8 *buf; + + /* create a URB, and a buffer for it */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + netdev_err(netdev, "No memory left for URBs\n"); + err = -ENOMEM; + break; + } + + buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL, + &urb->transfer_dma); + if (!buf) { + netdev_err(netdev, "No memory left for USB buffer\n"); + usb_free_urb(urb); + err = -ENOMEM; + break; + } + + usb_fill_bulk_urb(urb, priv->udev, + usb_rcvbulkpipe(priv->udev, + USB_8DEV_ENDP_DATA_RX), + buf, RX_BUFFER_SIZE, + usb_8dev_read_bulk_callback, priv); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &priv->rx_submitted); + + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + usb_unanchor_urb(urb); + usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf, + urb->transfer_dma); + usb_free_urb(urb); + break; + } + + /* Drop reference, USB core will take care of freeing it */ + usb_free_urb(urb); + } + + /* Did we submit any URBs */ + if (i == 0) { + netdev_warn(netdev, "couldn't setup read URBs\n"); + return err; + } + + /* Warn if we've couldn't transmit all the URBs */ + if (i < MAX_RX_URBS) + netdev_warn(netdev, "rx performance may be slow\n"); + + err = usb_8dev_cmd_open(priv); + if (err) + goto failed; + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + return 0; + +failed: + if (err == -ENODEV) + netif_device_detach(priv->netdev); + + netdev_warn(netdev, "couldn't submit control: %d\n", err); + + return err; +} + +/* Open USB device */ +static int usb_8dev_open(struct net_device *netdev) +{ + struct usb_8dev_priv *priv = netdev_priv(netdev); + int err; + + /* common open */ + err = open_candev(netdev); + if (err) + return err; + + can_led_event(netdev, CAN_LED_EVENT_OPEN); + + /* finally start device */ + err = usb_8dev_start(priv); + if (err) { + if (err == -ENODEV) + netif_device_detach(priv->netdev); + + netdev_warn(netdev, "couldn't start device: %d\n", + err); + + close_candev(netdev); + + return err; + } + + netif_start_queue(netdev); + + return 0; +} + +static void unlink_all_urbs(struct usb_8dev_priv *priv) +{ + int i; + + usb_kill_anchored_urbs(&priv->rx_submitted); + + usb_kill_anchored_urbs(&priv->tx_submitted); + atomic_set(&priv->active_tx_urbs, 0); + + for (i = 0; i < MAX_TX_URBS; i++) + priv->tx_contexts[i].echo_index = MAX_TX_URBS; +} + +/* Close USB device */ +static int usb_8dev_close(struct net_device *netdev) +{ + struct usb_8dev_priv *priv = netdev_priv(netdev); + int err = 0; + + /* Send CLOSE command to CAN controller */ + err = usb_8dev_cmd_close(priv); + if (err) + netdev_warn(netdev, "couldn't stop device"); + + priv->can.state = CAN_STATE_STOPPED; + + netif_stop_queue(netdev); + + /* Stop polling */ + unlink_all_urbs(priv); + + close_candev(netdev); + + can_led_event(netdev, CAN_LED_EVENT_STOP); + + return err; +} + +static const struct net_device_ops usb_8dev_netdev_ops = { + .ndo_open = usb_8dev_open, + .ndo_stop = usb_8dev_close, + .ndo_start_xmit = usb_8dev_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static const struct can_bittiming_const usb_8dev_bittiming_const = { + .name = "usb_8dev", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, +}; + +/* Probe USB device + * + * Check device and firmware. + * Set supported modes and bittiming constants. + * Allocate some memory. + */ +static int usb_8dev_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct net_device *netdev; + struct usb_8dev_priv *priv; + int i, err = -ENOMEM; + u32 version; + char buf[18]; + struct usb_device *usbdev = interface_to_usbdev(intf); + + /* product id looks strange, better we also check iProduct string */ + if (usb_string(usbdev, usbdev->descriptor.iProduct, buf, + sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) { + dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n"); + return -ENODEV; + } + + netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS); + if (!netdev) { + dev_err(&intf->dev, "Couldn't alloc candev\n"); + return -ENOMEM; + } + + priv = netdev_priv(netdev); + + priv->udev = usbdev; + priv->netdev = netdev; + + priv->can.state = CAN_STATE_STOPPED; + priv->can.clock.freq = USB_8DEV_ABP_CLOCK; + priv->can.bittiming_const = &usb_8dev_bittiming_const; + priv->can.do_set_mode = usb_8dev_set_mode; + priv->can.do_get_berr_counter = usb_8dev_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_ONE_SHOT; + + netdev->netdev_ops = &usb_8dev_netdev_ops; + + netdev->flags |= IFF_ECHO; /* we support local echo */ + + init_usb_anchor(&priv->rx_submitted); + + init_usb_anchor(&priv->tx_submitted); + atomic_set(&priv->active_tx_urbs, 0); + + for (i = 0; i < MAX_TX_URBS; i++) + priv->tx_contexts[i].echo_index = MAX_TX_URBS; + + priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg), + GFP_KERNEL); + if (!priv->cmd_msg_buffer) + goto cleanup_candev; + + usb_set_intfdata(intf, priv); + + SET_NETDEV_DEV(netdev, &intf->dev); + + mutex_init(&priv->usb_8dev_cmd_lock); + + err = register_candev(netdev); + if (err) { + netdev_err(netdev, + "couldn't register CAN device: %d\n", err); + goto cleanup_cmd_msg_buffer; + } + + err = usb_8dev_cmd_version(priv, &version); + if (err) { + netdev_err(netdev, "can't get firmware version\n"); + goto cleanup_unregister_candev; + } else { + netdev_info(netdev, + "firmware: %d.%d, hardware: %d.%d\n", + (version>>24) & 0xff, (version>>16) & 0xff, + (version>>8) & 0xff, version & 0xff); + } + + devm_can_led_init(netdev); + + return 0; + +cleanup_unregister_candev: + unregister_netdev(priv->netdev); + +cleanup_cmd_msg_buffer: + kfree(priv->cmd_msg_buffer); + +cleanup_candev: + free_candev(netdev); + + return err; + +} + +/* Called by the usb core when driver is unloaded or device is removed */ +static void usb_8dev_disconnect(struct usb_interface *intf) +{ + struct usb_8dev_priv *priv = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (priv) { + netdev_info(priv->netdev, "device disconnected\n"); + + unregister_netdev(priv->netdev); + free_candev(priv->netdev); + + unlink_all_urbs(priv); + } + +} + +static struct usb_driver usb_8dev_driver = { + .name = "usb_8dev", + .probe = usb_8dev_probe, + .disconnect = usb_8dev_disconnect, + .id_table = usb_8dev_table, +}; + +module_usb_driver(usb_8dev_driver); + +MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>"); +MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 0a2a5ee79a1..4e94057ef5c 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -46,6 +46,7 @@ #include <linux/if_ether.h> #include <linux/can.h> #include <linux/can/dev.h> +#include <linux/can/skb.h> #include <linux/slab.h> #include <net/rtnetlink.h> @@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) stats->rx_packets++; stats->rx_bytes += cfd->len; } - kfree_skb(skb); + consume_skb(skb); return NETDEV_TX_OK; } /* perform standard echo handling for CAN network interfaces */ if (loop) { - struct sock *srcsk = skb->sk; - skb = skb_share_check(skb, GFP_ATOMIC); + skb = can_create_echo_skb(skb); if (!skb) return NETDEV_TX_OK; /* receive with packet counting */ - skb->sk = srcsk; vcan_rx(skb, dev); } else { /* no looped packets => no counting */ - kfree_skb(skb); + consume_skb(skb); } return NETDEV_TX_OK; } diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c new file mode 100644 index 00000000000..5e8b5609c06 --- /dev/null +++ b/drivers/net/can/xilinx_can.c @@ -0,0 +1,1208 @@ +/* Xilinx CAN device driver + * + * Copyright (C) 2012 - 2014 Xilinx, Inc. + * Copyright (C) 2009 PetaLogix. All rights reserved. + * + * Description: + * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/can/led.h> + +#define DRIVER_NAME "xilinx_can" + +/* CAN registers set */ +enum xcan_reg { + XCAN_SRR_OFFSET = 0x00, /* Software reset */ + XCAN_MSR_OFFSET = 0x04, /* Mode select */ + XCAN_BRPR_OFFSET = 0x08, /* Baud rate prescaler */ + XCAN_BTR_OFFSET = 0x0C, /* Bit timing */ + XCAN_ECR_OFFSET = 0x10, /* Error counter */ + XCAN_ESR_OFFSET = 0x14, /* Error status */ + XCAN_SR_OFFSET = 0x18, /* Status */ + XCAN_ISR_OFFSET = 0x1C, /* Interrupt status */ + XCAN_IER_OFFSET = 0x20, /* Interrupt enable */ + XCAN_ICR_OFFSET = 0x24, /* Interrupt clear */ + XCAN_TXFIFO_ID_OFFSET = 0x30,/* TX FIFO ID */ + XCAN_TXFIFO_DLC_OFFSET = 0x34, /* TX FIFO DLC */ + XCAN_TXFIFO_DW1_OFFSET = 0x38, /* TX FIFO Data Word 1 */ + XCAN_TXFIFO_DW2_OFFSET = 0x3C, /* TX FIFO Data Word 2 */ + XCAN_RXFIFO_ID_OFFSET = 0x50, /* RX FIFO ID */ + XCAN_RXFIFO_DLC_OFFSET = 0x54, /* RX FIFO DLC */ + XCAN_RXFIFO_DW1_OFFSET = 0x58, /* RX FIFO Data Word 1 */ + XCAN_RXFIFO_DW2_OFFSET = 0x5C, /* RX FIFO Data Word 2 */ +}; + +/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */ +#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */ +#define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */ +#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */ +#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */ +#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */ +#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */ +#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */ +#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */ +#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */ +#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */ +#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */ +#define XCAN_ESR_BERR_MASK 0x00000008 /* Bit error */ +#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */ +#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */ +#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */ +#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */ +#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */ +#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */ +#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */ +#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */ +#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */ +#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */ +#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */ +#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */ +#define XCAN_IXR_BSOFF_MASK 0x00000200 /* Bus off interrupt */ +#define XCAN_IXR_ERROR_MASK 0x00000100 /* Error interrupt */ +#define XCAN_IXR_RXNEMP_MASK 0x00000080 /* RX FIFO NotEmpty intr */ +#define XCAN_IXR_RXOFLW_MASK 0x00000040 /* RX FIFO Overflow intr */ +#define XCAN_IXR_RXOK_MASK 0x00000010 /* Message received intr */ +#define XCAN_IXR_TXFLL_MASK 0x00000004 /* Tx FIFO Full intr */ +#define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */ +#define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */ +#define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */ +#define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */ +#define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */ +#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */ +#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */ +#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */ + +#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ + XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ + XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ + XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + +/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ +#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ +#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */ +#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */ +#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */ +#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */ +#define XCAN_ESR_REC_SHIFT 8 /* Rx Error Count */ + +/* CAN frame length constants */ +#define XCAN_FRAME_MAX_DATA_LEN 8 +#define XCAN_TIMEOUT (1 * HZ) + +/** + * struct xcan_priv - This definition define CAN driver instance + * @can: CAN private data structure. + * @tx_head: Tx CAN packets ready to send on the queue + * @tx_tail: Tx CAN packets successfully sended on the queue + * @tx_max: Maximum number packets the driver can send + * @napi: NAPI structure + * @read_reg: For reading data from CAN registers + * @write_reg: For writing data to CAN registers + * @dev: Network device data structure + * @reg_base: Ioremapped address to registers + * @irq_flags: For request_irq() + * @bus_clk: Pointer to struct clk + * @can_clk: Pointer to struct clk + */ +struct xcan_priv { + struct can_priv can; + unsigned int tx_head; + unsigned int tx_tail; + unsigned int tx_max; + struct napi_struct napi; + u32 (*read_reg)(const struct xcan_priv *priv, enum xcan_reg reg); + void (*write_reg)(const struct xcan_priv *priv, enum xcan_reg reg, + u32 val); + struct net_device *dev; + void __iomem *reg_base; + unsigned long irq_flags; + struct clk *bus_clk; + struct clk *can_clk; +}; + +/* CAN Bittiming constants as per Xilinx CAN specs */ +static const struct can_bittiming_const xcan_bittiming_const = { + .name = DRIVER_NAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 256, + .brp_inc = 1, +}; + +/** + * xcan_write_reg_le - Write a value to the device register little endian + * @priv: Driver private data structure + * @reg: Register offset + * @val: Value to write at the Register offset + * + * Write data to the paricular CAN register + */ +static void xcan_write_reg_le(const struct xcan_priv *priv, enum xcan_reg reg, + u32 val) +{ + iowrite32(val, priv->reg_base + reg); +} + +/** + * xcan_read_reg_le - Read a value from the device register little endian + * @priv: Driver private data structure + * @reg: Register offset + * + * Read data from the particular CAN register + * Return: value read from the CAN register + */ +static u32 xcan_read_reg_le(const struct xcan_priv *priv, enum xcan_reg reg) +{ + return ioread32(priv->reg_base + reg); +} + +/** + * xcan_write_reg_be - Write a value to the device register big endian + * @priv: Driver private data structure + * @reg: Register offset + * @val: Value to write at the Register offset + * + * Write data to the paricular CAN register + */ +static void xcan_write_reg_be(const struct xcan_priv *priv, enum xcan_reg reg, + u32 val) +{ + iowrite32be(val, priv->reg_base + reg); +} + +/** + * xcan_read_reg_be - Read a value from the device register big endian + * @priv: Driver private data structure + * @reg: Register offset + * + * Read data from the particular CAN register + * Return: value read from the CAN register + */ +static u32 xcan_read_reg_be(const struct xcan_priv *priv, enum xcan_reg reg) +{ + return ioread32be(priv->reg_base + reg); +} + +/** + * set_reset_mode - Resets the CAN device mode + * @ndev: Pointer to net_device structure + * + * This is the driver reset mode routine.The driver + * enters into configuration mode. + * + * Return: 0 on success and failure value on error + */ +static int set_reset_mode(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + unsigned long timeout; + + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + + timeout = jiffies + XCAN_TIMEOUT; + while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) { + if (time_after(jiffies, timeout)) { + netdev_warn(ndev, "timed out for config mode\n"); + return -ETIMEDOUT; + } + usleep_range(500, 10000); + } + + return 0; +} + +/** + * xcan_set_bittiming - CAN set bit timing routine + * @ndev: Pointer to net_device structure + * + * This is the driver set bittiming routine. + * Return: 0 on success and failure value on error + */ +static int xcan_set_bittiming(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct can_bittiming *bt = &priv->can.bittiming; + u32 btr0, btr1; + u32 is_config_mode; + + /* Check whether Xilinx CAN is in configuration mode. + * It cannot set bit timing if Xilinx CAN is not in configuration mode. + */ + is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) & + XCAN_SR_CONFIG_MASK; + if (!is_config_mode) { + netdev_alert(ndev, + "BUG! Cannot set bittiming - CAN is not in config mode\n"); + return -EPERM; + } + + /* Setting Baud Rate prescalar value in BRPR Register */ + btr0 = (bt->brp - 1); + + /* Setting Time Segment 1 in BTR Register */ + btr1 = (bt->prop_seg + bt->phase_seg1 - 1); + + /* Setting Time Segment 2 in BTR Register */ + btr1 |= (bt->phase_seg2 - 1) << XCAN_BTR_TS2_SHIFT; + + /* Setting Synchronous jump width in BTR Register */ + btr1 |= (bt->sjw - 1) << XCAN_BTR_SJW_SHIFT; + + priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0); + priv->write_reg(priv, XCAN_BTR_OFFSET, btr1); + + netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n", + priv->read_reg(priv, XCAN_BRPR_OFFSET), + priv->read_reg(priv, XCAN_BTR_OFFSET)); + + return 0; +} + +/** + * xcan_chip_start - This the drivers start routine + * @ndev: Pointer to net_device structure + * + * This is the drivers start routine. + * Based on the State of the CAN device it puts + * the CAN device into a proper mode. + * + * Return: 0 on success and failure value on error + */ +static int xcan_chip_start(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 err, reg_msr, reg_sr_mask; + unsigned long timeout; + + /* Check if it is in reset mode */ + err = set_reset_mode(ndev); + if (err < 0) + return err; + + err = xcan_set_bittiming(ndev); + if (err < 0) + return err; + + /* Enable interrupts */ + priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_INTR_ALL); + + /* Check whether it is loopback mode or normal mode */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { + reg_msr = XCAN_MSR_LBACK_MASK; + reg_sr_mask = XCAN_SR_LBACK_MASK; + } else { + reg_msr = 0x0; + reg_sr_mask = XCAN_SR_NORMAL_MASK; + } + + priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr); + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); + + timeout = jiffies + XCAN_TIMEOUT; + while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & reg_sr_mask)) { + if (time_after(jiffies, timeout)) { + netdev_warn(ndev, + "timed out for correct mode\n"); + return -ETIMEDOUT; + } + } + netdev_dbg(ndev, "status:#x%08x\n", + priv->read_reg(priv, XCAN_SR_OFFSET)); + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + return 0; +} + +/** + * xcan_do_set_mode - This sets the mode of the driver + * @ndev: Pointer to net_device structure + * @mode: Tells the mode of the driver + * + * This check the drivers state and calls the + * the corresponding modes to set. + * + * Return: 0 on success and failure value on error + */ +static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode) +{ + int ret; + + switch (mode) { + case CAN_MODE_START: + ret = xcan_chip_start(ndev); + if (ret < 0) { + netdev_err(ndev, "xcan_chip_start failed!\n"); + return ret; + } + netif_wake_queue(ndev); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/** + * xcan_start_xmit - Starts the transmission + * @skb: sk_buff pointer that contains data to be Txed + * @ndev: Pointer to net_device structure + * + * This function is invoked from upper layers to initiate transmission. This + * function uses the next available free txbuff and populates their fields to + * start the transmission. + * + * Return: 0 on success and failure value on error + */ +static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + u32 id, dlc, data[2] = {0, 0}; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + + /* Check if the TX buffer is full */ + if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) & + XCAN_SR_TXFLL_MASK)) { + netif_stop_queue(ndev); + netdev_err(ndev, "BUG!, TX FIFO full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + /* Watch carefully on the bit sequence */ + if (cf->can_id & CAN_EFF_FLAG) { + /* Extended CAN ID format */ + id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) & + XCAN_IDR_ID2_MASK; + id |= (((cf->can_id & CAN_EFF_MASK) >> + (CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) << + XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK; + + /* The substibute remote TX request bit should be "1" + * for extended frames as in the Xilinx CAN datasheet + */ + id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK; + + if (cf->can_id & CAN_RTR_FLAG) + /* Extended frames remote TX request */ + id |= XCAN_IDR_RTR_MASK; + } else { + /* Standard CAN ID format */ + id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) & + XCAN_IDR_ID1_MASK; + + if (cf->can_id & CAN_RTR_FLAG) + /* Standard frames remote TX request */ + id |= XCAN_IDR_SRR_MASK; + } + + dlc = cf->can_dlc << XCAN_DLCR_DLC_SHIFT; + + if (cf->can_dlc > 0) + data[0] = be32_to_cpup((__be32 *)(cf->data + 0)); + if (cf->can_dlc > 4) + data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); + + can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); + priv->tx_head++; + + /* Write the Frame to Xilinx CAN TX FIFO */ + priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id); + /* If the CAN frame is RTR frame this write triggers tranmission */ + priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc); + if (!(cf->can_id & CAN_RTR_FLAG)) { + priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data[0]); + /* If the CAN frame is Standard/Extended frame this + * write triggers tranmission + */ + priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data[1]); + stats->tx_bytes += cf->can_dlc; + } + + /* Check if the TX buffer is full */ + if ((priv->tx_head - priv->tx_tail) == priv->tx_max) + netif_stop_queue(ndev); + + return NETDEV_TX_OK; +} + +/** + * xcan_rx - Is called from CAN isr to complete the received + * frame processing + * @ndev: Pointer to net_device structure + * + * This function is invoked from the CAN isr(poll) to process the Rx frames. It + * does minimal processing and invokes "netif_receive_skb" to complete further + * processing. + * Return: 1 on success and 0 on failure. + */ +static int xcan_rx(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 id_xcan, dlc, data[2] = {0, 0}; + + skb = alloc_can_skb(ndev, &cf); + if (unlikely(!skb)) { + stats->rx_dropped++; + return 0; + } + + /* Read a frame from Xilinx zynq CANPS */ + id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET); + dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) >> + XCAN_DLCR_DLC_SHIFT; + + /* Change Xilinx CAN data length format to socketCAN data format */ + cf->can_dlc = get_can_dlc(dlc); + + /* Change Xilinx CAN ID format to socketCAN ID format */ + if (id_xcan & XCAN_IDR_IDE_MASK) { + /* The received frame is an Extended format frame */ + cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3; + cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >> + XCAN_IDR_ID2_SHIFT; + cf->can_id |= CAN_EFF_FLAG; + if (id_xcan & XCAN_IDR_RTR_MASK) + cf->can_id |= CAN_RTR_FLAG; + } else { + /* The received frame is a standard format frame */ + cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> + XCAN_IDR_ID1_SHIFT; + if (id_xcan & XCAN_IDR_SRR_MASK) + cf->can_id |= CAN_RTR_FLAG; + } + + if (!(id_xcan & XCAN_IDR_SRR_MASK)) { + data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); + data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + + /* Change Xilinx CAN data format to socketCAN data format */ + if (cf->can_dlc > 0) + *(__be32 *)(cf->data) = cpu_to_be32(data[0]); + if (cf->can_dlc > 4) + *(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]); + } + + stats->rx_bytes += cf->can_dlc; + stats->rx_packets++; + netif_receive_skb(skb); + + return 1; +} + +/** + * xcan_err_interrupt - error frame Isr + * @ndev: net_device pointer + * @isr: interrupt status register value + * + * This is the CAN error interrupt and it will + * check the the type of error and forward the error + * frame to upper layers. + */ +static void xcan_err_interrupt(struct net_device *ndev, u32 isr) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 err_status, status, txerr = 0, rxerr = 0; + + skb = alloc_can_err_skb(ndev, &cf); + + err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); + priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); + txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; + rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & + XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); + status = priv->read_reg(priv, XCAN_SR_OFFSET); + + if (isr & XCAN_IXR_BSOFF_MASK) { + priv->can.state = CAN_STATE_BUS_OFF; + priv->can.can_stats.bus_off++; + /* Leave device in Config Mode in bus-off state */ + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + can_bus_off(ndev); + if (skb) + cf->can_id |= CAN_ERR_BUSOFF; + } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) { + priv->can.state = CAN_STATE_ERROR_PASSIVE; + priv->can.can_stats.error_passive++; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (rxerr > 127) ? + CAN_ERR_CRTL_RX_PASSIVE : + CAN_ERR_CRTL_TX_PASSIVE; + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + } else if (status & XCAN_SR_ERRWRN_MASK) { + priv->can.state = CAN_STATE_ERROR_WARNING; + priv->can.can_stats.error_warning++; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + } + + /* Check for Arbitration lost interrupt */ + if (isr & XCAN_IXR_ARBLST_MASK) { + priv->can.can_stats.arbitration_lost++; + if (skb) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = CAN_ERR_LOSTARB_UNSPEC; + } + } + + /* Check for RX FIFO Overflow interrupt */ + if (isr & XCAN_IXR_RXOFLW_MASK) { + stats->rx_over_errors++; + stats->rx_errors++; + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + } + } + + /* Check for error interrupt */ + if (isr & XCAN_IXR_ERROR_MASK) { + 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; + } + } + + /* Check for Bit error interrupt */ + if (err_status & XCAN_ESR_BERR_MASK) { + stats->tx_errors++; + if (skb) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_BIT; + } + } + + /* Check for Stuff error interrupt */ + if (err_status & XCAN_ESR_STER_MASK) { + stats->rx_errors++; + if (skb) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_STUFF; + } + } + + /* Check for Form error interrupt */ + if (err_status & XCAN_ESR_FMER_MASK) { + stats->rx_errors++; + if (skb) { + cf->can_id |= CAN_ERR_PROT; + cf->data[2] = CAN_ERR_PROT_FORM; + } + } + + /* Check for CRC error interrupt */ + if (err_status & XCAN_ESR_CRCER_MASK) { + 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; + } + } + priv->can.can_stats.bus_error++; + } + + if (skb) { + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } + + netdev_dbg(ndev, "%s: error status register:0x%x\n", + __func__, priv->read_reg(priv, XCAN_ESR_OFFSET)); +} + +/** + * xcan_state_interrupt - It will check the state of the CAN device + * @ndev: net_device pointer + * @isr: interrupt status register value + * + * This will checks the state of the CAN device + * and puts the device into appropriate state. + */ +static void xcan_state_interrupt(struct net_device *ndev, u32 isr) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + /* Check for Sleep interrupt if set put CAN device in sleep state */ + if (isr & XCAN_IXR_SLP_MASK) + priv->can.state = CAN_STATE_SLEEPING; + + /* Check for Wake up interrupt if set put CAN device in Active state */ + if (isr & XCAN_IXR_WKUP_MASK) + priv->can.state = CAN_STATE_ERROR_ACTIVE; +} + +/** + * xcan_rx_poll - Poll routine for rx packets (NAPI) + * @napi: napi structure pointer + * @quota: Max number of rx packets to be processed. + * + * This is the poll routine for rx part. + * It will process the packets maximux quota value. + * + * Return: number of packets received + */ +static int xcan_rx_poll(struct napi_struct *napi, int quota) +{ + struct net_device *ndev = napi->dev; + struct xcan_priv *priv = netdev_priv(ndev); + u32 isr, ier; + int work_done = 0; + + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { + if (isr & XCAN_IXR_RXOK_MASK) { + priv->write_reg(priv, XCAN_ICR_OFFSET, + XCAN_IXR_RXOK_MASK); + work_done += xcan_rx(ndev); + } else { + priv->write_reg(priv, XCAN_ICR_OFFSET, + XCAN_IXR_RXNEMP_MASK); + break; + } + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } + + if (work_done) + can_led_event(ndev, CAN_LED_EVENT_RX); + + if (work_done < quota) { + napi_complete(napi); + ier = priv->read_reg(priv, XCAN_IER_OFFSET); + ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); + priv->write_reg(priv, XCAN_IER_OFFSET, ier); + } + return work_done; +} + +/** + * xcan_tx_interrupt - Tx Done Isr + * @ndev: net_device pointer + * @isr: Interrupt status register value + */ +static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) +{ + struct xcan_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + + while ((priv->tx_head - priv->tx_tail > 0) && + (isr & XCAN_IXR_TXOK_MASK)) { + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + can_get_echo_skb(ndev, priv->tx_tail % + priv->tx_max); + priv->tx_tail++; + stats->tx_packets++; + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } + can_led_event(ndev, CAN_LED_EVENT_TX); + netif_wake_queue(ndev); +} + +/** + * xcan_interrupt - CAN Isr + * @irq: irq number + * @dev_id: device id poniter + * + * This is the xilinx CAN Isr. It checks for the type of interrupt + * and invokes the corresponding ISR. + * + * Return: + * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise + */ +static irqreturn_t xcan_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct xcan_priv *priv = netdev_priv(ndev); + u32 isr, ier; + + /* Get the interrupt status from Xilinx CAN */ + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + if (!isr) + return IRQ_NONE; + + /* Check for the type of interrupt and Processing it */ + if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) { + priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK | + XCAN_IXR_WKUP_MASK)); + xcan_state_interrupt(ndev, isr); + } + + /* Check for Tx interrupt and Processing it */ + if (isr & XCAN_IXR_TXOK_MASK) + xcan_tx_interrupt(ndev, isr); + + /* Check for the type of error interrupt and Processing it */ + if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) { + priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK | + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK | + XCAN_IXR_ARBLST_MASK)); + xcan_err_interrupt(ndev, isr); + } + + /* Check for the type of receive interrupt and Processing it */ + if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { + ier = priv->read_reg(priv, XCAN_IER_OFFSET); + ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); + priv->write_reg(priv, XCAN_IER_OFFSET, ier); + napi_schedule(&priv->napi); + } + return IRQ_HANDLED; +} + +/** + * xcan_chip_stop - Driver stop routine + * @ndev: Pointer to net_device structure + * + * This is the drivers stop routine. It will disable the + * interrupts and put the device into configuration mode. + */ +static void xcan_chip_stop(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 ier; + + /* Disable interrupts and leave the can in configuration mode */ + ier = priv->read_reg(priv, XCAN_IER_OFFSET); + ier &= ~XCAN_INTR_ALL; + priv->write_reg(priv, XCAN_IER_OFFSET, ier); + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + priv->can.state = CAN_STATE_STOPPED; +} + +/** + * xcan_open - Driver open routine + * @ndev: Pointer to net_device structure + * + * This is the driver open routine. + * Return: 0 on success and failure value on error + */ +static int xcan_open(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + int ret; + + ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags, + ndev->name, ndev); + if (ret < 0) { + netdev_err(ndev, "irq allocation for CAN failed\n"); + goto err; + } + + ret = clk_prepare_enable(priv->can_clk); + if (ret) { + netdev_err(ndev, "unable to enable device clock\n"); + goto err_irq; + } + + ret = clk_prepare_enable(priv->bus_clk); + if (ret) { + netdev_err(ndev, "unable to enable bus clock\n"); + goto err_can_clk; + } + + /* Set chip into reset mode */ + ret = set_reset_mode(ndev); + if (ret < 0) { + netdev_err(ndev, "mode resetting failed!\n"); + goto err_bus_clk; + } + + /* Common open */ + ret = open_candev(ndev); + if (ret) + goto err_bus_clk; + + ret = xcan_chip_start(ndev); + if (ret < 0) { + netdev_err(ndev, "xcan_chip_start failed!\n"); + goto err_candev; + } + + can_led_event(ndev, CAN_LED_EVENT_OPEN); + napi_enable(&priv->napi); + netif_start_queue(ndev); + + return 0; + +err_candev: + close_candev(ndev); +err_bus_clk: + clk_disable_unprepare(priv->bus_clk); +err_can_clk: + clk_disable_unprepare(priv->can_clk); +err_irq: + free_irq(ndev->irq, ndev); +err: + return ret; +} + +/** + * xcan_close - Driver close routine + * @ndev: Pointer to net_device structure + * + * Return: 0 always + */ +static int xcan_close(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + napi_disable(&priv->napi); + xcan_chip_stop(ndev); + clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->can_clk); + free_irq(ndev->irq, ndev); + close_candev(ndev); + + can_led_event(ndev, CAN_LED_EVENT_STOP); + + return 0; +} + +/** + * xcan_get_berr_counter - error counter routine + * @ndev: Pointer to net_device structure + * @bec: Pointer to can_berr_counter structure + * + * This is the driver error counter routine. + * Return: 0 on success and failure value on error + */ +static int xcan_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) +{ + struct xcan_priv *priv = netdev_priv(ndev); + int ret; + + ret = clk_prepare_enable(priv->can_clk); + if (ret) + goto err; + + ret = clk_prepare_enable(priv->bus_clk); + if (ret) + goto err_clk; + + bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; + bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & + XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); + + clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->can_clk); + + return 0; + +err_clk: + clk_disable_unprepare(priv->can_clk); +err: + return ret; +} + + +static const struct net_device_ops xcan_netdev_ops = { + .ndo_open = xcan_open, + .ndo_stop = xcan_close, + .ndo_start_xmit = xcan_start_xmit, +}; + +/** + * xcan_suspend - Suspend method for the driver + * @dev: Address of the platform_device structure + * + * Put the driver into low power mode. + * Return: 0 always + */ +static int __maybe_unused xcan_suspend(struct device *dev) +{ + struct platform_device *pdev = dev_get_drvdata(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + } + + priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); + priv->can.state = CAN_STATE_SLEEPING; + + clk_disable(priv->bus_clk); + clk_disable(priv->can_clk); + + return 0; +} + +/** + * xcan_resume - Resume from suspend + * @dev: Address of the platformdevice structure + * + * Resume operation after suspend. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused xcan_resume(struct device *dev) +{ + struct platform_device *pdev = dev_get_drvdata(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + int ret; + + ret = clk_enable(priv->bus_clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + ret = clk_enable(priv->can_clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + clk_disable_unprepare(priv->bus_clk); + return ret; + } + + priv->write_reg(priv, XCAN_MSR_OFFSET, 0); + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + if (netif_running(ndev)) { + netif_device_attach(ndev); + netif_start_queue(ndev); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); + +/** + * xcan_probe - Platform registration call + * @pdev: Handle to the platform device structure + * + * This function does all the memory allocation and registration for the CAN + * device. + * + * Return: 0 on success and failure value on error + */ +static int xcan_probe(struct platform_device *pdev) +{ + struct resource *res; /* IO mem resources */ + struct net_device *ndev; + struct xcan_priv *priv; + void __iomem *addr; + int ret, rx_max, tx_max; + + /* Get the virtual base address for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(addr)) { + ret = PTR_ERR(addr); + goto err; + } + + ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); + if (ret < 0) + goto err; + + ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", &rx_max); + if (ret < 0) + goto err; + + /* Create a CAN device instance */ + ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + priv->dev = ndev; + priv->can.bittiming_const = &xcan_bittiming_const; + priv->can.do_set_mode = xcan_do_set_mode; + priv->can.do_get_berr_counter = xcan_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_BERR_REPORTING; + priv->reg_base = addr; + priv->tx_max = tx_max; + + /* Get IRQ for the device */ + ndev->irq = platform_get_irq(pdev, 0); + ndev->flags |= IFF_ECHO; /* We support local echo */ + + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + ndev->netdev_ops = &xcan_netdev_ops; + + /* Getting the CAN can_clk info */ + priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); + if (IS_ERR(priv->can_clk)) { + dev_err(&pdev->dev, "Device clock not found.\n"); + ret = PTR_ERR(priv->can_clk); + goto err_free; + } + /* Check for type of CAN device */ + if (of_device_is_compatible(pdev->dev.of_node, + "xlnx,zynq-can-1.0")) { + priv->bus_clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(priv->bus_clk)) { + dev_err(&pdev->dev, "bus clock not found\n"); + ret = PTR_ERR(priv->bus_clk); + goto err_free; + } + } else { + priv->bus_clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(priv->bus_clk)) { + dev_err(&pdev->dev, "bus clock not found\n"); + ret = PTR_ERR(priv->bus_clk); + goto err_free; + } + } + + ret = clk_prepare_enable(priv->can_clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable device clock\n"); + goto err_free; + } + + ret = clk_prepare_enable(priv->bus_clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable bus clock\n"); + goto err_unprepare_disable_dev; + } + + priv->write_reg = xcan_write_reg_le; + priv->read_reg = xcan_read_reg_le; + + if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) { + priv->write_reg = xcan_write_reg_be; + priv->read_reg = xcan_read_reg_be; + } + + priv->can.clock.freq = clk_get_rate(priv->can_clk); + + netif_napi_add(ndev, &priv->napi, xcan_rx_poll, rx_max); + + ret = register_candev(ndev); + if (ret) { + dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); + goto err_unprepare_disable_busclk; + } + + devm_can_led_init(ndev); + clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->can_clk); + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + priv->reg_base, ndev->irq, priv->can.clock.freq, + priv->tx_max); + + return 0; + +err_unprepare_disable_busclk: + clk_disable_unprepare(priv->bus_clk); +err_unprepare_disable_dev: + clk_disable_unprepare(priv->can_clk); +err_free: + free_candev(ndev); +err: + return ret; +} + +/** + * xcan_remove - Unregister the device after releasing the resources + * @pdev: Handle to the platform device structure + * + * This function frees all the resources allocated to the device. + * Return: 0 always + */ +static int xcan_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct xcan_priv *priv = netdev_priv(ndev); + + if (set_reset_mode(ndev) < 0) + netdev_err(ndev, "mode resetting failed!\n"); + + unregister_candev(ndev); + netif_napi_del(&priv->napi); + free_candev(ndev); + + return 0; +} + +/* Match table for OF platform binding */ +static struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,zynq-can-1.0", }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + +static struct platform_driver xcan_driver = { + .probe = xcan_probe, + .remove = xcan_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .pm = &xcan_dev_pm_ops, + .of_match_table = xcan_of_match, + }, +}; + +module_platform_driver(xcan_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Xilinx Inc"); +MODULE_DESCRIPTION("Xilinx CAN interface"); |
