Changeset 2b017ba in mainline for kernel/generic/src/ipc/irq.c
- Timestamp:
- 2006-10-16T20:51:55Z (19 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5f9b4d9a
- Parents:
- e3890b3f
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/irq.c
re3890b3f r2b017ba 1 1 /* 2 2 * Copyright (C) 2006 Ondrej Palkovsky 3 * Copyright (C) 2006 Jakub Jermar 3 4 * All rights reserved. 4 5 * … … 40 41 * 41 42 * The structure of a notification message is as follows: 42 * - METHOD: interrupt number43 * - METHOD: method as registered by the SYS_IPC_REGISTER_IRQ syscall 43 44 * - ARG1: payload modified by a 'top-half' handler 44 * - ARG2: payload 45 * - ARG3: payload 45 * - ARG2: payload modified by a 'top-half' handler 46 * - ARG3: payload modified by a 'top-half' handler 46 47 * - in_phone_hash: interrupt counter (may be needed to assure correct order 47 48 * in multithreaded drivers) … … 51 52 #include <mm/slab.h> 52 53 #include <errno.h> 54 #include <ddi/irq.h> 53 55 #include <ipc/ipc.h> 54 56 #include <ipc/irq.h> 55 #include <atomic.h>56 57 #include <syscall/copy.h> 57 58 #include <console/console.h> 58 59 #include <print.h> 59 60 60 typedef struct { 61 SPINLOCK_DECLARE(lock); 62 answerbox_t *box; 63 irq_code_t *code; 64 atomic_t counter; 65 } ipc_irq_t; 66 67 68 static ipc_irq_t *irq_conns = NULL; 69 static int irq_conns_size; 70 71 72 /* Execute code associated with IRQ notification */ 61 /** Execute code associated with IRQ notification. 62 * 63 * @param call Notification call. 64 * @param code Top-half pseudocode. 65 */ 73 66 static void code_execute(call_t *call, irq_code_t *code) 74 67 { … … 169 162 } 170 163 171 /** Unregister task from irq */ 172 void ipc_irq_unregister(answerbox_t *box, int irq) 164 /** Unregister task from IRQ notification. 165 * 166 * @param box Answerbox associated with the notification. 167 * @param inr IRQ numbe. 168 * @param devno Device number. 169 */ 170 void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) 173 171 { 174 172 ipl_t ipl; 175 i nt mq = irq + IPC_IRQ_RESERVED_VIRTUAL;173 irq_t *irq; 176 174 177 175 ipl = interrupts_disable(); 178 spinlock_lock(&irq_conns[mq].lock); 179 if (irq_conns[mq].box == box) { 180 irq_conns[mq].box = NULL; 181 code_free(irq_conns[mq].code); 182 irq_conns[mq].code = NULL; 183 } 184 185 spinlock_unlock(&irq_conns[mq].lock); 176 irq = irq_find_and_lock(inr, devno); 177 if (irq) { 178 if (irq->notif_cfg.answerbox == box) { 179 code_free(irq->notif_cfg.code); 180 irq->notif_cfg.code = NULL; 181 irq->notif_cfg.answerbox = NULL; 182 irq->notif_cfg.method = 0; 183 irq->notif_cfg.counter = 0; 184 spinlock_unlock(&irq->lock); 185 } 186 } 186 187 interrupts_restore(ipl); 187 188 } 188 189 189 /** Register an answerbox as a receiving end of interrupts notifications */ 190 int ipc_irq_register(answerbox_t *box, int irq, irq_code_t *ucode) 190 /** Register an answerbox as a receiving end for IRQ notifications. 191 * 192 * @param box Receiving answerbox. 193 * @param inr IRQ number. 194 * @param devno Device number. 195 * @param method Method to be associated with the notification. 196 * @param ucode Uspace pointer to top-half pseudocode. 197 * 198 * @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success. 199 */ 200 int 201 ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode) 191 202 { 192 203 ipl_t ipl; 193 204 irq_code_t *code; 194 int mq = irq + IPC_IRQ_RESERVED_VIRTUAL; 195 196 ASSERT(irq_conns); 205 irq_t *irq; 197 206 198 207 if (ucode) { … … 204 213 205 214 ipl = interrupts_disable(); 206 spinlock_lock(&irq_conns[mq].lock); 207 208 if (irq_conns[mq].box) { 209 spinlock_unlock(&irq_conns[mq].lock); 215 irq = irq_find_and_lock(inr, devno); 216 if (!irq) { 217 interrupts_restore(ipl); 218 code_free(code); 219 return ENOENT; 220 } 221 222 if (irq->notif_cfg.answerbox) { 223 spinlock_unlock(&irq->lock); 210 224 interrupts_restore(ipl); 211 225 code_free(code); 212 226 return EEXISTS; 213 227 } 214 irq_conns[mq].box = box; 215 irq_conns[mq].code = code; 216 atomic_set(&irq_conns[mq].counter, 0); 217 spinlock_unlock(&irq_conns[mq].lock); 228 229 irq->notif_cfg.answerbox = box; 230 irq->notif_cfg.method = method; 231 irq->notif_cfg.code = code; 232 irq->notif_cfg.counter = 0; 233 spinlock_unlock(&irq->lock); 218 234 interrupts_restore(ipl); 219 235 … … 221 237 } 222 238 223 /** Add call to proper answerbox queue 224 * 225 * Assume irq_conns[mq].lock is locked */ 226 static void send_call(int mq, call_t *call) 227 { 228 spinlock_lock(&irq_conns[mq].box->irq_lock); 229 list_append(&call->link, &irq_conns[mq].box->irq_notifs); 230 spinlock_unlock(&irq_conns[mq].box->irq_lock); 239 /** Add call to proper answerbox queue. 240 * 241 * Assume irq->lock is locked. 242 * 243 */ 244 static void send_call(irq_t *irq, call_t *call) 245 { 246 spinlock_lock(&irq->notif_cfg.answerbox->irq_lock); 247 list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs); 248 spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock); 231 249 232 waitq_wakeup(&irq _conns[mq].box->wq, 0);250 waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST); 233 251 } 234 252 … … 236 254 * 237 255 */ 238 void ipc_irq_send_msg(i ntirq, unative_t a1, unative_t a2, unative_t a3)256 void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3) 239 257 { 240 258 call_t *call; 241 int mq = irq + IPC_IRQ_RESERVED_VIRTUAL; 242 243 spinlock_lock(&irq_conns[mq].lock); 244 245 if (irq_conns[mq].box) { 259 260 spinlock_lock(&irq->lock); 261 262 if (irq->notif_cfg.answerbox) { 246 263 call = ipc_call_alloc(FRAME_ATOMIC); 247 264 if (!call) { 248 spinlock_unlock(&irq _conns[mq].lock);265 spinlock_unlock(&irq->lock); 249 266 return; 250 267 } 251 268 call->flags |= IPC_CALL_NOTIF; 252 IPC_SET_METHOD(call->data, irq );269 IPC_SET_METHOD(call->data, irq->notif_cfg.method); 253 270 IPC_SET_ARG1(call->data, a1); 254 271 IPC_SET_ARG2(call->data, a2); 255 272 IPC_SET_ARG3(call->data, a3); 256 273 /* Put a counter to the message */ 257 call->private = atomic_preinc(&irq_conns[mq].counter);274 call->private = ++irq->notif_cfg.counter; 258 275 259 send_call( mq, call);260 } 261 spinlock_unlock(&irq _conns[mq].lock);276 send_call(irq, call); 277 } 278 spinlock_unlock(&irq->lock); 262 279 } 263 280 264 281 /** Notify task that an irq had occurred. 265 282 * 266 * We expect interrupts to be disabled 267 */ 268 void ipc_irq_send_notif(i ntirq)283 * We expect interrupts to be disabled and the irq->lock already held. 284 */ 285 void ipc_irq_send_notif(irq_t *irq) 269 286 { 270 287 call_t *call; 271 int mq = irq + IPC_IRQ_RESERVED_VIRTUAL; 272 273 ASSERT(irq_conns); 274 spinlock_lock(&irq_conns[mq].lock); 275 276 if (irq_conns[mq].box) { 288 289 ASSERT(irq); 290 291 if (irq->notif_cfg.answerbox) { 277 292 call = ipc_call_alloc(FRAME_ATOMIC); 278 293 if (!call) { 279 spinlock_unlock(&irq_conns[mq].lock);280 294 return; 281 295 } 282 296 call->flags |= IPC_CALL_NOTIF; 283 297 /* Put a counter to the message */ 284 call->private = atomic_preinc(&irq_conns[mq].counter);298 call->private = ++irq->notif_cfg.counter; 285 299 /* Set up args */ 286 IPC_SET_METHOD(call->data, irq );300 IPC_SET_METHOD(call->data, irq->notif_cfg.method); 287 301 288 302 /* Execute code to handle irq */ 289 code_execute(call, irq _conns[mq].code);303 code_execute(call, irq->notif_cfg.code); 290 304 291 send_call(mq, call); 292 } 293 294 spinlock_unlock(&irq_conns[mq].lock); 295 } 296 297 298 /** Initialize table of interrupt handlers 299 * 300 * @param irqcount Count of required hardware IRQs to be supported 301 */ 302 void ipc_irq_make_table(int irqcount) 303 { 304 int i; 305 306 irqcount += IPC_IRQ_RESERVED_VIRTUAL; 307 308 irq_conns_size = irqcount; 309 irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0); 310 for (i=0; i < irqcount; i++) { 311 spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock"); 312 irq_conns[i].box = NULL; 313 irq_conns[i].code = NULL; 314 } 315 } 316 317 /** Disconnect all irq's notifications 318 * 319 * @todo It may be better to do some linked list, so that 320 * we wouldn't need to go through whole array every cleanup 305 send_call(irq, call); 306 } 307 } 308 309 /** Disconnect all IRQ notifications from an answerbox. 310 * 311 * @param box Answerbox for which we want to carry out the cleanup. 321 312 */ 322 313 void ipc_irq_cleanup(answerbox_t *box) 323 314 { 324 int i; 325 ipl_t ipl; 326 327 for (i=0; i < irq_conns_size; i++) { 328 ipl = interrupts_disable(); 329 spinlock_lock(&irq_conns[i].lock); 330 if (irq_conns[i].box == box) 331 irq_conns[i].box = NULL; 332 spinlock_unlock(&irq_conns[i].lock); 333 interrupts_restore(ipl); 334 } 315 /* TODO */ 335 316 } 336 317
Note:
See TracChangeset
for help on using the changeset viewer.