diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-09-27 14:47:26 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-09-27 14:47:26 -0400 |
commit | f21e1d0ef90c2e88ae6a563afc31ea601ed968c7 (patch) | |
tree | d7a0cf75344c890c81fbd402f0da1764937eebc8 /litmus/sched_mc.c | |
parent | 2fe725ef2142dd6c1bbf72e8d1b0a6f7e885d7ed (diff) |
Timer merging
Diffstat (limited to 'litmus/sched_mc.c')
-rw-r--r-- | litmus/sched_mc.c | 339 |
1 files changed, 214 insertions, 125 deletions
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c index 577e7d36faf5..30898246ea38 100644 --- a/litmus/sched_mc.c +++ b/litmus/sched_mc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <litmus/sched_trace.h> | 22 | #include <litmus/sched_trace.h> |
23 | #include <litmus/domain.h> | 23 | #include <litmus/domain.h> |
24 | #include <litmus/bheap.h> | 24 | #include <litmus/bheap.h> |
25 | #include <litmus/event_group.h> | ||
25 | 26 | ||
26 | #include <litmus/sched_mc.h> | 27 | #include <litmus/sched_mc.h> |
27 | 28 | ||
@@ -34,85 +35,84 @@ | |||
34 | * @timer For ghost task budget enforcement | 35 | * @timer For ghost task budget enforcement |
35 | * @node Used to sort crit_entries by preemptability in global domains | 36 | * @node Used to sort crit_entries by preemptability in global domains |
36 | */ | 37 | */ |
37 | typedef struct { | 38 | struct crit_entry { |
38 | enum crit_level level; | 39 | enum crit_level level; |
39 | struct task_struct* linked; | 40 | struct task_struct* linked; |
40 | domain_t* domain; | 41 | struct domain* domain; |
41 | int usable; | 42 | int usable; |
43 | #ifdef CONFIG_MERGE_TIMERS | ||
44 | struct rt_event event; | ||
45 | #else | ||
42 | struct hrtimer timer; | 46 | struct hrtimer timer; |
47 | #endif | ||
43 | struct bheap_node* node; | 48 | struct bheap_node* node; |
44 | atomic_t dirty; | 49 | }; |
45 | } crit_entry_t; | ||
46 | 50 | ||
47 | /** | 51 | /** |
48 | * cpu_entry_t - State of a CPU for the entire MC system | 52 | * struct cpu_entry - State of a CPU for the entire MC system |
49 | * @cpu CPU id | 53 | * @cpu CPU id |
50 | * @scheduled Task that is physically running | 54 | * @scheduled Task that is physically running |
51 | * @linked Task that should be running / is logically running | 55 | * @linked Task that should be running / is logically running |
52 | * @lock For serialization | 56 | * @lock For serialization |
53 | * @crit_entries Array of CPU state per criticality level | 57 | * @crit_entries Array of CPU state per criticality level |
54 | */ | 58 | */ |
55 | typedef struct { | 59 | struct cpu_entry { |
56 | int cpu; | 60 | int cpu; |
57 | struct task_struct* scheduled; | 61 | struct task_struct* scheduled; |
58 | struct task_struct* linked; | 62 | struct task_struct* linked; |
59 | raw_spinlock_t lock; | 63 | raw_spinlock_t lock; |
60 | crit_entry_t crit_entries[NUM_CRIT_LEVELS]; | 64 | struct crit_entry crit_entries[NUM_CRIT_LEVELS]; |
61 | #ifdef CONFIG_PLUGIN_MC_REDIRECT | 65 | #ifdef CONFIG_PLUGIN_MC_REDIRECT |
62 | struct list_head redir; | 66 | struct list_head redir; |
63 | raw_spinlock_t redir_lock; | 67 | raw_spinlock_t redir_lock; |
64 | #endif | 68 | #endif |
65 | } cpu_entry_t; | 69 | #ifdef CONFIG_MERGE_TIMERS |
70 | struct event_group* event_group; | ||
71 | #endif | ||
72 | }; | ||
66 | 73 | ||
67 | /** | 74 | /** |
68 | * domain_data_t - Wrap domains with related CPU state | 75 | * struct domain_data - Wrap domains with related CPU state |
69 | * @domain A domain for a criticality level | 76 | * @domain A domain for a criticality level |
70 | * @heap The preemptable heap of crit entries (for global domains) | 77 | * @heap The preemptable heap of crit entries (for global domains) |
71 | * @crit_entry The crit entry for this domain (for partitioned domains) | 78 | * @crit_entry The crit entry for this domain (for partitioned domains) |
72 | */ | 79 | */ |
73 | typedef struct { | 80 | struct domain_data { |
74 | domain_t domain; | 81 | struct domain domain; |
75 | struct bheap* heap; | 82 | struct bheap* heap; |
76 | crit_entry_t* crit_entry; | 83 | struct crit_entry* crit_entry; |
77 | } domain_data_t; | 84 | }; |
78 | 85 | ||
79 | static cpu_entry_t* cpus[NR_CPUS]; | 86 | DEFINE_PER_CPU(struct cpu_entry, cpus); |
80 | #ifdef CONFIG_RELEASE_MASTER | 87 | #ifdef CONFIG_RELEASE_MASTER |
81 | static int interrupt_cpu; | 88 | static int interrupt_cpu; |
82 | #endif | 89 | #endif |
90 | #ifdef CONFIG_MERGE_TIMERS | ||
91 | static struct event_group* global_group; | ||
92 | #endif | ||
83 | 93 | ||
84 | #define domain_data(dom) (container_of(dom, domain_data_t, domain)) | 94 | #define domain_data(dom) (container_of(dom, struct domain_data, domain)) |
85 | #define is_global(dom) (domain_data(dom)->heap) | 95 | #define is_global(dom) (domain_data(dom)->heap) |
86 | #define is_global_task(t) (is_global(get_task_domain(t))) | 96 | #define is_global_task(t) (is_global(get_task_domain(t))) |
87 | #define is_in_list(t) (tsk_rt(t)->list.next != tsk_rt(t)->list) | ||
88 | #define can_requeue(t) \ | 97 | #define can_requeue(t) \ |
89 | (!is_global_task(t) || (t)->rt_param.scheduled_on == NO_CPU) | 98 | (!is_global_task(t) || (t)->rt_param.scheduled_on == NO_CPU) |
90 | #define entry_level(e) \ | 99 | #define entry_level(e) \ |
91 | (((e)->linked) ? tsk_mc_crit((e)->linked) : NUM_CRIT_LEVELS - 1) | 100 | (((e)->linked) ? tsk_mc_crit((e)->linked) : NUM_CRIT_LEVELS - 1) |
92 | #define crit_cpu(ce) \ | 101 | #define crit_cpu(ce) \ |
93 | (container_of((void*)((ce) - (ce)->level), cpu_entry_t, crit_entries)) | 102 | (container_of((void*)((ce) - (ce)->level), struct cpu_entry, crit_entries)) |
94 | /* Useful debug macros */ | ||
95 | #define TS "(%s/%d:%d:%s)" | ||
96 | #define TA(t) (t) ? (is_ghost(t)) ? "ghost" : t->comm : "NULL", (t) ? t->pid : 1, \ | ||
97 | (t) ? t->rt_param.job_params.job_no : 1, \ | ||
98 | (t && get_task_domain(t)) ? get_task_domain(t)->name : "" | ||
99 | #define TRACE_ENTRY(e, fmt, args...) \ | 103 | #define TRACE_ENTRY(e, fmt, args...) \ |
100 | TRACE("P%d, linked=" TS " " fmt "\n", \ | 104 | TRACE("P%d, linked=" TS " " fmt "\n", e->cpu, TA(e->linked), ##args) |
101 | e->cpu, TA(e->linked), ##args) | ||
102 | #define TRACE_CRIT_ENTRY(ce, fmt, args...) \ | 105 | #define TRACE_CRIT_ENTRY(ce, fmt, args...) \ |
103 | TRACE("%s P%d, linked=" TS " " fmt "\n", \ | 106 | TRACE("%s P%d, linked=" TS " " fmt "\n", \ |
104 | (ce)->domain->name, crit_cpu(ce)->cpu, TA((ce)->linked), ##args) | 107 | (ce)->domain->name, crit_cpu(ce)->cpu, TA((ce)->linked), ##args) |
105 | #undef TRACE_TASK | ||
106 | #define TRACE_TASK(t, fmt, args...) \ | ||
107 | TRACE(TS " " fmt "\n", TA(t), ##args) | ||
108 | 108 | ||
109 | /* | 109 | /* |
110 | * Sort CPUs within a global domain by the domain's priority function. | 110 | * Sort CPUs within a global domain by the domain's priority function. |
111 | */ | 111 | */ |
112 | static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b) | 112 | static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b) |
113 | { | 113 | { |
114 | domain_t *domain; | 114 | struct domain *domain; |
115 | crit_entry_t *first, *second; | 115 | struct crit_entry *first, *second; |
116 | struct task_struct *first_link, *second_link; | 116 | struct task_struct *first_link, *second_link; |
117 | 117 | ||
118 | first = a->value; | 118 | first = a->value; |
@@ -134,7 +134,7 @@ static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b) | |||
134 | * Return true if the domain has a higher priority ready task. The curr | 134 | * Return true if the domain has a higher priority ready task. The curr |
135 | * task must belong to the domain. | 135 | * task must belong to the domain. |
136 | */ | 136 | */ |
137 | static noinline int mc_preempt_needed(domain_t *dom, struct task_struct* curr) | 137 | static int mc_preempt_needed(struct domain *dom, struct task_struct* curr) |
138 | { | 138 | { |
139 | struct task_struct *next = dom->peek_ready(dom); | 139 | struct task_struct *next = dom->peek_ready(dom); |
140 | if (!next || !curr) { | 140 | if (!next || !curr) { |
@@ -149,15 +149,45 @@ static noinline int mc_preempt_needed(domain_t *dom, struct task_struct* curr) | |||
149 | * Return next CPU which should preempted or NULL if the domain has no | 149 | * Return next CPU which should preempted or NULL if the domain has no |
150 | * preemptable CPUs. | 150 | * preemptable CPUs. |
151 | */ | 151 | */ |
152 | static inline crit_entry_t* lowest_prio_cpu(domain_t *dom) | 152 | static inline struct crit_entry* lowest_prio_cpu(struct domain *dom) |
153 | { | 153 | { |
154 | struct bheap *heap = domain_data(dom)->heap; | 154 | struct bheap *heap = domain_data(dom)->heap; |
155 | struct bheap_node* hn = bheap_peek(cpu_lower_prio, heap); | 155 | struct bheap_node* hn = bheap_peek(cpu_lower_prio, heap); |
156 | return (hn) ? hn->value : NULL; | 156 | return (hn) ? hn->value : NULL; |
157 | } | 157 | } |
158 | 158 | ||
159 | /** | 159 | /* |
160 | * update_ghost_time() - Time accounting for ghost tasks. | 160 | * Cancel ghost timer. |
161 | */ | ||
162 | static inline void cancel_ghost(struct crit_entry *ce) | ||
163 | { | ||
164 | #ifdef CONFIG_MERGE_TIMERS | ||
165 | cancel_event(&ce->event); | ||
166 | #else | ||
167 | hrtimer_try_to_cancel(&ce->timer); | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Arm ghost timer. Will merge timers if the option is specified. | ||
173 | */ | ||
174 | static inline void arm_ghost(struct crit_entry *ce, lt_t fire) | ||
175 | { | ||
176 | #ifdef CONFIG_MERGE_TIMERS | ||
177 | struct event_group* group = (is_global(ce->domain)) ? | ||
178 | global_group : crit_cpu(ce)->event_group; | ||
179 | add_event(group, &ce->event, fire); | ||
180 | #else | ||
181 | __hrtimer_start_range_ns(&ce->timer, | ||
182 | ns_to_ktime(when_to_fire), | ||
183 | 0 /* delta */, | ||
184 | HRTIMER_MODE_ABS_PINNED, | ||
185 | 0 /* no wakeup */); | ||
186 | #endif | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Time accounting for ghost tasks. | ||
161 | * Must be called before a decision is made involving the task's budget. | 191 | * Must be called before a decision is made involving the task's budget. |
162 | */ | 192 | */ |
163 | static void update_ghost_time(struct task_struct *p) | 193 | static void update_ghost_time(struct task_struct *p) |
@@ -167,14 +197,14 @@ static void update_ghost_time(struct task_struct *p) | |||
167 | BUG_ON(!is_ghost(p)); | 197 | BUG_ON(!is_ghost(p)); |
168 | if (unlikely ((s64)delta < 0)) { | 198 | if (unlikely ((s64)delta < 0)) { |
169 | delta = 0; | 199 | delta = 0; |
170 | TRACE_TASK(p, "WARNING: negative time delta"); | 200 | TRACE_MC_TASK(p, "WARNING: negative time delta"); |
171 | } | 201 | } |
172 | if (tsk_mc_data(p)->mc_job.ghost_budget <= delta) { | 202 | if (tsk_mc_data(p)->mc_job.ghost_budget <= delta) { |
173 | TRACE_TASK(p, "Ghost job could have ended"); | 203 | TRACE_MC_TASK(p, "Ghost job could have ended"); |
174 | tsk_mc_data(p)->mc_job.ghost_budget = 0; | 204 | tsk_mc_data(p)->mc_job.ghost_budget = 0; |
175 | p->se.exec_start = clock; | 205 | p->se.exec_start = clock; |
176 | } else { | 206 | } else { |
177 | TRACE_TASK(p, "Ghost job updated, but didn't finish"); | 207 | TRACE_MC_TASK(p, "Ghost job updated, but didn't finish"); |
178 | tsk_mc_data(p)->mc_job.ghost_budget -= delta; | 208 | tsk_mc_data(p)->mc_job.ghost_budget -= delta; |
179 | p->se.exec_start = clock; | 209 | p->se.exec_start = clock; |
180 | } | 210 | } |
@@ -184,7 +214,7 @@ static void update_ghost_time(struct task_struct *p) | |||
184 | * link_task_to_crit() - Logically run a task at a criticality level. | 214 | * link_task_to_crit() - Logically run a task at a criticality level. |
185 | * Caller must hold @ce's domain's lock. | 215 | * Caller must hold @ce's domain's lock. |
186 | */ | 216 | */ |
187 | static void link_task_to_crit(crit_entry_t *ce, | 217 | static void link_task_to_crit(struct crit_entry *ce, |
188 | struct task_struct *task) | 218 | struct task_struct *task) |
189 | { | 219 | { |
190 | lt_t when_to_fire; | 220 | lt_t when_to_fire; |
@@ -198,10 +228,10 @@ static void link_task_to_crit(crit_entry_t *ce, | |||
198 | 228 | ||
199 | /* Unlink last task */ | 229 | /* Unlink last task */ |
200 | if (ce->linked) { | 230 | if (ce->linked) { |
201 | TRACE_TASK(ce->linked, "Unlinking"); | 231 | TRACE_MC_TASK(ce->linked, "Unlinking"); |
202 | ce->linked->rt_param.linked_on = NO_CPU; | 232 | ce->linked->rt_param.linked_on = NO_CPU; |
203 | if (is_ghost(ce->linked)) { | 233 | if (is_ghost(ce->linked)) { |
204 | hrtimer_try_to_cancel(&ce->timer); | 234 | cancel_ghost(ce); |
205 | if (tsk_mc_data(ce->linked)->mc_job.ghost_budget > 0) { | 235 | if (tsk_mc_data(ce->linked)->mc_job.ghost_budget > 0) { |
206 | /* Job isn't finished, so do accounting */ | 236 | /* Job isn't finished, so do accounting */ |
207 | update_ghost_time(ce->linked); | 237 | update_ghost_time(ce->linked); |
@@ -218,11 +248,7 @@ static void link_task_to_crit(crit_entry_t *ce, | |||
218 | task->se.exec_start = litmus_clock(); | 248 | task->se.exec_start = litmus_clock(); |
219 | when_to_fire = litmus_clock() + | 249 | when_to_fire = litmus_clock() + |
220 | tsk_mc_data(task)->mc_job.ghost_budget; | 250 | tsk_mc_data(task)->mc_job.ghost_budget; |
221 | __hrtimer_start_range_ns(&ce->timer, | 251 | arm_ghost(ce, when_to_fire); |
222 | ns_to_ktime(when_to_fire), | ||
223 | 0 /* delta */, | ||
224 | HRTIMER_MODE_ABS_PINNED, | ||
225 | 0 /* no wakeup */); | ||
226 | } | 252 | } |
227 | } | 253 | } |
228 | 254 | ||
@@ -234,17 +260,18 @@ static void link_task_to_crit(crit_entry_t *ce, | |||
234 | } | 260 | } |
235 | } | 261 | } |
236 | 262 | ||
237 | static void check_for_preempt(domain_t*); | 263 | static void check_for_preempt(struct domain*); |
238 | /** | 264 | /** |
239 | * job_arrival() - Called when a task re-enters the system. | 265 | * job_arrival() - Called when a task re-enters the system. |
240 | * Caller must hold no locks. | 266 | * Caller must hold no locks. |
241 | */ | 267 | */ |
242 | static void job_arrival(struct task_struct *task) | 268 | static void job_arrival(struct task_struct *task) |
243 | { | 269 | { |
244 | domain_t *dom = get_task_domain(task); | 270 | struct domain *dom = get_task_domain(task); |
245 | 271 | ||
246 | TRACE_TASK(task, "Job arriving"); | 272 | TRACE_MC_TASK(task, "Job arriving"); |
247 | BUG_ON(!task); | 273 | BUG_ON(!task); |
274 | |||
248 | if (can_requeue(task)) { | 275 | if (can_requeue(task)) { |
249 | raw_spin_lock(dom->lock); | 276 | raw_spin_lock(dom->lock); |
250 | dom->requeue(dom, task); | 277 | dom->requeue(dom, task); |
@@ -257,7 +284,7 @@ static void job_arrival(struct task_struct *task) | |||
257 | * causing the system to crash when the task is scheduled | 284 | * causing the system to crash when the task is scheduled |
258 | * in two places simultaneously. | 285 | * in two places simultaneously. |
259 | */ | 286 | */ |
260 | TRACE_TASK(task, "Delayed arrival of scheduled task"); | 287 | TRACE_MC_TASK(task, "Delayed arrival of scheduled task"); |
261 | } | 288 | } |
262 | } | 289 | } |
263 | 290 | ||
@@ -267,7 +294,7 @@ static void job_arrival(struct task_struct *task) | |||
267 | */ | 294 | */ |
268 | static void low_prio_arrival(struct task_struct *task) | 295 | static void low_prio_arrival(struct task_struct *task) |
269 | { | 296 | { |
270 | cpu_entry_t *entry; | 297 | struct cpu_entry *entry; |
271 | 298 | ||
272 | /* Race conditions! */ | 299 | /* Race conditions! */ |
273 | if (!can_requeue(task)) return; | 300 | if (!can_requeue(task)) return; |
@@ -278,9 +305,9 @@ static void low_prio_arrival(struct task_struct *task) | |||
278 | goto arrive; | 305 | goto arrive; |
279 | #endif | 306 | #endif |
280 | if (smp_processor_id() != interrupt_cpu) { | 307 | if (smp_processor_id() != interrupt_cpu) { |
281 | entry = cpus[smp_processor_id()]; | 308 | entry = &__get_cpu_var(cpus); |
282 | raw_spin_lock(&entry->redir_lock); | 309 | raw_spin_lock(&entry->redir_lock); |
283 | TRACE_TASK(task, "Adding to redirect queue"); | 310 | TRACE_MC_TASK(task, "Adding to redirect queue"); |
284 | list_add(&tsk_rt(task)->list, &entry->redir); | 311 | list_add(&tsk_rt(task)->list, &entry->redir); |
285 | raw_spin_unlock(&entry->redir_lock); | 312 | raw_spin_unlock(&entry->redir_lock); |
286 | litmus_reschedule(interrupt_cpu); | 313 | litmus_reschedule(interrupt_cpu); |
@@ -299,18 +326,18 @@ static void low_prio_arrival(struct task_struct *task) | |||
299 | static void fix_global_levels(void) | 326 | static void fix_global_levels(void) |
300 | { | 327 | { |
301 | int c; | 328 | int c; |
302 | cpu_entry_t *e; | 329 | struct cpu_entry *e; |
303 | struct list_head *pos, *safe; | 330 | struct list_head *pos, *safe; |
304 | struct task_struct *t; | 331 | struct task_struct *t; |
305 | 332 | ||
306 | TRACE("Fixing global levels\n"); | 333 | TRACE("Fixing global levels\n"); |
307 | for_each_online_cpu(c) { | 334 | for_each_online_cpu(c) { |
308 | e = cpus[c]; | 335 | e = &per_cpu(cpus, c); |
309 | raw_spin_lock(&e->redir_lock); | 336 | raw_spin_lock(&e->redir_lock); |
310 | list_for_each_safe(pos, safe, &e->redir) { | 337 | list_for_each_safe(pos, safe, &e->redir) { |
311 | t = list_entry(pos, struct task_struct, rt_param.list); | 338 | t = list_entry(pos, struct task_struct, rt_param.list); |
312 | TRACE_TASK(t, "Dequeued redirected job"); | 339 | BUG_ON(!t); |
313 | BUG_ON(is_queued(t)); | 340 | TRACE_MC_TASK(t, "Dequeued redirected job"); |
314 | list_del_init(pos); | 341 | list_del_init(pos); |
315 | job_arrival(t); | 342 | job_arrival(t); |
316 | } | 343 | } |
@@ -324,10 +351,10 @@ static void fix_global_levels(void) | |||
324 | * The task must first have been linked to one of the CPU's crit_entries. | 351 | * The task must first have been linked to one of the CPU's crit_entries. |
325 | * Caller must hold the entry lock. | 352 | * Caller must hold the entry lock. |
326 | */ | 353 | */ |
327 | static void link_task_to_cpu(cpu_entry_t *entry, struct task_struct *task) | 354 | static void link_task_to_cpu(struct cpu_entry *entry, struct task_struct *task) |
328 | { | 355 | { |
329 | int i = entry_level(entry); | 356 | int i = entry_level(entry); |
330 | TRACE_TASK(task, "Linking to P%d", entry->cpu); | 357 | TRACE_MC_TASK(task, "Linking to P%d", entry->cpu); |
331 | BUG_ON(task && tsk_rt(task)->linked_on != entry->cpu); | 358 | BUG_ON(task && tsk_rt(task)->linked_on != entry->cpu); |
332 | BUG_ON(task && is_ghost(task)); | 359 | BUG_ON(task && is_ghost(task)); |
333 | 360 | ||
@@ -348,10 +375,10 @@ static void link_task_to_cpu(cpu_entry_t *entry, struct task_struct *task) | |||
348 | * | 375 | * |
349 | * Caller must hold the lock for @dom and @ce's CPU lock. | 376 | * Caller must hold the lock for @dom and @ce's CPU lock. |
350 | */ | 377 | */ |
351 | static void preempt(domain_t *dom, crit_entry_t *ce) | 378 | static void preempt(struct domain *dom, struct crit_entry *ce) |
352 | { | 379 | { |
353 | struct task_struct *task = dom->take_ready(dom); | 380 | struct task_struct *task = dom->take_ready(dom); |
354 | cpu_entry_t *entry = crit_cpu(ce); | 381 | struct cpu_entry *entry = crit_cpu(ce); |
355 | 382 | ||
356 | BUG_ON(!task); | 383 | BUG_ON(!task); |
357 | TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task)); | 384 | TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task)); |
@@ -373,17 +400,25 @@ static void preempt(domain_t *dom, crit_entry_t *ce) | |||
373 | * This should be called after a new task has been linked to @entry. | 400 | * This should be called after a new task has been linked to @entry. |
374 | * The caller must hold the @entry->lock, but this method will release it. | 401 | * The caller must hold the @entry->lock, but this method will release it. |
375 | */ | 402 | */ |
376 | static void update_crit_levels(cpu_entry_t *entry) | 403 | static void update_crit_levels(struct cpu_entry *entry) |
377 | { | 404 | { |
378 | int i; | 405 | int i, global_preempted; |
379 | crit_entry_t *ce; | 406 | struct crit_entry *ce; |
380 | struct task_struct *tasks[NUM_CRIT_LEVELS]; | 407 | struct task_struct *readmit[NUM_CRIT_LEVELS]; |
381 | enum crit_level level = entry_level(entry); | 408 | enum crit_level level = entry_level(entry); |
382 | 409 | ||
383 | /* Remove lower priority tasks from the entry */ | 410 | /* Remove lower priority tasks from the entry */ |
384 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { | 411 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { |
385 | ce = &entry->crit_entries[i]; | 412 | ce = &entry->crit_entries[i]; |
386 | tasks[i] = ce->linked; | 413 | |
414 | global_preempted = entry->scheduled == ce->linked && | ||
415 | ce->linked && entry->linked && | ||
416 | !is_ghost(ce->linked) && is_global(ce->domain); | ||
417 | /* Do not readmit global tasks which are preempted! These can't | ||
418 | * ever be re-admitted until they are descheduled for reasons | ||
419 | * explained in job_arrival. | ||
420 | */ | ||
421 | readmit[i] = (!global_preempted) ? ce->linked : NULL; | ||
387 | ce->usable = 0; | 422 | ce->usable = 0; |
388 | if (ce->linked) | 423 | if (ce->linked) |
389 | link_task_to_crit(ce, NULL); | 424 | link_task_to_crit(ce, NULL); |
@@ -394,8 +429,8 @@ static void update_crit_levels(cpu_entry_t *entry) | |||
394 | /* Re-admit tasks to the system */ | 429 | /* Re-admit tasks to the system */ |
395 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { | 430 | for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { |
396 | ce = &entry->crit_entries[i]; | 431 | ce = &entry->crit_entries[i]; |
397 | if (tasks[i]) | 432 | if (readmit[i]) |
398 | low_prio_arrival(tasks[i]); | 433 | low_prio_arrival(readmit[i]); |
399 | } | 434 | } |
400 | } | 435 | } |
401 | 436 | ||
@@ -405,11 +440,11 @@ static void update_crit_levels(cpu_entry_t *entry) | |||
405 | * Makes gigantic nasty assumption that there is 1 global criticality level, | 440 | * Makes gigantic nasty assumption that there is 1 global criticality level, |
406 | * and it is the last one in each list, so it doesn't call update_crit.. | 441 | * and it is the last one in each list, so it doesn't call update_crit.. |
407 | */ | 442 | */ |
408 | static void check_for_preempt(domain_t *dom) | 443 | static void check_for_preempt(struct domain *dom) |
409 | { | 444 | { |
410 | int preempted = 1; | 445 | int preempted = 1; |
411 | cpu_entry_t *entry; | 446 | struct cpu_entry *entry; |
412 | crit_entry_t *ce; | 447 | struct crit_entry *ce; |
413 | 448 | ||
414 | if (is_global(dom)) { | 449 | if (is_global(dom)) { |
415 | /* Loop until we find a non-preemptable CPU */ | 450 | /* Loop until we find a non-preemptable CPU */ |
@@ -443,17 +478,17 @@ static void check_for_preempt(domain_t *dom) | |||
443 | static void remove_from_all(struct task_struct* task) | 478 | static void remove_from_all(struct task_struct* task) |
444 | { | 479 | { |
445 | int update = 0; | 480 | int update = 0; |
446 | cpu_entry_t *entry; | 481 | struct cpu_entry *entry; |
447 | crit_entry_t *ce; | 482 | struct crit_entry *ce; |
448 | domain_t *dom = get_task_domain(task); | 483 | struct domain *dom = get_task_domain(task); |
449 | 484 | ||
450 | TRACE_TASK(task, "Removing from everything"); | 485 | TRACE_MC_TASK(task, "Removing from everything"); |
451 | BUG_ON(!task); | 486 | BUG_ON(!task); |
452 | 487 | ||
453 | raw_spin_lock(dom->lock); | 488 | raw_spin_lock(dom->lock); |
454 | 489 | ||
455 | if (task->rt_param.linked_on != NO_CPU) { | 490 | if (task->rt_param.linked_on != NO_CPU) { |
456 | entry = cpus[task->rt_param.linked_on]; | 491 | entry = &per_cpu(cpus, task->rt_param.linked_on); |
457 | raw_spin_lock(&entry->lock); | 492 | raw_spin_lock(&entry->lock); |
458 | 493 | ||
459 | /* Unlink only if task is still linked post lock */ | 494 | /* Unlink only if task is still linked post lock */ |
@@ -492,7 +527,7 @@ static void remove_from_all(struct task_struct* task) | |||
492 | */ | 527 | */ |
493 | static void job_completion(struct task_struct *task, int forced) | 528 | static void job_completion(struct task_struct *task, int forced) |
494 | { | 529 | { |
495 | TRACE_TASK(task, "Completed"); | 530 | TRACE_MC_TASK(task, "Completed"); |
496 | sched_trace_task_completion(task, forced); | 531 | sched_trace_task_completion(task, forced); |
497 | BUG_ON(!task); | 532 | BUG_ON(!task); |
498 | 533 | ||
@@ -525,11 +560,19 @@ static void job_completion(struct task_struct *task, int forced) | |||
525 | /** | 560 | /** |
526 | * mc_ghost_exhausted() - Complete logically running ghost task. | 561 | * mc_ghost_exhausted() - Complete logically running ghost task. |
527 | */ | 562 | */ |
563 | #ifdef CONFIG_MERGE_TIMERS | ||
564 | static void mc_ghost_exhausted(struct rt_event *e) | ||
565 | { | ||
566 | struct crit_entry *ce = container_of(e, struct crit_entry, event); | ||
567 | #else | ||
528 | static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer) | 568 | static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer) |
529 | { | 569 | { |
570 | struct crit_entry *ce = container_of(timer, struct crit_entry, timer); | ||
571 | #endif | ||
572 | |||
530 | unsigned long flags; | 573 | unsigned long flags; |
531 | struct task_struct *tmp = NULL; | 574 | struct task_struct *tmp = NULL; |
532 | crit_entry_t *ce = container_of(timer, crit_entry_t, timer);; | 575 | |
533 | 576 | ||
534 | local_irq_save(flags); | 577 | local_irq_save(flags); |
535 | TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing"); | 578 | TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing"); |
@@ -553,7 +596,9 @@ static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer) | |||
553 | job_completion(tmp, 0); | 596 | job_completion(tmp, 0); |
554 | 597 | ||
555 | local_irq_restore(flags); | 598 | local_irq_restore(flags); |
599 | #ifndef CONFIG_MERGE_TIMERS | ||
556 | return HRTIMER_NORESTART; | 600 | return HRTIMER_NORESTART; |
601 | #endif | ||
557 | } | 602 | } |
558 | 603 | ||
559 | /** | 604 | /** |
@@ -563,10 +608,10 @@ static void mc_release_jobs(rt_domain_t* rt, struct bheap* tasks) | |||
563 | { | 608 | { |
564 | unsigned long flags; | 609 | unsigned long flags; |
565 | struct task_struct *first = bheap_peek(rt->order, tasks)->value; | 610 | struct task_struct *first = bheap_peek(rt->order, tasks)->value; |
566 | domain_t *dom = get_task_domain(first); | 611 | struct domain *dom = get_task_domain(first); |
567 | 612 | ||
568 | raw_spin_lock_irqsave(dom->lock, flags); | 613 | raw_spin_lock_irqsave(dom->lock, flags); |
569 | TRACE_TASK(first, "Jobs released"); | 614 | TRACE_MC_TASK(first, "Jobs released"); |
570 | __merge_ready(rt, tasks); | 615 | __merge_ready(rt, tasks); |
571 | check_for_preempt(dom); | 616 | check_for_preempt(dom); |
572 | raw_spin_unlock_irqrestore(dom->lock, flags); | 617 | raw_spin_unlock_irqrestore(dom->lock, flags); |
@@ -579,7 +624,7 @@ static void mc_release_jobs(rt_domain_t* rt, struct bheap* tasks) | |||
579 | static void mc_task_new(struct task_struct *t, int on_rq, int running) | 624 | static void mc_task_new(struct task_struct *t, int on_rq, int running) |
580 | { | 625 | { |
581 | unsigned long flags; | 626 | unsigned long flags; |
582 | cpu_entry_t* entry; | 627 | struct cpu_entry* entry; |
583 | enum crit_level level = tsk_mc_crit(t); | 628 | enum crit_level level = tsk_mc_crit(t); |
584 | 629 | ||
585 | local_irq_save(flags); | 630 | local_irq_save(flags); |
@@ -587,9 +632,9 @@ static void mc_task_new(struct task_struct *t, int on_rq, int running) | |||
587 | 632 | ||
588 | /* Assign domain */ | 633 | /* Assign domain */ |
589 | if (level < CRIT_LEVEL_C) | 634 | if (level < CRIT_LEVEL_C) |
590 | entry = cpus[get_partition(t)]; | 635 | entry = &per_cpu(cpus, get_partition(t)); |
591 | else | 636 | else |
592 | entry = cpus[task_cpu(t)]; | 637 | entry = &per_cpu(cpus, task_cpu(t)); |
593 | t->rt_param._domain = entry->crit_entries[level].domain; | 638 | t->rt_param._domain = entry->crit_entries[level].domain; |
594 | 639 | ||
595 | /* Setup job params */ | 640 | /* Setup job params */ |
@@ -619,7 +664,7 @@ static void mc_task_wake_up(struct task_struct *task) | |||
619 | lt_t now = litmus_clock(); | 664 | lt_t now = litmus_clock(); |
620 | local_irq_save(flags); | 665 | local_irq_save(flags); |
621 | 666 | ||
622 | TRACE_TASK(task, "Wakes up"); | 667 | TRACE_MC_TASK(task, "Wakes up"); |
623 | if (is_tardy(task, now)) { | 668 | if (is_tardy(task, now)) { |
624 | /* Task missed its last release */ | 669 | /* Task missed its last release */ |
625 | release_at(task, now); | 670 | release_at(task, now); |
@@ -638,7 +683,7 @@ static void mc_task_block(struct task_struct *task) | |||
638 | { | 683 | { |
639 | unsigned long flags; | 684 | unsigned long flags; |
640 | local_irq_save(flags); | 685 | local_irq_save(flags); |
641 | TRACE_TASK(task, "Block at %llu", litmus_clock()); | 686 | TRACE_MC_TASK(task, "Block at %llu", litmus_clock()); |
642 | remove_from_all(task); | 687 | remove_from_all(task); |
643 | local_irq_restore(flags); | 688 | local_irq_restore(flags); |
644 | } | 689 | } |
@@ -651,11 +696,11 @@ static void mc_task_exit(struct task_struct *task) | |||
651 | unsigned long flags; | 696 | unsigned long flags; |
652 | local_irq_save(flags); | 697 | local_irq_save(flags); |
653 | BUG_ON(!is_realtime(task)); | 698 | BUG_ON(!is_realtime(task)); |
654 | TRACE_TASK(task, "RIP"); | 699 | TRACE_MC_TASK(task, "RIP"); |
655 | 700 | ||
656 | remove_from_all(task); | 701 | remove_from_all(task); |
657 | if (tsk_rt(task)->scheduled_on != NO_CPU) { | 702 | if (tsk_rt(task)->scheduled_on != NO_CPU) { |
658 | cpus[tsk_rt(task)->scheduled_on]->scheduled = NULL; | 703 | per_cpu(cpus, tsk_rt(task)->scheduled_on).scheduled = NULL; |
659 | tsk_rt(task)->scheduled_on = NO_CPU; | 704 | tsk_rt(task)->scheduled_on = NO_CPU; |
660 | } | 705 | } |
661 | 706 | ||
@@ -689,9 +734,9 @@ static long mc_admit_task(struct task_struct* task) | |||
689 | static struct task_struct* mc_schedule(struct task_struct * prev) | 734 | static struct task_struct* mc_schedule(struct task_struct * prev) |
690 | { | 735 | { |
691 | unsigned long flags; | 736 | unsigned long flags; |
692 | domain_t *dom; | 737 | struct domain *dom; |
693 | crit_entry_t *ce; | 738 | struct crit_entry *ce; |
694 | cpu_entry_t* entry = cpus[smp_processor_id()]; | 739 | struct cpu_entry* entry = &__get_cpu_var(cpus); |
695 | int i, out_of_time, sleep, preempt, exists, blocks, global, lower; | 740 | int i, out_of_time, sleep, preempt, exists, blocks, global, lower; |
696 | struct task_struct *dtask = NULL, *ready_task = NULL, *next = NULL; | 741 | struct task_struct *dtask = NULL, *ready_task = NULL, *next = NULL; |
697 | 742 | ||
@@ -703,6 +748,7 @@ static struct task_struct* mc_schedule(struct task_struct * prev) | |||
703 | BUG_ON(is_realtime(prev) && !entry->scheduled); | 748 | BUG_ON(is_realtime(prev) && !entry->scheduled); |
704 | 749 | ||
705 | /* Determine state */ | 750 | /* Determine state */ |
751 | raw_spin_lock(&entry->lock); | ||
706 | exists = entry->scheduled != NULL; | 752 | exists = entry->scheduled != NULL; |
707 | blocks = exists && !is_running(entry->scheduled); | 753 | blocks = exists && !is_running(entry->scheduled); |
708 | out_of_time = exists && budget_enforced(entry->scheduled) && | 754 | out_of_time = exists && budget_enforced(entry->scheduled) && |
@@ -715,17 +761,20 @@ static struct task_struct* mc_schedule(struct task_struct * prev) | |||
715 | 761 | ||
716 | if (exists) { | 762 | if (exists) { |
717 | entry->scheduled->rt_param.scheduled_on = NO_CPU; | 763 | entry->scheduled->rt_param.scheduled_on = NO_CPU; |
718 | TRACE_TASK(prev, | 764 | TRACE_MC_TASK(prev, |
719 | "blocks:%d out_of_time:%d sleep:%d preempt:%d " | 765 | "blocks:%d out_of_time:%d sleep:%d preempt:%d " |
720 | "state:%d sig:%d global:%d", | 766 | "state:%d sig:%d global:%d", |
721 | blocks, out_of_time, sleep, preempt, | 767 | blocks, out_of_time, sleep, preempt, |
722 | prev->state, signal_pending(prev), global); | 768 | prev->state, signal_pending(prev), global); |
723 | } | 769 | } |
770 | raw_spin_unlock(&entry->lock); | ||
771 | |||
724 | 772 | ||
725 | #ifdef CONFIG_PLUGIN_MC_REDIRECT | 773 | #ifdef CONFIG_PLUGIN_MC_REDIRECT |
726 | if (smp_processor_id() == interrupt_cpu) | 774 | if (smp_processor_id() == interrupt_cpu) |
727 | fix_global_levels(); | 775 | fix_global_levels(); |
728 | #endif | 776 | #endif |
777 | |||
729 | /* If a task blocks we have no choice but to reschedule */ | 778 | /* If a task blocks we have no choice but to reschedule */ |
730 | if (blocks) | 779 | if (blocks) |
731 | remove_from_all(entry->scheduled); | 780 | remove_from_all(entry->scheduled); |
@@ -769,6 +818,7 @@ static struct task_struct* mc_schedule(struct task_struct * prev) | |||
769 | raw_spin_unlock(dom->lock); | 818 | raw_spin_unlock(dom->lock); |
770 | update_crit_levels(entry); | 819 | update_crit_levels(entry); |
771 | raw_spin_lock(&entry->lock); | 820 | raw_spin_lock(&entry->lock); |
821 | continue; | ||
772 | } | 822 | } |
773 | } | 823 | } |
774 | raw_spin_unlock(dom->lock); | 824 | raw_spin_unlock(dom->lock); |
@@ -784,22 +834,12 @@ static struct task_struct* mc_schedule(struct task_struct * prev) | |||
784 | raw_spin_unlock(&entry->lock); | 834 | raw_spin_unlock(&entry->lock); |
785 | local_irq_restore(flags); | 835 | local_irq_restore(flags); |
786 | if (next) | 836 | if (next) |
787 | TRACE_TASK(next, "Scheduled at %llu", litmus_clock()); | 837 | TRACE_MC_TASK(next, "Scheduled at %llu", litmus_clock()); |
788 | else if (exists && !next) | 838 | else if (exists && !next) |
789 | TRACE("Becomes idle at %llu\n", litmus_clock()); | 839 | TRACE("Becomes idle at %llu\n", litmus_clock()); |
790 | return next; | 840 | return next; |
791 | } | 841 | } |
792 | 842 | ||
793 | static long mc_activate_plugin(void) | ||
794 | { | ||
795 | #ifdef CONFIG_RELEASE_MASTER | ||
796 | interrupt_cpu = atomic_read(&release_master_cpu); | ||
797 | if (interrupt_cpu == NO_CPU) | ||
798 | interrupt_cpu = 0; | ||
799 | #endif | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | /* ************************************************************************** | 843 | /* ************************************************************************** |
804 | * Initialization | 844 | * Initialization |
805 | * ************************************************************************** */ | 845 | * ************************************************************************** */ |
@@ -807,23 +847,36 @@ static long mc_activate_plugin(void) | |||
807 | /* Initialize values here so that they are allocated with the module | 847 | /* Initialize values here so that they are allocated with the module |
808 | * and destroyed when the module is unloaded. | 848 | * and destroyed when the module is unloaded. |
809 | */ | 849 | */ |
810 | DEFINE_PER_CPU(cpu_entry_t, _mc_cpus); | 850 | |
811 | /* LVL-A */ | 851 | /* LVL-A */ |
812 | DEFINE_PER_CPU(domain_data_t, _mc_crit_a); | 852 | DEFINE_PER_CPU(struct domain_data, _mc_crit_a); |
813 | DEFINE_PER_CPU(rt_domain_t, _mc_crit_a_rt); | 853 | DEFINE_PER_CPU(rt_domain_t, _mc_crit_a_rt); |
814 | /* LVL-B */ | 854 | /* LVL-B */ |
815 | DEFINE_PER_CPU(domain_data_t, _mc_crit_b); | 855 | DEFINE_PER_CPU(struct domain_data, _mc_crit_b); |
816 | DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt); | 856 | DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt); |
817 | /* LVL-C */ | 857 | /* LVL-C */ |
818 | static domain_data_t _mc_crit_c; | 858 | static struct domain_data _mc_crit_c; |
819 | static rt_domain_t _mc_crit_c_rt; | 859 | static rt_domain_t _mc_crit_c_rt; |
820 | struct bheap _mc_heap_c; | 860 | struct bheap _mc_heap_c; |
821 | struct bheap_node _mc_nodes_c[NR_CPUS]; | 861 | struct bheap_node _mc_nodes_c[NR_CPUS]; |
822 | 862 | ||
823 | /* | 863 | #ifdef CONFIG_MERGE_TIMERS |
824 | * XXX commented out because I think this was an obvious typo | 864 | #ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER |
825 | */ | 865 | struct event_group _mc_group; |
826 | /* release_at)_ */ | 866 | #else |
867 | DEFINE_PER_CPU(struct event_group, _mc_groups); | ||
868 | #endif | ||
869 | #endif | ||
870 | |||
871 | static long mc_activate_plugin(void) | ||
872 | { | ||
873 | #ifdef CONFIG_RELEASE_MASTER | ||
874 | interrupt_cpu = atomic_read(&release_master_cpu); | ||
875 | if (interrupt_cpu == NO_CPU) | ||
876 | interrupt_cpu = 0; | ||
877 | #endif | ||
878 | return 0; | ||
879 | } | ||
827 | 880 | ||
828 | static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = { | 881 | static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = { |
829 | .plugin_name = "MC", | 882 | .plugin_name = "MC", |
@@ -837,8 +890,8 @@ static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = { | |||
837 | .activate_plugin = mc_activate_plugin, | 890 | .activate_plugin = mc_activate_plugin, |
838 | }; | 891 | }; |
839 | 892 | ||
840 | static void init_crit_entry(crit_entry_t *ce, enum crit_level level, | 893 | static void init_crit_entry(struct crit_entry *ce, enum crit_level level, |
841 | domain_data_t *dom_data, | 894 | struct domain_data *dom_data, |
842 | struct bheap_node *node) | 895 | struct bheap_node *node) |
843 | { | 896 | { |
844 | ce->level = level; | 897 | ce->level = level; |
@@ -846,12 +899,17 @@ static void init_crit_entry(crit_entry_t *ce, enum crit_level level, | |||
846 | ce->node = node; | 899 | ce->node = node; |
847 | ce->domain = &dom_data->domain; | 900 | ce->domain = &dom_data->domain; |
848 | ce->usable = 1; | 901 | ce->usable = 1; |
849 | atomic_set(&ce->dirty, 1); | 902 | #ifdef CONFIG_MERGE_TIMERS |
903 | init_event(&ce->event, level, mc_ghost_exhausted, | ||
904 | event_list_alloc(GFP_ATOMIC)); | ||
905 | #else | ||
850 | hrtimer_init(&ce->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 906 | hrtimer_init(&ce->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
851 | ce->timer.function = mc_ghost_exhausted; | 907 | ce->timer.function = mc_ghost_exhausted; |
908 | #endif | ||
909 | |||
852 | } | 910 | } |
853 | 911 | ||
854 | static void init_local_domain(cpu_entry_t *entry, domain_data_t *dom_data, | 912 | static void init_local_domain(struct cpu_entry *entry, struct domain_data *dom_data, |
855 | enum crit_level level) | 913 | enum crit_level level) |
856 | { | 914 | { |
857 | dom_data->heap = NULL; | 915 | dom_data->heap = NULL; |
@@ -859,12 +917,12 @@ static void init_local_domain(cpu_entry_t *entry, domain_data_t *dom_data, | |||
859 | init_crit_entry(dom_data->crit_entry, level, dom_data, NULL); | 917 | init_crit_entry(dom_data->crit_entry, level, dom_data, NULL); |
860 | } | 918 | } |
861 | 919 | ||
862 | static void init_global_domain(domain_data_t *dom_data, enum crit_level level, | 920 | static void init_global_domain(struct domain_data *dom_data, enum crit_level level, |
863 | struct bheap *heap, struct bheap_node *nodes) | 921 | struct bheap *heap, struct bheap_node *nodes) |
864 | { | 922 | { |
865 | int cpu; | 923 | int cpu; |
866 | cpu_entry_t *entry; | 924 | struct cpu_entry *entry; |
867 | crit_entry_t *ce; | 925 | struct crit_entry *ce; |
868 | struct bheap_node *node; | 926 | struct bheap_node *node; |
869 | 927 | ||
870 | dom_data->crit_entry = NULL; | 928 | dom_data->crit_entry = NULL; |
@@ -872,7 +930,7 @@ static void init_global_domain(domain_data_t *dom_data, enum crit_level level, | |||
872 | bheap_init(heap); | 930 | bheap_init(heap); |
873 | 931 | ||
874 | for_each_online_cpu(cpu) { | 932 | for_each_online_cpu(cpu) { |
875 | entry = cpus[cpu]; | 933 | entry = &per_cpu(cpus, cpu); |
876 | node = &nodes[cpu]; | 934 | node = &nodes[cpu]; |
877 | ce = &entry->crit_entries[level]; | 935 | ce = &entry->crit_entries[level]; |
878 | init_crit_entry(ce, level, dom_data, node); | 936 | init_crit_entry(ce, level, dom_data, node); |
@@ -881,40 +939,62 @@ static void init_global_domain(domain_data_t *dom_data, enum crit_level level, | |||
881 | } | 939 | } |
882 | } | 940 | } |
883 | 941 | ||
884 | static inline void init_edf_domain(domain_t *dom, rt_domain_t *rt) | 942 | static inline void init_edf_domain(struct domain *dom, rt_domain_t *rt, |
943 | int timer_cpu, int prio) | ||
885 | { | 944 | { |
886 | pd_domain_init(dom, rt, edf_ready_order, NULL, | 945 | pd_domain_init(dom, rt, edf_ready_order, NULL, |
887 | mc_release_jobs, mc_preempt_needed, | 946 | mc_release_jobs, mc_preempt_needed, |
888 | edf_higher_prio); | 947 | edf_higher_prio); |
948 | #ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER | ||
949 | #ifdef CONFIG_MERGE_TIMERS | ||
950 | rt->event_group = &_mc_group; | ||
951 | rt->prio = prio; | ||
952 | #else | ||
953 | rt->release_master = interrupt_cpu; | ||
954 | #endif | ||
955 | #elif CONFIG_MERGE_TIMERS | ||
956 | rt->event_group = &_mc_groups[timer_cpu]; | ||
957 | rt->prio = prio; | ||
958 | #endif | ||
889 | } | 959 | } |
890 | 960 | ||
891 | static int __init init_mc(void) | 961 | static int __init init_mc(void) |
892 | { | 962 | { |
893 | int cpu; | 963 | int cpu; |
894 | cpu_entry_t *entry; | 964 | struct cpu_entry *entry; |
965 | struct domain_data *dom_data; | ||
895 | rt_domain_t *rt; | 966 | rt_domain_t *rt; |
896 | domain_data_t *dom_data; | ||
897 | raw_spinlock_t *a_dom, *b_dom, *c_dom; /* For lock debugger */ | 967 | raw_spinlock_t *a_dom, *b_dom, *c_dom; /* For lock debugger */ |
898 | 968 | ||
899 | for_each_online_cpu(cpu) { | 969 | for_each_online_cpu(cpu) { |
900 | entry = &per_cpu(_mc_cpus, cpu); | 970 | entry = &per_cpu(cpus, cpu); |
901 | cpus[cpu] = entry; | ||
902 | 971 | ||
903 | /* CPU */ | 972 | /* CPU */ |
904 | entry->cpu = cpu; | 973 | entry->cpu = cpu; |
905 | entry->scheduled = NULL; | 974 | entry->scheduled = NULL; |
906 | entry->linked = NULL; | 975 | entry->linked = NULL; |
907 | raw_spin_lock_init(&entry->lock); | 976 | raw_spin_lock_init(&entry->lock); |
977 | |||
908 | #ifdef CONFIG_PLUGIN_MC_REDIRECT | 978 | #ifdef CONFIG_PLUGIN_MC_REDIRECT |
909 | raw_spin_lock_init(&entry->redir_lock); | 979 | raw_spin_lock_init(&entry->redir_lock); |
910 | INIT_LIST_HEAD(&entry->redir); | 980 | INIT_LIST_HEAD(&entry->redir); |
911 | #endif | 981 | #endif |
912 | 982 | ||
983 | #ifdef CONFIG_MERGE_TIMERS | ||
984 | #ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER | ||
985 | entry->event_group = &_mc_group; | ||
986 | #else | ||
987 | init_event_group(&_mc_groups[cpu], | ||
988 | CONFIG_MERGE_TIMERS_WINDOW, cpu); | ||
989 | entry->event_group = &_mc_groups[cpu]; | ||
990 | #endif | ||
991 | #endif | ||
992 | |||
913 | /* CRIT_LEVEL_A */ | 993 | /* CRIT_LEVEL_A */ |
914 | dom_data = &per_cpu(_mc_crit_a, cpu); | 994 | dom_data = &per_cpu(_mc_crit_a, cpu); |
915 | rt = &per_cpu(_mc_crit_a_rt, cpu); | 995 | rt = &per_cpu(_mc_crit_a_rt, cpu); |
916 | init_local_domain(entry, dom_data, CRIT_LEVEL_A); | 996 | init_local_domain(entry, dom_data, CRIT_LEVEL_A); |
917 | init_edf_domain(&dom_data->domain, rt); | 997 | init_edf_domain(&dom_data->domain, rt, cpu, CRIT_LEVEL_A); |
918 | a_dom = dom_data->domain.lock; | 998 | a_dom = dom_data->domain.lock; |
919 | raw_spin_lock_init(a_dom); | 999 | raw_spin_lock_init(a_dom); |
920 | dom_data->domain.name = "LVL-A"; | 1000 | dom_data->domain.name = "LVL-A"; |
@@ -923,16 +1003,25 @@ static int __init init_mc(void) | |||
923 | dom_data = &per_cpu(_mc_crit_b, cpu); | 1003 | dom_data = &per_cpu(_mc_crit_b, cpu); |
924 | rt = &per_cpu(_mc_crit_b_rt, cpu); | 1004 | rt = &per_cpu(_mc_crit_b_rt, cpu); |
925 | init_local_domain(entry, dom_data, CRIT_LEVEL_B); | 1005 | init_local_domain(entry, dom_data, CRIT_LEVEL_B); |
926 | init_edf_domain(&dom_data->domain, rt); | 1006 | init_edf_domain(&dom_data->domain, rt, cpu, CRIT_LEVEL_B); |
927 | b_dom = dom_data->domain.lock; | 1007 | b_dom = dom_data->domain.lock; |
928 | raw_spin_lock_init(b_dom); | 1008 | raw_spin_lock_init(b_dom); |
929 | dom_data->domain.name = "LVL-B"; | 1009 | dom_data->domain.name = "LVL-B"; |
930 | } | 1010 | } |
931 | 1011 | ||
1012 | #ifdef CONFIG_MERGE_TIMERS | ||
1013 | #ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER | ||
1014 | init_event_group(&_mc_group, CONFIG_MERGE_TIMERS_WINDOW, interrupt_cpu); | ||
1015 | global_group = &_mc_group; | ||
1016 | #else | ||
1017 | global_group = &_mc_groups[0]; | ||
1018 | #endif | ||
1019 | #endif | ||
1020 | |||
932 | /* CRIT_LEVEL_C */ | 1021 | /* CRIT_LEVEL_C */ |
933 | init_global_domain(&_mc_crit_c, CRIT_LEVEL_C, | 1022 | init_global_domain(&_mc_crit_c, CRIT_LEVEL_C, |
934 | &_mc_heap_c, _mc_nodes_c); | 1023 | &_mc_heap_c, _mc_nodes_c); |
935 | init_edf_domain(&_mc_crit_c.domain, &_mc_crit_c_rt); | 1024 | init_edf_domain(&_mc_crit_c.domain, &_mc_crit_c_rt, 0, CRIT_LEVEL_C); |
936 | c_dom = _mc_crit_c.domain.lock; | 1025 | c_dom = _mc_crit_c.domain.lock; |
937 | raw_spin_lock_init(c_dom); | 1026 | raw_spin_lock_init(c_dom); |
938 | _mc_crit_c.domain.name = "LVL-C"; | 1027 | _mc_crit_c.domain.name = "LVL-C"; |