This patch provides the core support to allow state changes going down including "back to error active".
For any state change the CAN_ERR_STATE_CHANGE bit will be set in the can_id. If the state gets worse, the CAN_ERR_CRTL bis is set as usual also for backward compatibility. If the state is back to error active, the data[1] field will be set to CAN_ERR_CRTL_ACTIVE. The state change management will be done by a common "can_change_state()" function doing all the necessary bit settings and counter increments. Signed-off-by: Wolfgang Grandegger <[email protected]> --- drivers/net/can/dev.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/can/dev.h | 11 +++++++ include/linux/can/error.h | 2 + 3 files changed, 82 insertions(+), 0 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 400d871..d8e4ebb 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -242,6 +242,75 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } +void can_change_state(struct net_device *dev, struct can_frame *cf, + enum can_state state, unsigned int err_dir) +{ + struct can_priv *priv = netdev_priv(dev); + + /* Function should only be called in case of real state changes */ + if (state == priv->state) { + netdev_warn(dev, "%s: oops, state did not change", __func__); + return; + } + + /* This message reports CAN error state changes */ + cf->can_id |= CAN_ERR_STATE_CHANGE; + /* If it get's worse, we set the controller problem bit */ + if (state > priv->state && state != CAN_STATE_BUS_OFF) + cf->can_id |= CAN_ERR_CRTL; + + switch (state) { + case CAN_STATE_ERROR_WARNING: + case CAN_STATE_ERROR_PASSIVE: + /* State change triggered by TX or RX errors? */ + if (err_dir == CAN_ERR_DIR_UNKNOWN && + priv->do_get_berr_counter) { + if (cf->data[6] > cf->data[7]) + err_dir = CAN_ERR_DIR_TX; + else if (cf->data[7] > cf->data[6]) + err_dir = CAN_ERR_DIR_RX; + } + + if (state == CAN_STATE_ERROR_WARNING) { + priv->can_stats.error_warning++; + if (err_dir == CAN_ERR_DIR_TX) + cf->data[1] = CAN_ERR_CRTL_TX_WARNING; + else if (err_dir == CAN_ERR_DIR_RX) + cf->data[1] = CAN_ERR_CRTL_RX_WARNING; + else + cf->data[1] = CAN_ERR_CRTL_TX_WARNING | + CAN_ERR_CRTL_RX_WARNING; + } else { + priv->can_stats.error_passive++; + if (err_dir == CAN_ERR_DIR_TX) + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE; + else if (err_dir == CAN_ERR_DIR_RX) + cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE; + else + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | + CAN_ERR_CRTL_RX_PASSIVE; + } + break; + + case CAN_STATE_ERROR_ACTIVE: + cf->data[1] = CAN_ERR_CRTL_ACTIVE; /* back to error active */ + break; + + case CAN_STATE_BUS_OFF: + priv->can_stats.bus_off++; + cf->can_id |= CAN_ERR_BUSOFF; + break; + + default: + break; + + } + + /* Finally set new state */ + priv->state = state; +} +EXPORT_SYMBOL_GPL(can_change_state); + /* * Local echo of CAN messages * diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index a0969fc..a50862f 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -27,6 +27,13 @@ enum can_mode { }; /* + * CAN error direction + */ +#define CAN_ERR_DIR_UNKNOWN 0x0 +#define CAN_ERR_DIR_RX 0x1 +#define CAN_ERR_DIR_TX 0x2 + +/* * CAN common private data */ struct can_priv { @@ -90,6 +97,9 @@ void unregister_candev(struct net_device *dev); int can_restart_now(struct net_device *dev); void can_bus_off(struct net_device *dev); +void can_change_state(struct net_device *dev, struct can_frame *cf, + enum can_state state, unsigned int err_dir); + void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, unsigned int idx); void can_get_echo_skb(struct net_device *dev, unsigned int idx); @@ -99,4 +109,5 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf); + #endif /* CAN_DEV_H */ diff --git a/include/linux/can/error.h b/include/linux/can/error.h index 63e855e..44c893c 100644 --- a/include/linux/can/error.h +++ b/include/linux/can/error.h @@ -24,6 +24,7 @@ #define CAN_ERR_BUSOFF 0x00000040U /* bus off */ #define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */ #define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */ +#define CAN_ERR_STATE_CHANGE 0x00000200U /* CAN error state change / data[1] */ /* arbitration lost in bit ... / data[0] */ #define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */ @@ -39,6 +40,7 @@ #define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ /* (at least one error counter exceeds */ /* the protocol-defined level of 127) */ +#define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */ /* error in CAN protocol (type) / data[2] */ #define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ -- 1.7.4.1 _______________________________________________ Socketcan-users mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-users
