Rev 1223 | Rev 1260 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1223 | Rev 1258 | ||
---|---|---|---|
Line 41... | Line 41... | ||
41 | #include <memstr.h> |
41 | #include <memstr.h> |
42 | #include <debug.h> |
42 | #include <debug.h> |
43 | 43 | ||
44 | #include <print.h> |
44 | #include <print.h> |
45 | #include <proc/thread.h> |
45 | #include <proc/thread.h> |
- | 46 | #include <arch/interrupt.h> |
|
46 | 47 | ||
47 | /* Open channel that is assigned automatically to new tasks */ |
48 | /* Open channel that is assigned automatically to new tasks */ |
48 | answerbox_t *ipc_phone_0 = NULL; |
49 | answerbox_t *ipc_phone_0 = NULL; |
49 | 50 | ||
50 | static slab_cache_t *ipc_call_slab; |
51 | static slab_cache_t *ipc_call_slab; |
51 | 52 | ||
- | 53 | typedef struct { |
|
- | 54 | SPINLOCK_DECLARE(lock); |
|
- | 55 | answerbox_t *box; |
|
- | 56 | } ipc_irq_t; |
|
- | 57 | ||
- | 58 | static ipc_irq_t *irq_conns = NULL; |
|
- | 59 | static int irq_conns_size; |
|
- | 60 | ||
52 | /* Initialize new call */ |
61 | /* Initialize new call */ |
53 | static void _ipc_call_init(call_t *call) |
62 | static void _ipc_call_init(call_t *call) |
54 | { |
63 | { |
55 | memsetb((__address)call, sizeof(*call), 0); |
64 | memsetb((__address)call, sizeof(*call), 0); |
56 | call->callerbox = &TASK->answerbox; |
65 | call->callerbox = &TASK->answerbox; |
Line 59... | Line 68... | ||
59 | 68 | ||
60 | /** Allocate & initialize call structure |
69 | /** Allocate & initialize call structure |
61 | * |
70 | * |
62 | * The call is initialized, so that the reply will be directed |
71 | * The call is initialized, so that the reply will be directed |
63 | * to TASK->answerbox |
72 | * to TASK->answerbox |
- | 73 | * |
|
- | 74 | * @param flags Parameters for slab_alloc (ATOMIC, etc.) |
|
64 | */ |
75 | */ |
65 | call_t * ipc_call_alloc(void) |
76 | call_t * ipc_call_alloc(int flags) |
66 | { |
77 | { |
67 | call_t *call; |
78 | call_t *call; |
68 | 79 | ||
69 | call = slab_alloc(ipc_call_slab, 0); |
80 | call = slab_alloc(ipc_call_slab, flags); |
70 | _ipc_call_init(call); |
81 | _ipc_call_init(call); |
71 | 82 | ||
72 | return call; |
83 | return call; |
73 | } |
84 | } |
74 | 85 | ||
Line 88... | Line 99... | ||
88 | /** Initialize answerbox structure |
99 | /** Initialize answerbox structure |
89 | */ |
100 | */ |
90 | void ipc_answerbox_init(answerbox_t *box) |
101 | void ipc_answerbox_init(answerbox_t *box) |
91 | { |
102 | { |
92 | spinlock_initialize(&box->lock, "ipc_box_lock"); |
103 | spinlock_initialize(&box->lock, "ipc_box_lock"); |
- | 104 | spinlock_initialize(&box->irq_lock, "ipc_box_irqlock"); |
|
93 | waitq_initialize(&box->wq); |
105 | waitq_initialize(&box->wq); |
94 | list_initialize(&box->connected_phones); |
106 | list_initialize(&box->connected_phones); |
95 | list_initialize(&box->calls); |
107 | list_initialize(&box->calls); |
96 | list_initialize(&box->dispatched_calls); |
108 | list_initialize(&box->dispatched_calls); |
97 | list_initialize(&box->answers); |
109 | list_initialize(&box->answers); |
- | 110 | list_initialize(&box->irq_notifs); |
|
98 | box->task = TASK; |
111 | box->task = TASK; |
99 | } |
112 | } |
100 | 113 | ||
101 | /** Connect phone to answerbox */ |
114 | /** Connect phone to answerbox */ |
102 | void ipc_phone_connect(phone_t *phone, answerbox_t *box) |
115 | void ipc_phone_connect(phone_t *phone, answerbox_t *box) |
Line 259... | Line 272... | ||
259 | spinlock_lock(&box->lock); |
272 | spinlock_lock(&box->lock); |
260 | list_remove(&phone->list); |
273 | list_remove(&phone->list); |
261 | phone->callee = NULL; |
274 | phone->callee = NULL; |
262 | spinlock_unlock(&box->lock); |
275 | spinlock_unlock(&box->lock); |
263 | 276 | ||
264 | call = ipc_call_alloc(); |
277 | call = ipc_call_alloc(0); |
265 | IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
278 | IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
266 | call->flags |= IPC_CALL_DISCARD_ANSWER; |
279 | call->flags |= IPC_CALL_DISCARD_ANSWER; |
267 | _ipc_call(phone, box, call); |
280 | _ipc_call(phone, box, call); |
268 | 281 | ||
269 | phone->busy = IPC_BUSY_FREE; |
282 | phone->busy = IPC_BUSY_FREE; |
Line 299... | Line 312... | ||
299 | * - to distinguish between call and answer, look at call->flags |
312 | * - to distinguish between call and answer, look at call->flags |
300 | */ |
313 | */ |
301 | call_t * ipc_wait_for_call(answerbox_t *box, int flags) |
314 | call_t * ipc_wait_for_call(answerbox_t *box, int flags) |
302 | { |
315 | { |
303 | call_t *request; |
316 | call_t *request; |
- | 317 | ipl_t ipl; |
|
304 | 318 | ||
305 | restart: |
319 | restart: |
306 | if (flags & IPC_WAIT_NONBLOCKING) { |
320 | if (flags & IPC_WAIT_NONBLOCKING) { |
307 | if (waitq_sleep_timeout(&box->wq,0,1) == ESYNCH_WOULD_BLOCK) |
321 | if (waitq_sleep_timeout(&box->wq,0,1) == ESYNCH_WOULD_BLOCK) |
308 | return NULL; |
322 | return NULL; |
309 | } else |
323 | } else |
310 | waitq_sleep(&box->wq); |
324 | waitq_sleep(&box->wq); |
311 | 325 | ||
312 | spinlock_lock(&box->lock); |
326 | spinlock_lock(&box->lock); |
- | 327 | if (!list_empty(&box->irq_notifs)) { |
|
- | 328 | ipl = interrupts_disable(); |
|
- | 329 | spinlock_lock(&box->irq_lock); |
|
- | 330 | ||
- | 331 | request = list_get_instance(box->answers.next, call_t, list); |
|
- | 332 | list_remove(&request->list); |
|
- | 333 | ||
- | 334 | spinlock_unlock(&box->irq_lock); |
|
- | 335 | interrupts_restore(ipl); |
|
313 | if (!list_empty(&box->answers)) { |
336 | } else if (!list_empty(&box->answers)) { |
314 | /* Handle asynchronous answers */ |
337 | /* Handle asynchronous answers */ |
315 | request = list_get_instance(box->answers.next, call_t, list); |
338 | request = list_get_instance(box->answers.next, call_t, list); |
316 | list_remove(&request->list); |
339 | list_remove(&request->list); |
317 | atomic_dec(&request->data.phone->active_calls); |
340 | atomic_dec(&request->data.phone->active_calls); |
318 | } else if (!list_empty(&box->calls)) { |
341 | } else if (!list_empty(&box->calls)) { |
Line 331... | Line 354... | ||
331 | } |
354 | } |
332 | spinlock_unlock(&box->lock); |
355 | spinlock_unlock(&box->lock); |
333 | return request; |
356 | return request; |
334 | } |
357 | } |
335 | 358 | ||
336 | /** Initilize ipc subsystem */ |
- | |
337 | void ipc_init(void) |
- | |
338 | { |
- | |
339 | ipc_call_slab = slab_cache_create("ipc_call", |
- | |
340 | sizeof(call_t), |
- | |
341 | 0, |
- | |
342 | NULL, NULL, 0); |
- | |
343 | } |
- | |
344 | - | ||
345 | /** Answer all calls from list with EHANGUP msg */ |
359 | /** Answer all calls from list with EHANGUP msg */ |
346 | static void ipc_cleanup_call_list(link_t *lst) |
360 | static void ipc_cleanup_call_list(link_t *lst) |
347 | { |
361 | { |
348 | call_t *call; |
362 | call_t *call; |
349 | 363 | ||
Line 354... | Line 368... | ||
354 | IPC_SET_RETVAL(call->data, EHANGUP); |
368 | IPC_SET_RETVAL(call->data, EHANGUP); |
355 | _ipc_answer_free_call(call); |
369 | _ipc_answer_free_call(call); |
356 | } |
370 | } |
357 | } |
371 | } |
358 | 372 | ||
- | 373 | /** Disconnect all irq's notifications |
|
- | 374 | * |
|
- | 375 | * TODO: It may be better to do some linked list, so that |
|
- | 376 | * we wouldn't need to go through whole array every cleanup |
|
- | 377 | */ |
|
- | 378 | static void ipc_irq_cleanup(answerbox_t *box) |
|
- | 379 | { |
|
- | 380 | int i; |
|
- | 381 | ipl_t ipl; |
|
- | 382 | ||
- | 383 | for (i=0; i < irq_conns_size; i++) { |
|
- | 384 | ipl = interrupts_disable(); |
|
- | 385 | spinlock_lock(&irq_conns[i].lock); |
|
- | 386 | if (irq_conns[i].box == box) |
|
- | 387 | irq_conns[i].box = NULL; |
|
- | 388 | spinlock_unlock(&irq_conns[i].lock); |
|
- | 389 | interrupts_restore(ipl); |
|
- | 390 | } |
|
- | 391 | } |
|
- | 392 | ||
359 | /** Cleans up all IPC communication of the given task |
393 | /** Cleans up all IPC communication of the given task |
360 | * |
394 | * |
361 | * |
395 | * |
362 | */ |
396 | */ |
363 | void ipc_cleanup(task_t *task) |
397 | void ipc_cleanup(task_t *task) |
Line 368... | Line 402... | ||
368 | 402 | ||
369 | /* Disconnect all our phones ('ipc_phone_hangup') */ |
403 | /* Disconnect all our phones ('ipc_phone_hangup') */ |
370 | for (i=0;i < IPC_MAX_PHONES; i++) |
404 | for (i=0;i < IPC_MAX_PHONES; i++) |
371 | ipc_phone_hangup(&task->phones[i]); |
405 | ipc_phone_hangup(&task->phones[i]); |
372 | 406 | ||
- | 407 | /* Disconnect all connected irqs */ |
|
- | 408 | ipc_irq_cleanup(&task->answerbox); |
|
- | 409 | ||
373 | /* Disconnect all phones connected to our answerbox */ |
410 | /* Disconnect all phones connected to our answerbox */ |
374 | restart_phones: |
411 | restart_phones: |
375 | spinlock_lock(&task->answerbox.lock); |
412 | spinlock_lock(&task->answerbox.lock); |
376 | while (!list_empty(&task->answerbox.connected_phones)) { |
413 | while (!list_empty(&task->answerbox.connected_phones)) { |
377 | phone = list_get_instance(task->answerbox.connected_phones.next, |
414 | phone = list_get_instance(task->answerbox.connected_phones.next, |
Line 403... | Line 440... | ||
403 | 440 | ||
404 | atomic_dec(&task->active_calls); |
441 | atomic_dec(&task->active_calls); |
405 | ipc_call_free(call); |
442 | ipc_call_free(call); |
406 | } |
443 | } |
407 | } |
444 | } |
- | 445 | ||
- | 446 | /** Initialize table of interrupt handlers */ |
|
- | 447 | static void ipc_irq_make_table(int irqcount) |
|
- | 448 | { |
|
- | 449 | int i; |
|
- | 450 | ||
- | 451 | irq_conns_size = irqcount; |
|
- | 452 | irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0); |
|
- | 453 | for (i=0; i < irqcount; i++) { |
|
- | 454 | spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock"); |
|
- | 455 | irq_conns[i].box = NULL; |
|
- | 456 | } |
|
- | 457 | } |
|
- | 458 | ||
- | 459 | void ipc_irq_unregister(answerbox_t *box, int irq) |
|
- | 460 | { |
|
- | 461 | ipl_t ipl; |
|
- | 462 | ||
- | 463 | ipl = interrupts_disable(); |
|
- | 464 | spinlock_lock(&irq_conns[irq].lock); |
|
- | 465 | if (irq_conns[irq].box == box) |
|
- | 466 | irq_conns[irq].box = NULL; |
|
- | 467 | ||
- | 468 | spinlock_unlock(&irq_conns[irq].lock); |
|
- | 469 | interrupts_restore(ipl); |
|
- | 470 | } |
|
- | 471 | ||
- | 472 | /** Register an answerbox as a receiving end of interrupts notifications */ |
|
- | 473 | int ipc_irq_register(answerbox_t *box, int irq) |
|
- | 474 | { |
|
- | 475 | ipl_t ipl; |
|
- | 476 | ||
- | 477 | ASSERT(irq_conns); |
|
- | 478 | ||
- | 479 | ipl = interrupts_disable(); |
|
- | 480 | spinlock_lock(&irq_conns[irq].lock); |
|
- | 481 | ||
- | 482 | if (irq_conns[irq].box) { |
|
- | 483 | spinlock_unlock(&irq_conns[irq].lock); |
|
- | 484 | interrupts_restore(ipl); |
|
- | 485 | return EEXISTS; |
|
- | 486 | } |
|
- | 487 | irq_conns[irq].box = box; |
|
- | 488 | spinlock_unlock(&irq_conns[irq].lock); |
|
- | 489 | interrupts_restore(ipl); |
|
- | 490 | ||
- | 491 | return 0; |
|
- | 492 | } |
|
- | 493 | ||
- | 494 | /** Notify process that an irq had happend |
|
- | 495 | * |
|
- | 496 | * We expect interrupts to be disabled |
|
- | 497 | */ |
|
- | 498 | void ipc_irq_send_notif(int irq) |
|
- | 499 | { |
|
- | 500 | call_t *call; |
|
- | 501 | ||
- | 502 | ASSERT(irq_conns); |
|
- | 503 | spinlock_lock(&irq_conns[irq].lock); |
|
- | 504 | ||
- | 505 | if (irq_conns[irq].box) { |
|
- | 506 | call = ipc_call_alloc(FRAME_ATOMIC); |
|
- | 507 | call->flags |= IPC_CALL_NOTIF; |
|
- | 508 | IPC_SET_METHOD(call->data, IPC_M_INTERRUPT); |
|
- | 509 | IPC_SET_ARG1(call->data, irq); |
|
- | 510 | ||
- | 511 | spinlock_lock(&irq_conns[irq].box->irq_lock); |
|
- | 512 | list_append(&call->list, &irq_conns[irq].box->irq_notifs); |
|
- | 513 | spinlock_unlock(&irq_conns[irq].box->irq_lock); |
|
- | 514 | ||
- | 515 | waitq_wakeup(&irq_conns[irq].box->wq, 0); |
|
- | 516 | } |
|
- | 517 | ||
- | 518 | spinlock_unlock(&irq_conns[irq].lock); |
|
- | 519 | } |
|
- | 520 | ||
- | 521 | /** Initilize ipc subsystem */ |
|
- | 522 | void ipc_init(void) |
|
- | 523 | { |
|
- | 524 | ipc_call_slab = slab_cache_create("ipc_call", |
|
- | 525 | sizeof(call_t), |
|
- | 526 | 0, |
|
- | 527 | NULL, NULL, 0); |
|
- | 528 | ipc_irq_make_table(IRQ_COUNT); |
|
- | 529 | } |
|
- | 530 |