OpenCloudOS-Kernel/drivers/usb/dwc3/gadget.c

4433 lines
115 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "debug.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
#define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \
& ~((d)->interval - 1))
/**
* dwc3_gadget_set_test_mode - enables usb2 test modes
* @dwc: pointer to our context structure
* @mode: the mode to set (J, K SE0 NAK, Force Enable)
*
* Caller should take care of locking. This function will return 0 on
* success or -EINVAL if wrong Test Selector is passed.
*/
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
switch (mode) {
case USB_TEST_J:
case USB_TEST_K:
case USB_TEST_SE0_NAK:
case USB_TEST_PACKET:
case USB_TEST_FORCE_ENABLE:
reg |= mode << 1;
break;
default:
return -EINVAL;
}
dwc3_gadget_dctl_write_safe(dwc, reg);
return 0;
}
/**
* dwc3_gadget_get_link_state - gets current state of usb link
* @dwc: pointer to our context structure
*
* Caller should take care of locking. This function will
* return the link state on success (>= 0) or -ETIMEDOUT.
*/
int dwc3_gadget_get_link_state(struct dwc3 *dwc)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
return DWC3_DSTS_USBLNKST(reg);
}
/**
* dwc3_gadget_set_link_state - sets usb link to a particular state
* @dwc: pointer to our context structure
* @state: the state to put link into
*
* Caller should take care of locking. This function will
* return 0 on success or -ETIMEDOUT.
*/
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
{
int retries = 10000;
u32 reg;
/*
* Wait until device controller is ready. Only applies to 1.94a and
* later RTL.
*/
2020-04-12 10:20:01 +08:00
if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) {
while (--retries) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
if (reg & DWC3_DSTS_DCNRD)
udelay(5);
else
break;
}
if (retries <= 0)
return -ETIMEDOUT;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
/* set no action before sending new link state change */
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* set requested state */
reg |= DWC3_DCTL_ULSTCHNGREQ(state);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/*
* The following code is racy when called from dwc3_gadget_wakeup,
* and is not needed, at least on newer versions
*/
2020-04-12 10:20:01 +08:00
if (!DWC3_VER_IS_PRIOR(DWC3, 194A))
return 0;
/* wait for a change in DSTS */
retries = 10000;
while (--retries) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
if (DWC3_DSTS_USBLNKST(reg) == state)
return 0;
udelay(5);
}
return -ETIMEDOUT;
}
/**
* dwc3_ep_inc_trb - increment a trb index.
* @index: Pointer to the TRB index to increment.
*
* The index should never point to the link TRB. After incrementing,
* if it is point to the link TRB, wrap around to the beginning. The
* link TRB is always at the last TRB entry.
*/
static void dwc3_ep_inc_trb(u8 *index)
{
(*index)++;
if (*index == (DWC3_TRB_NUM - 1))
*index = 0;
}
/**
* dwc3_ep_inc_enq - increment endpoint's enqueue pointer
* @dep: The endpoint whose enqueue pointer we're incrementing
*/
static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
{
dwc3_ep_inc_trb(&dep->trb_enqueue);
}
/**
* dwc3_ep_inc_deq - increment endpoint's dequeue pointer
* @dep: The endpoint whose enqueue pointer we're incrementing
*/
static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
{
dwc3_ep_inc_trb(&dep->trb_dequeue);
}
static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
struct dwc3_request *req, int status)
{
struct dwc3 *dwc = dep->dwc;
list_del(&req->list);
req->remaining = 0;
req->needs_extra_trb = false;
if (req->request.status == -EINPROGRESS)
req->request.status = status;
if (req->trb)
usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction);
req->trb = NULL;
trace_dwc3_gadget_giveback(req);
if (dep->number > 1)
pm_runtime_put(dwc->dev);
}
/**
* dwc3_gadget_giveback - call struct usb_request's ->complete callback
* @dep: The endpoint to whom the request belongs to
* @req: The request we're giving back
* @status: completion code for the request
*
* Must be called with controller's lock held and interrupts disabled. This
* function will unmap @req and call its ->complete() callback to notify upper
* layers that it has completed.
*/
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status)
{
struct dwc3 *dwc = dep->dwc;
dwc3_gadget_del_and_unmap_request(dep, req, status);
req->status = DWC3_REQUEST_STATUS_COMPLETED;
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
}
/**
* dwc3_send_gadget_generic_command - issue a generic command for the controller
* @dwc: pointer to the controller context
* @cmd: the command to be issued
* @param: command parameter
*
* Caller should take care of locking. Issue @cmd with a given @param to @dwc
* and wait for its completion.
*/
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
u32 param)
{
u32 timeout = 500;
int status = 0;
int ret = 0;
u32 reg;
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
status = DWC3_DGCMD_STATUS(reg);
if (status)
ret = -EINVAL;
break;
}
} while (--timeout);
if (!timeout) {
ret = -ETIMEDOUT;
status = -ETIMEDOUT;
}
trace_dwc3_gadget_generic_cmd(cmd, param, status);
return ret;
}
static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
/**
* dwc3_send_gadget_ep_cmd - issue an endpoint command
* @dep: the endpoint to which the command is going to be issued
* @cmd: the command to be issued
* @params: parameters to the command
*
* Caller should handle locking. This function will issue @cmd with given
* @params to @dep and wait for its completion.
*/
int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
struct dwc3_gadget_ep_cmd_params *params)
{
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
struct dwc3 *dwc = dep->dwc;
u32 timeout = 5000;
u32 saved_config = 0;
u32 reg;
int cmd_status = 0;
int ret = -EINVAL;
/*
* When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
* GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an
* endpoint command.
*
* Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY
* settings. Restore them after the command is completed.
*
* DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
*/
if (dwc->gadget->speed <= USB_SPEED_HIGH) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
}
if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
}
if (saved_config)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
int link_state;
/*
* Initiate remote wakeup if the link state is in U3 when
* operating in SS/SSP or L1/L2 when operating in HS/FS. If the
* link state is in U1/U2, no remote wakeup is needed. The Start
* Transfer command will initiate the link recovery.
*/
link_state = dwc3_gadget_get_link_state(dwc);
switch (link_state) {
case DWC3_LINK_STATE_U2:
if (dwc->gadget->speed >= USB_SPEED_SUPER)
break;
fallthrough;
case DWC3_LINK_STATE_U3:
ret = __dwc3_gadget_wakeup(dwc);
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
ret);
break;
}
}
/*
* For some commands such as Update Transfer command, DEPCMDPARn
* registers are reserved. Since the driver often sends Update Transfer
* command, don't write to DEPCMDPARn to avoid register write delays and
* improve performance.
*/
if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_UPDATETRANSFER) {
dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);
dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);
}
/*
* Synopsys Databook 2.60a states in section 6.3.2.5.6 of that if we're
* not relying on XferNotReady, we can make use of a special "No
* Response Update Transfer" command where we should clear both CmdAct
* and CmdIOC bits.
*
* With this, we don't need to wait for command completion and can
* straight away issue further commands to the endpoint.
*
* NOTICE: We're making an assumption that control endpoints will never
* make use of Update Transfer command. This is a safe assumption
* because we can never have more than one request at a time with
* Control Endpoints. If anybody changes that assumption, this chunk
* needs to be updated accordingly.
*/
if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_UPDATETRANSFER &&
!usb_endpoint_xfer_isoc(desc))
cmd &= ~(DWC3_DEPCMD_CMDIOC | DWC3_DEPCMD_CMDACT);
else
cmd |= DWC3_DEPCMD_CMDACT;
dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
if (!(cmd & DWC3_DEPCMD_CMDACT)) {
ret = 0;
goto skip_status;
}
do {
reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
if (!(reg & DWC3_DEPCMD_CMDACT)) {
cmd_status = DWC3_DEPCMD_STATUS(reg);
switch (cmd_status) {
case 0:
ret = 0;
break;
case DEPEVT_TRANSFER_NO_RESOURCE:
dev_WARN(dwc->dev, "No resource for %s\n",
dep->name);
ret = -EINVAL;
break;
case DEPEVT_TRANSFER_BUS_EXPIRY:
/*
* SW issues START TRANSFER command to
* isochronous ep with future frame interval. If
* future interval time has already passed when
* core receives the command, it will respond
* with an error status of 'Bus Expiry'.
*
* Instead of always returning -EINVAL, let's
* give a hint to the gadget driver that this is
* the case by returning -EAGAIN.
*/
ret = -EAGAIN;
break;
default:
dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
}
break;
}
} while (--timeout);
if (timeout == 0) {
ret = -ETIMEDOUT;
cmd_status = -ETIMEDOUT;
}
skip_status:
trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
if (ret == 0)
dep->flags |= DWC3_EP_TRANSFER_STARTED;
if (ret != -ETIMEDOUT)
dwc3_gadget_ep_get_transfer_index(dep);
}
if (saved_config) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= saved_config;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
return ret;
}
static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd = DWC3_DEPCMD_CLEARSTALL;
/*
* As of core revision 2.60a the recommended programming model
* is to set the ClearPendIN bit when issuing a Clear Stall EP
* command for IN endpoints. This is to prevent an issue where
* some (non-compliant) hosts may not send ACK TPs for pending
* IN transfers due to a mishandled error condition. Synopsys
* STAR 9000614252.
*/
2020-04-12 10:20:01 +08:00
if (dep->direction &&
!DWC3_VER_IS_PRIOR(DWC3, 260A) &&
(dwc->gadget->speed >= USB_SPEED_SUPER))
cmd |= DWC3_DEPCMD_CLEARPENDIN;
memset(&params, 0, sizeof(params));
return dwc3_send_gadget_ep_cmd(dep, cmd, &params);
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
return dep->trb_pool_dma + offset;
}
static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
if (dep->trb_pool)
return 0;
dep->trb_pool = dma_alloc_coherent(dwc->sysdev,
sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
&dep->trb_pool_dma, GFP_KERNEL);
if (!dep->trb_pool) {
dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
dep->name);
return -ENOMEM;
}
return 0;
}
static void dwc3_free_trb_pool(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
dma_free_coherent(dwc->sysdev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
dep->trb_pool, dep->trb_pool_dma);
dep->trb_pool = NULL;
dep->trb_pool_dma = 0;
}
static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
memset(&params, 0x00, sizeof(params));
params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
&params);
}
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
/**
* dwc3_gadget_start_config - configure ep resources
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
* @dep: endpoint that is being enabled
*
* Issue a %DWC3_DEPCMD_DEPSTARTCFG command to @dep. After the command's
* completion, it will set Transfer Resource for all available endpoints.
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
*
* The assignment of transfer resources cannot perfectly follow the data book
* due to the fact that the controller driver does not have all knowledge of the
* configuration in advance. It is given this information piecemeal by the
* composite gadget framework after every SET_CONFIGURATION and
* SET_INTERFACE. Trying to follow the databook programming model in this
* scenario can cause errors. For two reasons:
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
*
* 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every
* %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE (8.1.5). This is
* incorrect in the scenario of multiple interfaces.
*
* 2) The databook does not mention doing more %DWC3_DEPCMD_DEPXFERCFG for new
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
* endpoint on alt setting (8.1.6).
*
* The following simplified method is used instead:
*
* All hardware endpoints can be assigned a transfer resource and this setting
* will stay persistent until either a core reset or hibernation. So whenever we
* do a %DWC3_DEPCMD_DEPSTARTCFG(0) we can go ahead and do
* %DWC3_DEPCMD_DEPXFERCFG for every hardware endpoint as well. We are
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
* guaranteed that there are as many transfer resources as endpoints.
*
* This function is called for each endpoint when it is being enabled but is
* triggered only when called for EP0-out, which always happens first, and which
* should only happen in one of the above conditions.
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
*/
static int dwc3_gadget_start_config(struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3 *dwc;
u32 cmd;
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
int i;
int ret;
if (dep->number)
return 0;
memset(&params, 0x00, sizeof(params));
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
cmd = DWC3_DEPCMD_DEPSTARTCFG;
dwc = dep->dwc;
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
if (ret)
return ret;
for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
struct dwc3_ep *dep = dwc->eps[i];
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
if (!dep)
continue;
ret = dwc3_gadget_set_xfer_resource(dep);
usb: dwc3: Fix assignment of EP transfer resources The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assignment of transfer resources cannot perfectly follow the data book due to the fact that the controller driver does not have all knowledge of the configuration in advance. It is given this information piecemeal by the composite gadget framework after every SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook programming model in this scenario can cause errors. For two reasons: 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION and SET_INTERFACE (8.1.5). This is incorrect in the scenario of multiple interfaces. 2) The databook does not mention doing more DEPXFERCFG for new endpoint on alt setting (8.1.6). The following simplified method is used instead: All hardware endpoints can be assigned a transfer resource and this setting will stay persistent until either a core reset or hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and do DEPXFERCFG for every hardware endpoint as well. We are guaranteed that there are as many transfer resources as endpoints. This patch triggers off of the calling dwc3_gadget_start_config() for EP0-out, which always happens first, and which should only happen in one of the above conditions. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Cc: <stable@vger.kernel.org> # v3.2+ Reported-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2016-02-17 12:10:53 +08:00
if (ret)
return ret;
}
return 0;
}
static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
{
const struct usb_ss_ep_comp_descriptor *comp_desc;
const struct usb_endpoint_descriptor *desc;
struct dwc3_gadget_ep_cmd_params params;
struct dwc3 *dwc = dep->dwc;
comp_desc = dep->endpoint.comp_desc;
desc = dep->endpoint.desc;
memset(&params, 0x00, sizeof(params));
params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
| 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;
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
}
params.param0 |= action;
if (action == DWC3_DEPCFG_ACTION_RESTORE)
params.param2 |= dep->saved_state;
if (usb_endpoint_xfer_control(desc))
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
| DWC3_DEPCFG_XFER_COMPLETE_EN
| DWC3_DEPCFG_STREAM_EVENT_EN;
dep->stream_capable = true;
}
if (!usb_endpoint_xfer_control(desc))
params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
/*
* We are doing 1:1 mapping for endpoints, meaning
* Physical Endpoints 2 maps to Logical Endpoint 2 and
* so on. We consider the direction bit as part of the physical
* endpoint number. So USB endpoint 0x81 is 0x03.
*/
params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
/*
* We must use the lower 16 TX FIFOs even though
* HW might have more
*/
if (dep->direction)
params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
if (desc->bInterval) {
u8 bInterval_m1;
/*
* Valid range for DEPCFG.bInterval_m1 is from 0 to 13.
*
* NOTE: The programming guide incorrectly stated bInterval_m1
* must be set to 0 when operating in fullspeed. Internally the
* controller does not have this limitation. See DWC_usb3x
* programming guide section 3.2.2.1.
*/
bInterval_m1 = min_t(u8, desc->bInterval - 1, 13);
if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
dwc->gadget->speed == USB_SPEED_FULL)
dep->interval = desc->bInterval;
else
dep->interval = 1 << (desc->bInterval - 1);
params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
}
return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
}
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
bool interrupt);
/**
* dwc3_gadget_calc_tx_fifo_size - calculates the txfifo size value
* @dwc: pointer to the DWC3 context
* @nfifos: number of fifos to calculate for
*
* Calculates the size value based on the equation below:
*
* DWC3 revision 280A and prior:
* fifo_size = mult * (max_packet / mdwidth) + 1;
*
* DWC3 revision 290A and onwards:
* fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1
*
* The max packet size is set to 1024, as the txfifo requirements mainly apply
* to super speed USB use cases. However, it is safe to overestimate the fifo
* allocations for other scenarios, i.e. high speed USB.
*/
static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)
{
int max_packet = 1024;
int fifo_size;
int mdwidth;
mdwidth = dwc3_mdwidth(dwc);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3;
if (DWC3_VER_IS_PRIOR(DWC3, 290A))
fifo_size = mult * (max_packet / mdwidth) + 1;
else
fifo_size = mult * ((max_packet + mdwidth) / mdwidth) + 1;
return fifo_size;
}
/**
* dwc3_gadget_clear_tx_fifo_size - Clears txfifo allocation
* @dwc: pointer to the DWC3 context
*
* Iterates through all the endpoint registers and clears the previous txfifo
* allocations.
*/
void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int fifo_depth;
int size;
int num;
if (!dwc->do_fifo_resize)
return;
/* Read ep0IN related TXFIFO size */
dep = dwc->eps[1];
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
if (DWC3_IP_IS(DWC3))
fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size);
else
fifo_depth = DWC31_GTXFIFOSIZ_TXFDEP(size);
dwc->last_fifo_depth = fifo_depth;
/* Clear existing TXFIFO for all IN eps except ep0 */
for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM);
num += 2) {
dep = dwc->eps[num];
/* Don't change TXFRAMNUM on usb31 version */
size = DWC3_IP_IS(DWC3) ? 0 :
dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) &
DWC31_GTXFIFOSIZ_TXFRAMNUM;
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size);
usb: dwc3: gadget: Skip resizing EP's TX FIFO if already resized Some functions may dynamically enable and disable their endpoints regularly throughout their operation, particularly when Set Interface is employed to switch between Alternate Settings. For instance the UAC2 function has its respective endpoints for playback & capture associated with AltSetting 1, in which case those endpoints would not get enabled until the host activates the AltSetting. And they conversely become disabled when the interfaces' AltSetting 0 is chosen. With the DWC3 FIFO resizing algorithm recently added, every usb_ep_enable() call results in a call to resize that EP's TXFIFO, but if the same endpoint is enabled again and again, this incorrectly leads to FIFO RAM allocation exhaustion as the mechanism did not account for the possibility that endpoints can be re-enabled many times. Example log splat: dwc3 a600000.dwc3: Fifosize(3717) > RAM size(3462) ep3in depth:217973127 configfs-gadget gadget: u_audio_start_capture:521 Error! dwc3 a600000.dwc3: request 000000000be13e18 was not queued to ep3in Add another bit DWC3_EP_TXFIFO_RESIZED to dep->flags to keep track of whether an EP had already been resized in the current configuration. If so, bail out of dwc3_gadget_resize_tx_fifos() to avoid the calculation error resulting from accumulating the EP's FIFO depth repeatedly. This flag is retained across multiple ep_disable() and ep_enable() calls and is cleared when GTXFIFOSIZn is reset in dwc3_gadget_clear_tx_fifos() upon receiving the next Set Config. Fixes: 9f607a309fbe9 ("usb: dwc3: Resize TX FIFOs to meet EP bursting requirements") Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20211021180129.27938-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-22 02:01:28 +08:00
dep->flags &= ~DWC3_EP_TXFIFO_RESIZED;
}
dwc->num_ep_resized = 0;
}
/*
* dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
* @dwc: pointer to our context structure
*
* This function will a best effort FIFO allocation in order
* to improve FIFO usage and throughput, while still allowing
* us to enable as many endpoints as possible.
*
* Keep in mind that this operation will be highly dependent
* on the configured size for RAM1 - which contains TxFifo -,
* the amount of endpoints enabled on coreConsultant tool, and
* the width of the Master Bus.
*
* In general, FIFO depths are represented with the following equation:
*
* fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1
*
* In conjunction with dwc3_gadget_check_config(), this resizing logic will
* ensure that all endpoints will have enough internal memory for one max
* packet per endpoint.
*/
static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
int fifo_0_start;
int ram1_depth;
int fifo_size;
int min_depth;
int num_in_ep;
int remaining;
int num_fifos = 1;
int fifo;
int tmp;
if (!dwc->do_fifo_resize)
return 0;
/* resize IN endpoints except ep0 */
if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1)
return 0;
usb: dwc3: gadget: Skip resizing EP's TX FIFO if already resized Some functions may dynamically enable and disable their endpoints regularly throughout their operation, particularly when Set Interface is employed to switch between Alternate Settings. For instance the UAC2 function has its respective endpoints for playback & capture associated with AltSetting 1, in which case those endpoints would not get enabled until the host activates the AltSetting. And they conversely become disabled when the interfaces' AltSetting 0 is chosen. With the DWC3 FIFO resizing algorithm recently added, every usb_ep_enable() call results in a call to resize that EP's TXFIFO, but if the same endpoint is enabled again and again, this incorrectly leads to FIFO RAM allocation exhaustion as the mechanism did not account for the possibility that endpoints can be re-enabled many times. Example log splat: dwc3 a600000.dwc3: Fifosize(3717) > RAM size(3462) ep3in depth:217973127 configfs-gadget gadget: u_audio_start_capture:521 Error! dwc3 a600000.dwc3: request 000000000be13e18 was not queued to ep3in Add another bit DWC3_EP_TXFIFO_RESIZED to dep->flags to keep track of whether an EP had already been resized in the current configuration. If so, bail out of dwc3_gadget_resize_tx_fifos() to avoid the calculation error resulting from accumulating the EP's FIFO depth repeatedly. This flag is retained across multiple ep_disable() and ep_enable() calls and is cleared when GTXFIFOSIZn is reset in dwc3_gadget_clear_tx_fifos() upon receiving the next Set Config. Fixes: 9f607a309fbe9 ("usb: dwc3: Resize TX FIFOs to meet EP bursting requirements") Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20211021180129.27938-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-22 02:01:28 +08:00
/* bail if already resized */
if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
return 0;
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
if ((dep->endpoint.maxburst > 1 &&
usb_endpoint_xfer_bulk(dep->endpoint.desc)) ||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
num_fifos = 3;
if (dep->endpoint.maxburst > 6 &&
usb_endpoint_xfer_bulk(dep->endpoint.desc) && DWC3_IP_IS(DWC31))
num_fifos = dwc->tx_fifo_resize_max_num;
/* FIFO size for a single buffer */
fifo = dwc3_gadget_calc_tx_fifo_size(dwc, 1);
/* Calculate the number of remaining EPs w/o any FIFO */
num_in_ep = dwc->max_cfg_eps;
num_in_ep -= dwc->num_ep_resized;
/* Reserve at least one FIFO for the number of IN EPs */
min_depth = num_in_ep * (fifo + 1);
remaining = ram1_depth - min_depth - dwc->last_fifo_depth;
remaining = max_t(int, 0, remaining);
/*
* We've already reserved 1 FIFO per EP, so check what we can fit in
* addition to it. If there is not enough remaining space, allocate
* all the remaining space to the EP.
*/
fifo_size = (num_fifos - 1) * fifo;
if (remaining < fifo_size)
fifo_size = remaining;
fifo_size += fifo;
/* Last increment according to the TX FIFO size equation */
fifo_size++;
/* Check if TXFIFOs start at non-zero addr */
tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);
fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16));
if (DWC3_IP_IS(DWC3))
dwc->last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
else
dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEP(fifo_size);
/* Check fifo size allocation doesn't exceed available RAM size. */
if (dwc->last_fifo_depth >= ram1_depth) {
dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
dwc->last_fifo_depth, ram1_depth,
dep->endpoint.name, fifo_size);
if (DWC3_IP_IS(DWC3))
fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
else
fifo_size = DWC31_GTXFIFOSIZ_TXFDEP(fifo_size);
dwc->last_fifo_depth -= fifo_size;
return -ENOMEM;
}
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size);
usb: dwc3: gadget: Skip resizing EP's TX FIFO if already resized Some functions may dynamically enable and disable their endpoints regularly throughout their operation, particularly when Set Interface is employed to switch between Alternate Settings. For instance the UAC2 function has its respective endpoints for playback & capture associated with AltSetting 1, in which case those endpoints would not get enabled until the host activates the AltSetting. And they conversely become disabled when the interfaces' AltSetting 0 is chosen. With the DWC3 FIFO resizing algorithm recently added, every usb_ep_enable() call results in a call to resize that EP's TXFIFO, but if the same endpoint is enabled again and again, this incorrectly leads to FIFO RAM allocation exhaustion as the mechanism did not account for the possibility that endpoints can be re-enabled many times. Example log splat: dwc3 a600000.dwc3: Fifosize(3717) > RAM size(3462) ep3in depth:217973127 configfs-gadget gadget: u_audio_start_capture:521 Error! dwc3 a600000.dwc3: request 000000000be13e18 was not queued to ep3in Add another bit DWC3_EP_TXFIFO_RESIZED to dep->flags to keep track of whether an EP had already been resized in the current configuration. If so, bail out of dwc3_gadget_resize_tx_fifos() to avoid the calculation error resulting from accumulating the EP's FIFO depth repeatedly. This flag is retained across multiple ep_disable() and ep_enable() calls and is cleared when GTXFIFOSIZn is reset in dwc3_gadget_clear_tx_fifos() upon receiving the next Set Config. Fixes: 9f607a309fbe9 ("usb: dwc3: Resize TX FIFOs to meet EP bursting requirements") Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20211021180129.27938-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-22 02:01:28 +08:00
dep->flags |= DWC3_EP_TXFIFO_RESIZED;
dwc->num_ep_resized++;
return 0;
}
/**
* __dwc3_gadget_ep_enable - initializes a hw endpoint
* @dep: endpoint to be initialized
* @action: one of INIT, MODIFY or RESTORE
*
* Caller should take care of locking. Execute all necessary commands to
* initialize a HW endpoint so it can be used by a gadget driver.
*/
static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
{
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
struct dwc3 *dwc = dep->dwc;
u32 reg;
int ret;
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_resize_tx_fifos(dep);
if (ret)
return ret;
ret = dwc3_gadget_start_config(dep);
if (ret)
return ret;
}
ret = dwc3_gadget_set_ep_config(dep, action);
if (ret)
return ret;
if (!(dep->flags & DWC3_EP_ENABLED)) {
struct dwc3_trb *trb_st_hw;
struct dwc3_trb *trb_link;
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg |= DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
if (usb_endpoint_xfer_control(desc))
goto out;
/* Initialize the TRB ring */
dep->trb_dequeue = 0;
dep->trb_enqueue = 0;
memset(dep->trb_pool, 0,
sizeof(struct dwc3_trb) * DWC3_TRB_NUM);
/* Link TRB. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
}
/*
* Issue StartTransfer here with no-op TRB so we can always rely on No
* Response Update Transfer command.
*/
if (usb_endpoint_xfer_bulk(desc) ||
usb_endpoint_xfer_int(desc)) {
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_trb *trb;
dma_addr_t trb_dma;
u32 cmd;
memset(&params, 0, sizeof(params));
trb = &dep->trb_pool[0];
trb_dma = dwc3_trb_dma_offset(dep, trb);
params.param0 = upper_32_bits(trb_dma);
params.param1 = lower_32_bits(trb_dma);
cmd = DWC3_DEPCMD_STARTTRANSFER;
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
if (ret < 0)
return ret;
if (dep->stream_capable) {
/*
* For streams, at start, there maybe a race where the
* host primes the endpoint before the function driver
* queues a request to initiate a stream. In that case,
* the controller will not see the prime to generate the
* ERDY and start stream. To workaround this, issue a
* no-op TRB as normal, but end it immediately. As a
* result, when the function driver queues the request,
* the next START_TRANSFER command will cause the
* controller to generate an ERDY to initiate the
* stream.
*/
dwc3_stop_active_transfer(dep, true, true);
/*
* All stream eps will reinitiate stream on NoStream
* rejection until we can determine that the host can
* prime after the first transfer.
*
* However, if the controller is capable of
* TXF_FLUSH_BYPASS, then IN direction endpoints will
* automatically restart the stream without the driver
* initiation.
*/
if (!dep->direction ||
!(dwc->hwparams.hwparams9 &
DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS))
dep->flags |= DWC3_EP_FORCE_RESTART_STREAM;
}
}
out:
trace_dwc3_gadget_ep_enable(dep);
return 0;
}
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_request *req;
dwc3_stop_active_transfer(dep, true, false);
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->started_list)) {
req = next_request(&dep->started_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
while (!list_empty(&dep->pending_list)) {
req = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
while (!list_empty(&dep->cancelled_list)) {
req = next_request(&dep->cancelled_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
}
/**
* __dwc3_gadget_ep_disable - disables a hw endpoint
* @dep: the endpoint to disable
*
* This function undoes what __dwc3_gadget_ep_enable did and also removes
* requests which are currently being processed by the hardware and those which
* are not yet scheduled.
*
* Caller should take care of locking.
*/
static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
trace_dwc3_gadget_ep_disable(dep);
/* make sure HW endpoint isn't stalled */
if (dep->flags & DWC3_EP_STALL)
__dwc3_gadget_ep_set_halt(dep, 0, false);
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg &= ~DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
/* Clear out the ep descriptors for non-ep0 */
if (dep->number > 1) {
dep->endpoint.comp_desc = NULL;
dep->endpoint.desc = NULL;
}
dwc3_remove_requests(dwc, dep);
dep->stream_capable = false;
dep->type = 0;
usb: dwc3: gadget: Skip resizing EP's TX FIFO if already resized Some functions may dynamically enable and disable their endpoints regularly throughout their operation, particularly when Set Interface is employed to switch between Alternate Settings. For instance the UAC2 function has its respective endpoints for playback & capture associated with AltSetting 1, in which case those endpoints would not get enabled until the host activates the AltSetting. And they conversely become disabled when the interfaces' AltSetting 0 is chosen. With the DWC3 FIFO resizing algorithm recently added, every usb_ep_enable() call results in a call to resize that EP's TXFIFO, but if the same endpoint is enabled again and again, this incorrectly leads to FIFO RAM allocation exhaustion as the mechanism did not account for the possibility that endpoints can be re-enabled many times. Example log splat: dwc3 a600000.dwc3: Fifosize(3717) > RAM size(3462) ep3in depth:217973127 configfs-gadget gadget: u_audio_start_capture:521 Error! dwc3 a600000.dwc3: request 000000000be13e18 was not queued to ep3in Add another bit DWC3_EP_TXFIFO_RESIZED to dep->flags to keep track of whether an EP had already been resized in the current configuration. If so, bail out of dwc3_gadget_resize_tx_fifos() to avoid the calculation error resulting from accumulating the EP's FIFO depth repeatedly. This flag is retained across multiple ep_disable() and ep_enable() calls and is cleared when GTXFIFOSIZn is reset in dwc3_gadget_clear_tx_fifos() upon receiving the next Set Config. Fixes: 9f607a309fbe9 ("usb: dwc3: Resize TX FIFOs to meet EP bursting requirements") Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20211021180129.27938-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-22 02:01:28 +08:00
dep->flags &= DWC3_EP_TXFIFO_RESIZED;
return 0;
}
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
return -EINVAL;
}
static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
{
return -EINVAL;
}
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct dwc3_ep *dep;
struct dwc3 *dwc;
unsigned long flags;
int ret;
if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
pr_debug("dwc3: invalid parameters\n");
return -EINVAL;
}
if (!desc->wMaxPacketSize) {
pr_debug("dwc3: missing wMaxPacketSize\n");
return -EINVAL;
}
dep = to_dwc3_ep(ep);
dwc = dep->dwc;
if (dev_WARN_ONCE(dwc->dev, dep->flags & DWC3_EP_ENABLED,
"%s is already enabled\n",
dep->name))
return 0;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static int dwc3_gadget_ep_disable(struct usb_ep *ep)
{
struct dwc3_ep *dep;
struct dwc3 *dwc;
unsigned long flags;
int ret;
if (!ep) {
pr_debug("dwc3: invalid parameters\n");
return -EINVAL;
}
dep = to_dwc3_ep(ep);
dwc = dep->dwc;
if (dev_WARN_ONCE(dwc->dev, !(dep->flags & DWC3_EP_ENABLED),
"%s is already disabled\n",
dep->name))
return 0;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_disable(dep);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
gfp_t gfp_flags)
{
struct dwc3_request *req;
struct dwc3_ep *dep = to_dwc3_ep(ep);
req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
return NULL;
req->direction = dep->direction;
req->epnum = dep->number;
req->dep = dep;
req->status = DWC3_REQUEST_STATUS_UNKNOWN;
trace_dwc3_alloc_request(req);
return &req->request;
}
static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
struct usb_request *request)
{
struct dwc3_request *req = to_dwc3_request(request);
trace_dwc3_free_request(req);
kfree(req);
}
/**
* dwc3_ep_prev_trb - returns the previous TRB in the ring
* @dep: The endpoint with the TRB ring
* @index: The index of the current TRB in the ring
*
* Returns the TRB prior to the one pointed to by the index. If the
* index is 0, we will wrap backwards, skip the link TRB, and return
* the one just before that.
*/
static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)
{
u8 tmp = index;
if (!tmp)
tmp = DWC3_TRB_NUM - 1;
return &dep->trb_pool[tmp - 1];
}
static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
{
u8 trbs_left;
/*
* If the enqueue & dequeue are equal then the TRB ring is either full
* or empty. It's considered full when there are DWC3_TRB_NUM-1 of TRBs
* pending to be processed by the driver.
*/
if (dep->trb_enqueue == dep->trb_dequeue) {
/*
* If there is any request remained in the started_list at
* this point, that means there is no TRB available.
*/
if (!list_empty(&dep->started_list))
return 0;
return DWC3_TRB_NUM - 1;
}
trbs_left = dep->trb_dequeue - dep->trb_enqueue;
trbs_left &= (DWC3_TRB_NUM - 1);
if (dep->trb_dequeue < dep->trb_enqueue)
trbs_left--;
return trbs_left;
}
static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
dma_addr_t dma, unsigned int length, unsigned int chain,
unsigned int node, unsigned int stream_id,
unsigned int short_not_ok, unsigned int no_interrupt,
unsigned int is_last, bool must_interrupt)
{
struct dwc3 *dwc = dep->dwc;
struct usb_gadget *gadget = dwc->gadget;
enum usb_device_speed speed = gadget->speed;
trb->size = DWC3_TRB_SIZE_LENGTH(length);
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
if (!node) {
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/*
* USB Specification 2.0 Section 5.9.2 states that: "If
* there is only a single transaction in the microframe,
* only a DATA0 data packet PID is used. If there are
* two transactions per microframe, DATA1 is used for
* the first transaction data packet and DATA0 is used
* for the second transaction data packet. If there are
* three transactions per microframe, DATA2 is used for
* the first transaction data packet, DATA1 is used for
* the second, and DATA0 is used for the third."
*
* IOW, we should satisfy the following cases:
*
* 1) length <= maxpacket
* - DATA0
*
* 2) maxpacket < length <= (2 * maxpacket)
* - DATA1, DATA0
*
* 3) (2 * maxpacket) < length <= (3 * maxpacket)
* - DATA2, DATA1, DATA0
*/
if (speed == USB_SPEED_HIGH) {
struct usb_ep *ep = &dep->endpoint;
unsigned int mult = 2;
unsigned int maxp = usb_endpoint_maxp(ep->desc);
if (length <= (2 * maxp))
mult--;
if (length <= maxp)
mult--;
trb->size |= DWC3_TRB_SIZE_PCM1(mult);
}
} else {
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
}
/* always enable Interrupt on Missed ISOC */
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
trb->ctrl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
* This is only possible with faulty memory because we
* checked it already :)
*/
dev_WARN(dwc->dev, "Unknown endpoint type %d\n",
usb_endpoint_type(dep->endpoint.desc));
}
/*
* Enable Continue on Short Packet
* when endpoint is not a stream capable
*/
if (usb_endpoint_dir_out(dep->endpoint.desc)) {
if (!dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_CSP;
if (short_not_ok)
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
}
/* All TRBs setup for MST must set CSP=1 when LST=0 */
if (dep->stream_capable && DWC3_MST_CAPABLE(&dwc->hwparams))
trb->ctrl |= DWC3_TRB_CTRL_CSP;
if ((!no_interrupt && !chain) || must_interrupt)
trb->ctrl |= DWC3_TRB_CTRL_IOC;
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
else if (dep->stream_capable && is_last &&
!DWC3_MST_CAPABLE(&dwc->hwparams))
trb->ctrl |= DWC3_TRB_CTRL_LST;
if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
usb: dwc3: Correct the logic for checking TRB full in __dwc3_prepare_one_trb() Availability of TRB's is calculated using dwc3_calc_trbs_left(), which determines total available TRB's based on the HWO bit set in a TRB. In the present code, __dwc3_prepare_one_trb() is called with a TRB which needs to be prepared for transfer. This __dwc3_prepare_one_trb() calls dwc3_calc_trbs_left() to determine total available TRBs and set IOC bit if the total available TRBs are zero. Since the present working TRB (which is passed as an argument to __dwc3_prepare_one_trb() ) doesn't yet have the HWO bit set before calling dwc3_calc_trbs_left(), there are chances that dwc3_calc_trbs_left() wrongly calculates this present working TRB as free(since the HWO bit is not yet set) and returns the total available TRBs as greater than zero (including the present working TRB). This could be a problem. This patch corrects the above mentioned problem in __dwc3_prepare_one_trb() by increementing the dep->trb_enqueue at the last (after preparing the TRB) instead of increementing at the start and setting the IOC bit only if the total available TRBs returned by dwc3_calc_trbs_left() is 1 . Since we are increementing the dep->trb_enqueue at the last, the present working TRB is also considered as available by dwc3_calc_trbs_left() and non zero value is returned . So, according to the modified logic, when the total available TRBs is equal to 1 that means the total available TRBs in the pool are 0. Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> Reviewed-by: Thinh Nguyen <thinhn@synopsys.com> Tested-by: Tejas Joglekar <tejas.joglekar@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-12-01 19:13:29 +08:00
dwc3_ep_inc_enq(dep);
trace_dwc3_prepare_trb(dep, trb);
}
/**
* dwc3_prepare_one_trb - setup one TRB from one request
* @dep: endpoint for which this request is prepared
* @req: dwc3_request pointer
* @trb_length: buffer size of the TRB
* @chain: should this TRB be chained to the next?
* @node: only for isochronous endpoints. First TRB needs different type.
* @use_bounce_buffer: set to use bounce buffer
* @must_interrupt: set to interrupt on TRB completion
*/
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, unsigned int trb_length,
unsigned int chain, unsigned int node, bool use_bounce_buffer,
bool must_interrupt)
{
struct dwc3_trb *trb;
dma_addr_t dma;
unsigned int stream_id = req->request.stream_id;
unsigned int short_not_ok = req->request.short_not_ok;
unsigned int no_interrupt = req->request.no_interrupt;
unsigned int is_last = req->request.is_last;
if (use_bounce_buffer)
dma = dep->dwc->bounce_addr;
else if (req->request.num_sgs > 0)
dma = sg_dma_address(req->start_sg);
else
dma = req->request.dma;
trb = &dep->trb_pool[dep->trb_enqueue];
if (!req->trb) {
dwc3_gadget_move_started_request(req);
req->trb = trb;
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node,
stream_id, short_not_ok, no_interrupt, is_last,
must_interrupt);
}
static bool dwc3_needs_extra_trb(struct dwc3_ep *dep, struct dwc3_request *req)
{
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
unsigned int rem = req->request.length % maxp;
if ((req->request.length && req->request.zero && !rem &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc)) ||
(!req->direction && rem))
return true;
return false;
}
/**
* dwc3_prepare_last_sg - prepare TRBs for the last SG entry
* @dep: The endpoint that the request belongs to
* @req: The request to prepare
* @entry_length: The last SG entry size
* @node: Indicates whether this is not the first entry (for isoc only)
*
* Return the number of TRBs prepared.
*/
static int dwc3_prepare_last_sg(struct dwc3_ep *dep,
struct dwc3_request *req, unsigned int entry_length,
unsigned int node)
{
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
unsigned int rem = req->request.length % maxp;
unsigned int num_trbs = 1;
if (dwc3_needs_extra_trb(dep, req))
num_trbs++;
if (dwc3_calc_trbs_left(dep) < num_trbs)
return 0;
req->needs_extra_trb = num_trbs > 1;
/* Prepare a normal TRB */
if (req->direction || req->request.length)
dwc3_prepare_one_trb(dep, req, entry_length,
req->needs_extra_trb, node, false, false);
/* Prepare extra TRBs for ZLP and MPS OUT transfer alignment */
if ((!req->direction && !req->request.length) || req->needs_extra_trb)
dwc3_prepare_one_trb(dep, req,
req->direction ? 0 : maxp - rem,
false, 1, true, false);
return num_trbs;
}
static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
struct dwc3_request *req)
{
struct scatterlist *sg = req->start_sg;
struct scatterlist *s;
int i;
unsigned int length = req->request.length;
unsigned int remaining = req->request.num_mapped_sgs
- req->num_queued_sgs;
unsigned int num_trbs = req->num_trbs;
bool needs_extra_trb = dwc3_needs_extra_trb(dep, req);
/*
* If we resume preparing the request, then get the remaining length of
* the request and resume where we left off.
*/
for_each_sg(req->request.sg, s, req->num_queued_sgs, i)
length -= sg_dma_len(s);
for_each_sg(sg, s, remaining, i) {
unsigned int num_trbs_left = dwc3_calc_trbs_left(dep);
unsigned int trb_length;
bool must_interrupt = false;
bool last_sg = false;
trb_length = min_t(unsigned int, length, sg_dma_len(s));
length -= trb_length;
usb: dwc3: gadget: Update chain bit correctly when using sg list If scatter-gather operation is allowed, a large USB request is split into multiple TRBs. For preparing TRBs for sg list, driver iterates over the list and creates TRB for each sg and mark the chain bit to false for the last sg. The current IOMMU driver is clubbing the list of sgs which shares a page boundary into one and giving it to USB driver. With this the number of sgs mapped it not equal to the the number of sgs passed. Because of this USB driver is not marking the chain bit to false since it couldn't iterate to the last sg. This patch addresses this issue by marking the chain bit to false if it is the last mapped sg. At a practical level, this patch resolves USB transfer stalls seen with adb on dwc3 based db845c, pixel3 and other qcom hardware after functionfs gadget added scatter-gather support around v4.20. Credit also to Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> who implemented a very similar fix to this issue. Cc: Felipe Balbi <balbi@kernel.org> Cc: Yang Fei <fei.yang@intel.com> Cc: Thinh Nguyen <thinhn@synopsys.com> Cc: Tejas Joglekar <tejas.joglekar@synopsys.com> Cc: Andrzej Pietrasiewicz <andrzej.p@collabora.com> Cc: Jack Pham <jackp@codeaurora.org> Cc: Todd Kjos <tkjos@google.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Linux USB List <linux-usb@vger.kernel.org> Cc: stable <stable@vger.kernel.org> #4.20+ Signed-off-by: Pratham Pratap <prathampratap@codeaurora.org> [jstultz: Slight tweak to remove sg_is_last() usage, reworked commit message, minor comment tweak] Signed-off-by: John Stultz <john.stultz@linaro.org> Link: https://lore.kernel.org/r/20200302214443.55783-1-john.stultz@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-03-03 05:44:43 +08:00
/*
* IOMMU driver is coalescing the list of sgs which shares a
* page boundary into one and giving it to USB driver. With
* this the number of sgs mapped is not equal to the number of
* sgs passed. So mark the chain bit to false if it isthe last
* mapped sg.
*/
if ((i == remaining - 1) || !length)
last_sg = true;
if (!num_trbs_left)
break;
if (last_sg) {
if (!dwc3_prepare_last_sg(dep, req, trb_length, i))
break;
} else {
/*
* Look ahead to check if we have enough TRBs for the
* next SG entry. If not, set interrupt on this TRB to
* resume preparing the next SG entry when more TRBs are
* free.
*/
if (num_trbs_left == 1 || (needs_extra_trb &&
num_trbs_left <= 2 &&
sg_dma_len(sg_next(s)) >= length))
must_interrupt = true;
dwc3_prepare_one_trb(dep, req, trb_length, 1, i, false,
must_interrupt);
}
/*
* There can be a situation where all sgs in sglist are not
* queued because of insufficient trb number. To handle this
* case, update start_sg to next sg to be queued, so that
* we have free trbs we can continue queuing from where we
* previously stopped
*/
if (!last_sg)
req->start_sg = sg_next(s);
req->num_queued_sgs++;
req->num_pending_sgs--;
/*
* The number of pending SG entries may not correspond to the
* number of mapped SG entries. If all the data are queued, then
* don't include unused SG entries.
*/
if (length == 0) {
req->num_pending_sgs = 0;
break;
}
if (must_interrupt)
break;
}
return req->num_trbs - num_trbs;
}
static int dwc3_prepare_trbs_linear(struct dwc3_ep *dep,
struct dwc3_request *req)
{
return dwc3_prepare_last_sg(dep, req, req->request.length, 0);
}
/*
* dwc3_prepare_trbs - setup TRBs from requests
* @dep: endpoint for which requests are being prepared
*
* The function goes through the requests list and sets up TRBs for the
* transfers. The function returns once there are no more TRBs available or
* it runs out of requests.
*
* Returns the number of TRBs prepared or negative errno.
*/
static int dwc3_prepare_trbs(struct dwc3_ep *dep)
{
struct dwc3_request *req, *n;
int ret = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
/*
* We can get in a situation where there's a request in the started list
* but there weren't enough TRBs to fully kick it in the first time
* around, so it has been waiting for more TRBs to be freed up.
*
* In that case, we should check if we have a request with pending_sgs
* in the started list and prepare TRBs for that request first,
* otherwise we will prepare TRBs completely out of order and that will
* break things.
*/
list_for_each_entry(req, &dep->started_list, list) {
if (req->num_pending_sgs > 0) {
ret = dwc3_prepare_trbs_sg(dep, req);
if (!ret || req->num_pending_sgs)
return ret;
}
if (!dwc3_calc_trbs_left(dep))
return ret;
/*
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
* burst capability may try to read and use TRBs beyond the
* active transfer instead of stopping.
*/
if (dep->stream_capable && req->request.is_last &&
!DWC3_MST_CAPABLE(&dep->dwc->hwparams))
return ret;
}
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
struct dwc3 *dwc = dep->dwc;
ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
dep->direction);
if (ret)
return ret;
req->sg = req->request.sg;
req->start_sg = req->sg;
req->num_queued_sgs = 0;
req->num_pending_sgs = req->request.num_mapped_sgs;
if (req->num_pending_sgs > 0) {
ret = dwc3_prepare_trbs_sg(dep, req);
if (req->num_pending_sgs)
return ret;
} else {
ret = dwc3_prepare_trbs_linear(dep, req);
}
if (!ret || !dwc3_calc_trbs_left(dep))
return ret;
/*
* Don't prepare beyond a transfer. In DWC_usb32, its transfer
* burst capability may try to read and use TRBs beyond the
* active transfer instead of stopping.
*/
if (dep->stream_capable && req->request.is_last &&
!DWC3_MST_CAPABLE(&dwc->hwparams))
return ret;
}
return ret;
}
static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep);
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_request *req;
int starting;
int ret;
u32 cmd;
/*
* Note that it's normal to have no new TRBs prepared (i.e. ret == 0).
* This happens when we need to stop and restart a transfer such as in
* the case of reinitiating a stream or retrying an isoc transfer.
*/
ret = dwc3_prepare_trbs(dep);
if (ret < 0)
return ret;
starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED);
/*
* If there's no new TRB prepared and we don't need to restart a
* transfer, there's no need to update the transfer.
*/
if (!ret && !starting)
return ret;
req = next_request(&dep->started_list);
if (!req) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
return 0;
}
memset(&params, 0, sizeof(params));
if (starting) {
params.param0 = upper_32_bits(req->trb_dma);
params.param1 = lower_32_bits(req->trb_dma);
cmd = DWC3_DEPCMD_STARTTRANSFER;
if (dep->stream_capable)
cmd |= DWC3_DEPCMD_PARAM(req->request.stream_id);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
} else {
cmd = DWC3_DEPCMD_UPDATETRANSFER |
DWC3_DEPCMD_PARAM(dep->resource_index);
}
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
if (ret < 0) {
struct dwc3_request *tmp;
if (ret == -EAGAIN)
return ret;
dwc3_stop_active_transfer(dep, true, true);
list_for_each_entry_safe(req, tmp, &dep->started_list, list)
dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_DEQUEUED);
/* If ep isn't started, then there's no end transfer pending */
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
return ret;
}
if (dep->stream_capable && req->request.is_last &&
!DWC3_MST_CAPABLE(&dep->dwc->hwparams))
dep->flags |= DWC3_EP_WAIT_TRANSFER_COMPLETE;
return 0;
}
static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
return DWC3_DSTS_SOFFN(reg);
}
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
/**
* dwc3_gadget_start_isoc_quirk - workaround invalid frame number
* @dep: isoc endpoint
*
* This function tests for the correct combination of BIT[15:14] from the 16-bit
* microframe number reported by the XferNotReady event for the future frame
* number to start the isoc transfer.
*
* In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed
* isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the
* XferNotReady event are invalid. The driver uses this number to schedule the
* isochronous transfer and passes it to the START TRANSFER command. Because
* this number is invalid, the command may fail. If BIT[15:14] matches the
* internal 16-bit microframe, the START TRANSFER command will pass and the
* transfer will start at the scheduled time, if it is off by 1, the command
* will still pass, but the transfer will start 2 seconds in the future. For all
* other conditions, the START TRANSFER command will fail with bus-expiry.
*
* In order to workaround this issue, we can test for the correct combination of
* BIT[15:14] by sending START TRANSFER commands with different values of
* BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart
* (or 2 seconds). 4 seconds into the future will result in a bus-expiry status.
* As the result, within the 4 possible combinations for BIT[15:14], there will
* be 2 successful and 2 failure START COMMAND status. One of the 2 successful
* command status will result in a 2-second delay start. The smaller BIT[15:14]
* value is the correct combination.
*
* Since there are only 4 outcomes and the results are ordered, we can simply
* test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to
* deduce the smaller successful combination.
*
* Let test0 = test status for combination 'b00 and test1 = test status for 'b01
* of BIT[15:14]. The correct combination is as follow:
*
* if test0 fails and test1 passes, BIT[15:14] is 'b01
* if test0 fails and test1 fails, BIT[15:14] is 'b10
* if test0 passes and test1 fails, BIT[15:14] is 'b11
* if test0 passes and test1 passes, BIT[15:14] is 'b00
*
* Synopsys STAR 9001202023: Wrong microframe number for isochronous IN
* endpoints.
*/
static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
{
int cmd_status = 0;
bool test0;
bool test1;
while (dep->combo_num < 2) {
struct dwc3_gadget_ep_cmd_params params;
u32 test_frame_number;
u32 cmd;
/*
* Check if we can start isoc transfer on the next interval or
* 4 uframes in the future with BIT[15:14] as dep->combo_num
*/
test_frame_number = dep->frame_number & DWC3_FRNUMBER_MASK;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
test_frame_number |= dep->combo_num << 14;
test_frame_number += max_t(u32, 4, dep->interval);
params.param0 = upper_32_bits(dep->dwc->bounce_addr);
params.param1 = lower_32_bits(dep->dwc->bounce_addr);
cmd = DWC3_DEPCMD_STARTTRANSFER;
cmd |= DWC3_DEPCMD_PARAM(test_frame_number);
cmd_status = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
/* Redo if some other failure beside bus-expiry is received */
if (cmd_status && cmd_status != -EAGAIN) {
dep->start_cmd_status = 0;
dep->combo_num = 0;
return 0;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
}
/* Store the first test status */
if (dep->combo_num == 0)
dep->start_cmd_status = cmd_status;
dep->combo_num++;
/*
* End the transfer if the START_TRANSFER command is successful
* to wait for the next XferNotReady to test the command again
*/
if (cmd_status == 0) {
dwc3_stop_active_transfer(dep, true, true);
return 0;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
}
}
/* test0 and test1 are both completed at this point */
test0 = (dep->start_cmd_status == 0);
test1 = (cmd_status == 0);
if (!test0 && test1)
dep->combo_num = 1;
else if (!test0 && !test1)
dep->combo_num = 2;
else if (test0 && !test1)
dep->combo_num = 3;
else if (test0 && test1)
dep->combo_num = 0;
dep->frame_number &= DWC3_FRNUMBER_MASK;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
dep->frame_number |= dep->combo_num << 14;
dep->frame_number += max_t(u32, 4, dep->interval);
/* Reinitialize test variables */
dep->start_cmd_status = 0;
dep->combo_num = 0;
return __dwc3_gadget_kick_transfer(dep);
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
}
static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
{
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
struct dwc3 *dwc = dep->dwc;
int ret;
int i;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
if (list_empty(&dep->pending_list) &&
list_empty(&dep->started_list)) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
return -EAGAIN;
}
2020-04-12 10:20:01 +08:00
if (!dwc->dis_start_transfer_quirk &&
(DWC3_VER_IS_PRIOR(DWC31, 170A) ||
DWC3_VER_TYPE_IS_WITHIN(DWC31, 170A, EA01, EA06))) {
if (dwc->gadget->speed <= USB_SPEED_HIGH && dep->direction)
return dwc3_gadget_start_isoc_quirk(dep);
}
if (desc->bInterval <= 14 &&
dwc->gadget->speed >= USB_SPEED_HIGH) {
u32 frame = __dwc3_gadget_get_frame(dwc);
bool rollover = frame <
(dep->frame_number & DWC3_FRNUMBER_MASK);
/*
* frame_number is set from XferNotReady and may be already
* out of date. DSTS only provides the lower 14 bit of the
* current frame number. So add the upper two bits of
* frame_number and handle a possible rollover.
* This will provide the correct frame_number unless more than
* rollover has happened since XferNotReady.
*/
dep->frame_number = (dep->frame_number & ~DWC3_FRNUMBER_MASK) |
frame;
if (rollover)
dep->frame_number += BIT(14);
}
for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) {
dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1);
ret = __dwc3_gadget_kick_transfer(dep);
if (ret != -EAGAIN)
break;
}
/*
* After a number of unsuccessful start attempts due to bus-expiry
* status, issue END_TRANSFER command and retry on the next XferNotReady
* event.
*/
if (ret == -EAGAIN) {
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
cmd = DWC3_DEPCMD_ENDTRANSFER |
DWC3_DEPCMD_CMDIOC |
DWC3_DEPCMD_PARAM(dep->resource_index);
dep->resource_index = 0;
memset(&params, 0, sizeof(params));
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
if (!ret)
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
}
return ret;
}
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
dev_dbg(dwc->dev, "%s: can't queue to disabled endpoint\n",
dep->name);
return -ESHUTDOWN;
}
if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
&req->request, req->dep->name))
return -EINVAL;
if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED,
"%s: request %pK already in flight\n",
dep->name, &req->request))
return -EINVAL;
pm_runtime_get(dwc->dev);
req->request.actual = 0;
req->request.status = -EINPROGRESS;
trace_dwc3_ep_queue(req);
list_add_tail(&req->list, &dep->pending_list);
req->status = DWC3_REQUEST_STATUS_QUEUED;
if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)
return 0;
/*
* Start the transfer only after the END_TRANSFER is completed
* and endpoint STALL is cleared.
*/
if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
(dep->flags & DWC3_EP_WEDGE) ||
(dep->flags & DWC3_EP_STALL)) {
dep->flags |= DWC3_EP_DELAY_START;
return 0;
}
/*
* NOTICE: Isochronous endpoints should NEVER be prestarted. We must
* wait for a XferNotReady event so we will know what's the current
* (micro-)frame number.
*
* Without this trick, we are very, very likely gonna get Bus Expiry
* errors which will force us issue EndTransfer command.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if (!(dep->flags & DWC3_EP_PENDING_REQUEST) &&
!(dep->flags & DWC3_EP_TRANSFER_STARTED))
return 0;
if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
return __dwc3_gadget_start_isoc(dep);
}
}
__dwc3_gadget_kick_transfer(dep);
return 0;
}
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags)
{
struct dwc3_request *req = to_dwc3_request(request);
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_queue(dep, req);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *req)
{
int i;
/* If req->trb is not set, then the request has not started */
if (!req->trb)
return;
/*
* If request was already started, this means we had to
* stop the transfer. With that we also need to ignore
* all TRBs used by the request, however TRBs can only
* be modified after completion of END_TRANSFER
* command. So what we do here is that we wait for
* END_TRANSFER completion and only after that, we jump
* over TRBs by clearing HWO and incrementing dequeue
* pointer.
*/
for (i = 0; i < req->num_trbs; i++) {
struct dwc3_trb *trb;
trb = &dep->trb_pool[dep->trb_dequeue];
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
}
req->num_trbs = 0;
}
static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep)
{
struct dwc3_request *req;
struct dwc3_request *tmp;
struct dwc3 *dwc = dep->dwc;
list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) {
dwc3_gadget_ep_skip_trbs(dep, req);
switch (req->status) {
case DWC3_REQUEST_STATUS_DISCONNECTED:
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
break;
case DWC3_REQUEST_STATUS_DEQUEUED:
dwc3_gadget_giveback(dep, req, -ECONNRESET);
break;
case DWC3_REQUEST_STATUS_STALLED:
dwc3_gadget_giveback(dep, req, -EPIPE);
break;
default:
dev_err(dwc->dev, "request cancelled with wrong reason:%d\n", req->status);
dwc3_gadget_giveback(dep, req, -ECONNRESET);
break;
}
}
}
static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
struct usb_request *request)
{
struct dwc3_request *req = to_dwc3_request(request);
struct dwc3_request *r = NULL;
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret = 0;
trace_dwc3_ep_dequeue(req);
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->cancelled_list, list) {
if (r == req)
goto out;
}
list_for_each_entry(r, &dep->pending_list, list) {
if (r == req) {
dwc3_gadget_giveback(dep, req, -ECONNRESET);
goto out;
}
}
list_for_each_entry(r, &dep->started_list, list) {
if (r == req) {
struct dwc3_request *t;
/* wait until it is processed */
dwc3_stop_active_transfer(dep, true, true);
/*
* Remove any started request if the transfer is
* cancelled.
*/
list_for_each_entry_safe(r, t, &dep->started_list, list)
dwc3_gadget_move_cancelled_request(r,
DWC3_REQUEST_STATUS_DEQUEUED);
dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE;
goto out;
}
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
request, ep->name);
ret = -EINVAL;
out:
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3 *dwc = dep->dwc;
struct dwc3_request *req;
struct dwc3_request *tmp;
int ret;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
return -EINVAL;
}
memset(&params, 0x00, sizeof(params));
if (value) {
struct dwc3_trb *trb;
unsigned int transfer_in_flight;
unsigned int started;
if (dep->number > 1)
trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
else
trb = &dwc->ep0_trb[dep->trb_enqueue];
transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
started = !list_empty(&dep->started_list);
if (!protocol && ((dep->direction && transfer_in_flight) ||
(!dep->direction && started))) {
return -EAGAIN;
}
ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETSTALL,
&params);
if (ret)
dev_err(dwc->dev, "failed to set STALL on %s\n",
dep->name);
else
dep->flags |= DWC3_EP_STALL;
} else {
/*
* Don't issue CLEAR_STALL command to control endpoints. The
* controller automatically clears the STALL when it receives
* the SETUP token.
*/
if (dep->number <= 1) {
dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
return 0;
}
dwc3_stop_active_transfer(dep, true, true);
list_for_each_entry_safe(req, tmp, &dep->started_list, list)
dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_STALLED);
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
dep->flags |= DWC3_EP_PENDING_CLEAR_STALL;
return 0;
}
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
ret = dwc3_send_clear_stall_ep_cmd(dep);
if (ret) {
dev_err(dwc->dev, "failed to clear STALL on %s\n",
dep->name);
return ret;
}
dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
if ((dep->flags & DWC3_EP_DELAY_START) &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc))
__dwc3_gadget_kick_transfer(dep);
dep->flags &= ~DWC3_EP_DELAY_START;
}
return ret;
}
static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_set_halt(dep, value, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
dep->flags |= DWC3_EP_WEDGE;
if (dep->number == 0 || dep->number == 1)
ret = __dwc3_gadget_ep0_set_halt(ep, 1);
else
ret = __dwc3_gadget_ep_set_halt(dep, 1, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
/* -------------------------------------------------------------------------- */
static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
};
static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
.enable = dwc3_gadget_ep0_enable,
.disable = dwc3_gadget_ep0_disable,
.alloc_request = dwc3_gadget_ep_alloc_request,
.free_request = dwc3_gadget_ep_free_request,
.queue = dwc3_gadget_ep0_queue,
.dequeue = dwc3_gadget_ep_dequeue,
.set_halt = dwc3_gadget_ep0_set_halt,
.set_wedge = dwc3_gadget_ep_set_wedge,
};
static const struct usb_ep_ops dwc3_gadget_ep_ops = {
.enable = dwc3_gadget_ep_enable,
.disable = dwc3_gadget_ep_disable,
.alloc_request = dwc3_gadget_ep_alloc_request,
.free_request = dwc3_gadget_ep_free_request,
.queue = dwc3_gadget_ep_queue,
.dequeue = dwc3_gadget_ep_dequeue,
.set_halt = dwc3_gadget_ep_set_halt,
.set_wedge = dwc3_gadget_ep_set_wedge,
};
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_get_frame(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
return __dwc3_gadget_get_frame(dwc);
}
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
{
int retries;
int ret;
u32 reg;
u8 link_state;
/*
* According to the Databook Remote wakeup request should
* be issued only when the device is in early suspend state.
*
* We can check that via USB Link State bits in DSTS register.
*/
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
link_state = DWC3_DSTS_USBLNKST(reg);
switch (link_state) {
case DWC3_LINK_STATE_RESET:
case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */
case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
case DWC3_LINK_STATE_U2: /* in HS, means Sleep (L1) */
case DWC3_LINK_STATE_U1:
case DWC3_LINK_STATE_RESUME:
break;
default:
return -EINVAL;
}
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
if (ret < 0) {
dev_err(dwc->dev, "failed to put link in Recovery\n");
return ret;
}
/* Recent versions do this automatically */
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 194A)) {
/* write zeroes to Link Change Request */
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
/* poll until Link State changes to ON */
retries = 20000;
while (retries--) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
break;
}
if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
dev_err(dwc->dev, "failed to send remote wakeup\n");
return -EINVAL;
}
return 0;
}
static int dwc3_gadget_wakeup(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_wakeup(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
g->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static void dwc3_stop_active_transfers(struct dwc3 *dwc)
{
u32 epnum;
for (epnum = 2; epnum < dwc->num_eps; epnum++) {
struct dwc3_ep *dep;
dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_remove_requests(dwc, dep);
}
}
static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc)
{
enum usb_ssp_rate ssp_rate = dwc->gadget_ssp_rate;
u32 reg;
if (ssp_rate == USB_SSP_GEN_UNKNOWN)
ssp_rate = dwc->max_ssp_rate;
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~DWC3_DCFG_SPEED_MASK;
reg &= ~DWC3_DCFG_NUMLANES(~0);
if (ssp_rate == USB_SSP_GEN_1x2)
reg |= DWC3_DCFG_SUPERSPEED;
else if (dwc->max_ssp_rate != USB_SSP_GEN_1x2)
reg |= DWC3_DCFG_SUPERSPEED_PLUS;
if (ssp_rate != USB_SSP_GEN_2x1 &&
dwc->max_ssp_rate != USB_SSP_GEN_2x1)
reg |= DWC3_DCFG_NUMLANES(1);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
{
enum usb_device_speed speed;
u32 reg;
speed = dwc->gadget_max_speed;
if (speed == USB_SPEED_UNKNOWN || speed > dwc->maximum_speed)
speed = dwc->maximum_speed;
if (speed == USB_SPEED_SUPER_PLUS &&
DWC3_IP_IS(DWC32)) {
__dwc3_gadget_set_ssp_rate(dwc);
return;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
/*
* WORKAROUND: DWC3 revision < 2.20a have an issue
* which would cause metastability state on Run/Stop
* bit if we try to force the IP to USB2-only mode.
*
* Because of that, we cannot configure the IP to any
* speed other than the SuperSpeed
*
* Refers to:
*
* STAR#9000525659: Clock Domain Crossing on DCTL in
* USB 2.0 Mode
*/
if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
!dwc->dis_metastability_quirk) {
reg |= DWC3_DCFG_SUPERSPEED;
} else {
switch (speed) {
case USB_SPEED_FULL:
reg |= DWC3_DCFG_FULLSPEED;
break;
case USB_SPEED_HIGH:
reg |= DWC3_DCFG_HIGHSPEED;
break;
case USB_SPEED_SUPER:
reg |= DWC3_DCFG_SUPERSPEED;
break;
case USB_SPEED_SUPER_PLUS:
if (DWC3_IP_IS(DWC3))
reg |= DWC3_DCFG_SUPERSPEED;
else
reg |= DWC3_DCFG_SUPERSPEED_PLUS;
break;
default:
dev_err(dwc->dev, "invalid speed (%d)\n", speed);
if (DWC3_IP_IS(DWC3))
reg |= DWC3_DCFG_SUPERSPEED;
else
reg |= DWC3_DCFG_SUPERSPEED_PLUS;
}
}
if (DWC3_IP_IS(DWC32) &&
speed > USB_SPEED_UNKNOWN &&
speed < USB_SPEED_SUPER_PLUS)
reg &= ~DWC3_DCFG_NUMLANES(~0);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
u32 reg;
u32 timeout = 500;
if (pm_runtime_suspended(dwc->dev))
return 0;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on) {
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 187A)) {
reg &= ~DWC3_DCTL_TRGTULST_MASK;
reg |= DWC3_DCTL_TRGTULST_RX_DET;
}
2020-04-12 10:20:01 +08:00
if (!DWC3_VER_IS_PRIOR(DWC3, 194A))
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation)
reg |= DWC3_DCTL_KEEP_CONNECT;
__dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation && !suspend)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
dwc->pullups_connected = false;
}
dwc3_gadget_dctl_write_safe(dwc, reg);
do {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg &= DWC3_DSTS_DEVCTRLHLT;
} while (--timeout && !(!is_on ^ !reg));
if (!timeout)
return -ETIMEDOUT;
return 0;
}
static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
static void __dwc3_gadget_stop(struct dwc3 *dwc);
static int __dwc3_gadget_start(struct dwc3 *dwc);
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int ret;
is_on = !!is_on;
dwc->softconnect = is_on;
/*
* Per databook, when we want to stop the gadget, if a control transfer
* is still in process, complete it and get the core into setup phase.
*/
if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
reinit_completion(&dwc->ep0_in_setup);
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
if (ret == 0)
dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
}
/*
* Avoid issuing a runtime resume if the device is already in the
* suspended state during gadget disconnect. DWC3 gadget was already
* halted/stopped during runtime suspend.
*/
if (!is_on) {
pm_runtime_barrier(dwc->dev);
if (pm_runtime_suspended(dwc->dev))
return 0;
}
/*
* Check the return value for successful resume, or error. For a
* successful resume, the DWC3 runtime PM resume routine will handle
* the run stop sequence, so avoid duplicate operations here.
*/
ret = pm_runtime_get_sync(dwc->dev);
if (!ret || ret < 0) {
pm_runtime_put(dwc->dev);
return 0;
}
/*
* Synchronize and disable any further event handling while controller
* is being enabled/disabled.
*/
disable_irq(dwc->irq_gadget);
spin_lock_irqsave(&dwc->lock, flags);
if (!is_on) {
u32 count;
dwc->connected = false;
/*
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
* Section 4.1.8 Table 4-7, it states that for a device-initiated
* disconnect, the SW needs to ensure that it sends "a DEPENDXFER
* command for any active transfers" before clearing the RunStop
* bit.
*/
dwc3_stop_active_transfers(dwc);
__dwc3_gadget_stop(dwc);
/*
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
* Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the
* "software needs to acknowledge the events that are generated
* (by writing to GEVNTCOUNTn) while it is waiting for this bit
* to be set to '1'."
*/
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
count &= DWC3_GEVNTCOUNT_MASK;
if (count > 0) {
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
dwc->ev_buf->length;
}
} else {
__dwc3_gadget_start(dwc);
}
ret = dwc3_gadget_run_stop(dwc, is_on, false);
spin_unlock_irqrestore(&dwc->lock, flags);
enable_irq(dwc->irq_gadget);
pm_runtime_put(dwc->dev);
return ret;
}
static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
{
u32 reg;
/* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
DWC3_DEVTEN_CMDCMPLTEN |
DWC3_DEVTEN_ERRTICERREN |
DWC3_DEVTEN_WKUPEVTEN |
DWC3_DEVTEN_CONNECTDONEEN |
DWC3_DEVTEN_USBRSTEN |
DWC3_DEVTEN_DISCONNEVTEN);
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 250A))
reg |= DWC3_DEVTEN_ULSTCNGEN;
/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */
if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
reg |= DWC3_DEVTEN_U3L2L1SUSPEN;
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
}
static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
{
/* mask all interrupts */
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
/**
* dwc3_gadget_setup_nump - calculate and initialize NUMP field of %DWC3_DCFG
* @dwc: pointer to our context structure
*
* The following looks like complex but it's actually very simple. In order to
* calculate the number of packets we can burst at once on OUT transfers, we're
* gonna use RxFIFO size.
*
* To calculate RxFIFO size we need two numbers:
* MDWIDTH = size, in bits, of the internal memory bus
* RAM2_DEPTH = depth, in MDWIDTH, of internal RAM2 (where RxFIFO sits)
*
* Given these two numbers, the formula is simple:
*
* RxFIFO Size = (RAM2_DEPTH * MDWIDTH / 8) - 24 - 16;
*
* 24 bytes is for 3x SETUP packets
* 16 bytes is a clock domain crossing tolerance
*
* Given RxFIFO Size, NUMP = RxFIFOSize / 1024;
*/
static void dwc3_gadget_setup_nump(struct dwc3 *dwc)
{
u32 ram2_depth;
u32 mdwidth;
u32 nump;
u32 reg;
ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7);
mdwidth = dwc3_mdwidth(dwc);
nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024;
nump = min_t(u32, nump, 16);
/* update NumP */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~DWC3_DCFG_NUMP_MASK;
reg |= nump << DWC3_DCFG_NUMP_SHIFT;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
static int __dwc3_gadget_start(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int ret = 0;
u32 reg;
/*
* Use IMOD if enabled via dwc->imod_interval. Otherwise, if
* the core supports IMOD, disable it.
*/
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
} else if (dwc3_has_imod(dwc)) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
}
/*
* We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
* field instead of letting dwc3 itself calculate that automatically.
*
* This way, we maximize the chances that we'll be able to get several
* bursts of data without going through any sort of endpoint throttling.
*/
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
2020-04-12 10:20:01 +08:00
if (DWC3_IP_IS(DWC3))
reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
2020-04-12 10:20:01 +08:00
else
reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_gadget_setup_nump(dwc);
/*
* Currently the controller handles single stream only. So, Ignore
* Packet Pending bit for stream selection and don't search for another
* stream if the host sends Data Packet with PP=0 (for OUT direction) or
* ACK with NumP=0 and PP=0 (for IN direction). This slightly improves
* the stream performance.
*/
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_IGNSTRMPP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
/* Enable MST by default if the device is capable of MST */
if (DWC3_MST_CAPABLE(&dwc->hwparams)) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG1);
reg &= ~DWC3_DCFG1_DIS_MST_ENH;
dwc3_writel(dwc->regs, DWC3_DCFG1, reg);
}
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
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_DEPCFG_ACTION_INIT);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err1;
}
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
usb: dwc3: gadget: Fix the uninitialized link_state when udc starts Currently the link_state is uninitialized and the default value is 0(U0) before the first time we start the udc, and after we start the udc then stop the udc, the link_state will be undefined. We may have the following warnings if we start the udc again with an undefined link_state: WARNING: CPU: 0 PID: 327 at drivers/usb/dwc3/gadget.c:294 dwc3_send_gadget_ep_cmd+0x304/0x308 dwc3 100e0000.hidwc3_0: wakeup failed --> -22 [...] Call Trace: [<c010f270>] (unwind_backtrace) from [<c010b3d8>] (show_stack+0x10/0x14) [<c010b3d8>] (show_stack) from [<c034a4dc>] (dump_stack+0x84/0x98) [<c034a4dc>] (dump_stack) from [<c0118000>] (__warn+0xe8/0x100) [<c0118000>] (__warn) from [<c0118050>](warn_slowpath_fmt+0x38/0x48) [<c0118050>] (warn_slowpath_fmt) from [<c0442ec0>](dwc3_send_gadget_ep_cmd+0x304/0x308) [<c0442ec0>] (dwc3_send_gadget_ep_cmd) from [<c0445e68>](dwc3_ep0_start_trans+0x48/0xf4) [<c0445e68>] (dwc3_ep0_start_trans) from [<c0446750>](dwc3_ep0_out_start+0x64/0x80) [<c0446750>] (dwc3_ep0_out_start) from [<c04451c0>](__dwc3_gadget_start+0x1e0/0x278) [<c04451c0>] (__dwc3_gadget_start) from [<c04452e0>](dwc3_gadget_start+0x88/0x10c) [<c04452e0>] (dwc3_gadget_start) from [<c045ee54>](udc_bind_to_driver+0x88/0xbc) [<c045ee54>] (udc_bind_to_driver) from [<c045f29c>](usb_gadget_probe_driver+0xf8/0x140) [<c045f29c>] (usb_gadget_probe_driver) from [<bf005424>](gadget_dev_desc_UDC_store+0xac/0xc4 [libcomposite]) [<bf005424>] (gadget_dev_desc_UDC_store [libcomposite]) from[<c023d8e0>] (configfs_write_file+0xd4/0x160) [<c023d8e0>] (configfs_write_file) from [<c01d51e8>] (__vfs_write+0x1c/0x114) [<c01d51e8>] (__vfs_write) from [<c01d5ff4>] (vfs_write+0xa4/0x168) [<c01d5ff4>] (vfs_write) from [<c01d6d40>] (SyS_write+0x3c/0x90) [<c01d6d40>] (SyS_write) from [<c0107400>] (ret_fast_syscall+0x0/0x3c) Signed-off-by: Zeng Tao <prime.zeng@hisilicon.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-12-26 19:22:00 +08:00
dwc->link_state = DWC3_LINK_STATE_SS_DIS;
dwc->delayed_status = false;
dwc3_ep0_out_start(dwc);
dwc3_gadget_enable_irq(dwc);
return 0;
err1:
__dwc3_gadget_ep_disable(dwc->eps[0]);
err0:
return ret;
}
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int ret;
int irq;
irq = dwc->irq_gadget;
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
IRQF_SHARED, "dwc3", dwc->ev_buf);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
return ret;
}
spin_lock_irqsave(&dwc->lock, flags);
dwc->gadget_driver = driver;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static void __dwc3_gadget_stop(struct dwc3 *dwc)
{
dwc3_gadget_disable_irq(dwc);
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
}
static int dwc3_gadget_stop(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->gadget_driver = NULL;
dwc->max_cfg_eps = 0;
spin_unlock_irqrestore(&dwc->lock, flags);
free_irq(dwc->irq_gadget, dwc->ev_buf);
return 0;
}
usb: dwc3: gadget: Add support for disabling U1 and U2 entries Gadget applications may have a requirement to disable the U1 and U2 entry based on the usecase. Below are few usecases where the disabling U1/U2 entries may be possible. Usecase 1: When combining dwc3 with an redriver for a USB Type-C device solution, it sometimes have problems with leaving U1/U2 for certain hosts, resulting in link training errors and reconnects. For this U1/U2 state entries may be avoided. Usecase 2: When performing performance benchmarking on mass storage gadget the U1 and U2 entries can be disabled. Usecase 3: When periodic transfers like ISOC transfers are used with bInterval of 1 which doesn't require the link to enter into U1 or U2 state entry (since ping is issued from host for every uframe interval). In this case the U1 and U2 entry can be disabled. Disablement of U1/U2 can be done by setting U1DevExitLat and U2DevExitLat values to 0 in the BOS descriptor. Host on seeing 0 value for U1DevExitLat and U2DevExitLat, it doesn't send SET_SEL requests to the gadget. There may be some hosts which may send SET_SEL requests even after seeing 0 in the UxDevExitLat of BOS descriptor. To aviod U1/U2 entries for these type of hosts, dwc3 controller can be programmed to reject those U1/U2 requests by not enabling ACCEPTUxENA bits in DCTL register. This patch updates the same. Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> Signed-off-by: Claus H. Stovgaard <cst@phaseone.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2019-05-10 15:07:28 +08:00
static void dwc3_gadget_config_params(struct usb_gadget *g,
struct usb_dcd_config_params *params)
{
struct dwc3 *dwc = gadget_to_dwc(g);
params->besl_baseline = USB_DEFAULT_BESL_UNSPECIFIED;
params->besl_deep = USB_DEFAULT_BESL_UNSPECIFIED;
/* Recommended BESL */
if (!dwc->dis_enblslpm_quirk) {
/*
* If the recommended BESL baseline is 0 or if the BESL deep is
* less than 2, Microsoft's Windows 10 host usb stack will issue
* a usb reset immediately after it receives the extended BOS
* descriptor and the enumeration will fail. To maintain
* compatibility with the Windows' usb stack, let's set the
* recommended BESL baseline to 1 and clamp the BESL deep to be
* within 2 to 15.
*/
params->besl_baseline = 1;
if (dwc->is_utmi_l1_suspend)
params->besl_deep =
clamp_t(u8, dwc->hird_threshold, 2, 15);
}
usb: dwc3: gadget: Add support for disabling U1 and U2 entries Gadget applications may have a requirement to disable the U1 and U2 entry based on the usecase. Below are few usecases where the disabling U1/U2 entries may be possible. Usecase 1: When combining dwc3 with an redriver for a USB Type-C device solution, it sometimes have problems with leaving U1/U2 for certain hosts, resulting in link training errors and reconnects. For this U1/U2 state entries may be avoided. Usecase 2: When performing performance benchmarking on mass storage gadget the U1 and U2 entries can be disabled. Usecase 3: When periodic transfers like ISOC transfers are used with bInterval of 1 which doesn't require the link to enter into U1 or U2 state entry (since ping is issued from host for every uframe interval). In this case the U1 and U2 entry can be disabled. Disablement of U1/U2 can be done by setting U1DevExitLat and U2DevExitLat values to 0 in the BOS descriptor. Host on seeing 0 value for U1DevExitLat and U2DevExitLat, it doesn't send SET_SEL requests to the gadget. There may be some hosts which may send SET_SEL requests even after seeing 0 in the UxDevExitLat of BOS descriptor. To aviod U1/U2 entries for these type of hosts, dwc3 controller can be programmed to reject those U1/U2 requests by not enabling ACCEPTUxENA bits in DCTL register. This patch updates the same. Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> Signed-off-by: Claus H. Stovgaard <cst@phaseone.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2019-05-10 15:07:28 +08:00
/* U1 Device exit Latency */
if (dwc->dis_u1_entry_quirk)
params->bU1devExitLat = 0;
else
params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
/* U2 Device exit Latency */
if (dwc->dis_u2_entry_quirk)
params->bU2DevExitLat = 0;
else
params->bU2DevExitLat =
cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
}
static void dwc3_gadget_set_speed(struct usb_gadget *g,
enum usb_device_speed speed)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->gadget_max_speed = speed;
spin_unlock_irqrestore(&dwc->lock, flags);
}
static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
enum usb_ssp_rate rate)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->gadget_max_speed = USB_SPEED_SUPER_PLUS;
dwc->gadget_ssp_rate = rate;
spin_unlock_irqrestore(&dwc->lock, flags);
}
static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
{
struct dwc3 *dwc = gadget_to_dwc(g);
union power_supply_propval val = {0};
int ret;
if (dwc->usb2_phy)
return usb_phy_set_power(dwc->usb2_phy, mA);
if (!dwc->usb_psy)
return -EOPNOTSUPP;
val.intval = 1000 * mA;
ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
return ret;
}
/**
* dwc3_gadget_check_config - ensure dwc3 can support the USB configuration
* @g: pointer to the USB gadget
*
* Used to record the maximum number of endpoints being used in a USB composite
* device. (across all configurations) This is to be used in the calculation
* of the TXFIFO sizes when resizing internal memory for individual endpoints.
* It will help ensured that the resizing logic reserves enough space for at
* least one max packet.
*/
static int dwc3_gadget_check_config(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
struct usb_ep *ep;
int fifo_size = 0;
int ram1_depth;
int ep_num = 0;
if (!dwc->do_fifo_resize)
return 0;
list_for_each_entry(ep, &g->ep_list, ep_list) {
/* Only interested in the IN endpoints */
if (ep->claimed && (ep->address & USB_DIR_IN))
ep_num++;
}
if (ep_num <= dwc->max_cfg_eps)
return 0;
/* Update the max number of eps in the composition */
dwc->max_cfg_eps = ep_num;
fifo_size = dwc3_gadget_calc_tx_fifo_size(dwc, dwc->max_cfg_eps);
/* Based on the equation, increment by one for every ep */
fifo_size += dwc->max_cfg_eps;
/* Check if we can fit a single fifo per endpoint */
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
if (fifo_size > ram1_depth)
return -ENOMEM;
return 0;
}
static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->async_callbacks = enable;
spin_unlock_irqrestore(&dwc->lock, flags);
}
static const struct usb_gadget_ops dwc3_gadget_ops = {
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
.udc_set_speed = dwc3_gadget_set_speed,
.udc_set_ssp_rate = dwc3_gadget_set_ssp_rate,
usb: dwc3: gadget: Add support for disabling U1 and U2 entries Gadget applications may have a requirement to disable the U1 and U2 entry based on the usecase. Below are few usecases where the disabling U1/U2 entries may be possible. Usecase 1: When combining dwc3 with an redriver for a USB Type-C device solution, it sometimes have problems with leaving U1/U2 for certain hosts, resulting in link training errors and reconnects. For this U1/U2 state entries may be avoided. Usecase 2: When performing performance benchmarking on mass storage gadget the U1 and U2 entries can be disabled. Usecase 3: When periodic transfers like ISOC transfers are used with bInterval of 1 which doesn't require the link to enter into U1 or U2 state entry (since ping is issued from host for every uframe interval). In this case the U1 and U2 entry can be disabled. Disablement of U1/U2 can be done by setting U1DevExitLat and U2DevExitLat values to 0 in the BOS descriptor. Host on seeing 0 value for U1DevExitLat and U2DevExitLat, it doesn't send SET_SEL requests to the gadget. There may be some hosts which may send SET_SEL requests even after seeing 0 in the UxDevExitLat of BOS descriptor. To aviod U1/U2 entries for these type of hosts, dwc3 controller can be programmed to reject those U1/U2 requests by not enabling ACCEPTUxENA bits in DCTL register. This patch updates the same. Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> Signed-off-by: Claus H. Stovgaard <cst@phaseone.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2019-05-10 15:07:28 +08:00
.get_config_params = dwc3_gadget_config_params,
.vbus_draw = dwc3_gadget_vbus_draw,
.check_config = dwc3_gadget_check_config,
.udc_async_callbacks = dwc3_gadget_async_callbacks,
};
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
dep->endpoint.maxburst = 1;
dep->endpoint.ops = &dwc3_gadget_ep0_ops;
if (!dep->direction)
dwc->gadget->ep0 = &dep->endpoint;
dep->endpoint.caps.type_control = true;
return 0;
}
static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
u32 mdwidth;
int size;
mdwidth = dwc3_mdwidth(dwc);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth /= 8;
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1));
2020-04-12 10:20:01 +08:00
if (DWC3_IP_IS(DWC3))
size = DWC3_GTXFIFOSIZ_TXFDEP(size);
2020-04-12 10:20:01 +08:00
else
size = DWC31_GTXFIFOSIZ_TXFDEP(size);
/* FIFO Depth is in MDWDITH bytes. Multiply */
size *= mdwidth;
/*
* To meet performance requirement, a minimum TxFIFO size of 3x
* MaxPacketSize is recommended for endpoints that support burst and a
* minimum TxFIFO size of 2x MaxPacketSize for endpoints that don't
* support burst. Use those numbers and we can calculate the max packet
* limit as below.
*/
if (dwc->maximum_speed >= USB_SPEED_SUPER)
size /= 3;
else
size /= 2;
usb_ep_set_maxpacket_limit(&dep->endpoint, size);
dep->endpoint.max_streams = 16;
dep->endpoint.ops = &dwc3_gadget_ep_ops;
list_add_tail(&dep->endpoint.ep_list,
&dwc->gadget->ep_list);
dep->endpoint.caps.type_iso = true;
dep->endpoint.caps.type_bulk = true;
dep->endpoint.caps.type_int = true;
return dwc3_alloc_trb_pool(dep);
}
static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
u32 mdwidth;
int size;
mdwidth = dwc3_mdwidth(dwc);
/* MDWIDTH is represented in bits, convert to bytes */
mdwidth /= 8;
/* All OUT endpoints share a single RxFIFO space */
size = dwc3_readl(dwc->regs, DWC3_GRXFIFOSIZ(0));
2020-04-12 10:20:01 +08:00
if (DWC3_IP_IS(DWC3))
size = DWC3_GRXFIFOSIZ_RXFDEP(size);
2020-04-12 10:20:01 +08:00
else
size = DWC31_GRXFIFOSIZ_RXFDEP(size);
/* FIFO depth is in MDWDITH bytes */
size *= mdwidth;
/*
* To meet performance requirement, a minimum recommended RxFIFO size
* is defined as follow:
* RxFIFO size >= (3 x MaxPacketSize) +
* (3 x 8 bytes setup packets size) + (16 bytes clock crossing margin)
*
* Then calculate the max packet limit as below.
*/
size -= (3 * 8) + 16;
if (size < 0)
size = 0;
else
size /= 3;
usb_ep_set_maxpacket_limit(&dep->endpoint, size);
dep->endpoint.max_streams = 16;
dep->endpoint.ops = &dwc3_gadget_ep_ops;
list_add_tail(&dep->endpoint.ep_list,
&dwc->gadget->ep_list);
dep->endpoint.caps.type_iso = true;
dep->endpoint.caps.type_bulk = true;
dep->endpoint.caps.type_int = true;
return dwc3_alloc_trb_pool(dep);
}
static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
{
struct dwc3_ep *dep;
bool direction = epnum & 1;
int ret;
u8 num = epnum >> 1;
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep)
return -ENOMEM;
dep->dwc = dwc;
dep->number = epnum;
dep->direction = direction;
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
dwc->eps[epnum] = dep;
usb: dwc3: Add workaround for isoc start transfer failure In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the XferNotReady event are invalid. The driver uses this number to schedule the isochronous transfer and passes it to the START TRANSFER command. Because this number is invalid, the command may fail. If BIT[15:14] matches the internal 16-bit microframe, the START TRANSFER command will pass and the transfer will start at the scheduled time, if it is off by 1, the command will still pass, but the transfer will start 2 seconds in the future. For all other conditions, the START TRANSFER command will fail with bus-expiry. In order to workaround this issue, we can test for the correct combination of BIT[15:14] by sending START TRANSFER commands with different values of BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart (or 2 seconds). 4 seconds into the future will result in a bus-expiry status. As the result, within the 4 possible combinations for BIT[15:14], there will be 2 successful and 2 failure START COMMAND status. One of the 2 successful command status will result in a 2-second delay start. The smaller BIT[15:14] value is the correct combination. Since there are only 4 outcomes and the results are ordered, we can simply test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to deduce the smaller successful combination. Let test0 = test status for combination 'b00 and test1 = test status for 'b01 of BIT[15:14]. The correct combination is as follow: if test0 fails and test1 passes, BIT[15:14] is 'b01 if test0 fails and test1 fails, BIT[15:14] is 'b10 if test0 passes and test1 fails, BIT[15:14] is 'b11 if test0 passes and test1 passes, BIT[15:14] is 'b00 Synopsys STAR 9001202023: Wrong microframe number for isochronous IN endpoints. Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2018-11-15 14:56:54 +08:00
dep->combo_num = 0;
dep->start_cmd_status = 0;
snprintf(dep->name, sizeof(dep->name), "ep%u%s", num,
direction ? "in" : "out");
dep->endpoint.name = dep->name;
if (!(dep->number > 1)) {
dep->endpoint.desc = &dwc3_gadget_ep0_desc;
dep->endpoint.comp_desc = NULL;
}
if (num == 0)
ret = dwc3_gadget_init_control_endpoint(dep);
else if (direction)
ret = dwc3_gadget_init_in_endpoint(dep);
else
ret = dwc3_gadget_init_out_endpoint(dep);
if (ret)
return ret;
dep->endpoint.caps.dir_in = direction;
dep->endpoint.caps.dir_out = !direction;
INIT_LIST_HEAD(&dep->pending_list);
INIT_LIST_HEAD(&dep->started_list);
INIT_LIST_HEAD(&dep->cancelled_list);
usb: dwc3: debugfs: Add and remove endpoint dirs dynamically The DWC3 DebugFS directory and files are currently created once during probe. This includes creation of subdirectories for each of the gadget's endpoints. This works fine for peripheral-only controllers, as dwc3_core_init_mode() calls dwc3_gadget_init() just prior to calling dwc3_debugfs_init(). However, for dual-role controllers, dwc3_core_init_mode() will instead call dwc3_drd_init() which is problematic in a few ways. First, the initial state must be determined, then dwc3_set_mode() will have to schedule drd_work and by then dwc3_debugfs_init() could have already been invoked. Even if the initial mode is peripheral, dwc3_gadget_init() happens after the DebugFS files are created, and worse so if the initial state is host and the controller switches to peripheral much later. And secondly, even if the gadget endpoints' debug entries were successfully created, if the controller exits peripheral mode, its dwc3_eps are freed so the debug files would now hold stale references. So it is best if the DebugFS endpoint entries are created and removed dynamically at the same time the underlying dwc3_eps are. Do this by calling dwc3_debugfs_create_endpoint_dir() as each endpoint is created, and conversely remove the DebugFS entry when the endpoint is freed. Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly") Reviewed-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20210529192932.22912-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-05-30 03:29:32 +08:00
dwc3_debugfs_create_endpoint_dir(dep);
return 0;
}
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
{
u8 epnum;
INIT_LIST_HEAD(&dwc->gadget->ep_list);
for (epnum = 0; epnum < total; epnum++) {
int ret;
ret = dwc3_gadget_init_endpoint(dwc, epnum);
if (ret)
return ret;
}
return 0;
}
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
u8 epnum;
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = dwc->eps[epnum];
if (!dep)
continue;
/*
* Physical endpoints 0 and 1 are special; they form the
* bi-directional USB endpoint 0.
*
* For those two physical endpoints, we don't allocate a TRB
* pool nor do we add them the endpoints list. Due to that, we
* shouldn't do these two operations otherwise we would end up
* with all sorts of bugs when removing dwc3.ko.
*/
if (epnum != 0 && epnum != 1) {
dwc3_free_trb_pool(dep);
list_del(&dep->endpoint.ep_list);
}
debugfs_remove_recursive(debugfs_lookup(dep->name,
debugfs_lookup(dev_name(dep->dwc->dev),
usb_debug_root)));
kfree(dep);
}
}
/* -------------------------------------------------------------------------- */
static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
struct dwc3_request *req, struct dwc3_trb *trb,
const struct dwc3_event_depevt *event, int status, int chain)
{
unsigned int count;
dwc3_ep_inc_deq(dep);
trace_dwc3_complete_trb(dep, trb);
req->num_trbs--;
/*
* If we're in the middle of series of chained TRBs and we
* receive a short transfer along the way, DWC3 will skip
* through all TRBs including the last TRB in the chain (the
* where CHN bit is zero. DWC3 will also avoid clearing HWO
* bit and SW has to do it manually.
*
* We're going to do that here to avoid problems of HW trying
* to use bogus TRBs for transfers.
*/
if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
/*
* For isochronous transfers, the first TRB in a service interval must
* have the Isoc-First type. Track and report its interval frame number.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(trb->ctrl & DWC3_TRBCTL_ISOCHRONOUS_FIRST)) {
unsigned int frame_number;
frame_number = DWC3_TRB_CTRL_GET_SID_SOFN(trb->ctrl);
frame_number &= ~(dep->interval - 1);
req->request.frame_number = frame_number;
}
/*
* We use bounce buffer for requests that needs extra TRB or OUT ZLP. If
* this TRB points to the bounce buffer address, it's a MPS alignment
* TRB. Don't add it to req->remaining calculation.
*/
if (trb->bpl == lower_32_bits(dep->dwc->bounce_addr) &&
trb->bph == upper_32_bits(dep->dwc->bounce_addr)) {
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
return 1;
}
count = trb->size & DWC3_TRB_SIZE_MASK;
req->remaining += count;
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
return 1;
if (event->status & DEPEVT_STATUS_SHORT && !chain)
return 1;
usb: dwc3: gadget: Check for IOC/LST bit in TRB->ctrl fields The current code in dwc3_gadget_ep_reclaim_completed_trb() will check for IOC/LST bit in the event->status and returns if IOC/LST bit is set. This logic doesn't work if multiple TRBs are queued per request and the IOC/LST bit is set on the last TRB of that request. Consider an example where a queued request has multiple queued TRBs and IOC/LST bit is set only for the last TRB. In this case, the core generates XferComplete/XferInProgress events only for the last TRB (since IOC/LST are set only for the last TRB). As per the logic in dwc3_gadget_ep_reclaim_completed_trb() event->status is checked for IOC/LST bit and returns on the first TRB. This leaves the remaining TRBs left unhandled. Similarly, if the gadget function enqueues an unaligned request with sglist already in it, it should fail the same way, since we will append another TRB to something that already uses more than one TRB. To aviod this, this patch changes the code to check for IOC/LST bits in TRB->ctrl instead. At a practical level, this patch resolves USB transfer stalls seen with adb on dwc3 based HiKey960 after functionfs gadget added scatter-gather support around v4.20. Cc: Felipe Balbi <balbi@kernel.org> Cc: Yang Fei <fei.yang@intel.com> Cc: Thinh Nguyen <thinhn@synopsys.com> Cc: Tejas Joglekar <tejas.joglekar@synopsys.com> Cc: Andrzej Pietrasiewicz <andrzej.p@collabora.com> Cc: Jack Pham <jackp@codeaurora.org> Cc: Todd Kjos <tkjos@google.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Linux USB List <linux-usb@vger.kernel.org> Cc: stable <stable@vger.kernel.org> Tested-by: Tejas Joglekar <tejas.joglekar@synopsys.com> Reviewed-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> [jstultz: forward ported to mainline, reworded commit log, reworked to only check trb->ctrl as suggested by Felipe] Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2020-01-28 03:30:46 +08:00
if ((trb->ctrl & DWC3_TRB_CTRL_IOC) ||
(trb->ctrl & DWC3_TRB_CTRL_LST))
return 1;
return 0;
}
static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
struct dwc3_request *req, const struct dwc3_event_depevt *event,
int status)
{
struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
struct scatterlist *sg = req->sg;
struct scatterlist *s;
unsigned int num_queued = req->num_queued_sgs;
unsigned int i;
int ret = 0;
for_each_sg(sg, s, num_queued, i) {
trb = &dep->trb_pool[dep->trb_dequeue];
req->sg = sg_next(s);
req->num_queued_sgs--;
ret = dwc3_gadget_ep_reclaim_completed_trb(dep, req,
trb, event, status, true);
if (ret)
break;
}
return ret;
}
static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep,
struct dwc3_request *req, const struct dwc3_event_depevt *event,
int status)
{
struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
return dwc3_gadget_ep_reclaim_completed_trb(dep, req, trb,
event, status, false);
}
static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req)
{
return req->num_pending_sgs == 0 && req->num_queued_sgs == 0;
}
static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event,
struct dwc3_request *req, int status)
{
int ret;
if (req->request.num_mapped_sgs)
ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event,
status);
else
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status);
req->request.actual = req->request.length - req->remaining;
if (!dwc3_gadget_ep_request_completed(req))
goto out;
if (req->needs_extra_trb) {
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status);
req->needs_extra_trb = false;
}
dwc3_gadget_giveback(dep, req, status);
out:
return ret;
}
static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
struct dwc3_request *req;
struct dwc3_request *tmp;
list_for_each_entry_safe(req, tmp, &dep->started_list, list) {
int ret;
ret = dwc3_gadget_ep_cleanup_completed_request(dep, event,
req, status);
if (ret)
break;
}
}
static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep)
{
struct dwc3_request *req;
struct dwc3 *dwc = dep->dwc;
if (!dep->endpoint.desc || !dwc->pullups_connected ||
!dwc->connected)
return false;
if (!list_empty(&dep->pending_list))
return true;
/*
* We only need to check the first entry of the started list. We can
* assume the completed requests are removed from the started list.
*/
req = next_request(&dep->started_list);
if (!req)
return false;
return !dwc3_gadget_ep_request_completed(req);
}
static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
dep->frame_number = event->parameters;
}
static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
struct dwc3 *dwc = dep->dwc;
bool no_started_trb = true;
if (!dep->endpoint.desc)
return no_started_trb;
dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
goto out;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->started_list) &&
(list_empty(&dep->pending_list) || status == -EXDEV))
dwc3_stop_active_transfer(dep, true, true);
else if (dwc3_gadget_ep_should_continue(dep))
if (__dwc3_gadget_kick_transfer(dep) == 0)
no_started_trb = false;
out:
/*
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
* See dwc3_gadget_linksts_change_interrupt() for 1st half.
*/
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 183A)) {
u32 reg;
int i;
for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
dep = dwc->eps[i];
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
if (!list_empty(&dep->started_list))
return no_started_trb;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= dwc->u1u2;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->u1u2 = 0;
}
return no_started_trb;
}
static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
int status = 0;
if (!dep->endpoint.desc)
return;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
dwc3_gadget_endpoint_frame_from_event(dep, event);
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
if (event->status & DEPEVT_STATUS_MISSED_ISOC)
status = -EXDEV;
dwc3_gadget_endpoint_trbs_complete(dep, event, status);
}
static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
int status = 0;
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
if (dwc3_gadget_endpoint_trbs_complete(dep, event, status))
dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE;
}
static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
dwc3_gadget_endpoint_frame_from_event(dep, event);
/*
* The XferNotReady event is generated only once before the endpoint
* starts. It will be generated again when END_TRANSFER command is
* issued. For some controller versions, the XferNotReady event may be
* generated while the END_TRANSFER command is still in process. Ignore
* it and wait for the next XferNotReady event after the command is
* completed.
*/
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
return;
(void) __dwc3_gadget_start_isoc(dep);
}
static void dwc3_gadget_endpoint_command_complete(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
u8 cmd = DEPEVT_PARAMETER_CMD(event->parameters);
if (cmd != DWC3_DEPCMD_ENDTRANSFER)
return;
/*
* The END_TRANSFER command will cause the controller to generate a
* NoStream Event, and it's not due to the host DP NoStream rejection.
* Ignore the next NoStream event.
*/
if (dep->stream_capable)
dep->flags |= DWC3_EP_IGNORE_NEXT_NOSTREAM;
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
if (dep->flags & DWC3_EP_PENDING_CLEAR_STALL) {
struct dwc3 *dwc = dep->dwc;
dep->flags &= ~DWC3_EP_PENDING_CLEAR_STALL;
if (dwc3_send_clear_stall_ep_cmd(dep)) {
struct usb_ep *ep0 = &dwc->eps[0]->endpoint;
dev_err(dwc->dev, "failed to clear STALL on %s\n", dep->name);
if (dwc->delayed_status)
__dwc3_gadget_ep0_set_halt(ep0, 1);
return;
}
dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
if (dwc->delayed_status)
dwc3_ep0_send_delayed_status(dwc);
}
if ((dep->flags & DWC3_EP_DELAY_START) &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc))
__dwc3_gadget_kick_transfer(dep);
dep->flags &= ~DWC3_EP_DELAY_START;
}
static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
struct dwc3 *dwc = dep->dwc;
if (event->status == DEPEVT_STREAMEVT_FOUND) {
dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED;
goto out;
}
/* Note: NoStream rejection event param value is 0 and not 0xFFFF */
switch (event->parameters) {
case DEPEVT_STREAM_PRIME:
/*
* If the host can properly transition the endpoint state from
* idle to prime after a NoStream rejection, there's no need to
* force restarting the endpoint to reinitiate the stream. To
* simplify the check, assume the host follows the USB spec if
* it primed the endpoint more than once.
*/
if (dep->flags & DWC3_EP_FORCE_RESTART_STREAM) {
if (dep->flags & DWC3_EP_FIRST_STREAM_PRIMED)
dep->flags &= ~DWC3_EP_FORCE_RESTART_STREAM;
else
dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED;
}
break;
case DEPEVT_STREAM_NOSTREAM:
if ((dep->flags & DWC3_EP_IGNORE_NEXT_NOSTREAM) ||
!(dep->flags & DWC3_EP_FORCE_RESTART_STREAM) ||
(!DWC3_MST_CAPABLE(&dwc->hwparams) &&
!(dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)))
break;
/*
* If the host rejects a stream due to no active stream, by the
* USB and xHCI spec, the endpoint will be put back to idle
* state. When the host is ready (buffer added/updated), it will
* prime the endpoint to inform the usb device controller. This
* triggers the device controller to issue ERDY to restart the
* stream. However, some hosts don't follow this and keep the
* endpoint in the idle state. No prime will come despite host
* streams are updated, and the device controller will not be
* triggered to generate ERDY to move the next stream data. To
* workaround this and maintain compatibility with various
* hosts, force to reinitate the stream until the host is ready
* instead of waiting for the host to prime the endpoint.
*/
if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) {
unsigned int cmd = DWC3_DGCMD_SET_ENDPOINT_PRIME;
dwc3_send_gadget_generic_command(dwc, cmd, dep->number);
} else {
dep->flags |= DWC3_EP_DELAY_START;
dwc3_stop_active_transfer(dep, true, true);
return;
}
break;
}
out:
dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM;
}
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
struct dwc3_ep *dep;
u8 epnum = event->endpoint_number;
dep = dwc->eps[epnum];
if (!(dep->flags & DWC3_EP_ENABLED)) {
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
return;
/* Handle only EPCMDCMPLT when EP disabled */
if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
return;
}
if (epnum == 0 || epnum == 1) {
dwc3_ep0_interrupt(dwc, event);
return;
}
switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERINPROGRESS:
dwc3_gadget_endpoint_transfer_in_progress(dep, event);
break;
case DWC3_DEPEVT_XFERNOTREADY:
dwc3_gadget_endpoint_transfer_not_ready(dep, event);
break;
case DWC3_DEPEVT_EPCMDCMPLT:
dwc3_gadget_endpoint_command_complete(dep, event);
break;
case DWC3_DEPEVT_XFERCOMPLETE:
dwc3_gadget_endpoint_transfer_complete(dep, event);
break;
case DWC3_DEPEVT_STREAMEVT:
dwc3_gadget_endpoint_stream_event(dep, event);
break;
case DWC3_DEPEVT_RXTXFIFOEVT:
break;
}
}
static void dwc3_disconnect_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->disconnect) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->disconnect(dwc->gadget);
spin_lock(&dwc->lock);
}
}
static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->suspend) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->suspend(dwc->gadget);
spin_lock(&dwc->lock);
}
}
static void dwc3_resume_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(dwc->gadget);
spin_lock(&dwc->lock);
}
}
static void dwc3_reset_gadget(struct dwc3 *dwc)
{
if (!dwc->gadget_driver)
return;
if (dwc->async_callbacks && dwc->gadget->speed != USB_SPEED_UNKNOWN) {
spin_unlock(&dwc->lock);
usb_gadget_udc_reset(dwc->gadget, dwc->gadget_driver);
spin_lock(&dwc->lock);
}
}
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
bool interrupt)
{
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret;
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) ||
(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
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.
*
* 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 issuing EndTransfer with
* CMDIOC bit set and delay kicking transfer until the
* EndTransfer command had completed.
*
* As of IP version 3.10a of the DWC_usb3 IP, the controller
* supports a mode to work around the above limitation. The
* software can poll the CMDACT bit in the DEPCMD register
* after issuing a EndTransfer command. This mode is enabled
* by writing GUCTL2[14]. This polling is already done in the
* dwc3_send_gadget_ep_cmd() function so if the mode is
* enabled, the EndTransfer command will have completed upon
* returning from this function.
*
* This mode is NOT available on the DWC_usb31 IP.
*/
cmd = DWC3_DEPCMD_ENDTRANSFER;
cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0;
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
memset(&params, 0, sizeof(params));
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
WARN_ON_ONCE(ret);
dep->resource_index = 0;
if (!interrupt)
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
else
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
}
static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
{
u32 epnum;
for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
struct dwc3_ep *dep;
int ret;
dep = dwc->eps[epnum];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_STALL))
continue;
dep->flags &= ~DWC3_EP_STALL;
ret = dwc3_send_clear_stall_ep_cmd(dep);
WARN_ON_ONCE(ret);
}
}
static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
{
int reg;
dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_gadget_dctl_write_safe(dwc, reg);
dwc3_disconnect_gadget(dwc);
dwc->gadget->speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false;
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
dwc->connected = false;
}
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
/*
* Ideally, dwc3_reset_gadget() would trigger the function
* drivers to stop any active transfers through ep disable.
* However, for functions which defer ep disable, such as mass
* storage, we will need to rely on the call to stop active
* transfers here, and avoid allowing of request queuing.
*/
dwc->connected = false;
/*
* WORKAROUND: DWC3 revisions <1.88a have an issue which
* would cause a missing Disconnect Event if there's a
* pending Setup Packet in the FIFO.
*
* There's no suggested workaround on the official Bug
* report, which states that "unless the driver/application
* is doing any special handling of a disconnect event,
* there is no functional issue".
*
* Unfortunately, it turns out that we _do_ some special
* handling of a disconnect event, namely complete all
* pending transfers, notify gadget driver of the
* disconnection, and so on.
*
* Our suggested workaround is to follow the Disconnect
* Event steps here, instead, based on a setup_packet_pending
* flag. Such flag gets set whenever we have a SETUP_PENDING
* status for EP0 TRBs and gets cleared on XferComplete for the
* same endpoint.
*
* Refers to:
*
* STAR#9000466709: RTL: Device : Disconnect event not
* generated if setup packet pending in FIFO
*/
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 188A)) {
if (dwc->setup_packet_pending)
dwc3_gadget_disconnect_interrupt(dwc);
}
dwc3_reset_gadget(dwc);
/*
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
* Section 4.1.2 Table 4-2, it states that during a USB reset, the SW
* needs to ensure that it sends "a DEPENDXFER command for any active
* transfers."
*/
dwc3_stop_active_transfers(dwc);
dwc->connected = true;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg);
dwc->test_mode = false;
dwc3_clear_stall_all_ep(dwc);
/* Reset device address to zero */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int ret;
u32 reg;
u8 lanes = 1;
u8 speed;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
dwc->speed = speed;
if (DWC3_IP_IS(DWC32))
lanes = DWC3_DSTS_CONNLANES(reg) + 1;
dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN;
/*
* RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
* each time on Connect Done.
*
* Currently we always use the reset value. If any platform
* wants to set this to a different value, we need to add a
* setting and update GCTL.RAMCLKSEL here.
*/
switch (speed) {
case DWC3_DSTS_SUPERSPEED_PLUS:
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dwc->gadget->ep0->maxpacket = 512;
dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
if (lanes > 1)
dwc->gadget->ssp_rate = USB_SSP_GEN_2x2;
else
dwc->gadget->ssp_rate = USB_SSP_GEN_2x1;
break;
case DWC3_DSTS_SUPERSPEED:
/*
* WORKAROUND: DWC3 revisions <1.90a have an issue which
* would cause a missing USB3 Reset event.
*
* In such situations, we should force a USB3 Reset
* event by calling our dwc3_gadget_reset_interrupt()
* routine.
*
* Refers to:
*
* STAR#9000483510: RTL: SS : USB3 reset event may
* not be generated always when the link enters poll
*/
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 190A))
dwc3_gadget_reset_interrupt(dwc);
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dwc->gadget->ep0->maxpacket = 512;
dwc->gadget->speed = USB_SPEED_SUPER;
if (lanes > 1) {
dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
dwc->gadget->ssp_rate = USB_SSP_GEN_1x2;
}
break;
case DWC3_DSTS_HIGHSPEED:
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
dwc->gadget->ep0->maxpacket = 64;
dwc->gadget->speed = USB_SPEED_HIGH;
break;
case DWC3_DSTS_FULLSPEED:
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
dwc->gadget->ep0->maxpacket = 64;
dwc->gadget->speed = USB_SPEED_FULL;
break;
}
dwc->eps[1]->endpoint.maxpacket = dwc->gadget->ep0->maxpacket;
/* Enable USB2 LPM Capability */
2020-04-12 10:20:01 +08:00
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A) &&
!dwc->usb2_gadget_lpm_disable &&
(speed != DWC3_DSTS_SUPERSPEED) &&
(speed != DWC3_DSTS_SUPERSPEED_PLUS)) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold |
(dwc->is_utmi_l1_suspend << 4));
/*
* When dwc3 revisions >= 2.40a, LPM Erratum is enabled and
* DCFG.LPMCap is set, core responses with an ACK and the
* BESL value in the LPM token is less than or equal to LPM
* NYET threshold.
*/
2020-04-12 10:20:01 +08:00
WARN_ONCE(DWC3_VER_IS_PRIOR(DWC3, 240A) && dwc->has_lpm_erratum,
"LPM Erratum not available on dwc3 revisions < 2.40a\n");
2020-04-12 10:20:01 +08:00
if (dwc->has_lpm_erratum && !DWC3_VER_IS_PRIOR(DWC3, 240A))
reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold);
dwc3_gadget_dctl_write_safe(dwc, reg);
} else {
if (dwc->usb2_gadget_lpm_disable) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg);
}
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_MODIFY);
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_DEPCFG_ACTION_MODIFY);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
return;
}
/*
* Configure PHY via GUSB3PIPECTLn if required.
*
* Update GTXFIFOSIZn
*
* In both cases reset values should be sufficient.
*/
}
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
{
/*
* TODO take core out of low power mode when that's
* implemented.
*/
if (dwc->async_callbacks && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(dwc->gadget);
spin_lock(&dwc->lock);
}
}
static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
unsigned int pwropt;
/*
* WORKAROUND: DWC3 < 2.50a have an issue when configured without
* Hibernation mode enabled which would show up when device detects
* host-initiated U3 exit.
*
* In that case, device will generate a Link State Change Interrupt
* from U3 to RESUME which is only necessary if Hibernation is
* configured in.
*
* There are no functional changes due to such spurious event and we
* just need to ignore it.
*
* Refers to:
*
* STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
* operational mode
*/
pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 250A) &&
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
return;
}
}
/*
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
* on the link partner, the USB session might do multiple entry/exit
* of low power states before a transfer takes place.
*
* Due to this problem, we might experience lower throughput. The
* suggested workaround is to disable DCTL[12:9] bits if we're
* transitioning from U1/U2 to U0 and enable those bits again
* after a transfer completes and there are no pending transfers
* on any of the enabled endpoints.
*
* This is the first half of that workaround.
*
* Refers to:
*
* STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
* core send LGO_Ux entering U0
*/
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 183A)) {
if (next == DWC3_LINK_STATE_U0) {
u32 u1u2;
u32 reg;
switch (dwc->link_state) {
case DWC3_LINK_STATE_U1:
case DWC3_LINK_STATE_U2:
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
u1u2 = reg & (DWC3_DCTL_INITU2ENA
| DWC3_DCTL_ACCEPTU2ENA
| DWC3_DCTL_INITU1ENA
| DWC3_DCTL_ACCEPTU1ENA);
if (!dwc->u1u2)
dwc->u1u2 = reg & u1u2;
reg &= ~u1u2;
dwc3_gadget_dctl_write_safe(dwc, reg);
break;
default:
/* do nothing */
break;
}
}
}
switch (next) {
case DWC3_LINK_STATE_U1:
if (dwc->speed == USB_SPEED_SUPER)
dwc3_suspend_gadget(dwc);
break;
case DWC3_LINK_STATE_U2:
case DWC3_LINK_STATE_U3:
dwc3_suspend_gadget(dwc);
break;
case DWC3_LINK_STATE_RESUME:
dwc3_resume_gadget(dwc);
break;
default:
/* do nothing */
break;
}
dwc->link_state = next;
}
static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
if (dwc->link_state != next && next == DWC3_LINK_STATE_U3)
dwc3_suspend_gadget(dwc);
dwc->link_state = next;
}
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
unsigned int is_ss = evtinfo & BIT(4);
/*
* WORKAROUND: DWC3 revison 2.20a with hibernation support
* have a known issue which can cause USB CV TD.9.23 to fail
* randomly.
*
* Because of this issue, core could generate bogus hibernation
* events which SW needs to ignore.
*
* Refers to:
*
* STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
* Device Fallback from SuperSpeed
*/
if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
return;
/* enter hibernation here */
}
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
switch (event->type) {
case DWC3_DEVICE_EVENT_DISCONNECT:
dwc3_gadget_disconnect_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_RESET:
dwc3_gadget_reset_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_CONNECT_DONE:
dwc3_gadget_conndone_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_WAKEUP:
dwc3_gadget_wakeup_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_HIBER_REQ:
if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
"unexpected hibernation event\n"))
break;
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_SUSPEND:
/* It changed to be suspend event for version 2.30a and above */
2020-04-12 10:20:01 +08:00
if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) {
/*
* Ignore suspend event until the gadget enters into
* USB_STATE_CONFIGURED state.
*/
if (dwc->gadget->state >= USB_STATE_CONFIGURED)
dwc3_gadget_suspend_interrupt(dwc,
event->event_info);
}
break;
case DWC3_DEVICE_EVENT_SOF:
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
case DWC3_DEVICE_EVENT_CMD_CMPL:
case DWC3_DEVICE_EVENT_OVERFLOW:
break;
default:
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
}
static void dwc3_process_event_entry(struct dwc3 *dwc,
const union dwc3_event *event)
{
trace_dwc3_event(event->raw, dwc);
if (!event->type.is_devspec)
dwc3_endpoint_interrupt(dwc, &event->depevt);
else if (event->type.type == DWC3_EVENT_TYPE_DEV)
dwc3_gadget_interrupt(dwc, &event->devt);
else
dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
}
static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
{
struct dwc3 *dwc = evt->dwc;
irqreturn_t ret = IRQ_NONE;
int left;
left = evt->count;
if (!(evt->flags & DWC3_EVENT_PENDING))
return IRQ_NONE;
while (left > 0) {
union dwc3_event event;
event.raw = *(u32 *) (evt->cache + evt->lpos);
dwc3_process_event_entry(dwc, &event);
/*
* FIXME we wrap around correctly to the next entry as
* almost all entries are 4 bytes in size. There is one
* entry which has 12 bytes which is a regular entry
* followed by 8 bytes data. ATM I don't know how
* things are organized if we get next to the a
* boundary so I worry about that once we try to handle
* that.
*/
evt->lpos = (evt->lpos + 4) % evt->length;
left -= 4;
}
evt->count = 0;
evt->flags &= ~DWC3_EVENT_PENDING;
ret = IRQ_HANDLED;
/* Unmask interrupt */
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
}
return ret;
}
static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
{
struct dwc3_event_buffer *evt = _evt;
struct dwc3 *dwc = evt->dwc;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
spin_lock_irqsave(&dwc->lock, flags);
ret = dwc3_process_event_buf(evt);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
{
struct dwc3 *dwc = evt->dwc;
u32 amount;
u32 count;
if (pm_runtime_suspended(dwc->dev)) {
pm_runtime_get(dwc->dev);
disable_irq_nosync(dwc->irq_gadget);
dwc->pending_events = true;
return IRQ_HANDLED;
}
/*
* With PCIe legacy interrupt, test shows that top-half irq handler can
* be called again after HW interrupt deassertion. Check if bottom-half
* irq event handler completes before caching new event to prevent
* losing events.
*/
if (evt->flags & DWC3_EVENT_PENDING)
return IRQ_HANDLED;
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
evt->count = count;
evt->flags |= DWC3_EVENT_PENDING;
/* Mask interrupt */
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length));
amount = min(count, evt->length - evt->lpos);
memcpy(evt->cache + evt->lpos, evt->buf + evt->lpos, amount);
if (amount < count)
memcpy(evt->cache, evt->buf, count - amount);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
return IRQ_WAKE_THREAD;
}
static irqreturn_t dwc3_interrupt(int irq, void *_evt)
{
struct dwc3_event_buffer *evt = _evt;
return dwc3_check_event_buf(evt);
}
static int dwc3_gadget_get_irq(struct dwc3 *dwc)
{
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int irq;
irq = platform_get_irq_byname_optional(dwc3_pdev, "peripheral");
if (irq > 0)
goto out;
if (irq == -EPROBE_DEFER)
goto out;
irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
if (irq > 0)
goto out;
if (irq == -EPROBE_DEFER)
goto out;
irq = platform_get_irq(dwc3_pdev, 0);
if (irq > 0)
goto out;
if (!irq)
irq = -EINVAL;
out:
return irq;
}
static void dwc_gadget_release(struct device *dev)
{
struct usb_gadget *gadget = container_of(dev, struct usb_gadget, dev);
kfree(gadget);
}
/**
* dwc3_gadget_init - initializes gadget related registers
* @dwc: pointer to our controller context structure
*
* Returns 0 on success otherwise negative errno.
*/
int dwc3_gadget_init(struct dwc3 *dwc)
{
int ret;
int irq;
struct device *dev;
irq = dwc3_gadget_get_irq(dwc);
if (irq < 0) {
ret = irq;
goto err0;
}
dwc->irq_gadget = irq;
dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
sizeof(*dwc->ep0_trb) * 2,
&dwc->ep0_trb_addr, GFP_KERNEL);
if (!dwc->ep0_trb) {
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
ret = -ENOMEM;
goto err0;
}
dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
ret = -ENOMEM;
goto err1;
}
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
&dwc->bounce_addr, GFP_KERNEL);
if (!dwc->bounce) {
ret = -ENOMEM;
goto err2;
}
init_completion(&dwc->ep0_in_setup);
dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL);
if (!dwc->gadget) {
ret = -ENOMEM;
goto err3;
}
usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release);
dev = &dwc->gadget->dev;
dev->platform_data = dwc;
dwc->gadget->ops = &dwc3_gadget_ops;
dwc->gadget->speed = USB_SPEED_UNKNOWN;
dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN;
dwc->gadget->sg_supported = true;
dwc->gadget->name = "dwc3-gadget";
dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable;
/*
* FIXME We might be setting max_speed to <SUPER, however versions
* <2.20a of dwc3 have an issue with metastability (documented
* elsewhere in this driver) which tells us we can't set max speed to
* anything lower than SUPER.
*
* Because gadget.max_speed is only used by composite.c and function
* drivers (i.e. it won't go into dwc3's registers) we are allowing this
* to happen so we avoid sending SuperSpeed Capability descriptor
* together with our BOS descriptor as that could confuse host into
* thinking we can handle super speed.
*
* Note that, in fact, we won't even support GetBOS requests when speed
* is less than super speed because we don't have means, yet, to tell
* composite.c that we are USB 2.0 + LPM ECN.
*/
2020-04-12 10:20:01 +08:00
if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
!dwc->dis_metastability_quirk)
dev_info(dwc->dev, "changing max_speed on rev %08x\n",
dwc->revision);
dwc->gadget->max_speed = dwc->maximum_speed;
dwc->gadget->max_ssp_rate = dwc->max_ssp_rate;
/*
* REVISIT: Here we should clear all pending IRQs to be
* sure we're starting from a well known location.
*/
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
if (ret)
goto err4;
ret = usb_add_gadget(dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to add gadget\n");
goto err5;
}
if (DWC3_IP_IS(DWC32) && dwc->maximum_speed == USB_SPEED_SUPER_PLUS)
dwc3_gadget_set_ssp_rate(dwc->gadget, dwc->max_ssp_rate);
else
dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed);
return 0;
err5:
dwc3_gadget_free_endpoints(dwc);
err4:
usb_put_gadget(dwc->gadget);
usb: dwc3: gadget: Bail from dwc3_gadget_exit() if dwc->gadget is NULL There exists a possible scenario in which dwc3_gadget_init() can fail: during during host -> peripheral mode switch in dwc3_set_mode(), and a pending gadget driver fails to bind. Then, if the DRD undergoes another mode switch from peripheral->host the resulting dwc3_gadget_exit() will attempt to reference an invalid and dangling dwc->gadget pointer as well as call dma_free_coherent() on unmapped DMA pointers. The exact scenario can be reproduced as follows: - Start DWC3 in peripheral mode - Configure ConfigFS gadget with FunctionFS instance (or use g_ffs) - Run FunctionFS userspace application (open EPs, write descriptors, etc) - Bind gadget driver to DWC3's UDC - Switch DWC3 to host mode => dwc3_gadget_exit() is called. usb_del_gadget() will put the ConfigFS driver instance on the gadget_driver_pending_list - Stop FunctionFS application (closes the ep files) - Switch DWC3 to peripheral mode => dwc3_gadget_init() fails as usb_add_gadget() calls check_pending_gadget_drivers() and attempts to rebind the UDC to the ConfigFS gadget but fails with -19 (-ENODEV) because the FFS instance is not in FFS_ACTIVE state (userspace has not re-opened and written the descriptors yet, i.e. desc_ready!=0). - Switch DWC3 back to host mode => dwc3_gadget_exit() is called again, but this time dwc->gadget is invalid. Although it can be argued that userspace should take responsibility for ensuring that the FunctionFS application be ready prior to allowing the composite driver bind to the UDC, failure to do so should not result in a panic from the kernel driver. Fix this by setting dwc->gadget to NULL in the failure path of dwc3_gadget_init() and add a check to dwc3_gadget_exit() to bail out unless the gadget pointer is valid. Fixes: e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") Cc: <stable@vger.kernel.org> Reviewed-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20210528160405.17550-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-05-29 00:04:05 +08:00
dwc->gadget = NULL;
err3:
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
dwc->bounce_addr);
err2:
kfree(dwc->setup_buf);
err1:
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
dwc->ep0_trb, dwc->ep0_trb_addr);
err0:
return ret;
}
/* -------------------------------------------------------------------------- */
void dwc3_gadget_exit(struct dwc3 *dwc)
{
usb: dwc3: gadget: Bail from dwc3_gadget_exit() if dwc->gadget is NULL There exists a possible scenario in which dwc3_gadget_init() can fail: during during host -> peripheral mode switch in dwc3_set_mode(), and a pending gadget driver fails to bind. Then, if the DRD undergoes another mode switch from peripheral->host the resulting dwc3_gadget_exit() will attempt to reference an invalid and dangling dwc->gadget pointer as well as call dma_free_coherent() on unmapped DMA pointers. The exact scenario can be reproduced as follows: - Start DWC3 in peripheral mode - Configure ConfigFS gadget with FunctionFS instance (or use g_ffs) - Run FunctionFS userspace application (open EPs, write descriptors, etc) - Bind gadget driver to DWC3's UDC - Switch DWC3 to host mode => dwc3_gadget_exit() is called. usb_del_gadget() will put the ConfigFS driver instance on the gadget_driver_pending_list - Stop FunctionFS application (closes the ep files) - Switch DWC3 to peripheral mode => dwc3_gadget_init() fails as usb_add_gadget() calls check_pending_gadget_drivers() and attempts to rebind the UDC to the ConfigFS gadget but fails with -19 (-ENODEV) because the FFS instance is not in FFS_ACTIVE state (userspace has not re-opened and written the descriptors yet, i.e. desc_ready!=0). - Switch DWC3 back to host mode => dwc3_gadget_exit() is called again, but this time dwc->gadget is invalid. Although it can be argued that userspace should take responsibility for ensuring that the FunctionFS application be ready prior to allowing the composite driver bind to the UDC, failure to do so should not result in a panic from the kernel driver. Fix this by setting dwc->gadget to NULL in the failure path of dwc3_gadget_init() and add a check to dwc3_gadget_exit() to bail out unless the gadget pointer is valid. Fixes: e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") Cc: <stable@vger.kernel.org> Reviewed-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20210528160405.17550-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-05-29 00:04:05 +08:00
if (!dwc->gadget)
return;
usb: dwc3: gadget: Free gadget structure only after freeing endpoints As part of commit e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") the dwc3_gadget_release() was added which will free the dwc->gadget structure upon the device's removal when usb_del_gadget_udc() is called in dwc3_gadget_exit(). However, simply freeing the gadget results a dangling pointer situation: the endpoints created in dwc3_gadget_init_endpoints() have their dep->endpoint.ep_list members chained off the list_head anchored at dwc->gadget->ep_list. Thus when dwc->gadget is freed, the first dwc3_ep in the list now has a dangling prev pointer and likewise for the next pointer of the dwc3_ep at the tail of the list. The dwc3_gadget_free_endpoints() that follows will result in a use-after-free when it calls list_del(). This was caught by enabling KASAN and performing a driver unbind. The recent commit 568262bf5492 ("usb: dwc3: core: Add shutdown callback for dwc3") also exposes this as a panic during shutdown. There are a few possibilities to fix this. One could be to perform a list_del() of the gadget->ep_list itself which removes it from the rest of the dwc3_ep chain. Another approach is what this patch does, by splitting up the usb_del_gadget_udc() call into its separate "del" and "put" components. This allows dwc3_gadget_free_endpoints() to be called before the gadget is finally freed with usb_put_gadget(). Fixes: e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") Reviewed-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20210501093558.7375-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-05-01 17:35:58 +08:00
usb_del_gadget(dwc->gadget);
dwc3_gadget_free_endpoints(dwc);
usb: dwc3: gadget: Free gadget structure only after freeing endpoints As part of commit e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") the dwc3_gadget_release() was added which will free the dwc->gadget structure upon the device's removal when usb_del_gadget_udc() is called in dwc3_gadget_exit(). However, simply freeing the gadget results a dangling pointer situation: the endpoints created in dwc3_gadget_init_endpoints() have their dep->endpoint.ep_list members chained off the list_head anchored at dwc->gadget->ep_list. Thus when dwc->gadget is freed, the first dwc3_ep in the list now has a dangling prev pointer and likewise for the next pointer of the dwc3_ep at the tail of the list. The dwc3_gadget_free_endpoints() that follows will result in a use-after-free when it calls list_del(). This was caught by enabling KASAN and performing a driver unbind. The recent commit 568262bf5492 ("usb: dwc3: core: Add shutdown callback for dwc3") also exposes this as a panic during shutdown. There are a few possibilities to fix this. One could be to perform a list_del() of the gadget->ep_list itself which removes it from the rest of the dwc3_ep chain. Another approach is what this patch does, by splitting up the usb_del_gadget_udc() call into its separate "del" and "put" components. This allows dwc3_gadget_free_endpoints() to be called before the gadget is finally freed with usb_put_gadget(). Fixes: e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") Reviewed-by: Peter Chen <peter.chen@kernel.org> Signed-off-by: Jack Pham <jackp@codeaurora.org> Link: https://lore.kernel.org/r/20210501093558.7375-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-05-01 17:35:58 +08:00
usb_put_gadget(dwc->gadget);
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
dwc->bounce_addr);
kfree(dwc->setup_buf);
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
dwc->ep0_trb, dwc->ep0_trb_addr);
}
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
if (!dwc->gadget_driver)
return 0;
usb: dwc3: gadget: Fix system suspend/resume on TI platforms On TI platforms (dra7, am437x), the DWC3_DSTS_DEVCTRLHLT bit is not set after the device controller is stopped via DWC3_DCTL_RUN_STOP. If we don't disconnect and stop the gadget, it stops working after a system resume with the trace below. There is no point in preventing gadget disconnect and gadget stop during system suspend/resume as we're going to suspend in any case, whether DEVCTRLHLT timed out or not. [ 141.727480] ------------[ cut here ]------------ [ 141.732349] WARNING: CPU: 1 PID: 2135 at drivers/usb/dwc3/gadget.c:2384 dwc3_stop_active_transfer.constprop.4+0xc4/0xe4 [dwc3] [ 141.744299] Modules linked in: usb_f_ss_lb g_zero libcomposite xhci_plat_hcd xhci_hcd usbcore dwc3 evdev udc_core m25p80 usb_common spi_nor snd_soc_davinci_mcasp snd_soc_simple_card snd_soc_edma snd_soc_tlv3e [ 141.792163] CPU: 1 PID: 2135 Comm: irq/456-dwc3 Not tainted 4.10.0-rc8 #1138 [ 141.799547] Hardware name: Generic DRA74X (Flattened Device Tree) [ 141.805940] [<c01101b4>] (unwind_backtrace) from [<c010c31c>] (show_stack+0x10/0x14) [ 141.814066] [<c010c31c>] (show_stack) from [<c04a0918>] (dump_stack+0xac/0xe0) [ 141.821648] [<c04a0918>] (dump_stack) from [<c013708c>] (__warn+0xd8/0x104) [ 141.828955] [<c013708c>] (__warn) from [<c0137164>] (warn_slowpath_null+0x20/0x28) [ 141.836902] [<c0137164>] (warn_slowpath_null) from [<bf27784c>] (dwc3_stop_active_transfer.constprop.4+0xc4/0xe4 [dwc3]) [ 141.848329] [<bf27784c>] (dwc3_stop_active_transfer.constprop.4 [dwc3]) from [<bf27ab14>] (__dwc3_gadget_ep_disable+0x64/0x528 [dwc3]) [ 141.861034] [<bf27ab14>] (__dwc3_gadget_ep_disable [dwc3]) from [<bf27c27c>] (dwc3_gadget_ep_disable+0x3c/0xc8 [dwc3]) [ 141.872280] [<bf27c27c>] (dwc3_gadget_ep_disable [dwc3]) from [<bf23b428>] (usb_ep_disable+0x11c/0x18c [udc_core]) [ 141.883160] [<bf23b428>] (usb_ep_disable [udc_core]) from [<bf342774>] (disable_ep+0x18/0x54 [usb_f_ss_lb]) [ 141.893408] [<bf342774>] (disable_ep [usb_f_ss_lb]) from [<bf3437b0>] (disable_endpoints+0x18/0x50 [usb_f_ss_lb]) [ 141.904168] [<bf3437b0>] (disable_endpoints [usb_f_ss_lb]) from [<bf343814>] (disable_source_sink+0x2c/0x34 [usb_f_ss_lb]) [ 141.915771] [<bf343814>] (disable_source_sink [usb_f_ss_lb]) from [<bf329a9c>] (reset_config+0x48/0x7c [libcomposite]) [ 141.927012] [<bf329a9c>] (reset_config [libcomposite]) from [<bf329afc>] (composite_disconnect+0x2c/0x54 [libcomposite]) [ 141.938444] [<bf329afc>] (composite_disconnect [libcomposite]) from [<bf23d7dc>] (usb_gadget_udc_reset+0x10/0x34 [udc_core]) [ 141.950237] [<bf23d7dc>] (usb_gadget_udc_reset [udc_core]) from [<bf276d70>] (dwc3_gadget_reset_interrupt+0x64/0x698 [dwc3]) [ 141.962022] [<bf276d70>] (dwc3_gadget_reset_interrupt [dwc3]) from [<bf27952c>] (dwc3_thread_interrupt+0x618/0x1a3c [dwc3]) [ 141.973723] [<bf27952c>] (dwc3_thread_interrupt [dwc3]) from [<c01a7ce8>] (irq_thread_fn+0x1c/0x54) [ 141.983215] [<c01a7ce8>] (irq_thread_fn) from [<c01a7fbc>] (irq_thread+0x120/0x1f0) [ 141.991247] [<c01a7fbc>] (irq_thread) from [<c015ba14>] (kthread+0xf8/0x138) [ 141.998641] [<c015ba14>] (kthread) from [<c01078f0>] (ret_from_fork+0x14/0x24) [ 142.006213] ---[ end trace b4ecfe9f175b9a9c ]--- Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2017-02-15 20:16:26 +08:00
dwc3_gadget_run_stop(dwc, false, false);
dwc3_disconnect_gadget(dwc);
__dwc3_gadget_stop(dwc);
return 0;
}
int dwc3_gadget_resume(struct dwc3 *dwc)
{
int ret;
if (!dwc->gadget_driver || !dwc->softconnect)
return 0;
ret = __dwc3_gadget_start(dwc);
if (ret < 0)
goto err0;
ret = dwc3_gadget_run_stop(dwc, true, false);
if (ret < 0)
goto err1;
return 0;
err1:
__dwc3_gadget_stop(dwc);
err0:
return ret;
}
void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{
if (dwc->pending_events) {
dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
dwc->pending_events = false;
enable_irq(dwc->irq_gadget);
}
}