The commit d3cb25a12138 ("usb: gadget: udc: fix spin_lock in pch_udc")
obviously was not thought through and had made the situation even worse
than it was before. Two changes after almost reverted it. but a few
leftovers have been left as it. With this revert d3cb25a12138 completely.

While at it, narrow down the scope of unlocked section to prevent
potential race when prot_stall is assigned.

Fixes: d3cb25a12138 ("usb: gadget: udc: fix spin_lock in pch_udc")
Fixes: 9903b6bedd38 ("usb: gadget: pch-udc: fix lock")
Fixes: 1d23d16a88e6 ("usb: gadget: pch_udc: reorder spin_[un]lock to avoid 
deadlock")
Cc: Iago Abal <[email protected]>
Signed-off-by: Andy Shevchenko <[email protected]>
---
v2: no changes
 drivers/usb/gadget/udc/pch_udc.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index a5365b524617..58cea8d3d68f 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -597,18 +597,22 @@ static void pch_udc_reconnect(struct pch_udc_dev *dev)
 static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
                                          int is_active)
 {
+       unsigned long           iflags;
+
+       spin_lock_irqsave(&dev->lock, iflags);
        if (is_active) {
                pch_udc_reconnect(dev);
                dev->vbus_session = 1;
        } else {
                if (dev->driver && dev->driver->disconnect) {
-                       spin_lock(&dev->lock);
+                       spin_unlock_irqrestore(&dev->lock, iflags);
                        dev->driver->disconnect(&dev->gadget);
-                       spin_unlock(&dev->lock);
+                       spin_lock_irqsave(&dev->lock, iflags);
                }
                pch_udc_set_disconnect(dev);
                dev->vbus_session = 0;
        }
+       spin_unlock_irqrestore(&dev->lock, iflags);
 }
 
 /**
@@ -1167,20 +1171,25 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget 
*gadget, int value)
 static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
 {
        struct pch_udc_dev      *dev;
+       unsigned long           iflags;
 
        if (!gadget)
                return -EINVAL;
+
        dev = container_of(gadget, struct pch_udc_dev, gadget);
+
+       spin_lock_irqsave(&dev->lock, iflags);
        if (is_on) {
                pch_udc_reconnect(dev);
        } else {
                if (dev->driver && dev->driver->disconnect) {
-                       spin_lock(&dev->lock);
+                       spin_unlock_irqrestore(&dev->lock, iflags);
                        dev->driver->disconnect(&dev->gadget);
-                       spin_unlock(&dev->lock);
+                       spin_lock_irqsave(&dev->lock, iflags);
                }
                pch_udc_set_disconnect(dev);
        }
+       spin_unlock_irqrestore(&dev->lock, iflags);
 
        return 0;
 }
-- 
2.30.2

Reply via email to