regressions.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Marcelo Roberto Jimenez <marcelo.jimenez@gmail.com>
To: regressions@lists.linux.dev,
	Nicolas Ferre <nicolas.ferre@microchip.com>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Ludovic Desroches <ludovic.desroches@microchip.com>,
	linux-arm-kernel@lists.infradead.org,
	Cristian Birsan <cristian.birsan@microchip.com>,
	linux-usb@vger.kernel.org,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Felipe Balbi <balbi@kernel.org>, Jonas Bonn <jonas@norrbonn.se>
Cc: Marcelo Roberto Jimenez <marcelo.jimenez@gmail.com>
Subject: [PATCH] usb: gadget: atmel: Revert regression in USB Gadget (atmel_usba_udc)
Date: Sat, 11 Dec 2021 15:36:50 -0300	[thread overview]
Message-ID: <20211211183650.12183-1-marcelo.jimenez@gmail.com> (raw)

The regression occurs on the second time a self powered gadget is
connected to the host. In this situation, the gadget no loger accepts
an address in the USB enumeration phase.

The regression has been introduced in
commit 70a7f8be8598 ("usb: gadget: atmel: support USB suspend")

Signed-off-by: Marcelo Roberto Jimenez <marcelo.jimenez@gmail.com>
---

Hi,

I have been using an ACME Arietta board (Microchip AT91SAM9G25 MPU, ARM9@400Mhz) for some years, and from time to time I need to do a kernel upgrade to fix issues or introduce new required features.

I have recently noticed a regression in the ethernet over USB Gadget. The system boots fine and when the device is first connected to a host it is recognized. But upon disconnection, the second time the device is connected to the host, it is no longer recognized. Of course, the gadget is self powered.

I did a "git bisect" and found that the patch introducing the regression is this:

commit 70a7f8be85986a3c2ffc7274c41b89552dfe2ad0
Author: Jonas Bonn <jonas@norrbonn.se>
Date:   Wed Feb 20 13:20:00 2019 +0100
    usb: gadget: atmel: support USB suspend
    This patch adds support for USB suspend to the Atmel UDC.

I understand that supporting USB suspend state is important for power consumption, but something in this patch has broken the hardware behavior, so my suggestion is to revert it until we can figure out what is going wrong.

I have tested and confirm that reverting that patch makes the issue go away.

On the host side, I can see some log messages that indicate that the USB gadget is not accepting a new address in the enumeration phase. The following log shows the successful initial connection and disconnection, and then the failed second connection attempt:

usb 1-4.3: new high-speed USB device number 85 using xhci_hcd
usb 1-4.3: New USB device found, idVendor=0525, idProduct=a4a2, bcdDevice= 5.10
usb 1-4.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-4.3: Product: RNDIS/Ethernet Gadget
usb 1-4.3: Manufacturer: Linux 5.10.80-linux4microchip-2021.10-rc2+ with atmel_usba_udc
cdc_subset: probe of 1-4.3:1.0 failed with error -22
cdc_ether 1-4.3:1.0 usb0: register 'cdc_ether' at usb-0000:00:14.0-4.3, CDC Ethernet Device, 4a:85:ff:68:fa:82
cdc_ether 1-4.3:1.0 enp0s20f0u4u3: renamed from usb0
usb 1-4.3: USB disconnect, device number 85
cdc_ether 1-4.3:1.0 enp0s20f0u4u3: unregister 'cdc_ether' usb-0000:00:14.0-4.3, CDC Ethernet Device
usb 1-4.3: new high-speed USB device number 86 using xhci_hcd
usb 1-4.3: device descriptor read/64, error -71
usb 1-4.3: device descriptor read/64, error -71
usb 1-4.3: new high-speed USB device number 87 using xhci_hcd
usb 1-4.3: device descriptor read/64, error -71
usb 1-4.3: device descriptor read/64, error -71
usb 1-4-port3: attempt power cycle
usb 1-4.3: new high-speed USB device number 88 using xhci_hcd
usb 1-4.3: Device not responding to setup address.
usb 1-4.3: Device not responding to setup address.
usb 1-4.3: device not accepting address 88, error -71
usb 1-4.3: new high-speed USB device number 89 using xhci_hcd
usb 1-4.3: Device not responding to setup address.
usb 1-4.3: Device not responding to setup address.
usb 1-4.3: device not accepting address 89, error -71
usb 1-4-port3: unable to enumerate USB device

The steps to reproduce are very easy:
1. Have both the host and the gadget turned on.
2. Connect the gadget to an USB port.
3. Disconnect the gadget from the USB port.
4. Reconnect the gadget to the USB port.
5. The gadget is no longer recognized.

