Re: [PATCH v2 2/2] can: spi: hi311x: Add Holt HI-311x CAN driver

From: Akshay Bhat
Date: Mon Mar 13 2017 - 11:38:28 EST


Hi Wolfgang,

On 03/09/2017 12:36 PM, Wolfgang Grandegger wrote:
> Hello,
>
> doing a quick review... I realized a few issues...
>
> Am 17.01.2017 um 20:22 schrieb Akshay Bhat:
>> +static u8 hi3110_read(struct spi_device *spi, u8 command)
>> +{
>> + struct hi3110_priv *priv = spi_get_drvdata(spi);
>> + u8 val = 0;
>> +
>> + priv->spi_tx_buf[0] = command;
>> + hi3110_spi_trans(spi, 2);
>> + val = priv->spi_rx_buf[1];
>> + dev_dbg(&spi->dev, "hi3110_read: %02X, %02X\n", command, val);
>
> This produces a lot of output which is not useful for the normal user.
>

Fixed in v3 patch.

>> +static void hi3110_write(struct spi_device *spi, u8 reg, u8 val)
>> +{
>> + struct hi3110_priv *priv = spi_get_drvdata(spi);
>> +
>> + priv->spi_tx_buf[0] = reg;
>> + priv->spi_tx_buf[1] = val;
>> + dev_dbg(&spi->dev, "hi3110_write: %02X, %02X\n", reg, val);
>
> Ditto.
>

Fixed in v3 patch.


>> +
>> +static void hi3110_hw_rx(struct spi_device *spi)
>> +{
>> + struct hi3110_priv *priv = spi_get_drvdata(spi);
>> + struct sk_buff *skb;
>> + struct can_frame *frame;
>> + u8 buf[HI3110_RX_BUF_LEN - 1];
>> +
>> + skb = alloc_can_skb(priv->net, &frame);
>> + if (!skb) {
>> + dev_err(&spi->dev, "cannot allocate RX skb\n");
>
> Please return silenty! Otherwise it will make the situation worse.
>

Fixed in v3 patch.

>> +
>> + /* Data length */
>> + frame->can_dlc = get_can_dlc(buf[HI3110_FIFO_WOTIME_DLC_OFF] &
>> 0x0F);
>> + memcpy(frame->data, buf + HI3110_FIFO_WOTIME_DAT_OFF,
>> frame->can_dlc);
>
> No data bytes should not be copied for RTR messages.
>

Fixed in v3 patch.

>> +
>> + if (priv->tx_skb || priv->tx_len) {
>> + dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
>
> s/warn/err/? This should never happen; IIUC.
>

Fixed in v3 patch.

>> + return NETDEV_TX_BUSY;
>> + }
>> +
>> + if (can_dropped_invalid_skb(net, skb))
>> + return NETDEV_TX_OK;
>> +
>> + netif_stop_queue(net);
>
> The driver transfers the packets in sequence. Any chance to queue them?
> At least there is a TX FIFO for 8 messages. That's bad for RT but would
> increase the throughput.
>

I initially did not use the TX FIFO for the reason you mentioned above.
Queuing should be possible but since it requires lot more additional
logic, I can work on it a later time.


>> +
>> + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
>> + /* Put device into loopback mode */
>> + hi3110_write(spi, HI3110_WRITE_CTRL0,
>> + HI3110_CTRL0_LOOPBACK_MODE);
>> + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
>> + /* Put device into listen-only mode */
>> + hi3110_write(spi, HI3110_WRITE_CTRL0,
>> + HI3110_CTRL0_MONITOR_MODE);
>> + } else {
>> + /* Put device into normal mode */
>> + hi3110_write(spi, HI3110_WRITE_CTRL0,
>> + HI3110_CTRL0_NORMAL_MODE);
>
> "mode = x" and just one write is more compact.
>

Fixed in v3 patch.

>> +
>> + /* Wait for the device to enter normal mode */
>> + mdelay(HI3110_OST_DELAY_MS);
>> + reg = hi3110_read(spi, HI3110_READ_CTRL0);
>> + if ((reg & HI3110_CTRL0_MODE_MASK) != HI3110_CTRL0_NORMAL_MODE)
>> + return -EBUSY;
>
> Is this not necesary for listen or loopbcak only mode?
>

It is necessary, fixed in v3 patch.

>> +
>> +static void hi3110_error_skb(struct net_device *net, int can_id,
>> + int data1, int data2)
>> +{
>> + struct sk_buff *skb;
>> + struct can_frame *frame;
>> +
>> + skb = alloc_can_err_skb(net, &frame);
>> + if (skb) {
>> + frame->can_id |= can_id;
>> + frame->data[1] = data1;
>> + frame->data[2] = data2;
>> + netif_rx_ni(skb);
>> + } else {
>> + netdev_err(net, "cannot allocate error skb\n");
>
> Please remove the error message. Not a good at low memory situations.
>

Fixed in v3 patch.

>> + /* Check for protocol errors */
>> + if (eflag & HI3110_ERR_PROTOCOL_MASK) {
>> + can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
>> + priv->can.can_stats.bus_error++;
>> + priv->net->stats.rx_errors++;
>> + if (eflag & HI3110_ERR_BITERR)
>> + data2 |= CAN_ERR_PROT_BIT;
>> + else if (eflag & HI3110_ERR_FRMERR)
>> + data2 |= CAN_ERR_PROT_FORM;
>> + else if (eflag & HI3110_ERR_STUFERR)
>> + data2 |= CAN_ERR_PROT_STUFF;
>> + else
>> + data2 |= CAN_ERR_PROT_UNSPEC;
>
> And what about the ACK and CRC error defines at the beginning?
> It's also comon to use netdev_dbg() on error interrupts.
>

Good catch, I missed it. Fixed in v3 patch.

>> + }
>
> Bus error reporting can flood the system with interrupts. Any chance to
> implement CAN_CTRLMODE_BERR_REPORTING. I think the bus error interrupt
> can be enabled/disabled.
>

Thanks, was not aware of this feature. Added it in v3 patch.

>> + /* Update can state statistics */
>> + switch (priv->can.state) {
>> + case CAN_STATE_ERROR_ACTIVE:
>> + if (new_state >= CAN_STATE_ERROR_WARNING &&
>> + new_state <= CAN_STATE_BUS_OFF)
>> + priv->can.can_stats.error_warning++;
>> + /* fallthrough */
>> + case CAN_STATE_ERROR_WARNING:
>> + if (new_state >= CAN_STATE_ERROR_PASSIVE &&
>> + new_state <= CAN_STATE_BUS_OFF)
>> + priv->can.can_stats.error_passive++;
>> + break;
>> + default:
>> + break;
>> + }
>> + priv->can.state = new_state;
>> +
>> + if (intf & HI3110_INT_BUSERR) {
>> + /* Note: HI3110 Does report overflow errors */
>> + hi3110_error_skb(net, can_id, data1, data2);
>> + }
>
> Usually the bus error counts are filled in the error message frame as
> well. It the counts are available, I would also be nice to have the
> "do_get_berr_counter" callback as well.
>

Added it in v3 patch.

>> +static int hi3110_open(struct net_device *net)
>> +{
>> + struct hi3110_priv *priv = netdev_priv(net);
>> + struct spi_device *spi = priv->spi;
>> + unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_RISING;
>> + int ret;
>> +
>> + ret = open_candev(net);
>> + if (ret) {
>> + dev_err(&spi->dev, "unable to set initial baudrate!\n");
>
> open_candev() does already print an error message.
>

Fixed in v3 patch.


> A few other things to check:
>
> Run "cangen" and monitor the message with "candump -e any,0:0,#FFFFFFF".
> Then 1) disconnect the cable or 2) short-circuit CAN low and high at the
> connector. You should see error messages. After reconnection or removing
> the short-circuit (and bus-off recovery) the state should go back to
> "active".
>

With the above sequence, candump reports "ERRORFRAME" with
protocol-violation{{}{acknowledge-slot}}, bus-error. On re-connecting
the cable the can state goes back to ACTIVE and I see the messages that
were in the queue being sent.

> Run "canfdtest" to check for out-of-order messages. I do not expect
> problems with your driver, though.
>

Ran canfdtest for 100k loop (@1M can bit rate), did not see any issues.

Thanks for your valuable suggests and tests :)
Akshay.