All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet
@ 2020-07-24 21:50 Jason Wessel
  2020-07-24 21:50 ` [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left Jason Wessel
                   ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

I would like to get these patches merged for the next release, but
there has been no movement on some of them in over a month.  I would
fix any problems with the patches, but I am not aware of any.  The
patch set has been tested on all the generations of the raspberry pi
hardware and qemu and passed the travis ci checks.

-- Travis CI checks --

Pull Request #35 Rpi master

The commit 57805f2270c4 ("net: bcmgenet: Don't set ID_MODE_DIS when
not using RGMII") needed to be extended for the case of using the
rgmii-rxid. The latest version of the Rasbperry Pi4 dtb files for the
5.4 now specify the rgmii-rxid.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>

Commit 9a21770 #35: Rpi master Branch master 

-- End Travis CI checks --

Prior to this patch set, I had just a small number of USB keyboards
function properly with the Rasbpberry Pi boards.  Nearly every
composite USB keyboard/mouse I had access to including the Raritan
IP/KVM devices would not initialize properly.

v1-consoldiated:
  - Consolidated all the usb and ethernet patches into a single set
  - No changes to any of the patches

v1:
  - Testing completed against all generations of raspberry pi boards
  - check patch warnings add errors have been fixed

rfc v3:
  - Add in patch 6
  - Finally got the GearHead keyboard + mouse composite USB device working

rfc v2: 
  - Minor cleanups to patches 1-3 based on prior review
  - Patch 4 & 5 are new to fix various xhchi crashes
    while having additional devices plugged in along with
    booting off the usb port.  The nonblocking mode turned
    out to be somewhat complex.

rfc v1:

The original purpose of the patch set was to fix problems with the USB
keyboard support with the rpi4.  The generic xhci code lacks a non
blocking call to read an event.  This causes major problems for the
sleep function as well as for ethernet downloads where a keyboard poll
for interrupting the download blocks for 5 seconds.

----------------------------------------------------------------
The following changes since commit fee68b98fe3890631a9bdf8f8db328179011ee3f:

  Merge tag 'efi-2020-10-rc1-4' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi (2020-07-16 16:35:15 -0400)

are available in the Git repository at:

  https://github.com/jwessel/u-boot 

for you to fetch changes up to fb5b89c4f2aa2a95c4024b156099c838d1199bd0:

  bcmgenet: Add support for rgmii-rxid (2020-07-17 06:35:11 -0700)

----------------------------------------------------------------
Jason Wessel (9):
      fs/fat/fat.c: Do not perform zero block reads if there are no blocks left
      xhci: Add polling support for USB keyboards
      usb_kbd: succeed even if no interrupt is pending
      common/usb.c: Work around keyboard reporting "USB device not accepting new address"
      xhci-ring.c: Add the poll_pend state to properly abort transactions
      xhci-ring: Fix crash when issuing "usb reset"
      usb.c: Add a retry in the usb_prepare_device()
      bcmgenet: fix DMA buffer management
      bcmgenet: Add support for rgmii-rxid

 common/usb.c                 |  16 ++++--
 common/usb_kbd.c             |   4 +-
 drivers/net/bcmgenet.c       |  20 +++----
 drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++----------
 drivers/usb/host/xhci.c      |  11 ++--
 fs/fat/fat.c                 |   5 +-
 include/usb/xhci.h           |   5 +-
 7 files changed, 136 insertions(+), 48 deletions(-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-25 15:27   ` Heinrich Schuchardt
  2020-07-24 21:50 ` [PATCH 2/9] xhci: Add polling support for USB keyboards Jason Wessel
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

While using u-boot with qemu's virtio driver I stumbled across a
problem reading files less than sector size.  On the real hardware the
block reader seems ok with reading zero blocks, and while we could fix
the virtio host side of qemu to deal with a zero block read instead of
crashing, the u-boot fat driver should not be doing zero block reads
in the first place.  If you ask hardware to read zero blocks you are
just going to get zero data.  There may also be other hardware that
responds similarly to the virtio interface so this is worth fixing.

Without the patch I get the following and have to restart qemu because
it dies.
---------------------------------
=> fatls virtio 0:1
       30   cmdline.txt
=> fatload virtio 0:1 ${loadaddr} cmdline.txt
qemu-system-aarch64: virtio: zero sized buffers are not allowed
---------------------------------

With the patch I get the expected results.
---------------------------------
=> fatls virtio 0:1
       30   cmdline.txt
=> fatload virtio 0:1 ${loadaddr} cmdline.txt
30 bytes read in 11 ms (2 KiB/s)
=> md.b ${loadaddr} 0x1E
40080000: 64 77 63 5f 6f 74 67 2e 6c 70 6d 5f 65 6e 61 62    dwc_otg.lpm_enab
40080010: 6c 65 3d 30 20 72 6f 6f 74 77 61 69 74 0a          le=0 rootwait.

---------------------------------

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
---
 fs/fat/fat.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 9578b74bae..28aa5aaa9f 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -278,7 +278,10 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
 		}
 	} else {
 		idx = size / mydata->sect_size;
-		ret = disk_read(startsect, idx, buffer);
+		if (idx == 0)
+			ret = 0;
+		else
+			ret = disk_read(startsect, idx, buffer);
 		if (ret != idx) {
 			debug("Error reading data (got %d)\n", ret);
 			return -1;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/9] xhci: Add polling support for USB keyboards
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
  2020-07-24 21:50 ` [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 3/9] usb_kbd: succeed even if no interrupt is pending Jason Wessel
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

The xhci driver was causing intermittent 5 second delays from the USB
keyboard polling hook.  Executing something like a "sleep 1" for
example would sleep for 5 seconds, unless an event occurred on
the USB bus to shorten the delay.

