Skip to content

Instantly share code, notes, and snippets.

@jcs
Last active July 19, 2019 20:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcs/0973ae50738e58ae40d2bd11270acc3b to your computer and use it in GitHub Desktop.
Save jcs/0973ae50738e58ae40d2bd11270acc3b to your computer and use it in GitHub Desktop.
The Great ihidev(4) Debugging

The Problem

  • I2C-connected Windows Precision Touchpads on Skylake and newer laptops don't generate interrupts through the IOAPIC when using OpenBSD - polling has to be used to fetch touchpad data

OpenBSD

ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 20, 120 pins
[...]
dwiic0 at pci0 dev 21 function 0 "Intel 100 Series I2C" rev 0x21: apic 2 int 16
iic0 at dwiic0
dwiic1 at pci0 dev 21 function 1 "Intel 100 Series I2C" rev 0x21: apic 2 int 17
iic1 at dwiic1
ihidev0 at iic1 addr 0x15 irq 109 (polling), vendor 0x4f3 product 0x3056, ELAN2201
ihidev0: 93 report ids
imt0 at ihidev0: clickpad, 5 contacts
wsmouse0 at imt0 mux 0
  • Windows Precision Touchpad (imt0) works when polling ihidev0 for touches, but ihidev0 doesn't receive interrupts via IOAPIC pin 109 as the DSDT says it should, and how it is registered through iic_intr_establish (iic_intr_establish -> dwiic_i2c_intr_establish -> acpi_intr_establish -> intr_establish -> ioapic_addroute)
  • Touchpad sends data through I2C master (dwiic1) which gets its own interrupt (IOAPIC pin 17) which does fire for its own events
  • After S3 suspend and resume, touchpad starts sending interrupts properly
  • Uses its own ACPI stack (not based on ACPICA)

NetBSD

  • Imported dwiic and ihidev drivers, writing a new driver for ACPI I2C glue since they use ACPICA
  • Interrupts for ihidev0 fire correctly via ioapic0 pin 109 (before S3 suspend/resume)
[     1.089244] dwiic1 at pci0 dev 21 function 1status 0x100002
[     1.089244] reset 0xffffffff
[     1.089244] rlo 0xffffffff
[     1.089244] rho 0xffffffff
[     1.089244] dwiic1: power status 0xb -> 0x8
[     1.089244] : I2C controller instance 1
[     1.089244] ioapic0: int17 0xa064<vector=0x64,delmode=0x0=fixed,physical,actlo,level,dest=0x0> 0x0<target=0x0>
[     1.089244] dwiic1: interrupting at ioapic0 pin 17
[     1.089244] ACPI Warning: \_SB.PCI0.I2C1.TPL1._DSM: Insufficient arguments - Caller passed 3, ACPI requires 4 (20190405/nsarguments-309)
[     1.089244] status 0x100002
[     1.089244] reset 0x3
[     1.089244] rlo 0x0
[     1.089244] rho 0x0
[     1.089244] dwiic1: power status 0x8 -> 0x8
[     1.089244] iic1 at dwiic1: I2C bus
[     1.089244] ihidev0 at iic1 addr 0x15: vendor 0x4f3 product 0x3056, ELAN2201
[     1.089244] ihidev0: 93 report ids
[     1.089244] ioapic0: int109 0xf065<vector=0x65,delmode=0x0=fixed,physical,pending,actlo,irrpending,level,dest=0x0> 0x0<target=0x0>
[     1.089244] ihidev0: interrupting at irq 109
[     1.089244] ims0 at ihidev0 reportid 1: 2 buttons, W and Z dirs
[     1.089244] wsmouse0 at ims0 mux 0

Linux

  • Drivers for intel-lpss-*, i2c-designware-*, and i2c-hid-core which interrupt properly
  • Since Linux's drivers are so much different than OpenBSD's, it will be much easier to use NetBSD-current as a target for trying things or adding debugging information

LPSS (Intel Low-Power Subsystem)

  • NetBSD dwiic_pci.c does LPSS_RESET, REMAP_LO, REMAP_HI, LPSS_CLKGATE
  • Added REMAP_LO, REMAP_HI, LPSS_CLKGATE to OpenBSD, doesn't work, commented out in NetBSD, still works
  • A hack was added to the OpenBSD dwiic ACPI attachment to write to an LPSS register for Broadwell devices (I think this was for the Chromebook Pixel which used iatp) on S3 resume to wake up the touchpad

Power (dwiic)

IOAPIC

  • Touchpad is hooked up to ioapic0 pin 109
  • OpenBSD: ioapic0: dump109 0xa062 0x0
  • NetBSD: ioapic0: dump109 0x1a065<vector=0x65,delmode=0x0=fixed,physical,actlo,level,masked,dest=0x0> 0x0<target=0x0>
    • vector is different (65 vs 62), masked bit set in NetBSD
  • Interrupt fires on OpenBSD after S3 suspend/resume
    • This patch may be needed for OpenBSD to get ihidev to stop polling during suspend/resume to avoid breaking it
    • Interrupts don't work if just the full S0->S3->S0 software code path is exercised, must actually power down

ACPI

  • Both call \_SB.PCI0.I2C1.TPL1._INI
  • Both call \_SB.PCI0.I2C1.TPL1._DSM
  • NetBSD sys/dev/acpi/acpi_i2c.c: ACPI Warning: \_SB.PCI0.I2C1.TPL1._DSM: Insufficient arguments - Caller passed 3, ACPI requires 4 (20190405/nsarguments-309)
    • E-mailed bouyer@ a patch
  • Both call \_SB.PCI0.I2C1.TPL1._CRS

Things I've tried:

  • Disabling all other i2c/pckbc devices (ichiic*, pckbc*)
  • Removing LPSS_CLKGATE and LPSS_REMAP_{LO,HI} from netbsd, adding to openbsd
  • Moving dwiic_pci_attach guts and/or ihidev attachment/interrupt setup guts to a config_mountroot callback, so it's executed while !cold
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment