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, ptr_t data)
91 irq = valloc(sizeof(*irq));
92 *irq = (struct irq_object) {
94 .serve = callback ?: __default_servant,
95 .vector = IRQ_VECTOR_UNSET
98 if (type == IRQ_LINE) {
99 __irq_create_line(irq, data);
102 else if (type == IRQ_MESSAGE) {
103 __irq_create_msi(irq, data);
110 irq_revoke(irq_t irq)
112 if (--(irq->ref) > 0) {
119 irq_assign(struct irq_domain* domain, irq_t irq, void* irq_spec)
122 if (domain->ops->map_irq) {
123 err = domain->ops->map_irq(domain, irq, irq_spec);
130 A domain controller may choose to forward the interrupt
131 (i.e., irq became transparent and belongs to the higher domain)
132 We allow controller decide whether to record the irq under its wing
134 err = domain->ops->install_irq(domain, irq);
139 irq->domain = domain;
144 irq_find(struct irq_domain* domain, int local_irq)
147 struct irq_domain* current;
149 // Find recursively, in case of irq forwarding
151 current = domain ?: default_domain;
152 while (current && !irq) {
153 irq = (irq_t)btrie_get(¤t->irq_map, local_irq);
154 current = irq_parent_domain(current);
161 irq_record(struct irq_domain* domain, irq_t irq)
164 btrie_set(&domain->irq_map, irq->vector, irq);
168 irq_set_default_domain(struct irq_domain* domain)
170 assert(!default_domain);
171 default_domain = domain;
175 irq_forward_install(struct irq_domain* current, irq_t irq)
177 struct irq_domain* parent;
179 parent = irq_parent_domain(current);
181 if (irq->type == IRQ_LINE) {
182 irq->line->domain_local = irq->line->domain_mapped;
185 irq->domain = parent;
186 return parent->ops->install_irq(parent, irq);
190 irq_get_default_domain()
192 assert(default_domain);
193 return default_domain;