This is a note to let you know that I've just added the patch titled

    usb: gadget: pch_udc: Fix usb/gadget/pch_udc: Fix ether gadget 
connect/disconnect issue

to the 3.2-stable tree which can be found at:
    
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     usb-gadget-pch_udc-fix-usb-gadget-pch_udc-fix-ether.patch
and it can be found in the queue-3.2 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.


>From 1c575d2d2e3ff2a7cb3c2e2165064199cfd8ad32 Mon Sep 17 00:00:00 2001
From: Tomoya MORINAGA <[email protected]>
Date: Thu, 12 Jan 2012 11:27:08 +0900
Subject: usb: gadget: pch_udc: Fix usb/gadget/pch_udc: Fix ether gadget 
connect/disconnect issue

From: Tomoya MORINAGA <[email protected]>

commit 1c575d2d2e3ff2a7cb3c2e2165064199cfd8ad32 upstream.

ISSUE:
After a USB cable is connect/disconnected, the system rarely freezes.

CAUSE:
Since the USB device controller cannot know to disconnect the USB cable, when
it is used without detecting VBUS by GPIO, the UDC driver does not notify to
USB Gadget.

Since USB Gadget cannot know to disconnect, a false setting occurred when the
USB cable is connected/disconnect repeatedly.

Signed-off-by: Tomoya MORINAGA <[email protected]>
Signed-off-by: Felipe Balbi <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 drivers/usb/gadget/pch_udc.c |   70 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 4 deletions(-)

--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -311,6 +311,7 @@ struct pch_udc_ep {
  * @registered:                driver regsitered with system
  * @suspended:         driver in suspended state
  * @connected:         gadget driver associated
+ * @vbus_session:      required vbus_session state
  * @set_cfg_not_acked: pending acknowledgement 4 setup
  * @waiting_zlp_ack:   pending acknowledgement 4 ZLP
  * @data_requests:     DMA pool for data requests
@@ -337,6 +338,7 @@ struct pch_udc_dev {
                        registered:1,
                        suspended:1,
                        connected:1,
+                       vbus_session:1,
                        set_cfg_not_acked:1,
                        waiting_zlp_ack:1;
        struct pci_pool         *data_requests;
@@ -554,6 +556,31 @@ static void pch_udc_clear_disconnect(str
 }
 
 /**
+ * pch_udc_reconnect() - This API initializes usb device controller,
+ *                                             and clear the disconnect status.
+ * @dev:               Reference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev);
+static void pch_udc_reconnect(struct pch_udc_dev *dev)
+{
+       pch_udc_init(dev);
+
+       /* enable device interrupts */
+       /* pch_udc_enable_interrupts() */
+       pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
+                       UDC_DEVINT_UR | UDC_DEVINT_US |
+                       UDC_DEVINT_ENUM |
+                       UDC_DEVINT_SI | UDC_DEVINT_SC);
+
+       /* Clear the disconnect */
+       pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+       pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+       mdelay(1);
+       /* Resume USB signalling */
+       pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
  * pch_udc_vbus_session() - set or clearr the disconnect status.
  * @dev:       Reference to pch_udc_regs structure
  * @is_active: Parameter specifying the action
@@ -563,10 +590,18 @@ static void pch_udc_clear_disconnect(str
 static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
                                          int is_active)
 {
-       if (is_active)
-               pch_udc_clear_disconnect(dev);
-       else
+       if (is_active) {
+               pch_udc_reconnect(dev);
+               dev->vbus_session = 1;
+       } else {
+               if (dev->driver && dev->driver->disconnect) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
                pch_udc_set_disconnect(dev);
+               dev->vbus_session = 0;
+       }
 }
 
 /**
@@ -1126,7 +1161,17 @@ static int pch_udc_pcd_pullup(struct usb
        if (!gadget)
                return -EINVAL;
        dev = container_of(gadget, struct pch_udc_dev, gadget);
-       pch_udc_vbus_session(dev, is_on);
+       if (is_on) {
+               pch_udc_reconnect(dev);
+       } else {
+               if (dev->driver && dev->driver->disconnect) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
+               pch_udc_set_disconnect(dev);
+       }
+
        return 0;
 }
 
@@ -2482,6 +2527,15 @@ static void pch_udc_dev_isr(struct pch_u
                        dev->driver->suspend(&dev->gadget);
                        spin_lock(&dev->lock);
                }
+
+               if (dev->vbus_session == 0) {
+                       if (dev->driver && dev->driver->disconnect) {
+                               spin_unlock(&dev->lock);
+                               dev->driver->disconnect(&dev->gadget);
+                               spin_lock(&dev->lock);
+                       }
+                       pch_udc_reconnect(dev);
+               }
                dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
        }
        /* Clear the SOF interrupt, if enabled */
@@ -2509,6 +2563,14 @@ static irqreturn_t pch_udc_isr(int irq,
        dev_intr = pch_udc_read_device_interrupts(dev);
        ep_intr = pch_udc_read_ep_interrupts(dev);
 
+       /* For a hot plug, this find that the controller is hung up. */
+       if (dev_intr == ep_intr)
+               if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
+                       dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
+                       /* The controller is reset */
+                       pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+                       return IRQ_HANDLED;
+               }
        if (dev_intr)
                /* Clear device interrupts */
                pch_udc_write_device_interrupts(dev, dev_intr);


Patches currently in stable-queue which might be from [email protected] are

queue-3.2/usb-gadget-pch_udc-fix-usb-suspend-issue.patch
queue-3.2/pch_uart-fix-msi-setting-issue.patch
queue-3.2/gpio-add-missing-spin_lock_init-in-gpio-pch-driver.patch
queue-3.2/usb-gadget-pch_udc-fix-wrong-return-value.patch
queue-3.2/usb-gadget-pch_udc-fix-usb-gadget-pch_udc-fix-ether.patch
queue-3.2/usb-gadget-pch_udc-fix-disconnect-issue.patch
queue-3.2/usb-gadget-pch_udc-reduce-redundant-interrupt.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to