usb: dwc3: gadget: dynamically re-size TxFifos
authorFelipe Balbi <balbi@ti.com>
Wed, 18 Jan 2012 16:04:09 +0000 (18:04 +0200)
committerFelipe Balbi <balbi@ti.com>
Mon, 6 Feb 2012 09:48:34 +0000 (11:48 +0200)
We need to dynamically re-size TxFifos for the
cases where default values will not do.

While at that, we create a simple function which,
for now, will just allocate one full packet fifo
space for each of the enabled endpoints.

This can be improved later in order to allow for
better throughput by allocating more space for
endpoints which could make good use of that like
isochronous and bulk.

Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c

index 7c9df63..d119a1f 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -404,6 +405,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
+       struct device_node      *node = pdev->dev.of_node;
        struct resource         *res;
        struct dwc3             *dwc;
 
@@ -469,6 +471,9 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
        else
                dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
+       if (of_get_property(node, "tx-fifo-resize", NULL))
+               dwc->needs_fifo_resize = true;
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
        pm_runtime_forbid(&pdev->dev);
index f4878c4..123c3aa 100644 (file)
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
 
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)   ((n & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO   0
@@ -546,8 +550,13 @@ struct dwc3_hwparams {
 #define DWC3_MODE_DRD          2
 #define DWC3_MODE_HUB          3
 
+#define DWC3_MDWIDTH(n)                (((n) & 0xff00) >> 8)
+
 /* HWPARAMS1 */
-#define DWC3_NUM_INT(n)        (((n) & (0x3f << 15)) >> 15)
+#define DWC3_NUM_INT(n)                (((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)     ((n) & 0xffff)
 
 struct dwc3_request {
        struct usb_request      request;
@@ -594,6 +603,8 @@ struct dwc3_request {
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -651,6 +662,8 @@ struct dwc3 {
        unsigned                start_config_issued:1;
        unsigned                setup_packet_pending:1;
        unsigned                delayed_status:1;
+       unsigned                needs_fifo_resize:1;
+       unsigned                resize_fifos:1;
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
@@ -812,6 +825,7 @@ union dwc3_event {
 
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
index e90ebb9..5104dbf 100644 (file)
@@ -457,8 +457,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        case DWC3_ADDRESS_STATE:
                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)))
+               if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
                        dwc->dev_state = DWC3_CONFIGURED_STATE;
+                       dwc->resize_fifos = true;
+                       dev_dbg(dwc->dev, "resize fifos flag SET\n");
+               }
                break;
 
        case DWC3_CONFIGURED_STATE:
@@ -707,6 +710,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
 {
        struct dwc3_ep          *dep = dwc->eps[epnum];
 
+       if (dwc->resize_fifos) {
+               dev_dbg(dwc->dev, "starting to resize fifos\n");
+               dwc3_gadget_resize_tx_fifos(dwc);
+               dwc->resize_fifos = 0;
+       }
+
        WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
index d406a75..7913d1b 100644 (file)
@@ -125,6 +125,80 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
        return -ETIMEDOUT;
 }
 
+/**
+ * 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 the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * 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;
+
+       if (!dwc->needs_fifo_resize)
+               return 0;
+
+       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 < DWC3_ENDPOINTS_NUM; num++) {
+               struct dwc3_ep  *dep = dwc->eps[num];
+               int             fifo_number = dep->number >> 1;
+               int             tmp;
+
+               if (!(dep->number & 1))
+                       continue;
+
+               if (!(dep->flags & DWC3_EP_ENABLED))
+                       continue;
+
+               tmp = dep->endpoint.maxpacket;
+               tmp += mdwidth;
+               tmp += mdwidth;
+
+               fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+               fifo_size |= (last_fifo_depth << 16);
+
+               dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+                               dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+               dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
+                               fifo_size);
+
+               last_fifo_depth += (fifo_size & 0xffff);
+       }
+
+       return 0;
+}
+
 void dwc3_map_buffer_to_dma(struct dwc3_request *req)
 {
        struct dwc3                     *dwc = req->dep->dwc;