Skip to content

Commit 6e5c172

Browse files
Oliver Hartkoppdavem330
authored andcommitted
can: update can-bcm for hrtimer hardirq callbacks
Since commit ca10949 ("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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 858eb71 commit 6e5c172

File tree

1 file changed

+125
-83
lines changed

1 file changed

+125
-83
lines changed

net/can/bcm.c

Lines changed: 125 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070

7171
#define CAN_BCM_VERSION CAN_VERSION
7272
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";
7474

7575
MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
7676
MODULE_LICENSE("Dual BSD/GPL");
@@ -90,6 +90,7 @@ struct bcm_op {
9090
unsigned long frames_abs, frames_filtered;
9191
struct timeval ival1, ival2;
9292
struct hrtimer timer, thrtimer;
93+
struct tasklet_struct tsklet, thrtsklet;
9394
ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
9495
int rx_ifindex;
9596
int count;
@@ -341,6 +342,23 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
341342
}
342343
}
343344

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+
344362
/*
345363
* bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
346364
*/
@@ -352,20 +370,8 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
352370
if (op->kt_ival1.tv64 && (op->count > 0)) {
353371

354372
op->count--;
355-
if (!op->count && (op->flags & TX_COUNTEVT)) {
356-
struct bcm_msg_head msg_head;
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-
}
373+
if (!op->count && (op->flags & TX_COUNTEVT))
374+
tasklet_schedule(&op->tsklet);
369375
}
370376

371377
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)
402408
if (op->frames_filtered > ULONG_MAX/100)
403409
op->frames_filtered = op->frames_abs = 0;
404410

411+
/* this element is not throttled anymore */
412+
data->can_dlc &= (BCM_CAN_DLC_MASK|RX_RECV);
413+
405414
head.opcode = RX_CHANGED;
406415
head.flags = op->flags;
407416
head.count = op->count;
@@ -420,45 +429,41 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
420429
*/
421430
static void bcm_rx_update_and_send(struct bcm_op *op,
422431
struct can_frame *lastdata,
423-
struct can_frame *rxdata)
432+
const struct can_frame *rxdata)
424433
{
425434
memcpy(lastdata, rxdata, CFSIZ);
426435

427-
/* mark as used */
428-
lastdata->can_dlc |= RX_RECV;
436+
/* mark as used and throttled by default */
437+
lastdata->can_dlc |= (RX_RECV|RX_THR);
429438

430-
/* throtteling mode inactive OR data update already on the run ? */
431-
if (!op->kt_ival2.tv64 || hrtimer_callback_running(&op->thrtimer)) {
439+
/* throtteling mode inactive ? */
440+
if (!op->kt_ival2.tv64) {
432441
/* send RX_CHANGED to the user immediately */
433-
bcm_rx_changed(op, rxdata);
442+
bcm_rx_changed(op, lastdata);
434443
return;
435444
}
436445

437-
if (hrtimer_active(&op->thrtimer)) {
438-
/* mark as 'throttled' */
439-
lastdata->can_dlc |= RX_THR;
446+
/* with active throttling timer we are just done here */
447+
if (hrtimer_active(&op->thrtimer))
440448
return;
441-
}
442449

443-
if (!op->kt_lastmsg.tv64) {
444-
/* send first RX_CHANGED to the user immediately */
445-
bcm_rx_changed(op, rxdata);
446-
op->kt_lastmsg = ktime_get();
447-
return;
448-
}
450+
/* first receiption with enabled throttling mode */
451+
if (!op->kt_lastmsg.tv64)
452+
goto rx_changed_settime;
449453

454+
/* got a second frame inside a potential throttle period? */
450455
if (ktime_us_delta(ktime_get(), op->kt_lastmsg) <
451456
ktime_to_us(op->kt_ival2)) {
452-
/* mark as 'throttled' and start timer */
453-
lastdata->can_dlc |= RX_THR;
457+
/* do not send the saved data - only start throttle timer */
454458
hrtimer_start(&op->thrtimer,
455459
ktime_add(op->kt_lastmsg, op->kt_ival2),
456460
HRTIMER_MODE_ABS);
457461
return;
458462
}
459463

460464
/* 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);
462467
op->kt_lastmsg = ktime_get();
463468
}
464469

@@ -467,7 +472,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
467472
* received data stored in op->last_frames[]
468473
*/
469474
static void bcm_rx_cmp_to_index(struct bcm_op *op, int index,
470-
struct can_frame *rxdata)
475+
const struct can_frame *rxdata)
471476
{
472477
/*
473478
* no one uses the MSBs of can_dlc for comparation,
@@ -511,14 +516,12 @@ static void bcm_rx_starttimer(struct bcm_op *op)
511516
hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
512517
}
513518

514-
/*
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)
519+
static void bcm_rx_timeout_tsklet(unsigned long data)
518520
{
519-
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
521+
struct bcm_op *op = (struct bcm_op *)data;
520522
struct bcm_msg_head msg_head;
521523

524+
/* create notification to user */
522525
msg_head.opcode = RX_TIMEOUT;
523526
msg_head.flags = op->flags;
524527
msg_head.count = op->count;
@@ -528,6 +531,17 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
528531
msg_head.nframes = 0;
529532

530533
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);
531545

532546
/* no restart of the timer is done here! */
533547

@@ -540,38 +554,52 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
540554
return HRTIMER_NORESTART;
541555
}
542556

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+
543570
/*
544571
* 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)
545575
*/
546-
static int bcm_rx_thr_flush(struct bcm_op *op)
576+
static int bcm_rx_thr_flush(struct bcm_op *op, int update)
547577
{
548578
int updated = 0;
549579

550580
if (op->nframes > 1) {
551581
int i;
552582

553583
/* for MUX filter we start at index 1 */
554-
for (i = 1; i < op->nframes; i++) {
555-
if ((op->last_frames) &&
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-
}
584+
for (i = 1; i < op->nframes; i++)
585+
updated += bcm_rx_do_flush(op, update, i);
562586

563587
} else {
564588
/* for RX_FILTER_ID and simple filter */
565-
if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)) {
566-
op->last_frames[0].can_dlc &= ~RX_THR;
567-
bcm_rx_changed(op, &op->last_frames[0]);
568-
updated++;
569-
}
589+
updated += bcm_rx_do_flush(op, update, 0);
570590
}
571591

