summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/dwc3/core.h8
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c7
-rw-r--r--drivers/usb/dwc3/ep0.c29
-rw-r--r--drivers/usb/dwc3/gadget.c141
4 files changed, 92 insertions, 93 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 9f73ec68a23b..2e56d167ba05 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -543,6 +543,7 @@ struct dwc3_ep_events {
* @dbg_ep_events: different events counter for endpoint
* @dbg_ep_events_diff: differential events counter for endpoint
* @dbg_ep_events_ts: timestamp for previous event counters
+ * @fifo_depth: allocated TXFIFO depth
*/
struct dwc3_ep {
struct usb_ep endpoint;
@@ -583,6 +584,7 @@ struct dwc3_ep {
struct dwc3_ep_events dbg_ep_events;
struct dwc3_ep_events dbg_ep_events_diff;
struct timespec dbg_ep_events_ts;
+ int fifo_depth;
};
enum dwc3_phy {
@@ -813,7 +815,6 @@ struct dwc3_scratchpad_array {
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
- * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued
* @three_stage_setup: set if we perform a three phase setup
@@ -853,6 +854,7 @@ struct dwc3_scratchpad_array {
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
* @create_reg_debugfs: create debugfs entry to allow dwc3 register dump
+ * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -988,7 +990,6 @@ struct dwc3 {
unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;
- unsigned resize_fifos:1;
unsigned setup_packet_pending:1;
unsigned three_stage_setup:1;
unsigned usb3_lpm_capable:1;
@@ -1050,6 +1051,7 @@ struct dwc3 {
wait_queue_head_t wait_linkstate;
bool create_reg_debugfs;
+ int last_fifo_depth;
};
/* -------------------------------------------------------------------------- */
@@ -1199,7 +1201,7 @@ struct dwc3_gadget_ep_cmd_params {
/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
-int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep);
/* check whether we are on the DWC_usb3 core */
static inline bool dwc3_is_usb3(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 920555c64af4..1e23738e20b3 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1132,7 +1132,8 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
struct dwc3_gadget_ep_cmd_params params;
const struct usb_endpoint_descriptor *desc = ep->desc;
const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc;
- u32 reg;
+ u32 reg;
+ int ret;
memset(&params, 0x00, sizeof(params));
@@ -1181,6 +1182,10 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
/* Set XferRsc Index for GSI EP */
if (!(dep->flags & DWC3_EP_ENABLED)) {
+ ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
+ if (ret)
+ return;
+
memset(&params, 0x00, sizeof(params));
params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
dwc3_send_gadget_ep_cmd(dwc, dep->number,
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 24ecbc469eb6..dd9a41af43bd 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -601,8 +601,9 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
enum usb_device_state state = dwc->gadget.state;
u32 cfg;
- int ret;
+ int ret, num;
u32 reg;
+ struct dwc3_ep *dep;
cfg = le16_to_cpu(ctrl->wValue);
@@ -611,6 +612,24 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return -EINVAL;
case USB_STATE_ADDRESS:
+ /* Read ep0IN related TXFIFO size */
+ dwc->last_fifo_depth = (dwc3_readl(dwc->regs,
+ DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
+ /* Clear existing allocated TXFIFO for all IN eps except ep0 */
+ for (num = 0; num < dwc->num_in_eps; num++) {
+ dep = dwc->eps[(num << 1) | 1];
+ if (num) {
+ dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), 0);
+ dep->fifo_depth = 0;
+ } else {
+ dep->fifo_depth = dwc->last_fifo_depth;
+ }
+
+ dev_dbg(dwc->dev, "%s(): %s dep->fifo_depth:%x\n",
+ __func__, dep->name, dep->fifo_depth);
+ dbg_event(0xFF, "fifo_reset", dep->number);
+ }
+
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
@@ -635,9 +654,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
DWC3_DCTL_ACCEPTU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
-
- dwc->resize_fifos = true;
- dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
}
break;
@@ -1085,11 +1101,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{
int ret;
- if (dwc->resize_fifos) {
- dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
- dwc3_gadget_resize_tx_fifos(dwc);
- dwc->resize_fifos = 0;
- }
ret = dwc3_ep0_start_control_status(dep);
if (WARN_ON_ONCE(ret))
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f6117ac0e301..b9c5c9ba8419 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -172,88 +172,64 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
*
* Unfortunately, due to many variables that's not always the case.
*/
-int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
-{
- int last_fifo_depth = 0;
- int ram1_depth;
- int fifo_size;
- int mdwidth;
- int num;
- int num_eps;
- int max_packet = 1024;
- struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget);
-
- if (!(cdev && cdev->config) || !dwc->needs_fifo_resize)
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ int fifo_size, mdwidth, max_packet = 1024;
+ int tmp, mult = 1;
+
+ if (!dwc->needs_fifo_resize)
return 0;
- num_eps = dwc->num_in_eps;
- ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
- mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+ /* resize IN endpoints excepts ep0 */
+ if (!usb_endpoint_dir_in(dep->endpoint.desc) ||
+ dep->endpoint.ep_num == 0)
+ return 0;
+ /* Don't resize already resized IN endpoint */
+ if (dep->fifo_depth) {
+ dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n",
+ dep->endpoint.name, dep->fifo_depth);
+ return 0;
+ }
+
+ mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3;
- last_fifo_depth = (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
- dev_dbg(dwc->dev, "%s: num eps:%d max_packet:%d last_fifo_depth:%04x\n",
- __func__, num_eps, max_packet, last_fifo_depth);
-
- /* Don't resize ep0IN TxFIFO, start with ep1IN only. */
- for (num = 1; num < num_eps; num++) {
- /* bit0 indicates direction; 1 means IN ep */
- struct dwc3_ep *dep = dwc->eps[(num << 1) | 1];
- int mult = 1;
- int tmp;
-
- tmp = max_packet + mdwidth;
- /*
- * Interfaces like MBIM or ECM is having multiple data
- * interfaces. SET_CONFIG() happens before set_alt with
- * data interface 1 which results into calling this API
- * before GSI endpoint enabled. This results no txfifo
- * resize with GSI endpoint causing low throughput. Hence
- * use mult as 3 for GSI IN endpoint always irrespective
- * USB speed.
- */
- if (dep->endpoint.ep_type == EP_TYPE_GSI ||
- dep->endpoint.endless)
- mult = 3;
-
- if (!(dep->flags & DWC3_EP_ENABLED)) {
- dev_dbg(dwc->dev, "ep%dIn not enabled", num);
- goto resize_fifo;
- }
-
- if (((dep->endpoint.maxburst > 1) &&
- usb_endpoint_xfer_bulk(dep->endpoint.desc))
- || usb_endpoint_xfer_isoc(dep->endpoint.desc))
- mult = 3;
-
-resize_fifo:
- tmp *= mult;
- tmp += mdwidth;
-
- fifo_size = DIV_ROUND_UP(tmp, mdwidth);
-
- fifo_size |= (last_fifo_depth << 16);
-
- dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
- dep->name, last_fifo_depth, fifo_size & 0xffff);
-
- last_fifo_depth += (fifo_size & 0xffff);
- if (dwc->tx_fifo_size &&
- (last_fifo_depth >= dwc->tx_fifo_size)) {
- /*
- * Fifo size allocated exceeded available RAM size.
- * Hence return error.
- */
- dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n",
- last_fifo_depth, dwc->tx_fifo_size);
- return -ENOMEM;
- }
-
- dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
+ if (dep->endpoint.ep_type == EP_TYPE_GSI || dep->endpoint.endless)
+ mult = 3;
+
+ if (((dep->endpoint.maxburst > 1) &&
+ usb_endpoint_xfer_bulk(dep->endpoint.desc))
+ || usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ mult = 3;
+
+ tmp = ((max_packet + mdwidth) * mult) + mdwidth;
+ fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+ dep->fifo_depth = fifo_size;
+ fifo_size |= (dwc->last_fifo_depth << 16);
+ dwc->last_fifo_depth += (fifo_size & 0xffff);
+
+ dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n",
+ dep->endpoint.name, dep->endpoint.ep_num, dwc->last_fifo_depth,
+ dep->fifo_depth);
+
+ dbg_event(0xFF, "resize_fifo", dep->number);
+ dbg_event(0xFF, "fifo_depth", dep->fifo_depth);
+ /* Check fifo size allocation doesn't exceed available RAM size. */
+ if (dwc->tx_fifo_size &&
+ ((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size)) {
+ dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
+ (dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size,
+ dep->endpoint.name, fifo_size);
+ dwc->last_fifo_depth -= (fifo_size & 0xffff);
+ dep->fifo_depth = 0;
+ WARN_ON(1);
+ return -ENOMEM;
}
+ dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->endpoint.ep_num),
+ fifo_size);
return 0;
}
@@ -622,6 +598,17 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
if (!(dep->flags & DWC3_EP_ENABLED)) {
+ dep->endpoint.desc = desc;
+ dep->comp_desc = comp_desc;
+ dep->type = usb_endpoint_type(desc);
+ ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
+ if (ret) {
+ dep->endpoint.desc = NULL;
+ dep->comp_desc = NULL;
+ dep->type = 0;
+ return ret;
+ }
+
ret = dwc3_gadget_start_config(dwc, dep);
if (ret) {
dev_err(dwc->dev, "start_config() failed for %s\n",
@@ -641,9 +628,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
struct dwc3_trb *trb_st_hw;
struct dwc3_trb *trb_link;
- dep->endpoint.desc = desc;
- dep->comp_desc = comp_desc;
- dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
@@ -2894,9 +2878,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dwc3_stop_active_transfers(dwc);
dwc3_clear_stall_all_ep(dwc);
- /* bus reset issued due to missing status stage of a control transfer */
- dwc->resize_fifos = 0;
-
/* Reset device address to zero */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);