2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/owloysius.h>
5 static struct irq_domain* default_domain = NULL;
6 static DEFINE_LLIST(irq_domains);
9 __default_servant(irq_t irq, const struct hart_state* state)
15 irq_create_domain(struct device* intc_dev, const struct irq_domain_ops* ops)
17 struct irq_domain* domain;
19 assert(ops->install_irq);
21 domain = new_potens(potens(INT_DOMAIN), struct irq_domain);
22 device_grant_potens(intc_dev, potens_meta(domain));
24 btrie_init(&domain->irq_map, ilog2(8));
25 llist_append(&irq_domains, &domain->list);
32 irq_owning_domain(struct device* dev)
34 #ifdef CONFIG_USE_DEVICETREE
36 struct dtn* intr_parent;
37 struct potens_meta* domain_m;
39 intr_parent = dev->devtree_node->intr.parent;
40 intc = resolve_device_morph(dt_mobj(intr_parent));
46 domain_m = device_get_potens(intc, potens(INT_DOMAIN));
47 return !domain_m ?: get_potens(domain_m, struct irq_domain);
49 return default_domain;
54 irq_attach_domain(struct irq_domain* parent, struct irq_domain* child)
56 #ifndef CONFIG_USE_DEVICETREE
57 parent = parent ?: default_domain;
58 child->parent = parent;
64 __irq_create_line(irq_t irq, ptr_t local_int)
66 struct irq_line_wire *line;
68 line = valloc(sizeof(*line));
69 line->domain_local = local_int;
70 line->domain_mapped = local_int;
76 __irq_create_msi(irq_t irq, ptr_t message)
78 struct irq_msi_wire *msi;
80 msi = valloc(sizeof(*msi));
81 msi->message = message;
87 irq_declare(enum irq_type type, irq_servant callback,
88 ptr_t data, void* irq_extra)
92 irq = valloc(sizeof(*irq));
93 *irq = (struct irq_object) {
95 .serve = callback ?: __default_servant,
96 .irq_extra = irq_extra,
97 .vector = IRQ_VECTOR_UNSET
100 if (type == IRQ_LINE) {
101 __irq_create_line(irq, data);
104 else if (type == IRQ_MESSAGE) {
105 __irq_create_msi(irq, data);
112 irq_revoke(irq_t irq)
114 if (--(irq->ref) > 0) {
121 irq_assign(struct irq_domain* domain, irq_t irq)
124 if (domain->ops->map_irq) {
125 err = domain->ops->map_irq(domain, irq, irq->irq_extra);
132 A domain controller may choose to forward the interrupt
133 (i.e., irq became transparent and belongs to the higher domain)
134 We allow controller decide whether to record the irq under its wing
136 err = domain->ops->install_irq(domain, irq);
141 irq->domain = domain;
146 irq_find(struct irq_domain* domain, int local_irq)
149 struct irq_domain* current;
151 // Find recursively, in case of irq forwarding
153 current = domain ?: default_domain;
154 while (current && !irq) {
155 irq = (irq_t)btrie_get(¤t->irq_map, local_irq);
156 current = irq_parent_domain(current);
163 irq_record(struct irq_domain* domain, irq_t irq)
166 btrie_set(&domain->irq_map, irq->vector, irq);
170 irq_set_default_domain(struct irq_domain* domain)
172 assert(!default_domain);
173 default_domain = domain;
177 irq_forward_install(struct irq_domain* current, irq_t irq)
179 struct irq_domain* parent;
181 parent = irq_parent_domain(current);
183 if (irq->type == IRQ_LINE) {
184 irq->line->domain_local = irq->line->domain_mapped;
187 irq->domain = parent;
188 return parent->ops->install_irq(parent, irq);
192 irq_get_default_domain()
194 assert(default_domain);
195 return default_domain;