aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndri Yngvason <andri.yngvason@marel.com>2014-12-03 12:54:13 -0500
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-12-07 15:22:09 -0500
commitbac78aabcfece0c493b2ad824c68fbdc20448cbc (patch)
tree01465ed5ab04a32590aa36b13aef94a2a7bafd25
parent04ee0865d11f3f2a395e004a181ccfd2b258d088 (diff)
can: dev: Consolidate and unify state change handling
The handling of can error states is different between platforms. This is an attempt to correct that problem. I've moved this handling into a generic function for changing the error state. This ensures that error state changes are handled the same way everywhere (where this function is used). This new mechanism also adds reverse state transitioning in error frames, i.e. the user will be notified through the socket interface when the state goes down. Signed-off-by: Andri Yngvason <andri.yngvason@marel.com> Acked-by: Wolfgang Grandegger <wg@grandegger.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/dev.c78
-rw-r--r--include/linux/can/dev.h3
-rw-r--r--include/uapi/linux/can/error.h1
3 files changed, 82 insertions, 0 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 2cfe5012e4e5..3ec8f6f25e5f 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -273,6 +273,84 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
273 return err; 273 return err;
274} 274}
275 275
276static void can_update_state_error_stats(struct net_device *dev,
277 enum can_state new_state)
278{
279 struct can_priv *priv = netdev_priv(dev);
280
281 if (new_state <= priv->state)
282 return;
283
284 switch (new_state) {
285 case CAN_STATE_ERROR_WARNING:
286 priv->can_stats.error_warning++;
287 break;
288 case CAN_STATE_ERROR_PASSIVE:
289 priv->can_stats.error_passive++;
290 break;
291 case CAN_STATE_BUS_OFF:
292 default:
293 break;
294 };
295}
296
297static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
298{
299 switch (state) {
300 case CAN_STATE_ERROR_ACTIVE:
301 return CAN_ERR_CRTL_ACTIVE;
302 case CAN_STATE_ERROR_WARNING:
303 return CAN_ERR_CRTL_TX_WARNING;
304 case CAN_STATE_ERROR_PASSIVE:
305 return CAN_ERR_CRTL_TX_PASSIVE;
306 default:
307 return 0;
308 }
309}
310
311static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
312{
313 switch (state) {
314 case CAN_STATE_ERROR_ACTIVE:
315 return CAN_ERR_CRTL_ACTIVE;
316 case CAN_STATE_ERROR_WARNING:
317 return CAN_ERR_CRTL_RX_WARNING;
318 case CAN_STATE_ERROR_PASSIVE:
319 return CAN_ERR_CRTL_RX_PASSIVE;
320 default:
321 return 0;
322 }
323}
324
325void can_change_state(struct net_device *dev, struct can_frame *cf,
326 enum can_state tx_state, enum can_state rx_state)
327{
328 struct can_priv *priv = netdev_priv(dev);
329 enum can_state new_state = max(tx_state, rx_state);
330
331 if (unlikely(new_state == priv->state)) {
332 netdev_warn(dev, "%s: oops, state did not change", __func__);
333 return;
334 }
335
336 netdev_dbg(dev, "New error state: %d\n", new_state);
337
338 can_update_state_error_stats(dev, new_state);
339 priv->state = new_state;
340
341 if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
342 cf->can_id |= CAN_ERR_BUSOFF;
343 return;
344 }
345
346 cf->can_id |= CAN_ERR_CRTL;
347 cf->data[1] |= tx_state >= rx_state ?
348 can_tx_state_to_frame(dev, tx_state) : 0;
349 cf->data[1] |= tx_state <= rx_state ?
350 can_rx_state_to_frame(dev, rx_state) : 0;
351}
352EXPORT_SYMBOL_GPL(can_change_state);
353
276/* 354/*
277 * Local echo of CAN messages 355 * Local echo of CAN messages
278 * 356 *
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index b37ea95bc348..c05ff0f9f9a5 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -127,6 +127,9 @@ void unregister_candev(struct net_device *dev);
127int can_restart_now(struct net_device *dev); 127int can_restart_now(struct net_device *dev);
128void can_bus_off(struct net_device *dev); 128void can_bus_off(struct net_device *dev);
129 129
130void can_change_state(struct net_device *dev, struct can_frame *cf,
131 enum can_state tx_state, enum can_state rx_state);
132
130void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, 133void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
131 unsigned int idx); 134 unsigned int idx);
132unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx); 135unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
diff --git a/include/uapi/linux/can/error.h b/include/uapi/linux/can/error.h
index c247446ab25a..1c508be9687f 100644
--- a/include/uapi/linux/can/error.h
+++ b/include/uapi/linux/can/error.h
@@ -71,6 +71,7 @@
71#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ 71#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */
72 /* (at least one error counter exceeds */ 72 /* (at least one error counter exceeds */
73 /* the protocol-defined level of 127) */ 73 /* the protocol-defined level of 127) */
74#define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */
74 75
75/* error in CAN protocol (type) / data[2] */ 76/* error in CAN protocol (type) / data[2] */
76#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ 77#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */