mbox series

[v8,0/3] Firmware Support for USB-HID Devices and CP2112

Message ID 20230227140758.1575-1-kaehndan@gmail.com
Headers show
Series Firmware Support for USB-HID Devices and CP2112 | expand

Message

Daniel Kaehn Feb. 27, 2023, 2:07 p.m. UTC
This patchset allows USB-HID devices to have DeviceTree bindings through sharing
the USB fwnode with the HID driver, and adds such a binding and driver
implementation for the CP2112 USB to SMBus Bridge (which necessitated the
USB-HID change). This change allows a CP2112 permanently attached in hardware to
be described in DT and interoperate with other drivers.

Thanks to all for your patience in working with me on these! I'll have
many lessons learned for future submissions.

Changes in v8:
- Apply Review tags retroactively to patches previously reviewed

Changes in v7:
- Use dev_fwnode when calling fwnod_handle_put in i2c_adapter in hid-cp2112.c
- Capitalize I2C and GPIO in commit message for patch 0003

Changes in v6:
- Fix fwnode_handle reference leaks in hid-cp21112.c
- Simplify hog node pattern in silabs,cp2112.yaml

Changes in v5:
 - Use fwnode API instead of of_node api in hid-core.c and hid-cp2112.c
 - Include sda-gpios and scl-gpios in silabs,cp2112.yaml
 - Additional fixups to silabs,cp2112.yaml to address comments
 - Submit threaded interrupt bugfix separately from this patchset, as requested

Changes in v4:
 - Moved silabs,cp2112.yaml to /Documentation/devicetree/bindings/i2c

Changes in v3:
 - Additional fixups to silabs,cp2112.yaml to address comments

Changes in v2:
 - Added more detail to silabs,cp2112.yaml dt-binding
 - Moved silabs,cp2112.yaml to /Documentation/devicetree/bindings/input
 - Added support for setting smbus clock-frequency from DT in hid-cp2112.c
 - Added freeing of of_nodes on error paths of _probe in hid-cp2112.c

Danny Kaehn (3):
  dt-bindings: i2c: Add CP2112 HID USB to SMBus Bridge
  HID: usbhid: Share USB device firmware node with child HID device
  HID: cp2112: Fwnode Support

 .../bindings/i2c/silabs,cp2112.yaml           | 113 ++++++++++++++++++
 drivers/hid/hid-cp2112.c                      |  15 ++-
 drivers/hid/usbhid/hid-core.c                 |   2 +
 3 files changed, 128 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/silabs,cp2112.yaml

Comments

Andy Shevchenko Feb. 27, 2023, 11:07 p.m. UTC | #1
On Mon, Feb 27, 2023 at 08:07:58AM -0600, Danny Kaehn wrote:
> Bind I2C and GPIO interfaces to subnodes with names
> "i2c" and "gpio" if they exist, respectively. This
> allows the GPIO and I2C controllers to be described
> in firmware as usual. Additionally, support configuring the
> I2C bus speed from the clock-frequency device property.

A bit shorten indentation...

Nevertheless what I realized now is that this change, despite being OF
independent by used APIs, still OF-only.

Would it be possible to allow indexed access to child nodes as well, so if
there are no names, we may still be able to use firmware nodes from the correct
children?

P.S. The problem with ACPI is that "name" of the child node will be in capital
letters as it's in accordance with the specification.
Daniel Kaehn Feb. 28, 2023, 7:05 p.m. UTC | #2
On Mon, Feb 27, 2023 at 5:07 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Mon, Feb 27, 2023 at 08:07:58AM -0600, Danny Kaehn wrote:
> > Bind I2C and GPIO interfaces to subnodes with names
> > "i2c" and "gpio" if they exist, respectively. This
> > allows the GPIO and I2C controllers to be described
> > in firmware as usual. Additionally, support configuring the
> > I2C bus speed from the clock-frequency device property.
>
> A bit shorten indentation...
>
> Nevertheless what I realized now is that this change, despite being OF
> independent by used APIs, still OF-only.

