00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
#include <linux/module.h>
00100
#include <linux/version.h>
00101
#include <linux/proc_fs.h>
00102
#include <linux/sched.h>
00103
#include <linux/slab.h>
00104
#include <linux/interrupt.h>
00105
#include <asm/uaccess.h>
00106
#include <asm/system.h>
00107
#include <asm/rtai_sched.h>
00108
#include <rtai_tasklets.h>
00109
#include <rtai_lxrt.h>
00110
#include <rtai_malloc.h>
00111
#include <rtai_schedcore.h>
00112
00113
MODULE_LICENSE(
"GPL");
00114
00115
#ifdef CONFIG_RTAI_MALLOC
00116 #define sched_malloc(size) rt_malloc((size))
00117 #define sched_free(adr) rt_free((adr))
00118
#else
00119
#define sched_malloc(size) kmalloc((size), GFP_KERNEL)
00120
#define sched_free(adr) kfree((adr))
00121
#endif
00122
00123
DEFINE_LINUX_CR0
00124
00125 static struct rt_tasklet_struct timers_list =
00126 { &
timers_list, &
timers_list,
RT_SCHED_LOWEST_PRIORITY, 0,
RT_TIME_END, 0LL, 0, 0, 0,
00127
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
00128
0, NULL, NULL, { NULL }
00129
#endif
00130
};
00131
00132 static struct rt_tasklet_struct tasklets_list =
00133 { &
tasklets_list, &
tasklets_list, };
00134
00135 static spinlock_t
tasklets_lock = SPIN_LOCK_UNLOCKED;
00136 static spinlock_t
timers_lock = SPIN_LOCK_UNLOCKED;
00137
00138
static struct rt_fun_entry
rt_tasklet_fun[]
__attribute__ ((__unused__));
00139
00140 static struct rt_fun_entry
rt_tasklet_fun[] = {
00141 { 0,
rt_init_tasklet },
00142 { 0,
rt_delete_tasklet },
00143 { 0,
rt_insert_tasklet },
00144 { 0,
rt_remove_tasklet },
00145 { 0,
rt_tasklet_use_fpu },
00146 { 0,
rt_insert_timer },
00147 { 0,
rt_remove_timer },
00148 { 0,
rt_set_timer_priority },
00149 { 0,
rt_set_timer_firing_time },
00150 { 0,
rt_set_timer_period },
00151 { 0,
rt_set_tasklet_handler },
00152 { 0,
rt_set_tasklet_data },
00153 { 0,
rt_exec_tasklet },
00154 { 0,
rt_wait_tasklet_is_hard },
00155 { 0,
rt_set_tasklet_priority },
00156 { 0,
rt_register_task },
00157 };
00158
00159
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
00160
00161
00162
static inline void enq_timer(
struct rt_tasklet_struct *timed_timer)
00163 {
00164
struct rt_tasklet_struct *timerh, *tmrnxt, *timer;
00165 rb_node_t **rbtn, *rbtpn = NULL;
00166 timer = timerh = &
timers_list;
00167 rbtn = &timerh->rbr.rb_node;
00168
00169
while (*rbtn) {
00170 rbtpn = *rbtn;
00171 tmrnxt = rb_entry(rbtpn,
struct rt_tasklet_struct, rbn);
00172
if (timer->firing_time > tmrnxt->firing_time) {
00173 rbtn = &(rbtpn)->rb_right;
00174 }
else {
00175 rbtn = &(rbtpn)->rb_left;
00176 timer = tmrnxt;
00177 }
00178 }
00179 rb_link_node(&timed_timer->rbn, rbtpn, rbtn);
00180 rb_insert_color(&timed_timer->rbn, &timerh->rbr);
00181 timer->prev = (timed_timer->
prev = timer->
prev)->next = timed_timer;
00182 timed_timer->
next = timer;
00183 }
00184
00185
static inline void rem_timer(
struct rt_tasklet_struct *timer)
00186 {
00187 (timer->
next)->prev = timer->
prev;
00188 (timer->
prev)->
next = timer->
next;
00189 timer->
next = timer->
prev = timer;
00190 rb_erase(&timer->rbn, &
timers_list.rbr);
00191 }
00192
00193
#else
00194
00195
00196 static inline void enq_timer(
struct rt_tasklet_struct *timed_timer)
00197 {
00198
struct rt_tasklet_struct *timer;
00199 timer = &
timers_list;
00200
while (timed_timer->
firing_time >= (timer = timer->next)->firing_time);
00201 timer->
prev = (timed_timer->
prev = timer->
prev)->
next = timed_timer;
00202 timed_timer->
next = timer;
00203 }
00204
00205 static inline void rem_timer(
struct rt_tasklet_struct *timer)
00206 {
00207 (timer->
next)->prev = timer->
prev;
00208 (timer->
prev)->
next = timer->
next;
00209 timer->
next = timer->
prev = timer;
00210 }
00211
00212
#endif
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
int rt_insert_tasklet(
struct rt_tasklet_struct *tasklet,
int priority,
void (*handler)(
unsigned long),
unsigned long data,
unsigned long id,
int pid)
00246 {
00247
unsigned long flags;
00248
00249
00250
if (!
handler || !
id) {
00251
return -EINVAL;
00252 }
00253 tasklet->
uses_fpu = 0;
00254 tasklet->
priority = priority;
00255 tasklet->
handler =
handler;
00256 tasklet->
data = data;
00257 tasklet->
id =
id;
00258
if (!
pid) {
00259 tasklet->
task = 0;
00260 }
else {
00261 (tasklet->
task)->priority = priority;
00262 rt_copy_to_user(tasklet->
usptasklet, tasklet,
sizeof(
struct rt_tasklet_struct));
00263 }
00264
00265
flags =
rt_spin_lock_irqsave(&tasklets_lock);
00266 tasklet->
next = &
tasklets_list;
00267 tasklet->
prev =
tasklets_list.
prev;
00268 (
tasklets_list.
prev)->
next = tasklet;
00269
tasklets_list.
prev = tasklet;
00270
rt_spin_unlock_irqrestore(flags, &tasklets_lock);
00271
return 0;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
void rt_remove_tasklet(
struct rt_tasklet_struct *tasklet)
00285 {
00286
if (tasklet->
next != tasklet && tasklet->
prev != tasklet) {
00287
unsigned long flags;
00288
flags =
rt_spin_lock_irqsave(&tasklets_lock);
00289 (tasklet->
next)->prev = tasklet->
prev;
00290 (tasklet->
prev)->
next = tasklet->
next;
00291 tasklet->
next = tasklet->
prev = tasklet;
00292
rt_spin_unlock_irqrestore(flags, &tasklets_lock);
00293 }
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 struct rt_tasklet_struct *
rt_find_tasklet_by_id(
unsigned long id)
00311 {
00312
struct rt_tasklet_struct *tasklet;
00313
00314 tasklet = &
tasklets_list;
00315
while ((tasklet = tasklet->
next) != &
tasklets_list) {
00316
if (
id == tasklet->
id) {
00317
return tasklet;
00318 }
00319 }
00320
return 0;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
int rt_exec_tasklet(
struct rt_tasklet_struct *tasklet)
00344 {
00345
if (tasklet && tasklet->
next != tasklet && tasklet->
prev != tasklet) {
00346
if (!tasklet->
task) {
00347 tasklet->
handler(tasklet->
data);
00348 }
else {
00349
rt_task_resume(tasklet->
task);
00350 }
00351
return 0;
00352 }
00353
return -EINVAL;
00354 }
00355
00356
void rt_set_tasklet_priority(
struct rt_tasklet_struct *tasklet,
int priority)
00357 {
00358 tasklet->
priority = priority;
00359
if (tasklet->
task) {
00360 (tasklet->
task)->priority = priority;
00361 }
00362 }
00363
00364
int rt_set_tasklet_handler(
struct rt_tasklet_struct *tasklet,
void (*handler)(
unsigned long))
00365 {
00366
if (!
handler) {
00367
return -EINVAL;
00368 }
00369 tasklet->
handler =
handler;
00370
if (tasklet->
task) {
00371 rt_copy_to_user(tasklet->
usptasklet, tasklet,
sizeof(
struct rt_tasklet_struct));
00372 }
00373
return 0;
00374 }
00375
00376
void rt_set_tasklet_data(
struct rt_tasklet_struct *tasklet,
unsigned long data)
00377 {
00378 tasklet->
data = data;
00379
if (tasklet->
task) {
00380 rt_copy_to_user(tasklet->
usptasklet, tasklet,
sizeof(
struct rt_tasklet_struct));
00381 }
00382 }
00383
00384
RT_TASK *
rt_tasklet_use_fpu(
struct rt_tasklet_struct *tasklet,
int use_fpu)
00385 {
00386 tasklet->
uses_fpu = use_fpu ? 1 : 0;
00387
return tasklet->
task;
00388 }
00389
00390 static RT_TASK timers_manager;
00391
00392 static inline void asgn_min_prio(
void)
00393 {
00394
00395
struct rt_tasklet_struct *timer;
00396
unsigned long flags;
00397
int priority;
00398
00399 priority = (timer =
timers_list.
next)->priority;
00400
flags =
rt_spin_lock_irqsave(&
timers_lock);
00401
while ((timer = timer->next) != &
timers_list) {
00402
if (timer->priority < priority) {
00403 priority = timer->priority;
00404 }
00405
rt_spin_unlock_irqrestore(
flags, &
timers_lock);
00406
flags =
rt_spin_lock_irqsave(&
timers_lock);
00407 }
00408
rt_spin_unlock_irqrestore(
flags, &
timers_lock);
00409
flags = rt_global_save_flags_and_cli();
00410
if (
timers_manager.priority > priority) {
00411
timers_manager.priority = priority;
00412
if (
timers_manager.state ==
RT_SCHED_READY) {
00413 rem_ready_task(&
timers_manager);
00414 enq_ready_task(&
timers_manager);
00415 }
00416 }
00417 rt_global_restore_flags(
flags);
00418 }
00419
00420 static inline void set_timer_firing_time(
struct rt_tasklet_struct *timer,
RTIME firing_time)
00421 {
00422
if (timer->
next != timer && timer->
prev != timer) {
00423
unsigned long flags;
00424
00425 timer->
firing_time = firing_time;
00426
flags =
rt_spin_lock_irqsave(&
timers_lock);
00427
rem_timer(timer);
00428
enq_timer(timer);
00429
rt_spin_unlock_irqrestore(
flags, &
timers_lock);
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
int rt_insert_timer(
struct rt_tasklet_struct *timer,
int priority,
RTIME firing_time,
RTIME period,
void (*handler)(
unsigned long),
unsigned long data,
int pid)
00471 {
00472
unsigned long flags;
00473
00474
00475
if (!
handler) {
00476
return -EINVAL;
00477 }
00478 timer->
uses_fpu = 0;
00479 timer->
priority = priority;
00480 timer->
firing_time = firing_time;
00481 timer->
period = period;
00482 timer->
handler =
handler;
00483 timer->
data = data;
00484
if (!
pid) {
00485 timer->
task = 0;
00486 }
else {
00487 (timer->
task)->priority = priority;
00488 rt_copy_to_user(timer->
usptasklet, timer,
sizeof(
struct rt_tasklet_struct));
00489 }
00490
00491
flags =
rt_spin_lock_irqsave(&timers_lock);
00492
enq_timer(timer);
00493
rt_spin_unlock_irqrestore(flags, &timers_lock);
00494
00495
if (timer->
priority <
timers_manager.priority) {
00496
timers_manager.priority = timer->
priority;
00497 }
00498
00499
flags = rt_global_save_flags_and_cli();
00500
if (
timers_list.
next == timer && (
timers_manager.state &
RT_SCHED_DELAYED) && firing_time <
timers_manager.resume_time) {
00501
timers_manager.resume_time = firing_time;
00502 rem_timed_task(&timers_manager);
00503 enq_timed_task(&timers_manager);
00504
rt_schedule();
00505 }
00506 rt_global_restore_flags(flags);
00507
return 0;
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
void rt_remove_timer(
struct rt_tasklet_struct *timer)
00521 {
00522
if (timer->
next != timer && timer->
prev != timer) {
00523
unsigned long flags;
00524
flags =
rt_spin_lock_irqsave(&timers_lock);
00525
rem_timer(timer);
00526
rt_spin_unlock_irqrestore(flags, &timers_lock);
00527
asgn_min_prio();
00528 }
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
void rt_set_timer_priority(
struct rt_tasklet_struct *timer,
int priority)
00548 {
00549 timer->
priority = priority;
00550
if (timer->
task) {
00551 (timer->
task)->priority = priority;
00552 }
00553
asgn_min_prio();
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
void rt_set_timer_firing_time(
struct rt_tasklet_struct *timer,
RTIME firing_time)
00577 {
00578
unsigned long flags;
00579
00580
set_timer_firing_time(timer, firing_time);
00581
flags = rt_global_save_flags_and_cli();
00582
if (
timers_list.
next == timer && (
timers_manager.state &
RT_SCHED_DELAYED) && firing_time <
timers_manager.resume_time) {
00583
timers_manager.resume_time = firing_time;
00584 rem_timed_task(&timers_manager);
00585 enq_timed_task(&timers_manager);
00586
rt_schedule();
00587 }
00588 rt_global_restore_flags(flags);
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
void rt_set_timer_period(
struct rt_tasklet_struct *timer,
RTIME period)
00616 {
00617
unsigned long flags;
00618
flags =
rt_spin_lock_irqsave(&timers_lock);
00619 timer->
period = period;
00620
rt_spin_unlock_irqrestore(flags, &timers_lock);
00621 }
00622
00623
00624
00625 static void rt_timers_manager(
long dummy)
00626 {
00627
RTIME now;
00628
struct rt_tasklet_struct *tmr, *timer;
00629
unsigned long flags;
00630
int priority, used_fpu;
00631
00632
while (1) {
00633
rt_sleep_until((
timers_list.
next)->firing_time);
00634 now =
timers_manager.resume_time +
tuned.timers_tol[0];
00635
00636
while (1) {
00637 used_fpu = 0;
00638 tmr = timer = &
timers_list;
00639 priority =
RT_SCHED_LOWEST_PRIORITY;
00640
flags =
rt_spin_lock_irqsave(&
timers_lock);
00641
while ((tmr = tmr->next)->firing_time <= now) {
00642
if (tmr->priority < priority) {
00643 priority = (timer = tmr)->priority;
00644 }
00645 }
00646
timers_manager.priority = priority;
00647
rt_spin_unlock_irqrestore(
flags, &
timers_lock);
00648
if (timer == &
timers_list) {
00649
break;
00650 }
00651
if (!timer->period) {
00652
flags =
rt_spin_lock_irqsave(&
timers_lock);
00653
rem_timer(timer);
00654
rt_spin_unlock_irqrestore(
flags, &
timers_lock);
00655 }
else {
00656
set_timer_firing_time(timer, timer->firing_time + timer->period);
00657 }
00658
if (!timer->task) {
00659
if (!used_fpu && timer->uses_fpu) {
00660 used_fpu = 1;
00661
save_fpcr_and_enable_fpu(
linux_cr0);
00662
save_fpenv(
timers_manager.fpu_reg);
00663 }
00664 timer->handler(timer->data);
00665 }
else {
00666
rt_task_resume(timer->task);
00667 }
00668 }
00669
if (used_fpu) {
00670
restore_fpenv(
timers_manager.fpu_reg);
00671
restore_fpcr(
linux_cr0);
00672 }
00673
00674
asgn_min_prio();
00675
00676 }
00677 }
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
struct rt_tasklet_struct *
rt_init_tasklet(
void)
00693 {
00694
struct rt_tasklet_struct *tasklet;
00695 tasklet =
sched_malloc(
sizeof(
struct rt_tasklet_struct));
00696 memset(tasklet, 0,
sizeof(
struct rt_tasklet_struct));
00697
return tasklet;
00698 }
00699
00700 void rt_register_task(
struct rt_tasklet_struct *tasklet,
struct rt_tasklet_struct *usptasklet,
RT_TASK *task)
00701 {
00702 tasklet->
task =
task;
00703 tasklet->
usptasklet = usptasklet;
00704 rt_copy_to_user(usptasklet, tasklet,
sizeof(
struct rt_tasklet_struct));
00705 }
00706
00707 void rt_wait_tasklet_is_hard(
struct rt_tasklet_struct *tasklet,
int thread)
00708 {
00709 tasklet->
thread = thread;
00710
while (!tasklet->
task || !((tasklet->
task)->state &
RT_SCHED_SUSPENDED)) {
00711 current->state = TASK_INTERRUPTIBLE;
00712 schedule_timeout(2);
00713 }
00714 }
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
int rt_delete_tasklet(
struct rt_tasklet_struct *tasklet)
00732 {
00733
int thread;
00734
00735
rt_remove_tasklet(tasklet);
00736 tasklet->
handler = 0;
00737 rt_copy_to_user(tasklet->
usptasklet, tasklet,
sizeof(
struct rt_tasklet_struct));
00738
rt_task_resume(tasklet->
task);
00739 thread = tasklet->
thread;
00740
sched_free(tasklet);
00741
return thread;
00742 }
00743
00744 static int tasklets_stacksize =
TASKLET_STACK_SIZE;
00745
MODULE_PARM(tasklets_stacksize,
"i");
00746
00747 static RT_TASK *
rt_base_linux_task;
00748
00749 int __rtai_tasklets_init(
void)
00750 {
00751
RT_TASK *rt_linux_tasks[
NR_RT_CPUS];
00752
rt_base_linux_task =
rt_get_base_linux_task(rt_linux_tasks);
00753
if (
rt_sched_type() ==
RT_SCHED_MUP) {
00754
tuned.timers_tol[0] =
tuned.timers_tol[
timers_manager.runnable_on_cpus];
00755 }
00756
if(
rt_base_linux_task->task_trap_handler[0]) {
00757
if(((int (*)(
void *,
int))
rt_base_linux_task->task_trap_handler[0])(
rt_tasklet_fun,
TSKIDX)) {
00758
printk(
"Recompile your module with a different index\n");
00759
return -EACCES;
00760 }
00761 }
00762
rt_task_init(&
timers_manager,
rt_timers_manager, 0,
tasklets_stacksize,
RT_SCHED_LOWEST_PRIORITY, 0, 0);
00763
rt_task_resume(&
timers_manager);
00764
printk(KERN_INFO
"RTAI[tasklets]: loaded.\n");
00765
return 0;
00766 }
00767
00768 void __rtai_tasklets_exit(
void)
00769 {
00770
rt_task_delete(&
timers_manager);
00771
if(
rt_base_linux_task->task_trap_handler[1]) {
00772 ((int (*)(
void *,
int))
rt_base_linux_task->task_trap_handler[1])(
rt_tasklet_fun,
TSKIDX);
00773 }
00774
printk(KERN_INFO
"RTAI[tasklets]: unloaded.\n");
00775 }
00776
00777
00778
00779
#ifndef CONFIG_RTAI_TASKLETS_BUILTIN
00780
module_init(__rtai_tasklets_init);
00781
module_exit(__rtai_tasklets_exit);
00782
#endif
00783
00784
#ifdef CONFIG_KBUILD
00785
EXPORT_SYMBOL(rt_insert_tasklet);
00786
EXPORT_SYMBOL(rt_remove_tasklet);
00787
EXPORT_SYMBOL(rt_find_tasklet_by_id);
00788
EXPORT_SYMBOL(rt_exec_tasklet);
00789
EXPORT_SYMBOL(rt_set_tasklet_priority);
00790
EXPORT_SYMBOL(rt_set_tasklet_handler);
00791
EXPORT_SYMBOL(rt_set_tasklet_data);
00792
EXPORT_SYMBOL(rt_tasklet_use_fpu);
00793
EXPORT_SYMBOL(rt_insert_timer);
00794
EXPORT_SYMBOL(rt_remove_timer);
00795
EXPORT_SYMBOL(rt_set_timer_priority);
00796
EXPORT_SYMBOL(rt_set_timer_firing_time);
00797
EXPORT_SYMBOL(rt_set_timer_period);
00798
EXPORT_SYMBOL(rt_init_tasklet);
00799
EXPORT_SYMBOL(rt_register_task);
00800
EXPORT_SYMBOL(rt_wait_tasklet_is_hard);
00801
EXPORT_SYMBOL(rt_delete_tasklet);
00802
#endif