diff mbox series

usb: gadget: ether: split start/stop from init/halt

Message ID 20221212152945.1870385-2-lusus@denx.de
State Superseded
Delegated to: Marek Vasut
Headers show
Series usb: gadget: ether: split start/stop from init/halt | expand

Commit Message

Niel Fourie Dec. 12, 2022, 3:29 p.m. UTC
Split out _usb_eth_start() from _usb_eth_init() and
usb_eth_stop() from _usb_eth_halt(). Now _usb_eth_init() only
initialises and registers the gadget device, which _usb_eth_halt()
reverses, and together are used for probing and removing the
device. The _usb_eth_start() and _usb_eth_stop() functions connect
and disconnect the gadget as expected by the start()/stop()
callbacks.

Previously the gadget device was probed on every start() and
removed on every stop(), which is inconsistent with other DM_ETH
drivers. For non-DM gadget drivers the old behaviour has been
retained.

Signed-off-by: Niel Fourie <lusus@denx.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Lukasz Majewski <lukma@denx.de>
Cc: Ramon Fried <rfried.dev@gmail.com>
---
 drivers/usb/gadget/ether.c | 58 +++++++++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 13 deletions(-)

Comments

Marek Vasut Dec. 12, 2022, 4:46 p.m. UTC | #1
On 12/12/22 16:29, Niel Fourie wrote:
> Split out _usb_eth_start() from _usb_eth_init() and
> usb_eth_stop() from _usb_eth_halt(). Now _usb_eth_init() only
> initialises and registers the gadget device, which _usb_eth_halt()
> reverses, and together are used for probing and removing the
> device. The _usb_eth_start() and _usb_eth_stop() functions connect
> and disconnect the gadget as expected by the start()/stop()
> callbacks.
> 
> Previously the gadget device was probed on every start() and
> removed on every stop(), which is inconsistent with other DM_ETH
> drivers. For non-DM gadget drivers the old behaviour has been
> retained.

Does this mean the udevice pointer and associated private date are 
retained during the entire operation of the USB gadget , i.e. even 
between stop/start cycles ?
Niel Fourie Dec. 13, 2022, 11:01 a.m. UTC | #2
Hi Marek,

On 12/12/2022 17:46, Marek Vasut wrote:
> On 12/12/22 16:29, Niel Fourie wrote:
>> Split out _usb_eth_start() from _usb_eth_init() and
>> usb_eth_stop() from _usb_eth_halt(). Now _usb_eth_init() only
>> initialises and registers the gadget device, which _usb_eth_halt()
>> reverses, and together are used for probing and removing the
>> device. The _usb_eth_start() and _usb_eth_stop() functions connect
>> and disconnect the gadget as expected by the start()/stop()
>> callbacks.
>>
>> Previously the gadget device was probed on every start() and
>> removed on every stop(), which is inconsistent with other DM_ETH
>> drivers. For non-DM gadget drivers the old behaviour has been
>> retained.
> 
> Does this mean the udevice pointer and associated private date are 
> retained during the entire operation of the USB gadget , i.e. even 
> between stop/start cycles ?

In the DM_ETH case, yes. The drivers/devices remain registered the whole 
time between _usb_eth_init() and _usb_eth_halt(), and the need for 
revalidating the private data pointer falls away as was done in my 
previous patch.

I tested this on imx8mp with the dwc3 gadget driver, and the data 
structures, specifically the private data, remained intact from probe() 
until remove(). I also tested that probing again after removal works as 
expected.

I tested the non-DM_ETH case on an iMX6 Phytec Mira (pcm058) which uses 
the ci_udc.c driver, which appears to not support DM_ETH yet. In that 
case the gadget drivers get registered/unregistered in 
usb_eth_init()/usb_eth_halt().

