00001 #include "local.h"
00002
00003 #include <linux/interrupt.h>
00004
00005
00006 #define NUM_SOFTIRQS 6
00007
00008 DECLARE_INITVAR(dde26_softirq);
00009
00010
00011 ddekit_thread_t *dde_softirq_thread;
00012 ddekit_sem_t *dde_softirq_sem;
00013
00014
00015 struct tasklet_head
00016 {
00017 struct tasklet_struct *list;
00018 ddekit_lock_t lock;
00019 };
00020
00021
00022 static struct softirq_action softirq_vec[32];
00023
00024
00025 struct tasklet_head tasklet_vec;
00026 struct tasklet_head tasklet_hi_vec;
00027
00028 void open_softirq(int nr, void (*action)(struct softirq_action*))
00029 {
00030 softirq_vec[nr].action = action;
00031 }
00032
00033 static void raise_softirq_irqoff_cpu(unsigned int nr, unsigned int cpu)
00034 {
00035 CHECK_INITVAR(dde26_softirq);
00036
00037
00038 __raise_softirq_irqoff(nr);
00039
00040 ddekit_sem_up(dde_softirq_sem);
00041 }
00042
00043 void raise_softirq_irqoff(unsigned int nr)
00044 {
00045 raise_softirq_irqoff_cpu(nr, 0);
00046 }
00047
00048 void raise_softirq(unsigned int nr)
00049 {
00050 unsigned long flags;
00051
00052 local_irq_save(flags);
00053 raise_softirq_irqoff(nr);
00054 local_irq_restore(flags);
00055 }
00056
00057
00058
00059
00060 void tasklet_init(struct tasklet_struct *t,
00061 void (*func)(unsigned long), unsigned long data)
00062 {
00063 t->next = NULL;
00064 t->state = 0;
00065 atomic_set(&t->count, 0);
00066 t->func = func;
00067 t->data = data;
00068 }
00069
00070
00071 static void __tasklet_enqueue(struct tasklet_struct *t,
00072 struct tasklet_head *listhead)
00073 {
00074 ddekit_lock_lock(&listhead->lock);
00075 t->next = listhead->list;
00076 listhead->list = t;
00077 ddekit_lock_unlock(&listhead->lock);
00078 }
00079
00080 void __tasklet_schedule(struct tasklet_struct *t)
00081 {
00082 unsigned long flags;
00083
00084 CHECK_INITVAR(dde26_softirq);
00085
00086 local_irq_save(flags);
00087
00088 __tasklet_enqueue(t, &tasklet_vec);
00089
00090 raise_softirq_irqoff_cpu(TASKLET_SOFTIRQ, 0);
00091
00092 local_irq_restore(flags);
00093 }
00094
00095 void __tasklet_hi_schedule(struct tasklet_struct *t)
00096 {
00097 unsigned long flags;
00098
00099 CHECK_INITVAR(dde26_softirq);
00100
00101 local_irq_save(flags);
00102 __tasklet_enqueue(t, &tasklet_hi_vec);
00103 raise_softirq_irqoff_cpu(HI_SOFTIRQ, 0);
00104 local_irq_restore(flags);
00105 }
00106
00107
00108 static void tasklet_action(struct softirq_action *a)
00109 {
00110 struct tasklet_struct *list;
00111
00112 ddekit_lock_lock(&tasklet_vec.lock);
00113 list = tasklet_vec.list;
00114 tasklet_vec.list = NULL;
00115 ddekit_lock_unlock(&tasklet_vec.lock);
00116
00117 while (list) {
00118 struct tasklet_struct *t = list;
00119
00120 list = list->next;
00121
00122 if (tasklet_trylock(t)) {
00123 if (!atomic_read(&t->count)) {
00124 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
00125 BUG();
00126 t->func(t->data);
00127 tasklet_unlock(t);
00128 continue;
00129 }
00130 tasklet_unlock(t);
00131 }
00132
00133 ddekit_lock_lock(&tasklet_vec.lock);
00134 t->next = tasklet_vec.list;
00135 tasklet_vec.list = t;
00136 raise_softirq_irqoff_cpu(TASKLET_SOFTIRQ, 0);
00137 ddekit_lock_unlock(&tasklet_vec.lock);
00138 }
00139 }
00140
00141
00142 static void tasklet_hi_action(struct softirq_action *a)
00143 {
00144 struct tasklet_struct *list;
00145
00146 ddekit_lock_lock(&tasklet_hi_vec.lock);
00147 list = tasklet_hi_vec.list;
00148 tasklet_hi_vec.list = NULL;
00149 ddekit_lock_unlock(&tasklet_hi_vec.lock);
00150
00151 while (list) {
00152 struct tasklet_struct *t = list;
00153
00154 list = list->next;
00155
00156 if (tasklet_trylock(t)) {
00157 if (!atomic_read(&t->count)) {
00158 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
00159 BUG();
00160 t->func(t->data);
00161 tasklet_unlock(t);
00162 continue;
00163 }
00164 tasklet_unlock(t);
00165 }
00166
00167 ddekit_lock_lock(&tasklet_hi_vec.lock);
00168 t->next = tasklet_hi_vec.list;
00169 tasklet_hi_vec.list = t;
00170 raise_softirq_irqoff_cpu(HI_SOFTIRQ, 0);
00171 ddekit_lock_unlock(&tasklet_hi_vec.lock);
00172 }
00173 }
00174
00175
00176 #define MAX_SOFTIRQ_RETRIES 10
00177
00178
00179
00180 void __do_softirq(void)
00181 {
00182 int retries = MAX_SOFTIRQ_RETRIES;
00183 do {
00184 struct softirq_action *h = softirq_vec;
00185 unsigned long pending = local_softirq_pending();
00186
00187
00188 set_softirq_pending(0);
00189
00190
00191 while (pending) {
00192
00193 if (pending & 1)
00194 h->action(h);
00195
00196 h++;
00197
00198 pending >>= 1;
00199 }
00200
00201
00202
00203 } while (local_softirq_pending() && --retries);
00204
00205 }
00206
00207
00208 void do_softirq(void)
00209 {
00210 unsigned long flags;
00211
00212 local_irq_save(flags);
00213 if (local_softirq_pending())
00214 __do_softirq();
00215 local_irq_restore(flags);
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 void l4dde26_softirq_thread(void *arg)
00227 {
00228 printk("Softirq daemon starting\n");
00229 l4dde26_process_add_worker();
00230
00231
00232
00233
00234 preempt_count() |= SOFTIRQ_MASK;
00235
00236 while(1) {
00237 ddekit_sem_down(dde_softirq_sem);
00238 do_softirq();
00239 }
00240 }
00241
00242
00243
00244
00245
00246
00247 void l4dde26_softirq_init(void)
00248 {
00249 char name[20];
00250
00251 dde_softirq_sem = ddekit_sem_init(0);
00252
00253 set_softirq_pending(0);
00254
00255 ddekit_lock_init_unlocked(&tasklet_vec.lock);
00256 ddekit_lock_init_unlocked(&tasklet_hi_vec.lock);
00257
00258 snprintf(name, 20, ".softirqd");
00259 dde_softirq_thread = ddekit_thread_create(
00260 l4dde26_softirq_thread,
00261 NULL, name);
00262
00263 open_softirq(TASKLET_SOFTIRQ, tasklet_action);
00264 open_softirq(HI_SOFTIRQ, tasklet_hi_action);
00265
00266 INITIALIZE_INITVAR(dde26_softirq);
00267 }