Main Page | Modules | Class List | File List | Class Members | File Members | Related Pages

irq.c

Go to the documentation of this file.
00001 /* $Id: irq.c,v 1.25 2004/05/05 13:50:24 ch12 Exp $ */
00002 /*****************************************************************************/
00011 /* (c) 2003 Technische Universitaet Dresden
00012  * This file is part of DROPS, which is distributed under the terms of the
00013  * GNU General Public License 2. Please see the COPYING file for details.
00014  */
00015 
00040 /*****************************************************************************/
00041 
00042 /* L4 */
00043 #include <l4/env/errno.h>
00044 #include <l4/omega0/client.h>
00045 #include <l4/rmgr/librmgr.h>
00046 #include <l4/util/irq.h>
00047 #include <l4/util/thread.h>  /* attach_interrupt() */
00048 #include <l4/thread/thread.h>
00049 #include <l4/lock/lock.h>
00050 
00051 #include <l4/dde_linux/dde.h>
00052 
00053 /* Linux */
00054 #include <linux/sched.h>
00055 #include <asm/hardirq.h>
00056 #include <asm/irq.h>
00057 
00058 /* local */
00059 #include "__config.h"
00060 #include "internal.h"
00061 
00067 static struct irq_desc
00068 {
00069   int active;           
00070   int num;              
00071   l4thread_t t;         
00072   void (*handler) (int, void *, struct pt_regs *);
00074   unsigned long flags;  
00075   const char *dev_name; 
00076   void *dev_id;         
00077 } handlers[NR_IRQS];
00078 
00081 static int use_omega0 = 0;
00082 
00083 static int _initialized = 0;  
00085 int l4dde_irq_set_prio(unsigned int irq, unsigned prio){
00086     struct irq_desc *handler;
00087 
00088     /* Oh, I remember, currently only one handler per IRQ is allowed. */
00089     handler = &handlers[irq];
00090     if(!handler) return -L4_EINVAL;
00091     return l4thread_set_prio(handler->t, prio);
00092 }
00093 
00094 
00099 #define OM_MASK    0x00000001
00100 #define OM_UNMASK  0x00000002
00101 #define OM_CONSUME 0x00000004
00102 
00110 static inline int __omega0_attach(unsigned int irq, int *handle)
00111 {
00112   omega0_irqdesc_t irqdesc;
00113 
00114   /* setup irq descriptor */
00115   irqdesc.s.num = irq + 1;
00116   irqdesc.s.shared = 0;
00117 
00118   /* attach IRQ */
00119   *handle = omega0_attach(irqdesc);
00120   if (*handle < 0)
00121     return -1;
00122   else
00123     return 0;
00124 }
00125 
00135 static inline int __omega0_wait(unsigned int irq, int handle, unsigned int flags)
00136 {
00137   omega0_request_t request;
00138   int ret;
00139 
00140   /* setup omega0 request */
00141   request.s.param = irq + 1;
00142   request.s.wait = 1;
00143   request.s.consume = (flags & OM_CONSUME) ? 1 : 0;
00144   request.s.mask = (flags & OM_MASK) ? 1 : 0;
00145   request.s.unmask = (flags & OM_UNMASK) ? 1 : 0;
00146 
00147   /* wait for interrupt */
00148   ret = omega0_request(handle, request);
00149   if (ret != (irq + 1))
00150     Panic("error waiting for interrupt\n");
00151 
00152   return 0;
00153 }
00154 
00163 static inline void __enable_irq(unsigned int irq)
00164 {
00165   int port;
00166   l4util_cli();
00167   port = (((irq & 0x08) << 4) + 0x21);
00168   l4util_out8(l4util_in8(port) & ~(1 << (irq & 7)), port);
00169   l4util_sti();
00170 }
00171 
00176 static inline void __disable_irq(unsigned int irq)
00177 {
00178   unsigned short port;
00179   l4util_cli();
00180   port = (((irq & 0x08) << 4) + 0x21);
00181   l4util_out8(l4util_in8(port) | (1 << (irq & 7)), port);
00182   l4util_sti();
00183 }
00184 
00189 static inline void __ack_irq(unsigned int irq)
00190 {
00191   l4util_irq_acknowledge(irq);
00192 }
00193 
00199 static void dde_irq_thread(struct irq_desc *irq_desc)
00200 {
00201   unsigned int irq = irq_desc->num;     /* save irq description */
00202   int retval = 0;                       /* thread startup return value */
00203 
00204   int ret, error = L4_IPC_RETIMEOUT, irq_handle;
00205   l4_threadid_t irq_id;
00206   l4_umword_t dw0, dw1;
00207   l4_msgdope_t result;
00208   unsigned int om_flags;
00209 
00210   /* get permission for attaching to IRQ */
00211   if (use_omega0)
00212     {
00213       ret = __omega0_attach(irq, &irq_handle);
00214       if (ret < 0)
00215         Panic("failed to attach IRQ %d at omega0!\n", irq);
00216       else
00217         error = L4_IPC_RETIMEOUT;
00218     }
00219   else
00220     {
00221       if (rmgr_get_irq(irq))
00222         /* can't get permission -> block */
00223         Panic("%s: can't get permission for irq 0x%02x, giving up...\n",
00224               __FUNCTION__, irq);
00225 
00226       /* attach to IRQ */
00227       if (l4_is_invalid_id(irq_id = l4util_attach_interrupt(irq)))
00228         Panic("%s: can't attach to irq 0x%02x, giving up...\n",
00229               __FUNCTION__, irq);
00230 
00231       /* read spurious interrupts */
00232       for (;;)
00233         {
00234           error = l4_ipc_receive(irq_id,
00235                                       L4_IPC_SHORT_MSG, &dw0, &dw1,
00236                                       L4_IPC_TIMEOUT(0, 0, 1, 15, 0, 0), &result);
00237           if (error == L4_IPC_RETIMEOUT)
00238             break;
00239         }
00240     }
00241 
00242   if (l4dde_process_add_worker())
00243     Panic("l4dde_process_add_worker() failed");
00244   ++local_irq_count(smp_processor_id());
00245 
00246   /* we are up */
00247   retval = (error != L4_IPC_RETIMEOUT) ? 1 : 0;
00248   ret = l4thread_started(&retval);
00249 
00250   if ((ret < 0)|| retval)
00251     Panic("IRQ thread startup failed!");
00252 
00253   LOGd(DEBUG_MSG, "dde_irq_thread[%d] "l4util_idfmt" running.",
00254        irq_desc->num, l4util_idstr(l4thread_l4_id(l4thread_myself())));
00255 
00256   if (!use_omega0)
00257     __enable_irq(irq);
00258   om_flags = OM_UNMASK;
00259   for (;;)
00260     {
00261       if (use_omega0)
00262         error = __omega0_wait(irq, irq_handle, om_flags);
00263       else
00264         {
00265           /* wait for incoming interrupt */
00266           error = l4_ipc_receive(irq_id,
00267                                       L4_IPC_SHORT_MSG, &dw0, &dw1,
00268                                       L4_IPC_NEVER, &result);
00269           __disable_irq(irq);
00270           __ack_irq(irq);
00271         }
00272 
00273       switch (error)
00274         {
00275         case 0:
00276           LOGd(DEBUG_IRQ, "got IRQ %d\n", irq);
00277           if (irq_desc->active)
00278             irq_desc->handler(irq, irq_desc->dev_id, 0);
00279           if (use_omega0)
00280             om_flags = 0;
00281           else
00282             __enable_irq(irq);
00283           break;
00284         case L4_IPC_RETIMEOUT:
00285           LOGdL(DEBUG_ERRORS, "Error: timeout while receiving irq");
00286           break;
00287         default:
00288           LOGdL(DEBUG_ERRORS, "Error: receiving irq (%d)", error);
00289           break;
00290         }
00291     }
00292 }
00293 
00307 int request_irq(unsigned int irq,
00308                 void (*handler) (int, void *, struct pt_regs *),
00309                 unsigned long flags, const char *dev_name, void *dev_id)
00310 {
00311   l4thread_t irq_tid;
00312   char name[16];
00313 
00314   if (irq >= NR_IRQS)
00315     return -EINVAL;
00316   if (!handler)
00317     return -EINVAL;
00318 
00319   if(handlers[irq].t)
00320     {
00321       if (handlers[irq].active)
00322         {
00323           LOGd(DEBUG_IRQ, "XXX attempt to reattach to active irq %d", irq);
00324           return -EBUSY;
00325         }
00326       handlers[irq].active = 1;
00327 
00328       /* XXX what about handler, flags, ... ? */
00329 
00330       LOGd(DEBUG_IRQ, "reattached to irq %d", irq);
00331       return 0;
00332     }
00333 
00334   handlers[irq].handler = handler;
00335 
00336   /* create IRQ handler thread */
00337   snprintf(name, 16, ".irq%.2X", irq);
00338   irq_tid = l4thread_create_long(L4THREAD_INVALID_ID,
00339                                  (l4thread_fn_t) dde_irq_thread,
00340                                  name,
00341                                  L4THREAD_INVALID_SP,
00342                                  L4THREAD_DEFAULT_SIZE,
00343                                  L4THREAD_DEFAULT_PRIO,
00344                                  (void *) &handlers[irq],
00345                                  L4THREAD_CREATE_SYNC);
00346 
00347   if (irq_tid<0)
00348     {
00349       LOGdL(DEBUG_ERRORS, "Error: thread creation failed");
00350       return -EAGAIN;
00351     }
00352   if (*(int*)l4thread_startup_return(irq_tid))
00353     {
00354       LOGdL(DEBUG_ERRORS, "Error: irq not free");
00355       return -EBUSY;
00356     }
00357 
00358   handlers[irq].active = 1;
00359   handlers[irq].t = irq_tid;
00360 
00361   handlers[irq].flags = flags;
00362   handlers[irq].dev_name = dev_name;
00363   handlers[irq].dev_id = dev_id;
00364 
00365   LOGd(DEBUG_IRQ, "attached to irq %d", irq);
00366 
00367   return 0;
00368 }
00369 
00380 void free_irq(unsigned int irq, void *dev_id)
00381 {
00382   handlers[irq].active = 0;
00383 
00384   LOGd(DEBUG_IRQ, "XXX attempt to free irq %d ("l4util_idfmt")", irq,
00385        l4util_idstr(l4thread_l4_id(handlers[irq].t)));
00386 }
00387 
00388 
00392 void disable_irq(unsigned int irq_num)
00393 {
00394   LOG("%s not implemented", __FUNCTION__);
00395 }
00396 
00397 void disable_irq_nosync(unsigned int irq_num)
00398 {
00399   LOG("%s not implemented", __FUNCTION__);
00400 }
00401 
00402 void enable_irq(unsigned int irq_num)
00403 {
00404   LOG("%s not implemented", __FUNCTION__);
00405 }
00406 
00412 int probe_irq_on(unsigned long val)
00413 {
00414   LOG_Error("%s not implemented", __FUNCTION__);
00415   return 0;
00416 }
00422 int probe_irq_off(unsigned long val)
00423 {
00424   LOG_Error("%s not implemented", __FUNCTION__);
00425   return 0;
00426 }
00427 
00428 /*
00429  * This is called when we want to synchronize with
00430  * interrupts. We may for example tell a device to
00431  * stop sending interrupts: but to make sure there
00432  * are no interrupts that are executing on another
00433  * CPU we need to call this function.
00434  *
00435  * However, in non-SMP context, it is a define to barrier()
00436  */
00437 #ifdef CONFIG_SMP
00438 void synchronize_irq(void){
00439 #warning synchronize_irq() is not implemented.
00440 
00441   /* To implement this, I think it is better not to do a cli()/sti() as Linux
00442      does, but to wait until each of the current active interrupts was
00443      outside its interrupt loop once. Otherwise, the interrupt-code is blocked
00444      unnecessarily, which should be avoided.
00445   */
00446 }
00447 #endif
00448 
00458 int l4dde_irq_init(int omega0)
00459 {
00460   int i;
00461 
00462   if (_initialized)
00463     return -L4_ESKIPPED;
00464 
00465   use_omega0 = omega0;
00466 
00467   memset(&handlers, 0, sizeof(handlers));
00468   for (i=0; i<NR_IRQS;i++)
00469     handlers[i].num = i;
00470 
00471   ++_initialized;
00472   return 0;
00473 }
00474 
00482 l4_threadid_t l4dde_irq_l4_id(int irq){
00483     if(irq >= NR_IRQS) return L4_INVALID_ID;
00484     if(!handlers[irq].active) return L4_INVALID_ID;
00485     return l4thread_l4_id(handlers[irq].t);
00486 }

Linux DDE, written by Christian Helmuth  © 2003 Technische Universitaet Dresden