Message ID | 1623923899-16759-4-git-send-email-wcheng@codeaurora.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Re-introduce TX FIFO resize for larger EP bursting | expand |
On Thu, Jun 17, 2021 at 02:58:16AM -0700, Wesley Cheng wrote: > +static int dwc3_gadget_check_config(struct usb_gadget *g, unsigned long ep_map) > +{ > + struct dwc3 *dwc = gadget_to_dwc(g); > + unsigned long in_ep_map; > + int fifo_size = 0; > + int ram1_depth; > + int ep_num; > + > + if (!dwc->do_fifo_resize) > + return 0; > + > + /* Only interested in the IN endpoints */ > + in_ep_map = ep_map >> 16; Wait, this "map" is split up into 16/16 somehow? So it's only 32bits big? Where did you document this map structure? Why is it needed at all, you have the gadget, don't you have access to the full list of endpoints here as well? confused, greg k-h
Hi Wesley, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on usb/usb-testing] [also build test WARNING on robh/for-next v5.13-rc6 next-20210617] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Wesley-Cheng/Re-introduce-TX-FIFO-resize-for-larger-EP-bursting/20210617-180037 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing config: x86_64-randconfig-a011-20210617 (attached as .config) compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 64720f57bea6a6bf033feef4a5751ab9c0c3b401) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install x86_64 cross compiling tool for clang build # apt-get install binutils-x86-64-linux-gnu # https://github.com/0day-ci/linux/commit/94892083cf17e46a29d4ef33a044af04854162e6 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Wesley-Cheng/Re-introduce-TX-FIFO-resize-for-larger-EP-bursting/20210617-180037 git checkout 94892083cf17e46a29d4ef33a044af04854162e6 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): >> drivers/usb/dwc3/gadget.c:671:18: warning: variable 'dep' set but not used [-Wunused-but-set-variable] struct dwc3_ep *dep; ^ 1 warning generated. -- drivers/usb/dwc3/gadget.c:648: warning: Function parameter or member 'mult' not described in 'dwc3_gadget_calc_tx_fifo_size' drivers/usb/dwc3/gadget.c:648: warning: Excess function parameter 'nfifos' description in 'dwc3_gadget_calc_tx_fifo_size' >> drivers/usb/dwc3/gadget.c:670: warning: expecting prototype for dwc3_gadget_clear_tx_fifo_size(). Prototype was for dwc3_gadget_clear_tx_fifos() instead vim +/dep +671 drivers/usb/dwc3/gadget.c 661 662 /** 663 * dwc3_gadget_clear_tx_fifo_size - Clears txfifo allocation 664 * @dwc: pointer to the DWC3 context 665 * 666 * Iterates through all the endpoint registers and clears the previous txfifo 667 * allocations. 668 */ 669 void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) > 670 { > 671 struct dwc3_ep *dep; 672 int fifo_depth; 673 int size; 674 int num; 675 676 if (!dwc->do_fifo_resize) 677 return; 678 679 /* Read ep0IN related TXFIFO size */ 680 dep = dwc->eps[1]; 681 size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); 682 if (DWC3_IP_IS(DWC3)) 683 fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size); 684 else 685 fifo_depth = DWC31_GTXFIFOSIZ_TXFDEP(size); 686 687 dwc->last_fifo_depth = fifo_depth; 688 /* Clear existing TXFIFO for all IN eps except ep0 */ 689 for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); 690 num += 2) { 691 dep = dwc->eps[num]; 692 /* Don't change TXFRAMNUM on usb31 version */ 693 size = DWC3_IP_IS(DWC3) ? 0 : 694 dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & 695 DWC31_GTXFIFOSIZ_TXFRAMNUM; 696 697 dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); 698 } 699 dwc->num_ep_resized = 0; 700 } 701 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Wesley, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on usb/usb-testing] [also build test WARNING on robh/for-next v5.13-rc6 next-20210617] [cannot apply to balbi-usb/testing/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Wesley-Cheng/Re-introduce-TX-FIFO-resize-for-larger-EP-bursting/20210617-180037 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing config: m68k-allmodconfig (attached as .config) compiler: m68k-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/94892083cf17e46a29d4ef33a044af04854162e6 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Wesley-Cheng/Re-introduce-TX-FIFO-resize-for-larger-EP-bursting/20210617-180037 git checkout 94892083cf17e46a29d4ef33a044af04854162e6 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): drivers/usb/dwc3/gadget.c: In function 'dwc3_gadget_clear_tx_fifos': >> drivers/usb/dwc3/gadget.c:671:18: warning: variable 'dep' set but not used [-Wunused-but-set-variable] 671 | struct dwc3_ep *dep; | ^~~ -- drivers/usb/dwc3/gadget.c:648: warning: Function parameter or member 'mult' not described in 'dwc3_gadget_calc_tx_fifo_size' drivers/usb/dwc3/gadget.c:648: warning: Excess function parameter 'nfifos' description in 'dwc3_gadget_calc_tx_fifo_size' >> drivers/usb/dwc3/gadget.c:670: warning: expecting prototype for dwc3_gadget_clear_tx_fifo_size(). Prototype was for dwc3_gadget_clear_tx_fifos() instead vim +/dep +671 drivers/usb/dwc3/gadget.c 661 662 /** 663 * dwc3_gadget_clear_tx_fifo_size - Clears txfifo allocation 664 * @dwc: pointer to the DWC3 context 665 * 666 * Iterates through all the endpoint registers and clears the previous txfifo 667 * allocations. 668 */ 669 void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) > 670 { > 671 struct dwc3_ep *dep; 672 int fifo_depth; 673 int size; 674 int num; 675 676 if (!dwc->do_fifo_resize) 677 return; 678 679 /* Read ep0IN related TXFIFO size */ 680 dep = dwc->eps[1]; 681 size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); 682 if (DWC3_IP_IS(DWC3)) 683 fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size); 684 else 685 fifo_depth = DWC31_GTXFIFOSIZ_TXFDEP(size); 686 687 dwc->last_fifo_depth = fifo_depth; 688 /* Clear existing TXFIFO for all IN eps except ep0 */ 689 for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); 690 num += 2) { 691 dep = dwc->eps[num]; 692 /* Don't change TXFRAMNUM on usb31 version */ 693 size = DWC3_IP_IS(DWC3) ? 0 : 694 dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & 695 DWC31_GTXFIFOSIZ_TXFRAMNUM; 696 697 dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); 698 } 699 dwc->num_ep_resized = 0; 700 } 701 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 6/17/2021 4:10 AM, Greg KH wrote: > On Thu, Jun 17, 2021 at 02:58:16AM -0700, Wesley Cheng wrote: >> +static int dwc3_gadget_check_config(struct usb_gadget *g, unsigned long ep_map) >> +{ >> + struct dwc3 *dwc = gadget_to_dwc(g); >> + unsigned long in_ep_map; >> + int fifo_size = 0; >> + int ram1_depth; >> + int ep_num; >> + >> + if (!dwc->do_fifo_resize) >> + return 0; >> + >> + /* Only interested in the IN endpoints */ >> + in_ep_map = ep_map >> 16; Hi Greg, > > Wait, this "map" is split up into 16/16 somehow? So it's only 32bits > big? > Yes, correct. Upper 16 carries IN eps, lower 16 carries OUT eps. Will fix that based off your other comment. > Where did you document this map structure? Why is it needed at all, you > have the gadget, don't you have access to the full list of endpoints > here as well? > > confused, > Unfortunately, we do not have the entire list of endpoints for each function until the composite driver receives the SET_CONFIG packet from the host. By this time, if we incorrectly allowed the configuration to start enumeration w/ the host, and there were some EPs which have no FIFO memory allocated, that would lead to those interfaces/functions being broken. The USB UDC driver does have the in_epnum and out_epnum, but those are currently only being incremented in case we don't match EPs by string. (in usb_ep_autoconfig_ss()) Thanks Wesley Cheng > greg k-h >
On Mon, Jun 21, 2021 at 10:27:13PM -0700, Wesley Cheng wrote: > > > On 6/17/2021 4:10 AM, Greg KH wrote: > > On Thu, Jun 17, 2021 at 02:58:16AM -0700, Wesley Cheng wrote: > >> +static int dwc3_gadget_check_config(struct usb_gadget *g, unsigned long ep_map) > >> +{ > >> + struct dwc3 *dwc = gadget_to_dwc(g); > >> + unsigned long in_ep_map; > >> + int fifo_size = 0; > >> + int ram1_depth; > >> + int ep_num; > >> + > >> + if (!dwc->do_fifo_resize) > >> + return 0; > >> + > >> + /* Only interested in the IN endpoints */ > >> + in_ep_map = ep_map >> 16; > > Hi Greg, > > > > > Wait, this "map" is split up into 16/16 somehow? So it's only 32bits > > big? > > > > Yes, correct. Upper 16 carries IN eps, lower 16 carries OUT eps. Will > fix that based off your other comment. > > > Where did you document this map structure? Why is it needed at all, you > > have the gadget, don't you have access to the full list of endpoints > > here as well? > > > > confused, > > > > Unfortunately, we do not have the entire list of endpoints for each > function until the composite driver receives the SET_CONFIG packet from > the host. By this time, if we incorrectly allowed the configuration to > start enumeration w/ the host, and there were some EPs which have no > FIFO memory allocated, that would lead to those interfaces/functions > being broken. So how would this magic bitmap be any different here? I'm not understanding why you need to create something new here to represent data we already have. thanks, greg k-h
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e0a8e79..a7bcdb9d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1267,6 +1267,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) u8 rx_max_burst_prd; u8 tx_thr_num_pkt_prd; u8 tx_max_burst_prd; + u8 tx_fifo_resize_max_num; const char *usb_psy_name; int ret; @@ -1282,6 +1283,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) */ hird_threshold = 12; + tx_fifo_resize_max_num = 6; + dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = usb_get_dr_mode(dev); @@ -1325,6 +1328,10 @@ static void dwc3_get_properties(struct dwc3 *dwc) &tx_thr_num_pkt_prd); device_property_read_u8(dev, "snps,tx-max-burst-prd", &tx_max_burst_prd); + dwc->do_fifo_resize = device_property_read_bool(dev, + "tx-fifo-resize"); + device_property_read_u8(dev, "tx-fifo-max-num", + &tx_fifo_resize_max_num); dwc->disable_scramble_quirk = device_property_read_bool(dev, "snps,disable_scramble_quirk"); @@ -1390,6 +1397,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->tx_max_burst_prd = tx_max_burst_prd; dwc->imod_interval = 0; + + dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; } /* check whether the core supports IMOD */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index dccdf13..dd985ba 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1023,6 +1023,7 @@ struct dwc3_scratchpad_array { * @rx_max_burst_prd: max periodic ESS receive burst size * @tx_thr_num_pkt_prd: periodic ESS transmit packet count * @tx_max_burst_prd: max periodic ESS transmit burst size + * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise * @delayed_status: true when gadget driver asks for delayed status @@ -1079,6 +1080,11 @@ struct dwc3_scratchpad_array { * @dis_split_quirk: set to disable split boundary. * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. + * @max_cfg_eps: current max number of IN eps used across all USB configs. + * @last_fifo_depth: last fifo depth used to determine next fifo ram start + * address. + * @num_ep_resized: carries the current number endpoints which have had its tx + * fifo resized. */ struct dwc3 { struct work_struct drd_work; @@ -1233,6 +1239,7 @@ struct dwc3 { u8 rx_max_burst_prd; u8 tx_thr_num_pkt_prd; u8 tx_max_burst_prd; + u8 tx_fifo_resize_max_num; const char *hsphy_interface; @@ -1246,6 +1253,7 @@ struct dwc3 { unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; unsigned pending_events:1; + unsigned do_fifo_resize:1; unsigned pullups_connected:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; @@ -1281,6 +1289,10 @@ struct dwc3 { unsigned dis_split_quirk:1; u16 imod_interval; + + int max_cfg_eps; + int last_fifo_depth; + int num_ep_resized; }; #define INCRX_BURST_MODE 0 @@ -1512,6 +1524,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, u32 param); +void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } @@ -1531,6 +1544,8 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } +static inline void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) +{ } #endif #if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3cd2942..d28d085 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -619,6 +619,8 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; case USB_STATE_ADDRESS: + dwc3_gadget_clear_tx_fifos(dwc); + 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))) { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index af6d7f1..8855481a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -632,6 +632,179 @@ 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: + * + * 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; + + 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 + * + * Conversions can be done to the equation to derive the number of packets that + * will fit to a particular FIFO size value. + */ +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 * @action: one of INIT, MODIFY or RESTORE @@ -648,6 +821,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; @@ -2498,6 +2675,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); @@ -2585,6 +2763,39 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) return ret; } +static int dwc3_gadget_check_config(struct usb_gadget *g, unsigned long ep_map) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long in_ep_map; + int fifo_size = 0; + int ram1_depth; + int ep_num; + + if (!dwc->do_fifo_resize) + return 0; + + /* Only interested in the IN endpoints */ + in_ep_map = ep_map >> 16; + ep_num = hweight_long(in_ep_map); + + 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 const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, @@ -2596,6 +2807,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, }; /* -------------------------------------------------------------------------- */
Some devices have USB compositions which may require multiple endpoints that support EP bursting. HW defined TX FIFO sizes may not always be sufficient for these compositions. By utilizing flexible TX FIFO allocation, this allows for endpoints to request the required FIFO depth to achieve higher bandwidth. With some higher bMaxBurst configurations, using a larger TX FIFO size results in better TX throughput. By introducing the check_config() callback, the resizing logic can fetch the maximum number of endpoints used in the USB composition (can contain multiple configurations), which helps ensure that the resizing logic can fulfill the configuration(s), or return an error to the gadget layer otherwise during bind time. Signed-off-by: Wesley Cheng <wcheng@codeaurora.org> --- drivers/usb/dwc3/core.c | 9 ++ drivers/usb/dwc3/core.h | 15 ++++ drivers/usb/dwc3/ep0.c | 2 + drivers/usb/dwc3/gadget.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+)