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 | |
| 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>
| -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 | ||