Modeled after the code in the DWC2 driver, a nonblock state was added
to quickly return instead of blocking for up to 5 seconds waiting for
an event before timing out.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++---------
 drivers/usb/host/xhci.c      | 11 ++++++-----
 include/usb/xhci.h           |  5 +++--
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 86aeaab412..b7b2e16410 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -432,9 +432,11 @@ static int event_ready(struct xhci_ctrl *ctrl)
  *
  * @param ctrl		Host controller data structure
  * @param expected	TRB type expected from Event TRB
+ * @param nonblock	when true do not block waiting for response
  * @return pointer to event trb
  */
-union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
+union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected,
+				    bool nonblock)
 {
 	trb_type type;
 	unsigned long ts = get_timer(0);
@@ -442,8 +444,11 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
 	do {
 		union xhci_trb *event = ctrl->event_ring->dequeue;
 
-		if (!event_ready(ctrl))
+		if (!event_ready(ctrl)) {
+			if (nonblock)
+				return NULL;
 			continue;
+		}
 
 		type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
 		if (type == expected)
@@ -493,7 +498,7 @@ static void abort_td(struct usb_device *udev, int ep_index)
 
 	xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_STOP_RING);
 
-	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER, false);
 	field = le32_to_cpu(event->trans_event.flags);
 	BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
 	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
@@ -501,7 +506,7 @@ static void abort_td(struct usb_device *udev, int ep_index)
 		!= COMP_STOP)));
 	xhci_acknowledge_event(ctrl);
 
-	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
 	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
 		!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
 		event->event_cmd.status)) != COMP_SUCCESS);
@@ -509,7 +514,7 @@ static void abort_td(struct usb_device *udev, int ep_index)
 
 	xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
 		ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
-	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
 	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
 		!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
 		event->event_cmd.status)) != COMP_SUCCESS);
@@ -552,10 +557,11 @@ static void record_transfer_result(struct usb_device *udev,
  * @param pipe		contains the DIR_IN or OUT , devnum
  * @param length	length of the buffer
  * @param buffer	buffer to be read/written based on the request
+ * @param nonblock	when true do not block waiting for response
  * @return returns 0 if successful else -1 on failure
  */
 int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
-			int length, void *buffer)
+			int length, void *buffer, bool nonblock)
 {
 	int num_trbs = 0;
 	struct xhci_generic_trb *start_trb;
@@ -714,8 +720,10 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
 
 	giveback_first_trb(udev, ep_index, start_cycle, start_trb);
 
-	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER, nonblock);
 	if (!event) {
+		if (nonblock)
+			return -EINVAL;
 		debug("XHCI bulk transfer timed out, aborting...\n");
 		abort_td(udev, ep_index);
 		udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
@@ -911,7 +919,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
 
 	giveback_first_trb(udev, ep_index, start_cycle, start_trb);
 
-	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER, false);
 	if (!event)
 		goto abort;
 	field = le32_to_cpu(event->trans_event.flags);
@@ -929,7 +937,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
 	if (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))
 			== COMP_SHORT_TX) {
 		/* Short data stage, clear up additional status stage event */
-		event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+		event = xhci_wait_for_event(ctrl, TRB_TRANSFER, false);
 		if (!event)
 			goto abort;
 		BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index f635bb39f6..57d799e4cb 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -495,7 +495,7 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
 	xhci_flush_cache((uintptr_t)in_ctx->bytes, in_ctx->size);
 	xhci_queue_command(ctrl, in_ctx->bytes, udev->slot_id, 0,
 			   ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP);
-	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
 	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
 		!= udev->slot_id);
 
@@ -691,7 +691,7 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr)
 	ctrl_ctx->drop_flags = 0;
 
 	xhci_queue_command(ctrl, (void *)ctrl_ctx, slot_id, 0, TRB_ADDR_DEV);
-	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
 	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id);
 
 	switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) {
@@ -766,7 +766,7 @@ static int _xhci_alloc_device(struct usb_device *udev)
 	}
 
 	xhci_queue_command(ctrl, NULL, 0, 0, TRB_ENABLE_SLOT);
-	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
 	BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))
 		!= COMP_SUCCESS);
 
@@ -1152,6 +1152,7 @@ unknown:
  * @param buffer	buffer to be read/written based on the request
  * @param length	length of the buffer
  * @param interval	interval of the interrupt
+ * @param nonblock	when true do not block waiting for response
  * @return 0
  */
 static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
@@ -1169,7 +1170,7 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
 	 * (at most) one TD. A TD (comprised of sg list entries) can
 	 * take several service intervals to transmit.
 	 */
