Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: rcar_canfd: Add back-to-error-active support

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 <ramesh.shanmugasundaram@bp.renesas.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Ramesh Shanmugasundaram and committed by
Marc Kleine-Budde
926f1035 6f4c2eea

+56 -20
+56 -20
drivers/net/can/rcar/rcar_canfd.c
··· 917 917 rcar_canfd_write(priv->base, RCANFD_GERFL, 0); 918 918 } 919 919 920 - static void rcar_canfd_error(struct net_device *ndev) 920 + static void rcar_canfd_error(struct net_device *ndev, u32 cerfl, 921 + u16 txerr, u16 rxerr) 921 922 { 922 923 struct rcar_canfd_channel *priv = netdev_priv(ndev); 923 924 struct net_device_stats *stats = &ndev->stats; 924 925 struct can_frame *cf; 925 926 struct sk_buff *skb; 926 - u32 cerfl, csts; 927 - u32 txerr = 0, rxerr = 0; 928 927 u32 ch = priv->channel; 928 + 929 + netdev_dbg(ndev, "ch erfl %x txerr %u rxerr %u\n", cerfl, txerr, rxerr); 929 930 930 931 /* Propagate the error condition to the CAN stack */ 931 932 skb = alloc_can_err_skb(ndev, &cf); ··· 935 934 return; 936 935 } 937 936 938 - /* Channel error interrupt */ 939 - cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch)); 940 - csts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch)); 941 - txerr = RCANFD_CSTS_TECCNT(csts); 942 - rxerr = RCANFD_CSTS_RECCNT(csts); 943 - 944 - netdev_dbg(ndev, "ch erfl %x sts %x txerr %u rxerr %u\n", 945 - cerfl, csts, txerr, rxerr); 946 - 937 + /* Channel error interrupts */ 947 938 if (cerfl & RCANFD_CERFL_BEF) { 948 939 netdev_dbg(ndev, "Bus error\n"); 949 940 cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; ··· 1025 1032 cf->data[2] |= CAN_ERR_PROT_OVERLOAD; 1026 1033 } 1027 1034 1028 - /* Clear all channel error interrupts */ 1029 - rcar_canfd_write(priv->base, RCANFD_CERFL(ch), 0); 1035 + /* Clear channel error interrupts that are handled */ 1036 + rcar_canfd_write(priv->base, RCANFD_CERFL(ch), 1037 + RCANFD_CERFL_ERR(~cerfl)); 1030 1038 stats->rx_packets++; 1031 1039 stats->rx_bytes += cf->can_dlc; 1032 1040 netif_rx(skb); ··· 1092 1098 1093 1099 /* Global error interrupts */ 1094 1100 gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL); 1095 - if (RCANFD_GERFL_ERR(gpriv, gerfl)) 1101 + if (unlikely(RCANFD_GERFL_ERR(gpriv, gerfl))) 1096 1102 rcar_canfd_global_error(ndev); 1097 1103 1098 1104 /* Handle Rx interrupts */ 1099 1105 sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx)); 1100 - if (sts & RCANFD_RFSTS_RFIF) { 1106 + if (likely(sts & RCANFD_RFSTS_RFIF)) { 1101 1107 if (napi_schedule_prep(&priv->napi)) { 1102 1108 /* Disable Rx FIFO interrupts */ 1103 1109 rcar_canfd_clear_bit(priv->base, ··· 1110 1116 return IRQ_HANDLED; 1111 1117 } 1112 1118 1119 + static void rcar_canfd_state_change(struct net_device *ndev, 1120 + u16 txerr, u16 rxerr) 1121 + { 1122 + struct rcar_canfd_channel *priv = netdev_priv(ndev); 1123 + struct net_device_stats *stats = &ndev->stats; 1124 + enum can_state rx_state, tx_state, state = priv->can.state; 1125 + struct can_frame *cf; 1126 + struct sk_buff *skb; 1127 + 1128 + /* Handle transition from error to normal states */ 1129 + if (txerr < 96 && rxerr < 96) 1130 + state = CAN_STATE_ERROR_ACTIVE; 1131 + else if (txerr < 128 && rxerr < 128) 1132 + state = CAN_STATE_ERROR_WARNING; 1133 + 1134 + if (state != priv->can.state) { 1135 + netdev_dbg(ndev, "state: new %d, old %d: txerr %u, rxerr %u\n", 1136 + state, priv->can.state, txerr, rxerr); 1137 + skb = alloc_can_err_skb(ndev, &cf); 1138 + if (!skb) { 1139 + stats->rx_dropped++; 1140 + return; 1141 + } 1142 + tx_state = txerr >= rxerr ? state : 0; 1143 + rx_state = txerr <= rxerr ? state : 0; 1144 + 1145 + can_change_state(ndev, cf, tx_state, rx_state); 1146 + stats->rx_packets++; 1147 + stats->rx_bytes += cf->can_dlc; 1148 + netif_rx(skb); 1149 + } 1150 + } 1151 + 1113 1152 static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) 1114 1153 { 1115 1154 struct rcar_canfd_global *gpriv = dev_id; 1116 1155 struct net_device *ndev; 1117 1156 struct rcar_canfd_channel *priv; 1118 - u32 sts, cerfl, ch; 1157 + u32 sts, ch, cerfl; 1158 + u16 txerr, rxerr; 1119 1159 1120 1160 /* Common FIFO is a per channel resource */ 1121 1161 for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) { ··· 1158 1130 1159 1131 /* Channel error interrupts */ 1160 1132 cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch)); 1161 - if (RCANFD_CERFL_ERR(cerfl)) 1162 - rcar_canfd_error(ndev); 1133 + sts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch)); 1134 + txerr = RCANFD_CSTS_TECCNT(sts); 1135 + rxerr = RCANFD_CSTS_RECCNT(sts); 1136 + if (unlikely(RCANFD_CERFL_ERR(cerfl))) 1137 + rcar_canfd_error(ndev, cerfl, txerr, rxerr); 1138 + 1139 + /* Handle state change to lower states */ 1140 + if (unlikely((priv->can.state != CAN_STATE_ERROR_ACTIVE) && 1141 + (priv->can.state != CAN_STATE_BUS_OFF))) 1142 + rcar_canfd_state_change(ndev, txerr, rxerr); 1163 1143 1164 1144 /* Handle Tx interrupts */ 1165 1145 sts = rcar_canfd_read(priv->base, 1166 1146 RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX)); 1167 - if (sts & RCANFD_CFSTS_CFTXIF) 1147 + if (likely(sts & RCANFD_CFSTS_CFTXIF)) 1168 1148 rcar_canfd_tx_done(ndev); 1169 1149 } 1170 1150 return IRQ_HANDLED;