I assumed this would practically be the case -- not because of the casing
reason you gave (wasn't aware of that, thanks for the FYI), but because it
doesn't seem that there's any way to describe USB devices connected to
a USB port in ACPI, at least as far as I can tell (ACPI is still largely a black
box to me). But it seems reasonable that we should try to use the interface
in a way so that it could be described using ACPI at some point (assuming
that it isn't currently possible).

>
> Would it be possible to allow indexed access to child nodes as well, so if
> there are no names, we may still be able to use firmware nodes from the correct
> children?
>

Sure, you mean to fallback to using child nodes by index rather than by name
in the case that that device_get_named_child_node() fails?
Would we need to somehow verify that those nodes are the nodes we expect
them to be? (a.e. node 0 is actually the i2c-controller, node 1 is actually the
gpio-controller).

I don't see a reason why not, though I am curious if there is
precedence for this
strategy, a.e. in other drivers that use named child nodes. In my initial search
through the kernel, I don't think I found anything like this -- does that mean
those drivers also inherently won't work with ACPI?

The only driver I can find which uses device_get_named_child_node and has
an acpi_device_id is drivers/platform/x86/intel/chtwc_int33fe.c

> P.S. The problem with ACPI is that "name" of the child node will be in capital
> letters as it's in accordance with the specification.
>

Knowing that this is the limitation, some other potential resolutions
to potentially
consider might be:

- Uppercase the names of the child nodes for the DT binding -- it appears that
     the child node that chtwc_int33fe.c (the driver mentioned earlier) accesses
     does indeed have an upper-cased name -- though that driver doesn't have
     an of_device_id (makes sense, x86...). It seems named child nodes are
     always lowercase in DT bindings -- not sure if that's a rule, or
just how it
     currently happens to be.
- Do a case invariant compare on the names (and/or check for both lowercase
     and uppercase)
- Remove the use of child nodes, and combine the i2c and gpio nodes into the
    cp2112's fwnode. I didn't do this initially because I wanted to
avoid namespace
    collisions between GPIO hogs and i2c child devices, and thought
that logically
     made sense to keep them separate, but that was before knowing
this limitation
    of ACPI.

What are your / others' thoughts?

Thanks,

Danny Kaehn


> --
> With Best Regards,
> Andy Shevchenko
>
>
Andy Shevchenko March 1, 2023, 2:59 p.m. UTC | #3
+Cc: Hans (as some DT/ACPI interesting cases are being discussed).

On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
> On Mon, Feb 27, 2023 at 5:07 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Mon, Feb 27, 2023 at 08:07:58AM -0600, Danny Kaehn wrote:
> > > Bind I2C and GPIO interfaces to subnodes with names
> > > "i2c" and "gpio" if they exist, respectively. This
> > > allows the GPIO and I2C controllers to be described
> > > in firmware as usual. Additionally, support configuring the
> > > I2C bus speed from the clock-frequency device property.
> >
> > A bit shorten indentation...
> >
> > Nevertheless what I realized now is that this change, despite being OF
> > independent by used APIs, still OF-only.
> 
> I assumed this would practically be the case -- not because of the casing
> reason you gave (wasn't aware of that, thanks for the FYI), but because it
> doesn't seem that there's any way to describe USB devices connected to
> a USB port in ACPI, at least as far as I can tell (ACPI is still largely a black
> box to me).

That's not true :-)

Microsoft created a schema that is not part of the specification, but let's
say a standard de facto. Linux supports that and I even played with it [1]
to get connection of the arbitrary device to USB-2-GPIO/I²C/SPI adapter.

> But it seems reasonable that we should try to use the interface
> in a way so that it could be described using ACPI at some point (assuming
> that it isn't currently possible).
> 
> > Would it be possible to allow indexed access to child nodes as well, so if
> > there are no names, we may still be able to use firmware nodes from the correct
> > children?
> 
> Sure, you mean to fallback to using child nodes by index rather than by name
> in the case that that device_get_named_child_node() fails?  Would we need to
> somehow verify that those nodes are the nodes we expect them to be? (a.e.
> node 0 is actually the i2c-controller, node 1 is actually the
> gpio-controller).

Something like that, but I don't know if we can actually validate this without
having a preliminary agreement (hard-coded values) that index 0 is always let's
say I²C controller and so on.

> I don't see a reason why not, though I am curious if there is
> precedence for this
> strategy, a.e. in other drivers that use named child nodes. In my initial search
> through the kernel, I don't think I found anything like this -- does that mean
> those drivers also inherently won't work with ACPI?

If they are relying on names, yes, they won't work. It might be that some of them
have specific ACPI approach where different description is in use.

> The only driver I can find which uses device_get_named_child_node and has
> an acpi_device_id is drivers/platform/x86/intel/chtwc_int33fe.c

Yes, and you may notice the capitalization of the name. Also note, that relying
on the name in ACPI like now is quite fragile due to no common standard between
OEMs on how to name the same hardware nodes, they are free in that.

> > P.S. The problem with ACPI is that "name" of the child node will be in capital
> > letters as it's in accordance with the specification.
> 
> Knowing that this is the limitation, some other potential resolutions
> to potentially
> consider might be:
> 
> - Uppercase the names of the child nodes for the DT binding -- it appears
>   that the child node that chtwc_int33fe.c (the driver mentioned earlier)
>   accesses does indeed have an upper-cased name -- though that driver doesn't
>   have an of_device_id (makes sense, x86...). It seems named child nodes are
>   always lowercase in DT bindings -- not sure if that's a rule, or just how
>   it currently happens to be.

Not an option AFAIK, the DT and ACPI specifications are requiring conflicting
naming schema.

Possible way is to lowering case for ACPI names, but I dunno. We need more
opinions on this.

> - Do a case invariant compare on the names (and/or check for both lowercase
>   and uppercase)

For ACPI it will be always capital. For DT I have no clue if they allow capital
letters there, but I assume they don't.

> - Remove the use of child nodes, and combine the i2c and gpio nodes into the
>     cp2112's fwnode. I didn't do this initially because I wanted to avoid
>     namespace collisions between GPIO hogs and i2c child devices, and thought
>     that logically made sense to keep them separate, but that was before
>     knowing this limitation of ACPI.

Seems to me not an option at all, we need to define hardware as is. If it
combines two devices under a hood, should be two devices under a hood in
DT/ACPI.

[1]: https://stackoverflow.com/a/60855157/2511795
Andy Shevchenko March 1, 2023, 3:04 p.m. UTC | #4
On Wed, Mar 01, 2023 at 04:59:07PM +0200, Andy Shevchenko wrote:
> On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
> > On Mon, Feb 27, 2023 at 5:07 PM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > > On Mon, Feb 27, 2023 at 08:07:58AM -0600, Danny Kaehn wrote:
> > > > Bind I2C and GPIO interfaces to subnodes with names
> > > > "i2c" and "gpio" if they exist, respectively. This
> > > > allows the GPIO and I2C controllers to be described
> > > > in firmware as usual. Additionally, support configuring the
> > > > I2C bus speed from the clock-frequency device property.
> > >
> > > A bit shorten indentation...
> > >
> > > Nevertheless what I realized now is that this change, despite being OF
> > > independent by used APIs, still OF-only.
> > 
> > I assumed this would practically be the case -- not because of the casing
> > reason you gave (wasn't aware of that, thanks for the FYI), but because it
> > doesn't seem that there's any way to describe USB devices connected to
> > a USB port in ACPI, at least as far as I can tell (ACPI is still largely a black
> > box to me).
> 
> That's not true :-)
> 
> Microsoft created a schema that is not part of the specification, but let's
> say a standard de facto. Linux supports that and I even played with it [1]
> to get connection of the arbitrary device to USB-2-GPIO/I²C/SPI adapter.
> 
> > But it seems reasonable that we should try to use the interface
> > in a way so that it could be described using ACPI at some point (assuming
> > that it isn't currently possible).
> > 
> > > Would it be possible to allow indexed access to child nodes as well, so if
> > > there are no names, we may still be able to use firmware nodes from the correct
> > > children?
> > 
> > Sure, you mean to fallback to using child nodes by index rather than by name
> > in the case that that device_get_named_child_node() fails?  Would we need to
> > somehow verify that those nodes are the nodes we expect them to be? (a.e.
> > node 0 is actually the i2c-controller, node 1 is actually the
> > gpio-controller).
> 
> Something like that, but I don't know if we can actually validate this without
> having a preliminary agreement (hard-coded values) that index 0 is always let's
> say I²C controller and so on.
> 
> > I don't see a reason why not, though I am curious if there is
> > precedence for this
> > strategy, a.e. in other drivers that use named child nodes. In my initial search
> > through the kernel, I don't think I found anything like this -- does that mean
> > those drivers also inherently won't work with ACPI?
> 
> If they are relying on names, yes, they won't work. It might be that some of them
> have specific ACPI approach where different description is in use.
> 
> > The only driver I can find which uses device_get_named_child_node and has
> > an acpi_device_id is drivers/platform/x86/intel/chtwc_int33fe.c
> 
> Yes, and you may notice the capitalization of the name. Also note, that relying
> on the name in ACPI like now is quite fragile due to no common standard between
> OEMs on how to name the same hardware nodes, they are free in that.

Forgot to mention, that you need to take into consideration the drivers that are:
1) can be compiled with CONFIG_OF=n (i.e. using agnostic APIs);
2) having OF ID table;
3) being platform independent (no Kconfig dependency to something that's known
   to be an ARCH/CPU/etc one).

All of those can be instantiated in ACPI via special PRP0001 ACPI ID [2].

> > > P.S. The problem with ACPI is that "name" of the child node will be in capital
> > > letters as it's in accordance with the specification.
> > 
> > Knowing that this is the limitation, some other potential resolutions
> > to potentially
> > consider might be:
> > 
> > - Uppercase the names of the child nodes for the DT binding -- it appears
> >   that the child node that chtwc_int33fe.c (the driver mentioned earlier)
> >   accesses does indeed have an upper-cased name -- though that driver doesn't
> >   have an of_device_id (makes sense, x86...). It seems named child nodes are
> >   always lowercase in DT bindings -- not sure if that's a rule, or just how
> >   it currently happens to be.
> 
> Not an option AFAIK, the DT and ACPI specifications are requiring conflicting
> naming schema.
> 
> Possible way is to lowering case for ACPI names, but I dunno. We need more
> opinions on this.
> 
> > - Do a case invariant compare on the names (and/or check for both lowercase
> >   and uppercase)
> 
> For ACPI it will be always capital. For DT I have no clue if they allow capital
> letters there, but I assume they don't.
> 
> > - Remove the use of child nodes, and combine the i2c and gpio nodes into the
> >     cp2112's fwnode. I didn't do this initially because I wanted to avoid
> >     namespace collisions between GPIO hogs and i2c child devices, and thought
> >     that logically made sense to keep them separate, but that was before
> >     knowing this limitation of ACPI.
> 
> Seems to me not an option at all, we need to define hardware as is. If it
> combines two devices under a hood, should be two devices under a hood in
> DT/ACPI.
> 
> [1]: https://stackoverflow.com/a/60855157/2511795

[2]: https://docs.kernel.org/firmware-guide/acpi/enumeration.html#device-tree-namespace-link-device-id
Benjamin Tissoires March 2, 2023, 5:06 p.m. UTC | #5
On Mar 01 2023, Andy Shevchenko wrote:
> +Cc: Hans (as some DT/ACPI interesting cases are being discussed).
> 
> On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
> > On Mon, Feb 27, 2023 at 5:07 PM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > > On Mon, Feb 27, 2023 at 08:07:58AM -0600, Danny Kaehn wrote:
> > > > Bind I2C and GPIO interfaces to subnodes with names
> > > > "i2c" and "gpio" if they exist, respectively. This
> > > > allows the GPIO and I2C controllers to be described
> > > > in firmware as usual. Additionally, support configuring the
> > > > I2C bus speed from the clock-frequency device property.
> > >
> > > A bit shorten indentation...
> > >
> > > Nevertheless what I realized now is that this change, despite being OF
> > > independent by used APIs, still OF-only.
> > 
> > I assumed this would practically be the case -- not because of the casing
> > reason you gave (wasn't aware of that, thanks for the FYI), but because it
> > doesn't seem that there's any way to describe USB devices connected to
> > a USB port in ACPI, at least as far as I can tell (ACPI is still largely a black
> > box to me).
> 
> That's not true :-)
> 
> Microsoft created a schema that is not part of the specification, but let's
> say a standard de facto. Linux supports that and I even played with it [1]
> to get connection of the arbitrary device to USB-2-GPIO/I²C/SPI adapter.
> 
> > But it seems reasonable that we should try to use the interface
> > in a way so that it could be described using ACPI at some point (assuming
> > that it isn't currently possible).
> > 
> > > Would it be possible to allow indexed access to child nodes as well, so if
> > > there are no names, we may still be able to use firmware nodes from the correct
> > > children?
> > 
> > Sure, you mean to fallback to using child nodes by index rather than by name
> > in the case that that device_get_named_child_node() fails?  Would we need to
> > somehow verify that those nodes are the nodes we expect them to be? (a.e.
> > node 0 is actually the i2c-controller, node 1 is actually the
> > gpio-controller).
> 
> Something like that, but I don't know if we can actually validate this without
> having a preliminary agreement (hard-coded values) that index 0 is always let's
> say I²C controller and so on.
> 
> > I don't see a reason why not, though I am curious if there is
> > precedence for this
> > strategy, a.e. in other drivers that use named child nodes. In my initial search
> > through the kernel, I don't think I found anything like this -- does that mean
> > those drivers also inherently won't work with ACPI?
> 
> If they are relying on names, yes, they won't work. It might be that some of them
> have specific ACPI approach where different description is in use.
> 
> > The only driver I can find which uses device_get_named_child_node and has
> > an acpi_device_id is drivers/platform/x86/intel/chtwc_int33fe.c
> 
> Yes, and you may notice the capitalization of the name. Also note, that relying
> on the name in ACPI like now is quite fragile due to no common standard between
> OEMs on how to name the same hardware nodes, they are free in that.
> 
> > > P.S. The problem with ACPI is that "name" of the child node will be in capital
> > > letters as it's in accordance with the specification.
> > 
> > Knowing that this is the limitation, some other potential resolutions
> > to potentially
> > consider might be:
> > 
> > - Uppercase the names of the child nodes for the DT binding -- it appears
> >   that the child node that chtwc_int33fe.c (the driver mentioned earlier)
> >   accesses does indeed have an upper-cased name -- though that driver doesn't
> >   have an of_device_id (makes sense, x86...). It seems named child nodes are
> >   always lowercase in DT bindings -- not sure if that's a rule, or just how
> >   it currently happens to be.
> 
> Not an option AFAIK, the DT and ACPI specifications are requiring conflicting
> naming schema.
> 
> Possible way is to lowering case for ACPI names, but I dunno. We need more
> opinions on this.
> 
> > - Do a case invariant compare on the names (and/or check for both lowercase
> >   and uppercase)
> 
> For ACPI it will be always capital. For DT I have no clue if they allow capital
> letters there, but I assume they don't.
> 
> > - Remove the use of child nodes, and combine the i2c and gpio nodes into the
> >     cp2112's fwnode. I didn't do this initially because I wanted to avoid
> >     namespace collisions between GPIO hogs and i2c child devices, and thought
> >     that logically made sense to keep them separate, but that was before
> >     knowing this limitation of ACPI.
> 
> Seems to me not an option at all, we need to define hardware as is. If it
> combines two devices under a hood, should be two devices under a hood in
> DT/ACPI.
> 
> [1]: https://stackoverflow.com/a/60855157/2511795

Thanks Andy for your help here, and thanks for that link.

I am trying to test Danny's patch as I want to use it for my HID CI,
being an owner of a CP2112 device myself.

The current setup is using out of the tree patches [2] which are
implementing a platform i2c-hid support and some manual addition of a
I2C-HID device on top of it. This works fine but gets busted every now
and then when the tree sees a change that conflicts with these patches.

So with Danny's series, I thought I could have an SSDT override to
declare that very same device instead of patching my kernel before
testing it.

Of course, it gets tricky because I need to run that under qemu.

I am currently stuck at the "sharing the firmware_node from usb with
HID" step and I'd like to know if you could help me.

On my laptop, if I plug the CP2112 (without using a USB hub), I can get:

$> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*            
  lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
$> ls -l /sys/bus/usb/devices/2-9*/firmware_node
  lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
  lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25

So AFAIU the USB device is properly assigned a firmware node. My dsdt
also shows the "Device (RHUB)" and I guess everything is fine.

However, playing with qemu is not so easy.

I am running qemu with the following arguments (well, almost because I
have a wrapper script on top of it and I also run the compiled kernel
from the current tree):

#> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
                      -netdev user,id=hostnet0 \
                      -device virtio-net-pci,netdev=hostnet0 \
                      -m 4G \
                      -enable-kvm \
                      -cpu host \
                      -device qemu-xhci -usb \
                      -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
                      -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso

And this is what I get:

#> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
  lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001

#> ls -l /sys/bus/usb/devices/2-1*/firmware_node
  ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory

Looking at the DSDT, I do not see any reference to the USB hub, so I
wonder if the firmware_node needs to be populated first in the DSDT.

Also note that if I plug the CP2112 over a docking station, I lose the
firmware_node sysfs entries on the host too.

Do you think it would be achievable to emulate that over qemu and use a
mainline kernel without patches?

Cheers,
Benjamin

[2] https://gitlab.freedesktop.org/bentiss/gitlab-kernel-ci/-/tree/master/VM
Andy Shevchenko March 6, 2023, 10:49 a.m. UTC | #6
On Thu, Mar 02, 2023 at 06:06:06PM +0100, Benjamin Tissoires wrote:
> On Mar 01 2023, Andy Shevchenko wrote:
> > On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:

...

> > [1]: https://stackoverflow.com/a/60855157/2511795
> 
> Thanks Andy for your help here, and thanks for that link.
> 
> I am trying to test Danny's patch as I want to use it for my HID CI,
> being an owner of a CP2112 device myself.
> 
> The current setup is using out of the tree patches [2] which are
> implementing a platform i2c-hid support and some manual addition of a
> I2C-HID device on top of it. This works fine but gets busted every now
> and then when the tree sees a change that conflicts with these patches.
> 
> So with Danny's series, I thought I could have an SSDT override to
> declare that very same device instead of patching my kernel before
> testing it.
> 
> Of course, it gets tricky because I need to run that under qemu.
> 
> I am currently stuck at the "sharing the firmware_node from usb with
> HID" step and I'd like to know if you could help me.
> 
> On my laptop, if I plug the CP2112 (without using a USB hub), I can get:
> 
> $> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
>   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
> $> ls -l /sys/bus/usb/devices/2-9*/firmware_node
>   lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
>   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> 
> So AFAIU the USB device is properly assigned a firmware node. My dsdt
> also shows the "Device (RHUB)" and I guess everything is fine.

Yes, so far so good.

> However, playing with qemu is not so easy.
> 
> I am running qemu with the following arguments (well, almost because I
> have a wrapper script on top of it and I also run the compiled kernel
> from the current tree):
> 
> #> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
>                       -netdev user,id=hostnet0 \
>                       -device virtio-net-pci,netdev=hostnet0 \
>                       -m 4G \
>                       -enable-kvm \
>                       -cpu host \
>                       -device qemu-xhci -usb \
>                       -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
>                       -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso

Side question, where can I get those blobs from (EDKII and Fedora Live CD)?
I'm using Debian unstable.

> And this is what I get:
> 
> #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
>   lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001
> 
> #> ls -l /sys/bus/usb/devices/2-1*/firmware_node
>   ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory
> 
> Looking at the DSDT, I do not see any reference to the USB hub, so I
> wonder if the firmware_node needs to be populated first in the DSDT.

So, where QEMU takes DSDT (ACPI tables in general) from? Can you patch that?
I believe that's the problem in qemu.

> Also note that if I plug the CP2112 over a docking station, I lose the
> firmware_node sysfs entries on the host too.

This seems like a lack of firmware node propagating in the USB hub code in
the Linux kernel.

> Do you think it would be achievable to emulate that over qemu and use a
> mainline kernel without patches?

As long as qemu provides correct DSDT it should work I assume.

> [2] https://gitlab.freedesktop.org/bentiss/gitlab-kernel-ci/-/tree/master/VM
Benjamin Tissoires March 6, 2023, 12:36 p.m. UTC | #7
On Mon, Mar 6, 2023 at 11:49 AM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Mar 02, 2023 at 06:06:06PM +0100, Benjamin Tissoires wrote:
> > On Mar 01 2023, Andy Shevchenko wrote:
> > > On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
>
> ...
>
> > > [1]: https://stackoverflow.com/a/60855157/2511795
> >
> > Thanks Andy for your help here, and thanks for that link.
> >
> > I am trying to test Danny's patch as I want to use it for my HID CI,
> > being an owner of a CP2112 device myself.
> >
> > The current setup is using out of the tree patches [2] which are
> > implementing a platform i2c-hid support and some manual addition of a
> > I2C-HID device on top of it. This works fine but gets busted every now
> > and then when the tree sees a change that conflicts with these patches.
> >
> > So with Danny's series, I thought I could have an SSDT override to
> > declare that very same device instead of patching my kernel before
> > testing it.
> >
> > Of course, it gets tricky because I need to run that under qemu.
> >
> > I am currently stuck at the "sharing the firmware_node from usb with
> > HID" step and I'd like to know if you could help me.
> >
> > On my laptop, if I plug the CP2112 (without using a USB hub), I can get:
> >
> > $> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
> > $> ls -l /sys/bus/usb/devices/2-9*/firmware_node
> >   lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> >
> > So AFAIU the USB device is properly assigned a firmware node. My dsdt
> > also shows the "Device (RHUB)" and I guess everything is fine.
>
> Yes, so far so good.
>
> > However, playing with qemu is not so easy.
> >
> > I am running qemu with the following arguments (well, almost because I
> > have a wrapper script on top of it and I also run the compiled kernel
> > from the current tree):
> >
> > #> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
> >                       -netdev user,id=hostnet0 \
> >                       -device virtio-net-pci,netdev=hostnet0 \
> >                       -m 4G \
> >                       -enable-kvm \
> >                       -cpu host \
> >                       -device qemu-xhci -usb \
> >                       -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
> >                       -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso
>
> Side question, where can I get those blobs from (EDKII and Fedora Live CD)?
> I'm using Debian unstable.

You can install the ovmf package in debian[3], which should have a
similar file.
For the Fedora livecd -> https://getfedora.org/fr/workstation/download/
but any other distribution with a recent enough kernel should show the
same.
  >
>
> > And this is what I get:
> >
> > #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> >   lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001
> >
> > #> ls -l /sys/bus/usb/devices/2-1*/firmware_node
> >   ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory
> >
> > Looking at the DSDT, I do not see any reference to the USB hub, so I
> > wonder if the firmware_node needs to be populated first in the DSDT.
>
> So, where QEMU takes DSDT (ACPI tables in general) from? Can you patch that?
> I believe that's the problem in qemu.

That's a good question and it's one I am not sure I have the answer to.
I would have assumed that the DSDT was in the OVMF firmware, but given
that we can arbitrarily add command line arguments, I believe it
probably just provides a baseline and then we are screwed. The OVMF bios
is compiled only once, so I doubt there is any mechanism to
enable/disable a component in the DSDT, or make it dynamically
generated.

>
> > Also note that if I plug the CP2112 over a docking station, I lose the
> > firmware_node sysfs entries on the host too.
>
> This seems like a lack of firmware node propagating in the USB hub code in
> the Linux kernel.

That would make a lot of sense.

FWIW, in the VM I see a firmware node on the pci controller itself:
#> ls -l /sys/devices/pci0000\:00/0000\:00\:06.0/firmware_node
   lrwxrwxrwx 1 root root 0 Mar  6 12:24 /sys/devices/pci0000:00/0000:00:06.0/firmware_node -> ../../LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:07

And one the host, through a USB hub:

#> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
   lrwxrwxrwx. 1 root root 0 Mar  6 13:26 /sys/bus/hid/devices/0003:10C4:EA90.007C -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-8/2-8.2/2-8.2.4/2-8.2.4:1.0/0003:10C4:EA90.007C
#> ls -l /sys/bus/usb/devices/2-8*/firmware_node
   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e

Note that the firmware node propagation stopped at 2-8, and 2.8.2 is not
having a firmware node.


>
> > Do you think it would be achievable to emulate that over qemu and use a
> > mainline kernel without patches?
>
> As long as qemu provides correct DSDT it should work I assume.

Just to be sure I understand, for this to work, we need the DSDT to
export a "Device(RHUB)"?
Or if we fix the USB fw_node propagation, could we just overwrite
"\_SB_.PCI0.S30_"?  "\_SB_.PCI0.S30_" is the name the ACPI is giving to
the USB port in my VM case AFAIU.

Cheers,
Benjamin

>
> > [2] https://gitlab.freedesktop.org/bentiss/gitlab-kernel-ci/-/tree/master/VM

[3] https://packages.debian.org/buster/all/ovmf/filelist
Andy Shevchenko March 6, 2023, 1:07 p.m. UTC | #8
On Mon, Mar 06, 2023 at 01:36:51PM +0100, Benjamin Tissoires wrote:
> On Mon, Mar 6, 2023 at 11:49 AM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > On Thu, Mar 02, 2023 at 06:06:06PM +0100, Benjamin Tissoires wrote:
> > > On Mar 01 2023, Andy Shevchenko wrote:
> > > > On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:

...

[1]: https://stackoverflow.com/a/60855157/2511795

> > > Thanks Andy for your help here, and thanks for that link.
> > >
> > > I am trying to test Danny's patch as I want to use it for my HID CI,
> > > being an owner of a CP2112 device myself.
> > >
> > > The current setup is using out of the tree patches [2] which are
> > > implementing a platform i2c-hid support and some manual addition of a
> > > I2C-HID device on top of it. This works fine but gets busted every now
> > > and then when the tree sees a change that conflicts with these patches.
> > >
> > > So with Danny's series, I thought I could have an SSDT override to
> > > declare that very same device instead of patching my kernel before
> > > testing it.
> > >
> > > Of course, it gets tricky because I need to run that under qemu.
> > >
> > > I am currently stuck at the "sharing the firmware_node from usb with
> > > HID" step and I'd like to know if you could help me.
> > >
> > > On my laptop, if I plug the CP2112 (without using a USB hub), I can get:
> > >
> > > $> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
> > > $> ls -l /sys/bus/usb/devices/2-9*/firmware_node
> > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > >
> > > So AFAIU the USB device is properly assigned a firmware node. My dsdt
> > > also shows the "Device (RHUB)" and I guess everything is fine.
> > 
> > Yes, so far so good.
> > 
> > > However, playing with qemu is not so easy.
> > >
> > > I am running qemu with the following arguments (well, almost because I
> > > have a wrapper script on top of it and I also run the compiled kernel
> > > from the current tree):
> > >
> > > #> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
> > >                       -netdev user,id=hostnet0 \
> > >                       -device virtio-net-pci,netdev=hostnet0 \
> > >                       -m 4G \
> > >                       -enable-kvm \
> > >                       -cpu host \
> > >                       -device qemu-xhci -usb \
> > >                       -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
> > >                       -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso
> > 
> > Side question, where can I get those blobs from (EDKII and Fedora Live CD)?
> > I'm using Debian unstable.
> 
> You can install the ovmf package in debian[3], which should have a
> similar file.
> For the Fedora livecd -> https://getfedora.org/fr/workstation/download/
> but any other distribution with a recent enough kernel should show the
> same.

Thank you!

> > > And this is what I get:
> > >
> > > #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > >   lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001
> > >
> > > #> ls -l /sys/bus/usb/devices/2-1*/firmware_node
> > >   ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory
> > >
> > > Looking at the DSDT, I do not see any reference to the USB hub, so I
> > > wonder if the firmware_node needs to be populated first in the DSDT.
> > 
> > So, where QEMU takes DSDT (ACPI tables in general) from? Can you patch that?
> > I believe that's the problem in qemu.
> 
> That's a good question and it's one I am not sure I have the answer to.
> I would have assumed that the DSDT was in the OVMF firmware, but given
> that we can arbitrarily add command line arguments, I believe it
> probably just provides a baseline and then we are screwed. The OVMF bios
> is compiled only once, so I doubt there is any mechanism to
> enable/disable a component in the DSDT, or make it dynamically
> generated.

We have two ways of filling missing parts:
1) update the original source of DSDT (firmware or bootloader,
   whichever provides that);
2) adding an overlay.

The 2) works _if and only if_ there is *no* existing object in the tables.
In such cases, you can simply provide a *full* hierarchy. See an example of
PCI devices in the kernel documentation on how to do that. I believe something
similar can be done for USB.

> > > Also note that if I plug the CP2112 over a docking station, I lose the
> > > firmware_node sysfs entries on the host too.
> > 
> > This seems like a lack of firmware node propagating in the USB hub code in
> > the Linux kernel.
> 
> That would make a lot of sense.
> 
> FWIW, in the VM I see a firmware node on the pci controller itself:
> #> ls -l /sys/devices/pci0000\:00/0000\:00\:06.0/firmware_node
>   lrwxrwxrwx 1 root root 0 Mar  6 12:24 /sys/devices/pci0000:00/0000:00:06.0/firmware_node -> ../../LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:07
> 
> And one the host, through a USB hub:
> 
> #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
>   lrwxrwxrwx. 1 root root 0 Mar  6 13:26 /sys/bus/hid/devices/0003:10C4:EA90.007C -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-8/2-8.2/2-8.2.4/2-8.2.4:1.0/0003:10C4:EA90.007C
> #> ls -l /sys/bus/usb/devices/2-8*/firmware_node
>   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
>   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
> 
> Note that the firmware node propagation stopped at 2-8, and 2.8.2 is not
> having a firmware node.

It would be nice if you can run `grep -H 15 /sys/bus/acpi/devices/*/status`,
filter out unneeded ones, and for the rest also print their paths:
`cat filtered_list_of_acpi_devs | while read p; do grep -H . $p/path; done`

With this we will see what devices are actually present and up and running
in the system and what their paths in the ACPI namespace.

> > > Do you think it would be achievable to emulate that over qemu and use a
> > > mainline kernel without patches?
> > 
> > As long as qemu provides correct DSDT it should work I assume.
> 
> Just to be sure I understand, for this to work, we need the DSDT to
> export a "Device(RHUB)"?

Not sure I understand the term "export" here. We need a description
of the (to describe) missing parts.

> Or if we fix the USB fw_node propagation, could we just overwrite
> "\_SB_.PCI0.S30_"?  "\_SB_.PCI0.S30_" is the name the ACPI is giving to
> the USB port in my VM case AFAIU.

I have no idea what is the S30 node.

[2] https://gitlab.freedesktop.org/bentiss/gitlab-kernel-ci/-/tree/master/VM
[3] https://packages.debian.org/buster/all/ovmf/filelist
Benjamin Tissoires March 6, 2023, 2:48 p.m. UTC | #9
On Mon, Mar 6, 2023 at 2:07 PM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
>
> On Mon, Mar 06, 2023 at 01:36:51PM +0100, Benjamin Tissoires wrote:
> > On Mon, Mar 6, 2023 at 11:49 AM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > > On Thu, Mar 02, 2023 at 06:06:06PM +0100, Benjamin Tissoires wrote:
> > > > On Mar 01 2023, Andy Shevchenko wrote:
> > > > > On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
>
> ...
>
> [1]: https://stackoverflow.com/a/60855157/2511795
>
> > > > Thanks Andy for your help here, and thanks for that link.
> > > >
> > > > I am trying to test Danny's patch as I want to use it for my HID CI,
> > > > being an owner of a CP2112 device myself.
> > > >
> > > > The current setup is using out of the tree patches [2] which are
> > > > implementing a platform i2c-hid support and some manual addition of a
> > > > I2C-HID device on top of it. This works fine but gets busted every now
> > > > and then when the tree sees a change that conflicts with these patches.
> > > >
> > > > So with Danny's series, I thought I could have an SSDT override to
> > > > declare that very same device instead of patching my kernel before
> > > > testing it.
> > > >
> > > > Of course, it gets tricky because I need to run that under qemu.
> > > >
> > > > I am currently stuck at the "sharing the firmware_node from usb with
> > > > HID" step and I'd like to know if you could help me.
> > > >
> > > > On my laptop, if I plug the CP2112 (without using a USB hub), I can get:
> > > >
> > > > $> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
> > > > $> ls -l /sys/bus/usb/devices/2-9*/firmware_node
> > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > > >
> > > > So AFAIU the USB device is properly assigned a firmware node. My dsdt
> > > > also shows the "Device (RHUB)" and I guess everything is fine.
> > >
> > > Yes, so far so good.
> > >
> > > > However, playing with qemu is not so easy.
> > > >
> > > > I am running qemu with the following arguments (well, almost because I
> > > > have a wrapper script on top of it and I also run the compiled kernel
> > > > from the current tree):
> > > >
> > > > #> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
> > > >                       -netdev user,id=hostnet0 \
> > > >                       -device virtio-net-pci,netdev=hostnet0 \
> > > >                       -m 4G \
> > > >                       -enable-kvm \
> > > >                       -cpu host \
> > > >                       -device qemu-xhci -usb \
> > > >                       -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
> > > >                       -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso
> > >
> > > Side question, where can I get those blobs from (EDKII and Fedora Live CD)?
> > > I'm using Debian unstable.
> >
> > You can install the ovmf package in debian[3], which should have a
> > similar file.
> > For the Fedora livecd -> https://getfedora.org/fr/workstation/download/
> > but any other distribution with a recent enough kernel should show the
> > same.
>
> Thank you!
>
> > > > And this is what I get:
> > > >
> > > > #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > > >   lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001
> > > >
> > > > #> ls -l /sys/bus/usb/devices/2-1*/firmware_node
> > > >   ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory
> > > >
> > > > Looking at the DSDT, I do not see any reference to the USB hub, so I
> > > > wonder if the firmware_node needs to be populated first in the DSDT.
> > >
> > > So, where QEMU takes DSDT (ACPI tables in general) from? Can you patch that?
> > > I believe that's the problem in qemu.
> >
> > That's a good question and it's one I am not sure I have the answer to.
> > I would have assumed that the DSDT was in the OVMF firmware, but given
> > that we can arbitrarily add command line arguments, I believe it
> > probably just provides a baseline and then we are screwed. The OVMF bios
> > is compiled only once, so I doubt there is any mechanism to
> > enable/disable a component in the DSDT, or make it dynamically
> > generated.
>
> We have two ways of filling missing parts:
> 1) update the original source of DSDT (firmware or bootloader,
>    whichever provides that);
> 2) adding an overlay.
>
> The 2) works _if and only if_ there is *no* existing object in the tables.
> In such cases, you can simply provide a *full* hierarchy. See an example of
> PCI devices in the kernel documentation on how to do that. I believe something
> similar can be done for USB.

Please find attached the dsdt from the Qemu VM.


And after looking at it, your comments below, I think I am understanding
what is happening (on the qemu side at least):

#> grep PCI0.S /sys/bus/acpi/devices/*/path
/sys/bus/acpi/devices/device:02/path:\_SB_.PCI0.S00_
/sys/bus/acpi/devices/device:03/path:\_SB_.PCI0.S10_
/sys/bus/acpi/devices/device:04/path:\_SB_.PCI0.S18_
/sys/bus/acpi/devices/device:05/path:\_SB_.PCI0.S20_
/sys/bus/acpi/devices/device:06/path:\_SB_.PCI0.S28_
/sys/bus/acpi/devices/device:07/path:\_SB_.PCI0.S30_
/sys/bus/acpi/devices/device:08/path:\_SB_.PCI0.S38_
/sys/bus/acpi/devices/device:09/path:\_SB_.PCI0.S40_
/sys/bus/acpi/devices/device:0a/path:\_SB_.PCI0.S48_
/sys/bus/acpi/devices/device:0b/path:\_SB_.PCI0.S50_
/sys/bus/acpi/devices/device:0c/path:\_SB_.PCI0.S58_
/sys/bus/acpi/devices/device:0d/path:\_SB_.PCI0.S60_
/sys/bus/acpi/devices/device:0e/path:\_SB_.PCI0.S68_
/sys/bus/acpi/devices/device:0f/path:\_SB_.PCI0.S70_
/sys/bus/acpi/devices/device:10/path:\_SB_.PCI0.S78_
/sys/bus/acpi/devices/device:11/path:\_SB_.PCI0.S80_
/sys/bus/acpi/devices/device:12/path:\_SB_.PCI0.S88_
/sys/bus/acpi/devices/device:13/path:\_SB_.PCI0.S90_
/sys/bus/acpi/devices/device:14/path:\_SB_.PCI0.S98_
/sys/bus/acpi/devices/device:15/path:\_SB_.PCI0.SA0_
/sys/bus/acpi/devices/device:16/path:\_SB_.PCI0.SA8_
/sys/bus/acpi/devices/device:17/path:\_SB_.PCI0.SB0_
/sys/bus/acpi/devices/device:18/path:\_SB_.PCI0.SB8_
/sys/bus/acpi/devices/device:19/path:\_SB_.PCI0.SC0_
/sys/bus/acpi/devices/device:1a/path:\_SB_.PCI0.SC8_
/sys/bus/acpi/devices/device:1b/path:\_SB_.PCI0.SD0_
/sys/bus/acpi/devices/device:1c/path:\_SB_.PCI0.SD8_
/sys/bus/acpi/devices/device:1d/path:\_SB_.PCI0.SE0_
/sys/bus/acpi/devices/device:1e/path:\_SB_.PCI0.SE8_
/sys/bus/acpi/devices/device:1f/path:\_SB_.PCI0.SF0_
/sys/bus/acpi/devices/device:20/path:\_SB_.PCI0.SF8_

