Merge tag 'usb-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[linux-2.6-microblaze.git] / drivers / usb / dwc3 / gadget.c
index ccb68fe..804b505 100644 (file)
@@ -631,6 +631,187 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
 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);
+       }
+       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;
+
+       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);
+       dwc->num_ep_resized++;
+
+       return 0;
+}
+
 /**
  * __dwc3_gadget_ep_enable - initializes a hw endpoint
  * @dep: endpoint to be initialized
@@ -648,6 +829,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
        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;
@@ -2508,6 +2693,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
 
        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);
@@ -2595,6 +2781,51 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
        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);
@@ -2616,6 +2847,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
        .udc_set_ssp_rate       = dwc3_gadget_set_ssp_rate,
        .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,
 };
 
@@ -4011,7 +4243,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        }
 
 
-       usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release);
+       usb_initialize_gadget(dwc->sysdev, dwc->gadget, dwc_gadget_release);
        dev                             = &dwc->gadget->dev;
        dev->platform_data              = dwc;
        dwc->gadget->ops                = &dwc3_gadget_ops;