RE: [PATCH v2] can: rcar_canfd: Add Renesas R-Car CAN FD driver

Ramesh Shanmugasundaram
2016-04-28T12:31:40Z

Hi Oliver,

Thanks :-)
Actually it will be v5 patch set & I have sent it now. Marc comments were on old v2 patch.

Thanks,
Ramesh

> -----Original Message-----
> From: Oliver Hartkopp [mailto:socketcan@hartkopp.net]
> Sent: 28 April 2016 07:28
> To: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>;
> wg@grandegger.com; robh+dt@kernel.org; pawel.moll@arm.com;
> mark.rutland@arm.com; ijc+devicetree@hellion.org.uk; galak@codeaurora.org;
> corbet@lwn.net; mkl@pengutronix.de
> Cc: linux-renesas-soc@vger.kernel.org; devicetree@vger.kernel.org; linux-
> can@vger.kernel.org; netdev@vger.kernel.org; linux-doc@vger.kernel.org;
> geert+renesas@glider.be; Chris Paterson <Chris.Paterson2@renesas.com>
> Subject: Re: [PATCH v2] can: rcar_canfd: Add Renesas R-Car CAN FD driver
>
> Hello Ramesh,
>
> please send out a new v3 patchset to trigger the process again :-)
>
> Best regards,
> Oliver
>
> On 04/13/2016 08:25 AM, Ramesh Shanmugasundaram wrote:
> > HI Marc,
> >
> > Gentle reminder!
> > Are you happy with the open comment's disposition? I can send a next
> version of patch if we have a closure on current set of comments.
> >
> > Thanks,
> > Ramesh
> >
> >> -----Original Message-----
> >> From: Ramesh Shanmugasundaram
> >> Sent: 01 April 2016 13:49
> >> To: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>;
> >> wg@grandegger.com; robh+dt@kernel.org; pawel.moll@arm.com;
> >> mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
> >> galak@codeaurora.org; corbet@lwn.net
> >> Cc: linux-renesas-soc@vger.kernel.org; devicetree@vger.kernel.org;
> >> linux- can@vger.kernel.org; netdev@vger.kernel.org;
> >> linux-doc@vger.kernel.org;
> >> geert+renesas@glider.be; Chris Paterson <Chris.Paterson2@renesas.com>
> >> Subject: RE: [PATCH v2] can: rcar_canfd: Add Renesas R-Car CAN FD
> >> driver
> >>
> >> Hi Marc,
> >>
> >> Thanks for your time & review comments.
> >>
> >>> -----Original Message-----
> >> (...)
> >>>> +#define RCANFD_NAPI_WEIGHT 8 /* Rx poll quota */
> >>>> +
> >>>> +#define RCANFD_NUM_CHANNELS 2
> >>>> +#define RCANFD_CHANNELS_MASK 0x3 /* Two channels max */
> >>>
> >>> (BIT(RCANFD_NUM_CHANNELS) - 1
> >>
> >> OK
> >>
> >>>
> >>>> +
> >>>> +/* Rx FIFO is a global resource of the controller. There are 8
> >>>> +such
> >>> FIFOs
> >>>> + * available. Each channel gets a dedicated Rx FIFO (i.e.) the
> >>>> + channel
> >> (...)
> >>>> +#define RCANFD_CMFIFO_CFDLC(x) (((x) & 0xf) << 28)
> >>>> +#define RCANFD_CMFIFO_CFPTR(x) (((x) & 0xfff) << 16)
> >>>> +#define RCANFD_CMFIFO_CFTS(x) (((x) & 0xff) << 0)
> >>>> +
> >>>> +/* Global Test Config register */
> >>>> +#define RCANFD_GTSTCFG_C0CBCE BIT(0)
> >>>> +#define RCANFD_GTSTCFG_C1CBCE BIT(1)
> >>>> +
> >>>> +#define RCANFD_GTSTCTR_ICBCTME BIT(0)
> >>>> +
> >>>> +/* AFL Rx rules registers */
> >>>> +#define RCANFD_AFLCFG_SETRNC0(x) (((x) & 0xff) << 24)
> >>>> +#define RCANFD_AFLCFG_SETRNC1(x) (((x) & 0xff) << 16)
> >>>
> >>> What about something like:
> >>>
> >>> #define RCANFD_AFLCFG_SETRNC(n, x) (((x) & 0xff) << (24 - n * 8))
> >>>
> >>> This will save some if()s in the code
> >>
> >> Nice :-). Will update.
> >>
> >>>
> >>>> +#define RCANFD_AFLCFG_GETRNC0(x) (((x) >> 24) & 0xff)
> >>>> +#define RCANFD_AFLCFG_GETRNC1(x) (((x) >> 16) & 0xff)
> >>>> +
> >>>> +#define RCANFD_AFL_PAGENUM(entry) ((entry) / 16)
> >> (...)
> >>>> +#define rcar_canfd_read(priv, offset) \
> >>>> + readl(priv->base + (offset))
> >>>> +#define rcar_canfd_write(priv, offset, val) \
> >>>> + writel(val, priv->base + (offset))
> >>>> +#define rcar_canfd_set_bit(priv, reg, val) \
> >>>> + rcar_canfd_update(val, val, priv->base + (reg))
> >>>> +#define rcar_canfd_clear_bit(priv, reg, val) \
> >>>> + rcar_canfd_update(val, 0, priv->base + (reg))
> >>>> +#define rcar_canfd_update_bit(priv, reg, mask, val) \
> >>>> + rcar_canfd_update(mask, val, priv->base + (reg))
> >>>
> >>> please use static inline functions instead of defines.
> >>
> >> OK.
> >>
> >>>
> >>>> +
> >>>> +static void rcar_canfd_get_data(struct canfd_frame *cf,
> >>>> + struct rcar_canfd_channel *priv, u32 off)
> >>>
> >>> Please use "struct rcar_canfd_channel *priv" as first argument,
> >>> struct canfd_frame *cf as second. Remove off, as the offset is
> >>> already defined by the channel.
> >>
> >> I'll re-order priv, cf as you mentioned. I'll leave "off" arg as it
> >> is because it is based on FIFO number of channel + mode (CAN only or
> >> CANFD only). Otherwise, I will have to add another check inside this
> >> function for mode.
> >>
> >>>> +{
> >>>> + u32 i, lwords;
> >>>> +
> >>>> + lwords = cf->len / sizeof(u32);
> >>>> + if (cf->len % sizeof(u32))
> >>>> + lwords++;
> >>>
> >>> Use DIV_ROUND_UP() instead of open coding it.
> >>
> >> Agreed. Thanks.
> >>
> >>>
> >>>> + for (i = 0; i < lwords; i++)
> >>>> + *((u32 *)cf->data + i) =
> >>>> + rcar_canfd_read(priv, off + (i * sizeof(u32))); }
> >>>> +
> >>>> +static void rcar_canfd_put_data(struct canfd_frame *cf,
> >>>> + struct rcar_canfd_channel *priv, u32 off)
> >>>
> >>> same here
> >>
> >> Yes (same as _get_data)
> >>
> >>>
> >>>> +{
> >>>> + u32 i, j, lwords, leftover;
> >>>> + u32 data = 0;
> >>>> +
> >>>> + lwords = cf->len / sizeof(u32);
> >>>> + leftover = cf->len % sizeof(u32);
> >>>> + for (i = 0; i < lwords; i++)
> >>>> + rcar_canfd_write(priv, off + (i * sizeof(u32)),
> >>>> + *((u32 *)cf->data + i));
> >>>
> >>> Here you don't convert the endianess...
> >>
> >> Yes
> >>
> >>>> +
> >>>> + if (leftover) {
> >>>> + u8 *p = (u8 *)((u32 *)cf->data + i);
> >>>> +
> >>>> + for (j = 0; j < leftover; j++)
> >>>> + data |= p[j] << (j * 8);
> >>>
> >>> ...here you do an implicit endianess conversion. "data" is little
> >>> endian, while p[j] is big endian.
> >>
> >> Not sure I got the question correctly.
> >> Controller expectation of data bytes in 32bit register is bits[7:0] =
> >> byte0, bits[15:8] = byte1 and so on - little endian.
> >> For e.g. if cf->data points to byte stream H'112233445566
> >> (cf->data[0] = 0x11), first rcar_canfd_write will write 0x44332211
> >> value to register. Yes the host cpu is assumed little endian. In
> >> leftover case, data will be
> >> 0x00006655 - again little endian.
> >> I think I should remove this leftover logic and just mask the unused
> >> bits to zero as cf->data is pre-allocated for max length anyway.
> >>
> >> p[j] is a byte?? Am I missing something?
> >>
> >>>
> >>>> + rcar_canfd_write(priv, off + (i * sizeof(u32)), data);
> >>>> + }
> >>>
> >>> Have you tested to send CAN frames with len != n*4 against a
> >>> different controller?
> >>
> >> Yes, with Vector VN1630A.
> >>
> >>>> +}
> >>>> +
> >>>> +static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
> >>>> +{
> >>>> + u32 i;
> >>>> +
> >>>> + for (i = 0; i < RCANFD_FIFO_DEPTH; i++)
> >>>> + can_free_echo_skb(ndev, i);
> >>>> +}
> >>>> +
> >> (...)
> >>>> +static void rcar_canfd_tx_done(struct net_device *ndev) {
> >>>> + struct rcar_canfd_channel *priv = netdev_priv(ndev);
> >>>> + struct net_device_stats *stats = &ndev->stats;
> >>>> + u32 sts;
> >>>> + unsigned long flags;
> >>>> + u32 ch = priv->channel;
> >>>> +
> >>>> + do {
> >>>
> >>> You should iterare over all pending CAN frames:
> >>>
> >>>> for (/* nix */; (priv->tx_head - priv->tx_tail) > 0; priv-
> >>>> tx_tail++) {
> >>>
> >>
> >> Yes, current code does iterate over pending tx'ed frames. If we use
> >> this for loop semantics, we may have to protect the whole loop with
> >> no real benefit.
> >>
> >>>
> >>>> + u8 unsent, sent;
> >>>> +
> >>>> + sent = priv->tx_tail % RCANFD_FIFO_DEPTH;
> >>>
> >>> and check here, if that packet has really been tramsitted. Exit the
> >>> loop otherweise.
> >>
> >> We are here because of tx_done and hence no need to check tx done
> >> again for the first iteration. Hence the do-while loop. Checks
> >> further down takes care of the need for more iterations/pending tx'ed
> frames.
> >>
> >>>
> >>>> + stats->tx_packets++;
> >>>> + stats->tx_bytes += priv->tx_len[sent];
> >>>> + priv->tx_len[sent] = 0;
> >>>> + can_get_echo_skb(ndev, sent);
> >>>> +
> >>>> + spin_lock_irqsave(&priv->tx_lock, flags);
> >>>
> >>> What does the tx_lock protect? The tx path is per channel, isn't it?
> >>
> >> You are right - tx path is per channel. In tx path, head & tail are
> >> also used to determine when to stop/wakeup netif queue. They are
> >> incremented & compared in different contexts to make this decision.
> >> Per channel tx_lock protects this critical section.
> >>
> >>>
> >>>> + priv->tx_tail++;
> >>>> + sts = rcar_canfd_read(priv,
> >>>> + RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX));
> >>>> + unsent = RCANFD_CMFIFO_CFMC(sts);
> >>>> +
> >>>> + /* Wake producer only when there is room */
> >>>> + if (unsent != RCANFD_FIFO_DEPTH)
> >>>> + netif_wake_queue(ndev);
> >>>
> >>> Move the netif_wake_queue() out of the loop.
> >>
> >> With the tx logic mentioned above, I think keeping it in the loop
> >> seems better. For e.g. say cpu1 pumps 8 frames from an app loop and
> >> cpu0 handles tx_done interrupt handling: cpu1 would have stopped the
> >> queue because FIFO is full -> cpu0 gets tx_done interrupt and by the
> time it checks "unsent"
> >> there could be one or more frames transmitted by device (i.e.) there
> >> would be more space in fifo. It is better to wakeup the netif queue
> >> then and there so that app running on cpu1 can pump more. If we move
> >> it out of the loop we wake up the queue only in the end. Have I missed
> anything?
> >>
> >>>
> >>>> +
> >>>> + if (priv->tx_head - priv->tx_tail <= unsent) {
> >>>> + spin_unlock_irqrestore(&priv->tx_lock, flags);
> >>>> + break;
> >>>> + }
> >>>> + spin_unlock_irqrestore(&priv->tx_lock, flags);
> >>>> +
> >>>> + } while (1);
> >>>> +
> >>>> + /* Clear interrupt */
> >>>> + rcar_canfd_write(priv, RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX),
> >>>> + sts & ~RCANFD_CMFIFO_CFTXIF);
> >>>> + can_led_event(ndev, CAN_LED_EVENT_TX); }
> >>>> +
> >>>> + if (cf->can_id & CAN_RTR_FLAG)
> >>>> + id |= RCANFD_CMFIFO_CFRTR;
> >>>> +
> >>>> + rcar_canfd_write(priv, RCANFD_F_CFID(ch, RCANFD_CFFIFO_IDX),
> >>>> + id);
> >>>> + ptr = RCANFD_CMFIFO_CFDLC(can_len2dlc(cf->len));
> >>>
> >>> ptr usually means pointer, better call it dlc.
> >>
> >> I used the register name "ptr". OK, will change it do dlc.
> >>
> >>>
> >>>> + rcar_canfd_write(priv, RCANFD_F_CFPTR(ch, RCANFD_CFFIFO_IDX),
> >>>> + ptr);
> >>>> +
> >> (...)
> >>>> + can_put_echo_skb(skb, ndev, priv->tx_head %
> RCANFD_FIFO_DEPTH);
> >>>> +
> >>>> + spin_lock_irqsave(&priv->tx_lock, flags);
> >>>> + priv->tx_head++;
> >>>> +
> >>>> + /* Start Tx: Write 0xff to CFPC to increment the CPU-side
> >>>> + * pointer for the Common FIFO
> >>>> + */
> >>>> + rcar_canfd_write(priv, RCANFD_CFPCTR(ch, RCANFD_CFFIFO_IDX),
> >>>> +0xff);
> >>>> +
> >>>> + /* Stop the queue if we've filled all FIFO entries */
> >>>> + if (priv->tx_head - priv->tx_tail >= RCANFD_FIFO_DEPTH)
> >>>> + netif_stop_queue(ndev);
> >>>
> >>> Please move the check of stop_queue, before starting the send.
> >>
> >> OK.
> >>
> >>>
> >>>> +
> >>>> + spin_unlock_irqrestore(&priv->tx_lock, flags);
> >>>> + return NETDEV_TX_OK;
> >>>> +}
> >>>> +
> >> (...)
> >>>> +{
> >>>> + struct rcar_canfd_channel *priv =
> >>>> + container_of(napi, struct rcar_canfd_channel, napi);
> >>>> + int num_pkts;
> >>>> + u32 sts;
> >>>> + u32 ch = priv->channel;
> >>>> + u32 ridx = ch + RCANFD_RFFIFO_IDX;
> >>>> +
> >>>> + for (num_pkts = 0; num_pkts < quota; num_pkts++) {
> >>>> + sts = rcar_canfd_read(priv, RCANFD_RFSTS(ridx));
> >>>> + /* Clear interrupt bit */
> >>>> + if (sts & RCANFD_RFFIFO_RFIF)
> >>>> + rcar_canfd_write(priv, RCANFD_RFSTS(ridx),
> >>>> + sts & ~RCANFD_RFFIFO_RFIF);
> >>>> +
> >>>> + /* Check FIFO empty condition */
> >>>> + if (sts & RCANFD_RFFIFO_RFEMP)
> >>>> + break;
> >>>> +
> >>>> + rcar_canfd_rx_pkt(priv);
> >>>
> >>> This sequence looks strange. You first conditionally ack the
> >>> interrupt then you check for empty fifo, then read the CAN frame. I
> >>> would assume that you first check if there's a CAN frame, read it
> >>> and then clear the interrupt.
> >>
> >> Yes, I shall re-arrange the sequence as you mentioned.
> >>
> >>>
> >>>> + }
> >>>> +
> >>>> + /* All packets processed */
> >>>> + if (num_pkts < quota) {
> >>>> + napi_complete(napi);
> >>>> + /* Enable Rx FIFO interrupts */
> >>>> + rcar_canfd_set_bit(priv, RCANFD_RFCC(ridx),
> >>> RCANFD_RFFIFO_RFIE);
> >> (...)
> >>>> + for_each_set_bit(ch, &gpriv->channels_mask,
> RCANFD_NUM_CHANNELS) {
> >>>> + err = rcar_canfd_channel_probe(gpriv, ch);
> >>>> + if (err)
> >>>> + goto fail_channel;
> >>>> + }
> >>>
> >>> Should the CAN IP core be clocked the whole time? What about shuting
> >>> down the clock and enabling it on ifup?
> >>
> >> The fCAN clock is enabled only on ifup of one of the channels.
> >> However, the peripheral clock is enabled during probe to bring the
> >> controller to Global Operational mode. This clock cannot be turned
> >> off with the register values & mode retained.
> >>
> >>>> +
> >>>> + platform_set_drvdata(pdev, gpriv);
> >>>> + dev_info(&pdev->dev, "global operational state (clk %d)\n",
> >>>> + gpriv->clock_select);
> >> (...)
> >>>> + rcar_canfd_reset_controller(gpriv);
> >>>> + rcar_canfd_disable_global_interrupts(gpriv);
> >>>> +
> >>>> + for_each_set_bit(ch, &gpriv->channels_mask,
> RCANFD_NUM_CHANNELS) {
> >>>> + priv = gpriv->ch[ch];
> >>>> + if (priv) {
> >>>
> >>> This should always be true.
> >>
> >> I agree. I thought I cleaned this up but it's in my local commits :-(
> >>
> >>>
> >>>> + rcar_canfd_disable_channel_interrupts(priv);
> >>>> + unregister_candev(priv->ndev);
> >>>> + netif_napi_del(&priv->napi);
> >>>> + free_candev(priv->ndev);
> >>>
> >>> Please make use of rcar_canfd_channel_remove(), as you already have
> >>> the function.
> >>
> >> Yes.
> >>
> >> Thanks,
> >> Ramesh