UPSTREAM: usb: dwc3: gadget: Refactor EP0 forced stall/restart into a separate API
Several sequences utilize the same routine for forcing the control endpoint back into the SETUP phase. This is required, because those operations need to ensure that EP0 is back in the default state. Fixes: c96683798e27 ("usb: dwc3: ep0: Don't prepare beyond Setup stage") Cc: stable@vger.kernel.org Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Link: https://lore.kernel.org/r/20230420212759.29429-2-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Bug: 327520570 Change-Id: I9b468a021b04e765b074d9b48f46c6e828022705 (cherry picked from commit 8f40fc0808137c157dd408d2632e63bfca2aecdb) Signed-off-by: Prashanth K <quic_prashk@quicinc.com>
This commit is contained in:

committed by
Treehugger Robot

parent
f6c4f779c6
commit
5e21de099e
@@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
|||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dwc3_ep0_reset_state(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
unsigned int dir;
|
||||||
|
|
||||||
|
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||||
|
dir = !!dwc->ep0_expect_in;
|
||||||
|
if (dwc->ep0state == EP0_DATA_PHASE)
|
||||||
|
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
||||||
|
else
|
||||||
|
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
||||||
|
|
||||||
|
dwc->eps[0]->trb_enqueue = 0;
|
||||||
|
dwc->eps[1]->trb_enqueue = 0;
|
||||||
|
|
||||||
|
dwc3_ep0_stall_and_restart(dwc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc3_ep_inc_trb - increment a trb index.
|
* dwc3_ep_inc_trb - increment a trb index.
|
||||||
* @index: Pointer to the TRB index to increment.
|
* @index: Pointer to the TRB index to increment.
|
||||||
@@ -2547,16 +2565,9 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
|
|||||||
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
|
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
|
||||||
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
|
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
unsigned int dir;
|
|
||||||
|
|
||||||
dev_warn(dwc->dev, "wait for SETUP phase timed out\n");
|
dev_warn(dwc->dev, "wait for SETUP phase timed out\n");
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
dir = !!dwc->ep0_expect_in;
|
dwc3_ep0_reset_state(dwc);
|
||||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
|
||||||
else
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
|
||||||
dwc3_ep0_stall_and_restart(dwc);
|
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3849,16 +3860,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
|||||||
dwc->setup_packet_pending = false;
|
dwc->setup_packet_pending = false;
|
||||||
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
|
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
|
||||||
|
|
||||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
dwc3_ep0_reset_state(dwc);
|
||||||
unsigned int dir;
|
|
||||||
|
|
||||||
dir = !!dwc->ep0_expect_in;
|
|
||||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
|
||||||
else
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
|
||||||
dwc3_ep0_stall_and_restart(dwc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||||
@@ -3912,20 +3914,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|||||||
* phase. So ensure that EP0 is in setup phase by issuing a stall
|
* phase. So ensure that EP0 is in setup phase by issuing a stall
|
||||||
* and restart if EP0 is not in setup phase.
|
* and restart if EP0 is not in setup phase.
|
||||||
*/
|
*/
|
||||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
dwc3_ep0_reset_state(dwc);
|
||||||
unsigned int dir;
|
|
||||||
|
|
||||||
dir = !!dwc->ep0_expect_in;
|
|
||||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
|
||||||
else
|
|
||||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
|
||||||
|
|
||||||
dwc->eps[0]->trb_enqueue = 0;
|
|
||||||
dwc->eps[1]->trb_enqueue = 0;
|
|
||||||
|
|
||||||
dwc3_ep0_stall_and_restart(dwc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
|
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
|
||||||
|
Reference in New Issue
Block a user