Enabling APIC interrupt on GPIOs

razor1000
razor1000 New Member Posts: 22

Hi guys,
I'm having some trouble with my HID-over-I2C device. Everything is functionally working, but there are huge spikes of latency between when the GPIO asserts and when the system starts to read the data from the HID-over-I2C device. With no changes in the BIOS, the spikes could be as long as 20ms, which is rather awful. I'm expecting a max latency of maybe 2ms.

I enabled the "GPIO low latency" option in the CRB, and it cut the response latency by about half. Now I only see worst-case spikes of about 10ms. But that's still too much.

I was thinking maybe the latency is being caused by the GPIO interrupt being shared with all the other GPIOs. I know it is possible to configure the pin to cause an APIC interrupt instead, which seems like it might be faster, since the channels are not shared. Unfortunately I don't know how to configure the pins to use the APIC interrupt.

**Is there a way to configure GPIOs on the HAT connector to use the APIC interrupt instead of the GPIO interrupt using a BIOS setting or changing an ACPI table ? **

I noticed that enabling the "Touch Pad" or "Touch Panel" in the CRB allows you to configure the interrupt as GPIO or APIC. I tried enabling the "Touch Pad" using the APIC interrupt, but there was a resource conflict error in device manager. The IRQ it used was 0x18, which I think is for pin A0, and I have no idea where that pin is routed. I didn't try APIC with the "Touch Panel" because I don't know where I2C1 is routed. This is the functionality that I need, but with a different pin.

I'm enabling the HID-over-I2C device by overloading the "ssdt4" table (the PINCTRL table) using Microsoft's ASL compiler. (I'm using Windows 10). The instructions are here:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/microsoft-asl-compiler

These are the I2C and GPIO settings I'm using. The pin is GPIO11 on the HAT connector.

        Method (_CRS, 0, Serialized)  // _CRS: Current Resource Settings
        {
            Name (SBFI, ResourceTemplate ()
            {
                I2cSerialBusV2 (0x0024, ControllerInitiated, 0x00061A80,
                    AddressingMode7Bit, "\\_SB.PCI0.I2C3",
                    0x00, ResourceConsumer,,,
                    )

                GpioInt(Level, ActiveLow, Shared, PullDefault, 0x0000, "\\_SB.PCI0.GPI0", 0x00, ResourceConsumer,,)
                {
                    0x0076
                }
            })
            Return (SBFI) /* \_SB_.PCI0.I2C3.TPNL._CRS.SBFI */
        }

Comments

  • jayman
    jayman New Member Posts: 66 ✭✭

    Based on the information here: https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/enable-usermode-access

    In the GPIO section it states the following (among other requirements):

    Each pin requires both a GpioIO and a GpioInt resource. The GpioInt resource must immediately follow the GpioIO resource and must refer to the same pin number.
    The EdgeLevel field of the GpioInt descriptor must be Edge
    The ActiveLevel field of the GpioInt descriptor must be ActiveBoth
    The PinConfig field
    Must be the same in both the GpioIO and GpioInt descriptors
    Must be one of PullUp, PullDown, or PullNone. It cannot be PullDefault.

    It seems all of those rules are violated with the code snippet you posted.

    I have not tried using a GpioInt resource without an associated GpioIO resource, but using both the way outlined in that document (as well as following the other rules stated in that section) has worked fine for me to enable GPIO interrupts.

  • razor1000
    razor1000 New Member Posts: 22

    @jayman said:
    Based on the information here: https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/enable-usermode-access

    In the GPIO section it states the following (among other requirements):

    Each pin requires both a GpioIO and a GpioInt resource. The GpioInt resource must immediately follow the GpioIO resource and must refer to the same pin number.
    The EdgeLevel field of the GpioInt descriptor must be Edge
    The ActiveLevel field of the GpioInt descriptor must be ActiveBoth
    The PinConfig field
    Must be the same in both the GpioIO and GpioInt descriptors
    Must be one of PullUp, PullDown, or PullNone. It cannot be PullDefault.

    It seems all of those rules are violated with the code snippet you posted.

    I have not tried using a GpioInt resource without an associated GpioIO resource, but using both the way outlined in that document (as well as following the other rules stated in that section) has worked fine for me to enable GPIO interrupts.

    Those requirements are for rhproxy, which isn't what I'm using. I'm over-writing one of the tables. The GPIO interrupt works just fine in my setup, I just wanted to try the APIC interrupt to see if it there was less latency.

    In the end I figured out that the GPIO interrupt latency spikes were being caused by Driver Verifier being enabled. My guess is that the Windows HLK enabled it for one of the tests, and then didn't turn it back off again, so it was enabled for several HID drivers. With Driver Verifier disabled, the average GPIO interrupt latency is down to ~170us, which is great!