summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorMarek Vasut <marek.vasut@gmail.com>2020-04-06 14:29:44 +0200
committerTom Rini <trini@konsulko.com>2020-04-09 15:26:59 -0400
commit31232de07ef2bd97ff67625976eecd97eeb1bd3d (patch)
treea2c2b13d0321e29a09435d664c8a8c960a935e62 /common
parent0db0ba6141f402b1d496ef53d9fa69978f75ec61 (diff)
usb: Keep async schedule running only across mass storage xfers
Rather than keeping the asynchronous schedule running always, keep it running only across USB mass storage transfers for now, as it seems that keeping it running all the time interferes with certain control transfers during device enumeration. Note that running the async schedule all the time should not be an issue, especially on EHCI HCD, as that one implements most of the transfers using async schedule. Note that we have usb_disable_asynch(), which however is utterly broken. The usb_disable_asynch() blocks the USB core from doing async transfers by setting a global flag. The async schedule should however be disabled per USB controller. Moreover, setting a global flag does not prevent the controller from using the async schedule, which e.g. the EHCI HCD does. This patch implements additional callback to the controller, which permits it to lock the async schedule and keep it running across multiple transfers. Once the schedule is unlocked, it must also be disabled. This thus prevents the async schedule from running outside of the USB mass storage transfers. Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> Cc: Lukasz Majewski <lukma@denx.de> Cc: Tom Rini <trini@konsulko.com> Tested-by: Tom Rini <trini@konsulko.com> [omap3_beagle, previously failing]
Diffstat (limited to 'common')
-rw-r--r--common/usb.c6
-rw-r--r--common/usb_storage.c4
2 files changed, 10 insertions, 0 deletions
diff --git a/common/usb.c b/common/usb.c
index 349e838f1d..686f09a77d 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -172,6 +172,12 @@ int usb_detect_change(void)
return change;
}
+/* Lock or unlock async schedule on the controller */
+__weak int usb_lock_async(struct usb_device *dev, int lock)
+{
+ return 0;
+}
+
/*
* disables the asynch behaviour of the control message. This is used for data
* transfers that uses the exclusiv access to the control and bulk messages.
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 097b6729c1..b291ac55d1 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -1157,6 +1157,7 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
ss = (struct us_data *)udev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */
+ usb_lock_async(udev, 1);
srb->lun = block_dev->lun;
buf_addr = (uintptr_t)buffer;
start = blknr;
@@ -1195,6 +1196,7 @@ retry_it:
debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
start, smallblks, buf_addr);
+ usb_lock_async(udev, 0);
usb_disable_asynch(0); /* asynch transfer allowed */
if (blkcnt >= ss->max_xfer_blk)
debug("\n");
@@ -1239,6 +1241,7 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
ss = (struct us_data *)udev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */
+ usb_lock_async(udev, 1);
srb->lun = block_dev->lun;
buf_addr = (uintptr_t)buffer;
@@ -1280,6 +1283,7 @@ retry_it:
debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
start, smallblks, buf_addr);
+ usb_lock_async(udev, 0);
usb_disable_asynch(0); /* asynch transfer allowed */
if (blkcnt >= ss->max_xfer_blk)
debug("\n");