diff options
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/bcm.c | 208 |
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 |
72 | static __initdata const char banner[] = KERN_INFO | 72 | static __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 | ||
75 | MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); | 75 | MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); |
76 | MODULE_LICENSE("Dual BSD/GPL"); | 76 | MODULE_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 | ||
345 | static 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 | */ |
421 | static void bcm_rx_update_and_send(struct bcm_op *op, | 430 | static 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); | 465 | rx_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 | */ |
469 | static void bcm_rx_cmp_to_index(struct bcm_op *op, int index, | 474 | static 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 | /* | 519 | static void bcm_rx_timeout_tsklet(unsigned long data) |
515 | * bcm_rx_timeout_handler - when the (cyclic) CAN frame receiption timed out | ||
516 | */ | ||
517 | static 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 | */ | ||
539 | static 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 | */ | ||
560 | static 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 | */ |
546 | static int bcm_rx_thr_flush(struct bcm_op *op) | 576 | static 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 | ||
595 | static 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) | |||
596 | static void bcm_rx_handler(struct sk_buff *skb, void *data) | 626 | static 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 | |||
681 | rx_freeskb_starttimer: | ||
682 | bcm_rx_starttimer(op); | ||
683 | rx_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) |