Message ID | 20190429131208.3620-2-ard.biesheuvel@linaro.org (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | synquacer: implement ACPI gpio/interrupt support | expand |
On Mon, Apr 29, 2019 at 03:12:05PM +0200, Ard Biesheuvel wrote: > ACPI permits arbitrary producer->consumer interrupt links to be > described in AML, which means a topology such as the following > is perfectly legal: > > Device (EXIU) { > Name (_HID, "SCX0008") > Name (_UID, Zero) > Name (_CRS, ResourceTemplate () { > ... > }) > } > > Device (GPIO) { > Name (_HID, "SCX0007") > Name (_UID, Zero) > Name (_CRS, ResourceTemplate () { > Memory32Fixed (ReadWrite, SYNQUACER_GPIO_BASE, SYNQUACER_GPIO_SIZE) > Interrupt (ResourceConsumer, Edge, ActiveHigh, ExclusiveAndWake, 0, "\\_SB.EXIU") { > 7, > } > }) > ... > } > > The EXIU in this example is the external interrupt unit as can be found > on Socionext SynQuacer based platforms, which converts a block of 32 SPIs > from arbitrary polarity/trigger into level-high, with a separate set > of config/mask/unmask/clear controls. > > The existing DT based driver in drivers/irqchip/irq-sni-exiu.c models > this as a hierarchical domain stacked on top of the GIC's irqdomain. > Since the GIC is modeled as a DT node as well, obtaining a reference > to this irqdomain is easily done by going through the parent link. > > On ACPI systems, however, the GIC is not modeled as an object in the > namespace, and so device objects cannot refer to it directly. So in > order to obtain the irqdomain reference when driving the EXIU in ACPI > mode, we need a helper that returns the default domain for unqualified > interrupts. > > This is essentially what the ACPI GSI domain provides, so add a helper > that returns a reference to this domain. Or we directly export a function in: drivers/acpi/irq.c that creates a hierarchical domain with the default GSI domain as a parent, instead of exporting a function to get that domain from drivers, this should cut a bit of boilerplate and keep the default GSI domain handling in ACPI core. IIUC, the concept is a bit identical to what we did for MBIgen except that there IORT sets-up the device->msi_domain pointer and therefore the MBIgen driver does not have to do anything. Lorenzo > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > --- > drivers/acpi/irq.c | 14 ++++++++++---- > include/linux/acpi.h | 1 + > 2 files changed, 11 insertions(+), 4 deletions(-) > > diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c > index c3b2222e2129..d47bbd54d4aa 100644 > --- a/drivers/acpi/irq.c > +++ b/drivers/acpi/irq.c > @@ -17,6 +17,14 @@ enum acpi_irq_model_id acpi_irq_model; > > static struct fwnode_handle *acpi_gsi_domain_id; > > +/** > + * acpi_get_gsi_irqdomain - Retrieve the irqdomain that owns the GSI space. > + */ > +struct irq_domain *acpi_get_gsi_irqdomain(void) > +{ > + return irq_find_matching_fwnode(acpi_gsi_domain_id, DOMAIN_BUS_ANY); > +} > + > /** > * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI > * @gsi: GSI IRQ number to map > @@ -29,8 +37,7 @@ static struct fwnode_handle *acpi_gsi_domain_id; > */ > int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) > { > - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, > - DOMAIN_BUS_ANY); > + struct irq_domain *d = acpi_get_gsi_irqdomain(); > > *irq = irq_find_mapping(d, gsi); > /* > @@ -76,8 +83,7 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); > */ > void acpi_unregister_gsi(u32 gsi) > { > - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, > - DOMAIN_BUS_ANY); > + struct irq_domain *d = acpi_get_gsi_irqdomain(); > int irq = irq_find_mapping(d, gsi); > > irq_dispose_mapping(irq); > diff --git a/include/linux/acpi.h b/include/linux/acpi.h > index d5dcebd7aad3..1016027dd626 100644 > --- a/include/linux/acpi.h > +++ b/include/linux/acpi.h > @@ -316,6 +316,7 @@ static inline bool acpi_sci_irq_valid(void) > extern int sbf_port; > extern unsigned long acpi_realmode_flags; > > +struct irq_domain *acpi_get_gsi_irqdomain(void); > int acpi_register_gsi (struct device *dev, u32 gsi, int triggering, int polarity); > int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); > int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi); > -- > 2.20.1 >
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index c3b2222e2129..d47bbd54d4aa 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -17,6 +17,14 @@ enum acpi_irq_model_id acpi_irq_model; static struct fwnode_handle *acpi_gsi_domain_id; +/** + * acpi_get_gsi_irqdomain - Retrieve the irqdomain that owns the GSI space. + */ +struct irq_domain *acpi_get_gsi_irqdomain(void) +{ + return irq_find_matching_fwnode(acpi_gsi_domain_id, DOMAIN_BUS_ANY); +} + /** * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI * @gsi: GSI IRQ number to map @@ -29,8 +37,7 @@ static struct fwnode_handle *acpi_gsi_domain_id; */ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, - DOMAIN_BUS_ANY); + struct irq_domain *d = acpi_get_gsi_irqdomain(); *irq = irq_find_mapping(d, gsi); /* @@ -76,8 +83,7 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) { - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, - DOMAIN_BUS_ANY); + struct irq_domain *d = acpi_get_gsi_irqdomain(); int irq = irq_find_mapping(d, gsi); irq_dispose_mapping(irq); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d5dcebd7aad3..1016027dd626 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -316,6 +316,7 @@ static inline bool acpi_sci_irq_valid(void) extern int sbf_port; extern unsigned long acpi_realmode_flags; +struct irq_domain *acpi_get_gsi_irqdomain(void); int acpi_register_gsi (struct device *dev, u32 gsi, int triggering, int polarity); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
ACPI permits arbitrary producer->consumer interrupt links to be described in AML, which means a topology such as the following is perfectly legal: Device (EXIU) { Name (_HID, "SCX0008") Name (_UID, Zero) Name (_CRS, ResourceTemplate () { ... }) } Device (GPIO) { Name (_HID, "SCX0007") Name (_UID, Zero) Name (_CRS, ResourceTemplate () { Memory32Fixed (ReadWrite, SYNQUACER_GPIO_BASE, SYNQUACER_GPIO_SIZE) Interrupt (ResourceConsumer, Edge, ActiveHigh, ExclusiveAndWake, 0, "\\_SB.EXIU") { 7, } }) ... } The EXIU in this example is the external interrupt unit as can be found on Socionext SynQuacer based platforms, which converts a block of 32 SPIs from arbitrary polarity/trigger into level-high, with a separate set of config/mask/unmask/clear controls. The existing DT based driver in drivers/irqchip/irq-sni-exiu.c models this as a hierarchical domain stacked on top of the GIC's irqdomain. Since the GIC is modeled as a DT node as well, obtaining a reference to this irqdomain is easily done by going through the parent link. On ACPI systems, however, the GIC is not modeled as an object in the namespace, and so device objects cannot refer to it directly. So in order to obtain the irqdomain reference when driving the EXIU in ACPI mode, we need a helper that returns the default domain for unqualified interrupts. This is essentially what the ACPI GSI domain provides, so add a helper that returns a reference to this domain. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- drivers/acpi/irq.c | 14 ++++++++++---- include/linux/acpi.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-)