diff options
-rw-r--r-- | include/litmus/litmus_softirq.h | 13 | ||||
-rw-r--r-- | include/litmus/nvidia_info.h | 13 | ||||
-rw-r--r-- | litmus/Kconfig | 9 | ||||
-rw-r--r-- | litmus/Makefile | 1 | ||||
-rw-r--r-- | litmus/litmus_softirq.c | 158 | ||||
-rw-r--r-- | litmus/nvidia_info.c | 55 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 8 |
7 files changed, 180 insertions, 77 deletions
diff --git a/include/litmus/litmus_softirq.h b/include/litmus/litmus_softirq.h index 6d1f85c2e093..712c8119ae15 100644 --- a/include/litmus/litmus_softirq.h +++ b/include/litmus/litmus_softirq.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #ifndef __LITMUS_SOFTIRQ_H | ||
2 | #define __LITMUS_SOFTIRQ_H | ||
3 | |||
1 | #include <linux/interrupt.h> | 4 | #include <linux/interrupt.h> |
2 | 5 | ||
3 | /* | 6 | /* |
@@ -57,8 +60,12 @@ void kill_klitirqd(void); | |||
57 | to handle tasklets. 0, otherwise.*/ | 60 | to handle tasklets. 0, otherwise.*/ |
58 | int klitirqd_is_ready(void); | 61 | int klitirqd_is_ready(void); |
59 | 62 | ||
63 | /* Returns 1 if no NR_LITMUS_SOFTIRQD klitirqs are ready | ||
64 | to handle tasklets. 0, otherwise.*/ | ||
65 | int klitirqd_is_dead(void); | ||
66 | |||
60 | 67 | ||
61 | void __litmus_tasklet_schedule( | 68 | extern void __litmus_tasklet_schedule( |
62 | struct tasklet_struct *t, | 69 | struct tasklet_struct *t, |
63 | unsigned int k_id); | 70 | unsigned int k_id); |
64 | 71 | ||
@@ -96,4 +103,6 @@ static inline void litmus_tasklet_hi_schedule_first( | |||
96 | { | 103 | { |
97 | if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) | 104 | if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) |
98 | __litmus_tasklet_hi_schedule_first(t, k_id); | 105 | __litmus_tasklet_hi_schedule_first(t, k_id); |
99 | } \ No newline at end of file | 106 | } |
107 | |||
108 | #endif \ No newline at end of file | ||
diff --git a/include/litmus/nvidia_info.h b/include/litmus/nvidia_info.h new file mode 100644 index 000000000000..f28d8f0a7f40 --- /dev/null +++ b/include/litmus/nvidia_info.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __LITMUS_NVIDIA_H | ||
2 | #define __LITMUS_NVIDIA_H | ||
3 | |||
4 | #include <litmus/litmus_softirq.h> | ||
5 | |||
6 | int init_nvidia_info(void); | ||
7 | |||
8 | int is_nvidia_func(void *func); | ||
9 | |||
10 | int is_nvidia_in_callstack(void); | ||
11 | |||
12 | |||
13 | #endif | ||
diff --git a/litmus/Kconfig b/litmus/Kconfig index 58137f3e374e..42c5ff67c8c1 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig | |||
@@ -205,6 +205,15 @@ config NR_LITMUS_SOFTIRQD | |||
205 | help | 205 | help |
206 | Should be <= to the number of CPUs in your system. | 206 | Should be <= to the number of CPUs in your system. |
207 | 207 | ||
208 | config LITMUS_NVIDIA | ||
209 | bool "Litmus handling of NVIDIA interrupts." | ||
210 | depends on LITMUS_SOFTIRQD | ||
211 | default n | ||
212 | help | ||
213 | Direct tasklets from NVIDIA devices to Litmus's klitirqd. | ||
214 | |||
215 | If unsure, say No. | ||
216 | |||
208 | endmenu | 217 | endmenu |
209 | 218 | ||
210 | endmenu | 219 | endmenu |
diff --git a/litmus/Makefile b/litmus/Makefile index 0d0214c54896..3d3139609878 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -28,3 +28,4 @@ obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o | |||
28 | obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o | 28 | obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o |
29 | 29 | ||
30 | obj-$(CONFIG_LITMUS_SOFTIRQD) += litmus_softirq.o | 30 | obj-$(CONFIG_LITMUS_SOFTIRQD) += litmus_softirq.o |
31 | obj-$(CONFIG_LITMUS_NVIDIA) += nvidia_info.o | ||
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 | ||
diff --git a/litmus/nvidia_info.c b/litmus/nvidia_info.c new file mode 100644 index 000000000000..05f8356a8117 --- /dev/null +++ b/litmus/nvidia_info.c | |||
@@ -0,0 +1,55 @@ | |||
1 | |||
2 | #include <linux/module.h> | ||
3 | |||
4 | #include <litmus/sched_trace.h> | ||
5 | #include <litmus/nvidia_info.h> | ||
6 | |||
7 | static struct module* nvidia_mod = NULL; | ||
8 | |||
9 | int init_nvidia_info(void) | ||
10 | { | ||
11 | mutex_lock(&module_mutex); | ||
12 | nvidia_mod = find_module("nvidia"); | ||
13 | mutex_unlock(&module_mutex); | ||
14 | |||
15 | if(nvidia_mod != NULL) | ||
16 | { | ||
17 | TRACE("%s : Found NVIDIA module. Core Code: %x to %x\n", __FUNCTION__, | ||
18 | (void*)(nvidia_mod->module_core), | ||
19 | (void*)(nvidia_mod->module_core) + nvidia_mod->core_size); | ||
20 | return(0); | ||
21 | } | ||
22 | else | ||
23 | { | ||
24 | TRACE("%s : Could not find NVIDIA module! Loaded?\n", __FUNCTION__); | ||
25 | return(-1); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | |||
30 | /* works with pointers to static data inside the module too. */ | ||
31 | int is_nvidia_func(void *func_addr) | ||
32 | { | ||
33 | int ret = 0; | ||
34 | if(nvidia_mod) | ||
35 | { | ||
36 | ret = within_module_core((long unsigned int)func_addr, nvidia_mod); | ||
37 | |||
38 | TRACE("%s : %x is in NVIDIA module : %d\n", | ||
39 | __FUNCTION__, func_addr, ret); | ||
40 | } | ||
41 | else | ||
42 | { | ||
43 | TRACE("%s : No NVIDIA module info loaded!\n", __FUNCTION__); | ||
44 | } | ||
45 | |||
46 | return(ret); | ||
47 | } | ||
48 | |||
49 | int is_nvidia_in_callstack(void) | ||
50 | { | ||
51 | /* TODO -- Walk back through the callstack, running each called | ||
52 | function through is_nvidia_func() */ | ||
53 | TRACE("%s : NOT IMPLEMENTED!\n", __FUNCTION__); | ||
54 | return(1); | ||
55 | } | ||
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 586b7c3f7de1..99813698ee17 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -29,6 +29,10 @@ | |||
29 | #include <litmus/litmus_softirq.h> | 29 | #include <litmus/litmus_softirq.h> |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #ifdef CONFIG_LITMUS_NVIDIA | ||
33 | #include <litmus/nvidia_info.h> | ||
34 | #endif | ||
35 | |||
32 | /* Overview of GSN-EDF operations. | 36 | /* Overview of GSN-EDF operations. |
33 | * | 37 | * |
34 | * For a detailed explanation of GSN-EDF have a look at the FMLP paper. This | 38 | * For a detailed explanation of GSN-EDF have a look at the FMLP paper. This |
@@ -967,6 +971,10 @@ static long gsnedf_activate_plugin(void) | |||
967 | spawn_klitirqd(); | 971 | spawn_klitirqd(); |
968 | #endif | 972 | #endif |
969 | 973 | ||
974 | #ifdef CONFIG_LITMUS_NVIDIA | ||
975 | init_nvidia_info(); | ||
976 | #endif | ||
977 | |||
970 | return 0; | 978 | return 0; |
971 | } | 979 | } |
972 | 980 | ||