diff options
Diffstat (limited to 'litmus/litmus_softirq.c')
-rw-r--r-- | litmus/litmus_softirq.c | 158 |
1 files changed, 83 insertions, 75 deletions
diff --git a/litmus/litmus_softirq.c b/litmus/litmus_softirq.c index d1ea833dc8c4..dbefcb560063 100644 --- a/litmus/litmus_softirq.c +++ b/litmus/litmus_softirq.c | |||
@@ -1,27 +1,14 @@ | |||
1 | /* much copied shamelessly from Linux's softirq.c | 1 | /* much copied shamelessly from Linux's softirq.c |
2 | as well as PREEMPT_RT's softirq.c */ | 2 | as well as PREEMPT_RT's softirq.c */ |
3 | 3 | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/kernel_stat.h> | ||
6 | #include <linux/interrupt.h> | 4 | #include <linux/interrupt.h> |
7 | #include <linux/init.h> | ||
8 | #include <linux/mm.h> | ||
9 | #include <linux/notifier.h> | ||
10 | #include <linux/percpu.h> | 5 | #include <linux/percpu.h> |
11 | #include <linux/cpu.h> | 6 | #include <linux/cpu.h> |
12 | #include <linux/freezer.h> | ||
13 | #include <linux/kthread.h> | 7 | #include <linux/kthread.h> |
14 | #include <linux/rcupdate.h> | ||
15 | #include <linux/ftrace.h> | 8 | #include <linux/ftrace.h> |
16 | #include <linux/smp.h> | 9 | #include <linux/smp.h> |
17 | #include <linux/tick.h> | ||
18 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
19 | 11 | ||
20 | #define CREATE_TRACE_POINTS | ||
21 | #include <trace/events/irq.h> | ||
22 | |||
23 | #include <asm/irq.h> | ||
24 | |||
25 | #include <litmus/litmus.h> | 12 | #include <litmus/litmus.h> |
26 | #include <litmus/jobs.h> | 13 | #include <litmus/jobs.h> |
27 | #include <litmus/sched_plugin.h> | 14 | #include <litmus/sched_plugin.h> |
@@ -44,13 +31,12 @@ struct tasklet_head | |||
44 | struct tasklet_struct **tail; | 31 | struct tasklet_struct **tail; |
45 | }; | 32 | }; |
46 | 33 | ||
47 | // sys_sched_setscheduler(current->pid, SCHED_FIFO, ¶m); | ||
48 | // TODO: current->extra_flags |= PFE_SOFTIRQ; | ||
49 | |||
50 | struct klitirqd_info | 34 | struct klitirqd_info |
51 | { | 35 | { |
52 | struct task_struct* klitirqd; | 36 | struct task_struct* klitirqd; |
53 | raw_spinlock_t lock; | 37 | raw_spinlock_t lock; |
38 | |||
39 | u32 pending; | ||
54 | struct tasklet_head pending_tasklets; | 40 | struct tasklet_head pending_tasklets; |
55 | struct tasklet_head pending_tasklets_hi; | 41 | struct tasklet_head pending_tasklets_hi; |
56 | }; | 42 | }; |
@@ -79,41 +65,22 @@ inline unsigned int klitirqd_id(struct task_struct* tsk) | |||
79 | 65 | ||
80 | inline static u32 litirq_pending_hi_irqoff(struct klitirqd_info* which) | 66 | inline static u32 litirq_pending_hi_irqoff(struct klitirqd_info* which) |
81 | { | 67 | { |
82 | u32 pending = 0; | 68 | return (which->pending & LIT_TASKLET_HI); |
83 | |||
84 | if(which->pending_tasklets_hi.head != NULL) | ||
85 | { | ||
86 | pending = LIT_TASKLET_HI; | ||
87 | } | ||
88 | |||
89 | return pending; | ||
90 | }; | 69 | }; |
91 | 70 | ||
92 | inline static u32 litirq_pending_low_irqoff(struct klitirqd_info* which) | 71 | inline static u32 litirq_pending_low_irqoff(struct klitirqd_info* which) |
93 | { | 72 | { |
94 | u32 pending = 0; | 73 | return (which->pending & LIT_TASKLET_LOW); |
95 | |||
96 | if(which->pending_tasklets.head != NULL) | ||
97 | { | ||
98 | pending = LIT_TASKLET_LOW; | ||
99 | } | ||
100 | |||
101 | return pending; | ||
102 | }; | 74 | }; |
103 | 75 | ||
104 | 76 | ||
105 | static u32 litirq_pending_irqoff(struct klitirqd_info* which) | 77 | inline static u32 litirq_pending_irqoff(struct klitirqd_info* which) |
106 | { | 78 | { |
107 | u32 pending = 0; | 79 | return(which->pending); |
108 | |||
109 | pending |= litirq_pending_hi_irqoff(which); | ||
110 | pending |= litirq_pending_low_irqoff(which); | ||
111 | |||
112 | return pending; | ||
113 | }; | 80 | }; |
114 | 81 | ||
115 | 82 | ||
116 | static u32 litirq_pending(struct klitirqd_info* which) | 83 | inline static u32 litirq_pending(struct klitirqd_info* which) |
117 | { | 84 | { |
118 | unsigned long flags; | 85 | unsigned long flags; |
119 | u32 pending; | 86 | u32 pending; |
@@ -276,6 +243,13 @@ void trigger_litirqs(struct task_struct* tsk) | |||
276 | } | 243 | } |
277 | #endif | 244 | #endif |
278 | 245 | ||
246 | /* forward declarations */ | ||
247 | static void ___litmus_tasklet_schedule(struct tasklet_struct *t, | ||
248 | struct klitirqd_info *which, | ||
249 | int wakeup); | ||
250 | static void ___litmus_tasklet_hi_schedule(struct tasklet_struct *t, | ||
251 | struct klitirqd_info *which, | ||
252 | int wakeup); | ||
279 | 253 | ||
280 | static void do_lit_tasklet(struct klitirqd_info* which, | 254 | static void do_lit_tasklet(struct klitirqd_info* which, |
281 | struct tasklet_head* pending_tasklets) | 255 | struct tasklet_head* pending_tasklets) |
@@ -285,11 +259,14 @@ static void do_lit_tasklet(struct klitirqd_info* which, | |||
285 | 259 | ||
286 | raw_spin_lock_irqsave(&which->lock, flags); | 260 | raw_spin_lock_irqsave(&which->lock, flags); |
287 | 261 | ||
288 | /* copy out the tasklets for our private use. */ | 262 | /* copy out the tasklets for our private use. */ |
289 | list = pending_tasklets->head; | 263 | list = pending_tasklets->head; |
290 | pending_tasklets->head = NULL; | 264 | pending_tasklets->head = NULL; |
291 | pending_tasklets->tail = &pending_tasklets->head; | 265 | pending_tasklets->tail = &pending_tasklets->head; |
292 | 266 | which->pending &= (pending_tasklets == &which->pending_tasklets) ? | |
267 | ~LIT_TASKLET_LOW : | ||
268 | ~LIT_TASKLET_HI; | ||
269 | |||
293 | raw_spin_unlock_irqrestore(&which->lock, flags); | 270 | raw_spin_unlock_irqrestore(&which->lock, flags); |
294 | 271 | ||
295 | while(list) | 272 | while(list) |
@@ -314,17 +291,13 @@ static void do_lit_tasklet(struct klitirqd_info* which, | |||
314 | tasklet_unlock(t); | 291 | tasklet_unlock(t); |
315 | } | 292 | } |
316 | 293 | ||
317 | /* couldn't process tasklet. put it back at the end of the main queue. */ | ||
318 | TRACE_CUR("%s: Could not invoke tasklet. Requeuing.\n", __FUNCTION__); | 294 | TRACE_CUR("%s: Could not invoke tasklet. Requeuing.\n", __FUNCTION__); |
319 | 295 | ||
320 | t->next = NULL; | 296 | /* couldn't process tasklet. put it back at the end of the queue. */ |
321 | 297 | if(pending_tasklets == &which->pending_tasklets) | |
322 | raw_spin_lock_irqsave(&which->lock, flags); | 298 | ___litmus_tasklet_schedule(t, which, 0); |
323 | 299 | else | |
324 | *(pending_tasklets->tail) = t; | 300 | ___litmus_tasklet_hi_schedule(t, which, 0); |
325 | pending_tasklets->tail = &t->next; | ||
326 | |||
327 | raw_spin_unlock_irqrestore(&which->lock, flags); | ||
328 | } | 301 | } |
329 | } | 302 | } |
330 | 303 | ||
@@ -519,6 +492,8 @@ void spawn_klitirqd(void) | |||
519 | /* init the tasklet queues */ | 492 | /* init the tasklet queues */ |
520 | for(i = 0; i < NR_LITMUS_SOFTIRQD; ++i) | 493 | for(i = 0; i < NR_LITMUS_SOFTIRQD; ++i) |
521 | { | 494 | { |
495 | klitirqds[i].pending = 0; | ||
496 | |||
522 | klitirqds[i].pending_tasklets.head = NULL; | 497 | klitirqds[i].pending_tasklets.head = NULL; |
523 | klitirqds[i].pending_tasklets.tail = &klitirqds[i].pending_tasklets.head; | 498 | klitirqds[i].pending_tasklets.tail = &klitirqds[i].pending_tasklets.head; |
524 | 499 | ||
@@ -561,12 +536,38 @@ int klitirqd_is_ready(void) | |||
561 | return(atomic_read(&num_ready_klitirqds) == NR_LITMUS_SOFTIRQD); | 536 | return(atomic_read(&num_ready_klitirqds) == NR_LITMUS_SOFTIRQD); |
562 | } | 537 | } |
563 | 538 | ||
539 | int klitirqd_is_dead(void) | ||
540 | { | ||
541 | return(atomic_read(&num_ready_klitirqds) == 0); | ||
542 | } | ||
564 | 543 | ||
565 | 544 | ||
566 | void __litmus_tasklet_schedule(struct tasklet_struct *t, unsigned int k_id) | 545 | |
546 | static void ___litmus_tasklet_schedule(struct tasklet_struct *t, | ||
547 | struct klitirqd_info *which, | ||
548 | int wakeup) | ||
567 | { | 549 | { |
568 | unsigned long flags; | 550 | unsigned long flags; |
551 | |||
552 | t->next = NULL; | ||
553 | |||
554 | raw_spin_lock_irqsave(&which->lock, flags); | ||
569 | 555 | ||
556 | *(which->pending_tasklets.tail) = t; | ||
557 | which->pending_tasklets.tail = &t->next; | ||
558 | |||
559 | which->pending |= LIT_TASKLET_LOW; | ||
560 | |||
561 | if(wakeup) | ||
562 | { | ||
563 | wakeup_litirqd_locked(which); /* wake up the klitirqd */ | ||
564 | } | ||
565 | |||
566 | raw_spin_unlock_irqrestore(&which->lock, flags); | ||
567 | } | ||
568 | |||
569 | void __litmus_tasklet_schedule(struct tasklet_struct *t, unsigned int k_id) | ||
570 | { | ||
570 | if(unlikely((t->owner == NULL) || !is_realtime(t->owner))) | 571 | if(unlikely((t->owner == NULL) || !is_realtime(t->owner))) |
571 | { | 572 | { |
572 | TRACE("%s: No owner associated with this tasklet!\n", __FUNCTION__); | 573 | TRACE("%s: No owner associated with this tasklet!\n", __FUNCTION__); |
@@ -579,24 +580,37 @@ void __litmus_tasklet_schedule(struct tasklet_struct *t, unsigned int k_id) | |||
579 | BUG(); | 580 | BUG(); |
580 | } | 581 | } |
581 | 582 | ||
582 | raw_spin_lock_irqsave(&klitirqds[k_id].lock, flags); | 583 | ___litmus_tasklet_schedule(t, &klitirqds[k_id], 1); |
583 | |||
584 | t->next = NULL; | ||
585 | *klitirqds[k_id].pending_tasklets.tail = t; | ||
586 | klitirqds[k_id].pending_tasklets.tail = &t->next; | ||
587 | |||
588 | wakeup_litirqd_locked(&klitirqds[k_id]); /* wake up the klitirqd */ | ||
589 | |||
590 | raw_spin_unlock_irqrestore(&klitirqds[k_id].lock, flags); | ||
591 | } | 584 | } |
592 | 585 | ||
593 | EXPORT_SYMBOL(__litmus_tasklet_schedule); | 586 | EXPORT_SYMBOL(__litmus_tasklet_schedule); |
594 | 587 | ||
595 | 588 | ||
596 | void __litmus_tasklet_hi_schedule(struct tasklet_struct *t, unsigned int k_id) | 589 | static void ___litmus_tasklet_hi_schedule(struct tasklet_struct *t, |
590 | struct klitirqd_info *which, | ||
591 | int wakeup) | ||
597 | { | 592 | { |
598 | unsigned long flags; | 593 | unsigned long flags; |
594 | |||
595 | t->next = NULL; | ||
596 | |||
597 | raw_spin_lock_irqsave(&which->lock, flags); | ||
598 | |||
599 | *(which->pending_tasklets_hi.tail) = t; | ||
600 | which->pending_tasklets_hi.tail = &t->next; | ||
599 | 601 | ||
602 | which->pending |= LIT_TASKLET_HI; | ||
603 | |||
604 | if(wakeup) | ||
605 | { | ||
606 | wakeup_litirqd_locked(which); /* wake up the klitirqd */ | ||
607 | } | ||
608 | |||
609 | raw_spin_unlock_irqrestore(&which->lock, flags); | ||
610 | } | ||
611 | |||
612 | void __litmus_tasklet_hi_schedule(struct tasklet_struct *t, unsigned int k_id) | ||
613 | { | ||
600 | if(unlikely((t->owner == NULL) || !is_realtime(t->owner))) | 614 | if(unlikely((t->owner == NULL) || !is_realtime(t->owner))) |
601 | { | 615 | { |
602 | TRACE("%s: No owner associated with this tasklet!\n", __FUNCTION__); | 616 | TRACE("%s: No owner associated with this tasklet!\n", __FUNCTION__); |
@@ -609,15 +623,7 @@ void __litmus_tasklet_hi_schedule(struct tasklet_struct *t, unsigned int k_id) | |||
609 | BUG(); | 623 | BUG(); |
610 | } | 624 | } |
611 | 625 | ||
612 | raw_spin_lock_irqsave(&klitirqds[k_id].lock, flags); | 626 | ___litmus_tasklet_hi_schedule(t, &klitirqds[k_id], 1); |
613 | |||
614 | t->next = NULL; | ||
615 | *klitirqds[k_id].pending_tasklets_hi.tail = t; | ||
616 | klitirqds[k_id].pending_tasklets_hi.tail = &t->next; | ||
617 | |||
618 | wakeup_litirqd_locked(&klitirqds[k_id]); /* wake up the klitirqd */ | ||
619 | |||
620 | raw_spin_unlock_irqrestore(&klitirqds[k_id].lock, flags); | ||
621 | } | 627 | } |
622 | 628 | ||
623 | EXPORT_SYMBOL(__litmus_tasklet_hi_schedule); | 629 | EXPORT_SYMBOL(__litmus_tasklet_hi_schedule); |
@@ -642,7 +648,9 @@ void __litmus_tasklet_hi_schedule_first(struct tasklet_struct *t, unsigned int k | |||
642 | raw_spin_lock(&klitirqds[k_id].lock); | 648 | raw_spin_lock(&klitirqds[k_id].lock); |
643 | 649 | ||
644 | t->next = klitirqds[k_id].pending_tasklets_hi.head; | 650 | t->next = klitirqds[k_id].pending_tasklets_hi.head; |
645 | klitirqds[k_id].pending_tasklets_hi.head = t; | 651 | klitirqds[k_id].pending_tasklets_hi.head = t; |
652 | |||
653 | klitirqds[k_id].pending |= LIT_TASKLET_HI; | ||
646 | 654 | ||
647 | wakeup_litirqd_locked(&klitirqds[k_id]); /* wake up the klitirqd */ | 655 | wakeup_litirqd_locked(&klitirqds[k_id]); /* wake up the klitirqd */ |
648 | 656 | ||