bind/unbind command not working for usb_ether

Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
However the 'usb_ether' driver is never registered and thus doesn't appear in a 'dm tree' list and can't be bound to the usb controller.
With the help of Heiko I've found two ways to get the usb_ether driver to register:
dt-way: - add of match in ether.c: diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 63d552bc8b..8e2a05a5af 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2690,10 +2690,16 @@ int usb_ether_init(void) return 0; }
+static const struct udevice_id usb_ether_ids[] = { + { .compatible = "gadget,usb_ether" }, + { } +}; + U_BOOT_DRIVER(eth_usb) = { .name = "usb_ether", .id = UCLASS_ETH, .probe = usb_eth_probe, + .of_match = usb_ether_ids, .ops = &usb_eth_ops, .priv_auto_alloc_size = sizeof(struct ether_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), - then add it directly in your board u-boot.dts: +&usbotg1 { + usb_ether0 { + compatible = "gadget,usb_ether"; + status = "okay"; + }; +};
The non-dt way: - bind it manually in board code with: { struct udevice *dev; struct udevice *usb_dev; int ret;
ret = uclass_first_device(UCLASS_USB, &usb_dev); if (!usb_dev || ret) printf("%s: No USB device found\n", __func__);
ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev); if (!dev || ret) printf("%s: usb - not able to bind usb_ether device\n", __func__); } - Note that this is the same code from usb_ether_init() but with UCLASS_USB instead of UCLASS_USB_GADGET_GENERIC
What is the intended way to bind the usb_ether gadget device at runtime?
Additionally Heiko found that once bound and usb_ether is registered as a network device using a network command like ping/tftpboot calls usb_setup_ehci_gadget() which removes the USB driver ... and so also the child usb ethernet gadget device then re-probes only the usb driver and not the gadget thus fails. I compared this to how the 'ums' command works and that also removes the usb driver and child nodes but because ums isn't a gadget driver it doesn't get removed and works.
Best Regards,
Tim

Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice
However the 'usb_ether' driver is never registered and thus doesn't appear in a 'dm tree' list and can't be bound to the usb controller.
With the help of Heiko I've found two ways to get the usb_ether driver to register:
dt-way:
- add of match in ether.c:
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 63d552bc8b..8e2a05a5af 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2690,10 +2690,16 @@ int usb_ether_init(void) return 0; }
+static const struct udevice_id usb_ether_ids[] = {
{ .compatible = "gadget,usb_ether" },
{ }
+};
U_BOOT_DRIVER(eth_usb) = { .name = "usb_ether", .id = UCLASS_ETH, .probe = usb_eth_probe,
.of_match = usb_ether_ids, .ops = &usb_eth_ops, .priv_auto_alloc_size = sizeof(struct ether_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata),
- then add it directly in your board u-boot.dts:
+&usbotg1 {
usb_ether0 {
compatible = "gadget,usb_ether";
status = "okay";
};
+};
The non-dt way:
- bind it manually in board code with:
{ struct udevice *dev; struct udevice *usb_dev; int ret;
ret = uclass_first_device(UCLASS_USB, &usb_dev); if (!usb_dev || ret) printf("%s: No USB device found\n", __func__); ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev); if (!dev || ret) printf("%s: usb - not able to bind usb_ether
device\n", __func__); }
- Note that this is the same code from usb_ether_init() but with
UCLASS_USB instead of UCLASS_USB_GADGET_GENERIC
What is the intended way to bind the usb_ether gadget device at runtime?
Additionally Heiko found that once bound and usb_ether is registered as a network device using a network command like ping/tftpboot calls usb_setup_ehci_gadget() which removes the USB driver ... and so also the child usb ethernet gadget device then re-probes only the usb driver and not the gadget thus fails. I compared this to how the 'ums' command works and that also removes the usb driver and child nodes but because ums isn't a gadget driver it doesn't get removed and works.
Best Regards,
Tim

On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb Ventana > dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver thermal 0 [ ] imx_thermal |-- imx_thermal simple_bus 0 [ + ] simple_bus |-- soc pci 0 [ ] imx_pcie | |-- pcie@1ffc000 simple_bus 1 [ + ] simple_bus | |-- bus@2000000 simple_bus 2 [ ] simple_bus | | |-- spba-bus@2000000 serial 0 [ ] serial_mxc | | | `-- serial@2020000 gpio 0 [ + ] gpio_mxc | | |-- gpio@209c000 gpio 1 [ + ] gpio_mxc | | |-- gpio@20a0000 gpio 2 [ + ] gpio_mxc | | |-- gpio@20a4000 gpio 3 [ + ] gpio_mxc | | |-- gpio@20a8000 gpio 4 [ + ] gpio_mxc | | |-- gpio@20ac000 gpio 5 [ ] gpio_mxc | | |-- gpio@20b0000 gpio 6 [ ] gpio_mxc | | |-- gpio@20b4000 watchdog 0 [ + ] imx_wdt | | |-- wdog@20bc000 simple_bus 3 [ ] simple_bus | | |-- anatop@20c8000 simple_bus 4 [ ] simple_bus | | |-- snvs@20cc000 simple_bus 5 [ ] simple_bus | | |-- iomuxc-gpr@20e0000 pinctrl 0 [ + ] fsl_imx6q_iomuxc | | `-- iomuxc@20e0000 pinconfig 0 [ + ] pinconfig | | |-- enetgrp pinconfig 1 [ ] pinconfig | | |-- gpioledsgrp pinconfig 2 [ + ] pinconfig | | |-- i2c1grp pinconfig 3 [ + ] pinconfig | | |-- i2c2grp pinconfig 4 [ ] pinconfig | | |-- i2c3grp pinconfig 5 [ ] pinconfig | | |-- imugrp pinconfig 6 [ ] pinconfig | | |-- maggrp pinconfig 7 [ + ] pinconfig | | |-- pciegrp pinconfig 8 [ ] pinconfig | | |-- pmicgrp pinconfig 9 [ ] pinconfig | | |-- ppsgrp pinconfig 10 [ ] pinconfig | | |-- pwm2grp pinconfig 11 [ ] pinconfig | | |-- pwm3grp pinconfig 12 [ ] pinconfig | | |-- pwm4grp pinconfig 13 [ ] pinconfig | | |-- uart1grp pinconfig 14 [ + ] pinconfig | | |-- uart2grp pinconfig 15 [ ] pinconfig | | |-- uart3grp pinconfig 16 [ ] pinconfig | | |-- uart4grp pinconfig 17 [ ] pinconfig | | |-- uart5grp pinconfig 18 [ ] pinconfig | | |-- usbh1grp pinconfig 19 [ ] pinconfig | | |-- usbotggrp pinconfig 20 [ + ] pinconfig | | |-- usdhc3grp pinconfig 21 [ ] pinconfig | | |-- usdhc3grp100mhz pinconfig 22 [ ] pinconfig | | |-- usdhc3grp200mhz pinconfig 23 [ + ] pinconfig | | `-- wdoggrp simple_bus 6 [ + ] simple_bus | |-- bus@2100000 usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200 mmc 0 [ + ] fsl_esdhc | | |-- usdhc@2198000 blk 0 [ + ] mmc_blk | | | `-- usdhc@2198000.blk i2c 0 [ + ] i2c_mxc | | |-- i2c@21a0000 i2c_generi 0 [ + ] i2c_generic_chip_drv | | | |-- generic_51 i2c_generi 2 [ + ] i2c_generic_chip_drv | | | |-- generic_20 i2c_generi 3 [ + ] i2c_generic_chip_drv | | | |-- generic_29 i2c_generi 4 [ + ] i2c_generic_chip_drv | | | `-- generic_68 i2c 1 [ + ] i2c_mxc | | |-- i2c@21a4000 i2c_generi 1 [ + ] i2c_generic_chip_drv | | | `-- generic_3c i2c 2 [ ] i2c_mxc | | |-- i2c@21a8000 serial 1 [ + ] serial_mxc | | |-- serial@21e8000 serial 2 [ ] serial_mxc | | |-- serial@21ec000 serial 3 [ ] serial_mxc | | |-- serial@21f0000 serial 4 [ ] serial_mxc | | `-- serial@21f4000 video 0 [ + ] fsl_imx6q_ipu | `-- ipu@2400000 vidconsole 0 [ + ] vidconsole0 | `-- ipu@2400000.vidconsole0 led 0 [ ] gpio_led |-- leds led 1 [ ] gpio_led | |-- user1 led 2 [ ] gpio_led | |-- user2 led 3 [ ] gpio_led | `-- user3 regulator 0 [ ] regulator_fixed |-- regulator-1p0v regulator 1 [ + ] regulator_fixed |-- regulator-3p3v regulator 2 [ ] regulator_fixed |-- regulator-usb-h1-vbus regulator 3 [ ] regulator_fixed `-- regulator-usb-otg-vbus Ventana >
I'm not clear how for your board usb_ether is registered in the first place.
Best Regards,
Tim

Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice
Ventana > dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver thermal 0 [ ] imx_thermal |-- imx_thermal simple_bus 0 [ + ] simple_bus |-- soc pci 0 [ ] imx_pcie | |-- pcie@1ffc000 simple_bus 1 [ + ] simple_bus | |-- bus@2000000 simple_bus 2 [ ] simple_bus | | |-- spba-bus@2000000 serial 0 [ ] serial_mxc | | | `-- serial@2020000 gpio 0 [ + ] gpio_mxc | | |-- gpio@209c000 gpio 1 [ + ] gpio_mxc | | |-- gpio@20a0000 gpio 2 [ + ] gpio_mxc | | |-- gpio@20a4000 gpio 3 [ + ] gpio_mxc | | |-- gpio@20a8000 gpio 4 [ + ] gpio_mxc | | |-- gpio@20ac000 gpio 5 [ ] gpio_mxc | | |-- gpio@20b0000 gpio 6 [ ] gpio_mxc | | |-- gpio@20b4000 watchdog 0 [ + ] imx_wdt | | |-- wdog@20bc000 simple_bus 3 [ ] simple_bus | | |-- anatop@20c8000 simple_bus 4 [ ] simple_bus | | |-- snvs@20cc000 simple_bus 5 [ ] simple_bus | | |-- iomuxc-gpr@20e0000 pinctrl 0 [ + ] fsl_imx6q_iomuxc | | `-- iomuxc@20e0000 pinconfig 0 [ + ] pinconfig | | |-- enetgrp pinconfig 1 [ ] pinconfig | | |-- gpioledsgrp pinconfig 2 [ + ] pinconfig | | |-- i2c1grp pinconfig 3 [ + ] pinconfig | | |-- i2c2grp pinconfig 4 [ ] pinconfig | | |-- i2c3grp pinconfig 5 [ ] pinconfig | | |-- imugrp pinconfig 6 [ ] pinconfig | | |-- maggrp pinconfig 7 [ + ] pinconfig | | |-- pciegrp pinconfig 8 [ ] pinconfig | | |-- pmicgrp pinconfig 9 [ ] pinconfig | | |-- ppsgrp pinconfig 10 [ ] pinconfig | | |-- pwm2grp pinconfig 11 [ ] pinconfig | | |-- pwm3grp pinconfig 12 [ ] pinconfig | | |-- pwm4grp pinconfig 13 [ ] pinconfig | | |-- uart1grp pinconfig 14 [ + ] pinconfig | | |-- uart2grp pinconfig 15 [ ] pinconfig | | |-- uart3grp pinconfig 16 [ ] pinconfig | | |-- uart4grp pinconfig 17 [ ] pinconfig | | |-- uart5grp pinconfig 18 [ ] pinconfig | | |-- usbh1grp pinconfig 19 [ ] pinconfig | | |-- usbotggrp pinconfig 20 [ + ] pinconfig | | |-- usdhc3grp pinconfig 21 [ ] pinconfig | | |-- usdhc3grp100mhz pinconfig 22 [ ] pinconfig | | |-- usdhc3grp200mhz pinconfig 23 [ + ] pinconfig | | `-- wdoggrp simple_bus 6 [ + ] simple_bus | |-- bus@2100000 usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200 mmc 0 [ + ] fsl_esdhc | | |-- usdhc@2198000 blk 0 [ + ] mmc_blk | | | `-- usdhc@2198000.blk i2c 0 [ + ] i2c_mxc | | |-- i2c@21a0000 i2c_generi 0 [ + ] i2c_generic_chip_drv | | | |-- generic_51 i2c_generi 2 [ + ] i2c_generic_chip_drv | | | |-- generic_20 i2c_generi 3 [ + ] i2c_generic_chip_drv | | | |-- generic_29 i2c_generi 4 [ + ] i2c_generic_chip_drv | | | `-- generic_68 i2c 1 [ + ] i2c_mxc | | |-- i2c@21a4000 i2c_generi 1 [ + ] i2c_generic_chip_drv | | | `-- generic_3c i2c 2 [ ] i2c_mxc | | |-- i2c@21a8000 serial 1 [ + ] serial_mxc | | |-- serial@21e8000 serial 2 [ ] serial_mxc | | |-- serial@21ec000 serial 3 [ ] serial_mxc | | |-- serial@21f0000 serial 4 [ ] serial_mxc | | `-- serial@21f4000 video 0 [ + ] fsl_imx6q_ipu | `-- ipu@2400000 vidconsole 0 [ + ] vidconsole0 | `-- ipu@2400000.vidconsole0 led 0 [ ] gpio_led |-- leds led 1 [ ] gpio_led | |-- user1 led 2 [ ] gpio_led | |-- user2 led 3 [ ] gpio_led | `-- user3 regulator 0 [ ] regulator_fixed |-- regulator-1p0v regulator 1 [ + ] regulator_fixed |-- regulator-3p3v regulator 2 [ ] regulator_fixed |-- regulator-usb-h1-vbus regulator 3 [ ] regulator_fixed `-- regulator-usb-otg-vbus Ventana >
I'm not clear how for your board usb_ether is registered in the first place.
Best Regards,
Tim

On Tue, Feb 15, 2022 at 9:36 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice,
I added some debugging and found that 'bind usb 0 usb_ether' does the following: bind_by_class_index(class="usb" index=0 drv="usb_ether") uclass_get_by_name(name="usb") uclass_get_by_name_len(name="usb" len=3) ^^^ does a strncmp with name=usb and len=3 so it matches the first driver with a class name starting with 'usb' and in this case matches usb_mass_storage instead of 'usb'
Simon, this behavior comes from commit 4b030177b660 ("dm: core: Allow finding children / uclasses by partial name"). Why would device_find_child_by_name() want to use a substring match? I suppose if there is a valid reason for this such as your commit logs describe then those functions should directly call uclass_get_by_name_len() and uclass_get_by_name() should be doing a full name match correct?
Patrice, if I make uclass_get_by_name match the full string with the below patch then 'bind usb 0 usb_ether' indeed works as planned:
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a4d..33dbca544574 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -196,7 +196,16 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len)
enum uclass_id uclass_get_by_name(const char *name) { - return uclass_get_by_name_len(name, strlen(name)); + int i; + + for (i = 0; i < UCLASS_COUNT; i++) { + struct uclass_driver *uc_drv = lists_uclass_lookup(i); + + if (uc_drv && !strcmp(uc_drv->name, name)) + return i; + } + + return UCLASS_INVALID; }
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
I don't see the need to unbind 'ethernet' as you can select the active network device with 'ethact':
Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1 Ventana > ping 192.168.1.146 ^^^ but now we run into the issue Heiko discovered where the usb_gadget_register_driver() call from ether.c ends up removing usb and usb_ether and without his hack to return from device-remove if device is usb_ether we hang:
@@ -201,12 +202,16 @@ int device_remove(struct udevice *dev, uint flags) const struct driver *drv; int ret;
+printf("%s %s\n", __func__, dev->name); if (!dev) return -EINVAL;
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0;
+ if (!strncmp(dev->name, "usb_ether", 8)) + return 0; + /* * If the child returns EKEYREJECTED, continue. It just means that it * didn't match the flags.
Best Regards,
Tim

Hello Tim, Patrice,
On 15.02.22 19:28, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 9:36 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice,
I added some debugging and found that 'bind usb 0 usb_ether' does the following: bind_by_class_index(class="usb" index=0 drv="usb_ether") uclass_get_by_name(name="usb") uclass_get_by_name_len(name="usb" len=3) ^^^ does a strncmp with name=usb and len=3 so it matches the first driver with a class name starting with 'usb' and in this case matches usb_mass_storage instead of 'usb'
Ah!
Simon, this behavior comes from commit 4b030177b660 ("dm: core: Allow finding children / uclasses by partial name"). Why would device_find_child_by_name() want to use a substring match? I suppose if there is a valid reason for this such as your commit logs describe then those functions should directly call uclass_get_by_name_len() and uclass_get_by_name() should be doing a full name match correct?
Patrice, if I make uclass_get_by_name match the full string with the below patch then 'bind usb 0 usb_ether' indeed works as planned:
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a4d..33dbca544574 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -196,7 +196,16 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len)
enum uclass_id uclass_get_by_name(const char *name) {
return uclass_get_by_name_len(name, strlen(name));
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
if (uc_drv && !strcmp(uc_drv->name, name))
return i;
}
return UCLASS_INVALID;
}
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
I have to test, if this works for me too, but I have to find some time ...
I don't see the need to unbind 'ethernet' as you can select the active network device with 'ethact':
Yep, no need for unbinding...
Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1 Ventana > ping 192.168.1.146 ^^^ but now we run into the issue Heiko discovered where the usb_gadget_register_driver() call from ether.c ends up removing usb and usb_ether and without his hack to return from device-remove if device is usb_ether we hang:
@@ -201,12 +202,16 @@ int device_remove(struct udevice *dev, uint flags) const struct driver *drv; int ret;
+printf("%s %s\n", __func__, dev->name); if (!dev) return -EINVAL;
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0;
if (!strncmp(dev->name, "usb_ether", 8))
return 0;
/* * If the child returns EKEYREJECTED, continue. It just means that it * didn't match the flags.
Yes, we have to debug here deeper...
Thanks for digging in here!
bye, Heiko

Hi Tim
On 2/15/22 19:28, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 9:36 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice,
I added some debugging and found that 'bind usb 0 usb_ether' does the following: bind_by_class_index(class="usb" index=0 drv="usb_ether") uclass_get_by_name(name="usb") uclass_get_by_name_len(name="usb" len=3) ^^^ does a strncmp with name=usb and len=3 so it matches the first driver with a class name starting with 'usb' and in this case matches usb_mass_storage instead of 'usb'
Good catch ;-)
Simon, this behavior comes from commit 4b030177b660 ("dm: core: Allow finding children / uclasses by partial name"). Why would device_find_child_by_name() want to use a substring match? I suppose if there is a valid reason for this such as your commit logs describe then those functions should directly call uclass_get_by_name_len() and uclass_get_by_name() should be doing a full name match correct?
Patrice, if I make uclass_get_by_name match the full string with the below patch then 'bind usb 0 usb_ether' indeed works as planned:
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a4d..33dbca544574 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -196,7 +196,16 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len)
enum uclass_id uclass_get_by_name(const char *name) {
return uclass_get_by_name_len(name, strlen(name));
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
if (uc_drv && !strcmp(uc_drv->name, name))
return i;
}
return UCLASS_INVALID;
}
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
I don't see the need to unbind 'ethernet' as you can select the active network device with 'ethact':
Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1
Thanks for the tips, i didn't know it.
Ventana > ping 192.168.1.146 ^^^ but now we run into the issue Heiko discovered where the usb_gadget_register_driver() call from ether.c ends up removing usb and usb_ether and without his hack to return from device-remove if device is usb_ether we hang:
@@ -201,12 +202,16 @@ int device_remove(struct udevice *dev, uint flags) const struct driver *drv; int ret;
+printf("%s %s\n", __func__, dev->name); if (!dev) return -EINVAL;
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0;
if (!strncmp(dev->name, "usb_ether", 8))
return 0;
/* * If the child returns EKEYREJECTED, continue. It just means that it * didn't match the flags.
Best Regards,
Tim

On Wed, Feb 16, 2022 at 12:23 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 19:28, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 9:36 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice,
I added some debugging and found that 'bind usb 0 usb_ether' does the following: bind_by_class_index(class="usb" index=0 drv="usb_ether") uclass_get_by_name(name="usb") uclass_get_by_name_len(name="usb" len=3) ^^^ does a strncmp with name=usb and len=3 so it matches the first driver with a class name starting with 'usb' and in this case matches usb_mass_storage instead of 'usb'
Good catch ;-)
Simon, this behavior comes from commit 4b030177b660 ("dm: core: Allow finding children / uclasses by partial name"). Why would device_find_child_by_name() want to use a substring match? I suppose if there is a valid reason for this such as your commit logs describe then those functions should directly call uclass_get_by_name_len() and uclass_get_by_name() should be doing a full name match correct?
Patrice, if I make uclass_get_by_name match the full string with the below patch then 'bind usb 0 usb_ether' indeed works as planned:
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a4d..33dbca544574 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -196,7 +196,16 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len)
enum uclass_id uclass_get_by_name(const char *name) {
return uclass_get_by_name_len(name, strlen(name));
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
if (uc_drv && !strcmp(uc_drv->name, name))
return i;
}
return UCLASS_INVALID;
}
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
I don't see the need to unbind 'ethernet' as you can select the active network device with 'ethact':
Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1
Thanks for the tips, i didn't know it.
Ventana > ping 192.168.1.146 ^^^ but now we run into the issue Heiko discovered where the usb_gadget_register_driver() call from ether.c ends up removing usb and usb_ether and without his hack to return from device-remove if device is usb_ether we hang:
@@ -201,12 +202,16 @@ int device_remove(struct udevice *dev, uint flags) const struct driver *drv; int ret;
+printf("%s %s\n", __func__, dev->name); if (!dev) return -EINVAL;
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0;
if (!strncmp(dev->name, "usb_ether", 8))
return 0;
/* * If the child returns EKEYREJECTED, continue. It just means that it * didn't match the flags.
Simon,
Now that we have identified a fix needed to uclass_get_by_name to fix the dm bind command, can you comment on the other issue we have run into trying to use usb_ether?
Here's an example with some debugging: Ventana > net list device_probe ethernet@2188000 flags=0x1043 eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1 Ventana > ping 192.168.1.146 device_probe ethernet@2188000 flags=0x1043 device_probe usb_ether flags=0x4a device_probe usb@2184000 flags=0x1042 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x40 device_probe iomuxc@20e0000 flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x52 device_probe gpio@20a4000 flags=0x1043 device_probe root_driver flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 usb_eth_probe usb_ether usb_eth_start usb_setup_ehci_gadget usb_setup_ehci_gadget removing old device 'usb@2184000' device_remove usb@2184000 device_remove usb_ether usb_eth_stop usb_setup_ehci_gadget probing 'usb@2184000' device_probe usb@2184000 flags=0x42 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x1053 usb_setup_ehci_gadget done ^^^ hangs here - notice usb controller and the usb_ether child were removed then usb controller probed again (but not usb_ether)
fbeceb260232 ("dm: usb: Allow setting up a USB controller as a device/gadget") adds the usb_setup_ehci_gadget() function which removes the old USB controller device (and its usb_ether child) then probes only the USB controller leaving the usb_ether device un-probed. The commit log makes it sound like something isn't complete:
Some controllers support OTG (on-the-go) where they can operate as either host or device. The gadget layer in U-Boot supports this.
While this layer does not interact with driver model, we can provide a function which sets up the controller in the correct way. This way the code at least builds (although it likely will not work).
I'm not clear why the USB controller (and children) need to be removed here. If I comment out the removal and re-probe of the controller usb_ether then works fine:
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 27e2fc6fcd36..0882641b51b0 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -399,6 +399,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = uclass_find_first_device(UCLASS_USB, &dev); if (ret) return ret; +#if 0 ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; @@ -408,6 +409,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = device_probe(dev); if (ret) return ret; +#endif *ctlrp = dev_get_priv(dev);
return 0;
Why was it necessary to remove the USB controller and children and reprobe?
Best Regards,
Tim

Hi Tim,
On Wed, 16 Feb 2022 at 17:03, Tim Harvey tharvey@gateworks.com wrote:
On Wed, Feb 16, 2022 at 12:23 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 19:28, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 9:36 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/15/22 17:09, Tim Harvey wrote:
On Tue, Feb 15, 2022 at 5:29 AM Patrice CHOTARD patrice.chotard@foss.st.com wrote:
Hi Tim
On 2/10/22 18:04, Tim Harvey wrote: > Greetings, > > I'm trying to understand how to use the U-Boot bind command to bind > the usb_ether driver to the usb class to register a USB ethernet > gadget network device as referenced in: > commit 02291d83fdaaf ("doc: add bind/unbind command documentation") > commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device > to a driver from the command line") >
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name
root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
> I have enabled: > CONFIG_DM_USB=y > CONFIG_USB_GADGET=y > CONFIG_USB_ETHER=y > In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice,
In my case when I try to bind to usb_ether the device can not be found (as it is never registered in the first place): Ventana > unbind ethernet 0 Ventana > bind usb 0 usb_ether Cannot find device 0 of class usb
weird, because below, in the dm tree output, we can see :
usb 0 [ ] ehci_mx6 | | |-- usb@2184000 usb 1 [ ] ehci_mx6 | | |-- usb@2184200
so it should find a usb class device .....
Patrice,
I added some debugging and found that 'bind usb 0 usb_ether' does the following: bind_by_class_index(class="usb" index=0 drv="usb_ether") uclass_get_by_name(name="usb") uclass_get_by_name_len(name="usb" len=3) ^^^ does a strncmp with name=usb and len=3 so it matches the first driver with a class name starting with 'usb' and in this case matches usb_mass_storage instead of 'usb'
Good catch ;-)
Simon, this behavior comes from commit 4b030177b660 ("dm: core: Allow finding children / uclasses by partial name"). Why would device_find_child_by_name() want to use a substring match? I suppose if there is a valid reason for this such as your commit logs describe then those functions should directly call uclass_get_by_name_len() and uclass_get_by_name() should be doing a full name match correct?
Patrice, if I make uclass_get_by_name match the full string with the below patch then 'bind usb 0 usb_ether' indeed works as planned:
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a4d..33dbca544574 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -196,7 +196,16 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len)
enum uclass_id uclass_get_by_name(const char *name) {
return uclass_get_by_name_len(name, strlen(name));
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
if (uc_drv && !strcmp(uc_drv->name, name))
return i;
}
return UCLASS_INVALID;
}
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
I don't see the need to unbind 'ethernet' as you can select the active network device with 'ethact':
Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1
Thanks for the tips, i didn't know it.
Ventana > ping 192.168.1.146 ^^^ but now we run into the issue Heiko discovered where the usb_gadget_register_driver() call from ether.c ends up removing usb and usb_ether and without his hack to return from device-remove if device is usb_ether we hang:
@@ -201,12 +202,16 @@ int device_remove(struct udevice *dev, uint flags) const struct driver *drv; int ret;
+printf("%s %s\n", __func__, dev->name); if (!dev) return -EINVAL;
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0;
if (!strncmp(dev->name, "usb_ether", 8))
return 0;
/* * If the child returns EKEYREJECTED, continue. It just means that it * didn't match the flags.
Simon,
Now that we have identified a fix needed to uclass_get_by_name to fix the dm bind command, can you comment on the other issue we have run into trying to use usb_ether?
Here's an example with some debugging: Ventana > net list device_probe ethernet@2188000 flags=0x1043 eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1 Ventana > ping 192.168.1.146 device_probe ethernet@2188000 flags=0x1043 device_probe usb_ether flags=0x4a device_probe usb@2184000 flags=0x1042 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x40 device_probe iomuxc@20e0000 flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x52 device_probe gpio@20a4000 flags=0x1043 device_probe root_driver flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 usb_eth_probe usb_ether usb_eth_start usb_setup_ehci_gadget usb_setup_ehci_gadget removing old device 'usb@2184000' device_remove usb@2184000 device_remove usb_ether usb_eth_stop usb_setup_ehci_gadget probing 'usb@2184000' device_probe usb@2184000 flags=0x42 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x1053 usb_setup_ehci_gadget done ^^^ hangs here - notice usb controller and the usb_ether child were removed then usb controller probed again (but not usb_ether)
fbeceb260232 ("dm: usb: Allow setting up a USB controller as a device/gadget") adds the usb_setup_ehci_gadget() function which removes the old USB controller device (and its usb_ether child) then probes only the USB controller leaving the usb_ether device un-probed. The commit log makes it sound like something isn't complete:
Some controllers support OTG (on-the-go) where they can operate as either host or device. The gadget layer in U-Boot supports this. While this layer does not interact with driver model, we can provide a function which sets up the controller in the correct way. This way the code at least builds (although it likely will not work).
I'm not clear why the USB controller (and children) need to be removed here. If I comment out the removal and re-probe of the controller usb_ether then works fine:
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 27e2fc6fcd36..0882641b51b0 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -399,6 +399,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = uclass_find_first_device(UCLASS_USB, &dev); if (ret) return ret; +#if 0 ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; @@ -408,6 +409,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = device_probe(dev); if (ret) return ret; +#endif *ctlrp = dev_get_priv(dev);
return 0;
Why was it necessary to remove the USB controller and children and reprobe?
+Marek Vasut who may know more
I suspect that this is a bit of a hack to get the device running after it is swtiched from host to device mode?
The gadget side of things should really move to driver model.
Regards, SImon

On Sat, Aug 13, 2022 at 7:59 AM Simon Glass sjg@chromium.org wrote:
<snip>
Simon,
Now that we have identified a fix needed to uclass_get_by_name to fix the dm bind command, can you comment on the other issue we have run into trying to use usb_ether?
Here's an example with some debugging: Ventana > net list device_probe ethernet@2188000 flags=0x1043 eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active Ventana > bind usb 0 usb_ether Ventana > net list eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active eth1 : usb_ether 00:00:00:00:00:00 Ventana > setenv ethact eth1 Ventana > ping 192.168.1.146 device_probe ethernet@2188000 flags=0x1043 device_probe usb_ether flags=0x4a device_probe usb@2184000 flags=0x1042 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x40 device_probe iomuxc@20e0000 flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x52 device_probe gpio@20a4000 flags=0x1043 device_probe root_driver flags=0x1041 device_probe iomuxc@20e0000 flags=0x1041 usb_eth_probe usb_ether usb_eth_start usb_setup_ehci_gadget usb_setup_ehci_gadget removing old device 'usb@2184000' device_remove usb@2184000 device_remove usb_ether usb_eth_stop usb_setup_ehci_gadget probing 'usb@2184000' device_probe usb@2184000 flags=0x42 device_probe bus@2100000 flags=0x1051 device_probe usbotggrp flags=0x1041 device_probe regulator-usb-otg-vbus flags=0x1053 usb_setup_ehci_gadget done ^^^ hangs here - notice usb controller and the usb_ether child were removed then usb controller probed again (but not usb_ether)
fbeceb260232 ("dm: usb: Allow setting up a USB controller as a device/gadget") adds the usb_setup_ehci_gadget() function which removes the old USB controller device (and its usb_ether child) then probes only the USB controller leaving the usb_ether device un-probed. The commit log makes it sound like something isn't complete:
Some controllers support OTG (on-the-go) where they can operate as either host or device. The gadget layer in U-Boot supports this. While this layer does not interact with driver model, we can provide a function which sets up the controller in the correct way. This way the code at least builds (although it likely will not work).
I'm not clear why the USB controller (and children) need to be removed here. If I comment out the removal and re-probe of the controller usb_ether then works fine:
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 27e2fc6fcd36..0882641b51b0 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -399,6 +399,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = uclass_find_first_device(UCLASS_USB, &dev); if (ret) return ret; +#if 0 ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; @@ -408,6 +409,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) ret = device_probe(dev); if (ret) return ret; +#endif *ctlrp = dev_get_priv(dev);
return 0;
Why was it necessary to remove the USB controller and children and reprobe?
+Marek Vasut who may know more
I suspect that this is a bit of a hack to get the device running after it is swtiched from host to device mode?
The gadget side of things should really move to driver model.
Marek,
Do you know if there is a proper way of binding a usb_ether gadget driver at runtime so as to get USB over ethernet gadget support?
'bind usb 0 usb_ether' does bind the driver but when you try to use it the usb controller is removed which causes a failure.
Best Regards,
Tim

On 2/15/23 01:11, Tim Harvey wrote:
On Sat, Aug 13, 2022 at 7:59 AM Simon Glass sjg@chromium.org wrote:
<snip> >> >> Simon, >> >> Now that we have identified a fix needed to uclass_get_by_name to fix >> the dm bind command, can you comment on the other issue we have run >> into trying to use usb_ether? >> >> Here's an example with some debugging: >> Ventana > net list >> device_probe ethernet@2188000 flags=0x1043 >> eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active >> Ventana > bind usb 0 usb_ether >> Ventana > net list >> eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active >> eth1 : usb_ether 00:00:00:00:00:00 >> Ventana > setenv ethact eth1 >> Ventana > ping 192.168.1.146 >> device_probe ethernet@2188000 flags=0x1043 >> device_probe usb_ether flags=0x4a >> device_probe usb@2184000 flags=0x1042 >> device_probe bus@2100000 flags=0x1051 >> device_probe usbotggrp flags=0x40 >> device_probe iomuxc@20e0000 flags=0x1041 >> device_probe iomuxc@20e0000 flags=0x1041 >> device_probe regulator-usb-otg-vbus flags=0x52 >> device_probe gpio@20a4000 flags=0x1043 >> device_probe root_driver flags=0x1041 >> device_probe iomuxc@20e0000 flags=0x1041 >> usb_eth_probe usb_ether >> usb_eth_start >> usb_setup_ehci_gadget >> usb_setup_ehci_gadget removing old device 'usb@2184000' >> device_remove usb@2184000 >> device_remove usb_ether >> usb_eth_stop >> usb_setup_ehci_gadget probing 'usb@2184000' >> device_probe usb@2184000 flags=0x42 >> device_probe bus@2100000 flags=0x1051 >> device_probe usbotggrp flags=0x1041 >> device_probe regulator-usb-otg-vbus flags=0x1053 >> usb_setup_ehci_gadget done >> ^^^ hangs here - notice usb controller and the usb_ether child were >> removed then usb controller probed again (but not usb_ether) >> >> fbeceb260232 ("dm: usb: Allow setting up a USB controller as a >> device/gadget") adds the usb_setup_ehci_gadget() function which >> removes the old USB controller device (and its usb_ether child) then >> probes only the USB controller leaving the usb_ether device un-probed. >> The commit log makes it sound like something isn't complete: >> >> Some controllers support OTG (on-the-go) where they can operate as either >> host or device. The gadget layer in U-Boot supports this. >> >> While this layer does not interact with driver model, we can provide a >> function which sets up the controller in the correct way. This way the code >> at least builds (although it likely will not work). >> >> I'm not clear why the USB controller (and children) need to be removed >> here. If I comment out the removal and re-probe of the controller >> usb_ether then works fine: >> >> diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c >> index 27e2fc6fcd36..0882641b51b0 100644 >> --- a/drivers/usb/host/usb-uclass.c >> +++ b/drivers/usb/host/usb-uclass.c >> @@ -399,6 +399,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) >> ret = uclass_find_first_device(UCLASS_USB, &dev); >> if (ret) >> return ret; >> +#if 0 >> ret = device_remove(dev, DM_REMOVE_NORMAL); >> if (ret) >> return ret; >> @@ -408,6 +409,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) >> ret = device_probe(dev); >> if (ret) >> return ret; >> +#endif >> *ctlrp = dev_get_priv(dev); >> >> return 0; >> >> Why was it necessary to remove the USB controller and children and reprobe? > > +Marek Vasut who may know more > > I suspect that this is a bit of a hack to get the device running after > it is swtiched from host to device mode? > > The gadget side of things should really move to driver model. >
Marek,
Do you know if there is a proper way of binding a usb_ether gadget driver at runtime so as to get USB over ethernet gadget support?
'bind usb 0 usb_ether' does bind the driver but when you try to use it the usb controller is removed which causes a failure.
Look around patch
[PATCH v2] usb: gadget: ether: split start/stop from init/halt
which is a huge bag of subtle issues in its own right. I think it is moving in the right direction, except there seem to be additional bugs lurking around, which need to be addressed first instead of papering over them.

On Tue, Feb 14, 2023 at 4:31 PM Marek Vasut marex@denx.de wrote:
On 2/15/23 01:11, Tim Harvey wrote:
On Sat, Aug 13, 2022 at 7:59 AM Simon Glass sjg@chromium.org wrote:
<snip> >> >> Simon, >> >> Now that we have identified a fix needed to uclass_get_by_name to fix >> the dm bind command, can you comment on the other issue we have run >> into trying to use usb_ether? >> >> Here's an example with some debugging: >> Ventana > net list >> device_probe ethernet@2188000 flags=0x1043 >> eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active >> Ventana > bind usb 0 usb_ether >> Ventana > net list >> eth0 : ethernet@2188000 00:d0:12:f3:f2:f5 active >> eth1 : usb_ether 00:00:00:00:00:00 >> Ventana > setenv ethact eth1 >> Ventana > ping 192.168.1.146 >> device_probe ethernet@2188000 flags=0x1043 >> device_probe usb_ether flags=0x4a >> device_probe usb@2184000 flags=0x1042 >> device_probe bus@2100000 flags=0x1051 >> device_probe usbotggrp flags=0x40 >> device_probe iomuxc@20e0000 flags=0x1041 >> device_probe iomuxc@20e0000 flags=0x1041 >> device_probe regulator-usb-otg-vbus flags=0x52 >> device_probe gpio@20a4000 flags=0x1043 >> device_probe root_driver flags=0x1041 >> device_probe iomuxc@20e0000 flags=0x1041 >> usb_eth_probe usb_ether >> usb_eth_start >> usb_setup_ehci_gadget >> usb_setup_ehci_gadget removing old device 'usb@2184000' >> device_remove usb@2184000 >> device_remove usb_ether >> usb_eth_stop >> usb_setup_ehci_gadget probing 'usb@2184000' >> device_probe usb@2184000 flags=0x42 >> device_probe bus@2100000 flags=0x1051 >> device_probe usbotggrp flags=0x1041 >> device_probe regulator-usb-otg-vbus flags=0x1053 >> usb_setup_ehci_gadget done >> ^^^ hangs here - notice usb controller and the usb_ether child were >> removed then usb controller probed again (but not usb_ether) >> >> fbeceb260232 ("dm: usb: Allow setting up a USB controller as a >> device/gadget") adds the usb_setup_ehci_gadget() function which >> removes the old USB controller device (and its usb_ether child) then >> probes only the USB controller leaving the usb_ether device un-probed. >> The commit log makes it sound like something isn't complete: >> >> Some controllers support OTG (on-the-go) where they can operate as either >> host or device. The gadget layer in U-Boot supports this. >> >> While this layer does not interact with driver model, we can provide a >> function which sets up the controller in the correct way. This way the code >> at least builds (although it likely will not work). >> >> I'm not clear why the USB controller (and children) need to be removed >> here. If I comment out the removal and re-probe of the controller >> usb_ether then works fine: >> >> diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c >> index 27e2fc6fcd36..0882641b51b0 100644 >> --- a/drivers/usb/host/usb-uclass.c >> +++ b/drivers/usb/host/usb-uclass.c >> @@ -399,6 +399,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) >> ret = uclass_find_first_device(UCLASS_USB, &dev); >> if (ret) >> return ret; >> +#if 0 >> ret = device_remove(dev, DM_REMOVE_NORMAL); >> if (ret) >> return ret; >> @@ -408,6 +409,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) >> ret = device_probe(dev); >> if (ret) >> return ret; >> +#endif >> *ctlrp = dev_get_priv(dev); >> >> return 0; >> >> Why was it necessary to remove the USB controller and children and reprobe? > > +Marek Vasut who may know more > > I suspect that this is a bit of a hack to get the device running after > it is swtiched from host to device mode? > > The gadget side of things should really move to driver model. >
Marek,
Do you know if there is a proper way of binding a usb_ether gadget driver at runtime so as to get USB over ethernet gadget support?
'bind usb 0 usb_ether' does bind the driver but when you try to use it the usb controller is removed which causes a failure.
Look around patch
[PATCH v2] usb: gadget: ether: split start/stop from init/halt
which is a huge bag of subtle issues in its own right. I think it is moving in the right direction, except there seem to be additional bugs lurking around, which need to be addressed first instead of papering over them.
Marek,
Thanks for the reference - I'll take a look at Niel's patch. It doesn't address what I'm seeing but it seems to aim to resolve similar issues.
Best Regards,
Tim

Hi Tim
On 2/10/22 18:04, Tim Harvey wrote:
Greetings,
I'm trying to understand how to use the U-Boot bind command to bind the usb_ether driver to the usb class to register a USB ethernet gadget network device as referenced in: commit 02291d83fdaaf ("doc: add bind/unbind command documentation") commit 49c752c93a78 ("cmd: Add bind/unbind commands to bind a device to a driver from the command line")
For example, i made some trial on STM32MP1 platform:
At boot, we got :
STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset ..... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk ethernet 0 [ + ] eth_eqos | |-- ethernet@5800a000 eth_phy_ge 0 [ + ] eth_phy_generic_drv | | `-- ethernet-phy@0 usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 .....
As you can see, there is already an ethernet interface used. We unbind the ethernet interface before binding the usb_ether gadget to the usb class. First unbind the generic ethernet phy (eth_phy_generic_drv) and the ethernet driver (eth_eqos).
STM32MP> unbind eth_phy_generic 0 STM32MP> unbind ethernet 0 STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
Ethernet and phy driver are both unbinded. Now we can bind the usb_eher to the usb class
STM32MP> bind usb 0 usb_ether STM32MP> dm tree Class Index Probed Driver Name ----------------------------------------------------------- root 0 [ + ] root_driver root_driver firmware 0 [ ] psci |-- psci sysreset 0 [ ] psci-sysreset | `-- psci-sysreset .... blk 0 [ + ] mmc_blk | | `-- mmc@58005000.blk usb 0 [ ] ehci_generic | |-- usb@5800d000 ethernet 0 [ ] usb_ether | | `-- usb_ether video 0 [ ] stm32_display | |-- display-controller@5a001000 ....
usb_ether is now binded. As example, if you can then use some ethernet command as dhcp or ping :
STM32MP> dhcp using dwc2-udc, OUT ep2out-bulk IN ep1in-bulk STATUS ep3in-int MAC de:ad:be:ef:00:01 HOST MAC de:ad:be:ef:00:00 RNDIS ready high speed config #2: 2 mA, Ethernet Gadget, using RNDIS USB RNDIS network up! BOOTP broadcast 1
I have enabled: CONFIG_DM_USB=y CONFIG_USB_GADGET=y CONFIG_USB_ETHER=y
In my case i enabled also CONFIG_USB_ETH_RNDIS=y
Patrice
However the 'usb_ether' driver is never registered and thus doesn't appear in a 'dm tree' list and can't be bound to the usb controller.
With the help of Heiko I've found two ways to get the usb_ether driver to register:
dt-way:
- add of match in ether.c:
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 63d552bc8b..8e2a05a5af 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2690,10 +2690,16 @@ int usb_ether_init(void) return 0; }
+static const struct udevice_id usb_ether_ids[] = {
{ .compatible = "gadget,usb_ether" },
{ }
+};
U_BOOT_DRIVER(eth_usb) = { .name = "usb_ether", .id = UCLASS_ETH, .probe = usb_eth_probe,
.of_match = usb_ether_ids, .ops = &usb_eth_ops, .priv_auto_alloc_size = sizeof(struct ether_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata),
- then add it directly in your board u-boot.dts:
+&usbotg1 {
usb_ether0 {
compatible = "gadget,usb_ether";
status = "okay";
};
+};
The non-dt way:
- bind it manually in board code with:
{ struct udevice *dev; struct udevice *usb_dev; int ret;
ret = uclass_first_device(UCLASS_USB, &usb_dev); if (!usb_dev || ret) printf("%s: No USB device found\n", __func__); ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev); if (!dev || ret) printf("%s: usb - not able to bind usb_ether
device\n", __func__); }
- Note that this is the same code from usb_ether_init() but with
UCLASS_USB instead of UCLASS_USB_GADGET_GENERIC
What is the intended way to bind the usb_ether gadget device at runtime?
Additionally Heiko found that once bound and usb_ether is registered as a network device using a network command like ping/tftpboot calls usb_setup_ehci_gadget() which removes the USB driver ... and so also the child usb ethernet gadget device then re-probes only the usb driver and not the gadget thus fails. I compared this to how the 'ums' command works and that also removes the usb driver and child nodes but because ums isn't a gadget driver it doesn't get removed and works.
Best Regards,
Tim
participants (5)
-
Heiko Schocher
-
Marek Vasut
-
Patrice CHOTARD
-
Simon Glass
-
Tim Harvey