And those translate on the DSDT as (for the S30/S38 chunk I am
interested in):

             Device (S30)
             {
                 Name (_ADR, 0x00060000)  // _ADR: Address
                 Name (ASUN, 0x06)
                 Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
                 {
                     Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, ASUN))
                 }

                 Name (_SUN, 0x06)  // _SUN: Slot User Number
                 Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
                 {
                     PCEJ (BSEL, _SUN)
                 }
             }

             Device (S38)
             {
                 Name (_ADR, 0x00070000)  // _ADR: Address
                 Name (ASUN, 0x07)
                 Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
                 {
                     Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, ASUN))
                 }

                 Name (_SUN, 0x07)  // _SUN: Slot User Number
                 Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
                 {
                     PCEJ (BSEL, _SUN)
                 }
             }

The forwarded USB node is actually on device:07 -> S30_, and as much as
I'd like it to be a regular USB hub, this looks like a virtio node entry
that allows to forward a physical device to the VM.

So IMO, the missing piece might rely on the virtio-usb code which
doesn't export the firmware node, which means I can not extend the
device with an SSDT overlay ATM because the USB node doesn't have the
fw_node.

>
> > > > Also note that if I plug the CP2112 over a docking station, I lose the
> > > > firmware_node sysfs entries on the host too.
> > >
> > > This seems like a lack of firmware node propagating in the USB hub code in
> > > the Linux kernel.
> >
> > That would make a lot of sense.
> >
> > FWIW, in the VM I see a firmware node on the pci controller itself:
> > #> ls -l /sys/devices/pci0000\:00/0000\:00\:06.0/firmware_node
> >   lrwxrwxrwx 1 root root 0 Mar  6 12:24 /sys/devices/pci0000:00/0000:00:06.0/firmware_node -> ../../LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:07
> >
> > And one the host, through a USB hub:
> >
> > #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> >   lrwxrwxrwx. 1 root root 0 Mar  6 13:26 /sys/bus/hid/devices/0003:10C4:EA90.007C -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-8/2-8.2/2-8.2.4/2-8.2.4:1.0/0003:10C4:EA90.007C
> > #> ls -l /sys/bus/usb/devices/2-8*/firmware_node
> >   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
> >   lrwxrwxrwx. 1 root root 0 Mar  2 16:53 /sys/bus/usb/devices/2-8/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
> >
> > Note that the firmware node propagation stopped at 2-8, and 2.8.2 is not
> > having a firmware node.
>
> It would be nice if you can run `grep -H 15 /sys/bus/acpi/devices/*/status`,

This command (both on the host and on the VM) does not show any USB
device or even the PCI USB controller itself (PNP0A08 or PNP0A03).

> filter out unneeded ones, and for the rest also print their paths:
> `cat filtered_list_of_acpi_devs | while read p; do grep -H . $p/path; done`

see above for the VM case, and in the host:

#> grep XHC /sys/bus/acpi/devices/*/path
/sys/bus/acpi/devices/device:15/path:\_SB_.PCI0.XHC_
/sys/bus/acpi/devices/device:16/path:\_SB_.PCI0.XHC_.RHUB
/sys/bus/acpi/devices/device:17/path:\_SB_.PCI0.XHC_.RHUB.HS01
/sys/bus/acpi/devices/device:18/path:\_SB_.PCI0.XHC_.RHUB.HS02
/sys/bus/acpi/devices/device:19/path:\_SB_.PCI0.XHC_.RHUB.HS03
/sys/bus/acpi/devices/device:1a/path:\_SB_.PCI0.XHC_.RHUB.HS04
/sys/bus/acpi/devices/device:1b/path:\_SB_.PCI0.XHC_.RHUB.HS05
/sys/bus/acpi/devices/device:1c/path:\_SB_.PCI0.XHC_.RHUB.HS06
/sys/bus/acpi/devices/device:1d/path:\_SB_.PCI0.XHC_.RHUB.HS07
/sys/bus/acpi/devices/device:1e/path:\_SB_.PCI0.XHC_.RHUB.HS08
/sys/bus/acpi/devices/device:1f/path:\_SB_.PCI0.XHC_.RHUB.SS01
/sys/bus/acpi/devices/device:20/path:\_SB_.PCI0.XHC_.RHUB.SS02
/sys/bus/acpi/devices/device:21/path:\_SB_.PCI0.XHC_.RHUB.SS03
/sys/bus/acpi/devices/device:22/path:\_SB_.PCI0.XHC_.RHUB.SS04
/sys/bus/acpi/devices/device:23/path:\_SB_.PCI0.XHC_.RHUB.SS05
/sys/bus/acpi/devices/device:24/path:\_SB_.PCI0.XHC_.RHUB.SS06
/sys/bus/acpi/devices/device:25/path:\_SB_.PCI0.XHC_.RHUB.HS09
/sys/bus/acpi/devices/device:26/path:\_SB_.PCI0.XHC_.RHUB.HS10
/sys/bus/acpi/devices/device:27/path:\_SB_.PCI0.XHC_.RHUB.USR1
/sys/bus/acpi/devices/device:28/path:\_SB_.PCI0.XHC_.RHUB.USR2
/sys/bus/acpi/devices/device:85/path:\_SB_.PCI0.TXHC
/sys/bus/acpi/devices/device:86/path:\_SB_.PCI0.TXHC.RHUB
/sys/bus/acpi/devices/device:87/path:\_SB_.PCI0.TXHC.RHUB.HS01
/sys/bus/acpi/devices/device:88/path:\_SB_.PCI0.TXHC.RHUB.SS01
/sys/bus/acpi/devices/device:89/path:\_SB_.PCI0.TXHC.RHUB.SS02
/sys/bus/acpi/devices/device:8a/path:\_SB_.PCI0.TXHC.RHUB.SS03
/sys/bus/acpi/devices/device:8b/path:\_SB_.PCI0.TXHC.RHUB.SS04

Which is coherent with the ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:1e
I get when looking at the USB port.


>
> With this we will see what devices are actually present and up and running
> in the system and what their paths in the ACPI namespace.

So it seems that the USB hub functionality is not creating fw_nodes for
its children. But I am not sure this is a battle we want to fight right
now, because it doesn't make a lot of sense IMO to add an SSDT overlay
on a hub.

>
> > > > Do you think it would be achievable to emulate that over qemu and use a
> > > > mainline kernel without patches?
> > >
> > > As long as qemu provides correct DSDT it should work I assume.
> >
> > Just to be sure I understand, for this to work, we need the DSDT to
> > export a "Device(RHUB)"?
>
> Not sure I understand the term "export" here. We need a description
> of the (to describe) missing parts.

Yes, I meant "to describe" it.

>
> > Or if we fix the USB fw_node propagation, could we just overwrite
> > "\_SB_.PCI0.S30_"?  "\_SB_.PCI0.S30_" is the name the ACPI is giving to
> > the USB port in my VM case AFAIU.
>
> I have no idea what is the S30 node.

That gave me the hint I needed, I think. The problem must be in the
virtio drivers, where it doesn't attach the fw_node to the components it
creates. We probably need kind of the same patch Danny is sending in 2/3
in this series, but for virtio.

Cheers,
Benjamin

>
> [2] https://gitlab.freedesktop.org/bentiss/gitlab-kernel-ci/-/tree/master/VM
> [3] https://packages.debian.org/buster/all/ovmf/filelist
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Andy Shevchenko March 6, 2023, 5:01 p.m. UTC | #10
On Mon, Mar 06, 2023 at 03:48:18PM +0100, Benjamin Tissoires wrote:
> 
> 
> On Mon, Mar 6, 2023 at 2:07 PM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > 
> > On Mon, Mar 06, 2023 at 01:36:51PM +0100, Benjamin Tissoires wrote:
> > > On Mon, Mar 6, 2023 at 11:49 AM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > > > On Thu, Mar 02, 2023 at 06:06:06PM +0100, Benjamin Tissoires wrote:
> > > > > On Mar 01 2023, Andy Shevchenko wrote:
> > > > > > On Tue, Feb 28, 2023 at 01:05:54PM -0600, Daniel Kaehn wrote:
> > 
> > ...
> > 
> > [1]: https://stackoverflow.com/a/60855157/2511795
> > 
> > > > > Thanks Andy for your help here, and thanks for that link.
> > > > >
> > > > > I am trying to test Danny's patch as I want to use it for my HID CI,
> > > > > being an owner of a CP2112 device myself.
> > > > >
> > > > > The current setup is using out of the tree patches [2] which are
> > > > > implementing a platform i2c-hid support and some manual addition of a
> > > > > I2C-HID device on top of it. This works fine but gets busted every now
> > > > > and then when the tree sees a change that conflicts with these patches.
> > > > >
> > > > > So with Danny's series, I thought I could have an SSDT override to
> > > > > declare that very same device instead of patching my kernel before
> > > > > testing it.
> > > > >
> > > > > Of course, it gets tricky because I need to run that under qemu.
> > > > >
> > > > > I am currently stuck at the "sharing the firmware_node from usb with
> > > > > HID" step and I'd like to know if you could help me.
> > > > >
> > > > > On my laptop, if I plug the CP2112 (without using a USB hub), I can get:
> > > > >
> > > > > $> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/hid/devices/0003:10C4:EA90.0079 -> ../../../devices/pci0000:00/0000:00:14.0/usb2/2-9/2-9:1.0/0003:10C4:EA90.0079
> > > > > $> ls -l /sys/bus/usb/devices/2-9*/firmware_node
> > > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:03 /sys/bus/usb/devices/2-9:1.0/firmware_node -> ../../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > > > >   lrwxrwxrwx. 1 root root 0 Mar  2 17:02 /sys/bus/usb/devices/2-9/firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:15/device:16/device:25
> > > > >
> > > > > So AFAIU the USB device is properly assigned a firmware node. My dsdt
> > > > > also shows the "Device (RHUB)" and I guess everything is fine.
> > > >
> > > > Yes, so far so good.
> > > >
> > > > > However, playing with qemu is not so easy.
> > > > >
> > > > > I am running qemu with the following arguments (well, almost because I
> > > > > have a wrapper script on top of it and I also run the compiled kernel
> > > > > from the current tree):
> > > > >
> > > > > #> qemu-system-x86_64 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \
> > > > >                       -netdev user,id=hostnet0 \
> > > > >                       -device virtio-net-pci,netdev=hostnet0 \
> > > > >                       -m 4G \
> > > > >                       -enable-kvm \
> > > > >                       -cpu host \
> > > > >                       -device qemu-xhci -usb \
> > > > >                       -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
> > > > >                       -cdrom ~/Downloads/Fedora-Workstation-Live-x86_64-37-1.7.iso
> > > >
> > > > Side question, where can I get those blobs from (EDKII and Fedora Live CD)?
> > > > I'm using Debian unstable.
> > >
> > > You can install the ovmf package in debian[3], which should have a
> > > similar file.
> > > For the Fedora livecd -> https://getfedora.org/fr/workstation/download/
> > > but any other distribution with a recent enough kernel should show the
> > > same.
> > 
> > Thank you!
> > 
> > > > > And this is what I get:
> > > > >
> > > > > #> ls -l /sys/bus/hid/devices/0003:10C4:EA90.*
> > > > >   lrwxrwxrwx 1 root root 0 Mar  2 16:10 /sys/bus/hid/devices/0003:10C4:EA90.0001 -> ../../../devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/0003:10C4:EA90.0001
> > > > >
> > > > > #> ls -l /sys/bus/usb/devices/2-1*/firmware_node
> > > > >   ls: cannot access '/sys/bus/usb/devices/2-1*/firmware_node': No such file or directory
> > > > >
> > > > > Looking at the DSDT, I do not see any reference to the USB hub, so I
> > > > > wonder if the firmware_node needs to be populated first in the DSDT.
> > > >
> > > > So, where QEMU takes DSDT (ACPI tables in general) from? Can you patch that?
> > > > I believe that's the problem in qemu.
> > >
> > > That's a good question and it's one I am not sure I have the answer to.
> > > I would have assumed that the DSDT was in the OVMF firmware, but given
> > > that we can arbitrarily add command line arguments, I believe it
> > > probably just provides a baseline and then we are screwed. The OVMF bios
> > > is compiled only once, so I doubt there is any mechanism to
> > > enable/disable a component in the DSDT, or make it dynamically
> > > generated.
> > 
> > We have two ways of filling missing parts:
> > 1) update the original source of DSDT (firmware or bootloader,
> >    whichever provides that);
> > 2) adding an overlay.
> > 
> > The 2) works _if and only if_ there is *no* existing object in the tables.
> > In such cases, you can simply provide a *full* hierarchy. See an example of
> > PCI devices in the kernel documentation on how to do that. I believe something
> > similar can be done for USB.
> 
> Please find attached the dsdt from the Qemu VM.

