Commit c53a6ee8 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by David S. Miller

can: fix slowpath issue in hrtimer callback function

Due to the loopback functionality in can_send() we can not invoke it
from hardirq context which was done inside the
bcm_tx_timeout_handler() hrtimer callback:

[  700.361154]  [<c012228c>] warn_slowpath+0x80/0xb6
[  700.361163]  [<c013d559>] valid_state+0x125/0x136
[  700.361171]  [<c013d858>] mark_lock+0x18e/0x332
[  700.361180]  [<c013e300>] __lock_acquire+0x12e/0xb1e
[  700.361189]  [<f8ab5915>] bcm_tx_timeout_handler+0x0/0xbc [can_bcm]
[  700.361198]  [<c031e20a>] dev_queue_xmit+0x191/0x479
[  700.361206]  [<c01262a7>] __local_bh_disable+0x2b/0x64
[  700.361213]  [<c031e20a>] dev_queue_xmit+0x191/0x479
[  700.361225]  [<f8aa69a1>] can_send+0xd7/0x11a [can]
[  700.361235]  [<f8ab522b>] bcm_can_tx+0x9d/0xd9 [can_bcm]
[  700.361245]  [<f8ab597f>] bcm_tx_timeout_handler+0x6a/0xbc [can_bcm]
[  700.361255]  [<f8ab5915>] bcm_tx_timeout_handler+0x0/0xbc [can_bcm]
[  700.361263]  [<c0134143>] __run_hrtimer+0x5a/0x86
[  700.361273]  [<f8ab5915>] bcm_tx_timeout_handler+0x0/0xbc [can_bcm]
[  700.361282]  [<c0134a50>] hrtimer_interrupt+0xb9/0x110

This patch moves the rest of the functionality from the hrtimer
callback to the already existing tasklet to fix this slowpath problem.
Signed-off-by: default avatarOliver Hartkopp <oliver@hartkopp.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d57bc36e
...@@ -347,51 +347,54 @@ static void bcm_tx_timeout_tsklet(unsigned long data) ...@@ -347,51 +347,54 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
struct bcm_op *op = (struct bcm_op *)data; struct bcm_op *op = (struct bcm_op *)data;
struct bcm_msg_head msg_head; struct bcm_msg_head msg_head;
/* create notification to user */
msg_head.opcode = TX_EXPIRED;
msg_head.flags = op->flags;
msg_head.count = op->count;
msg_head.ival1 = op->ival1;
msg_head.ival2 = op->ival2;
msg_head.can_id = op->can_id;
msg_head.nframes = 0;
bcm_send_to_user(op, &msg_head, NULL, 0);
}
/*
* bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
*/
static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
enum hrtimer_restart ret = HRTIMER_NORESTART;
if (op->kt_ival1.tv64 && (op->count > 0)) { if (op->kt_ival1.tv64 && (op->count > 0)) {
op->count--; op->count--;
if (!op->count && (op->flags & TX_COUNTEVT)) if (!op->count && (op->flags & TX_COUNTEVT)) {
tasklet_schedule(&op->tsklet);
/* create notification to user */
msg_head.opcode = TX_EXPIRED;
msg_head.flags = op->flags;
msg_head.count = op->count;
msg_head.ival1 = op->ival1;
msg_head.ival2 = op->ival2;
msg_head.can_id = op->can_id;
msg_head.nframes = 0;
bcm_send_to_user(op, &msg_head, NULL, 0);
}
} }
if (op->kt_ival1.tv64 && (op->count > 0)) { if (op->kt_ival1.tv64 && (op->count > 0)) {
/* send (next) frame */ /* send (next) frame */
bcm_can_tx(op); bcm_can_tx(op);
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival1); hrtimer_start(&op->timer,
ret = HRTIMER_RESTART; ktime_add(ktime_get(), op->kt_ival1),
HRTIMER_MODE_ABS);
} else { } else {
if (op->kt_ival2.tv64) { if (op->kt_ival2.tv64) {
/* send (next) frame */ /* send (next) frame */
bcm_can_tx(op); bcm_can_tx(op);
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); hrtimer_start(&op->timer,
ret = HRTIMER_RESTART; ktime_add(ktime_get(), op->kt_ival2),
HRTIMER_MODE_ABS);
} }
} }
}
return ret; /*
* bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
*/
static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
tasklet_schedule(&op->tsklet);
return HRTIMER_NORESTART;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment