f_fs.c:Pick up QCOM fixes for adb stability issue
authora17671 <a17671@motorola.com>
Sun, 3 Feb 2019 06:25:20 +0000 (14:25 +0800)
committerlingsen1 <lingsen1@lenovo.com>
Sun, 7 Feb 2021 09:36:56 +0000 (17:36 +0800)
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 <vvreddy@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
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 <vvreddy@codeaurora.org>
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 <mrana@codeaurora.org>
Change-Id: I48389d8d922e30aeb1215207ba138e36799df250
Signed-off-by: a17671 <a17671@motorola.com>
Reviewed-on: https://gerrit.mot.com/1304658
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com>
Submit-Approved: Jira Key

drivers/usb/gadget/function/f_fs.c

index f98fb379b270b7b29daa3e0e475e00b7850bd2f5..2936fed7fbe1a8b00fd36e4c4762fea80b648f37 100644 (file)
@@ -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 */
 
@@ -886,6 +886,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))
@@ -896,11 +900,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? */
@@ -1080,7 +1097,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;
 }
 
@@ -1198,6 +1217,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;
@@ -1846,7 +1866,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);
@@ -1857,7 +1881,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);
 }
 
@@ -1871,7 +1895,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);
@@ -1892,7 +1916,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);
@@ -3463,12 +3487,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;