-
Notifications
You must be signed in to change notification settings - Fork 236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use sysfs interface on recent Linux kernels #450
Conversation
Split out current libusb based power on/off logic into a separate function in anticipation of a other power switching implementations. Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for submitting this!
Your patch looks great, except I would check access to disable sysfs interface more carefully.
Overall this is excellent idea, however, if you or Michael Grzeschik are working on sysfs interface, why not fix underlying kernel issue properly in proposed Linux kernel patch? That is, make kernel to properly remove devices being turned off and send appropriate notifications to userspace (udev) upon receiving power off from libusb? Then, your patch will not be necessary at all.
If sysfs interace gets committed and becomes official way to do this in Linux kernel, then obviously we would have no choice and use it with your patch.
But I woud wait until it hits official Linux kernel before accepting your patch into uhubctl.
hub->location, configuration, hub->location, port | ||
); | ||
|
||
int disable_fd = open(disable_path, O_WRONLY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If user is not using sudo, this path exists but cannot be opened for writing, perhaps it should complain here about permissions?
E.g. we can use access()
to check if file exists. If it does not, we fall back to libusb interface silently.
But if disable file exists and we cannot open it for writing, user should be aware that he is doing something wrong.
This mentiones patch is already mainline: |
Thanks, good to know. I understand why one might want to use sysfs interface to control port power without using any extra tools - makes it quite convenient. But I am still confused why exact same functionality of proper power switching (already implemented by
Don't get me wrong, if this is all we've got, so be it, let's change uhubctl to use sysfs interface. But I just find it weird that Linux kernel has to do things non-standard way compared to any other POSIX OS out there. Sending hub control messages should do whatever is written in USB spec, including power switching. Linux kernel is capable of doing it, why we have to invent ways to take detours and do it weird way??? |
Because when we just invoke the mentioned message, the kernel will just not get to know anything about the hub port state change. Usually the ehci core does not get any message/interrupt if a simple port on a hub is disabled. This way it is impossible for the kernel to properly disable all associated and probed devices behind that port. When doing it the way the kernel implements |
@mgrzeschik , if I understand it correctly, it is the kernel which is processing hub control message coming from userspace:
so kernel should be able to react on this properly (including ehci). But anyway, I won't stand in the way - lets do this if that the only way Linux is supporting this now. I think we should try sysfs interface on Linux by default, but to add an option to NOT call sysfs interface if any problem arises. E.g. add option with provisional name |
The controlltransfer you are refering to, that the kernel is getting thrown from the userspace is directly transmitted to the I think it would make sense to change the properties. So the default case will stay as it is. What do you think? |
Yes, adding this PR under |
After reviewing the patch once again, I just realized that the suggested autodetection should be prefered and the --sysfs is actually unnecessary. When a user will call the code without root privileges or on a older system, the newer binary will fallback I think the code is mergable as is. |
Hi @mvp, udev
I've just added a commit to the PR that adds a section to the README on how to set up root-less access to the sysfs interface. These rules are not yet tested that well as I am currently developing directly on an embedded device where more or less everything runs as root. I will do some testing before marking the PR as non-draft.
This sounds good to me. I will implement it tomorrow/soon.
Command line Parameters
I would prefer not to to this as it would make using uhubctl in scripts or wrappers like labgrid more complicated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding udev rules for sysfs, much appreciated!
We can push it as is, but I think that it would be helpful to change README.md to not split Linux 6 vs older Linux into separate paragraphs because they share everything except for 2-3 lines.
README.md
Outdated
SUBSYSTEM=="usb", DRIVER=="hub", \ | ||
RUN="/bin/sh -c \"chmod --silent 666 $sys$devpath/*-port*/disable\"" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just add this to relevant existing block to say this:
# Linux 5.x or earlier (its ok to have this block present in newer Linux):
SUBSYSTEM=="usb", ATTR{idVendor}=="2001", MODE="0666"
# Linux 6.0 or later (its ok to have this block present in older Linux):
SUBSYSTEM=="usb", DRIVER=="hub", \
RUN="/bin/sh -c \"chmod --silent 666 $sys$devpath/*-port*/disable\""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I like that better than the split sections. And have reworked my previous commits to match this.
It also turned out that having just the rule to change the …/disable
permissions is not enough, as libusb
is still used for a lot of things.
README.md
Outdated
If you don't like wide open mode `0666`, you can restrict access by group by using a rule like the | ||
following instead: | ||
|
||
SUBSYSTEM=="usb", DRIVER=="hub", \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, add this to relevant existing block to say this (note added -f
so it can work on older Linux without spamming logs):
# Linux 5.x or earlier (its ok to have this block present in newer Linux):
SUBSYSTEM=="usb", ATTR{idVendor}=="2001", MODE="0664", GROUP="dialout"
# Linux 6.0 or later (its ok to have this block present in older Linux):
SUBSYSTEM=="usb", DRIVER=="hub", \
RUN+="/bin/sh -c \"chown -f root:dialout $sys$devpath/*-port*/disable\"" \
RUN+="/bin/sh -c \"chmod -f 660 $sys$devpath/*-port*/disable\""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using only -f
is not enough to keep udev
from spamming the log, as chown
/chmod
still return an error code when the operation fails (even though they do not print a message).
I've also added || true
to the commandline to make sure that does not happen.
README.md
Outdated
@@ -211,6 +211,36 @@ USB device into the same physical USB port (this method is also used in Linux ke | |||
Linux USB permissions | |||
===================== | |||
|
|||
Kernels after 6.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linux 6.0 paragraph and Kernels before 6.0 have 95% in common.
I would prefer to refactor this to remove Linux 6.0 separate paragraph, and instead add Linux 6.0 specific blocks as outlined below.
We should suggest distro packagers to supply one udev rule file which contains support for both Linux 6.0 and older.
README.md
Outdated
On Linux Kernel 6.0 and later (e.g. `uname -r` shows a version numer greater or equal to 6.0) there is | ||
a standard interface to turn USB hub ports on or off, that can be used instead of libusb. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move this to start on Linux permissions paragraph to say something like this:
On Linux Kernel 6.0 and later (e.g. `uname -r` shows a version numer greater or equal to 6.0) there is
a standard interface to turn USB hub ports on or off, and `uhubctl` will try using it instead of `libusb`
if it is supported by current kernel.
Rules below have slight differences specific to Linux 6.x, but you can have both enabled
if you are not sure which kernel version you have or will have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
numer => number
Thanks a lot!
Perhaps only add
|
Starting with Linux kernel 6.0[1] there will be a sysfs interface to power USB ports off/on from userspace. Try to use this interface before falling back to the usual libusb based power switching (e.g. when running on a kernel <6.0 or if file permissions do not allow using the sysfs interface). The main benefit of using the sysfs interface is that the kernel does not get confused about the state of a port, so retrying should no longer be required. [1]: https://lore.kernel.org/all/20220607114522.3359148-1-m.grzeschik@pengutronix.de/ Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
The udev rules for the sysfs case are a bit more complex than those for the libusb based interface, as udev has built-in support for changing permissions on device files but not for sysfs attributes. Instead we have to use chmod / chown to set permissions and owners. You may notice the " || true" parts in the RUN part of the rules in addition to the -f parameters. These are there to make sure that no error is logged by udev even if the disable attribute does not exist. chmod/chown still return an error exit code even with -f if the requested path does not exist. " || true" makes sure this error is not propagated to udev. Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
Sounds sensible to me. Implementing it required a bunch of I've tested:
I think with the addition of the new |
Thank you for this work! I will follow up with few cleanups |
@hnez , @mgrzeschik : now that Linux kernel 6.0 is released, can you please confirm that uhubctl built from master works on 6.0 as expected? |
Hi, sorry for the long delay, I've been on vacation. I've just tested uhubctl on our embedded device with an (when it comes to USB) unpatched 6.0 kernel. Using
Our custom I will be in the office on Thursday and will have a look if I can find some other hub and another host to test with, maybe a USB 3.x one. I do however not have too high hopes of actually finding such a hub. |
To have this usb3 hub case tested: I did succesfully test this with an usb3 hub. After triggering an usb3 port to be disabled by uhubctl uhubctl -a off -l 2-1 -p 2 cat /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/1-1-port2/disable This got reversed for both ports after enabling one of the ports again. uhubctl -a on -l 1-1 -p 1 cat /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/1-1-port2/disable I also validated this by enumerating usb2 or usb3 devices on this ports. All corresponding usb |
Thank you @mgrzeschik! uhubctl 2.5.0 which contains this fix is already added into testing repositories of major Linux distros: Debian, Fedora, Raspbian, OpenSUSE. I would expect it to be present in all Linux package repositories in few months. |
> * Added support for Linux sysfs based power switching provided in > Linux kernel 6.0+ - it allows to solve reliability issues when > turning power off on Linux (#450). > * Added option --nodesc to skip querying device string descriptors > (necessary for some buggy devices which otherwise would completely freeze). > * New simpler way to configure udev rules on Linux > (one rule works for any USB hub). > * Even more supported devices. License file hash changed due to copyright year update. Link: mvp/uhubctl#450 Link: https://github.com/mvp/uhubctl/releases/tag/v2.5.0 Signed-off-by: Alexander Dahl <ada@thorsis.com>
> * Added support for Linux sysfs based power switching provided in > Linux kernel 6.0+ - it allows to solve reliability issues when > turning power off on Linux (#450). > * Added option --nodesc to skip querying device string descriptors > (necessary for some buggy devices which otherwise would completely freeze). > * New simpler way to configure udev rules on Linux > (one rule works for any USB hub). > * Even more supported devices. License file hash changed due to copyright year update. Link: mvp/uhubctl#450 Link: https://github.com/mvp/uhubctl/releases/tag/v2.5.0 Signed-off-by: Alexander Dahl <ada@thorsis.com> Message-Id: <20230918080706.36511-1-ada@thorsis.com> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
Hi,
we are currently developing a Linux based embedded device on which we want to be able to power on/off the individual USB ports.
Wiring up the on-board hub for individual port switching and using
uhubctl
as control software was thus an obvious choice.We could however not get the desired reliability when turning ports off, even when using the retry parameter.
To solve this problem one of my colleagues has implemented a sysfs interface to control the power status from userspace which will land in the upcoming 6.0 Linux Kernel release.
We have since switched to using the sysfs directly to control port power instead of
uhubctl
in our own software, but would nevertheless like to see support for it inuhubctl
.The benefit of using the sysfs interface is that Linux will not get confused about the state of the devices on the hub ports and will not try to power it back on immediately.
This PR is only a bare bones implementation of how to use the interface to set the status. It could however also be used to get the current status and it could even be possible to implement a version of of
uhubctl
on top of it that does not depend on libusb at all. I would like to hear your opinion of how deep the sysfs interface integration should go before investing more time into an implementation.I've marked the PR as draft as Linux Kernel 6.0 is not yet released and as I did not do a lot of testing yet.
Greetings
Leonard