-	return xhci_bulk_tx(udev, pipe, length, buffer);
+	return xhci_bulk_tx(udev, pipe, length, buffer, nonblock);
 }
 
 /**
@@ -1189,7 +1190,7 @@ static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
 		return -EINVAL;
 	}
 
-	return xhci_bulk_tx(udev, pipe, length, buffer);
+	return xhci_bulk_tx(udev, pipe, length, buffer, false);
 }
 
 /**
diff --git a/include/usb/xhci.h b/include/usb/xhci.h
index 7d34103fd5..73db77fc02 100644
--- a/include/usb/xhci.h
+++ b/include/usb/xhci.h
@@ -1249,9 +1249,10 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
 void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
 			u32 slot_id, u32 ep_index, trb_type cmd);
 void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
-union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected);
+union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected,
+				    bool nonblock);
 int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
-		 int length, void *buffer);
+		 int length, void *buffer, bool nonblock);
 int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
 		 struct devrequest *req, int length, void *buffer);
 int xhci_check_maxpacket(struct usb_device *udev);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/9] usb_kbd: succeed even if no interrupt is pending
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
  2020-07-24 21:50 ` [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left Jason Wessel
  2020-07-24 21:50 ` [PATCH 2/9] xhci: Add polling support for USB keyboards Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 4/9] common/usb.c: Work around keyboard reporting "USB device not accepting new address" Jason Wessel
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

After the initial configuration some USB keyboard+mouse devices never
return any kind of event on the interrupt line.  In particular, the
device identified by "Cypress Cypress USB Keyboard / PS2 Mouse as
3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/0003:04B4:0101.0001/input/input0"
never returns a data packet until the first external input event.

I found this was also true with some newer model Dell keyboards.

When the device is plugged into a xhci controller there is also no
point in waiting 5 seconds for a device that is never going to present
data, so the call to the interrupt service was changed to a
nonblocking operation for the controllers that support this.

With the patch applied, the rpi3 and rpi4 work well with the more
complex keyboard devices.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 common/usb_kbd.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index b316807844..3c0056e1b9 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -519,7 +519,9 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
 			   1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE) < 0) {
 #else
 	if (usb_int_msg(dev, data->intpipe, data->new, data->intpktsize,
-			data->intinterval, false) < 0) {
+			data->intinterval, true) < 0) {
+		/* Read first packet if the device provides it, else pick it up later */
+		return 1;
 #endif
 		printf("Failed to get keyboard state from device %04x:%04x\n",
 		       dev->descriptor.idVendor, dev->descriptor.idProduct);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/9] common/usb.c: Work around keyboard reporting "USB device not accepting new address"
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (2 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 3/9] usb_kbd: succeed even if no interrupt is pending Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions Jason Wessel
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

When resetting the rpi3 board sometimes it will display:
     USB device not accepting new address (error=0)

After the message appears, the usb keyboard will not work.  It seems
that the configuration actually did succeed however.  Checking the
device status for a return code of zero and continuing allows the usb
keyboard and other usb devices to work function.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 common/usb.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/common/usb.c b/common/usb.c
index aad13fd9c5..0eb5d40a2d 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -1054,11 +1054,12 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 	dev->devnum = addr;
 
 	err = usb_set_address(dev); /* set address */
-
-	if (err < 0) {
+	if (err < 0)
+		debug("\n       usb_set_address return < 0\n");
+	if (err < 0 && dev->status != 0) {
 		printf("\n      USB device not accepting new address " \
 			"(error=%lX)\n", dev->status);
-		return err;
+			return err;
 	}
 
 	mdelay(10);	/* Let the SET_ADDRESS settle */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (3 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 4/9] common/usb.c: Work around keyboard reporting "USB device not accepting new address" Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-08-20  8:26   ` Bin Meng
  2020-07-24 21:50 ` [PATCH 6/9] xhci-ring: Fix crash when issuing "usb reset" Jason Wessel
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

xhci_trl_tx and xhchi_bulk_tx can be called synchronously by other
drivers such as the usb storage or network, while the keyboard driver
exclusively uses the polling mode.

And pending polling transactions must be aborted before switching
modes to avoid corrupting the state of the controller.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 drivers/usb/host/xhci-ring.c | 86 +++++++++++++++++++++++++++++-------
 1 file changed, 70 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b7b2e16410..d6339f4f0a 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -24,6 +24,12 @@
 
 #include <usb/xhci.h>
 
+static void *last_bulk_tx_buf;
+static struct usb_device *poll_last_udev;
+int poll_last_ep_index;
+static unsigned long bulk_tx_poll_ts;
+static bool poll_pend;
+
 /**
  * Is this TRB a link TRB or was the last TRB the last TRB in this event ring
  * segment?  I.e. would the updated event TRB pointer step off the end of the
@@ -549,19 +555,8 @@ static void record_transfer_result(struct usb_device *udev,
 	}
 }
 
-/**** Bulk and Control transfer methods ****/
-/**
- * Queues up the BULK Request
- *
- * @param udev		pointer to the USB device structure
- * @param pipe		contains the DIR_IN or OUT , devnum
- * @param length	length of the buffer
- * @param buffer	buffer to be read/written based on the request
- * @param nonblock	when true do not block waiting for response
- * @return returns 0 if successful else -1 on failure
- */
-int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
-			int length, void *buffer, bool nonblock)
+static int _xhci_bulk_tx_queue(struct usb_device *udev, unsigned long pipe,
+			       int length, void *buffer)
 {
 	int num_trbs = 0;
 	struct xhci_generic_trb *start_trb;
@@ -575,7 +570,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
 	struct xhci_virt_device *virt_dev;
 	struct xhci_ep_ctx *ep_ctx;
 	struct xhci_ring *ring;		/* EP transfer ring */
-	union xhci_trb *event;
 
 	int running_total, trb_buff_len;
 	unsigned int total_packet_count;
@@ -719,20 +713,73 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
 	} while (running_total < length);
 
 	giveback_first_trb(udev, ep_index, start_cycle, start_trb);
+	return 0;
+}
 
