Message ID | 20210604144027.v11.2.I7c9a1f1d6ced41dd8310e8a03da666a32364e790@changeid (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | USB: misc: Add onboard_usb_hub driver | expand |
Hi Matthias, I love your patch! Perhaps something to improve: [auto build test WARNING on next-20210604] [also build test WARNING on v5.13-rc4] [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 base: ccc252d2e818f6a479441119ad453c3ce7c7c461 config: arc-allyesconfig (attached as .config) compiler: arceb-elf-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 git checkout 7107f99a12058b7147342c6f763d026102bd6606 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) | ^~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) | ^~~~~~~~~~~~~~~~~~~~~~~~~ vim +/onboard_hub_create_pdevs +400 drivers/usb/misc/onboard_usb_hub.c 394 395 /* 396 * Creates a platform device for each supported onboard hub that is connected to 397 * the given parent hub. To keep track of the platform devices they are added to 398 * a list that is owned by the parent hub. 399 */ > 400 void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) 401 { 402 int i; 403 phandle ph; 404 struct device_node *np, *npc; 405 struct platform_device *pdev; 406 struct pdev_list_entry *pdle; 407 408 for (i = 1; i <= parent_hub->maxchild; i++) { 409 np = usb_of_get_device_node(parent_hub, i); 410 if (!np) 411 continue; 412 413 if (!of_is_onboard_usb_hub(np)) 414 goto node_put; 415 416 if (of_property_read_u32(np, "companion-hub", &ph)) 417 goto node_put; 418 419 npc = of_find_node_by_phandle(ph); 420 if (!npc) 421 goto node_put; 422 423 pdev = of_find_device_by_node(npc); 424 of_node_put(npc); 425 426 if (pdev) { 427 /* the companion hub already has a platform device, nothing to do here */ 428 put_device(&pdev->dev); 429 goto node_put; 430 } 431 432 pdev = of_platform_device_create(np, NULL, &parent_hub->dev); 433 if (pdev) { 434 pdle = kzalloc(sizeof(*pdle), GFP_KERNEL); 435 if (!pdle) 436 goto node_put; 437 438 INIT_LIST_HEAD(&pdle->node); 439 440 pdle->pdev = pdev; 441 list_add(&pdle->node, pdev_list); 442 } else { 443 dev_err(&parent_hub->dev, 444 "failed to create platform device for onboard hub '%s'\n", 445 of_node_full_name(np)); 446 } 447 448 node_put: 449 of_node_put(np); 450 } 451 } 452 EXPORT_SYMBOL_GPL(onboard_hub_create_pdevs); 453 454 /* 455 * Destroys the platform devices in the given list and frees the memory associated 456 * with the list entry. 457 */ > 458 void onboard_hub_destroy_pdevs(struct list_head *pdev_list) 459 { 460 struct pdev_list_entry *pdle, *tmp; 461 462 list_for_each_entry_safe(pdle, tmp, pdev_list, node) { 463 of_platform_device_destroy(&pdle->pdev->dev, NULL); 464 kfree(pdle); 465 } 466 } 467 EXPORT_SYMBOL_GPL(onboard_hub_destroy_pdevs); 468 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On Sat, Jun 05, 2021 at 07:18:38AM +0800, kernel test robot wrote: > Hi Matthias, > > I love your patch! Perhaps something to improve: > > [auto build test WARNING on next-20210604] > [also build test WARNING on v5.13-rc4] > [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] > [If your patch is applied to the wrong git tree, kindly drop us a note. > And when submitting patch, we suggest to use '--base' as documented in > https://git-scm.com/docs/git-format-patch] > > url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > base: ccc252d2e818f6a479441119ad453c3ce7c7c461 > config: arc-allyesconfig (attached as .config) > compiler: arceb-elf-gcc (GCC) 9.3.0 > reproduce (this is a W=1 build): > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > chmod +x ~/bin/make.cross > # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 > git remote add linux-review https://github.com/0day-ci/linux > git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > git checkout 7107f99a12058b7147342c6f763d026102bd6606 > # save the attached .config to linux build tree > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc > > If you fix the issue, kindly add following tag as appropriate > Reported-by: kernel test robot <lkp@intel.com> > > All warnings (new ones prefixed by >>): > > >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] > 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) > | ^~~~~~~~~~~~~~~~~~~~~~~~ > >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] > 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) > | ^~~~~~~~~~~~~~~~~~~~~~~~~ Oh, I wasn't aware that prototypes are required for public functions. To avoid too much version churn I'll wait a bit for further comments before sending a v12 with the prototypes.
On Mon, Jun 07, 2021 at 10:51:57AM -0700, Matthias Kaehlcke wrote: > On Sat, Jun 05, 2021 at 07:18:38AM +0800, kernel test robot wrote: > > Hi Matthias, > > > > I love your patch! Perhaps something to improve: > > > > [auto build test WARNING on next-20210604] > > [also build test WARNING on v5.13-rc4] > > [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] > > [If your patch is applied to the wrong git tree, kindly drop us a note. > > And when submitting patch, we suggest to use '--base' as documented in > > https://git-scm.com/docs/git-format-patch] > > > > url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > base: ccc252d2e818f6a479441119ad453c3ce7c7c461 > > config: arc-allyesconfig (attached as .config) > > compiler: arceb-elf-gcc (GCC) 9.3.0 > > reproduce (this is a W=1 build): > > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > > chmod +x ~/bin/make.cross > > # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 > > git remote add linux-review https://github.com/0day-ci/linux > > git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > git checkout 7107f99a12058b7147342c6f763d026102bd6606 > > # save the attached .config to linux build tree > > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc > > > > If you fix the issue, kindly add following tag as appropriate > > Reported-by: kernel test robot <lkp@intel.com> > > > > All warnings (new ones prefixed by >>): > > > > >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] > > 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) > > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] > > 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) > > | ^~~~~~~~~~~~~~~~~~~~~~~~~ > > Oh, I wasn't aware that prototypes are required for public functions. How else can they be called?
On Mon, Jun 07, 2021 at 08:23:43PM +0200, Greg Kroah-Hartman wrote: > On Mon, Jun 07, 2021 at 10:51:57AM -0700, Matthias Kaehlcke wrote: > > On Sat, Jun 05, 2021 at 07:18:38AM +0800, kernel test robot wrote: > > > Hi Matthias, > > > > > > I love your patch! Perhaps something to improve: > > > > > > [auto build test WARNING on next-20210604] > > > [also build test WARNING on v5.13-rc4] > > > [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] > > > [If your patch is applied to the wrong git tree, kindly drop us a note. > > > And when submitting patch, we suggest to use '--base' as documented in > > > https://git-scm.com/docs/git-format-patch] > > > > > > url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > base: ccc252d2e818f6a479441119ad453c3ce7c7c461 > > > config: arc-allyesconfig (attached as .config) > > > compiler: arceb-elf-gcc (GCC) 9.3.0 > > > reproduce (this is a W=1 build): > > > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > > > chmod +x ~/bin/make.cross > > > # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 > > > git remote add linux-review https://github.com/0day-ci/linux > > > git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > git checkout 7107f99a12058b7147342c6f763d026102bd6606 > > > # save the attached .config to linux build tree > > > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc > > > > > > If you fix the issue, kindly add following tag as appropriate > > > Reported-by: kernel test robot <lkp@intel.com> > > > > > > All warnings (new ones prefixed by >>): > > > > > > >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] > > > 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) > > > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > > >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] > > > 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) > > > | ^~~~~~~~~~~~~~~~~~~~~~~~~ > > > > Oh, I wasn't aware that prototypes are required for public functions. > > How else can they be called? Well, there are prototypes in include/linux/usb/onboard_hub.h, however this header isn't included (anymore) by the driver itself to avoid conflicts when COMPILE_TEST=y (see https://lkml.org/lkml/2021/5/25/975).
On Mon, Jun 07, 2021 at 11:32:31AM -0700, Matthias Kaehlcke wrote: > On Mon, Jun 07, 2021 at 08:23:43PM +0200, Greg Kroah-Hartman wrote: > > On Mon, Jun 07, 2021 at 10:51:57AM -0700, Matthias Kaehlcke wrote: > > > On Sat, Jun 05, 2021 at 07:18:38AM +0800, kernel test robot wrote: > > > > Hi Matthias, > > > > > > > > I love your patch! Perhaps something to improve: > > > > > > > > [auto build test WARNING on next-20210604] > > > > [also build test WARNING on v5.13-rc4] > > > > [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] > > > > [If your patch is applied to the wrong git tree, kindly drop us a note. > > > > And when submitting patch, we suggest to use '--base' as documented in > > > > https://git-scm.com/docs/git-format-patch] > > > > > > > > url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > > base: ccc252d2e818f6a479441119ad453c3ce7c7c461 > > > > config: arc-allyesconfig (attached as .config) > > > > compiler: arceb-elf-gcc (GCC) 9.3.0 > > > > reproduce (this is a W=1 build): > > > > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > > > > chmod +x ~/bin/make.cross > > > > # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 > > > > git remote add linux-review https://github.com/0day-ci/linux > > > > git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > > git checkout 7107f99a12058b7147342c6f763d026102bd6606 > > > > # save the attached .config to linux build tree > > > > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc > > > > > > > > If you fix the issue, kindly add following tag as appropriate > > > > Reported-by: kernel test robot <lkp@intel.com> > > > > > > > > All warnings (new ones prefixed by >>): > > > > > > > > >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] > > > > 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) > > > > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > > > >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] > > > > 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) > > > > | ^~~~~~~~~~~~~~~~~~~~~~~~~ > > > > > > Oh, I wasn't aware that prototypes are required for public functions. > > > > How else can they be called? > > Well, there are prototypes in include/linux/usb/onboard_hub.h, however this > header isn't included (anymore) by the driver itself to avoid conflicts > when COMPILE_TEST=y (see https://lkml.org/lkml/2021/5/25/975). Then that needs to be resolved please. thanks, greg k-h
On Tue, Jun 08, 2021 at 10:56:08AM +0200, Greg Kroah-Hartman wrote: > On Mon, Jun 07, 2021 at 11:32:31AM -0700, Matthias Kaehlcke wrote: > > On Mon, Jun 07, 2021 at 08:23:43PM +0200, Greg Kroah-Hartman wrote: > > > On Mon, Jun 07, 2021 at 10:51:57AM -0700, Matthias Kaehlcke wrote: > > > > On Sat, Jun 05, 2021 at 07:18:38AM +0800, kernel test robot wrote: > > > > > Hi Matthias, > > > > > > > > > > I love your patch! Perhaps something to improve: > > > > > > > > > > [auto build test WARNING on next-20210604] > > > > > [also build test WARNING on v5.13-rc4] > > > > > [cannot apply to usb/usb-testing robh/for-next char-misc/char-misc-testing driver-core/driver-core-testing linus/master v5.13-rc4 v5.13-rc3 v5.13-rc2] > > > > > [If your patch is applied to the wrong git tree, kindly drop us a note. > > > > > And when submitting patch, we suggest to use '--base' as documented in > > > > > https://git-scm.com/docs/git-format-patch] > > > > > > > > > > url: https://github.com/0day-ci/linux/commits/Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > > > base: ccc252d2e818f6a479441119ad453c3ce7c7c461 > > > > > config: arc-allyesconfig (attached as .config) > > > > > compiler: arceb-elf-gcc (GCC) 9.3.0 > > > > > reproduce (this is a W=1 build): > > > > > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > > > > > chmod +x ~/bin/make.cross > > > > > # https://github.com/0day-ci/linux/commit/7107f99a12058b7147342c6f763d026102bd6606 > > > > > git remote add linux-review https://github.com/0day-ci/linux > > > > > git fetch --no-tags linux-review Matthias-Kaehlcke/USB-misc-Add-onboard_usb_hub-driver/20210605-054213 > > > > > git checkout 7107f99a12058b7147342c6f763d026102bd6606 > > > > > # save the attached .config to linux build tree > > > > > COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc > > > > > > > > > > If you fix the issue, kindly add following tag as appropriate > > > > > Reported-by: kernel test robot <lkp@intel.com> > > > > > > > > > > All warnings (new ones prefixed by >>): > > > > > > > > > > >> drivers/usb/misc/onboard_usb_hub.c:400:6: warning: no previous prototype for 'onboard_hub_create_pdevs' [-Wmissing-prototypes] > > > > > 400 | void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) > > > > > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > > > > >> drivers/usb/misc/onboard_usb_hub.c:458:6: warning: no previous prototype for 'onboard_hub_destroy_pdevs' [-Wmissing-prototypes] > > > > > 458 | void onboard_hub_destroy_pdevs(struct list_head *pdev_list) > > > > > | ^~~~~~~~~~~~~~~~~~~~~~~~~ > > > > > > > > Oh, I wasn't aware that prototypes are required for public functions. > > > > > > How else can they be called? > > > > Well, there are prototypes in include/linux/usb/onboard_hub.h, however this > > header isn't included (anymore) by the driver itself to avoid conflicts > > when COMPILE_TEST=y (see https://lkml.org/lkml/2021/5/25/975). > > Then that needs to be resolved please. I already sent at least two versions exclusively to deal with related issues, but there are still configurations that cause trouble, I would appreciate some guidance here. The latest issue was: > I get a build error when I apply this series to my tree: > > drivers/usb/misc/onboard_usb_hub.c:273:6: error: redefinition of ‘of_is_onboard_usb_hub’ > 273 | bool of_is_onboard_usb_hub(const struct device_node *np) > | ^~~~~~~~~~~~~~~~~~~~~ > In file included from drivers/usb/misc/onboard_usb_hub.c:21: > ./include/linux/usb/onboard_hub.h:9:20: note: previous definition of ‘of_is_onboard_usb_hub’ with type ‘bool(const struct device_node *)’ {aka ‘_Bool(const struct device_node *)’} > 9 | static inline bool of_is_onboard_usb_hub(const struct device_node *np) > | ^~~~~~~~~~~~~~~~~~~~~ This was with the following declaration in the header: #ifdef CONFIG_USB_ONBOARD_HUB bool of_is_onboard_usb_hub(const struct device_node *np); #else static inline bool of_is_onboard_usb_hub(const struct device_node *np) { return false; } #endif My initial assumption was that in this case the configuration was COMPILE_TEST=y and USB_ONBOARD_HUB=n, however should onboard_usb_hub.c even be compiled with USB_ONBOARD_HUB=n? IIUC COMPILE_TEST=y allows to compile certain drivers even when they couldn't actually run/be loaded on the target platform, but the config option would still need to be enabled. Then again, there was apparently an attempt to compile onboard_usb_hub.c, however the static inline from the header was picked, which suggests CONFIG_USB_ONBOARD_HUB=n. Also please let me know if you have other comments besides the prototype question, I'd prefer to avoid version churn if possible, this series already had a bit of that primarily due to the prototype issue. Thanks Matthias
On Tue, Jun 08, 2021 at 01:54:55PM -0700, Matthias Kaehlcke wrote: > Also please let me know if you have other comments besides the prototype > question, I'd prefer to avoid version churn if possible, this series > already had a bit of that primarily due to the prototype issue. When the kernel test robot finds issues, I drop the patches from my review queue as I don't have time to review stuff with obvious issues, so I do not even have the changes around to review at the moment. I have plenty of patches that do not have build problems to review :) Fix them up and resend, there's nothing wrong with sending lots of versions if you have to resolve problems. thanks, greg k-h
diff --git a/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub new file mode 100644 index 000000000000..e981d83648e6 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub @@ -0,0 +1,8 @@ +What: /sys/bus/platform/devices/<dev>/always_powered_in_suspend +Date: March 2021 +KernelVersion: 5.13 +Contact: Matthias Kaehlcke <matthias@kaehlcke.net> + linux-usb@vger.kernel.org +Description: + (RW) Controls whether the USB hub remains always powered + during system suspend or not. \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..32220210345d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13613,6 +13613,13 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov9734.c +ONBOARD USB HUB DRIVER +M: Matthias Kaehlcke <mka@chromium.org> +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/usb/onboard_usb_hub.yaml +F: drivers/usb/misc/onboard_usb_hub.c + ONENAND FLASH DRIVER M: Kyungmin Park <kyungmin.park@samsung.com> L: linux-mtd@lists.infradead.org diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 8f1144359012..f534269fbb20 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -284,3 +284,20 @@ config BRCM_USB_PINMAP This option enables support for remapping some USB external signals, which are typically on dedicated pins on the chip, to any gpio. + +config USB_ONBOARD_HUB + tristate "Onboard USB hub support" + depends on OF || COMPILE_TEST + help + Say Y here if you want to support discrete onboard USB hubs that + don't require an additional control bus for initialization, but + need some nontrivial form of initialization, such as enabling a + power regulator. An example for such a hub is the Realtek + RTS5411. + + The driver can be configured to turn off the power of the hub + during system suspend. This may reduce power consumption while + the system is suspended. + + To compile this driver as a module, choose M here: the + module will be called onboard_usb_hub. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 5f4e598573ab..2c5aec6f1b26 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o obj-$(CONFIG_BRCM_USB_PINMAP) += brcmstb-usb-pinmap.o +obj-$(CONFIG_USB_ONBOARD_HUB) += onboard_usb_hub.o diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c new file mode 100644 index 000000000000..a074d1bbfa8f --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for onboard USB hubs + * + * Copyright (c) 2020, Google LLC + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/sysfs.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/of.h> + +static struct usb_device_driver onboard_hub_usbdev_driver; + +/************************** Platform driver **************************/ + +struct udev_node { + struct usb_device *udev; + struct list_head list; +}; + +struct onboard_hub { + struct regulator *vdd; + struct device *dev; + bool always_powered_in_suspend; + bool is_powered_on; + bool going_away; + struct list_head udev_list; + struct mutex lock; +}; + +static int onboard_hub_power_on(struct onboard_hub *hub) +{ + int err; + + err = regulator_enable(hub->vdd); + if (err) { + dev_err(hub->dev, "failed to enable regulator: %d\n", err); + return err; + } + + hub->is_powered_on = true; + + return 0; +} + +static int onboard_hub_power_off(struct onboard_hub *hub) +{ + int err; + + err = regulator_disable(hub->vdd); + if (err) { + dev_err(hub->dev, "failed to disable regulator: %d\n", err); + return err; + } + + hub->is_powered_on = false; + + return 0; +} + +static int __maybe_unused onboard_hub_suspend(struct device *dev) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + struct udev_node *node; + bool power_off; + int rc = 0; + + if (hub->always_powered_in_suspend) + return 0; + + power_off = true; + + mutex_lock(&hub->lock); + + list_for_each_entry(node, &hub->udev_list, list) { + if (!device_may_wakeup(node->udev->bus->controller)) + continue; + + if (usb_wakeup_enabled_descendants(node->udev)) { + power_off = false; + break; + } + } + + mutex_unlock(&hub->lock); + + if (power_off) + rc = onboard_hub_power_off(hub); + + return rc; +} + +static int __maybe_unused onboard_hub_resume(struct device *dev) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + int rc = 0; + + if (!hub->is_powered_on) + rc = onboard_hub_power_on(hub); + + return rc; +} + +static int onboard_hub_add_usbdev(struct onboard_hub *hub, struct usb_device *udev) +{ + struct udev_node *node; + char link_name[64]; + int ret = 0; + + mutex_lock(&hub->lock); + + if (hub->going_away) { + ret = -EINVAL; + goto unlock; + } + + node = devm_kzalloc(hub->dev, sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto unlock; + } + + node->udev = udev; + + list_add(&node->list, &hub->udev_list); + + snprintf(link_name, sizeof(link_name), "usb_dev.%s", dev_name(&udev->dev)); + WARN_ON(sysfs_create_link(&hub->dev->kobj, &udev->dev.kobj, link_name)); + +unlock: + mutex_unlock(&hub->lock); + + return ret; +} + +static void onboard_hub_remove_usbdev(struct onboard_hub *hub, struct usb_device *udev) +{ + struct udev_node *node; + char link_name[64]; + + snprintf(link_name, sizeof(link_name), "usb_dev.%s", dev_name(&udev->dev)); + sysfs_remove_link(&hub->dev->kobj, link_name); + + mutex_lock(&hub->lock); + + list_for_each_entry(node, &hub->udev_list, list) { + if (node->udev == udev) { + list_del(&node->list); + break; + } + } + + mutex_unlock(&hub->lock); +} + +static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", hub->always_powered_in_suspend); +} + +static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret < 0) + return ret; + + hub->always_powered_in_suspend = val; + + return count; +} +static DEVICE_ATTR_RW(always_powered_in_suspend); + +static struct attribute *onboard_hub_attrs[] = { + &dev_attr_always_powered_in_suspend.attr, + NULL, +}; +ATTRIBUTE_GROUPS(onboard_hub); + +static int onboard_hub_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct onboard_hub *hub; + int err; + + hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(hub->vdd)) + return PTR_ERR(hub->vdd); + + hub->dev = dev; + mutex_init(&hub->lock); + INIT_LIST_HEAD(&hub->udev_list); + + dev_set_drvdata(dev, hub); + + err = onboard_hub_power_on(hub); + if (err) + return err; + + /* + * The USB driver might have been detached from the USB devices by + * onboard_hub_remove(), make sure to re-attach it if needed. + */ + err = driver_attach(&onboard_hub_usbdev_driver.drvwrap.driver); + if (err) { + onboard_hub_power_off(hub); + return err; + } + + return 0; +} + +static int onboard_hub_remove(struct platform_device *pdev) +{ + struct onboard_hub *hub = dev_get_drvdata(&pdev->dev); + struct udev_node *node; + struct usb_device *udev; + + hub->going_away = true; + + mutex_lock(&hub->lock); + + /* unbind the USB devices to avoid dangling references to this device */ + while (!list_empty(&hub->udev_list)) { + node = list_first_entry(&hub->udev_list, struct udev_node, list); + udev = node->udev; + + /* + * Unbinding the driver will call onboard_hub_remove_usbdev(), + * which acquires hub->lock. We must release the lock first. + */ + get_device(&udev->dev); + mutex_unlock(&hub->lock); + device_release_driver(&udev->dev); + put_device(&udev->dev); + mutex_lock(&hub->lock); + } + + mutex_unlock(&hub->lock); + + return onboard_hub_power_off(hub); +} + +static const struct of_device_id onboard_hub_match[] = { + { .compatible = "usbbda,411" }, + { .compatible = "usbbda,5411" }, + {} +}; +MODULE_DEVICE_TABLE(of, onboard_hub_match); + +static bool of_is_onboard_usb_hub(const struct device_node *np) +{ + return !!of_match_node(onboard_hub_match, np); +} + +static const struct dev_pm_ops __maybe_unused onboard_hub_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_hub_suspend, onboard_hub_resume) +}; + +static struct platform_driver onboard_hub_driver = { + .probe = onboard_hub_probe, + .remove = onboard_hub_remove, + + .driver = { + .name = "onboard-usb-hub", + .of_match_table = onboard_hub_match, + .pm = pm_ptr(&onboard_hub_pm_ops), + .dev_groups = onboard_hub_groups, + }, +}; + +/************************** USB driver **************************/ + +#define VENDOR_ID_REALTEK 0x0bda + +/* + * Returns the onboard_hub platform device that is associated with the USB + * device passed as parameter. + */ +static struct onboard_hub *_find_onboard_hub(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *np; + phandle ph; + + pdev = of_find_device_by_node(dev->of_node); + if (!pdev) { + if (of_property_read_u32(dev->of_node, "companion-hub", &ph)) { + dev_err(dev, "failed to read 'companion-hub' property\n"); + return ERR_PTR(-EINVAL); + } + + np = of_find_node_by_phandle(ph); + if (!np) { + dev_err(dev, "failed to find device node for companion hub\n"); + return ERR_PTR(-EINVAL); + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + + if (!pdev) + return ERR_PTR(-EPROBE_DEFER); + } + + put_device(&pdev->dev); + + return dev_get_drvdata(&pdev->dev); +} + +static int onboard_hub_usbdev_probe(struct usb_device *udev) +{ + struct device *dev = &udev->dev; + struct onboard_hub *hub; + int err; + + /* ignore supported hubs without device tree node */ + if (!dev->of_node) + return -ENODEV; + + hub = _find_onboard_hub(dev); + if (IS_ERR(hub)) + return PTR_ERR(hub); + + dev_set_drvdata(dev, hub); + + err = onboard_hub_add_usbdev(hub, udev); + if (err) + return err; + + err = sysfs_create_link(&udev->dev.kobj, &hub->dev->kobj, "onboard_hub_dev"); + if (err) + dev_warn(&udev->dev, "failed to create symlink to platform device: %d\n", err); + + return 0; +} + +static void onboard_hub_usbdev_disconnect(struct usb_device *udev) +{ + struct onboard_hub *hub = dev_get_drvdata(&udev->dev); + + sysfs_remove_link(&udev->dev.kobj, "onboard_hub_dev"); + + onboard_hub_remove_usbdev(hub, udev); +} + +static const struct usb_device_id onboard_hub_id_table[] = { + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.0 */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.0 */ + {}, +}; + +MODULE_DEVICE_TABLE(usb, onboard_hub_id_table); + +static struct usb_device_driver onboard_hub_usbdev_driver = { + + .name = "onboard-usb-hub", + .probe = onboard_hub_usbdev_probe, + .disconnect = onboard_hub_usbdev_disconnect, + .generic_subclass = 1, + .supports_autosuspend = 1, + .id_table = onboard_hub_id_table, +}; + +/*** Helpers for creating/destroying platform devices for onboard hubs ***/ + +struct pdev_list_entry { + struct platform_device *pdev; + struct list_head node; +}; + +/* + * Creates a platform device for each supported onboard hub that is connected to + * the given parent hub. To keep track of the platform devices they are added to + * a list that is owned by the parent hub. + */ +void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) +{ + int i; + phandle ph; + struct device_node *np, *npc; + struct platform_device *pdev; + struct pdev_list_entry *pdle; + + for (i = 1; i <= parent_hub->maxchild; i++) { + np = usb_of_get_device_node(parent_hub, i); + if (!np) + continue; + + if (!of_is_onboard_usb_hub(np)) + goto node_put; + + if (of_property_read_u32(np, "companion-hub", &ph)) + goto node_put; + + npc = of_find_node_by_phandle(ph); + if (!npc) + goto node_put; + + pdev = of_find_device_by_node(npc); + of_node_put(npc); + + if (pdev) { + /* the companion hub already has a platform device, nothing to do here */ + put_device(&pdev->dev); + goto node_put; + } + + pdev = of_platform_device_create(np, NULL, &parent_hub->dev); + if (pdev) { + pdle = kzalloc(sizeof(*pdle), GFP_KERNEL); + if (!pdle) + goto node_put; + + INIT_LIST_HEAD(&pdle->node); + + pdle->pdev = pdev; + list_add(&pdle->node, pdev_list); + } else { + dev_err(&parent_hub->dev, + "failed to create platform device for onboard hub '%s'\n", + of_node_full_name(np)); + } + + node_put: + of_node_put(np); + } +} +EXPORT_SYMBOL_GPL(onboard_hub_create_pdevs); + +/* + * Destroys the platform devices in the given list and frees the memory associated + * with the list entry. + */ +void onboard_hub_destroy_pdevs(struct list_head *pdev_list) +{ + struct pdev_list_entry *pdle, *tmp; + + list_for_each_entry_safe(pdle, tmp, pdev_list, node) { + of_platform_device_destroy(&pdle->pdev->dev, NULL); + kfree(pdle); + } +} +EXPORT_SYMBOL_GPL(onboard_hub_destroy_pdevs); + +/************************** Driver (de)registration **************************/ + +static int __init onboard_hub_init(void) +{ + int ret; + + ret = platform_driver_register(&onboard_hub_driver); + if (ret) + return ret; + + ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); + if (ret) + platform_driver_unregister(&onboard_hub_driver); + + return ret; +} +module_init(onboard_hub_init); + +static void __exit onboard_hub_exit(void) +{ + usb_deregister_device_driver(&onboard_hub_usbdev_driver); + platform_driver_unregister(&onboard_hub_driver); +} +module_exit(onboard_hub_exit); + +MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>"); +MODULE_DESCRIPTION("Driver for discrete onboard USB hubs"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/onboard_hub.h b/include/linux/usb/onboard_hub.h new file mode 100644 index 000000000000..fb6403c8f0e7 --- /dev/null +++ b/include/linux/usb/onboard_hub.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_USB_ONBOARD_HUB_H +#define __LINUX_USB_ONBOARD_HUB_H + +struct usb_device; +struct list_head; + +#ifdef CONFIG_USB_ONBOARD_HUB +void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list); +void onboard_hub_destroy_pdevs(struct list_head *pdev_list); +#else +static inline void onboard_hub_create_pdevs(struct usb_device *parent_hub, + struct list_head *pdev_list) {} +static inline void onboard_hub_destroy_pdevs(struct list_head *pdev_list) {} +#endif + +#endif /* __LINUX_USB_ONBOARD_HUB_H */