From: a17671 Date: Sun, 3 Feb 2019 06:25:20 +0000 (+0800) Subject: f_fs.c:Pick up QCOM fixes for adb stability issue X-Git-Tag: MMI-QSAS30.62-33-3~244 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=9d38e3f9c65742d14f4716a61e9547c137a968c1;p=GitHub%2FMotorolaMobilityLLC%2Fkernel-slsi.git f_fs.c:Pick up QCOM fixes for adb stability issue USB: gagget: f_fs: Return error if TX req is queued during device offline when USB cable is disconnected during TX data transfers, endpoints will be disabled during function disable. If userspace client tries to queue requests on disabled endpoints, driver will wait till endpoints are enabled and then queues previous session requests. This results in kernel driver and userspace driver out of sync and due to this, stall will be seen. Hence fix this issue by returning error value if client tries to queue requests on TX endpoint during device offline. CRs-Fixed: 633497 Change-Id: I3e43b8a704367aff7fe8dd88159315aef811c51c Signed-off-by: Vijayavardhan Vennapusa Signed-off-by: Mayank Rana USB: f_fs: Check error status before doing epfile I/O Set error status before disabling endpoint during function disable and also check error status before handling I/O. If error status is set, return error status to read/write calls made by userspace. Also set file's private data to NULL during epfile release. CRs-Fixed: 671880 Change-Id: I14b5ee541dfc18a7802ef4a8033878a7729d9adb Signed-off-by: Vijayavardhan Vennapusa USB: f_fs: Add memory barrier before atomic operations In few instances, it is observed that multiple adbd instances are running on device causing condition BUG_ON(ffs->gadget) to be true. ffs->opened and ffs->ref atomic variables are used here to make decision for checking ffs->gadget. These atomic variable operations requires expilict memory barrier to make sure that update to ffs->gadget is visible to other CPUs before updated atomic variable based value is seen. This change also adds explicit memory barriers before reading or modified any atomic varaiables. CRs-Fixed: 793733 Change-Id: I3c846eb6bbb53663892e05d51ebac8439aac957a Signed-off-by: Mayank Rana Change-Id: I48389d8d922e30aeb1215207ba138e36799df250 Signed-off-by: a17671 Reviewed-on: https://gerrit.mot.com/1304658 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 0ca1a242ae5e..d1a052614c39 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -128,7 +128,7 @@ struct ffs_ep { struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; - + atomic_t error; struct ffs_data *ffs; struct ffs_ep *ep; /* P: ffs->eps_lock */ @@ -883,6 +883,10 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) char *data = NULL; ssize_t ret, data_len = -EINVAL; int halt; + /* to get updated error atomic variable value */ + smp_mb__before_atomic(); + if (atomic_read(&epfile->error)) + return -ENODEV; /* Are we still active? */ if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) @@ -893,11 +897,24 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (!ep) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; + /* Don't wait on write if device is offline */ + if (!io_data->read) + return -ENODEV; + /* to get updated error atomic variable value */ + smp_mb__before_atomic(); - ret = wait_event_interruptible( + /* + * if ep is disabled, this fails all current IOs + * and wait for next epfile open to happen + */ + if (!atomic_read(&epfile->error)) { + ret = wait_event_interruptible( epfile->ffs->wait, (ep = epfile->ep)); - if (ret) - return -EINTR; + if (ret) + return -EINTR; + } + if (!ep) + return -ENODEV; } /* Do we halt? */ @@ -1077,7 +1094,9 @@ ffs_epfile_open(struct inode *inode, struct file *file) file->private_data = epfile; ffs_data_opened(epfile->ffs); - + /* to get updated opened atomic variable value */ + smp_mb__before_atomic(); + atomic_set(&epfile->error, 0); return 0; } @@ -1193,6 +1212,7 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); __ffs_epfile_read_buffer_free(epfile); + atomic_set(&epfile->error, 1); ffs_data_closed(epfile->ffs); return 0; @@ -1841,7 +1861,11 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned long flags; spin_lock_irqsave(&func->ffs->eps_lock, flags); - while (count--) { + do { + + if (epfile) + atomic_set(&epfile->error, 1); + /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); @@ -1852,7 +1876,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) __ffs_epfile_read_buffer_free(epfile); ++epfile; } - } + } while (--count); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); } @@ -1866,7 +1890,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) int ret = 0; spin_lock_irqsave(&func->ffs->eps_lock, flags); - while(count--) { + do { ep->ep->driver_data = ep; ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); @@ -1887,7 +1911,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) ++ep; ++epfile; - } + } while (--count); wake_up_interruptible(&ffs->wait); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); @@ -3458,12 +3482,12 @@ static void ffs_func_unbind(struct usb_configuration *c, /* cleanup after autoconfig */ spin_lock_irqsave(&func->ffs->eps_lock, flags); - while (count--) { + do { if (ep->ep && ep->req) usb_ep_free_request(ep->ep, ep->req); ep->req = NULL; ++ep; - } + } while (--count); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); kfree(func->eps); func->eps = NULL;