Skip to content

Commit 7327b16

Browse files
author
Marc Zyngier
committed
APCI: irq: Add support for multiple GSI domains
In an unfortunate departure from the ACPI spec, the LoongArch architecture split its GSI space across multiple interrupt controllers. In order to be able to reuse the core code and prevent architectures from reinventing an already square wheel, offer the arch code the ability to register a dispatcher function that will return the domain fwnode for a given GSI. The ARM GIC drivers are updated to support this (with a single domain, as intended). Signed-off-by: Marc Zyngier <[email protected]> Cc: Hanjun Guo <[email protected]> Cc: Lorenzo Pieralisi <[email protected]> Signed-off-by: Jianmin Lv <[email protected]> Tested-by: Hanjun Guo <[email protected]> Reviewed-by: Hanjun Guo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent af6a1cf commit 7327b16

File tree

4 files changed

+50
-28
lines changed

4 files changed

+50
-28
lines changed

drivers/acpi/irq.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
enum acpi_irq_model_id acpi_irq_model;
1414

15-
static struct fwnode_handle *acpi_gsi_domain_id;
15+
static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
1616

1717
/**
1818
* acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
@@ -26,9 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
2626
*/
2727
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
2828
{
29-
struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
30-
DOMAIN_BUS_ANY);
29+
struct irq_domain *d;
3130

31+
d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
32+
DOMAIN_BUS_ANY);
3233
*irq = irq_find_mapping(d, gsi);
3334
/*
3435
* *irq == 0 means no mapping, that should
@@ -53,12 +54,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
5354
{
5455
struct irq_fwspec fwspec;
5556

56-
if (WARN_ON(!acpi_gsi_domain_id)) {
57+
fwspec.fwnode = acpi_get_gsi_domain_id(gsi);
58+
if (WARN_ON(!fwspec.fwnode)) {
5759
pr_warn("GSI: No registered irqchip, giving up\n");
5860
return -EINVAL;
5961
}
6062

61-
fwspec.fwnode = acpi_gsi_domain_id;
6263
fwspec.param[0] = gsi;
6364
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
6465
fwspec.param_count = 2;
@@ -73,13 +74,14 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi);
7374
*/
7475
void acpi_unregister_gsi(u32 gsi)
7576
{
76-
struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
77-
DOMAIN_BUS_ANY);
77+
struct irq_domain *d;
7878
int irq;
7979

8080
if (WARN_ON(acpi_irq_model == ACPI_IRQ_MODEL_GIC && gsi < 16))
8181
return;
8282

83+
d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
84+
DOMAIN_BUS_ANY);
8385
irq = irq_find_mapping(d, gsi);
8486
irq_dispose_mapping(irq);
8587
}
@@ -97,15 +99,16 @@ EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
9799
* The referenced device fwhandle or NULL on failure
98100
*/
99101
static struct fwnode_handle *
100-
acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
102+
acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source,
103+
u32 gsi)
101104
{
102105
struct fwnode_handle *result;
103106
struct acpi_device *device;
104107
acpi_handle handle;
105108
acpi_status status;
106109

107110
if (!source->string_length)
108-
return acpi_gsi_domain_id;
111+
return acpi_get_gsi_domain_id(gsi);
109112

110113
status = acpi_get_handle(NULL, source->string_ptr, &handle);
111114
if (WARN_ON(ACPI_FAILURE(status)))
@@ -194,7 +197,7 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
194197
ctx->index -= irq->interrupt_count;
195198
return AE_OK;
196199
}
197-
fwnode = acpi_gsi_domain_id;
200+
fwnode = acpi_get_gsi_domain_id(irq->interrupts[ctx->index]);
198201
acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
199202
irq->triggering, irq->polarity,
200203
irq->shareable, ctx);
@@ -207,7 +210,8 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
207210
ctx->index -= eirq->interrupt_count;
208211
return AE_OK;
209212
}
210-
fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source);
213+
fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source,
214+
eirq->interrupts[ctx->index]);
211215
acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index],
212216
eirq->triggering, eirq->polarity,
213217
eirq->shareable, ctx);
@@ -291,10 +295,10 @@ EXPORT_SYMBOL_GPL(acpi_irq_get);
291295
* GSI interrupts
292296
*/
293297
void __init acpi_set_irq_model(enum acpi_irq_model_id model,
294-
struct fwnode_handle *fwnode)
298+
struct fwnode_handle *(*fn)(u32))
295299
{
296300
acpi_irq_model = model;
297-
acpi_gsi_domain_id = fwnode;
301+
acpi_get_gsi_domain_id = fn;
298302
}
299303

