Merge 5.14-rc5 into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Aug 2021 06:12:09 +0000 (08:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Aug 2021 06:12:09 +0000 (08:12 +0200)
We need the usb fixes in here as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1  2 
drivers/usb/dwc3/gadget.c

@@@ -631,187 -631,6 +631,187 @@@ static int dwc3_gadget_set_ep_config(st
  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
@@@ -829,10 -648,6 +829,10 @@@ static int __dwc3_gadget_ep_enable(stru
        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;
@@@ -1926,9 -1741,13 +1926,13 @@@ static void dwc3_gadget_ep_cleanup_canc
  {
        struct dwc3_request             *req;
        struct dwc3_request             *tmp;
+       struct list_head                local;
        struct dwc3                     *dwc = dep->dwc;
  
-       list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) {
+ restart:
+       list_replace_init(&dep->cancelled_list, &local);
+       list_for_each_entry_safe(req, tmp, &local, list) {
                dwc3_gadget_ep_skip_trbs(dep, req);
                switch (req->status) {
                case DWC3_REQUEST_STATUS_DISCONNECTED:
                        break;
                }
        }
+       if (!list_empty(&dep->cancelled_list))
+               goto restart;
  }
  
  static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
@@@ -2434,6 -2256,17 +2441,17 @@@ static int dwc3_gadget_pullup(struct us
                }
        }
  
+       /*
+        * Avoid issuing a runtime resume if the device is already in the
+        * suspended state during gadget disconnect.  DWC3 gadget was already
+        * halted/stopped during runtime suspend.
+        */
+       if (!is_on) {
+               pm_runtime_barrier(dwc->dev);
+               if (pm_runtime_suspended(dwc->dev))
+                       return 0;
+       }
        /*
         * Check the return value for successful resume, or error.  For a
         * successful resume, the DWC3 runtime PM resume routine will handle
@@@ -2683,7 -2516,6 +2701,7 @@@ static int dwc3_gadget_stop(struct usb_
  
        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);
@@@ -2771,51 -2603,6 +2789,51 @@@ static int dwc3_gadget_vbus_draw(struc
        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);
@@@ -2837,7 -2624,6 +2855,7 @@@ static const struct usb_gadget_ops dwc3
        .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,
  };
  
@@@ -3190,8 -2976,12 +3208,12 @@@ static void dwc3_gadget_ep_cleanup_comp
  {
        struct dwc3_request     *req;
        struct dwc3_request     *tmp;
+       struct list_head        local;
  
-       list_for_each_entry_safe(req, tmp, &dep->started_list, list) {
+ restart:
+       list_replace_init(&dep->started_list, &local);
+       list_for_each_entry_safe(req, tmp, &local, list) {
                int ret;
  
                ret = dwc3_gadget_ep_cleanup_completed_request(dep, event,
                if (ret)
                        break;
        }
+       if (!list_empty(&dep->started_list))
+               goto restart;
  }
  
  static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep)
@@@ -4233,7 -4026,7 +4258,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;