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
#include <linux/module.h>
00097
#include <linux/init.h>
00098
#include <linux/version.h>
00099
#include <asm/io.h>
00100
00101
#ifdef CONFIG_PROC_FS
00102
#include <linux/stat.h>
00103
#include <linux/proc_fs.h>
00104
#include <rtai_proc_fs.h>
00105
static struct proc_dir_entry *wd_proc;
00106
static int wdog_read_proc(
char *page,
char **start, off_t off,
int count,
00107
int *eof,
void *data);
00108
#endif
00109
00110
#include <asm/rtai.h>
00111
#include <rtai_sched.h>
00112
#include <rtai_wd.h>
00113
00114
00115
00116
#ifdef WDBUG
00117
#define LPT_PORT 0x378
00118
#define DBUG WDLOG
00119
#else
00120 #define DBUG(x...)
00121
#endif
00122
00123
00124 #define MY_ALLOC
00125
#ifndef MY_ALLOC
00126
#ifdef CONFIG_RTAI_MALLOC
00127
#include <rtai_malloc.h>
00128
#else
00129
#define MY_ALLOC // Not configured so we must use our own
00130
#endif
00131
#endif
00132
#ifdef MY_ALLOC
00133 #define BAD_TASK_MAX 100 // Feel free to change this
00134
00135 static spinlock_t
alloc_lock = SPIN_LOCK_UNLOCKED;
00136 static BAD_RT_TASK bad_task_pool[
BAD_TASK_MAX];
00137
#endif
00138
00139
00140 static char version[] =
"$Revision: 1.5 $";
00141 static char ver[10];
00142
00143
00144 static char *
policy_name[] =
00145 {
"Nothing",
"Resync",
"Debug",
"Stretch",
"Slip",
"Suspend",
"Kill"};
00146
00147
00148 static int num_wdogs;
00149 static RT_TASK wdog[
NR_RT_CPUS];
00150 static RT_TASK *
tlists[
NR_RT_CPUS];
00151 static RT_TASK **
smp_current;
00152 static BAD_RT_TASK *
bad_tl[
NR_RT_CPUS];
00153 static int sched;
00154
00155
00156
00157 static int TickPeriod = 10000000;
00158
MODULE_PARM(TickPeriod,
"i");
00159
00160 static int wd_OneShot = 1;
00161
MODULE_PARM(wd_OneShot,
"i");
00162
00163 static int Grace = 3;
00164
MODULE_PARM(Grace,
"i");
00165
00166 static int GraceDiv = 1;
00167
MODULE_PARM(GraceDiv,
"i");
00168
00169 static int Safety = 100;
00170
MODULE_PARM(Safety,
"i");
00171
00172 static wd_policy Policy =
WD_SUSPEND;
00173
MODULE_PARM(Policy,
"i");
00174
00175 static int Stretch = 10;
00176
MODULE_PARM(Stretch,
"i");
00177
00178 static int Slip = 10;
00179
MODULE_PARM(Slip,
"i");
00180
00181 static int Limit = 100;
00182
MODULE_PARM(Limit,
"i");
00183
00184
00185 int rt_wdset_grace(
int new)
00186 {
00187
int old =
Grace;
00188
00189
if (
Policy <=
WD_STRETCH &&
new != 1)
return -EINVAL;
00190
if (
new < 1)
return -EINVAL;
00191
Grace =
new;
00192
return old;
00193 }
00194
00195 int rt_wdset_gracediv(
int new)
00196 {
00197
int old =
GraceDiv;
00198
00199
if (
Policy <=
WD_STRETCH &&
new != 1)
return -EINVAL;
00200
if (
new < 1)
return -EINVAL;
00201
GraceDiv =
new;
00202
return old;
00203 }
00204
00205 int rt_wdset_safety(
int new)
00206 {
00207
int old =
Safety;
00208
00209
if (
new >= 0 &&
new <
Grace)
return -EINVAL;
00210
Safety =
new;
00211
return old;
00212 }
00213
00214 wd_policy rt_wdset_policy(
wd_policy new)
00215 {
00216
wd_policy old =
Policy;
00217
00218
if (new < WD_NOTHING || new >
WD_KILL)
return -EINVAL;
00219
if (
new <=
WD_STRETCH)
Grace =
GraceDiv = 1;
00220
if (
new ==
WD_DEBUG)
Safety =
Limit = -1;
00221
Policy =
new;
00222
return old;
00223 }
00224
00225 int rt_wdset_slip(
int new)
00226 {
00227
int old =
Slip;
00228
00229
if (
new < 0)
return -EINVAL;
00230
Slip =
new;
00231
return old;
00232 }
00233
00234 int rt_wdset_stretch(
int new)
00235 {
00236
int old =
Stretch;
00237
00238
if (
new < 0)
return -EINVAL;
00239
Stretch =
new;
00240
return old;
00241 }
00242
00243 int rt_wdset_limit(
int new)
00244 {
00245
int old =
Limit;
00246
00247
Limit =
new;
00248
return old;
00249 }
00250
00251
00252 static BAD_RT_TASK *
new_bad_task(
void)
00253 {
00254
#ifdef MY_ALLOC
00255
int bt;
00256
00257 spin_lock(&
alloc_lock);
00258
for (bt = 0; bt <
BAD_TASK_MAX; bt++) {
00259
if (!(
bad_task_pool[bt].
in_use)) {
00260
bad_task_pool[bt].
in_use = 1;
00261 spin_unlock(&
alloc_lock);
00262
return &
bad_task_pool[bt];
00263 }
00264 }
00265 spin_unlock(&
alloc_lock);
00266
return NULL;
00267
#else
00268
return rt_malloc(
sizeof(
BAD_RT_TASK));
00269
#endif
00270
}
00271
00272 static void free_bad_task(
BAD_RT_TASK *bt)
00273 {
00274
#ifdef MY_ALLOC
00275
bt->
in_use = 0;
00276
#else
00277
rt_free(bt);
00278
#endif
00279
}
00280
00281
00282 static void append_bad_task(
BAD_RT_TASK **list,
BAD_RT_TASK *
new)
00283 {
00284
BAD_RT_TASK *end = *list;
00285
00286
if (!end) {
00287 *list =
new;
00288 }
else {
00289
while (end->
next) end = end->
next;
00290 end->
next =
new;
00291 }
00292 }
00293
00294 static BAD_RT_TASK *
delete_bad_task(
BAD_RT_TASK **list,
BAD_RT_TASK *del)
00295 {
00296
BAD_RT_TASK *rtn, *bt = *list;
00297
00298
if (bt == del) {
00299 rtn = *list = NULL;
00300 }
else {
00301
while (bt->
next != del) bt = bt->
next;
00302 rtn = bt->
next = del->
next;
00303 }
00304
free_bad_task(del);
00305
return rtn;
00306 }
00307
00308 static BAD_RT_TASK *
find_bad_task(
BAD_RT_TASK *list,
RT_TASK *t)
00309 {
00310
BAD_RT_TASK *bt = list;
00311
00312
while (bt) {
00313
if (bt->
task == t)
break;
00314 bt = bt->
next;
00315 }
00316
return bt;
00317 }
00318
00319
00320 static int which_cpu(
RT_TASK *t)
00321 {
00322
int cpuid;
00323
00324
switch (
sched) {
00325
case RT_SCHED_UP:
00326
return 0;
00327
case RT_SCHED_MUP:
00328
return hard_cpu_id();
00329
case RT_SCHED_SMP:
00330
for (
cpuid = 0;
cpuid <
NR_RT_CPUS;
cpuid++) {
00331
if (t ==
smp_current[
cpuid]) {
00332
return cpuid;
00333 }
00334 }
00335
return hard_cpu_id();
00336 }
00337
return -1;
00338 }
00339
00340
00341 static void smpproof_task_suspend(
RT_TASK *t)
00342 {
00343
int cpuid;
00344
00345
rt_task_suspend(t);
00346
if ((
cpuid =
which_cpu(t)) >=
num_wdogs) {
00347
DBUG(
"Resuming dummy watchdog %d\n",
cpuid);
00348
rt_task_resume(&
wdog[
cpuid]);
00349 }
00350 }
00351
00352 static void smpproof_task_delete(
RT_TASK *t)
00353 {
00354
int cpuid;
00355
00356
rt_task_delete(t);
00357
if ((
cpuid =
which_cpu(t)) >=
num_wdogs) {
00358
DBUG(
"Resuming dummy watchdog %d\n",
cpuid);
00359
rt_task_resume(&
wdog[
cpuid]);
00360 }
00361 }
00362
00363
00364 static void stretch_badtask(
RT_TASK *t,
BAD_RT_TASK *bt,
int cpuid)
00365 {
00366
00367 t->period +=
llimd(bt->
orig_period,
Stretch, 100);
00368 t->resync_frame = 1;
00369
DBUG(
"...by %d%% to %uns\n",
00370
Stretch, (
int)
count2nano_cpuid(t->period,
cpuid));
00371 }
00372
00373 static void start_slipping_badtask(
RT_TASK *t,
BAD_RT_TASK *bt,
int cpuid)
00374 {
00375
00376 bt->
slipping = 1;
00377 bt->
countdown =
llimd(
llimd(
count2nano_cpuid(t->period,
cpuid),
Slip, 100),
00378 1,
00379
TickPeriod);
00380
DBUG(
"Suspending task 0x%X for %d ticks (slip %d)\n",
00381 t, bt->
countdown, bt->
count);
00382
00383
00384
smpproof_task_suspend(t);
00385 }
00386
00387 static void check_slipping_badtask(
BAD_RT_TASK *bt)
00388 {
00389
00390
if (--(bt->
countdown) <= 0) {
00391 bt->
slipping = 0;
00392
rt_task_resume(bt->
task);
00393
DBUG(
"Finished slip %d of task 0x%X, resuming\n", bt->
count, bt->
task);
00394 }
00395 }
00396
00397
00398 static void handle_badtask(
int wd,
RT_TASK *t,
BAD_RT_TASK *bt,
RTIME overrun)
00399 {
00400
00401
if (!bt) {
00402 bt =
new_bad_task();
00403
if (!bt)
return;
00404 bt->
task = t;
00405 bt->
next = NULL;
00406 bt->
slipping = 0;
00407 bt->
count = 0;
00408 bt->
countdown = 0;
00409 bt->
valid = 1;
00410 bt->
forced = 0;
00411 bt->
orig_period = t->period;
00412
append_bad_task(&
bad_tl[wd], bt);
00413 }
00414
00415
00416 (bt->
count)++;
00417 bt->
policy =
Policy;
00418
00419
00420
if ((overrun >= (
Safety * bt->
orig_period)) && (
Safety >= 0)) {
00421
WDLOG(
"Forcing suspension of severely overrun task %p\n", t);
00422 bt->
forced = 1;
00423
smpproof_task_suspend(t);
00424
return;
00425 }
00426
00427
00428
if ((bt->
count >=
Limit) && (
Limit >= 0)) {
00429
WDLOG(
"Task %p reached offence limit, suspending\n", t);
00430 bt->
forced = 1;
00431
smpproof_task_suspend(t);
00432
return;
00433 }
00434
00435
00436
switch (
Policy) {
00437
00438
case WD_NOTHING:
00439
break;
00440
00441
case WD_RESYNC:
00442
case WD_DEBUG:
00443
WDLOG(
"Resynchronising task %p\n", t);
00444 t->resync_frame = 1;
00445
break;
00446
00447
case WD_STRETCH:
00448
WDLOG(
"Stretching period of task %p\n", t);
00449
stretch_badtask(t, bt, wd);
00450
break;
00451
00452
case WD_SLIP:
00453
WDLOG(
"Slipping task %p\n", t);
00454
start_slipping_badtask(t, bt, wd);
00455
break;
00456
00457
case WD_SUSPEND:
00458
WDLOG(
"Suspending task %p\n", t);
00459
smpproof_task_suspend(t);
00460
break;
00461
00462
case WD_KILL:
00463
WDLOG(
"Killing task %p\n", t);
00464
smpproof_task_delete(t);
00465
break;
00466
00467
default:
00468
WDLOG(
"Invalid policy (%d)\n",
Policy);
00469
break;
00470 }
00471 }
00472
00473
00474 static void watchdog(
long wd)
00475 {
00476
#ifdef WDBUG
00477
int led = 0;
00478
static int output = 0x0000;
00479
#endif
00480
RT_TASK *
task, *
self =
rt_whoami();
00481
BAD_RT_TASK *bt;
00482
RTIME now, overrun;
00483
int another, dog;
00484
00485
while (1) {
00486
#ifdef WDBUG
00487
00488 led = !led;
00489
if (led) output |= (1 << wd);
00490
else output &= ~(1 << wd);
00491 outb(output, LPT_PORT);
00492
#endif
00493
00494 now =
rt_get_time_cpuid(wd);
00495
if (now -
self->resume_time >=
self->period) {
00496
self->resync_frame = 1;
00497
rt_task_wait_period();
00498
DBUG(
"Resynchronised watchdog %d\n", wd);
00499
continue;
00500 }
00501
00502
00503
for (bt =
bad_tl[wd]; bt; bt->
valid = 0, bt = bt->
next);
00504
00505
00506
task =
tlists[wd];
00507
while ((
task =
task->next)) {
00508
00509
00510
if (
task ==
self)
continue;
00511
for (another = dog = 0; dog <
num_wdogs; dog++) {
00512
if (
task == &
wdog[dog]) {
00513 another = 1 + dog;
00514
break;
00515 }
00516 }
00517
00518
00519
if ((bt =
find_bad_task(
bad_tl[wd],
task))) {
00520 bt->
valid = 1;
00521
if (bt->
slipping) {
00522
check_slipping_badtask(bt);
00523
continue;
00524 }
00525 }
00526
00527
00528
if (!
task->period ||
task->resync_frame ||
task->state &
00529 (
RT_SCHED_SUSPENDED|
RT_SCHED_DELAYED|
RT_SCHED_SEMAPHORE|
RT_SCHED_SEND|
RT_SCHED_RECEIVE|
RT_SCHED_RPC|
RT_SCHED_RETURN)) {
00530
continue;
00531 }
00532
00533
00534 overrun = now -
task->resume_time;
00535
if (overrun >=
llimd(
task->period,
Grace,
GraceDiv)) {
00536
if (another--) {
00537
WDLOG(
"WARNING: Watchdog %d is overrunning\n", another);
00538 }
else {
00539
WDLOG(
"Found overrunning task %p (list %d)\n",
task, wd);
00540
handle_badtask(wd,
task, bt, overrun);
00541 }
00542 }
00543 }
00544
00545
00546
for (bt =
bad_tl[wd]; bt;) {
00547
if (!(bt->
valid)) {
00548 bt =
delete_bad_task(&
bad_tl[wd], bt);
00549 }
else {
00550 bt = bt->
next;
00551 }
00552 }
00553
00554
00555
rt_task_wait_period();
00556 }
00557 }
00558
00559
00560 static void dummy(
long wd)
00561 {
00562
00563
while (1) {
00564
rt_task_suspend(&
wdog[wd]);
00565 }
00566 }
00567
00568
00569
#ifdef CONFIG_PROC_FS
00570
static int wdog_read_proc(
char *page,
char **start, off_t off,
int count,
00571
int *eof,
void *data)
00572 {
00573
PROC_PRINT_VARS;
00574
RT_TASK *
task;
00575
BAD_RT_TASK *bt;
00576
long onsec, osec;
00577
long ansec, asec;
00578
int cpuid, tl,
id = 1;
00579
char action[10];
00580
00581
00582
PROC_PRINT(
"\nRTAI Watchdog Status\n");
00583
PROC_PRINT(
"--------------------\n");
00584
PROC_PRINT(
"%d Watchdog task%s running @ %dHz in %s mode\n",
00585 num_wdogs, num_wdogs > 1 ?
"s" :
"",
00586 (
int)
imuldiv(NSECS_PER_SEC, 1, TickPeriod),
00587 wd_OneShot ?
"oneshot" :
"periodic");
00588
#ifdef MY_ALLOC
00589
PROC_PRINT(
"Using static memory management (%d entries)\n", BAD_TASK_MAX);
00590
#else
00591
PROC_PRINT(
"Using dynamic memory management\n");
00592
#endif
00593
PROC_PRINT(
"Policy : '%s'\n", policy_name[Policy]);
00594
PROC_PRINT(
"Grace periods : %d%s\n", Grace,
00595 (Policy <= WD_STRETCH) ?
" (forced)" :
"");
00596
PROC_PRINT(
"Grace divisor : %d%s\n", GraceDiv,
00597 (Policy <= WD_STRETCH) ?
" (forced)" :
"");
00598
PROC_PRINT(
"Safety limit : ");
00599
if (
Safety < 0) {
00600
PROC_PRINT(
"(disabled)\n");
00601 }
else {
00602
PROC_PRINT(
"%d period%s\n", Safety, Safety > 1 ?
"s" :
"");
00603 }
00604
PROC_PRINT(
"Slip factor : %d%%\n", Slip);
00605
PROC_PRINT(
"Stretch factor : %d%%\n", Stretch);
00606
PROC_PRINT(
"Offense limit : ");
00607
if (
Limit < 0) {
00608
PROC_PRINT(
"(disabled)\n");
00609 }
else {
00610
PROC_PRINT(
"%d\n", Limit);
00611 }
00612
00613
00614
PROC_PRINT(
"\nBad tasks...\n\n");
00615
PROC_PRINT(
"RT Task ID "
00616
"CPU%s "
00617
"Priority State Count "
00618
"Original period Adjusted period "
00619
"Action\n",
00620 (sched == RT_SCHED_SMP) ?
"s" :
"");
00621
PROC_PRINT(
"---------- -- "
00622
"---%s "
00623
"-------- ----- ----- "
00624
"--------------- --------------- "
00625
"---------\n",
00626 (sched == RT_SCHED_SMP) ?
"-" :
"");
00627
for (tl = 0; tl <
num_wdogs; tl++) {
00628
task =
tlists[tl];
00629
while ((
task =
task->next)) {
00630
if ((bt =
find_bad_task(bad_tl[tl], task))) {
00631
if (bt->
forced) {
00632 sprintf(action,
"%s *", policy_name[WD_SUSPEND]);
00633 }
else {
00634 strcpy(action, policy_name[bt->
policy]);
00635 }
00636
cpuid = (
sched ==
RT_SCHED_MUP) ?
task->runnable_on_cpus : 0;
00637 osec =
ulldiv(
count2nano_cpuid(bt->
orig_period, cpuid),
00638 NSECS_PER_SEC,
00639 &onsec);
00640 asec =
ulldiv(
count2nano_cpuid(
task->period, cpuid),
00641 NSECS_PER_SEC,
00642 &ansec);
00643
PROC_PRINT(
"0x%08lx %-2d "
00644
"%s%-2d%s "
00645
"%-8d 0x%-3x %-5d "
00646
"%02ds %09dns %02ds %09dns "
00647
"%s\n",
00648 (
long)task,
id,
00649 (sched == RT_SCHED_SMP) ?
"0x" :
"",
00650 (sched == RT_SCHED_UP) ?
00651 0 : (
int)
task->runnable_on_cpus,
00652 (sched == RT_SCHED_SMP) ?
"" :
" ",
00653
task->priority,
task->state, bt->
count,
00654 (
int)osec, (
int)onsec, (
int)asec, (
int)ansec,
00655 action);
00656 }
00657
id++;
00658 }
00659 }
00660
PROC_PRINT_DONE;
00661 }
00662
#endif
00663
00664
00665 int __rtai_wd_init(
void)
00666 {
00667
RTIME period;
00668
int dog;
00669
RT_TASK *lnx0;
00670
struct apic_timer_setup_data apic_data[
NR_RT_CPUS];
00671
char *c;
00672
00673
00674
if (
Policy <=
WD_STRETCH)
Grace =
GraceDiv = 1;
00675
if (
Policy ==
WD_DEBUG)
Safety =
Limit = -1;
00676
00677
00678
switch (
sched =
rt_sched_type()) {
00679
case RT_SCHED_UP :
00680
case RT_SCHED_SMP :
num_wdogs = 1;
break;
00681
case RT_SCHED_MUP :
num_wdogs =
NR_RT_CPUS;
break;
00682 }
00683
00684
00685 lnx0 =
rt_get_base_linux_task(
tlists);
00686
00687
00688
for (dog = 0; dog <
NR_RT_CPUS; dog++) {
00689
if ((
smp_current =
rt_register_watchdog(&
wdog[dog], dog)) < 0) {
00690
WDLOG(
"Failed to register watchdog %d with RTAI scheduler\n", dog);
00691
for (dog--; dog >= 0; dog--)
rt_deregister_watchdog(&
wdog[dog], dog);
00692
return -EBUSY;
00693 }
00694 }
00695
00696
00697
00698
if (
sched ==
RT_SCHED_MUP) {
00699
for (dog = 0; dog <
num_wdogs; dog++) {
00700 apic_data[dog].mode = !
wd_OneShot;
00701 apic_data[dog].count =
TickPeriod;
00702
if (
wd_OneShot) {
00703
00704 }
00705 }
00706
start_rt_apic_timers(apic_data, 0);
00707 }
else {
00708
if (
wd_OneShot) {
00709
rt_set_oneshot_mode();
00710
00711 }
else {
00712
rt_set_periodic_mode();
00713 }
00714
start_rt_timer((
int)
nano2count(
TickPeriod));
00715 }
00716
00717
00718
00719
00720
00721
for (dog = 0; dog <
NR_RT_CPUS; dog++) {
00722
rt_task_init_cpuid( &
wdog[dog],
00723 (dog <
num_wdogs) ?
watchdog :
dummy,
00724 dog, 2000,
RT_SCHED_HIGHEST_PRIORITY, 0, 0, dog);
00725 }
00726
for (dog = 0; dog <
num_wdogs; dog++) {
00727 period =
nano2count_cpuid(
TickPeriod, dog);
00728
rt_task_make_periodic( &
wdog[dog],
00729
rt_get_time_cpuid(dog) + period,
00730 period);
00731 }
00732
00733
00734
if ((c = strchr(
version,
' '))) {
00735 *(strchr(c,
'$')) =
'\0';
00736 strcpy(
ver, c + 1);
00737 }
else {
00738 strcpy(
ver,
"? ");
00739 }
00740
00741
00742
WDLOG(
"loaded.\n");
00743
WDLOG(
"%d Watchdog task%s running @ %dHz in %s mode\n",
00744
num_wdogs,
num_wdogs > 1 ?
"s" :
"",
00745
imuldiv(
NSECS_PER_SEC, 1,
TickPeriod),
00746
wd_OneShot ?
"oneshot" :
"periodic");
00747
#ifdef MY_ALLOC
00748
WDLOG(
"Using static memory management (%d entries)\n",
BAD_TASK_MAX);
00749
#else
00750
WDLOG(
"Using dynamic memory management\n");
00751
#endif
00752
WDLOG(
"Policy : '%s'\n",
policy_name[
Policy]);
00753
WDLOG(
"Grace periods : %d%s\n",
Grace,
00754 (
Policy <=
WD_STRETCH) ?
" (forced)" :
"");
00755
WDLOG(
"Grace divisor : %d%s\n",
GraceDiv,
00756 (
Policy <=
WD_STRETCH) ?
" (forced)" :
"");
00757
WDLOG(
"Safety limit : ");
00758
if (
Safety < 0) {
00759
rt_printk(
"(disabled)\n");
00760 }
else {
00761
rt_printk(
"%d period%s\n",
Safety,
Safety > 1 ?
"s" :
" ");
00762 }
00763
WDLOG(
"Slip factor : %d%%\n",
Slip);
00764
WDLOG(
"Stretch factor : %d%%\n",
Stretch);
00765
WDLOG(
"Offense limit : ");
00766
if (
Limit < 0) {
00767
rt_printk(
"(disabled)\n");
00768 }
else {
00769
rt_printk(
"%d\n",
Limit);
00770 }
00771
00772
#ifdef CONFIG_PROC_FS
00773
00774 wd_proc = create_proc_entry(
"watchdog", 0,
rtai_proc_root);
00775 wd_proc->read_proc = wdog_read_proc;
00776
#endif
00777
return 0;
00778 }
00779
00780 void __rtai_wd_exit(
void)
00781 {
00782
BAD_RT_TASK *bt;
00783
int dog;
00784
00785
#ifdef CONFIG_PROC_FS
00786
00787 remove_proc_entry(
"watchdog",
rtai_proc_root);
00788
#endif
00789
00790
for (dog = 0; dog <
NR_RT_CPUS; dog++) {
00791
rt_deregister_watchdog(&
wdog[dog], dog);
00792 }
00793
stop_rt_timer();
00794
rt_busy_sleep(
TickPeriod);
00795
00796
00797
for (dog = 0; dog <
NR_RT_CPUS; dog++) {
00798
rt_task_delete(&
wdog[dog]);
00799
if (dog <
num_wdogs) {
00800
for (bt =
bad_tl[dog]; bt;) {
00801 bt =
delete_bad_task(&
bad_tl[dog], bt);
00802 }
00803 }
00804 }
00805
00806
00807
WDLOG(
"unloaded.\n");
00808 }
00809
00810
module_init(__rtai_wd_init);
00811
module_exit(__rtai_wd_exit);
00812
00813
EXPORT_SYMBOL(rt_wdset_grace);
00814
EXPORT_SYMBOL(rt_wdset_gracediv);
00815
EXPORT_SYMBOL(rt_wdset_safety);
00816
EXPORT_SYMBOL(rt_wdset_policy);
00817
EXPORT_SYMBOL(rt_wdset_slip);
00818
EXPORT_SYMBOL(rt_wdset_stretch);
00819
EXPORT_SYMBOL(rt_wdset_limit);