Re: [RFC PATCH 2/3] irqchip/exiu: implement ACPI gpiolib/irqchip support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 29/04/2019 10:09, Ard Biesheuvel wrote:
> On Sat, 27 Apr 2019 at 00:27, Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> wrote:
>>
>> On Fri, 26 Apr 2019 at 13:45, Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> wrote:
>>>
>>> On Fri, 26 Apr 2019 at 10:44, Marc Zyngier <marc.zyngier@xxxxxxx> wrote:
>>>>
>>>> On 26/04/2019 09:24, Ard Biesheuvel wrote:
>>>>> On Thu, 25 Apr 2019 at 17:33, Marc Zyngier <marc.zyngier@xxxxxxx> wrote:
>>>>>>
>>>>>> Hi Ard,
>>>>>>
>>>>>> On 25/04/2019 11:20, Ard Biesheuvel wrote:
>>>>>>> Expose the existing EXIU hierarchical irqchip domain code to permit
>>>>>>> the interrupt controller to be used as the irqchip component of a
>>>>>>> GPIO controller on ACPI systems.
>>>>>>>
>>>>>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
>>>>>>> ---
>>>>>>>  drivers/irqchip/irq-sni-exiu.c | 82 +++++++++++++++++---
>>>>>>>  1 file changed, 73 insertions(+), 9 deletions(-)
>>>>>>>
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>>> +int exiu_acpi_init(struct platform_device *pdev, struct gpio_chip *gc)
>>>>>>> +{
>>>>>>> +     struct irq_domain *parent_domain = NULL, *domain;
>>>>>>> +     struct resource *res;
>>>>>>> +     int irq;
>>>>>>> +
>>>>>>> +     irq = platform_get_irq(pdev, 0);
>>>>>>> +     if (irq > 0)
>>>>>>> +             parent_domain = irq_get_irq_data(irq)->domain;
>>>>>>> +
>>>>>>> +     if (!parent_domain) {
>>>>>>> +             dev_err(&pdev->dev, "unable to obtain parent domain\n");
>>>>>>> +             return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>>>>>> +     if (!res) {
>>>>>>> +             dev_err(&pdev->dev, "failed to parse memory resource\n");
>>>>>>> +             return -ENXIO;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     domain = exiu_init(parent_domain, dev_fwnode(&pdev->dev), res);
>>>>>>> +     if (IS_ERR(domain)) {
>>>>>>> +             dev_err(&pdev->dev, "failed to create IRQ domain (%ld)\n",
>>>>>>> +                     PTR_ERR(domain));
>>>>>>> +             return PTR_ERR(domain);
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     gc->irq.domain = domain;
>>>>>>> +     gc->to_irq = exiu_acpi_gpio_to_irq;
>>>>>>> +
>>>>>>> +     dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(exiu_acpi_init);
>>>>>>> +#endif
>>>>>>>
>>>>>>
>>>>>> I must say I'm not overly keen on this function. Why can't this be
>>>>>> probed as an ACPI device, creating the corresponding domain, and leaving
>>>>>> to the GPIO driver the task of doing the GPIO stuff?
>>>>>>
>>>>>
>>>>> Because ACPI only permits 'system' interrupts or GPIO interrupts, it
>>>>> does not allow arbitrary device objects in the ACPI namespace to be
>>>>> targeted as interrupt controllers.
>>>>
>>>> Hmmm. We already have at least one driver (irq-mbigen.c) that does
>>>> exactly that. It uses interrupts from the GIC (it is notionally behind
>>>> the ITS), and offers a bunch of interrupt lines itself. Why is it different?
>>>>
>>>
>>> You are right, it isn't. It turns out that there is another way to
>>> signal ACPI events based on interrupts, and it involves the ACPI0013
>>> GED device. I will try to model it that way instead.
>>>
>>
>> Unfortunately, this doesn't work either. The GED device can respond to
>> GSIVs only, and so going via the EXIU doesn't work.
>>
>> I have attempted to hack it up via AML, but the GED driver uses a
>> threaded interrupt, and so the interrupt is re-enabled at the GIC
>> before the AML handler is executed (which clears it in the EXIU)
>>
>> For the RAS case, I guess we could let the firmware pick an arbitrary
>> unused SPI and signal that directly into the GIC, but for the power
>> button (which is physically wired to the EXIU), we have to model the
>> EXIU either has a separate pseudo-GPIO controller, or as part of the
>> real GPIO block.
> 
> (+ Mika)
> 
> I made some progress describing the EXIU and GPIO controllers as follow.
> 
>     Device (EXIU) {
>       Name (_HID, "SCX0008")
>       Name (_UID, Zero)
>       Name (_CRS, ResourceTemplate () {
>         Memory32Fixed (ReadWrite, SYNQUACER_EXIU_BASE, SYNQUACER_EXIU_SIZE)
>         Interrupt (ResourceConsumer, Level, ActiveHigh, ExclusiveAndWake) {
>           144, 145, 146, 147, 148, 149, 150, 151,
>           152, 153, 154, 155, 156, 157, 158, 159,
>           160, 161, 162, 163, 164, 165, 166, 167,
>           168, 169, 170, 171, 172, 173, 174, 175,
>         }
>       })
>       Name (_DSD, Package () {
>         ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>         Package () {
>           Package () { "socionext,spi-base", 112 },
>         }
>       })
>     }
> 
> and
> 
>     Device (GPIO) {
>       Name (_HID, "SCX0007")
>       Name (_UID, Zero)
>       Name (_CRS, ResourceTemplate () {
>         Memory32Fixed (ReadWrite, SYNQUACER_GPIO_BASE, SYNQUACER_GPIO_SIZE)
>         Interrupt (ResourceConsumer, Edge, ActiveLow,
> ExclusiveAndWake, 0, "\\_SB.EXIU") {
>           7,
>         }
>       })
>       Name (_AEI, ResourceTemplate () {
>         GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullDefault, 0,
> "\\_SB.GPIO")
>         {
>           7
>         }
>       })
>       Method (_E07) {
>         Notify (\_SB.PWRB, 0x80)
>       }
>     }
> 
> This is actually a fairly accurate depiction of reality: the EXIU is a
> separate unit, and only some of the GPIOs are routed through it.
> 
> In the GPIO controller's to_irq() callback, I return the Linux IRQ
> number based on the platform IRQ resources claimed by the GPIO device,
> and I end up with something like
> 
>  46:          0 ... 0      EXIU   7 Edge      ACPI:Event
> 
> which looks correct to me. debugfs tells me it is mapped as
> 
> handler:  handle_fasteoi_irq
> device:   (null)
> status:   0x00000001
> istate:   0x00000020
>             IRQS_ONESHOT
> ddepth:   0
> wdepth:   1
> dstate:   0x03404201
>             IRQ_TYPE_EDGE_RISING
>             IRQD_ACTIVATED
>             IRQD_IRQ_STARTED
>             IRQD_SINGLE_TARGET
>             IRQD_WAKEUP_STATE
> node:     0
> affinity: 0-23
> effectiv: 0
> domain:  \_SB_.EXIU
>  hwirq:   0x7
>  chip:    EXIU
>   flags:   0x55
>              IRQCHIP_SET_TYPE_MASKED
>              IRQCHIP_MASK_ON_SUSPEND
>              IRQCHIP_SKIP_SET_WAKE
>              IRQCHIP_EOI_THREADED
>  parent:
>     domain:  irqchip@(____ptrval____)-1
>      hwirq:   0x97
>      chip:    GICv3
>       flags:   0x15
>                  IRQCHIP_SET_TYPE_MASKED
>                  IRQCHIP_MASK_ON_SUSPEND
>                  IRQCHIP_SKIP_SET_WAKE
> 
> The EXIU domain is described as
> 
> name:   \_SB_.EXIU
>  size:   32
>  mapped: 1
>  flags:  0x00000041
>  parent: irqchip@(____ptrval____)-1
>     name:   irqchip@(____ptrval____)-1
>      size:   0
>      mapped: 55
>      flags:  0x00000041
> 
> Unfortunately, the system locks up entirely as soon as the interrupt
> is triggered (I use a DIP switch in this case). So while the
> description is accurate and the correct interrupt does get mapped,
> something is still not working entirely as expected.
> 
> Any thoughts?

It feels like an interrupt storm with an edge vs level misconfiguration.
Can you check that the IRQ_TYPE_EDGE_RISING is correctly propagated
across the hierarchy?

The EXIU block has:

Interrupt (ResourceConsumer, Level, ActiveHigh, ExclusiveAndWake) {

while the GPIO block has:

Interrupt (ResourceConsumer, Edge, ActiveLow, ExclusiveAndWake, 0,
"\\_SB.EXIU")

and the interrupt is configured for yet another trigger
(IRQ_TYPE_EDGE_RISING).

Hope this helps,

	M.
-- 
Jazz is not dead. It just smells funny...



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux