00001
00002
00011
00012
00013
00014
00015
00035
00036 #include <l4/env/errno.h>
00037 #include <l4/sys/syscalls.h>
00038 #include <l4/thread/thread.h>
00039 #include <l4/semaphore/semaphore.h>
00040 #include <l4/lock/lock.h>
00041
00042 #include <l4/dde_linux/dde.h>
00043
00044
00045 #include <linux/config.h>
00046 #include <linux/mm.h>
00047 #include <linux/kernel_stat.h>
00048 #include <linux/interrupt.h>
00049 #include <linux/smp_lock.h>
00050 #include <linux/init.h>
00051 #include <linux/tqueue.h>
00052
00053
00054 #include "internal.h"
00055 #include "__config.h"
00056
00068 static l4thread_t softirq_tid[SOFTIRQ_THREADS];
00069
00071 static l4semaphore_t softirq_sema = L4SEMAPHORE_LOCKED;
00072
00074 static int _initialized = 0;
00075
00112 void __cpu_raise_softirq(unsigned cpu, int nr)
00113 {
00114 l4semaphore_up(&softirq_sema);
00115 }
00116
00125 void raise_softirq(int nr)
00126 {
00127
00128
00129 cli();
00130 __cpu_raise_softirq(0, nr);
00131 sti();
00132 }
00133
00175 static struct tasklet_head tasklet_vec[NR_CPUS];
00176
00179 static struct tasklet_head tasklet_hi_vec[NR_CPUS];
00180
00182 static void tasklet_action(void)
00183 {
00184 struct tasklet_struct *list;
00185
00186 LOGd(DEBUG_SOFTIRQ, "low prio tasklet exec entrance");
00187
00188 cli();
00189 list = tasklet_vec[0].list;
00190 tasklet_vec[0].list = NULL;
00191 sti();
00192
00193 while (list != NULL)
00194 {
00195 struct tasklet_struct *t = list;
00196
00197 list = list->next;
00198
00199 if (tasklet_trylock(t))
00200 {
00201 if (atomic_read(&t->count) == 0)
00202 {
00203 clear_bit(TASKLET_STATE_SCHED, &t->state);
00204
00205 t->func(t->data);
00206 tasklet_unlock(t);
00207 continue;
00208 }
00209 tasklet_unlock(t);
00210 }
00211 cli();
00212 t->next = tasklet_vec[0].list;
00213 tasklet_vec[0].list = t;
00214 __cpu_raise_softirq(0, TASKLET_SOFTIRQ);
00215 sti();
00216 }
00217 }
00218
00223 static int tasklet_hi_action(void)
00224 {
00225 struct tasklet_struct *list;
00226
00227 if (!tasklet_hi_vec[0].list)
00228
00229 return 0;
00230
00231 LOGd(DEBUG_SOFTIRQ, "hi prio tasklet exec entrance");
00232
00233 cli();
00234 list = tasklet_hi_vec[0].list;
00235 tasklet_hi_vec[0].list = NULL;
00236 sti();
00237
00238 while (list != NULL)
00239 {
00240 struct tasklet_struct *t = list;
00241
00242 list = list->next;
00243
00244 if (tasklet_trylock(t))
00245 {
00246 if (atomic_read(&t->count) == 0)
00247 {
00248 clear_bit(TASKLET_STATE_SCHED, &t->state);
00249
00250 t->func(t->data);
00251 tasklet_unlock(t);
00252 continue;
00253 }
00254 tasklet_unlock(t);
00255 }
00256 cli();
00257 t->next = tasklet_hi_vec[0].list;
00258 tasklet_hi_vec[0].list = t;
00259 __cpu_raise_softirq(0, HI_SOFTIRQ);
00260 sti();
00261 }
00262
00263 return !0;
00264 }
00265
00273 void tasklet_init(struct tasklet_struct *t,
00274 void (*func) (unsigned long), unsigned long data)
00275 {
00276 t->func = func;
00277 t->data = data;
00278 t->state = 0;
00279 atomic_set(&t->count, 0);
00280 }
00281
00287 void tasklet_kill(struct tasklet_struct *t)
00288 {
00289
00290
00291
00292 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00293 {
00294 #if 0
00295 current->state = TASK_RUNNING;
00296 do
00297 {
00298 current->policy |= SCHED_YIELD;
00299 schedule();
00300 }
00301 while (test_bit(TASKLET_STATE_SCHED, &t->state));
00302 #else
00303 do
00304 {
00305
00306 # if SCHED_YIELD_OPT
00307 l4thread_usleep(SCHED_YIELD_TO);
00308 # else
00309 l4_yield();
00310 # endif
00311 }
00312 while (test_bit(TASKLET_STATE_SCHED, &t->state));
00313 #endif
00314 }
00315 tasklet_unlock_wait(t);
00316 clear_bit(TASKLET_STATE_SCHED, &t->state);
00317 }
00318
00327 void tasklet_schedule(struct tasklet_struct *t)
00328 {
00329 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00330 {
00331 cli();
00332 t->next = tasklet_vec[0].list;
00333 tasklet_vec[0].list = t;
00334
00335
00336 if (!t->next)
00337 __cpu_raise_softirq(0, TASKLET_SOFTIRQ);
00338 sti();
00339 }
00340 }
00341
00342
00351
00352 void tasklet_hi_schedule(struct tasklet_struct *t)
00353 {
00354 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00355 {
00356 cli();
00357 t->next = tasklet_hi_vec[0].list;
00358 tasklet_hi_vec[0].list = t;
00359
00360
00361 if (!t->next)
00362 __cpu_raise_softirq(0, HI_SOFTIRQ);
00363 sti();
00364 }
00365 }
00366
00383 spinlock_t tqueue_lock = SPIN_LOCK_UNLOCKED;
00384
00390 void __run_task_queue(task_queue * list)
00391 {
00392 struct list_head head, *next;
00393 unsigned long flags;
00394
00395 spin_lock_irqsave(&tqueue_lock, flags);
00396 list_add(&head, list);
00397 list_del_init(list);
00398 spin_unlock_irqrestore(&tqueue_lock, flags);
00399
00400 next = head.next;
00401 while (next != &head)
00402 {
00403 void (*f) (void *);
00404 struct tq_struct *p;
00405 void *data;
00406
00407 p = list_entry(next, struct tq_struct, list);
00408 next = next->next;
00409 f = p->routine;
00410 data = p->data;
00411 wmb();
00412 p->sync = 0;
00413 if (f)
00414 f(data);
00415 }
00416 }
00417
00428 static void dde_softirq_thread(int num)
00429 {
00430 softirq_tid[num] = l4thread_myself();
00431
00432 if (l4dde_process_add_worker())
00433 Panic("l4dde_process_add_worker() failed");
00434
00435 ++local_bh_count(smp_processor_id());
00436
00437
00438 if (l4thread_started(NULL)<0)
00439 Panic("softirq thread startup failed!");
00440
00441 LOGd(DEBUG_MSG, "dde_softirq_thread[%d] "l4util_idfmt" running.", num,
00442 l4util_idstr(l4thread_l4_id(l4thread_myself())));
00443
00444
00445 while (1)
00446 {
00447
00448 l4semaphore_down(&softirq_sema);
00449
00450
00451 if (!tasklet_hi_action())
00452 tasklet_action();
00453 }
00454 }
00455
00465 int l4dde_softirq_init()
00466 {
00467 #if !(SOFTIRQ_THREADS == 1)
00468 #error SOFTIRQ_THREADS has to be 1
00469 #else
00470 int err;
00471
00472 if (_initialized)
00473 return 0;
00474
00475
00476 err = l4thread_create_long(L4THREAD_INVALID_ID,
00477 (l4thread_fn_t) dde_softirq_thread,
00478 ".softirq",
00479 L4THREAD_INVALID_SP,
00480 L4THREAD_DEFAULT_SIZE,
00481 L4THREAD_DEFAULT_PRIO,
00482 (void *) 0,
00483 L4THREAD_CREATE_SYNC);
00484
00485 if (err < 0)
00486 return err;
00487
00488 ++_initialized;
00489 return 0;
00490 #endif
00491 }