forked from luck/tmp_suning_uos_patched
usb: dwc3: patches for v3.7 merge window
Some much needed changes for our dwc3 driver. First there's a rework on the ep0 handling due to some Silicon issue we uncovered which affects all users of this IP core (there's a missing XferNotReady(DATA) event in some conditions). This issue which show up as a SETUP transfers which wouldn't complete ever and we would fail TD 7.06 of the Link Layer Test from USB-IF and Lecroy's USB3 Exerciser. We also fix a long standing bug regarding EP0 enable sequencing where we weren't setting a particular bit (Ignore Sequence Number). Since we never saw any problems caused by that, it didn't deserve being sent to stable tree. On this pull request we also fix Burst Size initialization which should be done only in SuperSpeed and we were mistakenly setting Burst Size to the maximum value on non-SuperSpeed mode. Again, since we never saw any problems caused by that, we're not sending this patch to stable. There's also a memory ordering fix regarding usage of bitmaps in dwc3 driver. You will also find some sparse warnings fix, a fix for missed isochronous packets when the endpoint is already busy, and a fix for synchronization delay on dwc3_stop_active_transfer(). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQThLOAAoJEIaOsuA1yqREPB0P/igbry8UxYEfFA6+ojRmeS3x AztAUUixXsl44lQOLtl/VSuKqvhiIJ7VniBgL+nj1HdeJPMG6bdjBLwl2LjYBCQq xZbv07isqHqg8ntiGwOADQztU7p4BPGpDztogsTlNjUhclCvUwE9ZTf4Moe7Cnk8 TePUypvt3WQceWBpZxMd9Zirpmls0UTUW287OgQ+ik6QccokzQXxfzD5z3tS0bwo nRjWReihPJU68p5wcbILjo4VmhBsllYrRxB8CIatqxfjj6OssJ0ifcO6+jn7bnc5 T8OStPK8FigTLdNuV4sx3MCu9ItSY1+Y+gRnfXpdbkEqU303qI/rOC0jnmEhAhr1 /mS9llhCkfknpvL/DSlQnYzwfNA4wFjTLNoxOEDNkYNE84T+YAfZI1DGBvwJoYlZ NELQTJB2enVADmMyOwQcXwx7wu2uW7Sb6FcbYpIsZyADZVJPqtjG1o09d19xL0z5 YdP23D/A6/I6SySvW8cDy9F3ouCQfrkeEd71KF2+4s7zHZhU9cqFA65xOZ7FRB++ nUsTHCn07doqp+5vsRLV0BKPk3YH9mEg0aVv4ClSE57wZFPFAqXU5GtEgJ9mBAnv 3poV22oTvGdWuG3vzAAk83pnQPyxxv4DgDLc3gaKZXhecLDRp0O4uucuHrmyV5tn eynhmX9bDB5hLGN5KJtX =Lqwl -----END PGP SIGNATURE----- Merge tag 'dwc3-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next usb: dwc3: patches for v3.7 merge window Some much needed changes for our dwc3 driver. First there's a rework on the ep0 handling due to some Silicon issue we uncovered which affects all users of this IP core (there's a missing XferNotReady(DATA) event in some conditions). This issue which show up as a SETUP transfers which wouldn't complete ever and we would fail TD 7.06 of the Link Layer Test from USB-IF and Lecroy's USB3 Exerciser. We also fix a long standing bug regarding EP0 enable sequencing where we weren't setting a particular bit (Ignore Sequence Number). Since we never saw any problems caused by that, it didn't deserve being sent to stable tree. On this pull request we also fix Burst Size initialization which should be done only in SuperSpeed and we were mistakenly setting Burst Size to the maximum value on non-SuperSpeed mode. Again, since we never saw any problems caused by that, we're not sending this patch to stable. There's also a memory ordering fix regarding usage of bitmaps in dwc3 driver. You will also find some sparse warnings fix, a fix for missed isochronous packets when the endpoint is already busy, and a fix for synchronization delay on dwc3_stop_active_transfer().
This commit is contained in:
commit
e6d49d093e
@ -100,6 +100,7 @@ void dwc3_put_device_id(int id)
|
||||
|
||||
ret = test_bit(id, dwc3_devs);
|
||||
WARN(!ret, "dwc3: ID %d not in use\n", id);
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(id, dwc3_devs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc3_put_device_id);
|
||||
@ -462,7 +463,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
regs = devm_ioremap(dev, res->start, resource_size(res));
|
||||
regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||
if (!regs) {
|
||||
dev_err(dev, "ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
|
@ -457,7 +457,6 @@ enum dwc3_phy {
|
||||
enum dwc3_ep0_next {
|
||||
DWC3_EP0_UNKNOWN = 0,
|
||||
DWC3_EP0_COMPLETE,
|
||||
DWC3_EP0_NRDY_SETUP,
|
||||
DWC3_EP0_NRDY_DATA,
|
||||
DWC3_EP0_NRDY_STATUS,
|
||||
};
|
||||
@ -784,7 +783,6 @@ struct dwc3_event_depevt {
|
||||
#define DEPEVT_STREAMEVT_NOTFOUND 2
|
||||
|
||||
/* Control-only Status */
|
||||
#define DEPEVT_STATUS_CONTROL_SETUP 0
|
||||
#define DEPEVT_STATUS_CONTROL_DATA 1
|
||||
#define DEPEVT_STATUS_CONTROL_STATUS 2
|
||||
|
||||
|
@ -125,7 +125,6 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int ret = 0;
|
||||
|
||||
req->request.actual = 0;
|
||||
req->request.status = -EINPROGRESS;
|
||||
@ -156,16 +155,72 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
|
||||
dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
|
||||
DWC3_EP0_DIR_IN);
|
||||
} else if (dwc->delayed_status) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case gadget driver asked us to delay the STATUS phase,
|
||||
* handle it here.
|
||||
*/
|
||||
if (dwc->delayed_status) {
|
||||
unsigned direction;
|
||||
|
||||
direction = !dwc->ep0_expect_in;
|
||||
dwc->delayed_status = false;
|
||||
|
||||
if (dwc->ep0state == EP0_STATUS_PHASE)
|
||||
__dwc3_ep0_do_control_status(dwc, dwc->eps[1]);
|
||||
__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
|
||||
else
|
||||
dev_dbg(dwc->dev, "too early for delayed status\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/*
|
||||
* Unfortunately we have uncovered a limitation wrt the Data Phase.
|
||||
*
|
||||
* Section 9.4 says we can wait for the XferNotReady(DATA) event to
|
||||
* come before issueing Start Transfer command, but if we do, we will
|
||||
* miss situations where the host starts another SETUP phase instead of
|
||||
* the DATA phase. Such cases happen at least on TD.7.6 of the Link
|
||||
* Layer Compliance Suite.
|
||||
*
|
||||
* The problem surfaces due to the fact that in case of back-to-back
|
||||
* SETUP packets there will be no XferNotReady(DATA) generated and we
|
||||
* will be stuck waiting for XferNotReady(DATA) forever.
|
||||
*
|
||||
* By looking at tables 9-13 and 9-14 of the Databook, we can see that
|
||||
* it tells us to start Data Phase right away. It also mentions that if
|
||||
* we receive a SETUP phase instead of the DATA phase, core will issue
|
||||
* XferComplete for the DATA phase, before actually initiating it in
|
||||
* the wire, with the TRB's status set to "SETUP_PENDING". Such status
|
||||
* can only be used to print some debugging logs, as the core expects
|
||||
* us to go through to the STATUS phase and start a CONTROL_STATUS TRB,
|
||||
* just so it completes right away, without transferring anything and,
|
||||
* only then, we can go back to the SETUP phase.
|
||||
*
|
||||
* Because of this scenario, SNPS decided to change the programming
|
||||
* model of control transfers and support on-demand transfers only for
|
||||
* the STATUS phase. To fix the issue we have now, we will always wait
|
||||
* for gadget driver to queue the DATA phase's struct usb_request, then
|
||||
* start it right away.
|
||||
*
|
||||
* If we're actually in a 2-stage transfer, we will wait for
|
||||
* XferNotReady(STATUS).
|
||||
*/
|
||||
if (dwc->three_stage_setup) {
|
||||
unsigned direction;
|
||||
|
||||
direction = dwc->ep0_expect_in;
|
||||
dwc->ep0state = EP0_DATA_PHASE;
|
||||
|
||||
__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
|
||||
|
||||
dep->flags &= ~DWC3_EP0_DIR_IN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
@ -207,9 +262,14 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
|
||||
static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep = dwc->eps[0];
|
||||
struct dwc3_ep *dep;
|
||||
|
||||
/* reinitialize physical ep1 */
|
||||
dep = dwc->eps[1];
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
|
||||
/* stall is always issued on EP0 */
|
||||
dep = dwc->eps[0];
|
||||
__dwc3_gadget_ep_set_halt(dep, 1);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
dwc->delayed_status = false;
|
||||
@ -698,6 +758,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *ep0;
|
||||
u32 transferred;
|
||||
u32 status;
|
||||
u32 length;
|
||||
u8 epnum;
|
||||
|
||||
@ -710,6 +771,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
ur = &r->request;
|
||||
|
||||
trb = dwc->ep0_trb;
|
||||
|
||||
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
if (status == DWC3_TRBSTS_SETUP_PENDING) {
|
||||
dev_dbg(dwc->dev, "Setup Pending received\n");
|
||||
|
||||
if (r)
|
||||
dwc3_gadget_giveback(ep0, r, -ECONNRESET);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
if (dwc->ep0_bounced) {
|
||||
@ -746,8 +818,11 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||
{
|
||||
struct dwc3_request *r;
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3_trb *trb;
|
||||
u32 status;
|
||||
|
||||
dep = dwc->eps[0];
|
||||
trb = dwc->ep0_trb;
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
r = next_request(&dep->request_list);
|
||||
@ -767,6 +842,10 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||
}
|
||||
}
|
||||
|
||||
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
if (status == DWC3_TRBSTS_SETUP_PENDING)
|
||||
dev_dbg(dwc->dev, "Setup Pending received\n");
|
||||
|
||||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
@ -800,12 +879,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
||||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
@ -858,29 +931,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3_request *req;
|
||||
|
||||
dep = dwc->eps[0];
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
|
||||
if (event->endpoint_number)
|
||||
dep->flags |= DWC3_EP0_DIR_IN;
|
||||
return;
|
||||
}
|
||||
|
||||
req = next_request(&dep->request_list);
|
||||
dep = dwc->eps[event->endpoint_number];
|
||||
|
||||
__dwc3_ep0_do_control_data(dwc, dep, req);
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
@ -912,100 +962,61 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
|
||||
__dwc3_ep0_do_control_status(dwc, dep);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
u32 cmd;
|
||||
int ret;
|
||||
|
||||
if (!dep->resource_index)
|
||||
return;
|
||||
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
dep->resource_index = 0;
|
||||
}
|
||||
|
||||
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
dwc->setup_packet_pending = true;
|
||||
|
||||
/*
|
||||
* This part is very tricky: If we have just handled
|
||||
* XferNotReady(Setup) and we're now expecting a
|
||||
* XferComplete but, instead, we receive another
|
||||
* XferNotReady(Setup), we should STALL and restart
|
||||
* the state machine.
|
||||
*
|
||||
* In all other cases, we just continue waiting
|
||||
* for the XferComplete event.
|
||||
*
|
||||
* We are a little bit unsafe here because we're
|
||||
* not trying to ensure that last event was, indeed,
|
||||
* XferNotReady(Setup).
|
||||
*
|
||||
* Still, we don't expect any condition where that
|
||||
* should happen and, even if it does, it would be
|
||||
* another error condition.
|
||||
*/
|
||||
if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
|
||||
switch (event->status) {
|
||||
case DEPEVT_STATUS_CONTROL_SETUP:
|
||||
dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
break;
|
||||
case DEPEVT_STATUS_CONTROL_DATA:
|
||||
/* FALLTHROUGH */
|
||||
case DEPEVT_STATUS_CONTROL_STATUS:
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
dev_vdbg(dwc->dev, "waiting for XferComplete\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->status) {
|
||||
case DEPEVT_STATUS_CONTROL_SETUP:
|
||||
dev_vdbg(dwc->dev, "Control Setup\n");
|
||||
|
||||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
|
||||
dwc3_ep0_do_control_setup(dwc, event);
|
||||
break;
|
||||
|
||||
case DEPEVT_STATUS_CONTROL_DATA:
|
||||
dev_vdbg(dwc->dev, "Control Data\n");
|
||||
|
||||
dwc->ep0state = EP0_DATA_PHASE;
|
||||
|
||||
if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
|
||||
dev_vdbg(dwc->dev, "Expected %d got %d\n",
|
||||
dwc->ep0_next_event,
|
||||
DWC3_EP0_NRDY_DATA);
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* One of the possible error cases is when Host _does_
|
||||
* request for Data Phase, but it does so on the wrong
|
||||
* direction.
|
||||
* We already have a DATA transfer in the controller's cache,
|
||||
* if we receive a XferNotReady(DATA) we will ignore it, unless
|
||||
* it's for the wrong direction.
|
||||
*
|
||||
* Here, we already know ep0_next_event is DATA (see above),
|
||||
* so we only need to check for direction.
|
||||
* In that case, we must issue END_TRANSFER command to the Data
|
||||
* Phase we already have started and issue SetStall on the
|
||||
* control endpoint.
|
||||
*/
|
||||
if (dwc->ep0_expect_in != event->endpoint_number) {
|
||||
struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in];
|
||||
|
||||
dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
|
||||
dwc3_ep0_end_control_data(dwc, dep);
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
return;
|
||||
}
|
||||
|
||||
dwc3_ep0_do_control_data(dwc, event);
|
||||
break;
|
||||
|
||||
case DEPEVT_STATUS_CONTROL_STATUS:
|
||||
if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS)
|
||||
return;
|
||||
|
||||
dev_vdbg(dwc->dev, "Control Status\n");
|
||||
|
||||
dwc->ep0state = EP0_STATUS_PHASE;
|
||||
|
||||
if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
|
||||
dev_vdbg(dwc->dev, "Expected %d got %d\n",
|
||||
dwc->ep0_next_event,
|
||||
DWC3_EP0_NRDY_STATUS);
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dwc->delayed_status) {
|
||||
WARN_ON_ONCE(event->endpoint_number != 1);
|
||||
dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
|
||||
|
@ -431,15 +431,25 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
|
||||
static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
const struct usb_endpoint_descriptor *desc,
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc)
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc,
|
||||
bool ignore)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
|
||||
memset(¶ms, 0x00, sizeof(params));
|
||||
|
||||
params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
|
||||
| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
|
||||
| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1);
|
||||
| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
|
||||
|
||||
/* Burst size is only needed in SuperSpeed mode */
|
||||
if (dwc->gadget.speed == USB_SPEED_SUPER) {
|
||||
u32 burst = dep->endpoint.maxburst - 1;
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
|
||||
}
|
||||
|
||||
if (ignore)
|
||||
params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
|
||||
|
||||
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
|
||||
| DWC3_DEPCFG_XFER_NOT_READY_EN;
|
||||
@ -498,7 +508,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
*/
|
||||
static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
const struct usb_endpoint_descriptor *desc,
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc)
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc,
|
||||
bool ignore)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
u32 reg;
|
||||
@ -510,7 +521,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
|
||||
ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -558,27 +569,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
if (!list_empty(&dep->req_queued)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
|
||||
/*
|
||||
* NOTICE: We are violating what the Databook says about the
|
||||
* EndTransfer command. Ideally we would _always_ wait for the
|
||||
* EndTransfer Command Completion IRQ, but that's causing too
|
||||
* much trouble synchronizing between us and gadget driver.
|
||||
*
|
||||
* We have discussed this with the IP Provider and it was
|
||||
* suggested to giveback all requests here, but give HW some
|
||||
* extra time to synchronize with the interconnect. We're using
|
||||
* an arbitraty 100us delay for that.
|
||||
*
|
||||
* Note also that a similar handling was tested by Synopsys
|
||||
* (thanks a lot Paul) and nothing bad has come out of it.
|
||||
* In short, what we're doing is:
|
||||
*
|
||||
* - Issue EndTransfer WITH CMDIOC bit set
|
||||
* - Wait 100us
|
||||
* - giveback all requests to gadget driver
|
||||
*/
|
||||
udelay(100);
|
||||
|
||||
/* - giveback all requests to gadget driver */
|
||||
while (!list_empty(&dep->req_queued)) {
|
||||
req = next_request(&dep->req_queued);
|
||||
|
||||
@ -657,6 +648,12 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
|
||||
dep = to_dwc3_ep(ep);
|
||||
dwc = dep->dwc;
|
||||
|
||||
if (dep->flags & DWC3_EP_ENABLED) {
|
||||
dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
|
||||
dep->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
strlcat(dep->name, "-control", sizeof(dep->name));
|
||||
@ -674,16 +671,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
|
||||
dev_err(dwc->dev, "invalid endpoint transfer type\n");
|
||||
}
|
||||
|
||||
if (dep->flags & DWC3_EP_ENABLED) {
|
||||
dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
|
||||
dep->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
|
||||
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
@ -1087,15 +1078,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
*
|
||||
*/
|
||||
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1104,16 +1090,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
* core may not see the modified TRB(s).
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
(dep->flags & DWC3_EP_BUSY)) {
|
||||
(dep->flags & DWC3_EP_BUSY) &&
|
||||
!(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
||||
WARN_ON_ONCE(!dep->resource_index);
|
||||
ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
|
||||
false);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1518,14 +1502,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
goto err1;
|
||||
@ -1750,7 +1734,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
|
||||
struct dwc3_ep *dep = dwc->eps[i];
|
||||
dep = dwc->eps[i];
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
@ -1877,6 +1861,25 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||
if (!dep->resource_index)
|
||||
return;
|
||||
|
||||
/*
|
||||
* NOTICE: We are violating what the Databook says about the
|
||||
* EndTransfer command. Ideally we would _always_ wait for the
|
||||
* EndTransfer Command Completion IRQ, but that's causing too
|
||||
* much trouble synchronizing between us and gadget driver.
|
||||
*
|
||||
* We have discussed this with the IP Provider and it was
|
||||
* suggested to giveback all requests here, but give HW some
|
||||
* extra time to synchronize with the interconnect. We're using
|
||||
* an arbitraty 100us delay for that.
|
||||
*
|
||||
* Note also that a similar handling was tested by Synopsys
|
||||
* (thanks a lot Paul) and nothing bad has come out of it.
|
||||
* In short, what we're doing is:
|
||||
*
|
||||
* - Issue EndTransfer WITH CMDIOC bit set
|
||||
* - Wait 100us
|
||||
*/
|
||||
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
@ -1884,6 +1887,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
dep->resource_index = 0;
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfers(struct dwc3 *dwc)
|
||||
@ -2141,14 +2146,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
}
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
return;
|
||||
}
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user