From patchwork Wed Jun 22 12:31:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ramesh Shanmugasundaram X-Patchwork-Id: 9192685 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5EFA960890 for ; Wed, 22 Jun 2016 12:41:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4DB9028364 for ; Wed, 22 Jun 2016 12:41:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 42433283FE; Wed, 22 Jun 2016 12:41:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C5992283E9 for ; Wed, 22 Jun 2016 12:41:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752445AbcFVMlM (ORCPT ); Wed, 22 Jun 2016 08:41:12 -0400 Received: from relmlor2.renesas.com ([210.160.252.172]:24940 "EHLO relmlie1.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752722AbcFVMiu (ORCPT ); Wed, 22 Jun 2016 08:38:50 -0400 Received: from unknown (HELO relmlir4.idc.renesas.com) ([10.200.68.154]) by relmlie1.idc.renesas.com with ESMTP; 22 Jun 2016 21:38:34 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir4.idc.renesas.com (Postfix) with ESMTP id 77CFD509D8; Wed, 22 Jun 2016 21:38:34 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 65AC82806E; Wed, 22 Jun 2016 21:38:34 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 5C7972806D; Wed, 22 Jun 2016 21:38:34 +0900 (JST) Received: from relmlii2.idc.renesas.com [10.200.68.66] by relmlac2.idc.renesas.com with ESMTP id XAL06105; Wed, 22 Jun 2016 21:38:34 +0900 X-IronPort-AV: E=Sophos;i="5.22,559,1449500400"; d="scan'208";a="214003786" Received: from unknown (HELO localhost.localdomain) ([172.29.43.62]) by relmlii2.idc.renesas.com with ESMTP; 22 Jun 2016 21:38:30 +0900 From: Ramesh Shanmugasundaram To: mkl@pengutronix.de, wg@grandegger.com, robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk, galak@codeaurora.org Cc: ulrich.hecht+renesas@gmail.com, horms@verge.net.au, linux-renesas-soc@vger.kernel.org, devicetree@vger.kernel.org, linux-can@vger.kernel.org, linux-arm-kernel@lists.infradead.org, chris.paterson2@renesas.com, magnus.damm@gmail.com, socketcan@hartkopp.net, Ramesh Shanmugasundaram Subject: [PATCH v2 2/2] can: rcar_canfd: Add back-to-error-active support Date: Wed, 22 Jun 2016 13:31:47 +0100 Message-Id: <1466598707-44076-3-git-send-email-ramesh.shanmugasundaram@bp.renesas.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1466598707-44076-1-git-send-email-ramesh.shanmugasundaram@bp.renesas.com> References: <1466434007-50873-1-git-send-email-ramesh.shanmugasundaram@bp.renesas.com> <1466598707-44076-1-git-send-email-ramesh.shanmugasundaram@bp.renesas.com> Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP As per Wolfgang G, all new drivers should support decreasing state transition(back-to-error-active). This patch adds this support. This driver configures the controller to halt on bus-off entry. Hence, when in error states less than bus off state, the TEC/REC counters are checked for lower state transition eligibility and action. Signed-off-by: Ramesh Shanmugasundaram --- drivers/net/can/rcar/rcar_canfd.c | 76 ++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 6bcc474..43cdd55 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -917,16 +917,17 @@ static void rcar_canfd_global_error(struct net_device *ndev) rcar_canfd_write(priv->base, RCANFD_GERFL, 0); } -static void rcar_canfd_error(struct net_device *ndev) +static void rcar_canfd_error(struct net_device *ndev, u32 cerfl, + u16 txerr, u16 rxerr) { struct rcar_canfd_channel *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; - u32 cerfl, csts; - u32 txerr = 0, rxerr = 0; u32 ch = priv->channel; + netdev_dbg(ndev, "ch erfl %x txerr %u rxerr %u\n", cerfl, txerr, rxerr); + /* Propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(ndev, &cf); if (!skb) { @@ -934,15 +935,7 @@ static void rcar_canfd_error(struct net_device *ndev) return; } - /* Channel error interrupt */ - cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch)); - csts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch)); - txerr = RCANFD_CSTS_TECCNT(csts); - rxerr = RCANFD_CSTS_RECCNT(csts); - - netdev_dbg(ndev, "ch erfl %x sts %x txerr %u rxerr %u\n", - cerfl, csts, txerr, rxerr); - + /* Channel error interrupts */ if (cerfl & RCANFD_CERFL_BEF) { netdev_dbg(ndev, "Bus error\n"); cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; @@ -1032,8 +1025,9 @@ static void rcar_canfd_error(struct net_device *ndev) cf->data[2] |= CAN_ERR_PROT_OVERLOAD; } - /* Clear all channel error interrupts */ - rcar_canfd_write(priv->base, RCANFD_CERFL(ch), 0); + /* Clear channel error interrupts that are handled */ + rcar_canfd_write(priv->base, RCANFD_CERFL(ch), + RCANFD_CERFL_ERR(~cerfl)); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; netif_rx(skb); @@ -1098,12 +1092,12 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id) /* Global error interrupts */ gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL); - if (RCANFD_GERFL_ERR(gpriv, gerfl)) + if (unlikely(RCANFD_GERFL_ERR(gpriv, gerfl))) rcar_canfd_global_error(ndev); /* Handle Rx interrupts */ sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx)); - if (sts & RCANFD_RFSTS_RFIF) { + if (likely(sts & RCANFD_RFSTS_RFIF)) { if (napi_schedule_prep(&priv->napi)) { /* Disable Rx FIFO interrupts */ rcar_canfd_clear_bit(priv->base, @@ -1116,12 +1110,46 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void rcar_canfd_state_change(struct net_device *ndev, + u16 txerr, u16 rxerr) +{ + struct rcar_canfd_channel *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + enum can_state rx_state, tx_state, state = priv->can.state; + struct can_frame *cf; + struct sk_buff *skb; + + /* Handle transition from error to normal states */ + if (txerr < 96 && rxerr < 96) + state = CAN_STATE_ERROR_ACTIVE; + else if (txerr < 128 && rxerr < 128) + state = CAN_STATE_ERROR_WARNING; + + if (state != priv->can.state) { + netdev_dbg(ndev, "state: new %d, old %d: txerr %u, rxerr %u\n", + state, priv->can.state, txerr, rxerr); + skb = alloc_can_err_skb(ndev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + tx_state = txerr >= rxerr ? state : 0; + rx_state = txerr <= rxerr ? state : 0; + + can_change_state(ndev, cf, tx_state, rx_state); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } +} + static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) { struct rcar_canfd_global *gpriv = dev_id; struct net_device *ndev; struct rcar_canfd_channel *priv; - u32 sts, cerfl, ch; + u32 sts, ch, cerfl; + u16 txerr, rxerr; /* Common FIFO is a per channel resource */ for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) { @@ -1130,13 +1158,21 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) /* Channel error interrupts */ cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch)); - if (RCANFD_CERFL_ERR(cerfl)) - rcar_canfd_error(ndev); + sts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch)); + txerr = RCANFD_CSTS_TECCNT(sts); + rxerr = RCANFD_CSTS_RECCNT(sts); + if (unlikely(RCANFD_CERFL_ERR(cerfl))) + rcar_canfd_error(ndev, cerfl, txerr, rxerr); + + /* Handle state change to lower states */ + if (unlikely((priv->can.state != CAN_STATE_ERROR_ACTIVE) && + (priv->can.state != CAN_STATE_BUS_OFF))) + rcar_canfd_state_change(ndev, txerr, rxerr); /* Handle Tx interrupts */ sts = rcar_canfd_read(priv->base, RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX)); - if (sts & RCANFD_CFSTS_CFTXIF) + if (likely(sts & RCANFD_CFSTS_CFTXIF)) rcar_canfd_tx_done(ndev); } return IRQ_HANDLED;