1/*
2 * Copyright 2020, 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#include <assert.h>
14#include <camkes.h>
15#include <sel4/sel4.h>
16#include <stdbool.h>
17#include <stddef.h>
18#include <utils/util.h>
19#include <platsupport/irq.h>
20#include <camkes/irq.h>
21
22/*? macros.show_includes(me.instance.type.includes) ?*/
23
24
25/*- from 'global-endpoint.template.c' import allocate_cap with context -*/
26
27/*- do allocate_cap(me, is_reader=False) -*/
28/*- set notification_origin = pop('notification') -*/
29/*- set badge = pop('badge') -*/
30/*- include 'get-notification.template.c' -*/
31/*- set ntfn = pop('callback_notification') -*/
32/*- set type_attr = '%s_irq_type' % me.parent.from_interface.name -*/
33/*- set type = configuration[me.parent.from_instance.name].get(type_attr, 'simple') -*/
34
35/*- if type == 'simple' -*/
36    /*- set attr = '%s_irq_number' % me.parent.from_interface.name -*/
37    /*- set _irq = configuration[me.parent.from_instance.name].get(attr) -*/
38    /*- if _irq is none -*/
39        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ number is not defined' % (me.parent.from_instance.name, attr))) ?*/
40    /*- endif -*/
41    /*- if not isinstance(_irq, numbers.Integral) -*/
42        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ number is not an integer' % (me.parent.from_instance.name, attr))) ?*/
43    /*- endif -*/
44    /*- set spi_attr = '%s_spi_number' % me.parent.from_interface.name -*/
45    /*- set _irq_spi = configuration[me.parent.from_instance.name].get(spi_attr) -*/
46    /*- if (isinstance(_irq_spi, numbers.Integral)) and (_irq_spi == 0) -*/
47        /*- set _irq = _irq + 32 -*/
48    /*- endif -*/
49    /*- set irq = alloc('irq', seL4_IRQHandler, number=_irq, notification=my_cnode[ntfn]) -*/
50/*- elif type in ['arm'] -*/
51    /*- set attr = '%s_irq_trigger' % me.parent.from_interface.name -*/
52    /*- set trigger = configuration[me.parent.from_instance.name].get(attr, "level") -*/
53    /*- if trigger == "level" -*/
54        /*- set trigger = seL4_ARM_IRQ_LEVEL -*/
55        /*- set sel4_trigger_param = 0 -*/
56    /*- elif trigger == "edge" -*/
57        /*- set trigger = seL4_ARM_IRQ_EDGE -*/
58        /*- set sel4_trigger_param = 1 -*/
59    /*- else -*/
60        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ trigger mode can only be "edge" or "level" but is set to: %s' % (me.parent.from_instance.name, attr, trigger))) ?*/
61    /*- endif -*/
62    /*- set attr = '%s_irq_number' % me.parent.from_interface.name -*/
63    /*- set _irq = configuration[me.parent.from_instance.name].get(attr) -*/
64    /*- if _irq is none -*/
65        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ number is not defined' % (me.parent.from_instance.name, attr))) ?*/
66    /*- endif -*/
67    /*- if not isinstance(_irq, numbers.Integral) -*/
68        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ number is not an integer' % (me.parent.from_instance.name, attr))) ?*/
69    /*- endif -*/
70    /*- set attr = '%s_irq_target' % me.parent.from_interface.name -*/
71    /*- set target = configuration[me.parent.from_instance.name].get(attr, 0) -*/
72    /*- if not isinstance(target, numbers.Integral) -*/
73        /*? raise(TemplateError('Setting %s.%s that should specify a target core is not an integer' % (me.parent.from_instance.name, attr))) ?*/
74    /*- endif -*/
75    /*- set irq = alloc('irq', seL4_IRQHandler, number=_irq, trigger=trigger, target=target, notification=my_cnode[ntfn]) -*/
76/*- elif type in ['ioapic','isa','pci'] -*/
77    /*- if type == 'isa' -*/
78        /*- set level = 0 -*/
79        /*- set polarity = 0 -*/
80    /*- elif type == 'pci' -*/
81        /*- set level = 1 -*/
82        /*- set polarity = 1 -*/
83    /*- else -*/
84        /*- set attr = '%s_irq_level' % me.parent.from_interface.name -*/
85        /*- set level = configuration[me.parent.from_instance.name].get(attr) -*/
86        /*- if level is none -*/
87            /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC interrupt level is not defined' % (me.parent.from_instance.name, attr))) ?*/
88        /*- endif -*/
89        /*- if not isinstance(level, numbers.Integral) -*/
90            /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC interrupt level is not an integer' % (me.parent.from_instance.name, attr))) ?*/
91        /*- endif -*/
92        /*- set attr = '%s_irq_polarity' % me.parent.from_interface.name -*/
93        /*- set polarity = configuration[me.parent.from_instance.name].get(attr) -*/
94        /*- if polarity is none -*/
95            /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC interrupt polarity is not defined' % (me.parent.from_instance.name, attr))) ?*/
96        /*- endif -*/
97        /*- if not isinstance(polarity, numbers.Integral) -*/
98            /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC interrupt polarity is not an integer' % (me.parent.from_instance.name, attr))) ?*/
99        /*- endif -*/
100    /*- endif -*/
101    /*- set attr = '%s_irq_ioapic' % me.parent.from_interface.name -*/
102    /*- set ioapic = configuration[me.parent.from_instance.name].get(attr) -*/
103    /*- if ioapic is none -*/
104        /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC controller number is not defined' % (me.parent.from_instance.name, attr))) ?*/
105    /*- endif -*/
106    /*- if not isinstance(ioapic, numbers.Integral) -*/
107        /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC controller number is not an integer' % (me.parent.from_instance.name, attr))) ?*/
108    /*- endif -*/
109    /*- set attr = '%s_irq_ioapic_pin' % me.parent.from_interface.name -*/
110    /*- set ioapic_pin = configuration[me.parent.from_instance.name].get(attr) -*/
111    /*- if ioapic_pin is none -*/
112        /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC pin number is not defined' % (me.parent.from_instance.name, attr))) ?*/
113    /*- endif -*/
114    /*- if not isinstance(ioapic_pin, numbers.Integral) -*/
115        /*? raise(TemplateError('Setting %s.%s that should specify an IOAPIC pin number is not an integer' % (me.parent.from_instance.name, attr))) ?*/
116    /*- endif -*/
117    /*- set attr = '%s_irq_vector' % me.parent.from_interface.name -*/
118    /*- set vector = configuration[me.parent.from_instance.name].get(attr) -*/
119    /*- if vector is none -*/
120        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ vector is not defined' % (me.parent.from_instance.name, attr))) ?*/
121    /*- endif -*/
122    /*- if not isinstance(vector, numbers.Integral) -*/
123        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ vector is not an integer' % (me.parent.from_instance.name, attr))) ?*/
124    /*- endif -*/
125    /*- set irq = alloc('irq', seL4_IRQHandler, vector=vector, ioapic=ioapic, ioapic_pin=ioapic_pin, level=level, polarity=polarity, notification=my_cnode[ntfn]) -*/
126/*- elif type == 'msi' -*/
127    /*- set attr = '%s_irq_handle' % me.parent.from_interface.name -*/
128    /*- set handle = configuration[me.parent.from_instance.name].get(attr) -*/
129    /*- if handle is none -*/
130        /*? raise(TemplateError('Setting %s.%s that should specify an MSI handle is not defined' % (me.parent.from_instance.name, attr))) ?*/
131    /*- endif -*/
132    /*- if not isinstance(handle, numbers.Integral) -*/
133        /*? raise(TemplateError('Setting %s.%s that should specify an MSI handle is not an integer' % (me.parent.from_instance.name, attr))) ?*/
134    /*- endif -*/
135    /*- set attr = '%s_irq_pci_bus' % me.parent.from_interface.name -*/
136    /*- set pci_bus = configuration[me.parent.from_instance.name].get(attr) -*/
137    /*- if pci_bus is none -*/
138        /*? raise(TemplateError('Setting %s.%s that should specify a PCI bus is not defined' % (me.parent.from_instance.name, attr))) ?*/
139    /*- endif -*/
140    /*- if not isinstance(pci_bus, numbers.Integral) -*/
141        /*? raise(TemplateError('Setting %s.%s that should specify a PCI bus is not an integer' % (me.parent.from_instance.name, attr))) ?*/
142    /*- endif -*/
143    /*- set attr = '%s_irq_pci_dev' % me.parent.from_interface.name -*/
144    /*- set pci_dev = configuration[me.parent.from_instance.name].get(attr) -*/
145    /*- if pci_dev is none -*/
146        /*? raise(TemplateError('Setting %s.%s that should specify a PCI device is not defined' % (me.parent.from_instance.name, attr))) ?*/
147    /*- endif -*/
148    /*- if not isinstance(pci_dev, numbers.Integral) -*/
149        /*? raise(TemplateError('Setting %s.%s that should specify a PCI device is not an integer' % (me.parent.from_instance.name, attr))) ?*/
150    /*- endif -*/
151    /*- set attr = '%s_irq_pci_fun' % me.parent.from_interface.name -*/
152    /*- set pci_fun = configuration[me.parent.from_instance.name].get(attr) -*/
153    /*- if pci_fun is none -*/
154        /*? raise(TemplateError('Setting %s.%s that should specify a PCI function is not defined' % (me.parent.from_instance.name, attr))) ?*/
155    /*- endif -*/
156    /*- if not isinstance(pci_fun, numbers.Integral) -*/
157        /*? raise(TemplateError('Setting %s.%s that should specify a PCI function is not an integer' % (me.parent.from_instance.name, attr))) ?*/
158    /*- endif -*/
159    /*- set attr = '%s_irq_vector' % me.parent.from_interface.name -*/
160    /*- set vector = configuration[me.parent.from_instance.name].get(attr) -*/
161    /*- if vector is none -*/
162        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ vector is not defined' % (me.parent.from_instance.name, attr))) ?*/
163    /*- endif -*/
164    /*- if not isinstance(vector, numbers.Integral) -*/
165        /*? raise(TemplateError('Setting %s.%s that should specify an IRQ vector is not an integer' % (me.parent.from_instance.name, attr))) ?*/
166    /*- endif -*/
167    /*- set irq = alloc('irq', seL4_IRQHandler, vector=vector, handle=handle, pci_bus=pci_bus, pci_dev=pci_dev, pci_fun=pci_fun, notification=my_cnode[ntfn]) -*/
168/*- else -*/
169    /*? raise(TemplateError('Unknown irq type specified by %s.%s' % (me.parent.from_instance.name, type_attr))) ?*/
170/*- endif -*/
171
172/*# Add an entry to the allocated_irqs ELF section #*/
173/*- set irq_struct_name = '%s_irq' % me.interface.name -*/
174static allocated_irq_t /*? irq_struct_name ?*/ = {
175    .irq_handler = /*? irq ?*/,
176/*- if type == 'simple' -*/
177    .irq = { .type = PS_INTERRUPT, .irq = { .number = /*? _irq ?*/ }},
178/*- elif type in ['ioapic','isa','pci'] -*/
179    .irq = { .type = PS_IOAPIC, .ioapic = { .ioapic = /*? ioapic ?*/, .pin = /*? ioapic_pin ?*/,
180                                            .level = /*? level ?*/, .polarity = /*? polarity ?*/,
181                                            .vector = /*? vector ?*/ }},
182/*- elif type == 'msi' -*/
183    .irq = { .type = PS_MSI, .msi = { .pci_bus = /*? pci_bus ?*/, .pci_dev = /*? pci_dev ?*/,
184                                      .pci_func = /*? pci_fun ?*/, .handle = /*? handle ?*/,
185                                      .vector = /*? vector ?*/ }},
186/*- elif type == 'arm' -*/
187    .irq = { .type = PS_TRIGGER, .cpu = { .trigger = /*? trigger.value ?*/, .cpu_idx= /*? target ?*/, .number = /*? _irq ?*/ }},
188/*- endif -*/
189    .is_allocated = false,
190    .callback_fn = NULL,
191    .callback_data = NULL
192};
193USED SECTION("_allocated_irqs")
194allocated_irq_t * /*? irq_struct_name ?*/_ptr = &/*? irq_struct_name ?*/;
195
196int /*? me.interface.name ?*/_poll(void) {
197    assert(!"not implemented for this connector");
198    return 0;
199}
200
201void /*? me.interface.name ?*/_wait(void) {
202    assert(!"not implemented for this connector");
203    while (true);
204}
205
206int /*? me.interface.name ?*/_reg_callback(void (*callback)(void*) UNUSED,
207        void *arg UNUSED) {
208    assert(!"not implemented for this connector");
209    return -1;
210}
211
212
213static int /*? me.interface.name ?*/_acknowledge_cb(UNUSED void* cookie) {
214    return seL4_IRQHandler_Ack(/*? irq ?*/);
215}
216
217/*# Add an entry to the global_notification_irqs ELF section #*/
218/*- set irq_handler_struct_name = '%s_irq_handler' % me.interface.name -*/
219static global_notification_irq_handler_t /*? irq_handler_struct_name ?*/ = {
220    .badge = /*? badge ?*/,
221    .ack_fun = /*? me.interface.name ?*/_acknowledge_cb,
222    .allocated_ref = &/*? irq_struct_name ?*/,
223};
224
225USED SECTION("_global_notification_irqs")
226global_notification_irq_handler_t * /*? irq_handler_struct_name ?*/_ptr = &/*? irq_handler_struct_name ?*/;
227
228// Set the badge of the IRQHandler.
229static void __attribute__((constructor)) register_connector(void) {
230    int error = seL4_IRQHandler_SetNotification(/*? irq ?*/, /*? notification_origin ?*/);
231    if (error) {
232        assert(!"Failed to pair IRQ handler with notification");
233    }
234}
235
236