mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-05 19:31:57 -04:00
usb: chipidea: udc: protect usb interrupt enable
[ Upstream commit 72dc8df7920fc24eba0f586c56e900a1643ff2b3 ]
We hit the problem with below sequence:
- ci_udc_vbus_session() update vbus_active flag and ci->driver
is valid,
- before calling the ci_hdrc_gadget_connect(),
usb_gadget_udc_stop() is called by application remove gadget
driver,
- ci_udc_vbus_session() will contine do ci_hdrc_gadget_connect() as
gadget_ready is 1, so udc interrupt is enabled, but ci->driver is
NULL.
- USB connection irq generated but ci->driver is NULL.
As udc irq only should be enabled when gadget driver is binded, so
add spinlock to protect the usb irq enable for vbus session handling.
Signed-off-by: Jun Li <jun.li@nxp.com>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Stable-dep-of: b7a62611fab7 ("usb: chipidea: add USB PHY event")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
4fbf6bb0f9
commit
770809a958
1 changed files with 10 additions and 8 deletions
|
|
@ -1539,13 +1539,18 @@ static const struct usb_ep_ops usb_ep_ops = {
|
|||
static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
|
||||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
unsigned long flags;
|
||||
|
||||
if (is_active) {
|
||||
pm_runtime_get_sync(&_gadget->dev);
|
||||
hw_device_reset(ci);
|
||||
hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
|
||||
usb_udc_vbus_handler(_gadget, true);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (ci->driver) {
|
||||
hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
|
||||
usb_udc_vbus_handler(_gadget, true);
|
||||
}
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
} else {
|
||||
usb_udc_vbus_handler(_gadget, false);
|
||||
if (ci->driver)
|
||||
|
|
@ -1564,19 +1569,16 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
|
|||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
unsigned long flags;
|
||||
int gadget_ready = 0;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ci->vbus_active = is_active;
|
||||
if (ci->driver)
|
||||
gadget_ready = 1;
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
if (ci->usb_phy)
|
||||
usb_phy_set_charger_state(ci->usb_phy, is_active ?
|
||||
USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);
|
||||
|
||||
if (gadget_ready)
|
||||
if (ci->driver)
|
||||
ci_hdrc_gadget_connect(_gadget, is_active);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1836,6 +1838,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ci->driver = NULL;
|
||||
|
||||
if (ci->vbus_active) {
|
||||
hw_device_state(ci, 0);
|
||||
|
|
@ -1848,7 +1851,6 @@ static int ci_udc_stop(struct usb_gadget *gadget)
|
|||
pm_runtime_put(&ci->gadget.dev);
|
||||
}
|
||||
|
||||
ci->driver = NULL;
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
ci_udc_stop_for_otg_fsm(ci);
|
||||
|
|
|
|||
Loading…
Reference in a new issue