300304
/**
@@ -312,8 +316,14 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
312316
const struct irq_domain_ops *ops,
313317
void *host_data)
314318
{
315-
struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
316-
DOMAIN_BUS_ANY);
319+
struct irq_domain *d;
320+
321+
/* This only works for the GIC model... */
322+
if (acpi_irq_model != ACPI_IRQ_MODEL_GIC)
323+
return NULL;
324+
325+
d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(0),
326+
DOMAIN_BUS_ANY);
317327

318328
if (!d)
319329
return NULL;

drivers/irqchip/irq-gic-v3.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,11 +2360,17 @@ static void __init gic_acpi_setup_kvm_info(void)
23602360
vgic_set_kvm_info(&gic_v3_kvm_info);
23612361
}
23622362

2363+
static struct fwnode_handle *gsi_domain_handle;
2364+
2365+
static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi)
2366+
{
2367+
return gsi_domain_handle;
2368+
}
2369+
23632370
static int __init
23642371
gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
23652372
{
23662373
struct acpi_madt_generic_distributor *dist;
2367-
struct fwnode_handle *domain_handle;
23682374
size_t size;
23692375
int i, err;
23702376

@@ -2396,26 +2402,26 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
23962402
if (err)
23972403
goto out_redist_unmap;
23982404

2399-
domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
2400-
if (!domain_handle) {
2405+
gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
2406+
if (!gsi_domain_handle) {
24012407
err = -ENOMEM;
24022408
goto out_redist_unmap;
24032409
}
24042410

24052411
err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
2406-
acpi_data.nr_redist_regions, 0, domain_handle);
2412+
acpi_data.nr_redist_regions, 0, gsi_domain_handle);
24072413
if (err)
24082414
goto out_fwhandle_free;
24092415

2410-
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
2416+
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
24112417

24122418
if (static_branch_likely(&supports_deactivate_key))
24132419
gic_acpi_setup_kvm_info();
24142420

24152421
return 0;
24162422

24172423
out_fwhandle_free:
2418-
irq_domain_free_fwnode(domain_handle);
2424+
irq_domain_free_fwnode(gsi_domain_handle);
24192425
out_redist_unmap:
24202426
for (i = 0; i < acpi_data.nr_redist_regions; i++)
24212427
if (acpi_data.redist_regs[i].redist_base)

drivers/irqchip/irq-gic.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,11 +1682,17 @@ static void __init gic_acpi_setup_kvm_info(void)
16821682
vgic_set_kvm_info(&gic_v2_kvm_info);
16831683
}
16841684

1685+
static struct fwnode_handle *gsi_domain_handle;
1686+
1687+
static struct fwnode_handle *gic_v2_get_gsi_domain_id(u32 gsi)
1688+
{
1689+
return gsi_domain_handle;
1690+
}
1691+
16851692
static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
16861693
const unsigned long end)
16871694
{
16881695
struct acpi_madt_generic_distributor *dist;
1689-
struct fwnode_handle *domain_handle;
16901696
struct gic_chip_data *gic = &gic_data[0];
16911697
int count, ret;
16921698

@@ -1724,22 +1730,22 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
17241730
/*
17251731
* Initialize GIC instance zero (no multi-GIC support).
17261732
*/
1727-
domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
1728-
if (!domain_handle) {
1733+
gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
1734+
if (!gsi_domain_handle) {
17291735
pr_err("Unable to allocate domain handle\n");
17301736
gic_teardown(gic);
17311737
return -ENOMEM;
17321738
}
17331739

1734-
ret = __gic_init_bases(gic, domain_handle);
1740+
ret = __gic_init_bases(gic, gsi_domain_handle);
17351741
if (ret) {
17361742
pr_err("Failed to initialise GIC\n");
1737-
irq_domain_free_fwnode(domain_handle);
1743+
irq_domain_free_fwnode(gsi_domain_handle);
17381744
gic_teardown(gic);
17391745
return ret;
17401746
}
17411747

1742-
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
1748+
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
17431749

17441750
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
17451751
gicv2m_init(NULL, gic_data[0].domain);

include/linux/acpi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
356356
int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
357357

358358
void acpi_set_irq_model(enum acpi_irq_model_id model,
359-
struct fwnode_handle *fwnode);
359+
struct fwnode_handle *(*)(u32));
360360

361361
struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
362362
unsigned int size,

0 commit comments

Comments
 (0)