diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-03-18 13:19:10 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-04-01 05:54:59 -0400 |
commit | 07c7b6f6161be52b8ab6bca70ed6a7140708c94e (patch) | |
tree | 66410feb92de31d004ec2dfbf3cf69d307145cb0 /drivers/net/can/c_can | |
parent | 64f08f2f3544eb8b6b14fd35e6087d7d3ede77cd (diff) |
can: c_can: Fix the lost message handling
The lost message handling is broken in several ways.
1) Clearing the message lost flag is done by writing 0 to the
message control register of the object.
#define IF_MCONT_CLR_MSGLST (0 << 14)
That clears the object buffer configuration in the worst case,
which results in a loss of the EOB flag. That leaves the FIFO chain
without a limit and causes a complete lockup of the HW
2) In case that the error skb allocation fails, the code happily
claims that it handed down a packet. Just an accounting bug, but ....
3) The code adds a lot of pointless overhead to that error case, where
we need to get stuff done as fast as possible to avoid more packet
loss.
- printk an annoying error message
- reread the object buffer for nothing
Fix is simple again:
- Use the already known MSGCTRL content and only clear the MSGLST bit
- Fix the buffer accounting by adding a proper return code
- Remove the pointless operations
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can/c_can')
-rw-r--r-- | drivers/net/can/c_can/c_can.c | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index cef9967eff93..ef5f3b8099f4 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c | |||
@@ -122,7 +122,6 @@ | |||
122 | /* IFx message control */ | 122 | /* IFx message control */ |
123 | #define IF_MCONT_NEWDAT BIT(15) | 123 | #define IF_MCONT_NEWDAT BIT(15) |
124 | #define IF_MCONT_MSGLST BIT(14) | 124 | #define IF_MCONT_MSGLST BIT(14) |
125 | #define IF_MCONT_CLR_MSGLST (0 << 14) | ||
126 | #define IF_MCONT_INTPND BIT(13) | 125 | #define IF_MCONT_INTPND BIT(13) |
127 | #define IF_MCONT_UMASK BIT(12) | 126 | #define IF_MCONT_UMASK BIT(12) |
128 | #define IF_MCONT_TXIE BIT(11) | 127 | #define IF_MCONT_TXIE BIT(11) |
@@ -411,27 +410,22 @@ static inline void c_can_activate_rx_msg_obj(struct net_device *dev, | |||
411 | c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); | 410 | c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); |
412 | } | 411 | } |
413 | 412 | ||
414 | static void c_can_handle_lost_msg_obj(struct net_device *dev, | 413 | static int c_can_handle_lost_msg_obj(struct net_device *dev, |
415 | int iface, int objno) | 414 | int iface, int objno, u32 ctrl) |
416 | { | 415 | { |
417 | struct c_can_priv *priv = netdev_priv(dev); | ||
418 | struct net_device_stats *stats = &dev->stats; | 416 | struct net_device_stats *stats = &dev->stats; |
419 | struct sk_buff *skb; | 417 | struct c_can_priv *priv = netdev_priv(dev); |
420 | struct can_frame *frame; | 418 | struct can_frame *frame; |
419 | struct sk_buff *skb; | ||
421 | 420 | ||
422 | netdev_err(dev, "msg lost in buffer %d\n", objno); | 421 | ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT); |
423 | 422 | priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); | |
424 | c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); | ||
425 | |||
426 | priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), | ||
427 | IF_MCONT_CLR_MSGLST); | ||
428 | |||
429 | c_can_object_put(dev, iface, objno, IF_COMM_CONTROL); | 423 | c_can_object_put(dev, iface, objno, IF_COMM_CONTROL); |
430 | 424 | ||
431 | /* create an error msg */ | 425 | /* create an error msg */ |
432 | skb = alloc_can_err_skb(dev, &frame); | 426 | skb = alloc_can_err_skb(dev, &frame); |
433 | if (unlikely(!skb)) | 427 | if (unlikely(!skb)) |
434 | return; | 428 | return 0; |
435 | 429 | ||
436 | frame->can_id |= CAN_ERR_CRTL; | 430 | frame->can_id |= CAN_ERR_CRTL; |
437 | frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | 431 | frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; |
@@ -439,6 +433,7 @@ static void c_can_handle_lost_msg_obj(struct net_device *dev, | |||
439 | stats->rx_over_errors++; | 433 | stats->rx_over_errors++; |
440 | 434 | ||
441 | netif_receive_skb(skb); | 435 | netif_receive_skb(skb); |
436 | return 1; | ||
442 | } | 437 | } |
443 | 438 | ||
444 | static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) | 439 | static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) |
@@ -910,9 +905,13 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota) | |||
910 | C_CAN_IFACE(MSGCTRL_REG, IF_RX)); | 905 | C_CAN_IFACE(MSGCTRL_REG, IF_RX)); |
911 | 906 | ||
912 | if (msg_ctrl_save & IF_MCONT_MSGLST) { | 907 | if (msg_ctrl_save & IF_MCONT_MSGLST) { |
913 | c_can_handle_lost_msg_obj(dev, IF_RX, msg_obj); | 908 | int n; |
914 | num_rx_pkts++; | 909 | |
915 | quota--; | 910 | n = c_can_handle_lost_msg_obj(dev, IF_RX, |
911 | msg_obj, | ||
912 | msg_ctrl_save); | ||
913 | num_rx_pkts += n; | ||
914 | quota -=n; | ||
916 | continue; | 915 | continue; |
917 | } | 916 | } |
918 | 917 | ||