00001
00018
00019
00020
00021
00022
00023 #include <omega0_proto.h>
00024 #include <l4/sys/types.h>
00025 #include <l4/sys/ipc.h>
00026 #include <l4/sys/ktrace.h>
00027 #include <l4/util/util.h>
00028 #include <l4/rmgr/librmgr.h>
00029 #include <l4/log/l4log.h>
00030 #include <l4/omega0/client.h>
00031 #include <l4/util/rdtsc.h>
00032 #include <l4/util/spin.h>
00033 #include <l4/util/macros.h>
00034
00035 #include <stdio.h>
00036
00037 #include "globals.h"
00038 #include "irq_threads.h"
00039 #include "create_threads.h"
00040 #include "config.h"
00041
00042
00044 enum client_ipc_enum {
00045 RET_HANDLE,
00046
00047 RET_REPLY,
00048 RET_WAIT,
00049
00050 };
00051
00052 typedef struct{
00053 l4_threadid_t sender;
00054 l4_umword_t d0;
00055 omega0_request_t request;
00056 } client_ipc_t;
00057
00068 static int signal_single_user_thread(int irq, client_chain *c,
00069 client_ipc_t *ipc){
00070 int error;
00071 l4_msgdope_t result;
00072
00073 LOGdl(OMEGA0_DEBUG_IRQ_THREADS, "Got irq %#x, Wakeup thread "l4util_idfmt,
00074 irq, l4util_idstr(c->client));
00075
00076 if(ipc){
00077 error = l4_ipc_reply_and_wait(c->client,
00078 (void*)(L4_IPC_SHORT_MSG |
00079 L4_IPC_DECEIT_MASK),
00080 irq+1,
00081 OMEGA0_DEBUG_MEASUREMENT_SENDTIME
00082 ?(unsigned)(l4_rdtsc())
00083 :0,
00084 &ipc->sender, L4_IPC_SHORT_MSG,
00085 &ipc->d0, &ipc->request.i,
00086 L4_IPC_SEND_TIMEOUT_0, &result);
00087 } else {
00088 error = l4_ipc_send(c->client,
00089 (void*)(L4_IPC_SHORT_MSG | L4_IPC_DECEIT_MASK),
00090 irq+1,
00091 OMEGA0_DEBUG_MEASUREMENT_SENDTIME
00092 ?(unsigned)(l4_rdtsc())
00093 :0,
00094 L4_IPC_NEVER, &result);
00095 }
00096
00097
00098 if(!L4_IPC_SND_ERROR(result)){
00099
00100
00101 if(OMEGA0_STRATEGY_AUTO_CONSUME) irqs[irq].clients_waiting++;
00102 c->in_service = 1;
00103 c->last_irq_num= irqs[irq].counter;
00104 }
00105 else LOGdl(OMEGA0_DEBUG_IRQ_THREADS,
00106 "error %#x sending IPC to " l4util_idfmt,
00107 error, l4util_idstr(c->client));
00108 c->waiting = 0;
00109
00110 return error;
00111 }
00112
00127 static int signal_user_threads(int irq, client_ipc_t *ipc){
00128 client_chain *c;
00129 l4util_wq_lock_queue_elem_t wqe;
00130
00131 aquire_mutex(&irqs[irq].mutex, &wqe);
00132
00133 irqs[irq].counter++;
00134 if(OMEGA0_STRATEGY_AUTO_CONSUME) irqs[irq].clients_waiting=0;
00135
00136 for(c=irqs[irq].clients;c;c=c->next){
00137 if(c->next==0 && c->waiting){
00138
00139 release_mutex(&irqs[irq].mutex, &wqe);
00140 return signal_single_user_thread(irq, c, ipc);
00141 } else if(c->waiting){
00142 signal_single_user_thread(irq, c, 0);
00143 } else {
00144 LOGdl(OMEGA0_DEBUG_IRQ_THREADS,
00145 "client "l4util_idfmt" not waiting",
00146 l4util_idstr(c->client));
00147 }
00148 }
00149
00150 release_mutex(&irqs[irq].mutex, &wqe);
00151
00152
00153 return 1;
00154 }
00155
00159 static inline void irq_enable(int num)
00160 {
00161 l4_threadid_t irq;
00162 l4_msgdope_t result;
00163
00164 l4_make_taskid_from_irq(num, &irq);
00165 l4_ipc_send(irq, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_SEND_TIMEOUT_0, &result);
00166 }
00167
00176 static inline int irq_consume(int irq)
00177 {
00178 if (!irqs[irq].in_service) return -1;
00179
00180
00181 irq_enable(irq);
00182
00183 irqs[irq].in_service = 0;
00184 return 0;
00185 }
00186
00187 #if OMEGA0_STRATEGY_AUTO_CONSUME
00188
00201 void check_auto_consume(int irq, client_chain *c){
00202
00203 if(c->in_service && c->last_irq_num == irqs[irq].counter
00204 && irqs[irq].in_service && --irqs[irq].clients_waiting==0){
00205
00206 LOGdl(OMEGA0_DEBUG_IRQ_THREADS,
00207 "Automatically consuming irq %#x", irq);
00208 if(irq_consume(irq)){
00209 LOGl("An error occured during automatically consume operation");
00210 }
00211 } else {
00212 LOGdl(OMEGA0_DEBUG_IRQ_THREADS,
00213 "No automatic-consume of irq %#x, clients_waiting %d now",
00214 irq, irqs[irq].clients_waiting);
00215 }
00216 }
00217 #endif
00218
00249 static int handle_user_request(int irq,
00250 client_ipc_t *ipc){
00251 client_chain *c;
00252 int ret;
00253 l4util_wq_lock_queue_elem_t wqe;
00254
00255 aquire_mutex(&irqs[irq].mutex, &wqe);
00256
00257
00258 for(c=irqs[irq].clients;c;c=c->next){
00259 if(l4_thread_equal(ipc->sender, c->client)){
00260
00261 if(ipc->request.s.again){
00262 ipc->request.s.again=0;
00263 ipc->request.i |= c->last_request.i;
00264 }
00265
00266 if(ipc->request.s.unmask){
00267
00268
00269 if(ipc->request.s.param!=irq+1) {
00270 ret = -1; goto back;
00271 }
00272
00273 if(! c->masked) {
00274 ret = -2; goto back;
00275 }
00276
00277 if (--irqs[irq].masked == 0) irq_enable(irq);
00278 ipc->request.s.unmask = 0;
00279 c->masked = 0;
00280 }
00281
00282
00283 if(ipc->request.s.consume){
00284
00285 if(!c->in_service) {
00286 ret = -3; goto back;
00287 }
00288 if(irq_consume(irq)){
00289 ret = -4; goto back;
00290 }
00291 ipc->request.s.consume=0;
00292 c->in_service = 0;
00293 }
00294
00295
00296 if(ipc->request.s.mask){
00297
00298 if (ipc->request.s.param != irq + 1) {
00299 ret = -5; goto back;
00300 }
00301
00302
00303 if (c->masked) {
00304 ret = -6; goto back;
00305 }
00306
00307
00308 if (irqs[irq].masked == 0) {
00309
00310
00311
00312 }
00313 irqs[irq].masked++;
00314 ipc->request.s.mask = 0;
00315 c->masked = 1;
00316 }
00317
00318
00319 if(ipc->request.s.wait){
00320 if(OMEGA0_STRATEGY_AUTO_CONSUME){
00321 check_auto_consume(irq, c);
00322 }
00323
00324
00325
00326 c->in_service = 0;
00327 c->waiting = 1;
00328
00329
00330
00331
00332 if(irqs[irq].in_service &&
00333 irqs[irq].counter != c->last_irq_num){
00334
00335
00336 release_mutex(&irqs[irq].mutex, &wqe);
00337 ret = signal_single_user_thread(irq, c, ipc)
00338 ? RET_WAIT: RET_HANDLE;
00339 c->last_request = ipc->request;
00340 return ret;
00341 }
00342 ipc->request.s.wait = 0;
00343 ret = RET_WAIT;
00344 } else {
00345 ret = RET_REPLY;
00346 }
00347
00348 goto back;
00349 }
00350 }
00351
00352 LOGdl(OMEGA0_DEBUG_WARNING,
00353 "Client "l4util_idfmt" not found in the list of attached clients, "
00354 "ignoring request", l4util_idstr(ipc->sender));
00355 release_mutex(&irqs[irq].mutex, &wqe);
00356 return RET_WAIT;
00357
00358 back:
00359 c->last_request = ipc->request;
00360 release_mutex(&irqs[irq].mutex, &wqe);
00361
00362 LOGd(OMEGA0_DEBUG_IRQ_THREADS,
00363 "returning %d, forcing %s IPC back", ret, ret?"1":"no");
00364 return ret;
00365 }
00366
00372 static void attach_irq(int num){
00373 int error;
00374 l4_msgdope_t result;
00375 l4_umword_t dummy;
00376 l4_threadid_t irq_th;
00377
00378 if(rmgr_get_irq(num) != 0){
00379 LOGdl(OMEGA0_DEBUG_IRQ_THREADS,
00380 "error getting irq %#x from rmgr", num);
00381 irqs[num].available = 0;
00382 return;
00383 }
00384
00385 l4_make_taskid_from_irq(num, &irq_th);
00386
00387
00388 error = l4_ipc_receive(irq_th, 0, &dummy, &dummy,
00389 L4_IPC_BOTH_TIMEOUT_0, &result);
00390
00391 if(error==L4_IPC_RETIMEOUT){
00392 irqs[num].available=1;
00393 irqs[num].shared=0;
00394 irqs[num].masked=0;
00395 irqs[num].clients=NULL;
00396 irqs[num].counter=0;
00397 irqs[num].clients_waiting = 0;
00398 irqs[num].clients_registered = 0;
00399 irqs[num].mutex.last = NULL;
00400 } else {
00401 irqs[num].available=0;
00402 }
00403 }
00404
00410 void irq_handler(int num){
00411 int error;
00412 l4_msgdope_t result;
00413 l4_threadid_t mainthread = l4_myself();
00414 client_ipc_t ipc;
00415
00416
00417 irqs[num].lthread = mainthread.id.lthread;
00418
00419 mainthread.id.lthread = MANAGEMENT_THREAD;
00420 attach_irq(num);
00421 if(irqs[num].available){
00422 LOGdl(OMEGA0_DEBUG_IRQ_THREADS, "irq %#02x available", num);
00423 } else {
00424 LOGdl(OMEGA0_DEBUG_IRQ_THREADS, "irq %#02x not available", num);
00425 }
00426
00427 do{
00428 error = l4_ipc_send(mainthread, L4_IPC_SHORT_MSG, 0, 0, L4_IPC_NEVER,
00429 &result);
00430 if(error){
00431 LOGL("error sending birth-ipc to "l4util_idfmt".",
00432 l4util_idstr(mainthread));
00433 enter_kdebug("!");
00434 }
00435 }while(error);
00436
00437
00438 error = l4_ipc_wait(&ipc.sender, L4_IPC_SHORT_MSG,
00439 &ipc.d0, &ipc.request.i, L4_IPC_NEVER, &result);
00440 while (1) {
00441 while (error) {
00442 LOGdl(OMEGA0_DEBUG_WARNING,
00443 "IRQ %d: ipc error %#x", num, error);
00444 error = l4_ipc_wait(&ipc.sender, L4_IPC_SHORT_MSG,
00445 &ipc.d0, &ipc.request.i,
00446 L4_IPC_NEVER, &result);
00447 }
00448
00449
00450 if ( l4_is_irq_id(ipc.sender) &&
00451 (l4_get_irqnr(ipc.sender) <= IRQ_NUMS) ) {
00452
00453 if (OMEGA0_DEBUG_IRQ_THREADS) l4_spin_text(0, num, "IRQ: ");
00454
00455 irqs[num].in_service = 1;
00456 if (num == 7 && OMEGA0_DEBUG_IRQ_THREADS) {
00457 l4_spin_text(0,14,"IRQ 7: ");
00458 }
00459
00460
00461
00462 error = signal_user_threads(num, &ipc);
00463
00464 } else {
00465
00466
00467 int ret;
00468 if (ipc.d0 != OMEGA0_REQUEST) {
00469 LOGd(OMEGA0_DEBUG_REQUESTS,
00470 "non-Omega0 request from "l4util_idfmt,
00471 l4util_idstr(ipc.sender));
00472 error = 1;
00473 continue;
00474 }
00475 LOGd(OMEGA0_DEBUG_REQUESTS,
00476 "request %#08lx from "l4util_idfmt" (%c,%c,%c,%c,%c,0x%lx)",
00477 ipc.request.i, l4util_idstr(ipc.sender),
00478 ipc.request.s.wait?'w':'-',
00479 ipc.request.s.consume?'c':'-',
00480 ipc.request.s.mask?'m':'-',
00481 ipc.request.s.unmask?'u':'-',
00482 ipc.request.s.again?'a':'-',
00483 (unsigned long)ipc.request.s.param);
00484
00485 ret=handle_user_request(num, &ipc);
00486 if (ret == RET_HANDLE) continue;
00487 if (ret == RET_WAIT) {
00488 LOGd(OMEGA0_DEBUG_IRQ_THREADS, "sending no reply, waiting");
00489 error = l4_ipc_wait(&ipc.sender, L4_IPC_SHORT_MSG,
00490 &ipc.d0, &ipc.request.i,
00491 L4_IPC_NEVER, &result);
00492 } else {
00493 LOGd(OMEGA0_DEBUG_IRQ_THREADS,
00494 "sending ipc to "l4util_idfmt" and wait\n\n\n",
00495 l4util_idstr(ipc.sender));
00496
00497 error = l4_ipc_reply_and_wait(ipc.sender, L4_IPC_SHORT_MSG,
00498 ret,
00499 OMEGA0_DEBUG_MEASUREMENT_SENDTIME?
00500 (unsigned)(l4_rdtsc()):0,
00501 &ipc.sender, L4_IPC_SHORT_MSG,
00502 &ipc.d0, &ipc.request.i,
00503 L4_IPC_SEND_TIMEOUT_0,
00504 &result);
00505 }
00506 }
00507 }
00508 }
00509
00519 int attach_irqs(void){
00520 int error, i;
00521 char buf[140], *p=buf;
00522
00523 if((error=create_threads_sync())) return error;
00524
00525 buf[0]=0;
00526 p+=sprintf(p, "Available IRQs=[ ");
00527 for(i=0;i<IRQ_NUMS;i++){
00528 if(irqs[i].available) p+=sprintf(p, "%x ", i);
00529 else p+=sprintf(p, "<!%x> ", i);
00530 }
00531 p+=sprintf(p, "]\n");
00532 LOG_printf(buf);
00533
00534 return 0;
00535 }