The legacy non-DM_ETH implementation uses init()/halt() similarly to 
start()/stop() in the DM_ETH implementation, but had no further 
equivalent for probe()/remove() in struct eth_device. When the Ethernet 
gadget was ported to DM_ETH, this difference most likely lead to the 
existing implementation.

I unfortunately did not have other devices on hand to test against, so I 
am hoping that there are no other surprises.

Best regards,
Niel Fourie
Marek Vasut Dec. 15, 2022, 5:58 a.m. UTC | #3
On 12/13/22 12:01, Niel Fourie wrote:
> Hi Marek,

Hi,

> On 12/12/2022 17:46, Marek Vasut wrote:
>> On 12/12/22 16:29, Niel Fourie wrote:
>>> Split out _usb_eth_start() from _usb_eth_init() and
>>> usb_eth_stop() from _usb_eth_halt(). Now _usb_eth_init() only
>>> initialises and registers the gadget device, which _usb_eth_halt()
>>> reverses, and together are used for probing and removing the
>>> device. The _usb_eth_start() and _usb_eth_stop() functions connect
>>> and disconnect the gadget as expected by the start()/stop()
>>> callbacks.
>>>
>>> Previously the gadget device was probed on every start() and
>>> removed on every stop(), which is inconsistent with other DM_ETH
>>> drivers. For non-DM gadget drivers the old behaviour has been
>>> retained.
>>
>> Does this mean the udevice pointer and associated private date are 
>> retained during the entire operation of the USB gadget , i.e. even 
>> between stop/start cycles ?
> 
> In the DM_ETH case, yes. The drivers/devices remain registered the whole 
> time between _usb_eth_init() and _usb_eth_halt(), and the need for 
> revalidating the private data pointer falls away as was done in my 
> previous patch.

Perfect.

> I tested this on imx8mp with the dwc3 gadget driver, and the data 
> structures, specifically the private data, remained intact from probe() 
> until remove(). I also tested that probing again after removal works as 
> expected.

Excellent.

[...]

Should "[PATCH v2] net: eth-uclass: revalidate priv after stop() in 
eth_halt()" be dropped ? It seems this patch fully replaces it.
Niel Fourie Dec. 16, 2022, 4:35 p.m. UTC | #4
Hi Marek,

On 2022-12-15 06:58, Marek Vasut wrote:
> On 12/13/22 12:01, Niel Fourie wrote:
>> Hi Marek,
> 
> Hi,
> 
>> On 12/12/2022 17:46, Marek Vasut wrote:
>>> On 12/12/22 16:29, Niel Fourie wrote:
>>>> Split out _usb_eth_start() from _usb_eth_init() and
>>>> usb_eth_stop() from _usb_eth_halt(). Now _usb_eth_init() only
>>>> initialises and registers the gadget device, which _usb_eth_halt()
>>>> reverses, and together are used for probing and removing the
>>>> device. The _usb_eth_start() and _usb_eth_stop() functions connect
>>>> and disconnect the gadget as expected by the start()/stop()
>>>> callbacks.
>>>> 
>>>> Previously the gadget device was probed on every start() and
>>>> removed on every stop(), which is inconsistent with other DM_ETH
>>>> drivers. For non-DM gadget drivers the old behaviour has been
>>>> retained.
>>> 
>>> Does this mean the udevice pointer and associated private date are 
>>> retained during the entire operation of the USB gadget , i.e. even 
>>> between stop/start cycles ?
>> 
>> In the DM_ETH case, yes. The drivers/devices remain registered the 
>> whole time between _usb_eth_init() and _usb_eth_halt(), and the need 
>> for revalidating the private data pointer falls away as was done in my 
>> previous patch.
> 
> Perfect.
> 
>> I tested this on imx8mp with the dwc3 gadget driver, and the data 
>> structures, specifically the private data, remained intact from 
>> probe() until remove(). I also tested that probing again after removal 
>> works as expected.
> 
> Excellent.
> 
> [...]
> 
> Should "[PATCH v2] net: eth-uclass: revalidate priv after stop() in
> eth_halt()" be dropped ? It seems this patch fully replaces it.

