aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/sched_cedf.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/sched_cedf.c')
-rw-r--r--litmus/sched_cedf.c857
1 files changed, 857 insertions, 0 deletions
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c
new file mode 100644
index 00000000000..6e1327bbf50
--- /dev/null
+++ b/litmus/sched_cedf.c
@@ -0,0 +1,857 @@
1/*
2 * litmus/sched_cedf.c
3 *
4 * Implementation of the C-EDF scheduling algorithm.
5 *
6 * This implementation is based on G-EDF:
7 * - CPUs are clustered around L2 or L3 caches.
8 * - Clusters topology is automatically detected (this is arch dependent
9 * and is working only on x86 at the moment --- and only with modern
10 * cpus that exports cpuid4 information)
11 * - The plugins _does not_ attempt to put tasks in the right cluster i.e.
12 * the programmer needs to be aware of the topology to place tasks
13 * in the desired cluster
14 * - default clustering is around L2 cache (cache index = 2)
15 * supported clusters are: L1 (private cache: pedf), L2, L3, ALL (all
16 * online_cpus are placed in a single cluster).
17 *
18 * For details on functions, take a look at sched_gsn_edf.c
19 *
20 * Currently, we do not support changes in the number of online cpus.
21 * If the num_online_cpus() dynamically changes, the plugin is broken.
22 *
23 * This version uses the simple approach and serializes all scheduling
24 * decisions by the use of a queue lock. This is probably not the
25 * best way to do it, but it should suffice for now.
26 */
27
28#include <linux/spinlock.h>
29#include <linux/percpu.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32
33#include <linux/module.h>
34
35#include <litmus/litmus.h>
36#include <litmus/jobs.h>
37#include <litmus/preempt.h>
38#include <litmus/budget.h>
39#include <litmus/sched_plugin.h>
40#include <litmus/edf_common.h>
41#include <litmus/sched_trace.h>
42
43#include <litmus/clustered.h>
44
45#include <litmus/bheap.h>
46
47#ifdef CONFIG_SCHED_CPU_AFFINITY
48#include <litmus/affinity.h>
49#endif
50
51/* to configure the cluster size */
52#include <litmus/litmus_proc.h>
53#include <linux/uaccess.h>
54
55/* Reference configuration variable. Determines which cache level is used to
56 * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that
57 * all CPUs form a single cluster (just like GSN-EDF).
58 */
59static enum cache_level cluster_config = GLOBAL_CLUSTER;
60
61struct clusterdomain;
62
63/* cpu_entry_t - maintain the linked and scheduled state
64 *
65 * A cpu also contains a pointer to the cedf_domain_t cluster
66 * that owns it (struct clusterdomain*)
67 */
68typedef struct {
69 int cpu;
70 struct clusterdomain* cluster; /* owning cluster */
71 struct task_struct* linked; /* only RT tasks */
72 struct task_struct* scheduled; /* only RT tasks */
73 atomic_t will_schedule; /* prevent unneeded IPIs */
74 struct bheap_node* hn;
75} cpu_entry_t;
76
77/* one cpu_entry_t per CPU */
78DEFINE_PER_CPU(cpu_entry_t, cedf_cpu_entries);
79
80#define set_will_schedule() \
81 (atomic_set(&__get_cpu_var(cedf_cpu_entries).will_schedule, 1))
82#define clear_will_schedule() \
83 (atomic_set(&__get_cpu_var(cedf_cpu_entries).will_schedule, 0))
84#define test_will_schedule(cpu) \
85 (atomic_read(&per_cpu(cedf_cpu_entries, cpu).will_schedule))
86
87/*
88 * In C-EDF there is a cedf domain _per_ cluster
89 * The number of clusters is dynamically determined accordingly to the
90 * total cpu number and the cluster size
91 */
92typedef struct clusterdomain {
93 /* rt_domain for this cluster */
94 rt_domain_t domain;
95 /* cpus in this cluster */
96 cpu_entry_t* *cpus;
97 /* map of this cluster cpus */
98 cpumask_var_t cpu_map;
99 /* the cpus queue themselves according to priority in here */
100 struct bheap_node *heap_node;
101 struct bheap cpu_heap;
102 /* lock for this cluster */
103#define cluster_lock domain.ready_lock
104} cedf_domain_t;
105
106/* a cedf_domain per cluster; allocation is done at init/activation time */
107cedf_domain_t *cedf;
108
109#define remote_cluster(cpu) ((cedf_domain_t *) per_cpu(cedf_cpu_entries, cpu).cluster)
110#define task_cpu_cluster(task) remote_cluster(get_partition(task))
111
112/* Uncomment WANT_ALL_SCHED_EVENTS if you want to see all scheduling
113 * decisions in the TRACE() log; uncomment VERBOSE_INIT for verbose
114 * information during the initialization of the plugin (e.g., topology)
115#define WANT_ALL_SCHED_EVENTS
116 */
117#define VERBOSE_INIT
118
119static int cpu_lower_prio(struct bheap_node *_a, struct bheap_node *_b)
120{
121 cpu_entry_t *a, *b;
122 a = _a->value;
123 b = _b->value;
124 /* Note that a and b are inverted: we want the lowest-priority CPU at
125 * the top of the heap.
126 */
127 return edf_higher_prio(b->linked, a->linked);
128}
129
130/* update_cpu_position - Move the cpu entry to the correct place to maintain
131 * order in the cpu queue. Caller must hold cedf lock.
132 */
133static void update_cpu_position(cpu_entry_t *entry)
134{
135 cedf_domain_t *cluster = entry->cluster;
136
137 if (likely(bheap_node_in_heap(entry->hn)))
138 bheap_delete(cpu_lower_prio,
139 &cluster->cpu_heap,
140 entry->hn);
141
142 bheap_insert(cpu_lower_prio, &cluster->cpu_heap, entry->hn);
143}
144
145/* caller must hold cedf lock */
146static cpu_entry_t* lowest_prio_cpu(cedf_domain_t *cluster)
147{
148 struct bheap_node* hn;
149 hn = bheap_peek(cpu_lower_prio, &cluster->cpu_heap);
150 return hn->value;
151}
152
153
154/* link_task_to_cpu - Update the link of a CPU.
155 * Handles the case where the to-be-linked task is already
156 * scheduled on a different CPU.
157 */
158static noinline void link_task_to_cpu(struct task_struct* linked,
159 cpu_entry_t *entry)
160{
161 cpu_entry_t *sched;
162 struct task_struct* tmp;
163 int on_cpu;
164
165 BUG_ON(linked && !is_realtime(linked));
166
167 /* Currently linked task is set to be unlinked. */
168 if (entry->linked) {
169 entry->linked->rt_param.linked_on = NO_CPU;
170 }
171
172 /* Link new task to CPU. */
173 if (linked) {
174 tsk_rt(linked)->completed = 0;
175 /* handle task is already scheduled somewhere! */
176 on_cpu = linked->rt_param.scheduled_on;
177 if (on_cpu != NO_CPU) {
178 sched = &per_cpu(cedf_cpu_entries, on_cpu);
179 /* this should only happen if not linked already */
180 BUG_ON(sched->linked == linked);
181
182 /* If we are already scheduled on the CPU to which we
183 * wanted to link, we don't need to do the swap --
184 * we just link ourselves to the CPU and depend on
185 * the caller to get things right.
186 */
187 if (entry != sched) {
188 TRACE_TASK(linked,
189 "already scheduled on %d, updating link.\n",
190 sched->cpu);
191 tmp = sched->linked;
192 linked->rt_param.linked_on = sched->cpu;
193 sched->linked = linked;
194 update_cpu_position(sched);
195 linked = tmp;
196 }
197 }
198 if (linked) /* might be NULL due to swap */
199 linked->rt_param.linked_on = entry->cpu;
200 }
201 entry->linked = linked;
202#ifdef WANT_ALL_SCHED_EVENTS
203 if (linked)
204 TRACE_TASK(linked, "linked to %d.\n", entry->cpu);
205 else
206 TRACE("NULL linked to %d.\n", entry->cpu);
207#endif
208 update_cpu_position(entry);
209}
210
211/* unlink - Make sure a task is not linked any longer to an entry
212 * where it was linked before. Must hold cedf_lock.
213 */
214static noinline void unlink(struct task_struct* t)
215{
216 cpu_entry_t *entry;
217
218 if (t->rt_param.linked_on != NO_CPU) {
219 /* unlink */
220 entry = &per_cpu(cedf_cpu_entries, t->rt_param.linked_on);
221 t->rt_param.linked_on = NO_CPU;
222 link_task_to_cpu(NULL, entry);
223 } else if (is_queued(t)) {
224 /* This is an interesting situation: t is scheduled,
225 * but was just recently unlinked. It cannot be
226 * linked anywhere else (because then it would have
227 * been relinked to this CPU), thus it must be in some
228 * queue. We must remove it from the list in this
229 * case.
230 *
231 * in C-EDF case is should be somewhere in the queue for
232 * its domain, therefore and we can get the domain using
233 * task_cpu_cluster
234 */
235 remove(&(task_cpu_cluster(t))->domain, t);
236 }
237}
238
239
240/* preempt - force a CPU to reschedule
241 */
242static void preempt(cpu_entry_t *entry)
243{
244 preempt_if_preemptable(entry->scheduled, entry->cpu);
245}
246
247/* requeue - Put an unlinked task into gsn-edf domain.
248 * Caller must hold cedf_lock.
249 */
250static noinline void requeue(struct task_struct* task)
251{
252 cedf_domain_t *cluster = task_cpu_cluster(task);
253 BUG_ON(!task);
254 /* sanity check before insertion */
255 BUG_ON(is_queued(task));
256
257 if (is_early_releasing(task) || is_released(task, litmus_clock()))
258 __add_ready(&cluster->domain, task);
259 else {
260 /* it has got to wait */
261 add_release(&cluster->domain, task);
262 }
263}
264
265#ifdef CONFIG_SCHED_CPU_AFFINITY
266static cpu_entry_t* cedf_get_nearest_available_cpu(
267 cedf_domain_t *cluster, cpu_entry_t *start)
268{
269 cpu_entry_t *affinity;
270
271 get_nearest_available_cpu(affinity, start, cedf_cpu_entries,
272#ifdef CONFIG_RELEASE_MASTER
273 cluster->domain.release_master
274#else
275 NO_CPU
276#endif
277 );
278
279 /* make sure CPU is in our cluster */
280 if (affinity && cpu_isset(affinity->cpu, *cluster->cpu_map))
281 return(affinity);
282 else
283 return(NULL);
284}
285#endif
286
287
288/* check for any necessary preemptions */
289static void check_for_preemptions(cedf_domain_t *cluster)
290{
291 struct task_struct *task;
292 cpu_entry_t *last;
293
294 for(last = lowest_prio_cpu(cluster);
295 edf_preemption_needed(&cluster->domain, last->linked);
296 last = lowest_prio_cpu(cluster)) {
297 /* preemption necessary */
298 task = __take_ready(&cluster->domain);
299 TRACE("check_for_preemptions: attempting to link task %d to %d\n",
300 task->pid, last->cpu);
301#ifdef CONFIG_SCHED_CPU_AFFINITY
302 {
303 cpu_entry_t *affinity =
304 cedf_get_nearest_available_cpu(cluster,
305 &per_cpu(cedf_cpu_entries, task_cpu(task)));
306 if(affinity)
307 last = affinity;
308 else if(requeue_preempted_job(last->linked))
309 requeue(last->linked);
310 }
311#else
312 if (requeue_preempted_job(last->linked))
313 requeue(last->linked);
314#endif
315 link_task_to_cpu(task, last);
316 preempt(last);
317 }
318}
319
320/* cedf_job_arrival: task is either resumed or released */
321static noinline void cedf_job_arrival(struct task_struct* task)
322{
323 cedf_domain_t *cluster = task_cpu_cluster(task);
324 BUG_ON(!task);
325
326 requeue(task);
327 check_for_preemptions(cluster);
328}
329
330static void cedf_release_jobs(rt_domain_t* rt, struct bheap* tasks)
331{
332 cedf_domain_t* cluster = container_of(rt, cedf_domain_t, domain);
333 unsigned long flags;
334
335 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
336
337 __merge_ready(&cluster->domain, tasks);
338 check_for_preemptions(cluster);
339
340 raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags);
341}
342
343/* caller holds cedf_lock */
344static noinline void job_completion(struct task_struct *t, int forced)
345{
346 BUG_ON(!t);
347
348 sched_trace_task_completion(t, forced);
349
350 TRACE_TASK(t, "job_completion().\n");
351
352 /* set flags */
353 tsk_rt(t)->completed = 1;
354 /* prepare for next period */
355 prepare_for_next_period(t);
356 if (is_early_releasing(t) || is_released(t, litmus_clock()))
357 sched_trace_task_release(t);
358 /* unlink */
359 unlink(t);
360 /* requeue
361 * But don't requeue a blocking task. */
362 if (is_running(t))
363 cedf_job_arrival(t);
364}
365
366/* cedf_tick - this function is called for every local timer
367 * interrupt.
368 *
369 * checks whether the current task has expired and checks
370 * whether we need to preempt it if it has not expired
371 */
372static void cedf_tick(struct task_struct* t)
373{
374 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) {
375 if (!is_np(t)) {
376 /* np tasks will be preempted when they become
377 * preemptable again
378 */
379 litmus_reschedule_local();
380 set_will_schedule();
381 TRACE("cedf_scheduler_tick: "
382 "%d is preemptable "
383 " => FORCE_RESCHED\n", t->pid);
384 } else if (is_user_np(t)) {
385 TRACE("cedf_scheduler_tick: "
386 "%d is non-preemptable, "
387 "preemption delayed.\n", t->pid);
388 request_exit_np(t);
389 }
390 }
391}
392
393/* Getting schedule() right is a bit tricky. schedule() may not make any
394 * assumptions on the state of the current task since it may be called for a
395 * number of reasons. The reasons include a scheduler_tick() determined that it
396 * was necessary, because sys_exit_np() was called, because some Linux
397 * subsystem determined so, or even (in the worst case) because there is a bug
398 * hidden somewhere. Thus, we must take extreme care to determine what the
399 * current state is.
400 *
401 * The CPU could currently be scheduling a task (or not), be linked (or not).
402 *
403 * The following assertions for the scheduled task could hold:
404 *
405 * - !is_running(scheduled) // the job blocks
406 * - scheduled->timeslice == 0 // the job completed (forcefully)
407 * - is_completed() // the job completed (by syscall)
408 * - linked != scheduled // we need to reschedule (for any reason)
409 * - is_np(scheduled) // rescheduling must be delayed,
410 * sys_exit_np must be requested
411 *
412 * Any of these can occur together.
413 */
414static struct task_struct* cedf_schedule(struct task_struct * prev)
415{
416 cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries);
417 cedf_domain_t *cluster = entry->cluster;
418 int out_of_time, sleep, preempt, np, exists, blocks;
419 struct task_struct* next = NULL;
420
421#ifdef CONFIG_RELEASE_MASTER
422 /* Bail out early if we are the release master.
423 * The release master never schedules any real-time tasks.
424 */
425 if (unlikely(cluster->domain.release_master == entry->cpu)) {
426 sched_state_task_picked();
427 return NULL;
428 }
429#endif
430
431 raw_spin_lock(&cluster->cluster_lock);
432 clear_will_schedule();
433
434 /* sanity checking */
435 BUG_ON(entry->scheduled && entry->scheduled != prev);
436 BUG_ON(entry->scheduled && !is_realtime(prev));
437 BUG_ON(is_realtime(prev) && !entry->scheduled);
438
439 /* (0) Determine state */
440 exists = entry->scheduled != NULL;
441 blocks = exists && !is_running(entry->scheduled);
442 out_of_time = exists &&
443 budget_enforced(entry->scheduled) &&
444 budget_exhausted(entry->scheduled);
445 np = exists && is_np(entry->scheduled);
446 sleep = exists && is_completed(entry->scheduled);
447 preempt = entry->scheduled != entry->linked;
448
449#ifdef WANT_ALL_SCHED_EVENTS
450 TRACE_TASK(prev, "invoked cedf_schedule.\n");
451#endif
452
453 if (exists)
454 TRACE_TASK(prev,
455 "blocks:%d out_of_time:%d np:%d sleep:%d preempt:%d "
456 "state:%d sig:%d\n",
457 blocks, out_of_time, np, sleep, preempt,
458 prev->state, signal_pending(prev));
459 if (entry->linked && preempt)
460 TRACE_TASK(prev, "will be preempted by %s/%d\n",
461 entry->linked->comm, entry->linked->pid);
462
463
464 /* If a task blocks we have no choice but to reschedule.
465 */
466 if (blocks)
467 unlink(entry->scheduled);
468
469 /* Request a sys_exit_np() call if we would like to preempt but cannot.
470 * We need to make sure to update the link structure anyway in case
471 * that we are still linked. Multiple calls to request_exit_np() don't
472 * hurt.
473 */
474 if (np && (out_of_time || preempt || sleep)) {
475 unlink(entry->scheduled);
476 request_exit_np(entry->scheduled);
477 }
478
479 /* Any task that is preemptable and either exhausts its execution
480 * budget or wants to sleep completes. We may have to reschedule after
481 * this. Don't do a job completion if we block (can't have timers running
482 * for blocked jobs).
483 */
484 if (!np && (out_of_time || sleep) && !blocks)
485 job_completion(entry->scheduled, !sleep);
486
487 /* Link pending task if we became unlinked.
488 */
489 if (!entry->linked)
490 link_task_to_cpu(__take_ready(&cluster->domain), entry);
491
492 /* The final scheduling decision. Do we need to switch for some reason?
493 * If linked is different from scheduled, then select linked as next.
494 */
495 if ((!np || blocks) &&
496 entry->linked != entry->scheduled) {
497 /* Schedule a linked job? */
498 if (entry->linked) {
499 entry->linked->rt_param.scheduled_on = entry->cpu;
500 next = entry->linked;
501 }
502 if (entry->scheduled) {
503 /* not gonna be scheduled soon */
504 entry->scheduled->rt_param.scheduled_on = NO_CPU;
505 TRACE_TASK(entry->scheduled, "scheduled_on = NO_CPU\n");
506 }
507 } else
508 /* Only override Linux scheduler if we have a real-time task
509 * scheduled that needs to continue.
510 */
511 if (exists)
512 next = prev;
513
514 sched_state_task_picked();
515 raw_spin_unlock(&cluster->cluster_lock);
516
517#ifdef WANT_ALL_SCHED_EVENTS
518 TRACE("cedf_lock released, next=0x%p\n", next);
519
520 if (next)
521 TRACE_TASK(next, "scheduled at %llu\n", litmus_clock());
522 else if (exists && !next)
523 TRACE("becomes idle at %llu.\n", litmus_clock());
524#endif
525
526
527 return next;
528}
529
530
531/* _finish_switch - we just finished the switch away from prev
532 */
533static void cedf_finish_switch(struct task_struct *prev)
534{
535 cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries);
536
537 entry->scheduled = is_realtime(current) ? current : NULL;
538#ifdef WANT_ALL_SCHED_EVENTS
539 TRACE_TASK(prev, "switched away from\n");
540#endif
541}
542
543
544/* Prepare a task for running in RT mode
545 */
546static void cedf_task_new(struct task_struct * t, int on_rq, int running)
547{
548 unsigned long flags;
549 cpu_entry_t* entry;
550 cedf_domain_t* cluster;
551
552 TRACE("gsn edf: task new %d\n", t->pid);
553
554 /* the cluster doesn't change even if t is running */
555 cluster = task_cpu_cluster(t);
556
557 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
558
559 /* setup job params */
560 release_at(t, litmus_clock());
561
562 if (running) {
563 entry = &per_cpu(cedf_cpu_entries, task_cpu(t));
564 BUG_ON(entry->scheduled);
565
566#ifdef CONFIG_RELEASE_MASTER
567 if (entry->cpu != cluster->domain.release_master) {
568#endif
569 entry->scheduled = t;
570 tsk_rt(t)->scheduled_on = task_cpu(t);
571#ifdef CONFIG_RELEASE_MASTER
572 } else {
573 /* do not schedule on release master */
574 preempt(entry); /* force resched */
575 tsk_rt(t)->scheduled_on = NO_CPU;
576 }
577#endif
578 } else {
579 t->rt_param.scheduled_on = NO_CPU;
580 }
581 t->rt_param.linked_on = NO_CPU;
582
583 cedf_job_arrival(t);
584 raw_spin_unlock_irqrestore(&(cluster->cluster_lock), flags);
585}
586
587static void cedf_task_wake_up(struct task_struct *task)
588{
589 unsigned long flags;
590 lt_t now;
591 cedf_domain_t *cluster;
592
593 TRACE_TASK(task, "wake_up at %llu\n", litmus_clock());
594
595 cluster = task_cpu_cluster(task);
596
597 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
598 now = litmus_clock();
599 if (is_sporadic(task) && is_tardy(task, now)) {
600 /* new sporadic release */
601 release_at(task, now);
602 sched_trace_task_release(task);
603 }
604 else {
605 if (task->rt.time_slice) {
606 /* came back in time before deadline
607 */
608 tsk_rt(task)->completed = 0;
609 }
610 }
611 cedf_job_arrival(task);
612 raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags);
613}
614
615static void cedf_task_block(struct task_struct *t)
616{
617 unsigned long flags;
618 cedf_domain_t *cluster;
619
620 TRACE_TASK(t, "block at %llu\n", litmus_clock());
621
622 cluster = task_cpu_cluster(t);
623
624 /* unlink if necessary */
625 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
626 unlink(t);
627 raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags);
628
629 BUG_ON(!is_realtime(t));
630}
631
632
633static void cedf_task_exit(struct task_struct * t)
634{
635 unsigned long flags;
636 cedf_domain_t *cluster = task_cpu_cluster(t);
637
638 /* unlink if necessary */
639 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
640 unlink(t);
641 if (tsk_rt(t)->scheduled_on != NO_CPU) {
642 cpu_entry_t *cpu;
643 cpu = &per_cpu(cedf_cpu_entries, tsk_rt(t)->scheduled_on);
644 cpu->scheduled = NULL;
645 tsk_rt(t)->scheduled_on = NO_CPU;
646 }
647 raw_spin_unlock_irqrestore(&cluster->cluster_lock, flags);
648
649 BUG_ON(!is_realtime(t));
650 TRACE_TASK(t, "RIP\n");
651}
652
653static long cedf_admit_task(struct task_struct* tsk)
654{
655 return (remote_cluster(task_cpu(tsk)) == task_cpu_cluster(tsk)) ?
656 0 : -EINVAL;
657}
658
659/* total number of cluster */
660static int num_clusters;
661/* we do not support cluster of different sizes */
662static unsigned int cluster_size;
663
664#ifdef VERBOSE_INIT
665static void print_cluster_topology(cpumask_var_t mask, int cpu)
666{
667 int chk;
668 char buf[255];
669
670 chk = cpulist_scnprintf(buf, 254, mask);
671 buf[chk] = '\0';
672 printk(KERN_INFO "CPU = %d, shared cpu(s) = %s\n", cpu, buf);
673
674}
675#endif
676
677static int clusters_allocated = 0;
678
679static void cleanup_cedf(void)
680{
681 int i;
682
683 if (clusters_allocated) {
684 for (i = 0; i < num_clusters; i++) {
685 kfree(cedf[i].cpus);
686 kfree(cedf[i].heap_node);
687 free_cpumask_var(cedf[i].cpu_map);
688 }
689
690 kfree(cedf);
691 }
692}
693
694static long cedf_activate_plugin(void)
695{
696 int i, j, cpu, ccpu, cpu_count;
697 cpu_entry_t *entry;
698
699 cpumask_var_t mask;
700 int chk = 0;
701
702 /* de-allocate old clusters, if any */
703 cleanup_cedf();
704
705 printk(KERN_INFO "C-EDF: Activate Plugin, cluster configuration = %d\n",
706 cluster_config);
707
708 /* need to get cluster_size first */
709 if(!zalloc_cpumask_var(&mask, GFP_ATOMIC))
710 return -ENOMEM;
711
712 if (unlikely(cluster_config == GLOBAL_CLUSTER)) {
713 cluster_size = num_online_cpus();
714 } else {
715 chk = get_shared_cpu_map(mask, 0, cluster_config);
716 if (chk) {
717 /* if chk != 0 then it is the max allowed index */
718 printk(KERN_INFO "C-EDF: Cluster configuration = %d "
719 "is not supported on this hardware.\n",
720 cluster_config);
721 /* User should notice that the configuration failed, so
722 * let's bail out. */
723 return -EINVAL;
724 }
725
726 cluster_size = cpumask_weight(mask);
727 }
728
729 if ((num_online_cpus() % cluster_size) != 0) {
730 /* this can't be right, some cpus are left out */
731 printk(KERN_ERR "C-EDF: Trying to group %d cpus in %d!\n",
732 num_online_cpus(), cluster_size);
733 return -1;
734 }
735
736 num_clusters = num_online_cpus() / cluster_size;
737 printk(KERN_INFO "C-EDF: %d cluster(s) of size = %d\n",
738 num_clusters, cluster_size);
739
740 /* initialize clusters */
741 cedf = kmalloc(num_clusters * sizeof(cedf_domain_t), GFP_ATOMIC);
742 for (i = 0; i < num_clusters; i++) {
743
744 cedf[i].cpus = kmalloc(cluster_size * sizeof(cpu_entry_t),
745 GFP_ATOMIC);
746 cedf[i].heap_node = kmalloc(
747 cluster_size * sizeof(struct bheap_node),
748 GFP_ATOMIC);
749 bheap_init(&(cedf[i].cpu_heap));
750 edf_domain_init(&(cedf[i].domain), NULL, cedf_release_jobs);
751
752 if(!zalloc_cpumask_var(&cedf[i].cpu_map, GFP_ATOMIC))
753 return -ENOMEM;
754#ifdef CONFIG_RELEASE_MASTER
755 cedf[i].domain.release_master = atomic_read(&release_master_cpu);
756#endif
757 }
758
759 /* cycle through cluster and add cpus to them */
760 for (i = 0; i < num_clusters; i++) {
761
762 for_each_online_cpu(cpu) {
763 /* check if the cpu is already in a cluster */
764 for (j = 0; j < num_clusters; j++)
765 if (cpumask_test_cpu(cpu, cedf[j].cpu_map))
766 break;
767 /* if it is in a cluster go to next cpu */
768 if (j < num_clusters &&
769 cpumask_test_cpu(cpu, cedf[j].cpu_map))
770 continue;
771
772 /* this cpu isn't in any cluster */
773 /* get the shared cpus */
774 if (unlikely(cluster_config == GLOBAL_CLUSTER))
775 cpumask_copy(mask, cpu_online_mask);
776 else
777 get_shared_cpu_map(mask, cpu, cluster_config);
778
779 cpumask_copy(cedf[i].cpu_map, mask);
780#ifdef VERBOSE_INIT
781 print_cluster_topology(mask, cpu);
782#endif
783 /* add cpus to current cluster and init cpu_entry_t */
784 cpu_count = 0;
785 for_each_cpu(ccpu, cedf[i].cpu_map) {
786
787 entry = &per_cpu(cedf_cpu_entries, ccpu);
788 cedf[i].cpus[cpu_count] = entry;
789 atomic_set(&entry->will_schedule, 0);
790 entry->cpu = ccpu;
791 entry->cluster = &cedf[i];
792 entry->hn = &(cedf[i].heap_node[cpu_count]);
793 bheap_node_init(&entry->hn, entry);
794
795 cpu_count++;
796
797 entry->linked = NULL;
798 entry->scheduled = NULL;
799#ifdef CONFIG_RELEASE_MASTER
800 /* only add CPUs that should schedule jobs */
801 if (entry->cpu != entry->cluster->domain.release_master)
802#endif
803 update_cpu_position(entry);
804 }
805 /* done with this cluster */
806 break;
807 }
808 }
809
810 free_cpumask_var(mask);
811 clusters_allocated = 1;
812 return 0;
813}
814
815/* Plugin object */
816static struct sched_plugin cedf_plugin __cacheline_aligned_in_smp = {
817 .plugin_name = "C-EDF",
818 .finish_switch = cedf_finish_switch,
819 .tick = cedf_tick,
820 .task_new = cedf_task_new,
821 .complete_job = complete_job,
822 .task_exit = cedf_task_exit,
823 .schedule = cedf_schedule,
824 .task_wake_up = cedf_task_wake_up,
825 .task_block = cedf_task_block,
826 .admit_task = cedf_admit_task,
827 .activate_plugin = cedf_activate_plugin,
828};
829
830static struct proc_dir_entry *cluster_file = NULL, *cedf_dir = NULL;
831
832static int __init init_cedf(void)
833{
834 int err, fs;
835
836 err = register_sched_plugin(&cedf_plugin);
837 if (!err) {
838 fs = make_plugin_proc_dir(&cedf_plugin, &cedf_dir);
839 if (!fs)
840 cluster_file = create_cluster_file(cedf_dir, &cluster_config);
841 else
842 printk(KERN_ERR "Could not allocate C-EDF procfs dir.\n");
843 }
844 return err;
845}
846
847static void clean_cedf(void)
848{
849 cleanup_cedf();
850 if (cluster_file)
851 remove_proc_entry("cluster", cedf_dir);
852 if (cedf_dir)
853 remove_plugin_proc_dir(&cedf_plugin);
854}
855
856module_init(init_cedf);
857module_exit(clean_cedf);