aboutsummaryrefslogtreecommitdiffstats
path: root/net/can/bcm.c
diff options
context:
space:
mode:
authorOliver Hartkopp <oliver@hartkopp.net>2009-01-15 00:06:55 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-15 00:06:55 -0500
commitc53a6ee88b0a91bd012ef1b7988c0b93dae6f24d (patch)
tree29cd62321b70f58a72b20cbd30bb933b06525df7 /net/can/bcm.c
parentd57bc36e7aba9e3a00d154f5eff80ff596146fc4 (diff)
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: Oliver Hartkopp <oliver@hartkopp.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/can/bcm.c')
-rw-r--r--net/can/bcm.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 1649c8ab2c2f..b7c7d4651136 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -347,51 +347,54 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
347 struct bcm_op *op = (struct bcm_op *)data; 347 struct bcm_op *op = (struct bcm_op *)data;
348 struct bcm_msg_head msg_head; 348 struct bcm_msg_head msg_head;
349 349
350 /* create notification to user */
351 msg_head.opcode = TX_EXPIRED;
352 msg_head.flags = op->flags;
353 msg_head.count = op->count;
354 msg_head.ival1 = op->ival1;
355 msg_head.ival2 = op->ival2;
356 msg_head.can_id = op->can_id;
357 msg_head.nframes = 0;
358
359 bcm_send_to_user(op, &msg_head, NULL, 0);
360}
361
362/*
363 * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
364 */
365static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
366{
367 struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
368 enum hrtimer_restart ret = HRTIMER_NORESTART;
369
370 if (op->kt_ival1.tv64 && (op->count > 0)) { 350 if (op->kt_ival1.tv64 && (op->count > 0)) {
371 351
372 op->count--; 352 op->count--;
373 if (!op->count && (op->flags & TX_COUNTEVT)) 353 if (!op->count && (op->flags & TX_COUNTEVT)) {
374 tasklet_schedule(&op->tsklet); 354
355 /* create notification to user */
356 msg_head.opcode = TX_EXPIRED;
357 msg_head.flags = op->flags;
358 msg_head.count = op->count;
359 msg_head.ival1 = op->ival1;
360 msg_head.ival2 = op->ival2;
361 msg_head.can_id = op->can_id;
362 msg_head.nframes = 0;
363
364 bcm_send_to_user(op, &msg_head, NULL, 0);
365 }
375 } 366 }
376 367
377 if (op->kt_ival1.tv64 && (op->count > 0)) { 368 if (op->kt_ival1.tv64 && (op->count > 0)) {
378 369
379 /* send (next) frame */ 370 /* send (next) frame */
380 bcm_can_tx(op); 371 bcm_can_tx(op);
381 hrtimer_forward(hrtimer, ktime_get(), op->kt_ival1); 372 hrtimer_start(&op->timer,
382 ret = HRTIMER_RESTART; 373 ktime_add(ktime_get(), op->kt_ival1),
374 HRTIMER_MODE_ABS);
383 375
384 } else { 376 } else {
385 if (op->kt_ival2.tv64) { 377 if (op->kt_ival2.tv64) {
386 378
387 /* send (next) frame */ 379 /* send (next) frame */
388 bcm_can_tx(op); 380 bcm_can_tx(op);
389 hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); 381 hrtimer_start(&op->timer,
390 ret = HRTIMER_RESTART; 382 ktime_add(ktime_get(), op->kt_ival2),
383 HRTIMER_MODE_ABS);
391 } 384 }
392 } 385 }
386}
393 387
394 return ret; 388/*
389 * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
390 */
391static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
392{
393 struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
394
395 tasklet_schedule(&op->tsklet);
396
397 return HRTIMER_NORESTART;
395} 398}
396 399
397/* 400/*