summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Pham <jackp@codeaurora.org>2015-04-20 22:49:35 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:06:36 -0700
commitf0487e67e5e62f1b4b6a2061896a62742a19d54b (patch)
treec443ce4a7cba8737a5d6e8495e9f6a2c6479cf93
parent88ffd6eb9530fa8c9e51ed4ea2411795a83dc2de (diff)
usb: dwc3: Adjust TX FIFO allocation
Optimize the dwc3_gadget_resize_tx_fifos() function to better allocate the per-endpoint FIFOs depending on a number of factors: - super- or non-super speed - bulk/isoc with bursting - reduced RAM (when QDSS uses some internal RAM) - endpoint enabled in composition Signed-off-by: Jack Pham <jackp@codeaurora.org>
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/gadget.c46
-rw-r--r--drivers/usb/gadget/composite.c6
-rw-r--r--include/linux/usb/composite.h4
4 files changed, 44 insertions, 14 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 23a73345958d..c377250c5c9f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -800,6 +800,7 @@ struct dwc3_scratchpad_array {
* @err_evt_seen: previous event in queue was erratic error
* @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
* @in_lpm: indicates if controller is in low power mode (no clocks)
+ * @tx_fifo_size: Available RAM size for TX fifo allocation
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -953,6 +954,7 @@ struct dwc3 {
struct dwc3_gadget_events dbg_gadget_events;
atomic_t in_lpm;
+ int tx_fifo_size;
};
/* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 211014069acb..9a2adb8b8127 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -29,6 +29,7 @@
#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
#include "debug.h"
@@ -178,47 +179,53 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
int fifo_size;
int mdwidth;
int num;
+ int num_eps;
+ struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget);
if (!dwc->needs_fifo_resize)
return 0;
+ /* gadget.num_eps never be greater than dwc->num_in_eps */
+ num_eps = min_t(int, dwc->num_in_eps,
+ cdev->config->num_ineps_used + 1);
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3;
- /*
- * FIXME For now we will only allocate 1 wMaxPacketSize space
- * for each enabled endpoint, later patches will come to
- * improve this algorithm so that we better use the internal
- * FIFO space
- */
- for (num = 0; num < dwc->num_in_eps; num++) {
+ dev_dbg(dwc->dev, "%s: num eps: %d\n", __func__, num_eps);
+
+ for (num = 0; 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;
+ int max_packet = 1024;
- if (!(dep->flags & DWC3_EP_ENABLED))
- continue;
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ dev_warn(dwc->dev, "ep%dIn not enabled", num);
+ tmp = max_packet + mdwidth;
+ goto resize_fifo;
+ }
- if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
+ if (((dep->endpoint.maxburst > 1) &&
+ usb_endpoint_xfer_bulk(dep->endpoint.desc))
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
mult = 3;
-
/*
* REVISIT: the following assumes we will always have enough
* space available on the FIFO RAM for all possible use cases.
* Make sure that's true somehow and change FIFO allocation
* accordingly.
*
- * If we have Bulk or Isochronous endpoints, we want
- * them to be able to be very, very fast. So we're giving
+ * If we have Bulk (burst only) or Isochronous endpoints, we
+ * want them to be able to be very, very fast. So we're giving
* those endpoints a fifo_size which is enough for 3 full
* packets
*/
tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+resize_fifo:
tmp += mdwidth;
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
@@ -228,9 +235,20 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
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);
- last_fifo_depth += (fifo_size & 0xffff);
}
return 0;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 50be4fd1d11e..08badc2b23af 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -793,6 +793,8 @@ static int set_config(struct usb_composite_dev *cdev,
usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
cdev->config = c;
+ c->num_ineps_used = 0;
+ c->num_outeps_used = 0;
/* Initialize all interfaces by setting them to altsetting zero. */
for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
@@ -836,6 +838,10 @@ static int set_config(struct usb_composite_dev *cdev,
addr = ((ep->bEndpointAddress & 0x80) >> 3)
| (ep->bEndpointAddress & 0x0f);
set_bit(addr, f->endpoints);
+ if (usb_endpoint_dir_in(ep))
+ c->num_ineps_used++;
+ else
+ c->num_outeps_used++;
}
result = f->set_alt(f, tmp, 0);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index acecf5fa6a63..bc5637ab01df 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -336,6 +336,10 @@ struct usb_configuration {
unsigned highspeed:1;
unsigned fullspeed:1;
struct usb_function *interface[MAX_CONFIG_INTERFACES];
+
+ /* number of in and out eps used in this configuration */
+ int num_ineps_used;
+ int num_outeps_used;
};
int usb_add_config(struct usb_composite_dev *,