diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2019-08-12 08:57:14 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2019-08-13 11:32:20 -0400 |
commit | bf74aa86e111aa3b2fbb25db37e3a3fab71b5b68 (patch) | |
tree | 435e301cd5df88ec612cf73ed7063c29ad541b94 /net/can | |
parent | 9989f6333c58e5068abf65384b05de3847b07ce1 (diff) |
can: bcm: switch timer to HRTIMER_MODE_SOFT and remove hrtimer_tasklet
This patch switches the timer to HRTIMER_MODE_SOFT, which executed the
timer callback in softirq context and removes the hrtimer_tasklet.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/bcm.c | 156 |
1 files changed, 52 insertions, 104 deletions
diff --git a/net/can/bcm.c b/net/can/bcm.c index eb1d28b8c46a..28fd1a1c8487 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c | |||
@@ -106,7 +106,6 @@ struct bcm_op { | |||
106 | unsigned long frames_abs, frames_filtered; | 106 | unsigned long frames_abs, frames_filtered; |
107 | struct bcm_timeval ival1, ival2; | 107 | struct bcm_timeval ival1, ival2; |
108 | struct hrtimer timer, thrtimer; | 108 | struct hrtimer timer, thrtimer; |
109 | struct tasklet_struct tsklet, thrtsklet; | ||
110 | ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; | 109 | ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; |
111 | int rx_ifindex; | 110 | int rx_ifindex; |
112 | int cfsiz; | 111 | int cfsiz; |
@@ -371,25 +370,34 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, | |||
371 | } | 370 | } |
372 | } | 371 | } |
373 | 372 | ||
374 | static void bcm_tx_start_timer(struct bcm_op *op) | 373 | static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt) |
375 | { | 374 | { |
375 | ktime_t ival; | ||
376 | |||
376 | if (op->kt_ival1 && op->count) | 377 | if (op->kt_ival1 && op->count) |
377 | hrtimer_start(&op->timer, | 378 | ival = op->kt_ival1; |
378 | ktime_add(ktime_get(), op->kt_ival1), | ||
379 | HRTIMER_MODE_ABS); | ||
380 | else if (op->kt_ival2) | 379 | else if (op->kt_ival2) |
381 | hrtimer_start(&op->timer, | 380 | ival = op->kt_ival2; |
382 | ktime_add(ktime_get(), op->kt_ival2), | 381 | else |
383 | HRTIMER_MODE_ABS); | 382 | return false; |
383 | |||
384 | hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival)); | ||
385 | return true; | ||
384 | } | 386 | } |
385 | 387 | ||
386 | static void bcm_tx_timeout_tsklet(unsigned long data) | 388 | static void bcm_tx_start_timer(struct bcm_op *op) |
387 | { | 389 | { |
388 | struct bcm_op *op = (struct bcm_op *)data; | 390 | if (bcm_tx_set_expiry(op, &op->timer)) |
391 | hrtimer_start_expires(&op->timer, HRTIMER_MODE_ABS_SOFT); | ||
392 | } | ||
393 | |||
394 | /* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions */ | ||
395 | static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) | ||
396 | { | ||
397 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); | ||
389 | struct bcm_msg_head msg_head; | 398 | struct bcm_msg_head msg_head; |
390 | 399 | ||
391 | if (op->kt_ival1 && (op->count > 0)) { | 400 | if (op->kt_ival1 && (op->count > 0)) { |
392 | |||
393 | op->count--; | 401 | op->count--; |
394 | if (!op->count && (op->flags & TX_COUNTEVT)) { | 402 | if (!op->count && (op->flags & TX_COUNTEVT)) { |
395 | 403 | ||
@@ -406,22 +414,12 @@ static void bcm_tx_timeout_tsklet(unsigned long data) | |||
406 | } | 414 | } |
407 | bcm_can_tx(op); | 415 | bcm_can_tx(op); |
408 | 416 | ||
409 | } else if (op->kt_ival2) | 417 | } else if (op->kt_ival2) { |
410 | bcm_can_tx(op); | 418 | bcm_can_tx(op); |
419 | } | ||
411 | 420 | ||
412 | bcm_tx_start_timer(op); | 421 | return bcm_tx_set_expiry(op, &op->timer) ? |
413 | } | 422 | HRTIMER_RESTART : HRTIMER_NORESTART; |
414 | |||
415 | /* | ||
416 | * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions | ||
417 | */ | ||
418 | static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) | ||
419 | { | ||
420 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); | ||
421 | |||
422 | tasklet_schedule(&op->tsklet); | ||
423 | |||
424 | return HRTIMER_NORESTART; | ||
425 | } | 423 | } |
426 | 424 | ||
427 | /* | 425 | /* |
@@ -487,7 +485,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op, | |||
487 | /* do not send the saved data - only start throttle timer */ | 485 | /* do not send the saved data - only start throttle timer */ |
488 | hrtimer_start(&op->thrtimer, | 486 | hrtimer_start(&op->thrtimer, |
489 | ktime_add(op->kt_lastmsg, op->kt_ival2), | 487 | ktime_add(op->kt_lastmsg, op->kt_ival2), |
490 | HRTIMER_MODE_ABS); | 488 | HRTIMER_MODE_ABS_SOFT); |
491 | return; | 489 | return; |
492 | } | 490 | } |
493 | 491 | ||
@@ -546,14 +544,21 @@ static void bcm_rx_starttimer(struct bcm_op *op) | |||
546 | return; | 544 | return; |
547 | 545 | ||
548 | if (op->kt_ival1) | 546 | if (op->kt_ival1) |
549 | hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL); | 547 | hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL_SOFT); |
550 | } | 548 | } |
551 | 549 | ||
552 | static void bcm_rx_timeout_tsklet(unsigned long data) | 550 | /* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out */ |
551 | static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) | ||
553 | { | 552 | { |
554 | struct bcm_op *op = (struct bcm_op *)data; | 553 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); |
555 | struct bcm_msg_head msg_head; | 554 | struct bcm_msg_head msg_head; |
556 | 555 | ||
556 | /* if user wants to be informed, when cyclic CAN-Messages come back */ | ||
557 | if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { | ||
558 | /* clear received CAN frames to indicate 'nothing received' */ | ||
559 | memset(op->last_frames, 0, op->nframes * op->cfsiz); | ||
560 | } | ||
561 | |||
557 | /* create notification to user */ | 562 | /* create notification to user */ |
558 | msg_head.opcode = RX_TIMEOUT; | 563 | msg_head.opcode = RX_TIMEOUT; |
559 | msg_head.flags = op->flags; | 564 | msg_head.flags = op->flags; |
@@ -564,25 +569,6 @@ static void bcm_rx_timeout_tsklet(unsigned long data) | |||
564 | msg_head.nframes = 0; | 569 | msg_head.nframes = 0; |
565 | 570 | ||
566 | bcm_send_to_user(op, &msg_head, NULL, 0); | 571 | bcm_send_to_user(op, &msg_head, NULL, 0); |
567 | } | ||
568 | |||
569 | /* | ||
570 | * bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out | ||
571 | */ | ||
572 | static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) | ||
573 | { | ||
574 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); | ||
575 | |||
576 | /* schedule before NET_RX_SOFTIRQ */ | ||
577 | tasklet_hi_schedule(&op->tsklet); | ||
578 | |||
579 | /* no restart of the timer is done here! */ | ||
580 | |||
581 | /* if user wants to be informed, when cyclic CAN-Messages come back */ | ||
582 | if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) { | ||
583 | /* clear received CAN frames to indicate 'nothing received' */ | ||
584 | memset(op->last_frames, 0, op->nframes * op->cfsiz); | ||
585 | } | ||
586 | 572 | ||
587 | return HRTIMER_NORESTART; | 573 | return HRTIMER_NORESTART; |
588 | } | 574 | } |
@@ -590,14 +576,12 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) | |||
590 | /* | 576 | /* |
591 | * bcm_rx_do_flush - helper for bcm_rx_thr_flush | 577 | * bcm_rx_do_flush - helper for bcm_rx_thr_flush |
592 | */ | 578 | */ |
593 | static inline int bcm_rx_do_flush(struct bcm_op *op, int update, | 579 | static inline int bcm_rx_do_flush(struct bcm_op *op, unsigned int index) |
594 | unsigned int index) | ||
595 | { | 580 | { |
596 | struct canfd_frame *lcf = op->last_frames + op->cfsiz * index; | 581 | struct canfd_frame *lcf = op->last_frames + op->cfsiz * index; |
597 | 582 | ||
598 | if ((op->last_frames) && (lcf->flags & RX_THR)) { | 583 | if ((op->last_frames) && (lcf->flags & RX_THR)) { |
599 | if (update) | 584 | bcm_rx_changed(op, lcf); |
600 | bcm_rx_changed(op, lcf); | ||
601 | return 1; | 585 | return 1; |
602 | } | 586 | } |
603 | return 0; | 587 | return 0; |
@@ -605,11 +589,8 @@ static inline int bcm_rx_do_flush(struct bcm_op *op, int update, | |||
605 | 589 | ||
606 | /* | 590 | /* |
607 | * bcm_rx_thr_flush - Check for throttled data and send it to the userspace | 591 | * bcm_rx_thr_flush - Check for throttled data and send it to the userspace |
608 | * | ||
609 | * update == 0 : just check if throttled data is available (any irq context) | ||
610 | * update == 1 : check and send throttled data to userspace (soft_irq context) | ||
611 | */ | 592 | */ |
612 | static int bcm_rx_thr_flush(struct bcm_op *op, int update) | 593 | static int bcm_rx_thr_flush(struct bcm_op *op) |
613 | { | 594 | { |
614 | int updated = 0; | 595 | int updated = 0; |
615 | 596 | ||
@@ -618,24 +599,16 @@ static int bcm_rx_thr_flush(struct bcm_op *op, int update) | |||
618 | 599 | ||
619 | /* for MUX filter we start at index 1 */ | 600 | /* for MUX filter we start at index 1 */ |
620 | for (i = 1; i < op->nframes; i++) | 601 | for (i = 1; i < op->nframes; i++) |
621 | updated += bcm_rx_do_flush(op, update, i); | 602 | updated += bcm_rx_do_flush(op, i); |
622 | 603 | ||
623 | } else { | 604 | } else { |
624 | /* for RX_FILTER_ID and simple filter */ | 605 | /* for RX_FILTER_ID and simple filter */ |
625 | updated += bcm_rx_do_flush(op, update, 0); | 606 | updated += bcm_rx_do_flush(op, 0); |
626 | } | 607 | } |
627 | 608 | ||
628 | return updated; | 609 | return updated; |
629 | } | 610 | } |
630 | 611 | ||
631 | static void bcm_rx_thr_tsklet(unsigned long data) | ||
632 | { | ||
633 | struct bcm_op *op = (struct bcm_op *)data; | ||
634 | |||
635 | /* push the changed data to the userspace */ | ||
636 | bcm_rx_thr_flush(op, 1); | ||
637 | } | ||
638 | |||
639 | /* | 612 | /* |
640 | * bcm_rx_thr_handler - the time for blocked content updates is over now: | 613 | * bcm_rx_thr_handler - the time for blocked content updates is over now: |
641 | * Check for throttled data and send it to the userspace | 614 | * Check for throttled data and send it to the userspace |
@@ -644,9 +617,7 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer) | |||
644 | { | 617 | { |
645 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); | 618 | struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); |
646 | 619 | ||
647 | tasklet_schedule(&op->thrtsklet); | 620 | if (bcm_rx_thr_flush(op)) { |
648 | |||
649 | if (bcm_rx_thr_flush(op, 0)) { | ||
650 | hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); | 621 | hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); |
651 | return HRTIMER_RESTART; | 622 | return HRTIMER_RESTART; |
652 | } else { | 623 | } else { |
@@ -742,23 +713,8 @@ static struct bcm_op *bcm_find_op(struct list_head *ops, | |||
742 | 713 | ||
743 | static void bcm_remove_op(struct bcm_op *op) | 714 | static void bcm_remove_op(struct bcm_op *op) |
744 | { | 715 | { |
745 | if (op->tsklet.func) { | 716 | hrtimer_cancel(&op->timer); |
746 | while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) || | 717 | hrtimer_cancel(&op->thrtimer); |
747 | test_bit(TASKLET_STATE_RUN, &op->tsklet.state) || | ||
748 | hrtimer_active(&op->timer)) { | ||
749 | hrtimer_cancel(&op->timer); | ||
750 | tasklet_kill(&op->tsklet); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | if (op->thrtsklet.func) { | ||
755 | while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) || | ||
756 | test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) || | ||
757 | hrtimer_active(&op->thrtimer)) { | ||
758 | hrtimer_cancel(&op->thrtimer); | ||
759 | tasklet_kill(&op->thrtsklet); | ||
760 | } | ||
761 | } | ||
762 | 718 | ||
763 | if ((op->frames) && (op->frames != &op->sframe)) | 719 | if ((op->frames) && (op->frames != &op->sframe)) |
764 | kfree(op->frames); | 720 | kfree(op->frames); |
@@ -991,15 +947,13 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
991 | op->ifindex = ifindex; | 947 | op->ifindex = ifindex; |
992 | 948 | ||
993 | /* initialize uninitialized (kzalloc) structure */ | 949 | /* initialize uninitialized (kzalloc) structure */ |
994 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 950 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, |
951 | HRTIMER_MODE_REL_SOFT); | ||
995 | op->timer.function = bcm_tx_timeout_handler; | 952 | op->timer.function = bcm_tx_timeout_handler; |
996 | 953 | ||
997 | /* initialize tasklet for tx countevent notification */ | ||
998 | tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet, | ||
999 | (unsigned long) op); | ||
1000 | |||
1001 | /* currently unused in tx_ops */ | 954 | /* currently unused in tx_ops */ |
1002 | hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 955 | hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, |
956 | HRTIMER_MODE_REL_SOFT); | ||
1003 | 957 | ||
1004 | /* add this bcm_op to the list of the tx_ops */ | 958 | /* add this bcm_op to the list of the tx_ops */ |
1005 | list_add(&op->list, &bo->tx_ops); | 959 | list_add(&op->list, &bo->tx_ops); |
@@ -1168,20 +1122,14 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
1168 | op->rx_ifindex = ifindex; | 1122 | op->rx_ifindex = ifindex; |
1169 | 1123 | ||
1170 | /* initialize uninitialized (kzalloc) structure */ | 1124 | /* initialize uninitialized (kzalloc) structure */ |
1171 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 1125 | hrtimer_init(&op->timer, CLOCK_MONOTONIC, |
1126 | HRTIMER_MODE_REL_SOFT); | ||
1172 | op->timer.function = bcm_rx_timeout_handler; | 1127 | op->timer.function = bcm_rx_timeout_handler; |
1173 | 1128 | ||
1174 | /* initialize tasklet for rx timeout notification */ | 1129 | hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, |
1175 | tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet, | 1130 | HRTIMER_MODE_REL_SOFT); |
1176 | (unsigned long) op); | ||
1177 | |||
1178 | hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
1179 | op->thrtimer.function = bcm_rx_thr_handler; | 1131 | op->thrtimer.function = bcm_rx_thr_handler; |
1180 | 1132 | ||
1181 | /* initialize tasklet for rx throttle handling */ | ||
1182 | tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet, | ||
1183 | (unsigned long) op); | ||
1184 | |||
1185 | /* add this bcm_op to the list of the rx_ops */ | 1133 | /* add this bcm_op to the list of the rx_ops */ |
1186 | list_add(&op->list, &bo->rx_ops); | 1134 | list_add(&op->list, &bo->rx_ops); |
1187 | 1135 | ||
@@ -1227,12 +1175,12 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
1227 | */ | 1175 | */ |
1228 | op->kt_lastmsg = 0; | 1176 | op->kt_lastmsg = 0; |
1229 | hrtimer_cancel(&op->thrtimer); | 1177 | hrtimer_cancel(&op->thrtimer); |
1230 | bcm_rx_thr_flush(op, 1); | 1178 | bcm_rx_thr_flush(op); |
1231 | } | 1179 | } |
1232 | 1180 | ||
1233 | if ((op->flags & STARTTIMER) && op->kt_ival1) | 1181 | if ((op->flags & STARTTIMER) && op->kt_ival1) |
1234 | hrtimer_start(&op->timer, op->kt_ival1, | 1182 | hrtimer_start(&op->timer, op->kt_ival1, |
1235 | HRTIMER_MODE_REL); | 1183 | HRTIMER_MODE_REL_SOFT); |
1236 | } | 1184 | } |
1237 | 1185 | ||
1238 | /* now we can register for can_ids, if we added a new bcm_op */ | 1186 | /* now we can register for can_ids, if we added a new bcm_op */ |