aboutsummaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <oliver@hartkopp.net>2009-01-04 20:31:18 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-04 20:31:18 -0500
commit6e5c172cf7ca1ab878cc6a6a4c1d52fef60f3ee0 (patch)
treed4b55754280eae3bbd6643eb9dd3f89b26137096 /net/can
parent858eb711ba64f8a001d7003295b8078bcab33b6d (diff)
can: update can-bcm for hrtimer hardirq callbacks
Since commit ca109491f612aab5c8152207631c0444f63da97f ("hrtimer: removing all ur callback modes") the hrtimer callbacks are processed only in hardirq context. This patch moves some functionality into tasklets to run in softirq context. Additionally some duplicated code was removed in bcm_rx_thr_flush() and an avoidable memcpy was removed from bcm_rx_handler(). Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/bcm.c208
1 files changed, 125 insertions, 83 deletions
diff --git a/net/can/bcm.c b/net/can/bcm.c
index da0d426c0ce4..6248ae2502c7 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -70,7 +70,7 @@
70 70
71#define CAN_BCM_VERSION CAN_VERSION 71#define CAN_BCM_VERSION CAN_VERSION
72static __initdata const char banner[] = KERN_INFO 72static __initdata const char banner[] = KERN_INFO
73 "can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n"; 73 "can: broadcast manager protocol (rev " CAN_BCM_VERSION " t)\n";
74 74
75MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); 75MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
76MODULE_LICENSE("Dual BSD/GPL"); 76MODULE_LICENSE("Dual BSD/GPL");
@@ -90,6 +90,7 @@ struct bcm_op {
90 unsigned long frames_abs, frames_filtered; 90 unsigned long frames_abs, frames_filtered;
91 struct timeval ival1, ival2; 91 struct timeval ival1, ival2;
92 struct hrtimer timer, thrtimer; 92 struct hrtimer timer, thrtimer;
93 struct tasklet_struct tsklet, thrtsklet;
93 ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; 94 ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
94 int rx_ifindex; 95 int rx_ifindex;
95 int count; 96 int count;
@@ -341,6 +342,23 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
341 } 342 }
342} 343}
343 344
345static void bcm_tx_timeout_tsklet(unsigned long data)
346{
347 struct bcm_op *op = (struct bcm_op *)data;
348 struct bcm_msg_head msg_head;
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
344/* 362/*
345 * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions 363 * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
346 */ 364 */
@@ -352,20 +370,8 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
352 if (op->kt_ival1.tv64 && (op->count > 0)) { 370 if (op->kt_ival1.tv64 && (op->count > 0)) {
353 371
354 op->count--; 372 op->count--;
355 if (!op->count && (op->flags & TX_COUNTEVT)) { 373 if (!op->count && (op->flags & TX_COUNTEVT))
356 struct bcm_msg_head msg_head; 374 tasklet_schedule(&op->tsklet);
357
358 /* create notification to user */
359 msg_head.opcode = TX_EXPIRED;
360 msg_head.flags = op->flags;
361 msg_head.count = op->count;
362 msg_head.ival1 = op->ival1;
363 msg_head.ival2 = op->ival2;
364 msg_head.can_id = op->can_id;
365 msg_head.nframes = 0;
366
367 bcm_send_to_user(op, &msg_head, NULL, 0);
368 }
369 } 375 }
370 376
371 if (op->kt_ival1.tv64 && (op->count > 0)) { 377 if (op->kt_ival1.tv64 && (op->count > 0)) {
@@ -402,6 +408,9 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
402 if (op->frames_filtered > ULONG_MAX/100) 408 if (op->frames_filtered > ULONG_MAX/100)
403 op->frames_filtered = op->frames_abs = 0; 409 op->frames_filtered = op->frames_abs = 0;
404 410
411 /* this element is not throttled anymore */
412 data->can_dlc &= (BCM_CAN_DLC_MASK|RX_RECV);
413
405 head.opcode = RX_CHANGED; 414 head.opcode = RX_CHANGED;
406 head.flags = op->flags; 415 head.flags = op->flags;
407 head.count = op->count; 416 head.count = op->count;
@@ -420,37 +429,32 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
420 */ 429 */
421static void bcm_rx_update_and_send(struct bcm_op *op, 430static void bcm_rx_update_and_send(struct bcm_op *op,
422 struct can_frame *lastdata, 431 struct can_frame *lastdata,
423 struct can_frame *rxdata) 432 const struct can_frame *rxdata)
424{ 433{
425 memcpy(lastdata, rxdata, CFSIZ); 434 memcpy(lastdata, rxdata, CFSIZ);
426 435
427 /* mark as used */ 436 /* mark as used and throttled by default */
428 lastdata->can_dlc |= RX_RECV; 437 lastdata->can_dlc |= (RX_RECV|RX_THR);
429 438
430 /* throtteling mode inactive OR data update already on the run ? */ 439 /* throtteling mode inactive ? */
431 if (!op->kt_ival2.tv64 || hrtimer_callback_running(&op->thrtimer)) { 440 if (!op->kt_ival2.tv64) {
432 /* send RX_CHANGED to the user immediately */ 441 /* send RX_CHANGED to the user immediately */
433 bcm_rx_changed(op, rxdata); 442 bcm_rx_changed(op, lastdata);
434 return; 443 return;
435 } 444 }
436 445
437 if (hrtimer_active(&op->thrtimer)) { 446 /* with active throttling timer we are just done here */
438 /* mark as 'throttled' */ 447 if (hrtimer_active(&op->thrtimer))
439 lastdata->can_dlc |= RX_THR;
440 return; 448 return;
441 }
442 449
443 if (!op->kt_lastmsg.tv64) { 450 /* first receiption with enabled throttling mode */
444 /* send first RX_CHANGED to the user immediately */ 451 if (!op->kt_lastmsg.tv64)
445 bcm_rx_changed(op, rxdata); 452 goto rx_changed_settime;
446 op->kt_lastmsg = ktime_get();
447 return;
448 }
449 453
454 /* got a second frame inside a potential throttle period? */
450 if (ktime_us_delta(ktime_get(), op->kt_lastmsg) < 455 if (ktime_us_delta(ktime_get(), op->kt_lastmsg) <
451 ktime_to_us(op->kt_ival2)) { 456 ktime_to_us(op->kt_ival2)) {
452 /* mark as 'throttled' and start timer */ 457 /* do not send the saved data - only start throttle timer */
453 lastdata->can_dlc |= RX_THR;
454 hrtimer_start(&op->thrtimer, 458 hrtimer_start(&op->thrtimer,
455 ktime_add(op->kt_lastmsg, op->kt_ival2), 459 ktime_add(op->kt_lastmsg, op->kt_ival2),
456 HRTIMER_MODE_ABS); 460 HRTIMER_MODE_ABS);
@@ -458,7 +462,8 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
458 } 462 }
459 463
460 /* the gap was that big, that throttling was not needed here */ 464 /* the gap was that big, that throttling was not needed here */
461 bcm_rx_changed(op, rxdata); 465rx_changed_settime:
466 bcm_rx_changed(op, lastdata);
462 op->kt_lastmsg = ktime_get(); 467 op->kt_lastmsg = ktime_get();
463} 468}
464 469
@@ -467,7 +472,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
467 * received data stored in op->last_frames[] 472 * received data stored in op->last_frames[]
468 */ 473 */
469static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, 474static void bcm_rx_cmp_to_index(struct bcm_op *op, int index,
470 struct can_frame *rxdata) 475 const struct can_frame *rxdata)
471{ 476{
472 /* 477 /*
473 * no one uses the MSBs of can_dlc for comparation, 478 * no one uses the MSBs of can_dlc for comparation,
@@ -511,14 +516,12 @@ static void bcm_rx_starttimer(struct bcm_op *op)
511 hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL); 516 hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
512} 517}
513 518
514/* 519static void bcm_rx_timeout_tsklet(unsigned long data)
515 * bcm_rx_timeout_handler - when the (cyclic) CAN frame receiption timed out
516 */
517static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
518{ 520{
519 struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); 521 struct bcm_op *op = (struct bcm_op *)data;
520 struct bcm_msg_head msg_head; 522 struct bcm_msg_head msg_head;
521 523
524 /* create notification to user */
522 msg_head.opcode = RX_TIMEOUT; 525 msg_head.opcode = RX_TIMEOUT;
523 msg_head.flags = op->flags; 526 msg_head.flags = op->flags;
524 msg_head.count = op->count; 527 msg_head.count = op->count;
@@ -528,6 +531,17 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
528 msg_head.nframes = 0; 531 msg_head.nframes = 0;
529 532
530 bcm_send_to_user(op, &msg_head, NULL, 0); 533 bcm_send_to_user(op, &msg_head, NULL, 0);
534}
535
536/*
537 * bcm_rx_timeout_handler - when the (cyclic) CAN frame receiption timed out
538 */
539static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
540{
541 struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
542
543 /* schedule before NET_RX_SOFTIRQ */
544 tasklet_hi_schedule(&op->tsklet);
531 545
532 /* no restart of the timer is done here! */ 546 /* no restart of the timer is done here! */
533 547
@@ -541,9 +555,25 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
541} 555}
542 556
543/* 557/*
558 * bcm_rx_do_flush - helper for bcm_rx_thr_flush
559 */
560static inline int bcm_rx_do_flush(struct bcm_op *op, int update, int index)
561{
562 if ((op->last_frames) && (op->last_frames[index].can_dlc & RX_THR)) {
563 if (update)
564 bcm_rx_changed(op, &op->last_frames[index]);
565 return 1;
566 }
567 return 0;
568}
569
570/*
544 * bcm_rx_thr_flush - Check for throttled data and send it to the userspace 571 * bcm_rx_thr_flush - Check for throttled data and send it to the userspace
572 *
573 * update == 0 : just check if throttled data is available (any irq context)
574 * update == 1 : check and send throttled data to userspace (soft_irq context)
545 */ 575 */
546static int bcm_rx_thr_flush(struct bcm_op *op) 576static int bcm_rx_thr_flush(struct bcm_op *op, int update)
547{ 577{
548 int updated = 0; 578 int updated = 0;
549 579
@@ -551,27 +581,25 @@ static int bcm_rx_thr_flush(struct bcm_op *op)
551 int i; 581 int i;
552 582
553 /* for MUX filter we start at index 1 */ 583 /* for MUX filter we start at index 1 */
554 for (i = 1; i < op->nframes; i++) { 584 for (i = 1; i < op->nframes; i++)
555 if ((op->last_frames) && 585 updated += bcm_rx_do_flush(op, update, i);
556 (op->last_frames[i].can_dlc & RX_THR)) {
557 op->last_frames[i].can_dlc &= ~RX_THR;
558 bcm_rx_changed(op, &op->last_frames[i]);
559 updated++;
560 }
561 }
562 586
563 } else { 587 } else {
564 /* for RX_FILTER_ID and simple filter */ 588 /* for RX_FILTER_ID and simple filter */
565 if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)) { 589 updated += bcm_rx_do_flush(op, update, 0);
566 op->last_frames[0].can_dlc &= ~RX_THR;
567 bcm_rx_changed(op, &op->last_frames[0]);
568 updated++;
569 }
570 } 590 }
571 591
572 return updated; 592 return updated;
573} 593}
574 594
595static void bcm_rx_thr_tsklet(unsigned long data)
596{
597 struct bcm_op *op = (struct bcm_op *)data;
598
599 /* push the changed data to the userspace */
600 bcm_rx_thr_flush(op, 1);
601}
602
575/* 603/*
576 * bcm_rx_thr_handler - the time for blocked content updates is over now: 604 * bcm_rx_thr_handler - the time for blocked content updates is over now:
577 * Check for throttled data and send it to the userspace 605 * Check for throttled data and send it to the userspace
@@ -580,7 +608,9 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
580{ 608{
581 struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); 609 struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
582 610
583 if (bcm_rx_thr_flush(op)) { 611 tasklet_schedule(&op->thrtsklet);
612
613 if (bcm_rx_thr_flush(op, 0)) {
584 hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); 614 hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
585 return HRTIMER_RESTART; 615 return HRTIMER_RESTART;
586 } else { 616 } else {
@@ -596,48 +626,38 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
596static void bcm_rx_handler(struct sk_buff *skb, void *data) 626static void bcm_rx_handler(struct sk_buff *skb, void *data)
597{ 627{
598 struct bcm_op *op = (struct bcm_op *)data; 628 struct bcm_op *op = (struct bcm_op *)data;
599 struct can_frame rxframe; 629 const struct can_frame *rxframe = (struct can_frame *)skb->data;
600 int i; 630 int i;
601 631
602 /* disable timeout */ 632 /* disable timeout */
603 hrtimer_cancel(&op->timer); 633 hrtimer_cancel(&op->timer);
604 634
605 if (skb->len == sizeof(rxframe)) { 635 if (op->can_id != rxframe->can_id)
606 memcpy(&rxframe, skb->data, sizeof(rxframe)); 636 goto rx_freeskb;
607 /* save rx timestamp */
608 op->rx_stamp = skb->tstamp;
609 /* save originator for recvfrom() */
610 op->rx_ifindex = skb->dev->ifindex;
611 /* update statistics */
612 op->frames_abs++;
613 kfree_skb(skb);
614 637
615 } else { 638 /* save rx timestamp */
616 kfree_skb(skb); 639 op->rx_stamp = skb->tstamp;
617 return; 640 /* save originator for recvfrom() */
618 } 641 op->rx_ifindex = skb->dev->ifindex;
619 642 /* update statistics */
620 if (op->can_id != rxframe.can_id) 643 op->frames_abs++;
621 return;
622 644
623 if (op->flags & RX_RTR_FRAME) { 645 if (op->flags & RX_RTR_FRAME) {
624 /* send reply for RTR-request (placed in op->frames[0]) */ 646 /* send reply for RTR-request (placed in op->frames[0]) */
625 bcm_can_tx(op); 647 bcm_can_tx(op);
626 return; 648 goto rx_freeskb;
627 } 649 }
628 650
629 if (op->flags & RX_FILTER_ID) { 651 if (op->flags & RX_FILTER_ID) {
630 /* the easiest case */ 652 /* the easiest case */
631 bcm_rx_update_and_send(op, &op->last_frames[0], &rxframe); 653 bcm_rx_update_and_send(op, &op->last_frames[0], rxframe);
632 bcm_rx_starttimer(op); 654 goto rx_freeskb_starttimer;
633 return;
634 } 655 }
635 656
636 if (op->nframes == 1) { 657 if (op->nframes == 1) {
637 /* simple compare with index 0 */ 658 /* simple compare with index 0 */
638 bcm_rx_cmp_to_index(op, 0, &rxframe); 659 bcm_rx_cmp_to_index(op, 0, rxframe);
639 bcm_rx_starttimer(op); 660 goto rx_freeskb_starttimer;
640 return;
641 } 661 }
642 662
643 if (op->nframes > 1) { 663 if (op->nframes > 1) {
@@ -649,15 +669,19 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
649 */ 669 */
650 670
651 for (i = 1; i < op->nframes; i++) { 671 for (i = 1; i < op->nframes; i++) {
652 if ((GET_U64(&op->frames[0]) & GET_U64(&rxframe)) == 672 if ((GET_U64(&op->frames[0]) & GET_U64(rxframe)) ==
653 (GET_U64(&op->frames[0]) & 673 (GET_U64(&op->frames[0]) &
654 GET_U64(&op->frames[i]))) { 674 GET_U64(&op->frames[i]))) {
655 bcm_rx_cmp_to_index(op, i, &rxframe); 675 bcm_rx_cmp_to_index(op, i, rxframe);
656 break; 676 break;
657 } 677 }
658 } 678 }
659 bcm_rx_starttimer(op);
660 } 679 }
680
681rx_freeskb_starttimer:
682 bcm_rx_starttimer(op);
683rx_freeskb:
684 kfree_skb(skb);
661} 685}
662 686
663/* 687/*
@@ -681,6 +705,12 @@ static void bcm_remove_op(struct bcm_op *op)
681 hrtimer_cancel(&op->timer); 705 hrtimer_cancel(&op->timer);
682 hrtimer_cancel(&op->thrtimer); 706 hrtimer_cancel(&op->thrtimer);
683 707
708 if (op->tsklet.func)
709 tasklet_kill(&op->tsklet);
710
711 if (op->thrtsklet.func)
712 tasklet_kill(&op->thrtsklet);
713
684 if ((op->frames) && (op->frames != &op->sframe)) 714 if ((op->frames) && (op->frames != &op->sframe))
685 kfree(op->frames); 715 kfree(op->frames);
686 716
@@ -891,6 +921,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
891 hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 921 hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
892 op->timer.function = bcm_tx_timeout_handler; 922 op->timer.function = bcm_tx_timeout_handler;
893 923
924 /* initialize tasklet for tx countevent notification */
925 tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
926 (unsigned long) op);
927
894 /* currently unused in tx_ops */ 928 /* currently unused in tx_ops */
895 hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 929 hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
896 930
@@ -1054,9 +1088,17 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
1054 hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 1088 hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1055 op->timer.function = bcm_rx_timeout_handler; 1089 op->timer.function = bcm_rx_timeout_handler;
1056 1090
1091 /* initialize tasklet for rx timeout notification */
1092 tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
1093 (unsigned long) op);
1094
1057 hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 1095 hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1058 op->thrtimer.function = bcm_rx_thr_handler; 1096 op->thrtimer.function = bcm_rx_thr_handler;
1059 1097
1098 /* initialize tasklet for rx throttle handling */
1099 tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
1100 (unsigned long) op);
1101
1060 /* add this bcm_op to the list of the rx_ops */ 1102 /* add this bcm_op to the list of the rx_ops */
1061 list_add(&op->list, &bo->rx_ops); 1103 list_add(&op->list, &bo->rx_ops);
1062 1104
@@ -1102,7 +1144,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
1102 */ 1144 */
1103 op->kt_lastmsg = ktime_set(0, 0); 1145 op->kt_lastmsg = ktime_set(0, 0);
1104 hrtimer_cancel(&op->thrtimer); 1146 hrtimer_cancel(&op->thrtimer);
1105 bcm_rx_thr_flush(op); 1147 bcm_rx_thr_flush(op, 1);
1106 } 1148 }
1107 1149
1108 if ((op->flags & STARTTIMER) && op->kt_ival1.tv64) 1150 if ((op->flags & STARTTIMER) && op->kt_ival1.tv64)