That old patch only exists for in case there were showstopper issues 
with the new patch which I missed, or as a stopgap if major changes were 
needed first. I did my best to test the new patch on the hardware I 
have, but if any other gadget drivers were to misbehave, I would not 
know about it, for example. But if you are happy with this new patch, 
that old patch could gladly be dropped.

Best regards,
Niel Fourie
Marek Vasut Dec. 18, 2022, 1:50 a.m. UTC | #5
On 12/12/22 16:29, Niel Fourie wrote:

[...]

> +static int _usb_eth_start(struct ether_priv *priv)
> +{
> +	unsigned long ts;
> +	unsigned long timeout = USB_CONNECT_TIMEOUT;
> +	struct eth_dev *dev = &priv->ethdev;
> +
> +	if (!dev->gadget)
> +		return -1;
>   
> +	dev->network_started = 0;

Will this work on systems which already have netconsole active ? I think 
this would break the netconsole connection, since the network would be 
reinitialized, won't it ?

I would expect this assignment to be in _init and _stop , not in _start 
callback.

But I wonder whether the current ethernet uclass interface running code 
does not make the entire network_started mechanism obsolete. See the 
patch which you referenced previously in related patch:

fa795f45254 ("net: eth-uclass: avoid running start() twice without stop()")

>   	packet_received = 0;
>   	packet_sent = 0;
>   
> -	gadget = dev->gadget;
> -	usb_gadget_connect(gadget);
> +	usb_gadget_connect(dev->gadget);
>   
>   	if (env_get("cdc_connect_timeout"))
>   		timeout = dectoul(env_get("cdc_connect_timeout"), NULL) * CONFIG_SYS_HZ;

[...]

> @@ -2493,9 +2509,13 @@ static void _usb_eth_halt(struct ether_priv *priv)
>   #ifndef CONFIG_DM_ETH
>   static int usb_eth_init(struct eth_device *netdev, struct bd_info *bd)
>   {
> +	int ret;
>   	struct ether_priv *priv = (struct ether_priv *)netdev->priv;

Keep the vars sorted as reverse xmas tree please, i.e. int ret goes 
below the struct .

[...]
Marek Vasut Dec. 18, 2022, 1:51 a.m. UTC | #6
On 12/16/22 17:35, lusus@denx.de wrote:
> Hi Marek,

Hi,

[...]

>> Should "[PATCH v2] net: eth-uclass: revalidate priv after stop() in
>> eth_halt()" be dropped ? It seems this patch fully replaces it.
> 
> That old patch only exists for in case there were showstopper issues 
> with the new patch which I missed, or as a stopgap if major changes were 
> needed first. I did my best to test the new patch on the hardware I 
> have, but if any other gadget drivers were to misbehave, I would not 
> know about it, for example. But if you are happy with this new patch, 
> that old patch could gladly be dropped.

The new patch is by far preferable. If you can sort out the 
network_started comment, I would like to pick this via usb/next.

Thanks
Niel Fourie Jan. 20, 2023, 5:26 p.m. UTC | #7
Hi Marek

On 18/12/2022 02:51, Marek Vasut wrote:
> On 12/16/22 17:35, lusus@denx.de wrote:
>> Hi Marek,
> 
> Hi,
> 
> [...]
> 
>>> Should "[PATCH v2] net: eth-uclass: revalidate priv after stop() in
>>> eth_halt()" be dropped ? It seems this patch fully replaces it.
>>
>> That old patch only exists for in case there were showstopper issues 
>> with the new patch which I missed, or as a stopgap if major changes 
>> were needed first. I did my best to test the new patch on the hardware 
>> I have, but if any other gadget drivers were to misbehave, I would not 
>> know about it, for example. But if you are happy with this new patch, 
>> that old patch could gladly be dropped.
> 
> The new patch is by far preferable. If you can sort out the 
> network_started comment, I would like to pick this via usb/next.

I did some more testing and I found that keeping network_started as it 
is works best, so I did not change it for v2 of this patch.

Unfortunately during local testing (on imx8mp), I uncovered an issue in 
the dwc3 gadget driver causing it to hang. I have a workaround, but I am 
still looking into fixing the root cause, and that would have to be 
fixed in a separate patch series.

Similar issues might also still crop up with other gadget drivers.

Best regards,
Niel Fourie
Marek Vasut Jan. 20, 2023, 6:42 p.m. UTC | #8
On 1/20/23 18:26, Niel Fourie wrote:
> Hi Marek

Hi,

> On 18/12/2022 02:51, Marek Vasut wrote:
>> On 12/16/22 17:35, lusus@denx.de wrote:
>>> Hi Marek,
>>
>> Hi,
>>
>> [...]
>>
>>>> Should "[PATCH v2] net: eth-uclass: revalidate priv after stop() in
>>>> eth_halt()" be dropped ? It seems this patch fully replaces it.
>>>
>>> That old patch only exists for in case there were showstopper issues 
>>> with the new patch which I missed, or as a stopgap if major changes 
>>> were needed first. I did my best to test the new patch on the 
>>> hardware I have, but if any other gadget drivers were to misbehave, I 
>>> would not know about it, for example. But if you are happy with this 
>>> new patch, that old patch could gladly be dropped.
>>
>> The new patch is by far preferable. If you can sort out the 
>> network_started comment, I would like to pick this via usb/next.
> 
> I did some more testing and I found that keeping network_started as it 
> is works best, so I did not change it for v2 of this patch.

This doesn't answer the question whether netconsole connection gets 
broken or not by this change, it think the netconsole connection would 
get broken and that's not good.

> Unfortunately during local testing (on imx8mp), I uncovered an issue in 
> the dwc3 gadget driver causing it to hang. I have a workaround, but I am 
> still looking into fixing the root cause, and that would have to be 
> fixed in a separate patch series.

You can send the workaround as [RFC][PATCH] so it wouldn't get included 
accidentally and possibly CC Peng Fan from NXP.

> Similar issues might also still crop up with other gadget drivers.

[...]
diff mbox series

Patch

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 43aec7ffa70..a75b4eeb5bb 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2305,15 +2305,11 @@  fail:
 
 /*-------------------------------------------------------------------------*/
 static void _usb_eth_halt(struct ether_priv *priv);
+static void _usb_eth_stop(struct ether_priv *priv);
 
 static int _usb_eth_init(struct ether_priv *priv)
 {
-	struct eth_dev *dev = &priv->ethdev;
-	struct usb_gadget *gadget;
-	unsigned long ts;
 	int ret;
-	unsigned long timeout = USB_CONNECT_TIMEOUT;
-
 	ret = usb_gadget_initialize(0);
 	if (ret)
 		return ret;
@@ -2353,14 +2349,26 @@  static int _usb_eth_init(struct ether_priv *priv)
 	priv->eth_driver.resume		= eth_resume;
 	if (usb_gadget_register_driver(&priv->eth_driver) < 0)
 		goto fail;
+	return 0;
+fail:
+	_usb_eth_halt(priv);
+	return -1;
+}
 
-	dev->network_started = 0;
+static int _usb_eth_start(struct ether_priv *priv)
+{
+	unsigned long ts;
+	unsigned long timeout = USB_CONNECT_TIMEOUT;
+	struct eth_dev *dev = &priv->ethdev;
+
+	if (!dev->gadget)
+		return -1;
 
+	dev->network_started = 0;
 	packet_received = 0;
 	packet_sent = 0;
 
-	gadget = dev->gadget;
-	usb_gadget_connect(gadget);
+	usb_gadget_connect(dev->gadget);
 
 	if (env_get("cdc_connect_timeout"))
 		timeout = dectoul(env_get("cdc_connect_timeout"), NULL) * CONFIG_SYS_HZ;
@@ -2378,6 +2386,7 @@  static int _usb_eth_init(struct ether_priv *priv)
 	rx_submit(dev, dev->rx_req, 0);
 	return 0;
 fail:
+	_usb_eth_stop(priv);
 	_usb_eth_halt(priv);
 	return -1;
 }
@@ -2457,11 +2466,10 @@  static int _usb_eth_recv(struct ether_priv *priv)
 	return 0;
 }
 
-static void _usb_eth_halt(struct ether_priv *priv)
+static void _usb_eth_stop(struct ether_priv *priv)
 {
 	struct eth_dev *dev = &priv->ethdev;
 
-	/* If the gadget not registered, simple return */
 	if (!dev->gadget)
 		return;
 
@@ -2485,6 +2493,14 @@  static void _usb_eth_halt(struct ether_priv *priv)
 		usb_gadget_handle_interrupts(0);
 		dev->network_started = 0;
 	}
+}
+
+static void _usb_eth_halt(struct ether_priv *priv)
+{
+	struct eth_dev *dev = &priv->ethdev;
+
+	if (!dev->gadget)
+		return;
 
 	usb_gadget_unregister_driver(&priv->eth_driver);
 	usb_gadget_release(0);
@@ -2493,9 +2509,13 @@  static void _usb_eth_halt(struct ether_priv *priv)
 #ifndef CONFIG_DM_ETH
 static int usb_eth_init(struct eth_device *netdev, struct bd_info *bd)
 {
+	int ret;
 	struct ether_priv *priv = (struct ether_priv *)netdev->priv;
 
-	return _usb_eth_init(priv);
+	ret = _usb_eth_init(priv);
+	if (!ret)
+		ret = _usb_eth_start(priv);
+	return ret;
 }
 
 static int usb_eth_send(struct eth_device *netdev, void *packet, int length)
@@ -2536,6 +2556,7 @@  void usb_eth_halt(struct eth_device *netdev)
 {
 	struct ether_priv *priv = (struct ether_priv *)netdev->priv;
 
+	_usb_eth_stop(priv);
 	_usb_eth_halt(priv);
 }
 
@@ -2559,7 +2580,7 @@  static int usb_eth_start(struct udevice *dev)
 {
 	struct ether_priv *priv = dev_get_priv(dev);
 
-	return _usb_eth_init(priv);
+	return _usb_eth_start(priv);
 }
 
 static int usb_eth_send(struct udevice *dev, void *packet, int length)
@@ -2609,7 +2630,7 @@  static void usb_eth_stop(struct udevice *dev)
 {
 	struct ether_priv *priv = dev_get_priv(dev);
 
-	_usb_eth_halt(priv);
+	_usb_eth_stop(priv);
 }
 
 static int usb_eth_probe(struct udevice *dev)
@@ -2623,6 +2644,16 @@  static int usb_eth_probe(struct udevice *dev)
 	get_ether_addr(CONFIG_USBNET_DEV_ADDR, pdata->enetaddr);
 	eth_env_set_enetaddr("usbnet_devaddr", pdata->enetaddr);
 
+	return _usb_eth_init(priv);
+
+	return 0;
+}
+
+static int usb_eth_remove(struct udevice *dev)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+
+	_usb_eth_halt(priv);
 	return 0;
 }
 
@@ -2658,6 +2689,7 @@  U_BOOT_DRIVER(eth_usb) = {
 	.name	= "usb_ether",
 	.id	= UCLASS_ETH,
 	.probe	= usb_eth_probe,
+	.remove = usb_eth_remove,
 	.ops	= &usb_eth_ops,
 	.priv_auto	= sizeof(struct ether_priv),
 	.plat_auto	= sizeof(struct eth_pdata),