+/**** Bulk and Control transfer methods ****/
+/**
+ * Queues up the BULK Request
+ *
+ * @param udev		pointer to the USB device structure
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param length	length of the buffer
+ * @param buffer	buffer to be read/written based on the request
+ * @param nonblock	when true do not block waiting for response
+ * @return returns 0 if successful else -1 on failure
+ */
+int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
+		 int length, void *buffer, bool nonblock)
+{
+	u32 field;
+	int ret;
+	union xhci_trb *event;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int ep_index = usb_pipe_ep_index(pipe);
+
+	if (poll_pend) {
+		/*
+		 * Abort a pending poll operation if it should have
+		 * timed out, or if this is a different buffer from a
+		 * separate request
+		 */
+		if (get_timer(bulk_tx_poll_ts) > XHCI_TIMEOUT ||
+		    last_bulk_tx_buf != buffer || poll_last_udev != udev ||
+		    ep_index != poll_last_ep_index) {
+			abort_td(poll_last_udev, poll_last_ep_index);
+			poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
+			poll_last_udev->act_len = 0;
+			poll_pend = false;
+		}
+	} /* No else here because poll_pend might have changed above */
+	if (!poll_pend) {
+		last_bulk_tx_buf = buffer;
+		ret = _xhci_bulk_tx_queue(udev, pipe, length, buffer);
+		if (ret)
+			return ret;
+	}
 	event = xhci_wait_for_event(ctrl, TRB_TRANSFER, nonblock);
 	if (!event) {
-		if (nonblock)
+		if (nonblock) {
+			if (!poll_pend) {
+				/* Start the timer */
+				bulk_tx_poll_ts = get_timer(0);
+				poll_last_udev = udev;
+				poll_last_ep_index = ep_index;
+				poll_pend = true;
+			}
 			return -EINVAL;
+		}
 		debug("XHCI bulk transfer timed out, aborting...\n");
 		abort_td(udev, ep_index);
 		udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
 		udev->act_len = 0;
+		poll_pend = false;
 		return -ETIMEDOUT;
 	}
+	poll_pend = false;
 	field = le32_to_cpu(event->trans_event.flags);
 
-	BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
+	BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
 	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
 	BUG_ON(*(void **)(uintptr_t)le64_to_cpu(event->trans_event.buffer) -
 		buffer > (size_t)length);
@@ -779,6 +826,13 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
 		le16_to_cpu(req->value), le16_to_cpu(req->value),
 		le16_to_cpu(req->index));
 
+	if (poll_pend) {
+		abort_td(poll_last_udev, poll_last_ep_index);
+		poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
+		poll_last_udev->act_len = 0;
+		poll_pend = false;
+	}
+
 	ep_index = usb_pipe_ep_index(pipe);
 
 	ep_ring = virt_dev->eps[ep_index].ring;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/9] xhci-ring: Fix crash when issuing "usb reset"
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (4 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 7/9] usb.c: Add a retry in the usb_prepare_device() Jason Wessel
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

If a "usb reset" is issued when the poll_pend state is set the
abort_td() function will hit one of the BUG() statements in abort_td()
or the BUG() statement at the end of xhci_wait_for_event().

The controller has been reset, so the rest of the cleanup should be
skipped and poll_pend flag should be cleared.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 drivers/usb/host/xhci-ring.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d6339f4f0a..f2a07204cd 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -483,6 +483,8 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected,
 	if (expected == TRB_TRANSFER)
 		return NULL;
 
+	if (poll_pend)
+		return NULL;
 	printf("XHCI timeout on event type %d... cannot recover.\n", expected);
 	BUG();
 }
@@ -505,11 +507,16 @@ static void abort_td(struct usb_device *udev, int ep_index)
 	xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_STOP_RING);
 
 	event = xhci_wait_for_event(ctrl, TRB_TRANSFER, false);
-	field = le32_to_cpu(event->trans_event.flags);
-	BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
-	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
-	BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
-		!= COMP_STOP)));
+	if (event) {
+		field = le32_to_cpu(event->trans_event.flags);
+		BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+		BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+		BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
+						 != COMP_STOP)));
+	} else {
+		debug("XHCI abort timeout\n");
+		return;
+	}
 	xhci_acknowledge_event(ctrl);
 
 	event = xhci_wait_for_event(ctrl, TRB_COMPLETION, false);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/9] usb.c: Add a retry in the usb_prepare_device()
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (5 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 6/9] xhci-ring: Fix crash when issuing "usb reset" Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 8/9] bcmgenet: fix DMA buffer management Jason Wessel
  2020-07-24 21:50 ` [PATCH 9/9] bcmgenet: Add support for rgmii-rxid Jason Wessel
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

I have found through testing some USB 2 composite mouse/keyboard
devices do not response to the usb_set_address call immediately
following the port reset.  It can take anywhere from 2ms to 20ms.

This patch adds a retry and delay for usb_prepare_device() and allows
all the USB keyboards I tried to function properly.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 common/usb.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/common/usb.c b/common/usb.c
index 0eb5d40a2d..39bae86a11 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -1032,6 +1032,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 			      struct usb_device *parent)
 {
 	int err;
+	int retry_msec = 0;
 
 	/*
 	 * Allocate usb 3.0 device context.
@@ -1054,6 +1055,14 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 	dev->devnum = addr;
 
 	err = usb_set_address(dev); /* set address */
+	/* Retry for old composite keyboard/mouse usb2 hardware */
+	while (err < 0 && retry_msec <= 40) {
+		retry_msec += 20;
+		mdelay(20);
+		err = usb_set_address(dev); /* set address */
+	}
+	if (retry_msec > 0)
+		debug("usb_set_address delay: %i\n", retry_msec);
 	if (err < 0)
 		debug("\n       usb_set_address return < 0\n");
 	if (err < 0 && dev->status != 0) {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/9] bcmgenet: fix DMA buffer management
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (6 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 7/9] usb.c: Add a retry in the usb_prepare_device() Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  2020-07-24 21:50 ` [PATCH 9/9] bcmgenet: Add support for rgmii-rxid Jason Wessel
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

This commit fixes a serious issue occurring when several network
commands are run on a raspberry pi 4 board: for instance a "dhcp"
command and then one or several "tftp" commands. In this case,
packet recv callbacks were called several times on the same packets,
and send function was failing most of the time.

note: if the boot procedure is made of a single network
command, the issue is not visible.

The issue is related to management of the packet ring buffers
(producer / consumer) and DMA.
Each time a packet is received, the ethernet device stores it
in the buffer and increments an index called RDMA_PROD_INDEX.
Each time the driver outputs a received packet, it increments
another index called RDMA_CONS_INDEX.

