1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/*- import 'helpers/error.c' as error with context -*/ 14 15#include <assert.h> 16#include <camkes/error.h> 17#include <sel4/sel4.h> 18#include <stddef.h> 19#include <stdint.h> 20#include <utils/util.h> 21 22/*? macros.show_includes(me.instance.type.includes) ?*/ 23 24/*- set instance = me.instance.name -*/ 25/*- set interface = me.interface.name -*/ 26 27/*- set attr = "%s_attributes" % me.parent.from_interface.name -*/ 28/*- set irq= [] -*/ 29/*- set notification_obj = alloc_obj('notification', seL4_NotificationObject) -*/ 30/*- set notification = alloc_cap('notification', notification_obj, read=True) -*/ 31/*- set _irq = configuration[me.parent.from_instance.name].get(attr) -*/ 32/*- if _irq is not none -*/ 33 /*- set attr_irq, attr_level, attr_trig = _irq.strip('"').split(',') -*/ 34 /*- set irq_handler = alloc('irq', seL4_IRQHandler, number=int(attr_irq, 0), notification=my_cnode[notification]) -*/ 35 /*- do irq.append((irq_handler, int(attr_level, 0), int(attr_trig, 0))) -*/ 36/*- endif -*/ 37/*- set lock = alloc('lock', seL4_NotificationObject, read=True, write=True) -*/ 38 39/* Interface-specific error handling */ 40/*- set error_handler = '%s_error_handler' % me.interface.name -*/ 41/*? error.make_error_handler(interface, error_handler) ?*/ 42 43#define MAX_CALLBACKS 10 44 45static void (*volatile callbacks[MAX_CALLBACKS])(void*); 46static void *callback_args[MAX_CALLBACKS]; 47static volatile int event_pending; 48static volatile int sleepers; 49 50#define CAS __sync_val_compare_and_swap 51#define ATOMIC_INCREMENT(ptr) __sync_fetch_and_add((ptr), 1) 52#define ATOMIC_DECREMENT(ptr) __sync_fetch_and_sub((ptr), 1) 53 54#define SLEEP() \ 55 do { \ 56 ATOMIC_INCREMENT(&sleepers); \ 57 assert(sleepers > 0); \ 58 seL4_Wait(/*? lock ?*/, NULL); \ 59 assert(sleepers > 0); \ 60 ATOMIC_DECREMENT(&sleepers); \ 61 } while (0) 62 63#define WAKE() seL4_Signal(/*? lock ?*/) 64 65int /*? me.interface.name ?*/__run(void) { 66 /* Set trigger mode */ 67 seL4_IRQHandler_SetMode(/*? irq[0][0] ?*/, /*? irq[0][1] ?*/, /*? irq[0][2] ?*/); 68 while (1) { 69 int handled = 0; 70 71 seL4_Wait(/*? notification ?*/, NULL); 72 73 /* First preference: callbacks. */ 74 if (!handled) { 75 for (int i = 0; i < MAX_CALLBACKS; ++i) { 76 void (*callback)(void*) = callbacks[i]; 77 if (callback != NULL) { 78 callbacks[i] = NULL; /* No need for CAS. */ 79 callback(callback_args[i]); 80 handled = 1; 81 } 82 } 83 } 84 85 /* There may in fact already be a pending event, but we don't care. */ 86 event_pending = 1; 87 88 /* Second preference: waiters. */ 89 if (!handled) { 90 if (sleepers > 0) { /* No lock required. */ 91 WAKE(); 92 /* Assume one of them will grab it. */ 93 handled = 1; 94 } 95 } 96 97 /* Else, leave it for polling. */ 98 } 99 100 UNREACHABLE(); 101} 102 103int /*? me.interface.name ?*/_poll(void) { 104 return CAS(&event_pending, 1, 0); 105} 106 107void /*? me.interface.name ?*/_wait(void) { 108 while (!/*? me.interface.name ?*/_poll()) { 109 SLEEP(); 110 } 111} 112 113int /*? me.interface.name ?*/_reg_callback(void (*callback)(void*), void *arg) { 114 int error; 115 for (int i = 0; i < MAX_CALLBACKS; ++i) { 116 if (CAS(&callbacks[i], NULL, callback) == NULL) { 117 callback_args[i] = arg; 118 error = seL4_IRQHandler_Ack(/*? irq[0][0] ?*/); 119 ERR_IF(error != 0, /*? error_handler ?*/, ((camkes_error_t){ 120 .type = CE_SYSCALL_FAILED, 121 .instance = "/*? instance ?*/", 122 .interface = "/*? interface ?*/", 123 .description = "failed to acknowledge IRQ", 124 .syscall = IRQAckIRQ, 125 .error = error, 126 }), ({ 127 return -1; 128 })); 129 return 0; 130 } 131 } 132 /* We didn't find an empty slot. */ 133 return -1; 134} 135