]> git.karo-electronics.de Git - linux-beck.git/commitdiff
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 7c9df630dbe4f848be07dda04a3f2a295a78d7c7..d119a1fbf9466243b2c3afecfe0f7e306523229b 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 f4878c4dec0fca2f9473f9a4d277dbe375605db9..123c3aa471283431874ba1a36c57326ce9eaf9d1 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 e90ebb9dd3e87f1905dd5b8f482b4f589826aa99..5104dbf46680de50e5ac48e9f4cc20303eae2781 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 d406a75456a0d661973e4028c39a9466df0b0ab2..7913d1b50e3853223786dacd4194adb0445e3bba 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;