Thank you!

> And after looking at it, your comments below, I think I am understanding
> what is happening (on the qemu side at least):
> 
> #> grep PCI0.S /sys/bus/acpi/devices/*/path
> /sys/bus/acpi/devices/device:02/path:\_SB_.PCI0.S00_
> /sys/bus/acpi/devices/device:03/path:\_SB_.PCI0.S10_
> /sys/bus/acpi/devices/device:04/path:\_SB_.PCI0.S18_
> /sys/bus/acpi/devices/device:05/path:\_SB_.PCI0.S20_
> /sys/bus/acpi/devices/device:06/path:\_SB_.PCI0.S28_
> /sys/bus/acpi/devices/device:07/path:\_SB_.PCI0.S30_
> /sys/bus/acpi/devices/device:08/path:\_SB_.PCI0.S38_
> /sys/bus/acpi/devices/device:09/path:\_SB_.PCI0.S40_
> /sys/bus/acpi/devices/device:0a/path:\_SB_.PCI0.S48_
> /sys/bus/acpi/devices/device:0b/path:\_SB_.PCI0.S50_
> /sys/bus/acpi/devices/device:0c/path:\_SB_.PCI0.S58_
> /sys/bus/acpi/devices/device:0d/path:\_SB_.PCI0.S60_
> /sys/bus/acpi/devices/device:0e/path:\_SB_.PCI0.S68_
> /sys/bus/acpi/devices/device:0f/path:\_SB_.PCI0.S70_
> /sys/bus/acpi/devices/device:10/path:\_SB_.PCI0.S78_
> /sys/bus/acpi/devices/device:11/path:\_SB_.PCI0.S80_
> /sys/bus/acpi/devices/device:12/path:\_SB_.PCI0.S88_
> /sys/bus/acpi/devices/device:13/path:\_SB_.PCI0.S90_
> /sys/bus/acpi/devices/device:14/path:\_SB_.PCI0.S98_
> /sys/bus/acpi/devices/device:15/path:\_SB_.PCI0.SA0_
> /sys/bus/acpi/devices/device:16/path:\_SB_.PCI0.SA8_
> /sys/bus/acpi/devices/device:17/path:\_SB_.PCI0.SB0_
> /sys/bus/acpi/devices/device:18/path:\_SB_.PCI0.SB8_
> /sys/bus/acpi/devices/device:19/path:\_SB_.PCI0.SC0_
> /sys/bus/acpi/devices/device:1a/path:\_SB_.PCI0.SC8_
> /sys/bus/acpi/devices/device:1b/path:\_SB_.PCI0.SD0_
> /sys/bus/acpi/devices/device:1c/path:\_SB_.PCI0.SD8_
> /sys/bus/acpi/devices/device:1d/path:\_SB_.PCI0.SE0_
> /sys/bus/acpi/devices/device:1e/path:\_SB_.PCI0.SE8_
> /sys/bus/acpi/devices/device:1f/path:\_SB_.PCI0.SF0_
> /sys/bus/acpi/devices/device:20/path:\_SB_.PCI0.SF8_

Ah, not much to get out of it.
Daniel Kaehn March 6, 2023, 7:40 p.m. UTC | #11
Hello,

Sorry about the radio silence from me --
I've been trying to get this working on my end as well.

I was able to get my passed-through USB device  on a qemu system to
have a firmware_node by
using the "Upgrading ACPI tables via initrd" kernel feature [1]. In
case this provides helpful information,
the below describes what I did.

This was using the default yocto core-image-minimal image and
qemu-system-x86_64.

I invoke qemu with the convenience "runqemu" script, as follows:
runqemu nographic qemuparams="
    -initrd ../acpi-overlay/instrumented_initrd
    -device 'usb-host,vendorid=0x10c4,productid=0xea90'
    -pflash ./build/tmp/work/core2-64-poky-linux/ovmf/edk2-stable202211-r0/ovmf/ovmf.fd
    "

Which invokes qemu with something like the following (sorry about the
long lines..):
qemu-system-x86_64 \
    -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:02 \
    -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
    -object rng-random,filename=/dev/urandom,id=rng0 \
    -device virtio-rng-pci,rng=rng0 \
    -drive file=/home/kaehnd/src/local/x86/build/tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64-20230306143252.rootfs.ext4,if=virtio,format=raw
\
    -usb -device usb-tablet -usb -device usb-kbd   -cpu IvyBridge \
    -machine q35,i8042=off -smp 4 -m 256 \
    -device 'usb-host,vendorid=0x10c4,productid=0xea90' \
    -serial mon:stdio -serial null -nographic \
    -kernel /home/kaehnd/src/local/x86/build/tmp/deploy/images/qemux86-64/bzImage
\
    -append 'root=/dev/vda
        rw  ip=192.168.7.2::192.168.7.1:255.255.255.0::eth0:off:8.8.8.8
        console=ttyS0 console=ttyS1 oprofile.timer=1
        tsc=reliable no_timer_check rcupdate.rcu_expedited=1 '


The sysfs path tree for the CP2112 was as follows:
#> ls -l  /sys/bus/hid/devices/0003:10C4:EA90.0003
lrwxrwxrwx    1 root     root             0 Mar  6 19:24
/sys/bus/hid/devices/0003:10C4:EA90.0003 ->
../../../devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0/0003:10C4:EA90.0003


Out of the box, firmware_node files existed only through what I assume
is the PCI bus:
/sys/devices/pci0000:00

It's ACPI path:
#> cat /sys/devices/pci0000:00/firmware_node/path
\_SB_.PCI0

Using the instructions at [1], I grabbed the dsdt table, and modified
it as follows.

Underneath the PCI0 node, I added the following ASL

```
Device (SE9)
{
    Name (_ADR, 0x001D0001) // _ADR: Address
    Device (RHUB)
    {
        Name (_ADR, Zero)
        Device (CP2) // the USB-hid & CP2112 shared node
        {
            Name (_ADR, One)
        }
    }
}
```

If I'm understanding correctly, this adds the SE9 device as function 1
of PCI device 0x1d,
then RHUB as the USB controller it provides, and finally, CP2 as the
USB device attached to port 1 of the controller.

With this as the loaded dsdt table, the USB device now has a firmware_node :)
#> cat /sys/bus/usb/devices/3-1:1.0/firmware_node/path
\_SB_.PCI0.SE9_.RHUB.CP2_

After applying my patches, the HID device also references this node:
#> cat /sys/bus/hid/devices/0003:10C4:EA90.0003/firmware_node/path
\_SB_.PCI0.SE9_.RHUB.CP2_

With this all said -- I noticed iasl prints this statement when trying
to create a node with a lowercase name:
"At least one lower case letter found in NameSeg, ASL is case
insensitive - converting to upper case (GPIO)"

I wonder if this suggests that adding a call to toupper() to
acpi_fwnode_get_named_child_node would be
an appropriate solution for the node name casing issue....

[1] https://www.kernel.org/doc/html/latest/admin-guide/acpi/initrd_table_override.html
Andy Shevchenko March 6, 2023, 8:36 p.m. UTC | #12
On Mon, Mar 06, 2023 at 01:40:16PM -0600, Daniel Kaehn wrote:

...

> Device (SE9)
> {
>     Name (_ADR, 0x001D0001) // _ADR: Address
>     Device (RHUB)
>     {
>         Name (_ADR, Zero)
>         Device (CP2) // the USB-hid & CP2112 shared node
>         {
>             Name (_ADR, One)
>         }
>     }
> }
> 
> If I'm understanding correctly, this adds the SE9 device as function 1
> of PCI device 0x1d,

To be precise this does not add the device. It adds a description of
the companion device in case the real one will appear on the PCI bus
with BDF 00:1d.1.

> then RHUB as the USB controller it provides, and finally, CP2 as the
> USB device attached to port 1 of the controller.
> 
> With this as the loaded dsdt table, the USB device now has a firmware_node :)
> #> cat /sys/bus/usb/devices/3-1:1.0/firmware_node/path
> \_SB_.PCI0.SE9_.RHUB.CP2_
> 
> After applying my patches, the HID device also references this node:
> #> cat /sys/bus/hid/devices/0003:10C4:EA90.0003/firmware_node/path
> \_SB_.PCI0.SE9_.RHUB.CP2_
> 
> With this all said -- I noticed iasl prints this statement when trying
> to create a node with a lowercase name:
> "At least one lower case letter found in NameSeg, ASL is case
> insensitive - converting to upper case (GPIO)"

Yes, because it should be in the upper case.

> I wonder if this suggests that adding a call to toupper() to
> acpi_fwnode_get_named_child_node would be
> an appropriate solution for the node name casing issue....

I dunno. You need to ask in the linux-acpi@ mailing list.
To me this is corner case that can't be easily solved
(because two different specifications treat it differently.

You also need to ask DT people about capital letters there.
And my guts tell me that it's probably also carved in the spec
as "must be lower case" or alike.
Benjamin Tissoires March 7, 2023, 1:17 p.m. UTC | #13
On Mar 06 2023, Andy Shevchenko wrote:
> On Mon, Mar 06, 2023 at 01:40:16PM -0600, Daniel Kaehn wrote:
> 
> ...
> 
> > Device (SE9)
> > {
> >     Name (_ADR, 0x001D0001) // _ADR: Address
> >     Device (RHUB)
> >     {
> >         Name (_ADR, Zero)
> >         Device (CP2) // the USB-hid & CP2112 shared node
> >         {
> >             Name (_ADR, One)
> >         }
> >     }
> > }
> > 
> > If I'm understanding correctly, this adds the SE9 device as function 1
> > of PCI device 0x1d,
> 
> To be precise this does not add the device. It adds a description of
> the companion device in case the real one will appear on the PCI bus
> with BDF 00:1d.1.
> 
> > then RHUB as the USB controller it provides, and finally, CP2 as the
> > USB device attached to port 1 of the controller.
> > 
> > With this as the loaded dsdt table, the USB device now has a firmware_node :)
> > #> cat /sys/bus/usb/devices/3-1:1.0/firmware_node/path
> > \_SB_.PCI0.SE9_.RHUB.CP2_
> > 
> > After applying my patches, the HID device also references this node:
> > #> cat /sys/bus/hid/devices/0003:10C4:EA90.0003/firmware_node/path
> > \_SB_.PCI0.SE9_.RHUB.CP2_
> > 

Great! Thanks a lot for that. Turns out that with both of your inputs I
can also do the same, but without the need for OVMF and DSDT patching,
with just an SSDT override.

Turns out that the override documentation [1] mentions "This option
allows loading of user defined SSDTs from initrd and it is useful when
the system does not support EFI or ..."

FWIW, I am attaching my full DSDT override in case it is valuable:
(on my system, the default USB controller (non-xhc) is at PCI address
1.2, which explains the slight difference). It can be loaded in the same
way you are overriding the full DSDT, but with just that compilation
output:

