This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Sitara DCAN Linux driving both CAN interfaces simultaneously

Other Parts Discussed in Thread: AM3359

Hello,

I'm working on TI Sitara TQ board TQMa335x with AM3359 CPU. On the board are two CAN interfaces. I'm using TI Linux kernel 3.14.19 (linux-ti2014.10.00). DCAN core driver source file is drivers/net/can/c_can/c_can.c and platform bus driver source file is drivers/net/can/c_can/c_can_platform.c. I'm using CAN Utilities by Pengutronix canutils-4.0.6 and libsocketcan by Pengutronix  libsocketcan-0.0.10. In dts file am335x-mba335x.dts I enabled both CAN interfaces (can0 and can1).

Tests in loopback mode (canconfig can0/can1 bitrate 100000 ctrlmode triple-sampling on loopback on) work OK for both interfaces.

The problem is, if I start both interfaces simultaneously, then system froze. E.g., canconfig can0 bitrate 50000 ctrlmode triple-sampling on and canconfig can1 bitrate 50000 ctrlmode triple-sampling on and then canconfig can0 start (till here everything is still OK), but on canconfig can1 start, the end of story happened. Linux kernel stuck in BUG.

Question: Is it possible to run both CAN interfaces on Sitara simultaneously and how can this be implemented (in my case there is a loopback wired between both interfaces)?


Thanks and best regards, Davor

  • Hi,

    Can you check if this issue still exists with the latest kernel: software-dl.ti.com/.../index_FDS.html
  • Thank you for your quick answer.

    And I'm sorry for my very late reply.

    The TI Linux kernel 4.1.13 (part of PROCESSOR-SDK-LINUX-AM335X) is by default not bootable on our TQ (TQMa335x with AM3359) board. Since the usage of two CAN interfaces was not our privileged task, we postponed this issue.

    Finally I fixed this bug in the TI Linux kernel 3.14.19 (linux-ti2014.10.00).

    The problem was in the platform bus driver code, where initiating start DCAN interface (register raminit) was wrong implemented. It worked only incidentally for only one DCAN interface, and froze the system when tried to start the second interface.

    Here is attached DCAN patch for TI Linux kernel 3.14.19.

    diff -Naur linux-ti2014.10.00/drivers/net/can/c_can/c_can.c linux-ti2014.10.00-new/drivers/net/can/c_can/c_can.c
    --- linux-ti2014.10.00/drivers/net/can/c_can/c_can.c	2015-10-22 10:24:11.000000000 +0200
    +++ linux-ti2014.10.00-new/drivers/net/can/c_can/c_can.c	2016-05-24 14:14:45.000000000 +0200
    @@ -592,6 +592,7 @@
     {
     	struct c_can_priv *priv = netdev_priv(dev);
     	int err;
    +	struct pinctrl *p;
     
     	/* basic c_can configuration */
     	err = c_can_chip_config(dev);
    @@ -605,7 +606,15 @@
     	priv->can.state = CAN_STATE_ERROR_ACTIVE;
     
     	/* activate pins */
    +#if 0
     	pinctrl_pm_select_default_state(dev->dev.parent);
    +#else
    +	p = pinctrl_get_select(priv->device, "active");
    +	if (!IS_ERR(p))
    +		pinctrl_put(p);
    +	else
    +		pinctrl_pm_select_default_state(priv->device);
    +#endif
     	return 0;
     }
     
    @@ -615,6 +624,9 @@
     
     	c_can_irq_control(priv, false);
     
    +	/* put ctrl to init on stop to end ongoing transmission */
    +	priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_INIT);
    +
     	/* deactivate pins */
     	pinctrl_pm_select_sleep_state(dev->dev.parent);
     	priv->can.state = CAN_STATE_STOPPED;
    @@ -866,7 +878,11 @@
     	case C_CAN_BUS_OFF:
     		/* bus-off state */
     		priv->can.state = CAN_STATE_BUS_OFF;
    +#if 0
     		can_bus_off(dev);
    +#else
    +		priv->can.can_stats.bus_off++;
    +#endif
     		break;
     	default:
     		break;
    diff -Naur linux-ti2014.10.00/drivers/net/can/c_can/c_can_platform.c linux-ti2014.10.00-new/drivers/net/can/c_can/c_can_platform.c
    --- linux-ti2014.10.00/drivers/net/can/c_can/c_can_platform.c	2015-10-22 10:24:11.000000000 +0200
    +++ linux-ti2014.10.00-new/drivers/net/can/c_can/c_can_platform.c	2016-05-24 13:51:17.000000000 +0200
    @@ -78,10 +78,17 @@
     static void c_can_hw_raminit_wait_ti(const struct c_can_priv *priv, u32 mask,
     				  u32 val)
     {
    +	int timeout = 0;
    +
     	/* We look only at the bits of our instance. */
     	val &= mask;
    -	while ((readl(priv->raminit_ctrlreg) & mask) != val)
    +	while ((readl(priv->raminit_ctrlreg) & mask) != val) {
     		udelay(1);
    +		if (++timeout >= 1000) {
    +			dev_err(&priv->dev->dev, "%s: time out\n", __func__);
    +			break;
    +		}
    +	}
     }
     
     static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable)
    @@ -100,14 +107,14 @@
     	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);
    +	c_can_hw_raminit_wait_ti(priv, mask, ctrl);
     
     	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);
    +		c_can_hw_raminit_wait_ti(priv, mask, ctrl);
     	}
     	spin_unlock(&raminit_lock);
     }
    

    Best regards and thank you again,

    Davor.

  • Thanks for providing this feedback!