Allow state to decrease bus-off->passive->warning->active.
Use the common function can_chage_state().
Here is an example output of "candump -candump -td -e any,0:0,#FFFFFFFF"
for a recovery from error passive state due to no ack/cable (reconnect
after 5s) for a MSCAN on a MPC5200 SOC:
(000.204135) can2 6 [8] 25 84 EF 0F 3F 3D B7 3E
(000.206547) can2 20000204 [8] 00 08 00 00 00 00 00 00 ERRORFRAME
controller-problem{tx-error-warning}
state-change{tx-error-warning}
(000.000909) can2 20000204 [8] 00 20 00 00 00 00 00 00 ERRORFRAME
controller-problem{tx-error-passive}
state-change{tx-error-passive}
(004.928785) can2 7 [7] 4D BA 4C 90 60 BB D6
(000.000204) can2 20000200 [8] 00 08 00 00 00 00 00 00 ERRORFRAME
state-change{tx-error-warning}
(000.000000) can2 8 [1] 6F
(000.000239) can2 9 [8] 24 CD C3 9A 62 16 37 30
...
(000.204000) can2 33 [8] 58 DC 54 02 4D CF 61 BF
(000.000152) can2 20000200 [8] 00 40 00 00 00 00 00 00 ERRORFRAME
state-change{back-to-error-active}
(000.203725) can2 34 [0]
(000.204074) can2 35 [5] 71 E9 59 E5 2E
And for a MSCAN on a MPC5121 SOC:
(000.203997) can0 6 [8] 0F 21 AA BD 6C F5 2F 43
(000.206737) can0 20000204 [8] 00 08 00 00 00 00 60 00 ERRORFRAME
controller-problem{tx-error-warning}
state-change{tx-error-warning}
error-counter-tx-rx{{96}{0}}
(000.000962) can0 20000204 [8] 00 20 00 00 00 00 80 00 ERRORFRAME
controller-problem{tx-error-passive}
state-change{tx-error-passive}
error-counter-tx-rx{{128}{0}}
(004.929359) can0 7 [8] 64 7E BF 12 15 4A 22 E4
(000.000117) can0 20000200 [8] 00 08 00 00 00 00 7F 00 ERRORFRAME
state-change{tx-error-warning}
error-counter-tx-rx{{127}{0}}
(000.000163) can0 8 [1] 1C
...
(000.204030) can0 35 [8] 2D 8F 0E CA 26 4D 0D 37
(000.000123) can0 20000200 [8] 00 40 00 00 00 00 5F 00 ERRORFRAME
state-change{back-to-error-active}
error-counter-tx-rx{{95}{0}}
(000.203879) can0 36 [8] 6F C9 05 BA 73 9A A5 E2
Signed-off-by: Wolfgang Grandegger <[email protected]>
---
drivers/net/can/mscan/mscan.c | 89 ++++++++++++++++-------------------------
1 files changed, 34 insertions(+), 55 deletions(-)
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 41a2a2d..e9e6b14 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -290,20 +290,6 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb,
struct net_device *dev)
return NETDEV_TX_OK;
}
-/* This function returns the old state to see where we came from */
-static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
-{
- struct mscan_priv *priv = netdev_priv(dev);
- enum can_state state, old_state = priv->can.state;
-
- if (canrflg & MSCAN_CSCIF && old_state <= CAN_STATE_BUS_OFF) {
- state = state_map[max(MSCAN_STATE_RX(canrflg),
- MSCAN_STATE_TX(canrflg))];
- priv->can.state = state;
- }
- return old_state;
-}
-
static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
{
struct mscan_priv *priv = netdev_priv(dev);
@@ -350,60 +336,50 @@ static void mscan_get_err_frame(struct net_device *dev,
struct can_frame *frame,
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
- enum can_state old_state;
netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg);
- frame->can_id = CAN_ERR_FLAG;
if (canrflg & MSCAN_OVRIF) {
frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
stats->rx_errors++;
} else {
frame->data[1] = 0;
}
- old_state = check_set_state(dev, canrflg);
- /* State changed */
- if (old_state != priv->can.state) {
- switch (priv->can.state) {
- case CAN_STATE_ERROR_WARNING:
- frame->can_id |= CAN_ERR_CRTL;
- priv->can.can_stats.error_warning++;
- if ((priv->shadow_statflg & MSCAN_RSTAT_MSK) <
- (canrflg & MSCAN_RSTAT_MSK))
- frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
- if ((priv->shadow_statflg & MSCAN_TSTAT_MSK) <
+ if (canrflg & MSCAN_CSCIF) {
+ enum can_state state = state_map[max(MSCAN_STATE_RX(canrflg),
+ MSCAN_STATE_TX(canrflg))];
+ unsigned int err_dir = CAN_ERR_DIR_UNKNOWN;
+
+ if (state != priv->can.state) {
+
+ if ((priv->shadow_statflg & MSCAN_TSTAT_MSK) !=
(canrflg & MSCAN_TSTAT_MSK))
- frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
- break;
- case CAN_STATE_ERROR_PASSIVE:
- frame->can_id |= CAN_ERR_CRTL;
- priv->can.can_stats.error_passive++;
- frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
- break;
- case CAN_STATE_BUS_OFF:
- frame->can_id |= CAN_ERR_BUSOFF;
- /*
- * The MSCAN on the MPC5200 does recover from bus-off
- * automatically. To avoid that we stop the chip doing
- * a light-weight stop (we are in irq-context).
- */
- if (priv->type != MSCAN_TYPE_MPC5121) {
- out_8(®s->cantier, 0);
- out_8(®s->canrier, 0);
- setbits8(®s->canctl0,
- MSCAN_SLPRQ | MSCAN_INITRQ);
+ err_dir |= CAN_ERR_DIR_TX;
+ if ((priv->shadow_statflg & MSCAN_RSTAT_MSK) !=
+ (canrflg & MSCAN_RSTAT_MSK))
+ err_dir |= CAN_ERR_DIR_RX;
+ if (state == CAN_STATE_BUS_OFF) {
+ /*
+ * The MSCAN on the MPC5200 does recover from
+ * bus-off automatically. To avoid that we
+ * stop the chip doing a light-weight stop
+ * (we are in irq-context).
+ */
+ if (priv->type != MSCAN_TYPE_MPC5121) {
+ out_8(®s->cantier, 0);
+ out_8(®s->canrier, 0);
+ setbits8(®s->canctl0,
+ MSCAN_SLPRQ | MSCAN_INITRQ);
+ }
+ can_bus_off(dev);
}
- can_bus_off(dev);
- break;
- default:
- break;
+ can_change_state(dev, frame, state, err_dir);
}
+ priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
}
- priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
- frame->can_dlc = CAN_ERR_DLC;
out_8(®s->canrflg, MSCAN_ERR_IF);
}
@@ -424,7 +400,10 @@ static int mscan_rx_poll(struct napi_struct *napi, int
quota)
if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF)))
break;
- skb = alloc_can_skb(dev, &frame);
+ if (canrflg & MSCAN_RXF)
+ skb = alloc_can_skb(dev, &frame);
+ else /* MSCAN_ERR_IF */
+ skb = alloc_can_err_skb(dev, &frame);
if (!skb) {
if (printk_ratelimit())
netdev_notice(dev, "packet dropped\n");
@@ -435,7 +414,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int
quota)
if (canrflg & MSCAN_RXF)
mscan_get_rx_frame(dev, frame);
- else if (canrflg & MSCAN_ERR_IF)
+ else /* MSCAN_ERR_IF */
mscan_get_err_frame(dev, frame, canrflg);
stats->rx_packets++;
--
1.7.4.1
_______________________________________________
Socketcan-users mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-users