aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2013-03-13 14:41:03 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2013-03-13 14:57:09 -0400
commita51fba95554e70bd74308c13cf804102a99973b3 (patch)
tree189167694d7ce6bbea486b83335b3e9cfbb843fe
parent5a2819df472ccbd2915fa0d50d7ce04b97b0849b (diff)
parentf4ffe0719dfc150ee182f308d31a226b034f206b (diff)
Merge branch 'gh/staging' into temp
Conflicts: include/litmus/litmus.h include/litmus/rt_param.h litmus/Makefile litmus/sched_cedf.c litmus/sched_gsn_edf.c
-rw-r--r--include/litmus/litmus.h23
-rw-r--r--include/litmus/rt_param.h19
-rw-r--r--litmus/Kconfig21
-rw-r--r--litmus/Makefile3
-rw-r--r--litmus/aux_tasks.c7
-rw-r--r--litmus/jobs.c8
-rw-r--r--litmus/litmus_softirq.c7
-rw-r--r--litmus/sched_cedf.c31
-rw-r--r--litmus/sched_gsn_edf.c7
-rw-r--r--litmus/sched_pfair.c2
-rw-r--r--litmus/sched_pfp.c2
-rw-r--r--litmus/sched_psn_edf.c4
-rw-r--r--litmus/uncachedev.c102
13 files changed, 186 insertions, 50 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h
index 17d30326034c..70b421d59d34 100644
--- a/include/litmus/litmus.h
+++ b/include/litmus/litmus.h
@@ -61,6 +61,7 @@ void litmus_exit_task(struct task_struct *tsk);
61#define get_partition(t) (tsk_rt(t)->task_params.cpu) 61#define get_partition(t) (tsk_rt(t)->task_params.cpu)
62#define get_priority(t) (tsk_rt(t)->task_params.priority) 62#define get_priority(t) (tsk_rt(t)->task_params.priority)
63#define get_class(t) (tsk_rt(t)->task_params.cls) 63#define get_class(t) (tsk_rt(t)->task_params.cls)
64#define get_release_policy(t) (tsk_rt(t)->task_params.release_policy)
64 65
65/* job_param macros */ 66/* job_param macros */
66#define get_exec_time(t) (tsk_rt(t)->job_params.exec_time) 67#define get_exec_time(t) (tsk_rt(t)->job_params.exec_time)
@@ -72,6 +73,15 @@ void litmus_exit_task(struct task_struct *tsk);
72#define effective_priority(t) ((!(tsk_rt(t)->inh_task)) ? t : tsk_rt(t)->inh_task) 73#define effective_priority(t) ((!(tsk_rt(t)->inh_task)) ? t : tsk_rt(t)->inh_task)
73#define base_priority(t) (t) 74#define base_priority(t) (t)
74 75
76/* release policy macros */
77#define is_periodic(t) (get_release_policy(t) == PERIODIC)
78#define is_sporadic(t) (get_release_policy(t) == SPORADIC)
79#ifdef CONFIG_ALLOW_EARLY_RELEASE
80#define is_early_releasing(t) (get_release_policy(t) == EARLY)
81#else
82#define is_early_releasing(t) (0)
83#endif
84
75#define is_hrt(t) \ 85#define is_hrt(t) \
76 (tsk_rt(t)->task_params.cls == RT_CLASS_HARD) 86 (tsk_rt(t)->task_params.cls == RT_CLASS_HARD)
77#define is_srt(t) \ 87#define is_srt(t) \
@@ -85,19 +95,6 @@ static inline lt_t litmus_clock(void)
85 return ktime_to_ns(ktime_get()); 95 return ktime_to_ns(ktime_get());
86} 96}
87 97
88static inline int is_persistent(struct task_struct* t)
89{
90 int is_per = ( 0
91 #ifdef CONFIG_REALTIME_AUX_TASKS
92 || t->rt_param.is_aux_task
93 #endif
94 #ifdef CONFIG_LITMUS_SOFTIRQD
95 || t->rt_param.is_interrupt_thread
96 #endif
97 );
98 return is_per;
99}
100
101/* A macro to convert from nanoseconds to ktime_t. */ 98/* A macro to convert from nanoseconds to ktime_t. */
102#define ns_to_ktime(t) ktime_add_ns(ktime_set(0, 0), t) 99#define ns_to_ktime(t) ktime_add_ns(ktime_set(0, 0), t)
103 100
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index d9b0fa329b67..bf0ee8dbae6e 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -41,6 +41,24 @@ typedef enum {
41 PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */ 41 PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */
42} budget_signal_policy_t; 42} budget_signal_policy_t;
43 43
44/* Release behaviors for jobs. PERIODIC and EARLY jobs
45 must end by calling sys_complete_job() (or equivalent)
46 to set up their next release and deadline. */
47typedef enum {
48 /* Jobs are released sporadically (provided job precedence
49 constraints are met). */
50 SPORADIC,
51
52 /* Jobs are released periodically (provided job precedence
53 constraints are met). */
54 PERIODIC,
55
56 /* Jobs are released immediately after meeting precedence
57 constraints. Beware this can peg your CPUs if used in
58 the wrong applications. Only supported by EDF schedulers. */
59 EARLY
60} release_policy_t;
61
44typedef enum { 62typedef enum {
45 AUX_ENABLE = 0x1, 63 AUX_ENABLE = 0x1,
46 AUX_CURRENT = (AUX_ENABLE<<1), 64 AUX_CURRENT = (AUX_ENABLE<<1),
@@ -115,6 +133,7 @@ struct rt_task {
115 task_class_t cls; 133 task_class_t cls;
116 budget_policy_t budget_policy; /* ignored by pfair */ 134 budget_policy_t budget_policy; /* ignored by pfair */
117 budget_signal_policy_t budget_signal_policy; /* currently ignored by pfair */ 135 budget_signal_policy_t budget_signal_policy; /* currently ignored by pfair */
136 release_policy_t release_policy;
118}; 137};
119 138
120union np_flag { 139union np_flag {
diff --git a/litmus/Kconfig b/litmus/Kconfig
index 9e8ef804b499..437ce82f97e9 100644
--- a/litmus/Kconfig
+++ b/litmus/Kconfig
@@ -180,6 +180,27 @@ config SCHED_CPU_AFFINITY
180 180
181 Say Yes if unsure. 181 Say Yes if unsure.
182 182
183config ALLOW_EARLY_RELEASE
184 bool "Allow Early Releasing"
185 default y
186 help
187 Allow tasks to release jobs early (while still maintaining job
188 precedence constraints). Only supported by EDF schedulers. Early
189 releasing must be explicitly requested by real-time tasks via
190 the task_params passed to sys_set_task_rt_param().
191
192 Early releasing can improve job response times while maintaining
193 real-time correctness. However, it can easily peg your CPUs
194 since tasks never suspend to wait for their next job. As such, early
195 releasing is really only useful in the context of implementing
196 bandwidth servers, interrupt handling threads, or short-lived
197 computations.
198
199 Beware that early releasing may affect real-time analysis
200 if using locking protocols or I/O.
201
202 Say Yes if unsure.
203
183choice 204choice
184 prompt "EDF Tie-Break Behavior" 205 prompt "EDF Tie-Break Behavior"
185 default EDF_TIE_BREAK_LATENESS_NORM 206 default EDF_TIE_BREAK_LATENESS_NORM
diff --git a/litmus/Makefile b/litmus/Makefile
index 6b7acf0bbf2c..642a03617d4a 100644
--- a/litmus/Makefile
+++ b/litmus/Makefile
@@ -18,7 +18,8 @@ obj-y = sched_plugin.o litmus.o \
18 bheap.o \ 18 bheap.o \
19 binheap.o \ 19 binheap.o \
20 ctrldev.o \ 20 ctrldev.o \
21 aux_tasks.o \ 21 aux_tasks.o \
22 uncachedev.o \
22 sched_gsn_edf.o \ 23 sched_gsn_edf.o \
23 sched_psn_edf.o \ 24 sched_psn_edf.o \
24 sched_pfp.o 25 sched_pfp.o
diff --git a/litmus/aux_tasks.c b/litmus/aux_tasks.c
index a9fa9df5ef8b..db6523a3dcf7 100644
--- a/litmus/aux_tasks.c
+++ b/litmus/aux_tasks.c
@@ -27,14 +27,17 @@ static int admit_aux_task(struct task_struct *t)
27 * fail-safe. 27 * fail-safe.
28 */ 28 */
29 struct rt_task tp = { 29 struct rt_task tp = {
30 .exec_cost = AUX_SLICE_NS,
30 .period = AUX_SLICE_NS, 31 .period = AUX_SLICE_NS,
31 .relative_deadline = AUX_SLICE_NS, 32 .relative_deadline = AUX_SLICE_NS,
32 .exec_cost = AUX_SLICE_NS, /* allow full utilization with buget tracking */
33 .phase = 0, 33 .phase = 0,
34 .cpu = task_cpu(leader), /* take CPU of group leader */ 34 .cpu = task_cpu(leader), /* take CPU of group leader */
35 .priority = LITMUS_LOWEST_PRIORITY,
36 .cls = RT_CLASS_BEST_EFFORT,
35 .budget_policy = QUANTUM_ENFORCEMENT, 37 .budget_policy = QUANTUM_ENFORCEMENT,
36 .budget_signal_policy = NO_SIGNALS, 38 .budget_signal_policy = NO_SIGNALS,
37 .cls = RT_CLASS_BEST_EFFORT 39 /* use SPORADIC instead of EARLY since util = 1.0 */
40 .release_policy = SPORADIC,
38 }; 41 };
39 42
40 struct sched_param param = { .sched_priority = 0}; 43 struct sched_param param = { .sched_priority = 0};
diff --git a/litmus/jobs.c b/litmus/jobs.c
index 659625433867..991c6e60be74 100644
--- a/litmus/jobs.c
+++ b/litmus/jobs.c
@@ -8,14 +8,6 @@
8 8
9static inline void setup_release(struct task_struct *t, lt_t release) 9static inline void setup_release(struct task_struct *t, lt_t release)
10{ 10{
11 /* Shift all tasks that are actually daemons that inherit
12 * priority to be released immediatly. They need to be ready to run
13 * at _all_ times.
14 */
15 if (unlikely(is_persistent(t))) {
16 release = litmus_clock();
17 }
18
19 /* prepare next release */ 11 /* prepare next release */
20 t->rt_param.job_params.release = release; 12 t->rt_param.job_params.release = release;
21 t->rt_param.job_params.deadline = release + get_rt_relative_deadline(t); 13 t->rt_param.job_params.deadline = release + get_rt_relative_deadline(t);
diff --git a/litmus/litmus_softirq.c b/litmus/litmus_softirq.c
index aa83b363be7c..6ecea650673b 100644
--- a/litmus/litmus_softirq.c
+++ b/litmus/litmus_softirq.c
@@ -263,14 +263,17 @@ static int become_litmus_daemon(struct task_struct* tsk)
263 int ret = 0; 263 int ret = 0;
264 264
265 struct rt_task tp = { 265 struct rt_task tp = {
266 .exec_cost = KLMIRQD_SLICE_NS,
266 .period = KLMIRQD_SLICE_NS, 267 .period = KLMIRQD_SLICE_NS,
267 .relative_deadline = KLMIRQD_SLICE_NS, 268 .relative_deadline = KLMIRQD_SLICE_NS,
268 .exec_cost = KLMIRQD_SLICE_NS,
269 .phase = 0, 269 .phase = 0,
270 .cpu = task_cpu(current), 270 .cpu = task_cpu(current),
271 .priority = LITMUS_LOWEST_PRIORITY,
272 .cls = RT_CLASS_BEST_EFFORT,
271 .budget_policy = NO_ENFORCEMENT, 273 .budget_policy = NO_ENFORCEMENT,
272 .budget_signal_policy = NO_SIGNALS, 274 .budget_signal_policy = NO_SIGNALS,
273 .cls = RT_CLASS_BEST_EFFORT 275 /* use SPORADIC instead of EARLY since util = 1.0 */
276 .release_policy = SPORADIC,
274 }; 277 };
275 278
276 struct sched_param param = { .sched_priority = 0}; 279 struct sched_param param = { .sched_priority = 0};
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c
index efb11bb8c656..78ae5a080138 100644
--- a/litmus/sched_cedf.c
+++ b/litmus/sched_cedf.c
@@ -315,7 +315,7 @@ static noinline void requeue(struct task_struct* task)
315 /* sanity check before insertion */ 315 /* sanity check before insertion */
316 BUG_ON(is_queued(task)); 316 BUG_ON(is_queued(task));
317 317
318 if (is_released(task, litmus_clock())) 318 if (is_early_releasing(task) || is_released(task, litmus_clock())) {
319#ifdef CONFIG_REALTIME_AUX_TASKS 319#ifdef CONFIG_REALTIME_AUX_TASKS
320 if (unlikely(tsk_rt(task)->is_aux_task && task->state != TASK_RUNNING && !tsk_rt(task)->aux_ready)) { 320 if (unlikely(tsk_rt(task)->is_aux_task && task->state != TASK_RUNNING && !tsk_rt(task)->aux_ready)) {
321 /* aux_task probably transitioned to real-time while it was blocked */ 321 /* aux_task probably transitioned to real-time while it was blocked */
@@ -325,6 +325,7 @@ static noinline void requeue(struct task_struct* task)
325 else 325 else
326#endif 326#endif
327 __add_ready(&cluster->domain, task); 327 __add_ready(&cluster->domain, task);
328 }
328 else { 329 else {
329 TRACE_TASK(task, "not requeueing non-yet-released job\n"); 330 TRACE_TASK(task, "not requeueing non-yet-released job\n");
330 } 331 }
@@ -411,24 +412,22 @@ static void cedf_release_jobs(rt_domain_t* rt, struct bheap* tasks)
411/* caller holds cluster_lock */ 412/* caller holds cluster_lock */
412static noinline void job_completion(struct task_struct *t, int forced) 413static noinline void job_completion(struct task_struct *t, int forced)
413{ 414{
415 int do_release = 0;
414 lt_t now; 416 lt_t now;
415 BUG_ON(!t); 417 BUG_ON(!t);
416 418
417 sched_trace_task_completion(t, forced); 419 sched_trace_task_completion(t, forced);
418 420
419 TRACE_TASK(t, "job_completion() at %llu.\n", litmus_clock()); 421 now = litmus_clock();
420 422 TRACE_TASK(t, "job_completion() at %llu.\n", now);
421#ifdef CONFIG_LITMUS_LOCKING
422 BUG_ON(!is_persistent(t) && tsk_rt(t)->inh_task);
423#endif
424 423
425 /* set flags */ 424 /* set flags */
426 tsk_rt(t)->completed = 1; 425 tsk_rt(t)->completed = 1;
427 /* prepare for next period */ 426 /* prepare for next period */
428 prepare_for_next_period(t); 427 prepare_for_next_period(t);
429 428
430 now = litmus_clock(); 429 do_release = (is_early_releasing(t) || is_released(t, now));
431 if (is_released(t, now)) { 430 if (do_release) {
432 /* log here to capture overheads */ 431 /* log here to capture overheads */
433 sched_trace_task_release(t); 432 sched_trace_task_release(t);
434 } 433 }
@@ -438,7 +437,7 @@ static noinline void job_completion(struct task_struct *t, int forced)
438 /* release or arm next job */ 437 /* release or arm next job */
439 tsk_rt(t)->completed = 0; 438 tsk_rt(t)->completed = 0;
440 if (is_running(t)) { 439 if (is_running(t)) {
441 if (!is_released(t, now)) 440 if (!do_release)
442 add_release(&task_cpu_cluster(t)->domain, t); 441 add_release(&task_cpu_cluster(t)->domain, t);
443 else 442 else
444 cedf_job_arrival(t); 443 cedf_job_arrival(t);
@@ -1027,17 +1026,16 @@ static void cedf_task_wake_up(struct task_struct *task)
1027{ 1026{
1028 unsigned long flags; 1027 unsigned long flags;
1029 cedf_domain_t *cluster; 1028 cedf_domain_t *cluster;
1030 lt_t now = litmus_clock(); 1029 lt_t now;
1031
1032 TRACE_TASK(task, "wake_up at %llu\n", now);
1033 1030
1034 cluster = task_cpu_cluster(task); 1031 cluster = task_cpu_cluster(task);
1035 1032
1036 raw_spin_lock_irqsave(&cluster->cluster_lock, flags); 1033 raw_spin_lock_irqsave(&cluster->cluster_lock, flags);
1037 1034
1038 if (unlikely(is_persistent(task) && is_tardy(task, now))) { 1035 now = litmus_clock();
1039 /* treat tardy perisistent tasks as if they were sporadic 1036 TRACE_TASK(task, "wake_up at %llu\n", now);
1040 tasks by releasing a new job if they're tardy. */ 1037
1038 if (is_sporadic(task) && is_tardy(task, now)) {
1041 release_at(task, now); 1039 release_at(task, now);
1042 sched_trace_task_release(task); 1040 sched_trace_task_release(task);
1043 } 1041 }
@@ -1150,7 +1148,8 @@ static long cedf_admit_task(struct task_struct* tsk)
1150 edf_max_heap_base_priority_order); 1148 edf_max_heap_base_priority_order);
1151#endif 1149#endif
1152 1150
1153 return (task_cpu(tsk) == tsk->rt_param.task_params.cpu) ? 0 : -EINVAL; 1151 return (remote_cluster(task_cpu(tsk)) == task_cpu_cluster(tsk)) ?
1152 0 : -EINVAL;
1154} 1153}
1155 1154
1156 1155
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c
index 46a10fa17044..08cdf5c0e492 100644
--- a/litmus/sched_gsn_edf.c
+++ b/litmus/sched_gsn_edf.c
@@ -308,7 +308,7 @@ static noinline void requeue(struct task_struct* task)
308 /* sanity check before insertion */ 308 /* sanity check before insertion */
309 BUG_ON(is_queued(task)); 309 BUG_ON(is_queued(task));
310 310
311 if (is_released(task, litmus_clock())) { 311 if (is_early_releasing(task) || is_released(task, litmus_clock())) {
312#ifdef CONFIG_REALTIME_AUX_TASKS 312#ifdef CONFIG_REALTIME_AUX_TASKS
313 if (unlikely(tsk_rt(task)->is_aux_task && !is_running(task))) { 313 if (unlikely(tsk_rt(task)->is_aux_task && !is_running(task))) {
314 /* aux_task probably transitioned to real-time while it was blocked */ 314 /* aux_task probably transitioned to real-time while it was blocked */
@@ -411,8 +411,7 @@ static noinline void job_completion(struct task_struct *t, int forced)
411 tsk_rt(t)->completed = 1; 411 tsk_rt(t)->completed = 1;
412 /* prepare for next period */ 412 /* prepare for next period */
413 prepare_for_next_period(t); 413 prepare_for_next_period(t);
414 414 if (is_early_releasing(t) || is_released(t, litmus_clock()))
415 if (is_released(t, litmus_clock()))
416 sched_trace_task_release(t); 415 sched_trace_task_release(t);
417 /* unlink */ 416 /* unlink */
418 unlink(t); 417 unlink(t);
@@ -1008,7 +1007,7 @@ static void gsnedf_task_wake_up(struct task_struct *task)
1008#if 0 1007#if 0
1009 /* sporadic task model. will increment job numbers automatically */ 1008 /* sporadic task model. will increment job numbers automatically */
1010 now = litmus_clock(); 1009 now = litmus_clock();
1011 if (is_tardy(task, now)) { 1010 if (is_sporadic(task) && is_tardy(task, now)) {
1012 /* new sporadic release */ 1011 /* new sporadic release */
1013 release_at(task, now); 1012 release_at(task, now);
1014 sched_trace_task_release(task); 1013 sched_trace_task_release(task);
diff --git a/litmus/sched_pfair.c b/litmus/sched_pfair.c
index 6a89b003306c..d5fb3a832adc 100644
--- a/litmus/sched_pfair.c
+++ b/litmus/sched_pfair.c
@@ -710,7 +710,7 @@ static void pfair_task_wake_up(struct task_struct *t)
710 */ 710 */
711 requeue = tsk_rt(t)->flags == RT_F_REQUEUE; 711 requeue = tsk_rt(t)->flags == RT_F_REQUEUE;
712 now = litmus_clock(); 712 now = litmus_clock();
713 if (lt_before(get_deadline(t), now)) { 713 if (is_tardy(t, now)) {
714 TRACE_TASK(t, "sporadic release!\n"); 714 TRACE_TASK(t, "sporadic release!\n");
715 release_at(t, now); 715 release_at(t, now);
716 prepare_release(t, time2quanta(now, CEIL)); 716 prepare_release(t, time2quanta(now, CEIL));
diff --git a/litmus/sched_pfp.c b/litmus/sched_pfp.c
index 56d5a61c25e4..6edec830f063 100644
--- a/litmus/sched_pfp.c
+++ b/litmus/sched_pfp.c
@@ -359,7 +359,7 @@ static void pfp_task_wake_up(struct task_struct *task)
359 BUG_ON(is_queued(task)); 359 BUG_ON(is_queued(task));
360#endif 360#endif
361 now = litmus_clock(); 361 now = litmus_clock();
362 if (is_tardy(task, now) 362 if (is_sporadic(task) && is_tardy(task, now)
363#ifdef CONFIG_LITMUS_LOCKING 363#ifdef CONFIG_LITMUS_LOCKING
364 /* We need to take suspensions because of semaphores into 364 /* We need to take suspensions because of semaphores into
365 * account! If a job resumes after being suspended due to acquiring 365 * account! If a job resumes after being suspended due to acquiring
diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c
index fabff1be9bba..d1177cab152d 100644
--- a/litmus/sched_psn_edf.c
+++ b/litmus/sched_psn_edf.c
@@ -61,7 +61,7 @@ static void requeue(struct task_struct* t, rt_domain_t *edf)
61 TRACE_TASK(t, "requeue: !TASK_RUNNING\n"); 61 TRACE_TASK(t, "requeue: !TASK_RUNNING\n");
62 62
63 tsk_rt(t)->completed = 0; 63 tsk_rt(t)->completed = 0;
64 if (is_released(t, litmus_clock())) 64 if (is_early_releasing(t) || is_released(t, litmus_clock()))
65 __add_ready(edf, t); 65 __add_ready(edf, t);
66 else 66 else
67 add_release(edf, t); /* it has got to wait */ 67 add_release(edf, t); /* it has got to wait */
@@ -335,7 +335,7 @@ static void psnedf_task_wake_up(struct task_struct *task)
335 raw_spin_lock_irqsave(&pedf->slock, flags); 335 raw_spin_lock_irqsave(&pedf->slock, flags);
336 BUG_ON(is_queued(task)); 336 BUG_ON(is_queued(task));
337 now = litmus_clock(); 337 now = litmus_clock();
338 if (is_tardy(task, now) 338 if (is_sporadic(task) && is_tardy(task, now)
339#ifdef CONFIG_LITMUS_LOCKING 339#ifdef CONFIG_LITMUS_LOCKING
340 /* We need to take suspensions because of semaphores into 340 /* We need to take suspensions because of semaphores into
341 * account! If a job resumes after being suspended due to acquiring 341 * account! If a job resumes after being suspended due to acquiring
diff --git a/litmus/uncachedev.c b/litmus/uncachedev.c
new file mode 100644
index 000000000000..06a6a7c17983
--- /dev/null
+++ b/litmus/uncachedev.c
@@ -0,0 +1,102 @@
1#include <linux/sched.h>
2#include <linux/kernel.h>
3#include <linux/mm.h>
4#include <linux/fs.h>
5#include <linux/errno.h>
6#include <linux/highmem.h>
7#include <asm/page.h>
8#include <linux/miscdevice.h>
9#include <linux/module.h>
10
11#include <litmus/litmus.h>
12
13/* device for allocating pages not cached by the CPU */
14
15#define UNCACHE_NAME "litmus/uncache"
16
17void litmus_uncache_vm_open(struct vm_area_struct *vma)
18{
19}
20
21void litmus_uncache_vm_close(struct vm_area_struct *vma)
22{
23}
24
25int litmus_uncache_vm_fault(struct vm_area_struct* vma,
26 struct vm_fault* vmf)
27{
28 /* modeled after SG DMA video4linux, but without DMA. */
29 /* (see drivers/media/video/videobuf-dma-sg.c) */
30 struct page *page;
31
32 page = alloc_page(GFP_USER);
33 if (!page)
34 return VM_FAULT_OOM;
35
36 clear_user_highpage(page, (unsigned long)vmf->virtual_address);
37 vmf->page = page;
38
39 return 0;
40}
41
42static struct vm_operations_struct litmus_uncache_vm_ops = {
43 .open = litmus_uncache_vm_open,
44 .close = litmus_uncache_vm_close,
45 .fault = litmus_uncache_vm_fault,
46};
47
48static int litmus_uncache_mmap(struct file* filp, struct vm_area_struct* vma)
49{
50 /* first make sure mapper knows what he's doing */
51
52 /* you can only map the "first" page */
53 if (vma->vm_pgoff != 0)
54 return -EINVAL;
55
56 /* you can't share it with anyone */
57 if (vma->vm_flags & (VM_MAYSHARE | VM_SHARED))
58 return -EINVAL;
59
60 /* cannot be expanded, and is not a "normal" page. */
61 vma->vm_flags |= VM_DONTEXPAND;
62
63 /* noncached pages are not explicitly locked in memory (for now). */
64 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
65
66 vma->vm_ops = &litmus_uncache_vm_ops;
67
68 return 0;
69}
70
71static struct file_operations litmus_uncache_fops = {
72 .owner = THIS_MODULE,
73 .mmap = litmus_uncache_mmap,
74};
75
76static struct miscdevice litmus_uncache_dev = {
77 .name = UNCACHE_NAME,
78 .minor = MISC_DYNAMIC_MINOR,
79 .fops = &litmus_uncache_fops,
80 /* pages are not locked, so there is no reason why
81 anyone cannot allocate an uncache pages */
82 .mode = (S_IRUGO | S_IWUGO),
83};
84
85static int __init init_litmus_uncache_dev(void)
86{
87 int err;
88
89 printk("Initializing LITMUS^RT uncache device.\n");
90 err = misc_register(&litmus_uncache_dev);
91 if (err)
92 printk("Could not allocate %s device (%d).\n", UNCACHE_NAME, err);
93 return err;
94}
95
96static void __exit exit_litmus_uncache_dev(void)
97{
98 misc_deregister(&litmus_uncache_dev);
99}
100
101module_init(init_litmus_uncache_dev);
102module_exit(exit_litmus_uncache_dev);