572592
return updated;
573593
}
574594

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+
575603
/*
576604
* bcm_rx_thr_handler - the time for blocked content updates is over now:
577605
* 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)
580608
{
581609
struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
582610

583-
if (bcm_rx_thr_flush(op)) {
611+
tasklet_schedule(&op->thrtsklet);
612+
613+
if (bcm_rx_thr_flush(op, 0)) {
584614
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
585615
return HRTIMER_RESTART;
586616
} else {
@@ -596,48 +626,38 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
596626
static void bcm_rx_handler(struct sk_buff *skb, void *data)
597627
{
598628
struct bcm_op *op = (struct bcm_op *)data;
599-
struct can_frame rxframe;
629+
const struct can_frame *rxframe = (struct can_frame *)skb->data;
600630
int i;
601631

602632
/* disable timeout */
603633
hrtimer_cancel(&op->timer);
604634

605-
if (skb->len == sizeof(rxframe)) {
606-
memcpy(&rxframe, skb->data, sizeof(rxframe));
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);
635+
if (op->can_id != rxframe->can_id)
636+
goto rx_freeskb;
614637

615-
} else {
616-
kfree_skb(skb);
617-
return;
618-
}
619-
620-
if (op->can_id != rxframe.can_id)
621-
return;
638+
/* save rx timestamp */
639+
op->rx_stamp = skb->tstamp;
640+
/* save originator for recvfrom() */
641+
op->rx_ifindex = skb->dev->ifindex;
642+
/* update statistics */
643+
op->frames_abs++;
622644

623645
if (op->flags & RX_RTR_FRAME) {
624646
/* send reply for RTR-request (placed in op->frames[0]) */
625647
bcm_can_tx(op);
626-
return;
648+
goto rx_freeskb;
627649
}
628650

629651
if (op->flags & RX_FILTER_ID) {
630652
/* the easiest case */
631-
bcm_rx_update_and_send(op, &op->last_frames[0], &rxframe);
632-
bcm_rx_starttimer(op);
633-
return;
653+
bcm_rx_update_and_send(op, &op->last_frames[0], rxframe);
654+
goto rx_freeskb_starttimer;
634655
}
635656

636657
if (op->nframes == 1) {
637658
/* simple compare with index 0 */
638-
bcm_rx_cmp_to_index(op, 0, &rxframe);
639-
bcm_rx_starttimer(op);
640-
return;
659+
bcm_rx_cmp_to_index(op, 0, rxframe);
660+
goto rx_freeskb_starttimer;
641661
}
642662

643663
if (op->nframes > 1) {
@@ -649,15 +669,19 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
649669
*/
650670

651671
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)) ==
653673
(GET_U64(&op->frames[0]) &
654674
GET_U64(&op->frames[i]))) {
655-
bcm_rx_cmp_to_index(op, i, &rxframe);
675+
bcm_rx_cmp_to_index(op, i, rxframe);
656676
break;
657677
}
658678
}
659-
bcm_rx_starttimer(op);
660679
}
680+
681+
rx_freeskb_starttimer:
682+
bcm_rx_starttimer(op);
683+
rx_freeskb:
684+
kfree_skb(skb);
661685
}
662686

663687
/*
@@ -681,6 +705,12 @@ static void bcm_remove_op(struct bcm_op *op)
681705
hrtimer_cancel(&op->timer);
682706
hrtimer_cancel(&op->thrtimer);
683707

708+
if (op->tsklet.func)
709+
tasklet_kill(&op->tsklet);
710+
711+
if (op->thrtsklet.func)
712+
tasklet_kill(&op->thrtsklet);
713+
684714
if ((op->frames) && (op->frames != &op->sframe))
685715
kfree(op->frames);
686716

@@ -891,6 +921,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
891921
hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
892922
op->timer.function = bcm_tx_timeout_handler;
893923

924+
/* initialize tasklet for tx countevent notification */
925+
tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
926+
(unsigned long) op);
927+
894928
/* currently unused in tx_ops */
895929
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
896930

@@ -1054,9 +1088,17 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
10541088
hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
10551089
op->timer.function = bcm_rx_timeout_handler;
10561090

1091+
/* initialize tasklet for rx timeout notification */
1092+
tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
1093+
(unsigned long) op);
1094+
10571095
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
10581096
op->thrtimer.function = bcm_rx_thr_handler;
10591097

1098+
/* initialize tasklet for rx throttle handling */
1099+
tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
1100+
(unsigned long) op);
1101+
10601102
/* add this bcm_op to the list of the rx_ops */
10611103
list_add(&op->list, &bo->rx_ops);
10621104

@@ -1102,7 +1144,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11021144
*/
11031145
op->kt_lastmsg = ktime_set(0, 0);
11041146
hrtimer_cancel(&op->thrtimer);
1105-
bcm_rx_thr_flush(op);
1147+
bcm_rx_thr_flush(op, 1);
11061148
}
11071149

11081150
if ((op->flags & STARTTIMER) && op->kt_ival1.tv64)

0 commit comments

Comments
 (0)