Between each pair of network commands, as part of the driver
'start' function, previous code tried to reset both RDMA_CONS_INDEX
and RDMA_PROD_INDEX to 0. But RDMA_PROD_INDEX cannot be written from
driver side, thus its value was actually not updated, and only
RDMA_CONS_INDEX was reset to 0. This was resulting in a major
synchronization issue between the driver and the device. Most
visible behavior was that the driver seemed to receive again the
packets from the previous commands (e.g. DHCP response packets
"received" again when performing the first TFTP command).

This fix consists in setting RDMA_CONS_INDEX to the same
value as RDMA_PROD_INDEX, when resetting the driver.

The same kind of fix was needed on the TX side, and a few variables
had to be reset accordingly (c_index, tx_index, rx_index).

The rx_index and tx_index have only 256 entries so the bottom 8 bits
must be masked off.

Originated-by: Etienne Dubl? <etienne.duble@imag.fr>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 drivers/net/bcmgenet.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c
index 11b6148ab6..1b7e7ba2bf 100644
--- a/drivers/net/bcmgenet.c
+++ b/drivers/net/bcmgenet.c
@@ -378,8 +378,6 @@ static void rx_descs_init(struct bcmgenet_eth_priv *priv)
 	u32 len_stat, i;
 	void *desc_base = priv->rx_desc_base;
 
