rewrite the gic implementation, some other fix ups
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / common.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3
4 #include "gic-common.h"
5
6 LOG_MODULE("gic")
7
8 // FUTURE for now we assume uniprocessor
9 const int current_cpu = 0;
10
11 struct gic_pe*
12 gic_create_pe_context(struct gic* gic, void* pe_impl)
13 {
14     struct gic_pe* pe;
15
16     pe = vzalloc(sizeof(*pe));
17     
18     pe->impl = pe_impl;
19     pe->distr = gic;
20
21     return pe;
22 }
23
24 struct gic_pe*
25 gic_local_context_of(struct gic_int_class* int_class)
26 {
27     switch (int_class->kind)
28     {
29     case GIC_INT_PPI:
30         return container_of(int_class, struct gic_pe, ppi);
31     
32     case GIC_INT_PPI_EXT:
33         return container_of(int_class, struct gic_pe, ppi_e);
34
35     case GIC_INT_SGI:
36         return container_of(int_class, struct gic_pe, sgi);
37
38     case GIC_INT_LPI:
39         return container_of(int_class, struct gic_pe, lpi);
40
41     default:
42         return NULL;
43     }
44 }
45
46 struct gic*
47 gic_global_context_of(struct gic_int_class* int_class)
48 {
49     struct gic_pe* pe;
50
51     switch (int_class->kind)
52     {
53     case GIC_INT_SPI:
54         return container_of(int_class, struct gic, spi);
55     
56     case GIC_INT_SPI_EXT:
57         return container_of(int_class, struct gic, spi_e);
58
59     default:
60         break;
61     }
62
63     pe = gic_local_context_of(int_class);
64
65     return pe ? pe->distr : NULL;
66 }
67
68 static inline int
69 gic_resolve_pe(struct gic* gic, struct gic_interrupt* intr_out)
70 {
71     u32_t affval;
72     struct gic_pe* pe;
73
74     if (!(intr_out->affinity.raw_val & GIC_INTR_RAW_AFF)) {
75         return 0;
76     }
77
78     affval = (u32_t)(intr_out->affinity.raw_val >> 1);
79     for (int i = 0; i < gic->nr_cpus; i++, pe = NULL)
80     {
81         pe = gic->cores[i];
82         if (pe && pe->affinity == affval) {
83             break;
84         }
85     }
86     
87     if (!pe) 
88         return EINVAL;
89
90     intr_out->affinity.pe = pe;
91
92     return 0;
93 }
94
95 static inline bool
96 __intclass_inrange(struct gic_int_class* int_class, intid_t id)
97 {
98     return int_class->ops 
99         && (int_class->range.start <= id && id <= int_class->range.stop);
100 }
101
102 static inline enum gic_intkind
103 __get_intid_kind(struct gic* gic, intid_t id)
104 {
105     struct gic_pe* pe;
106
107     pe = gic->cores[current_cpu];
108     if (__intclass_inrang(&gic->spi, id)) {
109         return GIC_INT_SPI;
110     }
111
112     if (__intclass_inrang(&gic->spi_e, id)) {
113         return GIC_INT_SPI_EXT;
114     }
115
116     if (__intclass_inrang(&pe->sgi, id)) {
117         return GIC_INT_SGI;
118     }
119
120     if (__intclass_inrang(&pe->ppi, id)) {
121         return GIC_INT_PPI;
122     }
123
124     if (__intclass_inrang(&pe->ppi_e, id)) {
125         return GIC_INT_PPI_EXT;
126     }
127
128     if (__intclass_inrang(&pe->lpi, id)) {
129         return GIC_INT_LPI;
130     }
131
132     return GIC_INT_COUNT;
133 }
134
135 int
136 gic_get_interrupt(struct gic* gic, intid_t id, struct gic_interrupt* intr_out)
137 {
138     int err;
139     enum gic_intkind kind;
140     struct gic_int_class* class;
141     struct gic_pe* current_pe;
142
143     current_pe = gic->cores[current_cpu];
144     kind = __get_intid_kind(gic, id);
145
146     if (!current_pe) {
147         return EINVAL;
148     }
149
150     if (kind == GIC_INT_SPI || kind == GIC_INT_SPI_EXT) {
151         class = &gic->classes[kind - GIC_INT_SPI];
152     }
153     else if (kind < GIC_INT_SPI) {
154         class = &current_pe->classes[kind];
155     }
156     else {
157         return EINVAL;
158     }
159
160     if (!gic_valid_int_class(class)) {
161         return ENOENT;
162     }
163
164     intr_out->intid = id;
165     intr_out->kind = kind;
166
167     err = class->ops->retrieve(class, intr_out, id);
168     if (err) 
169         return err;
170
171     err = gic_resolve_pe(gic, intr_out);
172     if (err)
173         return err;
174
175     // TODO get irq object
176
177     return 0;
178 }
179
180 static void
181 __gic_create_profile(struct gic_interrupt* gint, 
182                      enum gic_intkind kind, irq_t irq)
183 {
184     gint->kind = kind;
185     gint->trig = irq->trig == IRQ_EDGE ? GIC_TRIG_EDGE : GIC_TRIG_LEVEL;
186     gint->grp  = GIC_INT_GROUP1_NS;
187     gint->priority = 255;
188     gint->intid = irq->vector;
189     gint->irq = irq;
190 }
191
192 static int
193 __gic_install_irq(struct irq_domain *domain, irq_t irq)
194 {
195     int err;
196     struct gic* gic;
197     struct gic_pe* pe;
198     struct gic_interrupt gint;
199     struct gic_int_class* class;
200
201     gic = irq_domain_obj(domain, struct gic);
202     pe  = gic->cores[current_cpu];
203
204     switch (irq->type)
205     {
206     case IRQ_DIRECT:
207         WARN("core-local interrupt not supported");
208         return ENOTSUP;
209
210     case IRQ_LINE:
211         class = &gic->spi;
212         break;
213
214     case IRQ_MESSAGE:
215         class = &pe->lpi;
216         break;
217     
218     default:
219         return EINVAL;
220     }
221
222     err = gic_assign_intid(class, irq);
223     if (err)
224         return err;
225
226     __gic_create_profile(&gint, class->kind, irq);
227     
228     err = class->ops->install(class, &gint);
229     if (err)
230         return err;
231
232     return class->ops->set_enabled(class, gint.intid, true);
233 }
234
235 static const struct irq_domain_ops gic_domain_ops = {
236     .install_irq = __gic_install_irq
237 };
238
239 struct gic*
240 gic_create_context(struct device* gicdev)
241 {
242     struct gic* gic;
243     struct irq_domain* domain;
244
245     gic = valloc(sizeof(*gic));
246     domain = irq_create_domain(gicdev, &gic_domain_ops);
247
248     irq_set_domain_object(gic, domain);
249     gic->domain = domain;
250
251     return gic;
252 }