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
99 if (type == IRQ_LINE) {
100 __irq_create_line(irq, data);
103 else if (type == IRQ_MESSAGE) {
104 __irq_create_msi(irq, data);
111 irq_revoke(irq_t irq)
113 if (--(irq->ref) > 0) {
120 irq_assign(struct irq_domain* domain, irq_t irq)
123 if (domain->ops->map_irq) {
124 err = domain->ops->map_irq(domain, irq, irq->irq_extra);
131 A domain controller may choose to forward the interrupt
132 (i.e., irq became transparent and belongs to the higher domain)
133 We allow controller decide whether to record the irq under its wing
135 err = domain->ops->install_irq(domain, irq);
140 irq->domain = domain;
145 irq_find(struct irq_domain* domain, int local_irq)
148 struct irq_domain* current;
150 // Find recursively, in case of irq forwarding
152 current = domain ?: default_domain;
153 while (current && !irq) {
154 irq = (irq_t)btrie_get(¤t->irq_map, local_irq);
155 current = irq_parent_domain(current);
162 irq_record(struct irq_domain* domain, irq_t irq)
165 btrie_set(&domain->irq_map, irq->vector, irq);
169 irq_set_default_domain(struct irq_domain* domain)
171 assert(!default_domain);
172 default_domain = domain;
176 irq_forward_install(struct irq_domain* current, irq_t irq)
178 struct irq_domain* parent;
180 parent = irq_parent_domain(current);
182 if (irq->type == IRQ_LINE) {
183 irq->line->domain_local = irq->line->domain_mapped;
186 irq->domain = parent;
187 return parent->ops->install_irq(parent, irq);
191 irq_get_default_domain()
193 assert(default_domain);
194 return default_domain;