aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/litmus/ce_domain.h23
-rw-r--r--include/litmus/sched_mc.h37
-rw-r--r--litmus/ce_domain.c89
-rw-r--r--litmus/sched_mc.c87
-rw-r--r--litmus/sched_mc_ce.c351
5 files changed, 339 insertions, 248 deletions
diff --git a/include/litmus/ce_domain.h b/include/litmus/ce_domain.h
new file mode 100644
index 000000000000..373f3f5f78d3
--- /dev/null
+++ b/include/litmus/ce_domain.h
@@ -0,0 +1,23 @@
1#ifndef _LITMUS_CE_DOMAIN_H
2#define _LITMUS_CE_DOMAIN_H
3
4/*
5 * Functions that the MC plugin needs to call through a domain pointer.
6 */
7void ce_requeue(domain_t*, struct task_struct*);
8struct task_struct* ce_peek_and_take_ready(domain_t*);
9int ce_higher_prio(struct task_struct*, struct task_struct*);
10
11typedef enum hrtimer_restart (*ce_timer_callback_t)(struct hrtimer*);
12
13void ce_domain_init(domain_t*,
14 raw_spinlock_t*,
15 requeue_t,
16 peek_ready_t,
17 take_ready_t,
18 preempt_needed_t,
19 task_prio_t,
20 struct ce_dom_data*,
21 const int,
22 ce_timer_callback_t);
23#endif
diff --git a/include/litmus/sched_mc.h b/include/litmus/sched_mc.h
index ad5d097b3d61..384e65e4151d 100644
--- a/include/litmus/sched_mc.h
+++ b/include/litmus/sched_mc.h
@@ -21,7 +21,10 @@ struct mc_job {
21}; 21};
22 22
23#ifdef __KERNEL__ 23#ifdef __KERNEL__
24/* only used in the kernel (no user space) */ 24/*
25 * These are used only in the kernel. Userspace programs like RTSpin won't see
26 * them.
27 */
25 28
26struct mc_data { 29struct mc_data {
27 struct mc_task mc_task; 30 struct mc_task mc_task;
@@ -33,18 +36,8 @@ struct mc_data {
33#define is_ghost(t) (tsk_mc_data(t)->mc_job.is_ghost) 36#define is_ghost(t) (tsk_mc_data(t)->mc_job.is_ghost)
34 37
35/* 38/*
36 * Cache the budget along with the struct PID for a task so that we don't need 39 * The MC-CE scheduler uses this as domain data.
37 * to fetch its task_struct every time we check to see what should be
38 * scheduled.
39 */ 40 */
40struct ce_dom_pid_entry {
41 struct pid *pid;
42 lt_t budget;
43 /* accumulated (summed) budgets, including this one */
44 lt_t acc_time;
45 int expected_job;
46};
47
48struct ce_dom_data { 41struct ce_dom_data {
49 int cpu; 42 int cpu;
50 struct task_struct *scheduled, *should_schedule; 43 struct task_struct *scheduled, *should_schedule;
@@ -52,9 +45,6 @@ struct ce_dom_data {
52 * Each CPU needs a mapping of level A ID (integer) to struct pid so 45 * Each CPU needs a mapping of level A ID (integer) to struct pid so
53 * that we can get its task struct. 46 * that we can get its task struct.
54 */ 47 */
55 struct ce_dom_pid_entry pid_entries[CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS];
56 int num_pid_entries;
57 lt_t cycle_time;
58 struct hrtimer_start_on_info timer_info; 48 struct hrtimer_start_on_info timer_info;
59 struct hrtimer timer; 49 struct hrtimer timer;
60}; 50};
@@ -90,6 +80,23 @@ typedef struct {
90 crit_entry_t* crit_entry; 80 crit_entry_t* crit_entry;
91} domain_data_t; 81} domain_data_t;
92 82
83/*
84 * Functions that are used with the MC-CE plugin.
85 */
86long mc_ce_set_domains(const int, domain_data_t*[]);
87unsigned int mc_ce_get_expected_job(const int, const int);
88
89/*
90 * These functions are (lazily) inserted into the MC plugin code so that it
91 * manipulates the MC-CE state.
92 */
93long mc_ce_admit_task_common(struct task_struct*);
94void mc_ce_task_exit_common(struct task_struct*);
95void mc_ce_timer_callback_common(domain_t*, struct hrtimer*);
96void mc_ce_release_at_common(struct task_struct*, lt_t);
97long mc_ce_activate_plugin_common(void);
98long mc_ce_deactivate_plugin_common(void);
99
93#endif /* __KERNEL__ */ 100#endif /* __KERNEL__ */
94 101
95#endif 102#endif
diff --git a/litmus/ce_domain.c b/litmus/ce_domain.c
index 8797c05d9392..c00feaf45a5c 100644
--- a/litmus/ce_domain.c
+++ b/litmus/ce_domain.c
@@ -19,35 +19,25 @@ void ce_requeue(domain_t *dom, struct task_struct *ts)
19{ 19{
20 const struct ce_dom_data *ce_data = dom->data; 20 const struct ce_dom_data *ce_data = dom->data;
21 const int idx = tsk_mc_data(ts)->mc_task.lvl_a_id; 21 const int idx = tsk_mc_data(ts)->mc_task.lvl_a_id;
22 const struct ce_dom_pid_entry *pid_entry = 22 const unsigned int just_finished = tsk_rt(ts)->job_params.job_no;
23 &ce_data->pid_entries[idx]; 23 const unsigned int expected_job =
24 const int just_finished = tsk_rt(ts)->job_params.job_no; 24 mc_ce_get_expected_job(ce_data->cpu, idx);
25 const int expected_job = pid_entry->expected_job;
26 const int asleep = RT_F_SLEEP == get_rt_flags(ts); 25 const int asleep = RT_F_SLEEP == get_rt_flags(ts);
27 26
28 TRACE_TASK(ts, "entered ce_requeue. asleep: %d just_finished: %4d " 27 TRACE_TASK(ts, "entered ce_requeue. asleep: %d just_finished: %3u "
29 "expected_job: %4d\n", 28 "expected_job: %3u\n",
30 asleep, just_finished, expected_job); 29 asleep, just_finished, expected_job);
31 30
32 /* When coming from job completion, the task will be asleep. */ 31 /* When coming from job completion, the task will be asleep. */
33 if (asleep && just_finished < expected_job) { 32 if (asleep && just_finished < expected_job) {
34 TRACE_TASK(ts, "appears behind\n"); 33 TRACE_TASK(ts, "appears behind\n");
35 } else if (asleep && expected_job < just_finished) { 34 } else if (asleep && expected_job < just_finished) {
36 TRACE_TASK(ts, "job %d completed in expected job %d which " 35 TRACE_TASK(ts, "job %u completed in expected job %u which "
37 "seems too early\n", just_finished, 36 "seems too early\n", just_finished,
38 expected_job); 37 expected_job);
39 } 38 }
40} 39}
41 40
42void mc_ce_task_exit(struct task_struct*);
43/*
44 * Called when a task exits the system.
45 */
46void ce_task_exit(domain_t *dom, struct task_struct *ts)
47{
48 mc_ce_task_exit(ts);
49}
50
51/* 41/*
52 * ce_take_ready and ce_peek_ready 42 * ce_take_ready and ce_peek_ready
53 */ 43 */
@@ -74,8 +64,7 @@ struct task_struct* ce_peek_and_take_ready(domain_t *dom)
74 (t) ? t->rt_param.job_params.job_no : 1, \ 64 (t) ? t->rt_param.job_params.job_no : 1, \
75 (t && get_task_domain(t)) ? get_task_domain(t)->name : "" 65 (t && get_task_domain(t)) ? get_task_domain(t)->name : ""
76 66
77int ce_higher_prio(struct task_struct *_a, 67int ce_higher_prio(struct task_struct *_a, struct task_struct *_b)
78 struct task_struct *_b)
79{ 68{
80 const struct task_struct *a = _a; 69 const struct task_struct *a = _a;
81 const domain_t *dom = get_task_domain(a); 70 const domain_t *dom = get_task_domain(a);
@@ -87,52 +76,22 @@ int ce_higher_prio(struct task_struct *_a,
87 return (a == ce_data->should_schedule); 76 return (a == ce_data->should_schedule);
88} 77}
89 78
90void __mc_ce_timer_callback(struct hrtimer *timer); 79void ce_domain_init(domain_t *dom,
91domain_data_t *ce_domain_for(int); 80 raw_spinlock_t *lock,
92void mc_check_for_preempt(domain_t*); 81 requeue_t requeue,
93static enum hrtimer_restart ce_timer_function(struct hrtimer *timer) 82 peek_ready_t peek_ready,
94{ 83 take_ready_t take_ready,
95 struct ce_dom_data *ce_data; 84 preempt_needed_t preempt_needed,
96 domain_data_t *dom_data; 85 task_prio_t task_prio,
97 unsigned long flags; 86 struct ce_dom_data *dom_data,
98 87 const int cpu,
99 TRACE("timer callback\n"); 88 ce_timer_callback_t ce_timer_callback)
100
101 ce_data = container_of(timer, struct ce_dom_data, timer);
102 dom_data = ce_domain_for(ce_data->cpu);
103 raw_spin_lock_irqsave(dom_data->domain.lock, flags);
104 __mc_ce_timer_callback(timer);
105 mc_check_for_preempt(&dom_data->domain);
106 raw_spin_unlock_irqrestore(dom_data->domain.lock, flags);
107 return HRTIMER_RESTART;
108}
109
110void mc_ce_release_at(struct task_struct*, lt_t);
111void ce_start(struct task_struct *ts, lt_t start)
112{
113 mc_ce_release_at(ts, start);
114}
115
116domain_data_t *ce_domain_for(int);
117long mc_ce_activate_plugin(void);
118long ce_activate_plugin(void)
119{
120 domain_data_t *dom_data;
121 struct ce_dom_data *ce_data;
122 int cpu;
123
124 /* first change the timer callback function */
125 for_each_online_cpu(cpu) {
126 dom_data = ce_domain_for(cpu);
127 ce_data = dom_data->domain.data;
128 ce_data->timer.function = ce_timer_function;
129 }
130 /* then run the regular CE activate plugin */
131 return mc_ce_activate_plugin();
132}
133
134long mc_ce_deactivate_plugin(void);
135long ce_deactivate_plugin(void)
136{ 89{
137 return mc_ce_deactivate_plugin(); 90 domain_init(dom, lock, requeue, peek_ready, take_ready, preempt_needed,
91 task_prio);
92 dom->data = dom_data;
93 dom_data->cpu = cpu;
94 hrtimer_start_on_info_init(&dom_data->timer_info);
95 hrtimer_init(&dom_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
96 dom_data->timer.function = ce_timer_callback;
138} 97}
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c
index 3b98a93511ab..11ba10a54f4d 100644
--- a/litmus/sched_mc.c
+++ b/litmus/sched_mc.c
@@ -507,7 +507,7 @@ static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer)
507{ 507{
508 unsigned long flags; 508 unsigned long flags;
509 struct task_struct *tmp = NULL; 509 struct task_struct *tmp = NULL;
510 crit_entry_t *ce = container_of(timer, crit_entry_t, timer);; 510 crit_entry_t *ce = container_of(timer, crit_entry_t, timer);
511 511
512 local_irq_save(flags); 512 local_irq_save(flags);
513 TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing"); 513 TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing");
@@ -534,22 +534,38 @@ static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer)
534 return HRTIMER_NORESTART; 534 return HRTIMER_NORESTART;
535} 535}
536 536
537void __mc_ce_timer_callback(struct hrtimer *timer);
538domain_data_t *ce_domain_for(int);
539static enum hrtimer_restart ce_timer_function(struct hrtimer *timer) 537static enum hrtimer_restart ce_timer_function(struct hrtimer *timer)
540{ 538{
541 struct ce_dom_data *ce_data; 539 struct ce_dom_data *ce_data =
542 domain_data_t *dom_data; 540 container_of(timer, struct ce_dom_data, timer);
541 crit_entry_t *ce = &cpus[ce_data->cpu]->crit_entries[CRIT_LEVEL_A];
542 domain_t *dom = ce->domain;
543 struct task_struct *old_link = NULL;
543 unsigned long flags; 544 unsigned long flags;
544 545
545 TRACE("timer callback\n"); 546 TRACE("MC level-A timer callback for CPU %d\n", ce_data->cpu);
547
548 raw_spin_lock_irqsave(dom->lock, flags);
549
550 raw_spin_lock(&crit_cpu(ce)->lock);
551 if (ce->linked &&
552 ce->linked == ce_data->should_schedule &&
553 is_ghost(ce->linked))
554 {
555 update_ghost_time(ce->linked);
556 if (tsk_mc_data(ce->linked)->mc_job.ghost_budget == 0) {
557 old_link = ce->linked;
558 link_task_to_crit(ce, NULL);
559 }
560 }
561 raw_spin_unlock(&crit_cpu(ce)->lock);
562
563 if (NULL != old_link)
564 job_completion(old_link, 0);
546 565
547 ce_data = container_of(timer, struct ce_dom_data, timer); 566 mc_ce_timer_callback_common(dom, timer);
548 dom_data = ce_domain_for(ce_data->cpu); 567 mc_check_for_preempt(dom);
549 raw_spin_lock_irqsave(dom_data->domain.lock, flags); 568 raw_spin_unlock_irqrestore(dom->lock, flags);
550 __mc_ce_timer_callback(timer);
551 mc_check_for_preempt(&dom_data->domain);
552 raw_spin_unlock_irqrestore(dom_data->domain.lock, flags);
553 return HRTIMER_RESTART; 569 return HRTIMER_RESTART;
554} 570}
555 571
@@ -658,12 +674,11 @@ static void mc_task_exit(struct task_struct *task)
658 } 674 }
659 675
660 if (CRIT_LEVEL_A == tsk_mc_crit(task)) 676 if (CRIT_LEVEL_A == tsk_mc_crit(task))
661 ce_task_exit(get_task_domain(task), task); 677 mc_ce_task_exit_common(task);
662 678
663 local_irq_restore(flags); 679 local_irq_restore(flags);
664} 680}
665 681
666long __mc_ce_admit_task(struct task_struct*);
667/** 682/**
668 * mc_admit_task() - Return true if the task is valid. 683 * mc_admit_task() - Return true if the task is valid.
669 * Assumes there are no partitioned levels after level B. 684 * Assumes there are no partitioned levels after level B.
@@ -685,7 +700,7 @@ static long mc_admit_task(struct task_struct* task)
685 goto out; 700 goto out;
686 } 701 }
687 if (crit == CRIT_LEVEL_A) { 702 if (crit == CRIT_LEVEL_A) {
688 ret = __mc_ce_admit_task(task); 703 ret = mc_ce_admit_task_common(task);
689 if (ret) 704 if (ret)
690 goto out; 705 goto out;
691 } 706 }
@@ -806,12 +821,30 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
806 821
807static long mc_activate_plugin(void) 822static long mc_activate_plugin(void)
808{ 823{
824 domain_data_t *dom_data;
825 domain_t *dom;
826 domain_data_t *our_domains[NR_CPUS];
827 int cpu, n = 0;
828 long ret;
829
809#ifdef CONFIG_RELEASE_MASTER 830#ifdef CONFIG_RELEASE_MASTER
810 interrupt_cpu = atomic_read(&release_master_cpu); 831 interrupt_cpu = atomic_read(&release_master_cpu);
811 if (interrupt_cpu == NO_CPU) 832 if (interrupt_cpu == NO_CPU)
812 interrupt_cpu = 0; 833 interrupt_cpu = 0;
813#endif 834#endif
814 return ce_activate_plugin(); 835 for_each_online_cpu(cpu) {
836 BUG_ON(NR_CPUS <= n);
837 dom = cpus[cpu]->crit_entries[CRIT_LEVEL_A].domain;
838 dom_data = domain_data(dom);
839 our_domains[cpu] = dom_data;
840 n++;
841 }
842 ret = mc_ce_set_domains(n, our_domains);
843 if (ret)
844 goto out;
845 ret = mc_ce_activate_plugin_common();
846out:
847 return ret;
815} 848}
816 849
817/* 850/*
@@ -823,14 +856,14 @@ void mc_release_at(struct task_struct *ts, lt_t start)
823{ 856{
824 /* hack so that we can have CE timers start at the right time */ 857 /* hack so that we can have CE timers start at the right time */
825 if (CRIT_LEVEL_A == tsk_mc_crit(ts)) 858 if (CRIT_LEVEL_A == tsk_mc_crit(ts))
826 ce_start(ts, start); 859 mc_ce_release_at_common(ts, start);
827 else 860 else
828 release_at(ts, start); 861 release_at(ts, start);
829} 862}
830 863
831long mc_deactivate_plugin(void) 864long mc_deactivate_plugin(void)
832{ 865{
833 return ce_deactivate_plugin(); 866 return mc_ce_deactivate_plugin_common();
834} 867}
835 868
836/* ************************************************************************** 869/* **************************************************************************
@@ -843,7 +876,8 @@ long mc_deactivate_plugin(void)
843DEFINE_PER_CPU(cpu_entry_t, _mc_cpus); 876DEFINE_PER_CPU(cpu_entry_t, _mc_cpus);
844/* LVL-A */ 877/* LVL-A */
845DEFINE_PER_CPU(domain_data_t, _mc_crit_a); 878DEFINE_PER_CPU(domain_data_t, _mc_crit_a);
846DEFINE_PER_CPU(rt_domain_t, _mc_crit_a_rt); 879DEFINE_PER_CPU(raw_spinlock_t, _mc_crit_a_lock);
880DEFINE_PER_CPU(struct ce_dom_data, _mc_crit_a_ce_data);
847/* LVL-B */ 881/* LVL-B */
848DEFINE_PER_CPU(domain_data_t, _mc_crit_b); 882DEFINE_PER_CPU(domain_data_t, _mc_crit_b);
849DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt); 883DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt);
@@ -925,7 +959,8 @@ static int __init init_mc(void)
925 cpu_entry_t *entry; 959 cpu_entry_t *entry;
926 rt_domain_t *rt; 960 rt_domain_t *rt;
927 domain_data_t *dom_data; 961 domain_data_t *dom_data;
928 raw_spinlock_t *a_dom, *b_dom, *c_dom; /* For lock debugger */ 962 raw_spinlock_t *a_dom_lock, *b_dom, *c_dom; /* For lock debugger */
963 struct ce_dom_data *ce_data;
929 964
930 for_each_online_cpu(cpu) { 965 for_each_online_cpu(cpu) {
931 entry = &per_cpu(_mc_cpus, cpu); 966 entry = &per_cpu(_mc_cpus, cpu);
@@ -942,10 +977,16 @@ static int __init init_mc(void)
942#endif 977#endif
943 978
944 /* CRIT_LEVEL_A */ 979 /* CRIT_LEVEL_A */
945 dom_data = ce_domain_for(cpu); 980 dom_data = &per_cpu(_mc_crit_a, cpu);
946 ce_domain_init(/* TODO */); 981 ce_data = &per_cpu(_mc_crit_a_ce_data, cpu);
982 a_dom_lock = &per_cpu(_mc_crit_a_lock, cpu);
983 raw_spin_lock_init(a_dom_lock);
984 ce_domain_init(&dom_data->domain,
985 a_dom_lock, ce_requeue, ce_peek_and_take_ready,
986 ce_peek_and_take_ready, mc_preempt_needed,
987 ce_higher_prio, ce_data, cpu,
988 ce_timer_function);
947 init_local_domain(entry, dom_data, CRIT_LEVEL_A); 989 init_local_domain(entry, dom_data, CRIT_LEVEL_A);
948 a_dom = dom_data->domain.lock;
949 dom_data->domain.name = "LVL-A"; 990 dom_data->domain.name = "LVL-A";
950 991
951 /* CRIT_LEVEL_B */ 992 /* CRIT_LEVEL_B */
diff --git a/litmus/sched_mc_ce.c b/litmus/sched_mc_ce.c
index 77acc67d05bd..8cac7ea58f66 100644
--- a/litmus/sched_mc_ce.c
+++ b/litmus/sched_mc_ce.c
@@ -27,25 +27,81 @@
27 27
28static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; 28static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp;
29 29
30#define is_active_plugin() (litmus == &mc_ce_plugin) 30#define using_linux_plugin() (litmus == &linux_sched_plugin)
31#define get_ce_data(dom_data_ref) (dom_data_ref->domain.data) 31
32/* get a reference to domain_t for a CPU */
33#define get_domain_for(cpu) (&domains[cpu]->domain)
34
35#define get_pid_table(cpu) (&per_cpu(ce_pid_table, cpu))
36#define get_pid_entry(cpu, idx) (&(get_pid_table(cpu)->entries[idx]))
32 37
33static atomic_t start_time_set = ATOMIC_INIT(-1); 38static atomic_t start_time_set = ATOMIC_INIT(-1);
34static atomic64_t start_time = ATOMIC64_INIT(0); 39static atomic64_t start_time = ATOMIC64_INIT(0);
35static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL; 40static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL;
36 41
42/*
43 * Cache the budget along with the struct PID for a task so that we don't need
44 * to fetch its task_struct every time we check to see what should be
45 * scheduled.
46 */
47struct ce_pid_entry {
48 struct pid *pid;
49 lt_t budget;
50 /* accumulated (summed) budgets, including this one */
51 lt_t acc_time;
52 unsigned int expected_job;
53};
54
55struct ce_pid_table {
56 struct ce_pid_entry entries[CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS];
57 int num_pid_entries;
58 lt_t cycle_time;
59};
60
61DEFINE_PER_CPU(struct ce_pid_table, ce_pid_table);
37 62
38DEFINE_PER_CPU(domain_data_t, mc_ce_doms); 63/*
64 * How we get the domain for a given CPU locally. Set with the
65 * mc_ce_set_domains function. Must be done before activating plugins. Be
66 * careful when using domains as a variable elsewhere in this file.
67 */
68static domain_data_t *domains[NR_CPUS] __cacheline_aligned_in_smp;
69
70/*
71 * The domains and other data used by the MC-CE plugin when it runs alone.
72 */
73DEFINE_PER_CPU(domain_data_t, _mc_ce_doms);
39DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data); 74DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data);
40DEFINE_PER_CPU(raw_spinlock_t, _dom_locks); 75DEFINE_PER_CPU(raw_spinlock_t, _mc_ce_dom_locks);
41 76
42/* Return the address of the domain_t for this CPU, used by the 77long mc_ce_set_domains(const int n, domain_data_t *domains_in[])
43 * mixed-criticality plugin. */
44domain_data_t *ce_domain_for(int cpu)
45{ 78{
46 return &per_cpu(mc_ce_doms, cpu); 79 const int max = (NR_CPUS < n) ? NR_CPUS : n;
80 domain_data_t *new_dom = NULL;
81 int i, ret;
82 if (!using_linux_plugin()) {
83 printk(KERN_WARNING "can't set MC-CE domains when not using "
84 "Linux scheduler.\n");
85 ret = -EINVAL;
86 goto out;
87 }
88 for (i = 0; i < max; ++i) {
89 new_dom = domains_in[i];
90 domains[i] = new_dom;
91 }
92 ret = 0;
93out:
94 return ret;
47} 95}
48 96
97unsigned int mc_ce_get_expected_job(const int cpu, const int idx)
98{
99 const struct ce_pid_table *pid_table = get_pid_table(cpu);
100 BUG_ON(0 > cpu);
101 BUG_ON(0 > idx);
102 BUG_ON(pid_table->num_pid_entries <= idx);
103 return pid_table->entries[idx].expected_job;
104}
49 105
50/* 106/*
51 * Get the offset into the cycle taking the start time into account. 107 * Get the offset into the cycle taking the start time into account.
@@ -65,14 +121,12 @@ static inline lt_t get_cycle_offset(const lt_t when, const lt_t cycle_time)
65 * 121 *
66 * Do not call prepare_for_next_period on Level-A tasks! 122 * Do not call prepare_for_next_period on Level-A tasks!
67 */ 123 */
68static void mc_ce_job_completion(struct task_struct *ts) 124static void mc_ce_job_completion(domain_t *dom, struct task_struct *ts)
69{ 125{
70 const domain_data_t *dom_data = &per_cpu(mc_ce_doms, smp_processor_id()); 126 const int cpu = task_cpu(ts);
71 const struct ce_dom_data *ce_data = get_ce_data(dom_data);
72 const int idx = tsk_mc_data(ts)->mc_task.lvl_a_id; 127 const int idx = tsk_mc_data(ts)->mc_task.lvl_a_id;
73 const struct ce_dom_pid_entry *pid_entry = 128 const struct ce_pid_entry *pid_entry = get_pid_entry(cpu, idx);
74 &ce_data->pid_entries[idx]; 129 unsigned int just_finished;
75 int just_finished;
76 130
77 TRACE_TASK(ts, "completed\n"); 131 TRACE_TASK(ts, "completed\n");
78 132
@@ -87,11 +141,11 @@ static void mc_ce_job_completion(struct task_struct *ts)
87 if (just_finished < pid_entry->expected_job) { 141 if (just_finished < pid_entry->expected_job) {
88 /* this job is already released because it's running behind */ 142 /* this job is already released because it's running behind */
89 set_rt_flags(ts, RT_F_RUNNING); 143 set_rt_flags(ts, RT_F_RUNNING);
90 TRACE_TASK(ts, "appears behind: the expected job is %d but " 144 TRACE_TASK(ts, "appears behind: the expected job is %u but "
91 "job %d just completed\n", 145 "job %u just completed\n",
92 pid_entry->expected_job, just_finished); 146 pid_entry->expected_job, just_finished);
93 } else if (pid_entry->expected_job < just_finished) { 147 } else if (pid_entry->expected_job < just_finished) {
94 printk(KERN_CRIT "job %d completed in expected job %d which " 148 printk(KERN_CRIT "job %u completed in expected job %u which "
95 "seems too early\n", just_finished, 149 "seems too early\n", just_finished,
96 pid_entry->expected_job); 150 pid_entry->expected_job);
97 BUG(); 151 BUG();
@@ -109,30 +163,30 @@ static void mc_ce_job_completion(struct task_struct *ts)
109static int mc_ce_schedule_at(const domain_t *dom, lt_t offset) 163static int mc_ce_schedule_at(const domain_t *dom, lt_t offset)
110{ 164{
111 const struct ce_dom_data *ce_data = dom->data; 165 const struct ce_dom_data *ce_data = dom->data;
112 const struct ce_dom_pid_entry *pid_entry = NULL; 166 struct ce_pid_table *pid_table = get_pid_table(ce_data->cpu);
113 int i; 167 const struct ce_pid_entry *pid_entry = NULL;
168 int idx;
114 169
115 BUG_ON(ce_data->cycle_time < 1); 170 BUG_ON(pid_table->cycle_time < 1);
116 BUG_ON(ce_data->num_pid_entries < 1); 171 BUG_ON(pid_table->num_pid_entries < 1);
117 172
118 for (i = 0; i < ce_data->num_pid_entries; ++i) { 173 for (idx = 0; idx < pid_table->num_pid_entries; ++idx) {
119 pid_entry = &ce_data->pid_entries[i]; 174 pid_entry = &pid_table->entries[idx];
120 if (offset < pid_entry->acc_time) { 175 if (offset < pid_entry->acc_time) {
121 /* found task to schedule in this window */ 176 /* found task to schedule in this window */
122 break; 177 break;
123 } 178 }
124 } 179 }
125 /* can only happen if cycle_time is not right */ 180 /* can only happen if cycle_time is not right */
126 BUG_ON(pid_entry->acc_time > ce_data->cycle_time); 181 BUG_ON(pid_entry->acc_time > pid_table->cycle_time);
127 TRACE("schedule at returned task %d for CPU %d\n", i, ce_data->cpu); 182 TRACE("schedule at returning task %d for CPU %d\n", idx, ce_data->cpu);
128 return i; 183 return idx;
129} 184}
130 185
131static struct task_struct *mc_ce_schedule(struct task_struct *prev) 186static struct task_struct *mc_ce_schedule(struct task_struct *prev)
132{ 187{
133 domain_data_t *dom_data = &per_cpu(mc_ce_doms, smp_processor_id()); 188 domain_t *dom = get_domain_for(smp_processor_id());
134 domain_t *dom = &dom_data->domain; 189 struct ce_dom_data *ce_data = dom->data;
135 struct ce_dom_data *ce_data = get_ce_data(dom_data);
136 struct task_struct *next = NULL; 190 struct task_struct *next = NULL;
137 int exists, sleep, should_sched_exists, should_sched_blocked, 191 int exists, sleep, should_sched_exists, should_sched_blocked,
138 should_sched_asleep; 192 should_sched_asleep;
@@ -150,7 +204,7 @@ static struct task_struct *mc_ce_schedule(struct task_struct *prev)
150 TRACE("exists: %d, sleep: %d\n", exists, sleep); 204 TRACE("exists: %d, sleep: %d\n", exists, sleep);
151 205
152 if (sleep) 206 if (sleep)
153 mc_ce_job_completion(ce_data->scheduled); 207 mc_ce_job_completion(dom, ce_data->scheduled);
154 208
155 /* these checks must go after the call to mc_ce_job_completion in case 209 /* these checks must go after the call to mc_ce_job_completion in case
156 * a late task needs to be scheduled again right away and its the only 210 * a late task needs to be scheduled again right away and its the only
@@ -181,8 +235,8 @@ static struct task_struct *mc_ce_schedule(struct task_struct *prev)
181 235
182static void mc_ce_finish_switch(struct task_struct *prev) 236static void mc_ce_finish_switch(struct task_struct *prev)
183{ 237{
184 domain_data_t *dom_data = &per_cpu(mc_ce_doms, smp_processor_id()); 238 domain_t *dom = get_domain_for(smp_processor_id());
185 struct ce_dom_data *ce_data = get_ce_data(dom_data); 239 struct ce_dom_data *ce_data = dom->data;
186 240
187 TRACE("finish switch\n"); 241 TRACE("finish switch\n");
188 242
@@ -197,14 +251,17 @@ static void mc_ce_finish_switch(struct task_struct *prev)
197 * Here we look up the task's PID structure and save it in the proper slot on 251 * Here we look up the task's PID structure and save it in the proper slot on
198 * the CPU this task will run on. 252 * the CPU this task will run on.
199 */ 253 */
200long __mc_ce_admit_task(struct task_struct *ts) 254long mc_ce_admit_task_common(struct task_struct *ts)
201{ 255{
202 domain_data_t *dom_data = &per_cpu(mc_ce_doms, get_partition(ts)); 256 domain_t *dom = get_domain_for(get_partition(ts));
203 struct ce_dom_data *ce_data = get_ce_data(dom_data); 257 struct ce_dom_data *ce_data = dom->data;
204 struct mc_data *mcd = tsk_mc_data(ts); 258 struct mc_data *mcd = tsk_mc_data(ts);
205 struct pid *pid = NULL; 259 struct pid *pid = NULL;
206 long retval = -EINVAL; 260 long retval = -EINVAL;
207 const int lvl_a_id = mcd->mc_task.lvl_a_id; 261 const int lvl_a_id = mcd->mc_task.lvl_a_id;
262 struct ce_pid_table *pid_table = get_pid_table(ce_data->cpu);
263
264 BUG_ON(get_partition(ts) != ce_data->cpu);
208 265
209 /* check the task has migrated to the right CPU (like in sched_cedf) */ 266 /* check the task has migrated to the right CPU (like in sched_cedf) */
210 if (task_cpu(ts) != get_partition(ts)) { 267 if (task_cpu(ts) != get_partition(ts)) {
@@ -228,26 +285,26 @@ long __mc_ce_admit_task(struct task_struct *ts)
228 goto out; 285 goto out;
229 } 286 }
230 287
231 if (lvl_a_id >= ce_data->num_pid_entries) { 288 if (lvl_a_id >= pid_table->num_pid_entries) {
232 printk(KERN_INFO "litmus: level A id greater than expected " 289 printk(KERN_INFO "litmus: level A id greater than expected "
233 "number of tasks %d for %d cpu %d\n", 290 "number of tasks %d for %d cpu %d\n",
234 ce_data->num_pid_entries, ts->pid, 291 pid_table->num_pid_entries, ts->pid,
235 get_partition(ts)); 292 get_partition(ts));
236 goto out_put_pid; 293 goto out_put_pid;
237 } 294 }
238 if (ce_data->pid_entries[lvl_a_id].pid) { 295 if (pid_table->entries[lvl_a_id].pid) {
239 printk(KERN_INFO "litmus: have saved pid info id: %d cpu: %d\n", 296 printk(KERN_INFO "litmus: have saved pid info id: %d cpu: %d\n",
240 lvl_a_id, get_partition(ts)); 297 lvl_a_id, get_partition(ts));
241 goto out_put_pid; 298 goto out_put_pid;
242 } 299 }
243 if (get_exec_cost(ts) >= ce_data->pid_entries[lvl_a_id].budget) { 300 if (get_exec_cost(ts) >= pid_table->entries[lvl_a_id].budget) {
244 printk(KERN_INFO "litmus: execution cost %llu is larger than " 301 printk(KERN_INFO "litmus: execution cost %llu is larger than "
245 "the budget %llu\n", 302 "the budget %llu\n",
246 get_exec_cost(ts), 303 get_exec_cost(ts),
247 ce_data->pid_entries[lvl_a_id].budget); 304 pid_table->entries[lvl_a_id].budget);
248 goto out_put_pid; 305 goto out_put_pid;
249 } 306 }
250 ce_data->pid_entries[lvl_a_id].pid = pid; 307 pid_table->entries[lvl_a_id].pid = pid;
251 retval = 0; 308 retval = 0;
252 /* don't call put_pid if we are successful */ 309 /* don't call put_pid if we are successful */
253 goto out; 310 goto out;
@@ -260,11 +317,10 @@ out:
260 317
261static long mc_ce_admit_task(struct task_struct *ts) 318static long mc_ce_admit_task(struct task_struct *ts)
262{ 319{
263 domain_data_t *dom_data = &per_cpu(mc_ce_doms, get_partition(ts)); 320 domain_t *dom = get_domain_for(get_partition(ts));
264 domain_t *dom = &dom_data->domain;
265 unsigned long flags, retval; 321 unsigned long flags, retval;
266 raw_spin_lock_irqsave(dom->lock, flags); 322 raw_spin_lock_irqsave(dom->lock, flags);
267 retval = __mc_ce_admit_task(ts); 323 retval = mc_ce_admit_task_common(ts);
268 raw_spin_unlock_irqrestore(dom->lock, flags); 324 raw_spin_unlock_irqrestore(dom->lock, flags);
269 return retval; 325 return retval;
270} 326}
@@ -276,27 +332,26 @@ static long mc_ce_admit_task(struct task_struct *ts)
276 */ 332 */
277static void mc_ce_task_new(struct task_struct *ts, int on_rq, int running) 333static void mc_ce_task_new(struct task_struct *ts, int on_rq, int running)
278{ 334{
279 domain_data_t *dom_data = &per_cpu(mc_ce_doms, task_cpu(ts)); 335 const int cpu = task_cpu(ts);
280 domain_t *dom = &dom_data->domain; 336 domain_t *dom = get_domain_for(cpu);
281 struct ce_dom_data *ce_data = get_ce_data(dom_data); 337 struct ce_dom_data *ce_data = dom->data;
338 struct ce_pid_table *pid_table = get_pid_table(cpu);
282 struct pid *pid_should_be_running; 339 struct pid *pid_should_be_running;
283 struct ce_dom_pid_entry *pid_entry; 340 struct ce_pid_entry *pid_entry;
284 unsigned long flags; 341 unsigned long flags;
285 int idx, should_be_running; 342 int idx, should_be_running;
286 lt_t offset; 343 lt_t offset;
287 344
288 /* have to call mc_ce_schedule_at because the task only gets a PID
289 * entry after calling admit_task */
290
291 raw_spin_lock_irqsave(dom->lock, flags); 345 raw_spin_lock_irqsave(dom->lock, flags);
292 pid_entry = &ce_data->pid_entries[tsk_mc_data(ts)->mc_task.lvl_a_id]; 346 pid_entry = get_pid_entry(cpu, tsk_mc_data(ts)->mc_task.lvl_a_id);
293 /* initialize some task state */ 347 /* initialize some task state */
294 set_rt_flags(ts, RT_F_RUNNING); 348 set_rt_flags(ts, RT_F_RUNNING);
295 tsk_rt(ts)->job_params.job_no = 1;
296 349
297 offset = get_cycle_offset(litmus_clock(), ce_data->cycle_time); 350 /* have to call mc_ce_schedule_at because the task only gets a PID
351 * entry after calling admit_task */
352 offset = get_cycle_offset(litmus_clock(), pid_table->cycle_time);
298 idx = mc_ce_schedule_at(dom, offset); 353 idx = mc_ce_schedule_at(dom, offset);
299 pid_should_be_running = ce_data->pid_entries[idx].pid; 354 pid_should_be_running = get_pid_entry(cpu, idx)->pid;
300 rcu_read_lock(); 355 rcu_read_lock();
301 should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID)); 356 should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID));
302 rcu_read_unlock(); 357 rcu_read_unlock();
@@ -323,9 +378,8 @@ static void mc_ce_task_new(struct task_struct *ts, int on_rq, int running)
323 */ 378 */
324static void mc_ce_task_wake_up(struct task_struct *ts) 379static void mc_ce_task_wake_up(struct task_struct *ts)
325{ 380{
326 domain_data_t *dom_data = &per_cpu(mc_ce_doms, smp_processor_id()); 381 domain_t *dom = get_domain_for(get_partition(ts));
327 domain_t *dom = &dom_data->domain; 382 struct ce_dom_data *ce_data = dom->data;
328 struct ce_dom_data *ce_data = get_ce_data(dom_data);
329 unsigned long flags; 383 unsigned long flags;
330 384
331 TRACE_TASK(ts, "wake up\n"); 385 TRACE_TASK(ts, "wake up\n");
@@ -349,26 +403,27 @@ static void mc_ce_task_block(struct task_struct *ts)
349/* 403/*
350 * Called when a task switches from RT mode back to normal mode. 404 * Called when a task switches from RT mode back to normal mode.
351 */ 405 */
352void mc_ce_task_exit(struct task_struct *ts) 406void mc_ce_task_exit_common(struct task_struct *ts)
353{ 407{
354 domain_data_t *dom_data = &per_cpu(mc_ce_doms, get_partition(ts)); 408 domain_t *dom = get_domain_for(get_partition(ts));
355 domain_t *dom = &dom_data->domain; 409 struct ce_dom_data *ce_data = dom->data;
356 struct ce_dom_data *ce_data = get_ce_data(dom_data);
357 unsigned long flags; 410 unsigned long flags;
358 struct pid *pid; 411 struct pid *pid;
359 const int lvl_a_id = tsk_mc_data(ts)->mc_task.lvl_a_id; 412 const int lvl_a_id = tsk_mc_data(ts)->mc_task.lvl_a_id;
413 struct ce_pid_table *pid_table = get_pid_table(ce_data->cpu);
360 414
361 TRACE_TASK(ts, "exited\n"); 415 TRACE_TASK(ts, "exited\n");
362 416
363 BUG_ON(task_cpu(ts) != get_partition(ts)); 417 BUG_ON(task_cpu(ts) != get_partition(ts));
364 BUG_ON(CRIT_LEVEL_A != tsk_mc_crit(ts)); 418 BUG_ON(CRIT_LEVEL_A != tsk_mc_crit(ts));
365 BUG_ON(lvl_a_id >= ce_data->num_pid_entries); 419 BUG_ON(lvl_a_id >= pid_table->num_pid_entries);
420 BUG_ON(ce_data->cpu != task_cpu(ts));
366 421
367 raw_spin_lock_irqsave(dom->lock, flags); 422 raw_spin_lock_irqsave(dom->lock, flags);
368 pid = ce_data->pid_entries[lvl_a_id].pid; 423 pid = pid_table->entries[lvl_a_id].pid;
369 BUG_ON(!pid); 424 BUG_ON(!pid);
370 put_pid(pid); 425 put_pid(pid);
371 ce_data->pid_entries[lvl_a_id].pid = NULL; 426 pid_table->entries[lvl_a_id].pid = NULL;
372 if (ce_data->scheduled == ts) 427 if (ce_data->scheduled == ts)
373 ce_data->scheduled = NULL; 428 ce_data->scheduled = NULL;
374 if (ce_data->should_schedule == ts) 429 if (ce_data->should_schedule == ts)
@@ -380,29 +435,27 @@ void mc_ce_task_exit(struct task_struct *ts)
380 * Timer stuff 435 * Timer stuff
381 **********************************************************/ 436 **********************************************************/
382 437
383void __mc_ce_timer_callback(struct hrtimer *timer) 438void mc_ce_timer_callback_common(domain_t *dom, struct hrtimer *timer)
384{ 439{
385 /* relative and absolute times for cycles */ 440 /* relative and absolute times for cycles */
386 lt_t now, offset_rel, cycle_start_abs, next_timer_abs; 441 lt_t now, offset_rel, cycle_start_abs, next_timer_abs;
387 struct task_struct *should_schedule; 442 struct task_struct *should_schedule;
388 struct ce_dom_pid_entry *pid_entry; 443 struct ce_pid_table *pid_table;
444 struct ce_pid_entry *pid_entry;
389 struct ce_dom_data *ce_data; 445 struct ce_dom_data *ce_data;
390 domain_data_t *dom_data;
391 domain_t *dom;
392 int idx, budget_overrun; 446 int idx, budget_overrun;
393 447
394 ce_data = container_of(timer, struct ce_dom_data, timer); 448 ce_data = dom->data;
395 dom_data = &per_cpu(mc_ce_doms, ce_data->cpu); 449 pid_table = get_pid_table(ce_data->cpu);
396 dom = &dom_data->domain;
397 450
398 /* Based off of the current time, figure out the offset into the cycle 451 /* Based off of the current time, figure out the offset into the cycle
399 * and the cycle's start time, and determine what should be scheduled. 452 * and the cycle's start time, and determine what should be scheduled.
400 */ 453 */
401 now = litmus_clock(); 454 now = litmus_clock();
402 offset_rel = get_cycle_offset(now, ce_data->cycle_time); 455 offset_rel = get_cycle_offset(now, pid_table->cycle_time);
403 cycle_start_abs = now - offset_rel; 456 cycle_start_abs = now - offset_rel;
404 idx = mc_ce_schedule_at(dom, offset_rel); 457 idx = mc_ce_schedule_at(dom, offset_rel);
405 pid_entry = &ce_data->pid_entries[idx]; 458 pid_entry = get_pid_entry(ce_data->cpu, idx);
406 /* set the timer to fire at the next cycle start */ 459 /* set the timer to fire at the next cycle start */
407 next_timer_abs = cycle_start_abs + pid_entry->acc_time; 460 next_timer_abs = cycle_start_abs + pid_entry->acc_time;
408 hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs)); 461 hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs));
@@ -426,8 +479,8 @@ void __mc_ce_timer_callback(struct hrtimer *timer)
426 budget_overrun = pid_entry->expected_job != 479 budget_overrun = pid_entry->expected_job !=
427 tsk_rt(should_schedule)->job_params.job_no; 480 tsk_rt(should_schedule)->job_params.job_no;
428 if (budget_overrun) 481 if (budget_overrun)
429 TRACE_TASK(should_schedule, "timer expected job number: %d " 482 TRACE_TASK(should_schedule, "timer expected job number: %u "
430 "but current job: %d\n", 483 "but current job: %u\n",
431 pid_entry->expected_job, 484 pid_entry->expected_job,
432 tsk_rt(should_schedule)->job_params.job_no); 485 tsk_rt(should_schedule)->job_params.job_no);
433 } 486 }
@@ -452,17 +505,15 @@ static enum hrtimer_restart mc_ce_timer_callback(struct hrtimer *timer)
452{ 505{
453 struct ce_dom_data *ce_data; 506 struct ce_dom_data *ce_data;
454 unsigned long flags; 507 unsigned long flags;
455 domain_data_t *dom_data;
456 domain_t *dom; 508 domain_t *dom;
457 509
458 ce_data = container_of(timer, struct ce_dom_data, timer); 510 ce_data = container_of(timer, struct ce_dom_data, timer);
459 dom_data = &per_cpu(mc_ce_doms, ce_data->cpu); 511 dom = get_domain_for(ce_data->cpu);
460 dom = &dom_data->domain;
461 512
462 TRACE("timer callback on CPU %d (before lock)\n", ce_data->cpu); 513 TRACE("timer callback on CPU %d (before lock)\n", ce_data->cpu);
463 514
464 raw_spin_lock_irqsave(dom->lock, flags); 515 raw_spin_lock_irqsave(dom->lock, flags);
465 __mc_ce_timer_callback(timer); 516 mc_ce_timer_callback_common(dom, timer);
466 517
467 if (ce_data->scheduled != ce_data->should_schedule) 518 if (ce_data->scheduled != ce_data->should_schedule)
468 preempt_if_preemptable(ce_data->scheduled, ce_data->cpu); 519 preempt_if_preemptable(ce_data->scheduled, ce_data->cpu);
@@ -478,14 +529,14 @@ static enum hrtimer_restart mc_ce_timer_callback(struct hrtimer *timer)
478static int cancel_all_timers(void) 529static int cancel_all_timers(void)
479{ 530{
480 struct ce_dom_data *ce_data; 531 struct ce_dom_data *ce_data;
481 domain_data_t *dom_data; 532 domain_t *dom;
482 int cpu, ret = 0, cancel_res; 533 int cpu, cancel_res, ret = 0;
483 534
484 TRACE("cancel all timers\n"); 535 TRACE("cancel all timers\n");
485 536
486 for_each_online_cpu(cpu) { 537 for_each_online_cpu(cpu) {
487 dom_data = &per_cpu(mc_ce_doms, cpu); 538 dom = get_domain_for(cpu);
488 ce_data = get_ce_data(dom_data); 539 ce_data = dom->data;
489 ce_data->should_schedule = NULL; 540 ce_data->should_schedule = NULL;
490 cancel_res = hrtimer_cancel(&ce_data->timer); 541 cancel_res = hrtimer_cancel(&ce_data->timer);
491 atomic_set(&ce_data->timer_info.state, 542 atomic_set(&ce_data->timer_info.state,
@@ -502,20 +553,22 @@ static int cancel_all_timers(void)
502 */ 553 */
503static void arm_all_timers(void) 554static void arm_all_timers(void)
504{ 555{
556 domain_t *dom;
505 struct ce_dom_data *ce_data; 557 struct ce_dom_data *ce_data;
506 domain_data_t *dom_data; 558 struct ce_pid_table *pid_table;
507 int cpu, idx; 559 int cpu, idx;
508 const lt_t start = atomic64_read(&start_time); 560 const lt_t start = atomic64_read(&start_time);
509 561
510 TRACE("arm all timers\n"); 562 TRACE("arm all timers\n");
511 563
512 for_each_online_cpu(cpu) { 564 for_each_online_cpu(cpu) {
513 dom_data = &per_cpu(mc_ce_doms, cpu); 565 dom = get_domain_for(cpu);
514 ce_data = get_ce_data(dom_data); 566 ce_data = dom->data;
515 if (0 == ce_data->num_pid_entries) 567 pid_table = get_pid_table(cpu);
568 if (0 == pid_table->num_pid_entries)
516 continue; 569 continue;
517 for (idx = 0; idx < ce_data->num_pid_entries; idx++) { 570 for (idx = 0; idx < pid_table->num_pid_entries; idx++) {
518 ce_data->pid_entries[idx].expected_job = 0; 571 pid_table->entries[idx].expected_job = 1;
519 } 572 }
520 TRACE("arming timer for CPU %d\n", cpu); 573 TRACE("arming timer for CPU %d\n", cpu);
521 hrtimer_start_on(cpu, &ce_data->timer_info, &ce_data->timer, 574 hrtimer_start_on(cpu, &ce_data->timer_info, &ce_data->timer,
@@ -528,7 +581,7 @@ static void arm_all_timers(void)
528 * call this. We can re-set our notion of the CE period start to make 581 * call this. We can re-set our notion of the CE period start to make
529 * the schedule look pretty. 582 * the schedule look pretty.
530 */ 583 */
531void mc_ce_release_at(struct task_struct *ts, lt_t start) 584void mc_ce_release_at_common(struct task_struct *ts, lt_t start)
532{ 585{
533 TRACE_TASK(ts, "release at\n"); 586 TRACE_TASK(ts, "release at\n");
534 if (atomic_inc_and_test(&start_time_set)) { 587 if (atomic_inc_and_test(&start_time_set)) {
@@ -540,15 +593,15 @@ void mc_ce_release_at(struct task_struct *ts, lt_t start)
540 atomic_dec(&start_time_set); 593 atomic_dec(&start_time_set);
541} 594}
542 595
543long mc_ce_activate_plugin(void) 596long mc_ce_activate_plugin_common(void)
544{ 597{
545 struct ce_dom_data *ce_data; 598 struct ce_dom_data *ce_data;
546 domain_data_t *dom_data; 599 domain_t *dom;
547 int cpu; 600 int cpu;
548 601
549 for_each_online_cpu(cpu) { 602 for_each_online_cpu(cpu) {
550 dom_data = &per_cpu(mc_ce_doms, cpu); 603 dom = get_domain_for(cpu);
551 ce_data = get_ce_data(dom_data); 604 ce_data = dom->data;
552 ce_data->scheduled = NULL; 605 ce_data->scheduled = NULL;
553 ce_data->should_schedule = NULL; 606 ce_data->should_schedule = NULL;
554 } 607 }
@@ -560,33 +613,54 @@ long mc_ce_activate_plugin(void)
560 return 0; 613 return 0;
561} 614}
562 615
616static long mc_ce_activate_plugin(void)
617{
618 domain_data_t *our_domains[NR_CPUS];
619 int cpu, n = 0;
620 long ret;
621
622 for_each_online_cpu(cpu) {
623 BUG_ON(NR_CPUS <= n);
624 our_domains[cpu] = &per_cpu(_mc_ce_doms, cpu);
625 n++;
626 }
627 ret = mc_ce_set_domains(n, our_domains);
628 if (ret)
629 goto out;
630 ret = mc_ce_activate_plugin_common();
631out:
632 return ret;
633}
634
563static void clear_pid_entries(void) 635static void clear_pid_entries(void)
564{ 636{
637 struct ce_pid_table *pid_table = NULL;
565 int cpu, entry; 638 int cpu, entry;
566 domain_data_t *dom_data;
567 struct ce_dom_data *ce_data;
568 639
569 for_each_online_cpu(cpu) { 640 for_each_online_cpu(cpu) {
570 dom_data = &per_cpu(mc_ce_doms, cpu); 641 pid_table = get_pid_table(cpu);
571 ce_data = get_ce_data(dom_data); 642 pid_table->num_pid_entries = 0;
572 ce_data->num_pid_entries = 0; 643 pid_table->cycle_time = 0;
573 ce_data->cycle_time = 0;
574 for (entry = 0; entry < CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS; 644 for (entry = 0; entry < CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS;
575 ++entry) { 645 ++entry) {
576 if (NULL != ce_data->pid_entries[entry].pid) { 646 if (NULL != pid_table->entries[entry].pid) {
577 put_pid(ce_data->pid_entries[entry].pid); 647 put_pid(pid_table->entries[entry].pid);
578 ce_data->pid_entries[entry].pid = NULL; 648 pid_table->entries[entry].pid = NULL;
579 } 649 }
580 ce_data->pid_entries[entry].budget = 0; 650 pid_table->entries[entry].budget = 0;
581 ce_data->pid_entries[entry].acc_time = 0; 651 pid_table->entries[entry].acc_time = 0;
582 ce_data->pid_entries[entry].expected_job = 0; 652 pid_table->entries[entry].expected_job = 1;
583 } 653 }
584 } 654 }
585} 655}
586 656
587long mc_ce_deactivate_plugin(void) 657long mc_ce_deactivate_plugin_common(void)
588{ 658{
659 int cpu;
589 cancel_all_timers(); 660 cancel_all_timers();
661 for_each_online_cpu(cpu) {
662 domains[cpu] = NULL;
663 }
590 return 0; 664 return 0;
591} 665}
592 666
@@ -596,43 +670,33 @@ static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp = {
596 .admit_task = mc_ce_admit_task, 670 .admit_task = mc_ce_admit_task,
597 .task_new = mc_ce_task_new, 671 .task_new = mc_ce_task_new,
598 .complete_job = complete_job, 672 .complete_job = complete_job,
599 .release_at = mc_ce_release_at, 673 .release_at = mc_ce_release_at_common,
600 .task_exit = mc_ce_task_exit, 674 .task_exit = mc_ce_task_exit_common,
601 .schedule = mc_ce_schedule, 675 .schedule = mc_ce_schedule,
602 .finish_switch = mc_ce_finish_switch, 676 .finish_switch = mc_ce_finish_switch,
603 .task_wake_up = mc_ce_task_wake_up, 677 .task_wake_up = mc_ce_task_wake_up,
604 .task_block = mc_ce_task_block, 678 .task_block = mc_ce_task_block,
605 .activate_plugin = mc_ce_activate_plugin, 679 .activate_plugin = mc_ce_activate_plugin,
606 .deactivate_plugin = mc_ce_deactivate_plugin, 680 .deactivate_plugin = mc_ce_deactivate_plugin_common,
607}; 681};
608 682
609int mc_preempt_needed(domain_t*, struct task_struct*);
610static int setup_proc(void); 683static int setup_proc(void);
611static int __init init_sched_mc_ce(void) 684static int __init init_sched_mc_ce(void)
612{ 685{
613 struct ce_dom_data *ce_data;
614 raw_spinlock_t *ce_lock; 686 raw_spinlock_t *ce_lock;
615 domain_data_t *dom_data; 687 domain_data_t *dom_data;
616 domain_t *dom; 688 domain_t *dom;
617 int cpu, err; 689 int cpu, err;
618 690
619 for_each_online_cpu(cpu) { 691 for_each_online_cpu(cpu) {
620 ce_lock = &per_cpu(_dom_locks, cpu); 692 domains[cpu] = NULL;
693 ce_lock = &per_cpu(_mc_ce_dom_locks, cpu);
621 raw_spin_lock_init(ce_lock); 694 raw_spin_lock_init(ce_lock);
622 dom_data = &per_cpu(mc_ce_doms, cpu); 695 dom_data = &per_cpu(_mc_ce_doms, cpu);
623 dom = &dom_data->domain; 696 dom = &dom_data->domain;
624 /* initialize the domain. the ce_ functions are for the MC 697 ce_domain_init(dom, ce_lock, NULL, NULL, NULL, NULL, NULL,
625 * plugin */ 698 &per_cpu(_mc_ce_dom_data, cpu), cpu,
626 /* move into ce_domain_init */ 699 mc_ce_timer_callback);
627 domain_init(dom, ce_lock, ce_requeue, ce_peek_and_take_ready,
628 ce_peek_and_take_ready, mc_preempt_needed,
629 ce_higher_prio);
630 dom->data = &per_cpu(_mc_ce_dom_data, cpu);
631 ce_data = get_ce_data(dom_data);
632 hrtimer_init(&ce_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
633 hrtimer_start_on_info_init(&ce_data->timer_info);
634 ce_data->cpu = cpu;
635 ce_data->timer.function = mc_ce_timer_callback;
636 } 700 }
637 clear_pid_entries(); 701 clear_pid_entries();
638 err = setup_proc(); 702 err = setup_proc();
@@ -674,7 +738,7 @@ out:
674#define PID_SPACE 15 738#define PID_SPACE 15
675#define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN) 739#define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN)
676static int write_pid_entry(char *page, const int count, const int cpu, 740static int write_pid_entry(char *page, const int count, const int cpu,
677 const int task, struct ce_dom_pid_entry *pid_entry) 741 const int task, struct ce_pid_entry *pid_entry)
678{ 742{
679 static char task_info[TASK_INFO_BUF]; 743 static char task_info[TASK_INFO_BUF];
680 struct task_struct *ts; 744 struct task_struct *ts;
@@ -731,8 +795,7 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count,
731 int *eof, void *data) 795 int *eof, void *data)
732{ 796{
733 int n = 0, err, cpu, t; 797 int n = 0, err, cpu, t;
734 struct ce_dom_data *ce_data; 798 struct ce_pid_table *pid_table;
735 domain_data_t *dom_data;
736 799
737 if (off > 0) { 800 if (off > 0) {
738 printk(KERN_INFO "litmus: MC-CE called read with off > 0\n"); 801 printk(KERN_INFO "litmus: MC-CE called read with off > 0\n");
@@ -740,11 +803,10 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count,
740 } 803 }
741 804
742 for_each_online_cpu(cpu) { 805 for_each_online_cpu(cpu) {
743 dom_data = &per_cpu(mc_ce_doms, cpu); 806 pid_table = get_pid_table(cpu);
744 ce_data = get_ce_data(dom_data); 807 for (t = 0; t < pid_table->num_pid_entries; ++t) {
745 for (t = 0; t < ce_data->num_pid_entries; ++t) {
746 err = write_pid_entry(page + n, count - n, 808 err = write_pid_entry(page + n, count - n,
747 cpu, t, &ce_data->pid_entries[t]); 809 cpu, t, get_pid_entry(cpu, t));
748 if (err < 0) { 810 if (err < 0) {
749 n = -ENOSPC; 811 n = -ENOSPC;
750 goto out; 812 goto out;
@@ -781,9 +843,8 @@ static int skip_comment(const char *buf, const unsigned long max)
781#define BUDGET_THRESHOLD 5000000ULL 843#define BUDGET_THRESHOLD 5000000ULL
782static int setup_pid_entry(const int cpu, const int task, const lt_t budget) 844static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
783{ 845{
784 domain_data_t *dom_data = &per_cpu(mc_ce_doms, cpu); 846 struct ce_pid_table *pid_table = get_pid_table(cpu);
785 struct ce_dom_data *ce_data = get_ce_data(dom_data); 847 struct ce_pid_entry *new_entry = NULL;
786 struct ce_dom_pid_entry *new_entry;
787 int err = 0; 848 int err = 0;
788 849
789 /* check the inputs */ 850 /* check the inputs */
@@ -801,20 +862,20 @@ static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
801 "MC-CE task; that might be an issue.\n"); 862 "MC-CE task; that might be an issue.\n");
802 } 863 }
803 /* check that we have space for a new entry */ 864 /* check that we have space for a new entry */
804 if (CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS <= ce_data->num_pid_entries) { 865 if (CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS <= pid_table->num_pid_entries) {
805 printk(KERN_INFO "litmus: too many MC-CE tasks for cpu " 866 printk(KERN_INFO "litmus: too many MC-CE tasks for cpu "
806 "%d\n", cpu); 867 "%d\n", cpu);
807 err = -EINVAL; 868 err = -EINVAL;
808 goto out; 869 goto out;
809 } 870 }
810 /* add the new entry */ 871 /* add the new entry */
811 new_entry = &ce_data->pid_entries[ce_data->num_pid_entries]; 872 new_entry = get_pid_entry(cpu, pid_table->num_pid_entries);
812 BUG_ON(NULL != new_entry->pid); 873 BUG_ON(NULL != new_entry->pid);
813 new_entry->budget = budget; 874 new_entry->budget = budget;
814 new_entry->acc_time = ce_data->cycle_time + budget; 875 new_entry->acc_time = pid_table->cycle_time + budget;
815 /* update the domain entry */ 876 /* update the domain entry */
816 ce_data->cycle_time += budget; 877 pid_table->cycle_time += budget;
817 ce_data->num_pid_entries++; 878 pid_table->num_pid_entries++;
818out: 879out:
819 return err; 880 return err;
820} 881}
@@ -835,9 +896,9 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer,
835 int cpu, task, cnt = 0, chars_read, converted, err; 896 int cpu, task, cnt = 0, chars_read, converted, err;
836 lt_t budget; 897 lt_t budget;
837 898
838 if (is_active_plugin()) { 899 if (!using_linux_plugin()) {
839 printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin " 900 printk(KERN_INFO "litmus: can only edit MC-CE proc under Linux "
840 "active\n"); 901 "plugin\n");
841 cnt = -EINVAL; 902 cnt = -EINVAL;
842 goto out; 903 goto out;
843 } 904 }