diff options
Diffstat (limited to 'drivers/net/can')
-rw-r--r-- | drivers/net/can/c_can/c_can_platform.c | 46 | ||||
-rw-r--r-- | drivers/net/can/dev.c | 2 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000.c | 27 | ||||
-rw-r--r-- | drivers/net/can/slcan.c | 39 |
4 files changed, 60 insertions, 54 deletions
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 824108cd9fd5..5dede6e64376 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -208,40 +208,31 @@ static int c_can_plat_probe(struct platform_device *pdev) } /* get the appropriate clk */ - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "no clock defined\n"); - ret = -ENODEV; + ret = PTR_ERR(clk); goto exit; } /* get the platform data */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!mem || irq <= 0) { + if (irq <= 0) { ret = -ENODEV; - goto exit_free_clk; - } - - if (!request_mem_region(mem->start, resource_size(mem), - KBUILD_MODNAME)) { - dev_err(&pdev->dev, "resource unavailable\n"); - ret = -ENODEV; - goto exit_free_clk; + goto exit; } - addr = ioremap(mem->start, resource_size(mem)); - if (!addr) { - dev_err(&pdev->dev, "failed to map can port\n"); - ret = -ENOMEM; - goto exit_release_mem; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(addr)) { + ret = PTR_ERR(addr); + goto exit; } /* allocate the c_can device */ dev = alloc_c_can_dev(); if (!dev) { ret = -ENOMEM; - goto exit_iounmap; + goto exit; } priv = netdev_priv(dev); @@ -287,7 +278,8 @@ static int c_can_plat_probe(struct platform_device *pdev) break; } - priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res); + 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 @@ -321,12 +313,6 @@ static int c_can_plat_probe(struct platform_device *pdev) exit_free_device: free_c_can_dev(dev); -exit_iounmap: - iounmap(addr); -exit_release_mem: - release_mem_region(mem->start, resource_size(mem)); -exit_free_clk: - clk_put(clk); exit: dev_err(&pdev->dev, "probe failed\n"); @@ -336,18 +322,10 @@ exit: 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); free_c_can_dev(dev); - iounmap(priv->base); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); - - clk_put(priv->priv); return 0; } diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e318e87e2bfc..9f91fcba43f8 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -565,7 +565,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max) else size = sizeof_priv; - dev = alloc_netdev(size, "can%d", can_setup); + dev = alloc_netdev(size, "can%d", NET_NAME_UNKNOWN, can_setup); if (!dev) return NULL; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f31499a32d7d..d1692154ed1b 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -141,6 +141,7 @@ static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); unsigned char status = priv->read_reg(priv, SJA1000_MOD); + u8 mod_reg_val = 0x00; int i; for (i = 0; i < 100; i++) { @@ -158,9 +159,10 @@ static void set_normal_mode(struct net_device *dev) /* set chip to normal mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) - priv->write_reg(priv, SJA1000_MOD, MOD_LOM); - else - priv->write_reg(priv, SJA1000_MOD, 0x00); + mod_reg_val |= MOD_LOM; + if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) + mod_reg_val |= MOD_STM; + priv->write_reg(priv, SJA1000_MOD, mod_reg_val); udelay(10); @@ -278,6 +280,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, uint8_t dlc; canid_t id; uint8_t dreg; + u8 cmd_reg_val = 0x00; int i; if (can_dropped_invalid_skb(dev, skb)) @@ -312,9 +315,14 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, can_put_echo_skb(skb, dev, 0); if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) - sja1000_write_cmdreg(priv, CMD_TR | CMD_AT); + cmd_reg_val |= CMD_AT; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + cmd_reg_val |= CMD_SRR; else - sja1000_write_cmdreg(priv, CMD_TR); + cmd_reg_val |= CMD_TR; + + sja1000_write_cmdreg(priv, cmd_reg_val); return NETDEV_TX_OK; } @@ -622,9 +630,12 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) priv->can.do_set_bittiming = sja1000_set_bittiming; priv->can.do_set_mode = sja1000_set_mode; priv->can.do_get_berr_counter = sja1000_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | - CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_ONE_SHOT; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_ONE_SHOT | + CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_PRESUME_ACK; spin_lock_init(&priv->cmdreg_lock); diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index dcf9196f6316..acb5b92ace92 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -52,6 +52,7 @@ #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> @@ -85,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 */ @@ -309,36 +311,46 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf) 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; + } - spin_lock_bh(&sl->lock); 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. */ static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -517,7 +529,7 @@ static struct slcan *slc_alloc(dev_t line) return NULL; sprintf(name, "slcan%d", i); - dev = alloc_netdev(sizeof(*sl), name, slc_setup); + dev = alloc_netdev(sizeof(*sl), name, NET_NAME_UNKNOWN, slc_setup); if (!dev) return NULL; @@ -528,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; @@ -626,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); |