-	priv->c_index = 0;
-
 	len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN;
 
 	for (i = 0; i < RX_DESCS; i++) {
@@ -403,8 +401,11 @@ static void rx_ring_init(struct bcmgenet_eth_priv *priv)
 	writel(RX_DESCS * DMA_DESC_SIZE / 4 - 1,
 	       priv->mac_reg + RDMA_RING_REG_BASE + DMA_END_ADDR);
 
-	writel(0x0, priv->mac_reg + RDMA_PROD_INDEX);
-	writel(0x0, priv->mac_reg + RDMA_CONS_INDEX);
+	/* cannot init RDMA_PROD_INDEX to 0, so align RDMA_CONS_INDEX on it instead */
+	priv->c_index = readl(priv->mac_reg + RDMA_PROD_INDEX);
+	writel(priv->c_index, priv->mac_reg + RDMA_CONS_INDEX);
+	priv->rx_index = priv->c_index;
+	priv->rx_index &= 0xFF;
 	writel((RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH,
 	       priv->mac_reg + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE);
 	writel(DMA_FC_THRESH_VALUE, priv->mac_reg + RDMA_XON_XOFF_THRESH);
@@ -421,8 +422,10 @@ static void tx_ring_init(struct bcmgenet_eth_priv *priv)
 	writel(0x0, priv->mac_reg + TDMA_WRITE_PTR);
 	writel(TX_DESCS * DMA_DESC_SIZE / 4 - 1,
 	       priv->mac_reg + TDMA_RING_REG_BASE + DMA_END_ADDR);
-	writel(0x0, priv->mac_reg + TDMA_PROD_INDEX);
-	writel(0x0, priv->mac_reg + TDMA_CONS_INDEX);
+	/* cannot init TDMA_CONS_INDEX to 0, so align TDMA_PROD_INDEX on it instead */
+	priv->tx_index = readl(priv->mac_reg + TDMA_CONS_INDEX);
+	writel(priv->tx_index, priv->mac_reg + TDMA_PROD_INDEX);
+	priv->tx_index &= 0xFF;
 	writel(0x1, priv->mac_reg + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH);
 	writel(0x0, priv->mac_reg + TDMA_FLOW_PERIOD);
 	writel((TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH,
@@ -469,8 +472,6 @@ static int bcmgenet_gmac_eth_start(struct udevice *dev)
 
 	priv->tx_desc_base = priv->mac_reg + GENET_TX_OFF;
 	priv->rx_desc_base = priv->mac_reg + GENET_RX_OFF;
-	priv->tx_index = 0x0;
-	priv->rx_index = 0x0;
 
 	bcmgenet_umac_reset(priv);
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 9/9] bcmgenet: Add support for rgmii-rxid
  2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
                   ` (7 preceding siblings ...)
  2020-07-24 21:50 ` [PATCH 8/9] bcmgenet: fix DMA buffer management Jason Wessel
@ 2020-07-24 21:50 ` Jason Wessel
  8 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-07-24 21:50 UTC (permalink / raw)
  To: u-boot

The commit 57805f2270c4 ("net: bcmgenet: Don't set ID_MODE_DIS when
not using RGMII") needed to be extended for the case of using the
rgmii-rxid.  The latest version of the Rasbperry Pi4 dtb files for the
5.4 now specify the rgmii-rxid.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 drivers/net/bcmgenet.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c
index 1b7e7ba2bf..ace1331362 100644
--- a/drivers/net/bcmgenet.c
+++ b/drivers/net/bcmgenet.c
@@ -457,7 +457,8 @@ static int bcmgenet_adjust_link(struct bcmgenet_eth_priv *priv)
 	clrsetbits_32(priv->mac_reg + EXT_RGMII_OOB_CTRL, OOB_DISABLE,
 			RGMII_LINK | RGMII_MODE_EN);
 
-	if (phy_dev->interface == PHY_INTERFACE_MODE_RGMII)
+	if (phy_dev->interface == PHY_INTERFACE_MODE_RGMII ||
+	    phy_dev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
 		setbits_32(priv->mac_reg + EXT_RGMII_OOB_CTRL, ID_MODE_DIS);
 
 	writel(speed << CMD_SPEED_SHIFT, (priv->mac_reg + UMAC_CMD));
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left
  2020-07-24 21:50 ` [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left Jason Wessel
@ 2020-07-25 15:27   ` Heinrich Schuchardt
  0 siblings, 0 replies; 13+ messages in thread
From: Heinrich Schuchardt @ 2020-07-25 15:27 UTC (permalink / raw)
  To: u-boot

On 7/24/20 11:50 PM, Jason Wessel wrote:
> While using u-boot with qemu's virtio driver I stumbled across a
> problem reading files less than sector size.  On the real hardware the
> block reader seems ok with reading zero blocks, and while we could fix
> the virtio host side of qemu to deal with a zero block read instead of
> crashing, the u-boot fat driver should not be doing zero block reads
> in the first place.  If you ask hardware to read zero blocks you are
> just going to get zero data.  There may also be other hardware that
> responds similarly to the virtio interface so this is worth fixing.
>
> Without the patch I get the following and have to restart qemu because
> it dies.

Our block drivers all have a different view on this:

mmc_read_blocks() is reading one block even if 0 blocks are requested.
scsi_setup_read16() happily passes the 0 to the controller.

I think blk_read_devnum(), blk_write_devnum(), blk_dread(), and
blk_dwrite() is where we need the block count check.

> ---------------------------------
> => fatls virtio 0:1
>        30   cmdline.txt
> => fatload virtio 0:1 ${loadaddr} cmdline.txt
> qemu-system-aarch64: virtio: zero sized buffers are not allowed
> ---------------------------------
>
> With the patch I get the expected results.
> ---------------------------------
> => fatls virtio 0:1
>        30   cmdline.txt
> => fatload virtio 0:1 ${loadaddr} cmdline.txt
> 30 bytes read in 11 ms (2 KiB/s)
> => md.b ${loadaddr} 0x1E
> 40080000: 64 77 63 5f 6f 74 67 2e 6c 70 6d 5f 65 6e 61 62    dwc_otg.lpm_enab
> 40080010: 6c 65 3d 30 20 72 6f 6f 74 77 61 69 74 0a          le=0 rootwait.
>
> ---------------------------------
>
> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
> Reviewed-by: Tom Rini <trini@konsulko.com>
> ---
>  fs/fat/fat.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/fs/fat/fat.c b/fs/fat/fat.c
> index 9578b74bae..28aa5aaa9f 100644
> --- a/fs/fat/fat.c
> +++ b/fs/fat/fat.c
> @@ -278,7 +278,10 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
>  		}
>  	} else {
>  		idx = size / mydata->sect_size;
> -		ret = disk_read(startsect, idx, buffer);
> +		if (idx == 0)
> +			ret = 0;
> +		else
> +			ret = disk_read(startsect, idx, buffer);

Using idx as variable name here for a block count is quite misleading.

Best regards

Heinrich

>  		if (ret != idx) {
>  			debug("Error reading data (got %d)\n", ret);
>  			return -1;
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions
  2020-07-24 21:50 ` [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions Jason Wessel
@ 2020-08-20  8:26   ` Bin Meng
  2020-08-24  3:35     ` Jason Wessel
  0 siblings, 1 reply; 13+ messages in thread
From: Bin Meng @ 2020-08-20  8:26 UTC (permalink / raw)
  To: u-boot

Hi Jason,

On Sat, Jul 25, 2020 at 5:51 AM Jason Wessel <jason.wessel@windriver.com> wrote:
>
> xhci_trl_tx and xhchi_bulk_tx can be called synchronously by other
> drivers such as the usb storage or network, while the keyboard driver
> exclusively uses the polling mode.
>

Could you provide more details as to when this will fail?

> And pending polling transactions must be aborted before switching
> modes to avoid corrupting the state of the controller.
>
> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
> ---
>  drivers/usb/host/xhci-ring.c | 86 +++++++++++++++++++++++++++++-------
>  1 file changed, 70 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index b7b2e16410..d6339f4f0a 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -24,6 +24,12 @@
>
>  #include <usb/xhci.h>
>
> +static void *last_bulk_tx_buf;
> +static struct usb_device *poll_last_udev;
> +int poll_last_ep_index;
> +static unsigned long bulk_tx_poll_ts;
> +static bool poll_pend;

Should these variables go into struct xhci_ctrl? What happens if 2
controllers are sending data?

> +
>  /**
>   * Is this TRB a link TRB or was the last TRB the last TRB in this event ring
>   * segment?  I.e. would the updated event TRB pointer step off the end of the
> @@ -549,19 +555,8 @@ static void record_transfer_result(struct usb_device *udev,
>         }
>  }
>
> -/**** Bulk and Control transfer methods ****/
> -/**
> - * Queues up the BULK Request
> - *
> - * @param udev         pointer to the USB device structure
> - * @param pipe         contains the DIR_IN or OUT , devnum
> - * @param length       length of the buffer
> - * @param buffer       buffer to be read/written based on the request
> - * @param nonblock     when true do not block waiting for response
> - * @return returns 0 if successful else -1 on failure
> - */
> -int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
> -                       int length, void *buffer, bool nonblock)
> +static int _xhci_bulk_tx_queue(struct usb_device *udev, unsigned long pipe,
> +                              int length, void *buffer)
>  {
>         int num_trbs = 0;
>         struct xhci_generic_trb *start_trb;
> @@ -575,7 +570,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>         struct xhci_virt_device *virt_dev;
>         struct xhci_ep_ctx *ep_ctx;
>         struct xhci_ring *ring;         /* EP transfer ring */
> -       union xhci_trb *event;
>
>         int running_total, trb_buff_len;
>         unsigned int total_packet_count;
> @@ -719,20 +713,73 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>         } while (running_total < length);
>
>         giveback_first_trb(udev, ep_index, start_cycle, start_trb);
> +       return 0;
> +}
>
> +/**** Bulk and Control transfer methods ****/
> +/**
> + * Queues up the BULK Request
> + *
> + * @param udev         pointer to the USB device structure
> + * @param pipe         contains the DIR_IN or OUT , devnum
> + * @param length       length of the buffer
> + * @param buffer       buffer to be read/written based on the request
> + * @param nonblock     when true do not block waiting for response
> + * @return returns 0 if successful else -1 on failure
> + */
> +int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
> +                int length, void *buffer, bool nonblock)
> +{
> +       u32 field;
> +       int ret;
> +       union xhci_trb *event;
> +       struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
> +       int ep_index = usb_pipe_ep_index(pipe);
> +
> +       if (poll_pend) {
> +               /*
> +                * Abort a pending poll operation if it should have
> +                * timed out, or if this is a different buffer from a
> +                * separate request
> +                */
> +               if (get_timer(bulk_tx_poll_ts) > XHCI_TIMEOUT ||
> +                   last_bulk_tx_buf != buffer || poll_last_udev != udev ||
> +                   ep_index != poll_last_ep_index) {
> +                       abort_td(poll_last_udev, poll_last_ep_index);
> +                       poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
> +                       poll_last_udev->act_len = 0;
> +                       poll_pend = false;
> +               }
> +       } /* No else here because poll_pend might have changed above */
> +       if (!poll_pend) {
> +               last_bulk_tx_buf = buffer;
> +               ret = _xhci_bulk_tx_queue(udev, pipe, length, buffer);
> +               if (ret)
> +                       return ret;
> +       }
>         event = xhci_wait_for_event(ctrl, TRB_TRANSFER, nonblock);
>         if (!event) {
> -               if (nonblock)
> +               if (nonblock) {
> +                       if (!poll_pend) {
> +                               /* Start the timer */
> +                               bulk_tx_poll_ts = get_timer(0);
> +                               poll_last_udev = udev;
> +                               poll_last_ep_index = ep_index;
> +                               poll_pend = true;
> +                       }
>                         return -EINVAL;
> +               }
>                 debug("XHCI bulk transfer timed out, aborting...\n");
>                 abort_td(udev, ep_index);
>                 udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
>                 udev->act_len = 0;
> +               poll_pend = false;
>                 return -ETIMEDOUT;
>         }
> +       poll_pend = false;
>         field = le32_to_cpu(event->trans_event.flags);
>
> -       BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
> +       BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
>         BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
>         BUG_ON(*(void **)(uintptr_t)le64_to_cpu(event->trans_event.buffer) -
>                 buffer > (size_t)length);
> @@ -779,6 +826,13 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
>                 le16_to_cpu(req->value), le16_to_cpu(req->value),
>                 le16_to_cpu(req->index));
>
> +       if (poll_pend) {
> +               abort_td(poll_last_udev, poll_last_ep_index);
> +               poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
> +               poll_last_udev->act_len = 0;
> +               poll_pend = false;
> +       }
> +
>         ep_index = usb_pipe_ep_index(pipe);
>
>         ep_ring = virt_dev->eps[ep_index].ring;
> --

Regards,
Bin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions
  2020-08-20  8:26   ` Bin Meng
@ 2020-08-24  3:35     ` Jason Wessel
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Wessel @ 2020-08-24  3:35 UTC (permalink / raw)
  To: u-boot



On 8/20/20 3:26 AM, Bin Meng wrote:
> Hi Jason,
> 
> On Sat, Jul 25, 2020 at 5:51 AM Jason Wessel <jason.wessel@windriver.com> wrote:
>>
>> xhci_trl_tx and xhchi_bulk_tx can be called synchronously by other
>> drivers such as the usb storage or network, while the keyboard driver
>> exclusively uses the polling mode.
>>
> 
> Could you provide more details as to when this will fail?


An example is when the keyboard poll happens just before loading an
a kernel image from the USB device.  The poll sets up the TRB to listen
but the packet may arrive when a keyboard event occurs, and the
existing drivers will crash when the keyboard event is received
instead of the request it has issued synchronously. 

It didn't seem to happen too often, but extended testing discovered
the problem. 


> 
>> And pending polling transactions must be aborted before switching
>> modes to avoid corrupting the state of the controller.
>>
>> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
>> ---
>>  drivers/usb/host/xhci-ring.c | 86 +++++++++++++++++++++++++++++-------
>>  1 file changed, 70 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
>> index b7b2e16410..d6339f4f0a 100644
>> --- a/drivers/usb/host/xhci-ring.c
>> +++ b/drivers/usb/host/xhci-ring.c
>> @@ -24,6 +24,12 @@
>>
>>  #include <usb/xhci.h>
>>
>> +static void *last_bulk_tx_buf;
>> +static struct usb_device *poll_last_udev;
>> +int poll_last_ep_index;
>> +static unsigned long bulk_tx_poll_ts;
>> +static bool poll_pend;
> 
> Should these variables go into struct xhci_ctrl? What happens if 2
> controllers are sending data?
>


I would say you are correct.  Because the board I was using only
had a single controller, the issue is only fixed for the single controller case. 

I can re-work the patches to account for the problem. 

Jason. 


 
>> +
>>  /**
>>   * Is this TRB a link TRB or was the last TRB the last TRB in this event ring
>>   * segment?  I.e. would the updated event TRB pointer step off the end of the
>> @@ -549,19 +555,8 @@ static void record_transfer_result(struct usb_device *udev,
>>         }
>>  }
>>
>> -/**** Bulk and Control transfer methods ****/
>> -/**
>> - * Queues up the BULK Request
>> - *
>> - * @param udev         pointer to the USB device structure
>> - * @param pipe         contains the DIR_IN or OUT , devnum
>> - * @param length       length of the buffer
>> - * @param buffer       buffer to be read/written based on the request
>> - * @param nonblock     when true do not block waiting for response
>> - * @return returns 0 if successful else -1 on failure
>> - */
>> -int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>> -                       int length, void *buffer, bool nonblock)
>> +static int _xhci_bulk_tx_queue(struct usb_device *udev, unsigned long pipe,
>> +                              int length, void *buffer)
>>  {
>>         int num_trbs = 0;
>>         struct xhci_generic_trb *start_trb;
>> @@ -575,7 +570,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>>         struct xhci_virt_device *virt_dev;
>>         struct xhci_ep_ctx *ep_ctx;
>>         struct xhci_ring *ring;         /* EP transfer ring */
>> -       union xhci_trb *event;
>>
>>         int running_total, trb_buff_len;
>>         unsigned int total_packet_count;
>> @@ -719,20 +713,73 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>>         } while (running_total < length);
>>
>>         giveback_first_trb(udev, ep_index, start_cycle, start_trb);
>> +       return 0;
>> +}
>>
>> +/**** Bulk and Control transfer methods ****/
>> +/**
>> + * Queues up the BULK Request
>> + *
>> + * @param udev         pointer to the USB device structure
>> + * @param pipe         contains the DIR_IN or OUT , devnum
>> + * @param length       length of the buffer
>> + * @param buffer       buffer to be read/written based on the request
>> + * @param nonblock     when true do not block waiting for response
>> + * @return returns 0 if successful else -1 on failure
>> + */
>> +int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
>> +                int length, void *buffer, bool nonblock)
>> +{
>> +       u32 field;
>> +       int ret;
>> +       union xhci_trb *event;
>> +       struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
>> +       int ep_index = usb_pipe_ep_index(pipe);
>> +
>> +       if (poll_pend) {
>> +               /*
>> +                * Abort a pending poll operation if it should have
>> +                * timed out, or if this is a different buffer from a
>> +                * separate request
>> +                */
>> +               if (get_timer(bulk_tx_poll_ts) > XHCI_TIMEOUT ||
>> +                   last_bulk_tx_buf != buffer || poll_last_udev != udev ||
>> +                   ep_index != poll_last_ep_index) {
>> +                       abort_td(poll_last_udev, poll_last_ep_index);
>> +                       poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
>> +                       poll_last_udev->act_len = 0;
>> +                       poll_pend = false;
>> +               }
>> +       } /* No else here because poll_pend might have changed above */
>> +       if (!poll_pend) {
>> +               last_bulk_tx_buf = buffer;
>> +               ret = _xhci_bulk_tx_queue(udev, pipe, length, buffer);
>> +               if (ret)
>> +                       return ret;
>> +       }
>>         event = xhci_wait_for_event(ctrl, TRB_TRANSFER, nonblock);
>>         if (!event) {
>> -               if (nonblock)
>> +               if (nonblock) {
>> +                       if (!poll_pend) {
>> +                               /* Start the timer */
>> +                               bulk_tx_poll_ts = get_timer(0);
>> +                               poll_last_udev = udev;
>> +                               poll_last_ep_index = ep_index;
>> +                               poll_pend = true;
>> +                       }
>>                         return -EINVAL;
>> +               }
>>                 debug("XHCI bulk transfer timed out, aborting...\n");
>>                 abort_td(udev, ep_index);
>>                 udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
>>                 udev->act_len = 0;
>> +               poll_pend = false;
>>                 return -ETIMEDOUT;
>>         }
>> +       poll_pend = false;
>>         field = le32_to_cpu(event->trans_event.flags);
>>
>> -       BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
>> +       BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
>>         BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
>>         BUG_ON(*(void **)(uintptr_t)le64_to_cpu(event->trans_event.buffer) -
>>                 buffer > (size_t)length);
>> @@ -779,6 +826,13 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
>>                 le16_to_cpu(req->value), le16_to_cpu(req->value),
>>                 le16_to_cpu(req->index));
>>
>> +       if (poll_pend) {
>> +               abort_td(poll_last_udev, poll_last_ep_index);
>> +               poll_last_udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
>> +               poll_last_udev->act_len = 0;
>> +               poll_pend = false;
>> +       }
>> +
>>         ep_index = usb_pipe_ep_index(pipe);
>>
>>         ep_ring = virt_dev->eps[ep_index].ring;
>> --
> 
> Regards,
> Bin
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-08-24  3:35 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-24 21:50 [PULL][PATCH 0/9] Raspberry pi improvements qemu/usb/ethernet Jason Wessel
2020-07-24 21:50 ` [PATCH 1/9] fs/fat/fat.c: Do not perform zero block reads if there are no blocks left Jason Wessel
2020-07-25 15:27   ` Heinrich Schuchardt
2020-07-24 21:50 ` [PATCH 2/9] xhci: Add polling support for USB keyboards Jason Wessel
2020-07-24 21:50 ` [PATCH 3/9] usb_kbd: succeed even if no interrupt is pending Jason Wessel
2020-07-24 21:50 ` [PATCH 4/9] common/usb.c: Work around keyboard reporting "USB device not accepting new address" Jason Wessel
2020-07-24 21:50 ` [PATCH 5/9] xhci-ring.c: Add the poll_pend state to properly abort transactions Jason Wessel
2020-08-20  8:26   ` Bin Meng
2020-08-24  3:35     ` Jason Wessel
2020-07-24 21:50 ` [PATCH 6/9] xhci-ring: Fix crash when issuing "usb reset" Jason Wessel
2020-07-24 21:50 ` [PATCH 7/9] usb.c: Add a retry in the usb_prepare_device() Jason Wessel
2020-07-24 21:50 ` [PATCH 8/9] bcmgenet: fix DMA buffer management Jason Wessel
2020-07-24 21:50 ` [PATCH 9/9] bcmgenet: Add support for rgmii-rxid Jason Wessel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.