---
DefinitionBlock ("cp2112.aml", "SSDT", 5, "", "CP2112", 1)
{
  External (_SB_.PCI0, DeviceObj)

  Scope (\_SB_.PCI0)
  {
    Device (USB0)
    {
      Name (_ADR, 0x00010002) // _ADR: Address
      Device (RHUB)
      {
        Name (_ADR, Zero)
        Device (CP21) // the USB-hid & CP2112 shared node
        {
          Name (_ADR, One)
          Device (I2C)
          {
            Name (_ADR, Zero)
            Name (_STA, 0x0F)
          }

          Device (GPIO)
          {
            Name (_ADR, One)
            Name (_STA, 0x0F)
          }
        }
      }
    }
  }

  Scope (\_SB_.PCI0.USB0.RHUB.CP21.I2C)
  {
    Device (TPD0)
    {
      Name (_HID, "RMI40001")
      Name (_CID, "PNP0C50")
      Name (_STA, 0x0F)

      Name (SBFB, ResourceTemplate ()
      {
          I2cSerialBusV2 (0x00c, ControllerInitiated, 100000,
              AddressingMode7Bit, "\\_SB_.PCI0.USB0.RHUB.CP21.I2C",
              0x00, ResourceConsumer,, Exclusive,
              )
      })
      Name (SBFG, ResourceTemplate ()
      {
          GpioInt (Level, ActiveLow, Exclusive, PullDefault, 0x0000,
              "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", 0x00, ResourceConsumer, ,
              )
              {   // Pin list
                  0x0002
              }
      })
      Method(_CRS, 0x0, NotSerialized)
      {
        Return (ConcatenateResTemplate (SBFB, SBFG))
      }

      Method(_DSM, 0x4, Serialized)
      {
        // DSM UUID
        switch (ToBuffer (Arg0))
        {
          // ACPI DSM UUID for HIDI2C
          case (ToUUID ("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
          {
              // DSM Function
              switch (ToInteger (Arg2))
              {
                  // Function 0: Query function, return based on revision
                  case(0)
                  {
                      // DSM Revision
                      switch (ToInteger (Arg1))
                      {
                          // Revision 1: Function 1 supported
                          case (1)
                          {
                              Return (Buffer (One) { 0x03 })
                          }

                          default
                          {
                              // Revision 2+: no functions supported
                              Return (Buffer (One) { 0x00 })
                          }
                      }
                  }

                  // Function 1 : HID Function
                  case(1)
                  {
                      // HID Descriptor Address
                      Return (0x0020)
                  }

                  default
                  {
                      // Functions 2+: not supported
                      Return (Buffer (One) { 0x00 })
                  }
              }
          }

          default
          {
              // No other GUIDs supported
              Return (Buffer (One) { 0x00 })
          }
        }
      }
    }
  }
}
---

This almost works. Almost because the I2C device is correctly created,
but I have an issue with the GpioInt call which is not properly set by
the kernel and which returns -EDEFER. /o\ 

> > With this all said -- I noticed iasl prints this statement when trying
> > to create a node with a lowercase name:
> > "At least one lower case letter found in NameSeg, ASL is case
> > insensitive - converting to upper case (GPIO)"
> 
> Yes, because it should be in the upper case.
> 
> > I wonder if this suggests that adding a call to toupper() to
> > acpi_fwnode_get_named_child_node would be
> > an appropriate solution for the node name casing issue....
> 
> I dunno. You need to ask in the linux-acpi@ mailing list.
> To me this is corner case that can't be easily solved
> (because two different specifications treat it differently.
> 
> You also need to ask DT people about capital letters there.
> And my guts tell me that it's probably also carved in the spec
> as "must be lower case" or alike.

FWIW while trying to enable this, at some point I named the I2C and the
GPIO entries "I2C0" and "GPI0" (with the number '0', not the letter
'o'), and it was not working as you would expect.

It is commonly accepted in the ACPI world that the names do not carry
meaning AFAICT, and so I think I agree with Andy's initial comment
regarding using indexes, not names to also fetch the I2C and GPIO nodes.
You can probably have a fallback mechanism for when "i2c" is not
present, or simply check if you are in DT or not and use the names only
if we are in DT.

Thanks a lot to both of you, this will be tremendously helpful to me.

Cheers,
Benjamin

[1] https://www.kernel.org/doc/html/latest/admin-guide/acpi/ssdt-overlays.html#loading-acpi-ssdts-from-initrd
Daniel Kaehn March 7, 2023, 1:53 p.m. UTC | #14
On Tue, Mar 7, 2023 at 7:17 AM Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
>
> On Mar 06 2023, Andy Shevchenko wrote:
> > On Mon, Mar 06, 2023 at 01:40:16PM -0600, Daniel Kaehn wrote:
> >
> > ...
> >
> > > Device (SE9)
> > > {
> > >     Name (_ADR, 0x001D0001) // _ADR: Address
> > >     Device (RHUB)
> > >     {
> > >         Name (_ADR, Zero)
> > >         Device (CP2) // the USB-hid & CP2112 shared node
> > >         {
> > >             Name (_ADR, One)
> > >         }
> > >     }
> > > }
> > >
> > > If I'm understanding correctly, this adds the SE9 device as function 1
> > > of PCI device 0x1d,
> >
> > To be precise this does not add the device. It adds a description of
> > the companion device in case the real one will appear on the PCI bus
> > with BDF 00:1d.1.
> >
> > > then RHUB as the USB controller it provides, and finally, CP2 as the
> > > USB device attached to port 1 of the controller.
> > >
> > > With this as the loaded dsdt table, the USB device now has a firmware_node :)
> > > #> cat /sys/bus/usb/devices/3-1:1.0/firmware_node/path
> > > \_SB_.PCI0.SE9_.RHUB.CP2_
> > >
> > > After applying my patches, the HID device also references this node:
> > > #> cat /sys/bus/hid/devices/0003:10C4:EA90.0003/firmware_node/path
> > > \_SB_.PCI0.SE9_.RHUB.CP2_
> > >
>
> Great! Thanks a lot for that. Turns out that with both of your inputs I
> can also do the same, but without the need for OVMF and DSDT patching,
> with just an SSDT override.
>
Ah, interesting.. I tried the SSDT override route initially, but tried
applying it
through EFI variables and through configfs, neither of which worked since
they appeared to be applied after the relevant drivers were already loaded
(at least that was my suspicion). I wonder if loading the overlay through the
initramfs was the key.

> Turns out that the override documentation [1] mentions "This option
> allows loading of user defined SSDTs from initrd and it is useful when
> the system does not support EFI or ..."
>
> FWIW, I am attaching my full DSDT override in case it is valuable:
> (on my system, the default USB controller (non-xhc) is at PCI address
> 1.2, which explains the slight difference). It can be loaded in the same
> way you are overriding the full DSDT, but with just that compilation
> output:
>
> ---
> DefinitionBlock ("cp2112.aml", "SSDT", 5, "", "CP2112", 1)
> {
>   External (_SB_.PCI0, DeviceObj)
>
>   Scope (\_SB_.PCI0)
>   {
>     Device (USB0)
>     {
>       Name (_ADR, 0x00010002) // _ADR: Address
>       Device (RHUB)
>       {
>         Name (_ADR, Zero)
>         Device (CP21) // the USB-hid & CP2112 shared node
>         {
>           Name (_ADR, One)
>           Device (I2C)
>           {
>             Name (_ADR, Zero)
>             Name (_STA, 0x0F)
>           }
>
>           Device (GPIO)
>           {
>             Name (_ADR, One)
>             Name (_STA, 0x0F)
>           }
>         }
>       }
>     }
>   }

To get this to work -- I assume you had to change the driver to look
for uppercase
"GPIO" and "I2C", or some similar change?


>
>   Scope (\_SB_.PCI0.USB0.RHUB.CP21.I2C)
>   {
>     Device (TPD0)
>     {
>       Name (_HID, "RMI40001")
>       Name (_CID, "PNP0C50")
>       Name (_STA, 0x0F)
>
>       Name (SBFB, ResourceTemplate ()
>       {
>           I2cSerialBusV2 (0x00c, ControllerInitiated, 100000,
>               AddressingMode7Bit, "\\_SB_.PCI0.USB0.RHUB.CP21.I2C",
>               0x00, ResourceConsumer,, Exclusive,
>               )
>       })
>       Name (SBFG, ResourceTemplate ()
>       {
>           GpioInt (Level, ActiveLow, Exclusive, PullDefault, 0x0000,
>               "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", 0x00, ResourceConsumer, ,
>               )
>               {   // Pin list
>                   0x0002
>               }
>       })
>       Method(_CRS, 0x0, NotSerialized)
>       {
>         Return (ConcatenateResTemplate (SBFB, SBFG))
>       }
>
>       Method(_DSM, 0x4, Serialized)
>       {
>         // DSM UUID
>         switch (ToBuffer (Arg0))
>         {
>           // ACPI DSM UUID for HIDI2C
>           case (ToUUID ("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
>           {
>               // DSM Function
>               switch (ToInteger (Arg2))
>               {
>                   // Function 0: Query function, return based on revision
>                   case(0)
>                   {
>                       // DSM Revision
>                       switch (ToInteger (Arg1))
>                       {
>                           // Revision 1: Function 1 supported
>                           case (1)
>                           {
>                               Return (Buffer (One) { 0x03 })
>                           }
>
>                           default
>                           {
>                               // Revision 2+: no functions supported
>                               Return (Buffer (One) { 0x00 })
>                           }
>                       }
>                   }
>
>                   // Function 1 : HID Function
>                   case(1)
>                   {
>                       // HID Descriptor Address
>                       Return (0x0020)
>                   }
>
>                   default
>                   {
>                       // Functions 2+: not supported
>                       Return (Buffer (One) { 0x00 })
>                   }
>               }
>           }
>
>           default
>           {
>               // No other GUIDs supported
>               Return (Buffer (One) { 0x00 })
>           }
>         }
>       }
>     }
>   }
> }
> ---
>
> This almost works. Almost because the I2C device is correctly created,
> but I have an issue with the GpioInt call which is not properly set by
> the kernel and which returns -EDEFER. /o\
>

Ahh, yep, I've had this issue as well -- I suspect the issue you're
having is that the
CP2112 driver initializes the i2c controller before the gpiochip, and
if any i2c devices
on the bus depend on the CP2112's gpio, the probe will never succeed!
I have made
and been testing with a patch to fix this, but since it was midway
through submitting
this series, thought it might be bad practice to "tack on" additional
patches to a patchset
mid-review (since it only causes an issue in some (admittedly fairly
common) use-cases)
so I was going to send it as an individual patch once (if) these were applied.

If you think that would be necessary to include for these to merge,
I'd be happy to append
it to this review. I also have another patch which adds i2c bus
recovery to the driver, but
that seems independent enough that it should be sent on its own.

> > > With this all said -- I noticed iasl prints this statement when trying
> > > to create a node with a lowercase name:
> > > "At least one lower case letter found in NameSeg, ASL is case
> > > insensitive - converting to upper case (GPIO)"
> >
> > Yes, because it should be in the upper case.
> >
> > > I wonder if this suggests that adding a call to toupper() to
> > > acpi_fwnode_get_named_child_node would be
> > > an appropriate solution for the node name casing issue....
> >
> > I dunno. You need to ask in the linux-acpi@ mailing list.
> > To me this is corner case that can't be easily solved
> > (because two different specifications treat it differently.
> >
> > You also need to ask DT people about capital letters there.
> > And my guts tell me that it's probably also carved in the spec
> > as "must be lower case" or alike.
>
> FWIW while trying to enable this, at some point I named the I2C and the
> GPIO entries "I2C0" and "GPI0" (with the number '0', not the letter
> 'o'), and it was not working as you would expect.
>
> It is commonly accepted in the ACPI world that the names do not carry
> meaning AFAICT, and so I think I agree with Andy's initial comment
> regarding using indexes, not names to also fetch the I2C and GPIO nodes.
> You can probably have a fallback mechanism for when "i2c" is not
> present, or simply check if you are in DT or not and use the names only
> if we are in DT.

More and more, after actually seeing and working with ACPI, I suspect that
you both are right. Maybe (hopefully) though, there is some unified way that can
be made to do this, so that individual drivers won't have to directly code for /
be aware of the differences in the firmware languages (at least, that seemed
to be the intent of the fw_node/device api in the first place). Maybe a
`device_get_child_by_name_or_index` (terribly long name) sort of function
might fill in that gap?

I plan to send an email asking this question more generically to ACPI & DT folks
as Andy suggested, so hopefully there will be some ideas.

>
> Thanks a lot to both of you, this will be tremendously helpful to me.
>
> Cheers,
> Benjamin
>
Thanks for testing this out! Glad that ACPI support ended up being worked into
this after all :)
Andy Shevchenko March 7, 2023, 6:15 p.m. UTC | #15
On Tue, Mar 07, 2023 at 07:53:20AM -0600, Daniel Kaehn wrote:
> On Tue, Mar 7, 2023 at 7:17 AM Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:

...

> More and more, after actually seeing and working with ACPI, I suspect that
> you both are right. Maybe (hopefully) though, there is some unified way that can
> be made to do this, so that individual drivers won't have to directly code for /
> be aware of the differences in the firmware languages (at least, that seemed
> to be the intent of the fw_node/device api in the first place). Maybe a
> `device_get_child_by_name_or_index` (terribly long name) sort of function
> might fill in that gap?

Look also at the solution I proposed in response to Benjamin in my previous
email.
Daniel Kaehn March 7, 2023, 7:57 p.m. UTC | #16
On Tue, Mar 7, 2023 at 12:14 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, Mar 07, 2023 at 02:17:06PM +0100, Benjamin Tissoires wrote:
> > On Mar 06 2023, Andy Shevchenko wrote:
> > It is commonly accepted in the ACPI world that the names do not carry
> > meaning AFAICT, and so I think I agree with Andy's initial comment
> > regarding using indexes, not names to also fetch the I2C and GPIO nodes.
> > You can probably have a fallback mechanism for when "i2c" is not
> > present, or simply check if you are in DT or not and use the names only
> > if we are in DT.
>
> The solution is to provide in the main node the list of cell names, that way
> you will always know the indices:
>
>   Device (DEV) {
>           _DSD
>                   "cell-names" { "i2c", "gpio" } // index of the name is the
>                                                  // index of the cell
>
>         Device (I2C0) {
>         }
>
>         Device (GPI0) {
>         }
>   }
>
> Problem solved.
>

Just to make sure I'm understanding you correctly:

Are you proposing that specifically this driver directly reads "cell-names"
from the ACPI DSD to implement this indexing? Or are you proposing a
kernel-wide mechanism of "overriding" a fwnode name with ACPI?
(assuming this doesn't exist already, and I'm not just missing it in
the kernel source)

Or are you proposing something else entirely?
(apologies if this should be obvious -- throwing up the ACPI newbie
card again here :) )

In any case, would this be something I should post to the email chain
with DT and ACPI
folks for opinions before I start to implement it?

Thanks,

Danny Kaehn
Daniel Kaehn March 8, 2023, 3:37 p.m. UTC | #17
On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
>
> On Mar 07 2023, Andy Shevchenko wrote:
> > On Tue, Mar 07, 2023 at 03:48:52PM +0100, Benjamin Tissoires wrote:
> > > On Mar 07 2023, Daniel Kaehn wrote:
> >
> > ...
> >
> > > So I can see that the device gets probed, and that all ACPI resources
> > > are tried to get the IRQ.
> > > Right now, I see that it's attempting to bind to the acpi resource in
> > > acpi_dev_resource_interrupt() (in file drivers/acpi/resources.c), but
> > > instead of having a ACPI_RESOURCE_TYPE_EXTENDED_IRQ I only get a
> > > ACPI_RESOURCE_TYPE_GPIO for the GpioInt() definition in the _CRS method.
> > >
> > > So I am missing the proper transition from GpioInt to IRQ in the acpi.
> >
> > I'm not sure I understand what this means.
> >
> > The Linux kernel takes either Interrupt() resource (which is
> > IOxAPIC / GIC / etc) or GpioInt() (which is GPIO based).
> >
> > In both cases I²C framework submits this into client's IRQ field.
> >
>
> I finally managed to get past the retrieval of the GpioInt.
>
> Turns out that the function acpi_get_gpiod() matches on the parent of
> the gpio_chip (gc->parent), which means that, with the current code and
> my SSDT, it matches on the HID CP2112 ACPI node, not the GPIO one.
>
> For reference (with lots of boiler plate removed):
>
>         Device (CP21) { // the USB-hid & CP2112 shared node
>          Device (GPIO) {
>             Name (_ADR, One)
>             Name (_STA, 0x0F)
>
>             Name (_DSD, Package () {
>               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>               Package () {
>                 Package () { "gpio-line-names", Package () {
>                             "",
>                             "",
>                             "irq-rmi4",
>                             "",
>                             "power", // set to 1 with gpio-hog above
>                             "",
>                             "",
>                             "",
>                             ""}},
>               }
>             })
>          }
>
>   Scope (\_SB_.PCI0.USB0.RHUB.CP21.I2C)
>   {
>     Device (TPD0)
>     {
>       Name (_HID, "RMI40001")
>       Name (_CID, "PNP0C50")
>       Name (_STA, 0x0F)
>
>       Name (SBFB, ResourceTemplate ()
>       {
>           I2cSerialBusV2 (0x00c, ControllerInitiated, 100000,
>               AddressingMode7Bit, "\\_SB_.PCI0.USB0.RHUB.CP21.I2C",
>               0x00, ResourceConsumer,, Exclusive,
>               )
>       })
>       Name (SBFG, ResourceTemplate ()
>       {
>           GpioInt (Level, ActiveLow, Exclusive, PullDefault, 0x0000,
>               "\\_SB_.PCI0.USB0.RHUB.CP21", 0x00, ResourceConsumer, ,
>               )
>               {   // Pin list
>                   0x0002
>               }
>       })
> ---
>
> But if I refer "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", the IRQ is never assigned.
> With the parent (CP21), it works.
>
> So I wonder if the cp2112 driver is correctly assigning the gc->parent
> field.


Did you make a change to the CP2112 driver patch to look for uppercase
"I2C" and "GPIO"?
Otherwise, it won't assign those child nodes appropriately, and the
gpiochip code will use
the parent node by default if the gpiochip's fwnode isn't assigned (I believe).

If that was indeed your problem all along (and I'm not missing
something else), sorry about that --
I made a comment above, but didn't add much spacing around it to make
it stand out (since I noticed you didn't reply to that part in your response)

> To get this to work -- I assume you had to change the driver to look
> for uppercase
> "GPIO" and "I2C", or some similar change?

Thanks,

Danny Kaehn
Benjamin Tissoires March 8, 2023, 3:55 p.m. UTC | #18
On Mar 08 2023, Daniel Kaehn wrote:
> On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
> > But if I refer "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", the IRQ is never assigned.
> > With the parent (CP21), it works.
> >
> > So I wonder if the cp2112 driver is correctly assigning the gc->parent
> > field.
> 
> 
> Did you make a change to the CP2112 driver patch to look for uppercase
> "I2C" and "GPIO"?

yes, sorry I should have mentioned it. This is the only modification I
have compared to the upstream kernel plus your patch series.

> Otherwise, it won't assign those child nodes appropriately, and the
> gpiochip code will use
> the parent node by default if the gpiochip's fwnode isn't assigned (I believe).

I don't think it's a fwnode issue, but a problem with the assignment of
the parent of the gc:
---
dev->gc.parent = &hdev->dev;
---

Because the function acpi_gpiochip_find() in drivers/gpio/gpiolib-acpi.c
compares the acpi handle returned by fetching the ACPI path
("\\_SB_.PCI0.USB0.RHUB.CP21.GPIO") and the one of gc->parent, which in
the hid-cp2112 case is the HID device itself.

> 
> If that was indeed your problem all along (and I'm not missing
> something else), sorry about that --
> I made a comment above, but didn't add much spacing around it to make
> it stand out (since I noticed you didn't reply to that part in your response)

Yeah, sorry I should have been explicit about this.

For reference, I am appending the full SSDT override which works.

Even if you don't have an i2c-hid device connected, this should at
least call the probe function in i2c-hid-core.c, which is a proof that
the ACPI binding is properly done (the first SMBus read will fail with a
timeout)

Also, I played around with the _DSD that Andy was mentioning (and some
others), hopefully this will help you getting the mapping from the
"cell-names" to the fwnode child index faster.

Cheers,
Benjamin

---
DefinitionBlock ("cp2112.aml", "SSDT", 5, "", "CP2112", 1)
{
  External (_SB_.PCI0, DeviceObj)

  Scope (\_SB_.PCI0)
  {
    Device (USB0)
    {
      Name (_ADR, 0x00010002) // _ADR: Address
      Device (RHUB)
      {
        Name (_ADR, Zero)
        Device (CP21) // the USB-hid & CP2112 shared node
        {
          Name (_ADR, One)
					Name (_DSD, Package ()
					{
						ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
						Package () {
							Package () { "cell-names", Package () {
									"i2c",
									"gpio",
								}
							}
						}
					})

          Device (I2C)
          {
            Name (_ADR, Zero)
            Name (_STA, 0x0F)
          }

          Device (GPIO)
          {
            Name (_ADR, One)
            Name (_STA, 0x0F)

            Name (_DSD, Package () {
              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
              Package () {
                Package () { "gpio-hog", 1 },
                Package () { "gpios", Package () { 4, 0 } },
                Package () { "output-high", 1 },
                Package () { "line-name", "gpio4-pullup" },
              },
              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
              Package () {
                Package () { "gpio-line-names", Package () {
                            "",
                            "",
                            "irq-rmi4",
                            "",
                            "power", // set to 1 with gpio-hog above
                            "",
                            "",
                            "",
                            ""}},
              }
            })
          }
        }
      }
    }
  }

  Scope (\_SB_.PCI0.USB0.RHUB.CP21.I2C)
  {
    Device (TPD0)
    {
      Name (_HID, "RMI40001")
      Name (_CID, "PNP0C50")
      Name (_STA, 0x0F)

      Name (SBFB, ResourceTemplate ()
      {
          I2cSerialBusV2 (0x2c, ControllerInitiated, 100000,
              AddressingMode7Bit, "\\_SB_.PCI0.USB0.RHUB.CP21.I2C",
              0x00, ResourceConsumer,, Exclusive,
              )
      })
      Name (SBFG, ResourceTemplate ()
      {
          GpioInt (Level, ActiveLow, Exclusive, PullDefault, 0x0000,
              "\\_SB_.PCI0.USB0.RHUB.CP21", 0x00, ResourceConsumer, ,
              )
              {   // Pin list
                  0x0002
              }
      })
      Name (_DSD, Package ()
      {
          ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
          Package ()
          {
              Package () { "irq-gpios", Package () { ^TPD0, 1, 0, 0 } },
          }
      })
      Method(_CRS, 0x0, NotSerialized)
      {
        Return (ConcatenateResTemplate (SBFG, SBFB))
      }

      Method(_DSM, 0x4, Serialized)
      {
        // DSM UUID
        switch (ToBuffer (Arg0))
        {
          // ACPI DSM UUID for HIDI2C
          case (ToUUID ("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
          {
              // DSM Function
              switch (ToInteger (Arg2))
              {
                  // Function 0: Query function, return based on revision
                  case(0)
                  {
                      // DSM Revision
                      switch (ToInteger (Arg1))
                      {
                          // Revision 1: Function 1 supported
                          case (1)
                          {
                              Return (Buffer (One) { 0x03 })
                          }

                          default
                          {
                              // Revision 2+: no functions supported
                              Return (Buffer (One) { 0x00 })
                          }
                      }
                  }

                  // Function 1 : HID Function
                  case(1)
                  {
                      // HID Descriptor Address
                      Return (0x0020)
                  }

                  default
                  {
                      // Functions 2+: not supported
                      Return (Buffer (One) { 0x00 })
                  }
              }
          }

          default
          {
              // No other GUIDs supported
              Return (Buffer (One) { 0x00 })
          }
        }
      }
    }
  }
}
---
Andy Shevchenko March 8, 2023, 4:20 p.m. UTC | #19
On Wed, Mar 08, 2023 at 04:26:11PM +0100, Benjamin Tissoires wrote:
> On Mar 07 2023, Andy Shevchenko wrote:
> > On Tue, Mar 07, 2023 at 03:48:52PM +0100, Benjamin Tissoires wrote:
> > > On Mar 07 2023, Daniel Kaehn wrote:

...

> So I wonder if the cp2112 driver is correctly assigning the gc->parent
> field.

Seems it needs custom fwnode

	gc->fwnode = child_of_cp_which_is_gpio;
Andy Shevchenko March 8, 2023, 4:30 p.m. UTC | #20
On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> On Mar 08 2023, Daniel Kaehn wrote:
> > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > <benjamin.tissoires@redhat.com> wrote:
> > > But if I refer "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", the IRQ is never assigned.
> > > With the parent (CP21), it works.
> > >
> > > So I wonder if the cp2112 driver is correctly assigning the gc->parent
> > > field.

> > Did you make a change to the CP2112 driver patch to look for uppercase
> > "I2C" and "GPIO"?
> 
> yes, sorry I should have mentioned it. This is the only modification I
> have compared to the upstream kernel plus your patch series.
> 
> > Otherwise, it won't assign those child nodes appropriately, and the
> > gpiochip code will use
> > the parent node by default if the gpiochip's fwnode isn't assigned (I believe).
> 
> I don't think it's a fwnode issue, but a problem with the assignment of
> the parent of the gc:
> ---
> dev->gc.parent = &hdev->dev;
> ---

I don't think so. The parent should point to the _physical_ device, which is
CP2112, which is correct in my opinion.

> Because the function acpi_gpiochip_find() in drivers/gpio/gpiolib-acpi.c
> compares the acpi handle returned by fetching the ACPI path
> ("\\_SB_.PCI0.USB0.RHUB.CP21.GPIO") and the one of gc->parent, which in
> the hid-cp2112 case is the HID device itself.

We have specifically gc->fwnode for cases like this.

...

>         Device (CP21) // the USB-hid & CP2112 shared node
>         {
>           Name (_ADR, One)
> 		Name (_DSD, Package ()
> 		{
> 			ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> 			Package () {
> 				Package () { "cell-names", Package () { "i2c", "gpio" }
> 			}

Yeah, looking at this, I think it still fragile. First of all, either this is
missing, or simply wrong. We would need to access indices. ACPI _ADR is in the
specification. As much as with PCI it may be considered reliable.

So, that said, forget about it, and simply use _ADR as indicator of the node.
See how MFD (in the Linux kernel) cares about this. Ex. Diolan DLN-2 driver.

> 		})
> 
>           Device (I2C)
>           {
>             Name (_ADR, Zero)
>             Name (_STA, 0x0F)
>           }
> 
>           Device (GPIO)
>           {
>             Name (_ADR, One)
>             Name (_STA, 0x0F)
> 
>             Name (_DSD, Package () {
>               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>               Package () {
>                 Package () { "gpio-hog", 1 },
>                 Package () { "gpios", Package () { 4, 0 } },
>                 Package () { "output-high", 1 },
>                 Package () { "line-name", "gpio4-pullup" },
>               },
>               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>               Package () {
>                 Package () { "gpio-line-names", Package () {
>                             "",
>                             "",
>                             "irq-rmi4",
>                             "",
>                             "power", // set to 1 with gpio-hog above
>                             "",
>                             "",
>                             "",
>                             ""}},
>               }
>             })
>           }
>         }
Andy Shevchenko March 8, 2023, 4:36 p.m. UTC | #21
On Wed, Mar 08, 2023 at 06:30:46PM +0200, Andy Shevchenko wrote:
> On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> > On Mar 08 2023, Daniel Kaehn wrote:
> > > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > > <benjamin.tissoires@redhat.com> wrote:

...

> > 			ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> > 			Package () {
> > 				Package () { "cell-names", Package () { "i2c", "gpio" }
> > 			}
> 
> Yeah, looking at this, I think it still fragile. First of all, either this is
> missing, or simply wrong. We would need to access indices. ACPI _ADR is in the
> specification. As much as with PCI it may be considered reliable.
> 
> So, that said, forget about it, and simply use _ADR as indicator of the node.
> See how MFD (in the Linux kernel) cares about this. Ex. Diolan DLN-2 driver.

And that said, maybe CP2112 should simply re-use what MFD _already_ provides?
Daniel Kaehn March 8, 2023, 6:32 p.m. UTC | #22
On Wed, Mar 8, 2023 at 10:36 AM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Mar 08, 2023 at 06:30:46PM +0200, Andy Shevchenko wrote:
> > On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> > > On Mar 08 2023, Daniel Kaehn wrote:
> > > > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > > > <benjamin.tissoires@redhat.com> wrote:
>
> ...
>
> > >                     ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> > >                     Package () {
> > >                             Package () { "cell-names", Package () { "i2c", "gpio" }
> > >                     }
> >
> > Yeah, looking at this, I think it still fragile. First of all, either this is
> > missing, or simply wrong. We would need to access indices. ACPI _ADR is in the
> > specification. As much as with PCI it may be considered reliable.
> >
> > So, that said, forget about it, and simply use _ADR as indicator of the node.
> > See how MFD (in the Linux kernel) cares about this. Ex. Diolan DLN-2 driver.
>
> And that said, maybe CP2112 should simply re-use what MFD _already_ provides?

Great point -- it definitely seems like this driver belongs in the mfd
directory to begin with.

It seems like aside from rewriting the CP2112 driver into an mfd
driver and two platform drivers,
my route forward for now would be to just do something like this (not
yet tested):

+ struct acpi_device *adev = ACPI_COMPANION(&hdev->dev);
+ if (adev)
+    ACPI_COMPANION_SET(&dev->adap.dev, acpi_find_child_device(adev,
0x0, false));
+ else
+     device_set_node(&dev->adap.dev,
device_get_named_child_node(&hdev->dev, "i2c"));

(and the same for the gpiochip)

The follow-up question -- does there exist something analogous to DT
bindings for ACPI devices,
other than the ACPI spec itself, where this should be documented? Or
will consumers truly have to
read the driver code to determine that _ADR 0 is I2C and _ADR 1 is
GPIO? (I haven't seen anything
in my search so far -- but knowing that it truly doesn't exist would
make me respect people developing
embedded ACPI-based systems all the more!)

Thanks for your patience in working through all of this, especially
considering how long of an email
chain this has become!

Thanks,

Danny Kaehn
Benjamin Tissoires March 9, 2023, 9:38 a.m. UTC | #23
On Mar 08 2023, Andy Shevchenko wrote:
> On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> > On Mar 08 2023, Daniel Kaehn wrote:
> > > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > > <benjamin.tissoires@redhat.com> wrote:
> > > > But if I refer "\\_SB_.PCI0.USB0.RHUB.CP21.GPIO", the IRQ is never assigned.
> > > > With the parent (CP21), it works.
> > > >
> > > > So I wonder if the cp2112 driver is correctly assigning the gc->parent
> > > > field.
> 
> > > Did you make a change to the CP2112 driver patch to look for uppercase
> > > "I2C" and "GPIO"?
> > 
> > yes, sorry I should have mentioned it. This is the only modification I
> > have compared to the upstream kernel plus your patch series.
> > 
> > > Otherwise, it won't assign those child nodes appropriately, and the
> > > gpiochip code will use
> > > the parent node by default if the gpiochip's fwnode isn't assigned (I believe).
> > 
> > I don't think it's a fwnode issue, but a problem with the assignment of
> > the parent of the gc:
> > ---
> > dev->gc.parent = &hdev->dev;
> > ---
> 
> I don't think so. The parent should point to the _physical_ device, which is
> CP2112, which is correct in my opinion.
> 

Right. I tend to agree, and then the problem seems to be relying in
gpiolib-acpi.c

> > Because the function acpi_gpiochip_find() in drivers/gpio/gpiolib-acpi.c
> > compares the acpi handle returned by fetching the ACPI path
> > ("\\_SB_.PCI0.USB0.RHUB.CP21.GPIO") and the one of gc->parent, which in
> > the hid-cp2112 case is the HID device itself.
> 
> We have specifically gc->fwnode for cases like this.

Looks like gpiolib-acpi.c doesn't care about fwnode at all.

if I do the following:

---
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index d8a421ce26a8..5aebc266426b 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -126,7 +126,7 @@ static bool acpi_gpio_deferred_req_irqs_done;
 
 static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
 {
-       return gc->parent && device_match_acpi_handle(gc->parent, data);
+       return ACPI_HANDLE_FWNODE(gc->fwnode) == data;
 }
 
 /**
---

I can now directly reference the GPIO ACPI node in my GpioInt()
declaration. And AFAICT this should be safe to do because gpiolib ensure
that gc->fwnode is set, using the one from the parent if it is not set
previously.

I need to check if this works with my icelake laptop, and if so I'll
send it to the list.

The reason the intel gpios are working (the only one I checked) is
because the \\SB.GPI0 node refers to the pinctrl controller (driver
pinctrl-icelake.c in my case, which then creates a subdevice for
handling the gpio).

> 
> ...
> 

Cheers,
Benjamin
Andy Shevchenko March 9, 2023, 11:43 a.m. UTC | #24
On Wed, Mar 08, 2023 at 12:32:07PM -0600, Daniel Kaehn wrote:
> On Wed, Mar 8, 2023 at 10:36 AM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Wed, Mar 08, 2023 at 06:30:46PM +0200, Andy Shevchenko wrote:
> > > On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> > > > On Mar 08 2023, Daniel Kaehn wrote:
> > > > > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > > > > <benjamin.tissoires@redhat.com> wrote:

...

> > > >                     ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> > > >                     Package () {
> > > >                             Package () { "cell-names", Package () { "i2c", "gpio" }
> > > >                     }
> > >
> > > Yeah, looking at this, I think it still fragile. First of all, either this is
> > > missing, or simply wrong. We would need to access indices. ACPI _ADR is in the
> > > specification. As much as with PCI it may be considered reliable.
> > >
> > > So, that said, forget about it, and simply use _ADR as indicator of the node.
> > > See how MFD (in the Linux kernel) cares about this. Ex. Diolan DLN-2 driver.
> >
> > And that said, maybe CP2112 should simply re-use what MFD _already_ provides?
> 
> Great point -- it definitely seems like this driver belongs in the mfd
> directory to begin with.

It can be iteratively converted later on.

> It seems like aside from rewriting the CP2112 driver into an mfd
> driver and two platform drivers,
> my route forward for now would be to just do something like this (not
> yet tested):
> 
> + struct acpi_device *adev = ACPI_COMPANION(&hdev->dev);
> + if (adev)
> +    ACPI_COMPANION_SET(&dev->adap.dev, acpi_find_child_device(adev,
> 0x0, false));

ACPI_COMPANION_SET() is something different to simple device_set_node().
I would expect that in this driver we simply use the child fwnode as is.
But since you are not using so called secondary fwnode, I believe it's
fine for now.

> + else
> +     device_set_node(&dev->adap.dev,
> device_get_named_child_node(&hdev->dev, "i2c"));
> 
> (and the same for the gpiochip)
> 
> The follow-up question -- does there exist something analogous to DT
> bindings for ACPI devices,
> other than the ACPI spec itself, where this should be documented? Or
> will consumers truly have to
> read the driver code to determine that _ADR 0 is I2C and _ADR 1 is
> GPIO? (I haven't seen anything
> in my search so far -- but knowing that it truly doesn't exist would
> make me respect people developing
> embedded ACPI-based systems all the more!)

See how the acpi_get_local_address() is used in the 3 users of it.

Ideally we need a new callback in the fwnode ops to return either
(least) 32-bit of _ADR or "reg" property.

Dunno, if "reg" is actually what suits here.

That said, I would do something like (pseudo-code)

device_for_each_child_node() {
	if (name == $NAME)
		$NAME->fwnode = child;
	else if (_ADR = $INDEX)
		$NAME->fwnode = child;
}


> Thanks for your patience in working through all of this, especially
> considering how long of an email
> chain this has become!

You're welcome!
Andy Shevchenko March 9, 2023, 11:56 a.m. UTC | #25
On Thu, Mar 09, 2023 at 01:43:02PM +0200, Andy Shevchenko wrote:
> On Wed, Mar 08, 2023 at 12:32:07PM -0600, Daniel Kaehn wrote:
> > On Wed, Mar 8, 2023 at 10:36 AM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > > On Wed, Mar 08, 2023 at 06:30:46PM +0200, Andy Shevchenko wrote:
> > > > On Wed, Mar 08, 2023 at 04:55:27PM +0100, Benjamin Tissoires wrote:
> > > > > On Mar 08 2023, Daniel Kaehn wrote:
> > > > > > On Wed, Mar 8, 2023 at 9:26 AM Benjamin Tissoires
> > > > > > <benjamin.tissoires@redhat.com> wrote:

...

> > > > >                     ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> > > > >                     Package () {
> > > > >                             Package () { "cell-names", Package () { "i2c", "gpio" }
> > > > >                     }
> > > >
> > > > Yeah, looking at this, I think it still fragile. First of all, either this is
> > > > missing, or simply wrong. We would need to access indices. ACPI _ADR is in the
> > > > specification. As much as with PCI it may be considered reliable.
> > > >
> > > > So, that said, forget about it, and simply use _ADR as indicator of the node.
> > > > See how MFD (in the Linux kernel) cares about this. Ex. Diolan DLN-2 driver.
> > >
> > > And that said, maybe CP2112 should simply re-use what MFD _already_ provides?
> > 
> > Great point -- it definitely seems like this driver belongs in the mfd
> > directory to begin with.
> 
> It can be iteratively converted later on.
> 
> > It seems like aside from rewriting the CP2112 driver into an mfd
> > driver and two platform drivers,
> > my route forward for now would be to just do something like this (not
> > yet tested):
> > 
> > + struct acpi_device *adev = ACPI_COMPANION(&hdev->dev);
> > + if (adev)
> > +    ACPI_COMPANION_SET(&dev->adap.dev, acpi_find_child_device(adev,
> > 0x0, false));
> 
> ACPI_COMPANION_SET() is something different to simple device_set_node().
> I would expect that in this driver we simply use the child fwnode as is.
> But since you are not using so called secondary fwnode, I believe it's
> fine for now.
> 
> > + else
> > +     device_set_node(&dev->adap.dev,
> > device_get_named_child_node(&hdev->dev, "i2c"));
> > 
> > (and the same for the gpiochip)

> > The follow-up question -- does there exist something analogous to DT
> > bindings for ACPI devices,
> > other than the ACPI spec itself, where this should be documented? Or
> > will consumers truly have to
> > read the driver code to determine that _ADR 0 is I2C and _ADR 1 is
> > GPIO? (I haven't seen anything
> > in my search so far -- but knowing that it truly doesn't exist would
> > make me respect people developing
> > embedded ACPI-based systems all the more!)

The below misplaced, so here is the answer to the followup.
The _DSD heavily relies on the DT schemas and other standards such as MIPI.
For many cases there are no standards or any developed approaches.

Feel free to add a piece of documentation for the devices that are utilising
_ADR in ACPI (we have at least I²C/GPIO controller on Intel Quark —
drivers/mfd/intel_quark_i2c_gpio.c, and mentioned earlier the Diolan DLN-2 —
drivers/mfd/dln2.c).

> See how the acpi_get_local_address() is used in the 3 users of it.
> 
> Ideally we need a new callback in the fwnode ops to return either
> (least) 32-bit of _ADR or "reg" property.
> 
> Dunno, if "reg" is actually what suits here.
> 
> That said, I would do something like (pseudo-code)
> 
> device_for_each_child_node() {
> 	if (name == $NAME)
> 		$NAME->fwnode = child;
> 	else if (_ADR = $INDEX)
> 		$NAME->fwnode = child;
> }
> 
> > Thanks for your patience in working through all of this, especially
> > considering how long of an email
> > chain this has become!
> 
> You're welcome!
Andy Shevchenko March 9, 2023, 1:50 p.m. UTC | #26
On Thu, Mar 09, 2023 at 10:38:11AM +0100, Benjamin Tissoires wrote:
> On Mar 08 2023, Andy Shevchenko wrote:

...

> Looks like gpiolib-acpi.c doesn't care about fwnode at all.
> 
> if I do the following:
> 
> ---
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> index d8a421ce26a8..5aebc266426b 100644
> --- a/drivers/gpio/gpiolib-acpi.c
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -126,7 +126,7 @@ static bool acpi_gpio_deferred_req_irqs_done;
>  
>  static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
>  {
> -       return gc->parent && device_match_acpi_handle(gc->parent, data);
> +       return ACPI_HANDLE_FWNODE(gc->fwnode) == data;
>  }
>  
>  /**
> ---

This seems a legit fix.

> I can now directly reference the GPIO ACPI node in my GpioInt()
> declaration. And AFAICT this should be safe to do because gpiolib ensure
> that gc->fwnode is set, using the one from the parent if it is not set
> previously.
> 
> I need to check if this works with my icelake laptop, and if so I'll
> send it to the list.
> 
> The reason the intel gpios are working (the only one I checked) is
> because the \\SB.GPI0 node refers to the pinctrl controller (driver
> pinctrl-icelake.c in my case, which then creates a subdevice for
> handling the gpio).

Good catch!