diff options
Diffstat (limited to 'drivers/net/can/grcan.c')
-rw-r--r-- | drivers/net/can/grcan.c | 91 |
1 files changed, 43 insertions, 48 deletions
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 378200b682fa..4bedcc3eea0d 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/delay.h> +#include <linux/ethtool.h> #include <linux/io.h> #include <linux/can/dev.h> #include <linux/spinlock.h> @@ -241,13 +242,14 @@ struct grcan_device_config { .rxsize = GRCAN_DEFAULT_BUFFER_SIZE, \ } -#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 0x4100 +#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 4100 #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 device *ofdev_dev; struct napi_struct napi; struct grcan_registers __iomem *regs; /* ioremap'ed registers */ @@ -255,7 +257,6 @@ struct grcan_priv { 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 @@ -515,12 +516,10 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo) 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); + stats->tx_bytes += can_get_echo_skb(dev, i, NULL); } else { /* For cleanup of untransmitted messages */ - can_free_echo_skb(dev, i); + can_free_echo_skb(dev, i, NULL); } priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE, @@ -673,6 +672,7 @@ static void grcan_err(struct net_device *dev, u32 sources, u32 status) /* There are no others at this point */ break; } + cf.can_id |= CAN_ERR_CNT; cf.data[6] = txerr; cf.data[7] = rxerr; priv->can.state = state; @@ -726,7 +726,7 @@ static void grcan_err(struct net_device *dev, u32 sources, u32 status) txrx = "on rx "; stats->rx_errors++; } - netdev_err(dev, "Fatal AHB buss error %s- halting device\n", + netdev_err(dev, "Fatal AHB bus error %s- halting device\n", txrx); spin_lock_irqsave(&priv->lock, flags); @@ -924,7 +924,7 @@ 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_free_coherent(priv->ofdev_dev, dma->base_size, dma->base_buf, dma->base_handle); memset(dma, 0, sizeof(*dma)); } @@ -949,7 +949,7 @@ static int grcan_allocate_dma_buffers(struct net_device *dev, /* 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_buf = dma_alloc_coherent(priv->ofdev_dev, dma->base_size, &dma->base_handle, GFP_KERNEL); @@ -1062,16 +1062,10 @@ static int grcan_open(struct net_device *dev) priv->can.echo_skb_max = dma->tx.size; priv->can.echo_skb = priv->echo_skb; - priv->txdlc = kcalloc(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; + goto exit_free_echo_skb; err = request_irq(dev->irq, grcan_interrupt, IRQF_SHARED, dev->name, dev); @@ -1093,8 +1087,6 @@ static int grcan_open(struct net_device *dev) exit_close_candev: close_candev(dev); -exit_free_txdlc: - kfree(priv->txdlc); exit_free_echo_skb: kfree(priv->echo_skb); exit_free_dma_buffers: @@ -1113,8 +1105,10 @@ static int grcan_close(struct net_device *dev) priv->closing = true; if (priv->need_txbug_workaround) { + spin_unlock_irqrestore(&priv->lock, flags); del_timer_sync(&priv->hang_timer); del_timer_sync(&priv->rr_timer); + spin_lock_irqsave(&priv->lock, flags); } netif_stop_queue(dev); grcan_stop_hardware(dev); @@ -1129,12 +1123,11 @@ static int grcan_close(struct net_device *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) +static void grcan_transmit_catch_up(struct net_device *dev) { struct grcan_priv *priv = netdev_priv(dev); unsigned long flags; @@ -1142,7 +1135,7 @@ static int grcan_transmit_catch_up(struct net_device *dev, int budget) spin_lock_irqsave(&priv->lock, flags); - work_done = catch_up_echo_skb(dev, budget, true); + work_done = catch_up_echo_skb(dev, -1, true); if (work_done) { if (!priv->resetting && !priv->closing && !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) @@ -1156,8 +1149,6 @@ static int grcan_transmit_catch_up(struct net_device *dev, int budget) } spin_unlock_irqrestore(&priv->lock, flags); - - return work_done; } static int grcan_receive(struct net_device *dev, int budget) @@ -1201,21 +1192,21 @@ static int grcan_receive(struct net_device *dev, int budget) cf->can_id = ((slot[0] & GRCAN_MSG_BID) >> GRCAN_MSG_BID_BIT); } - cf->can_dlc = get_can_dlc((slot[1] & GRCAN_MSG_DLC) + cf->len = can_cc_dlc2len((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++) { + for (i = 0; i < cf->len; i++) { j = GRCAN_MSG_DATA_SLOT_INDEX(i); shift = GRCAN_MSG_DATA_SHIFT(i); cf->data[i] = (u8)(slot[j] >> shift); } - } - /* Update statistics and read pointer */ + stats->rx_bytes += cf->len; + } stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size); @@ -1239,19 +1230,13 @@ static int grcan_poll(struct napi_struct *napi, int budget) 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; + int work_done; - /* Half of the budget for receiveing messages */ - rx_work_done = grcan_receive(dev, rx_budget); + work_done = grcan_receive(dev, 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); + grcan_transmit_catch_up(dev); - if (rx_work_done < rx_budget && tx_work_done < tx_budget) { + if (work_done < budget) { napi_complete(napi); /* Guarantee no interference with a running reset that otherwise @@ -1268,7 +1253,7 @@ static int grcan_poll(struct napi_struct *napi, int budget) spin_unlock_irqrestore(&priv->lock, flags); } - return rx_work_done + tx_work_done; + return work_done; } /* Work tx bug by waiting while for the risky situation to clear. If that fails, @@ -1360,7 +1345,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb, unsigned long flags; u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT; - if (can_dropped_invalid_skb(dev, skb)) + if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; /* Trying to transmit in silent mode will generate error interrupts, but @@ -1399,7 +1384,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb, 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; + dlc = cf->len; if (eff) tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID; else @@ -1447,8 +1432,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb, * 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); + can_put_echo_skb(skb, dev, slotindex, 0); /* Make sure everything is written before allowing hardware to * read from the memory @@ -1578,6 +1562,10 @@ static const struct net_device_ops grcan_netdev_ops = { .ndo_change_mtu = can_change_mtu, }; +static const struct ethtool_ops grcan_ethtool_ops = { + .get_ts_info = ethtool_op_get_ts_info, +}; + static int grcan_setup_netdev(struct platform_device *ofdev, void __iomem *base, int irq, u32 ambafreq, bool txbug) @@ -1594,12 +1582,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev, dev->irq = irq; dev->flags |= IFF_ECHO; dev->netdev_ops = &grcan_netdev_ops; + dev->ethtool_ops = &grcan_ethtool_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->ofdev_dev = &ofdev->dev; priv->regs = base; priv->can.bittiming_const = &grcan_bittiming_const; priv->can.do_set_bittiming = grcan_set_bittiming; @@ -1626,7 +1616,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev, timer_setup(&priv->hang_timer, grcan_initiate_running_reset, 0); } - netif_napi_add(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT); + netif_napi_add_weight(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", @@ -1652,6 +1642,7 @@ exit_free_candev: static int grcan_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; + struct device_node *sysid_parent; u32 sysid, ambafreq; int irq, err; void __iomem *base; @@ -1660,10 +1651,14 @@ static int grcan_probe(struct platform_device *ofdev) /* 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; + sysid_parent = of_find_node_by_path("/ambapp0"); + if (sysid_parent) { + err = of_property_read_u32(sysid_parent, "systemid", &sysid); + if (!err && ((sysid & GRLIB_VERSION_MASK) >= + GRCAN_TXBUG_SAFE_GRLIB_VERSION)) + txbug = false; + of_node_put(sysid_parent); + } err = of_property_read_u32(np, "freq", &ambafreq); if (err) { |