On a side note, the ACME Arietta board DTD does not use VBUS sensing by default, although the hardware diagram shows a provision to do that using the PB16 GPIO. I have tried to enable that via DTD, but there seems to be a hardware design flaw (assuming that the intention was to provide VBUS sensing) due to a connection with the processor SHDN pin, which is from the processor shutdown controller, and the 3.3 volts voltage regulator enable pin. The problem is that even when the USB is disconnected, the voltage never gets near enough zero to trigger the GPIO interrupt, which I could verify that would indeed happen by a temporary short of the (unconnected) USB VBUS pin to the ground. That was only to say that even without VBUS sensing, the device has always worked, and that enabling VBUS sensing is not a viable solution in the current project.

Best regards,
Marcelo.


 drivers/usb/gadget/udc/atmel_usba_udc.c | 55 +++----------------------
 drivers/usb/gadget/udc/atmel_usba_udc.h |  1 -
 2 files changed, 6 insertions(+), 50 deletions(-)

diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 2b893bceea45..54cdea5cc31c 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1705,9 +1705,6 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
 	}
 }
 
-static int start_clock(struct usba_udc *udc);
-static void stop_clock(struct usba_udc *udc);
-
 static irqreturn_t usba_udc_irq(int irq, void *devid)
 {
 	struct usba_udc *udc = devid;
@@ -1722,13 +1719,10 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	DBG(DBG_INT, "irq, status=%#08x\n", status);
 
 	if (status & USBA_DET_SUSPEND) {
-		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND|USBA_WAKE_UP);
-		usba_int_enb_set(udc, USBA_WAKE_UP);
-		usba_int_enb_clear(udc, USBA_DET_SUSPEND);
-		udc->suspended = true;
 		toggle_bias(udc, 0);
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		usba_int_enb_set(udc, USBA_WAKE_UP);
 		udc->bias_pulse_needed = true;
-		stop_clock(udc);
 		DBG(DBG_BUS, "Suspend detected\n");
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN
 				&& udc->driver && udc->driver->suspend) {
@@ -1739,17 +1733,14 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	}
 
 	if (status & USBA_WAKE_UP) {
-		start_clock(udc);
 		toggle_bias(udc, 1);
 		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		usba_int_enb_clear(udc, USBA_WAKE_UP);
 		DBG(DBG_BUS, "Wake Up CPU detected\n");
 	}
 
 	if (status & USBA_END_OF_RESUME) {
-		udc->suspended = false;
 		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
-		usba_int_enb_clear(udc, USBA_WAKE_UP);
-		usba_int_enb_set(udc, USBA_DET_SUSPEND);
 		generate_bias_pulse(udc);
 		DBG(DBG_BUS, "Resume detected\n");
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN
@@ -1764,8 +1755,6 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	if (dma_status) {
 		int i;
 
-		usba_int_enb_set(udc, USBA_DET_SUSPEND);
-
 		for (i = 1; i <= USBA_NR_DMAS; i++)
 			if (dma_status & (1 << i))
 				usba_dma_irq(udc, &udc->usba_ep[i]);
@@ -1775,8 +1764,6 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	if (ep_status) {
 		int i;
 
-		usba_int_enb_set(udc, USBA_DET_SUSPEND);
-
 		for (i = 0; i < udc->num_ep; i++)
 			if (ep_status & (1 << i)) {
 				if (ep_is_control(&udc->usba_ep[i]))
@@ -1790,9 +1777,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 		struct usba_ep *ep0, *ep;
 		int i;
 
-		usba_writel(udc, INT_CLR,
-			USBA_END_OF_RESET|USBA_END_OF_RESUME
-			|USBA_DET_SUSPEND|USBA_WAKE_UP);
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
 		generate_bias_pulse(udc);
 		reset_all_endpoints(udc);
 
@@ -1819,11 +1804,6 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
 		usba_ep_writel(ep0, CTL_ENB,
 				USBA_EPT_ENABLE | USBA_RX_SETUP);
-
-		/* If we get reset while suspended... */
-		udc->suspended = false;
-		usba_int_enb_clear(udc, USBA_WAKE_UP);
-
 		usba_int_enb_set(udc, USBA_BF(EPT_INT, 1) |
 				      USBA_DET_SUSPEND | USBA_END_OF_RESUME);
 
@@ -1896,19 +1876,9 @@ static int usba_start(struct usba_udc *udc)
 	if (ret)
 		return ret;
 
-	if (udc->suspended)
-		return 0;
-
 	spin_lock_irqsave(&udc->lock, flags);
 	toggle_bias(udc, 1);
 	usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-	/* Clear all requested and pending interrupts... */
-	usba_writel(udc, INT_ENB, 0);
-	udc->int_enb_cache = 0;
-	usba_writel(udc, INT_CLR,
-		USBA_END_OF_RESET|USBA_END_OF_RESUME
-		|USBA_DET_SUSPEND|USBA_WAKE_UP);
-	/* ...and enable just 'reset' IRQ to get us started */
 	usba_int_enb_set(udc, USBA_END_OF_RESET);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1919,9 +1889,6 @@ static void usba_stop(struct usba_udc *udc)
 {
 	unsigned long flags;
 
-	if (udc->suspended)
-		return;
-
 	spin_lock_irqsave(&udc->lock, flags);
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	reset_all_endpoints(udc);
@@ -1949,7 +1916,6 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
 		if (vbus) {
 			usba_start(udc);
 		} else {
-			udc->suspended = false;
 			if (udc->driver->disconnect)
 				udc->driver->disconnect(&udc->gadget);
 
@@ -2028,7 +1994,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
 	if (udc->vbus_pin)
 		disable_irq(gpiod_to_irq(udc->vbus_pin));
 
-	udc->suspended = false;
 	usba_stop(udc);
 
 	udc->driver = NULL;
@@ -2393,7 +2358,6 @@ static int usba_udc_suspend(struct device *dev)
 	mutex_lock(&udc->vbus_mutex);
 
 	if (!device_may_wakeup(dev)) {
-		udc->suspended = false;
 		usba_stop(udc);
 		goto out;
 	}
@@ -2403,13 +2367,10 @@ static int usba_udc_suspend(struct device *dev)
 	 * to request vbus irq, assuming always on.
 	 */
 	if (udc->vbus_pin) {
-		/* FIXME: right to stop here...??? */
 		usba_stop(udc);
 		enable_irq_wake(gpiod_to_irq(udc->vbus_pin));
 	}
 
-	enable_irq_wake(udc->irq);
-
 out:
 	mutex_unlock(&udc->vbus_mutex);
 	return 0;
@@ -2423,12 +2384,8 @@ static int usba_udc_resume(struct device *dev)
 	if (!udc->driver)
 		return 0;
 
-	if (device_may_wakeup(dev)) {
-		if (udc->vbus_pin)
-			disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
-
-		disable_irq_wake(udc->irq);
-	}
+	if (device_may_wakeup(dev) && udc->vbus_pin)
+		disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
 
 	/* If Vbus is present, enable the controller and wait for reset */
 	mutex_lock(&udc->vbus_mutex);
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h
index 620472f218bc..b44873148393 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
@@ -343,7 +343,6 @@ struct usba_udc {
 	struct usba_ep *usba_ep;
 	bool bias_pulse_needed;
 	bool clocked;
-	bool suspended;
 	bool ep_prealloc;
 
 	u16 devstatus;
-- 
2.30.2


             reply	other threads:[~2021-12-11 18:37 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-11 18:36 Marcelo Roberto Jimenez [this message]
2021-12-12  9:48 ` [PATCH] usb: gadget: atmel: Revert regression in USB Gadget (atmel_usba_udc) Thorsten Leemhuis
2022-01-26 12:20   ` Greg Kroah-Hartman
2022-01-26 12:54     ` Thorsten Leemhuis
     [not found]     ` <CACjc_5o9eO5YTVt4jE7v1E9nirCwFMc1=Ub-jXSFCg1_8A2M-A@mail.gmail.com>
2022-01-26 13:43       ` Marcelo Roberto Jimenez
2021-12-13 10:02 ` Jonas Bonn
     [not found]   ` <CACjc_5pHbLStniQnOVLDW5iLbKn8ovePuQsFFqeEnQPSSYxJoQ@mail.gmail.com>
2021-12-15 13:04     ` Cristian.Birsan
2021-12-15 15:54       ` Marcelo Roberto Jimenez
2021-12-20 14:50         ` Greg Kroah-Hartman
2021-12-22 18:33           ` Cristian.Birsan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211211183650.12183-1-marcelo.jimenez@gmail.com \
    --to=marcelo.jimenez@gmail.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=balbi@kernel.org \
    --cc=cristian.birsan@microchip.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jonas@norrbonn.se \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=ludovic.desroches@microchip.com \
    --cc=nicolas.ferre@microchip.com \
    --cc=regressions@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).