diff mbox series

usb: dwc3: gadget: Add TxFIFO resizing supports for single port RAM

Message ID 20241107104040.502-1-selvarasu.g@samsung.com (mailing list archive)
State Superseded
Headers show
Series usb: dwc3: gadget: Add TxFIFO resizing supports for single port RAM | expand

Commit Message

Selvarasu Ganesan Nov. 7, 2024, 10:40 a.m. UTC
This commit adds support for resizing the TxFIFO in USB2.0-only mode
where using single port RAM, and limit the use of extra FIFOs for bulk
transfers in non-SS mode. It prevents the issue of limited RAM size
usage.

Fixes: fad16c823e66 ("usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs")
Cc: stable@vger.kernel.org # 6.12.x: fad16c82: usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs
Signed-off-by: Selvarasu Ganesan <selvarasu.g@samsung.com>
---
 drivers/usb/dwc3/core.h   |  4 +++
 drivers/usb/dwc3/gadget.c | 56 ++++++++++++++++++++++++++++++---------
 2 files changed, 48 insertions(+), 12 deletions(-)

Comments

Thinh Nguyen Nov. 7, 2024, 11:34 p.m. UTC | #1
On Thu, Nov 07, 2024, Selvarasu Ganesan wrote:
> This commit adds support for resizing the TxFIFO in USB2.0-only mode
> where using single port RAM, and limit the use of extra FIFOs for bulk

This should be split into 2 changes: 1 for adding support for
single-port RAM, and the other for budgeting the bulk fifo setting.

The first change is not a fix, and the latter may be a fix (may need
more feedback from others).

> transfers in non-SS mode. It prevents the issue of limited RAM size
> usage.
> 
> Fixes: fad16c823e66 ("usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs")
> Cc: stable@vger.kernel.org # 6.12.x: fad16c82: usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs
> Signed-off-by: Selvarasu Ganesan <selvarasu.g@samsung.com>
> ---
>  drivers/usb/dwc3/core.h   |  4 +++
>  drivers/usb/dwc3/gadget.c | 56 ++++++++++++++++++++++++++++++---------
>  2 files changed, 48 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index eaa55c0cf62f..8306b39e5c64 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -915,6 +915,7 @@ struct dwc3_hwparams {
>  #define DWC3_MODE(n)		((n) & 0x7)
>  
>  /* HWPARAMS1 */
> +#define DWC3_SPRAM_TYPE(n)	(((n) >> 23) & 1)
>  #define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
>  
>  /* HWPARAMS3 */
> @@ -925,6 +926,9 @@ struct dwc3_hwparams {
>  #define DWC3_NUM_IN_EPS(p)	(((p)->hwparams3 &		\
>  			(DWC3_NUM_IN_EPS_MASK)) >> 18)
>  
> +/* HWPARAMS6 */
> +#define DWC3_RAM0_DEPTH(n)	(((n) & (0xffff0000)) >> 16)
> +
>  /* HWPARAMS7 */
>  #define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
>  
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index 2fed2aa01407..d3e25f7d7cd0 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -687,6 +687,42 @@ static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)
>  	return fifo_size;
>  }
>  
> +/**
> + * dwc3_gadget_calc_ram_depth - calculates the ram depth for txfifo
> + * @dwc: pointer to the DWC3 context
> + */
> +static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)
> +{
> +	int ram_depth;
> +	int fifo_0_start;
> +	bool spram_type;
> +	int tmp;
> +
> +	/* Check supporting RAM type by HW */
> +	spram_type = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1);
> +
> +	/* If a single port RAM is utilized, then allocate TxFIFOs from
> +	 * RAM0. otherwise, allocate them from RAM1.
> +	 */

Please use this comment block style
/*
 * xxxx
 * xxxx
 */

> +	ram_depth = spram_type ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
> +			DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);

Don't use spram_type as a boolean. Perhaps define a macro for type value
1 and 0 (for single vs 2-port)

> +
> +
> +	/* In a single port RAM configuration, the available RAM is shared
> +	 * between the RX and TX FIFOs. This means that the txfifo can begin
> +	 * at a non-zero address.
> +	 */
> +	if (spram_type) {

if (spram_type == DWC3_SPRAM_TYPE_SINGLE) {
	...
}

> +		/* Check if TXFIFOs start at non-zero addr */
> +		tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
> +		fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);
> +
> +		ram_depth -= (fifo_0_start >> 16);
> +	}
> +
> +	return ram_depth;
> +}
> +
>  /**
>   * dwc3_gadget_clear_tx_fifos - Clears txfifo allocation
>   * @dwc: pointer to the DWC3 context
> @@ -753,7 +789,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>  {
>  	struct dwc3 *dwc = dep->dwc;
>  	int fifo_0_start;
> -	int ram1_depth;
> +	int ram_depth;
>  	int fifo_size;
>  	int min_depth;
>  	int num_in_ep;
> @@ -773,7 +809,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>  	if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
>  		return 0;
>  
> -	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
> +	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
>  
>  	switch (dwc->gadget->speed) {
>  	case USB_SPEED_SUPER_PLUS:
> @@ -792,10 +828,6 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>  			break;
>  		}
>  		fallthrough;
> -	case USB_SPEED_FULL:
> -		if (usb_endpoint_xfer_bulk(dep->endpoint.desc))
> -			num_fifos = 2;
> -		break;

Please take out the fallthrough above if you remove this condition.

>  	default:
>  		break;
>  	}
> @@ -809,7 +841,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>  
>  	/* 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 = ram_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
> @@ -835,9 +867,9 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>  		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) {
> +	if (dwc->last_fifo_depth >= ram_depth) {
>  		dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
> -			dwc->last_fifo_depth, ram1_depth,
> +			dwc->last_fifo_depth, ram_depth,
>  			dep->endpoint.name, fifo_size);
>  		if (DWC3_IP_IS(DWC3))
>  			fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
> @@ -3090,7 +3122,7 @@ 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 ram_depth;
>  	int ep_num = 0;
>  
>  	if (!dwc->do_fifo_resize)
> @@ -3113,8 +3145,8 @@ static int dwc3_gadget_check_config(struct usb_gadget *g)
>  	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)
> +	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
> +	if (fifo_size > ram_depth)
>  		return -ENOMEM;
>  
>  	return 0;
> -- 
> 2.17.1
> 

We may need to think a little more on how to budgeting the resource
properly to accomodate for different requirements. If there's no single
formula to satisfy for all platform, perhaps we may need to introduce
parameters that users can set base on the needs of their application.

I'd like to Ack on the new change that checks single-port RAM. For the
budgeting of fifo, let's keep the discussion going a little more.

Thanks,
Thinh
Selvarasu Ganesan Nov. 8, 2024, 4:54 a.m. UTC | #2
On 11/8/2024 5:04 AM, Thinh Nguyen wrote:
> On Thu, Nov 07, 2024, Selvarasu Ganesan wrote:
>> This commit adds support for resizing the TxFIFO in USB2.0-only mode
>> where using single port RAM, and limit the use of extra FIFOs for bulk
> This should be split into 2 changes: 1 for adding support for
> single-port RAM, and the other for budgeting the bulk fifo setting.
>
> The first change is not a fix, and the latter may be a fix (may need
> more feedback from others).
Hi Thinh,
Thanks for reviewing.
Sure i will do split into 2 changes.
>> transfers in non-SS mode. It prevents the issue of limited RAM size
>> usage.
>>
>> Fixes: fad16c823e66 ("usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs")
>> Cc: stable@vger.kernel.org # 6.12.x: fad16c82: usb: dwc3: gadget: Refine the logic for resizing Tx FIFOs
>> Signed-off-by: Selvarasu Ganesan <selvarasu.g@samsung.com>
>> ---
>>   drivers/usb/dwc3/core.h   |  4 +++
>>   drivers/usb/dwc3/gadget.c | 56 ++++++++++++++++++++++++++++++---------
>>   2 files changed, 48 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
>> index eaa55c0cf62f..8306b39e5c64 100644
>> --- a/drivers/usb/dwc3/core.h
>> +++ b/drivers/usb/dwc3/core.h
>> @@ -915,6 +915,7 @@ struct dwc3_hwparams {
>>   #define DWC3_MODE(n)		((n) & 0x7)
>>   
>>   /* HWPARAMS1 */
>> +#define DWC3_SPRAM_TYPE(n)	(((n) >> 23) & 1)
>>   #define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
>>   
>>   /* HWPARAMS3 */
>> @@ -925,6 +926,9 @@ struct dwc3_hwparams {
>>   #define DWC3_NUM_IN_EPS(p)	(((p)->hwparams3 &		\
>>   			(DWC3_NUM_IN_EPS_MASK)) >> 18)
>>   
>> +/* HWPARAMS6 */
>> +#define DWC3_RAM0_DEPTH(n)	(((n) & (0xffff0000)) >> 16)
>> +
>>   /* HWPARAMS7 */
>>   #define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
>>   
>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
>> index 2fed2aa01407..d3e25f7d7cd0 100644
>> --- a/drivers/usb/dwc3/gadget.c
>> +++ b/drivers/usb/dwc3/gadget.c
>> @@ -687,6 +687,42 @@ static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)
>>   	return fifo_size;
>>   }
>>   
>> +/**
>> + * dwc3_gadget_calc_ram_depth - calculates the ram depth for txfifo
>> + * @dwc: pointer to the DWC3 context
>> + */
>> +static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)
>> +{
>> +	int ram_depth;
>> +	int fifo_0_start;
>> +	bool spram_type;
>> +	int tmp;
>> +
>> +	/* Check supporting RAM type by HW */
>> +	spram_type = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1);
>> +
>> +	/* If a single port RAM is utilized, then allocate TxFIFOs from
>> +	 * RAM0. otherwise, allocate them from RAM1.
>> +	 */
> Please use this comment block style
> /*
>   * xxxx
>   * xxxx
>   */
Sure, will update it in next version.
>> +	ram_depth = spram_type ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
>> +			DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
> Don't use spram_type as a boolean. Perhaps define a macro for type value
> 1 and 0 (for single vs 2-port)
Are you expecting something like below?

#define DWC3_SINGLE_PORT_RAM     1
#define DWC3_TW0_PORT_RAM        0

// ...

int ram_depth;
int fifo_0_start;
int spram_type;
int tmp;

/*
* Check supporting RAM type by HW. If a single port RAM
* is utilized, then allocate TxFIFOs from RAM0. otherwise,
* allocate them from RAM1.
*/
spram_type = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1);

/*
* In a single port RAM configuration, the available RAM is shared
* between the RX and TX FIFOs. This means that the txfifo can begin
* at a non-zero address.
*/

if (spram_type == DWC3_SINGLE_PORT_RAM) {

     ram_depth = DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6);

     /* Check if TXFIFOs start at non-zero addr */
     tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
     fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);

ram_depth -= (fifo_0_start >> 16);
} else
     ram_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);

return ram_depth;
>> +
>> +
>> +	/* In a single port RAM configuration, the available RAM is shared
>> +	 * between the RX and TX FIFOs. This means that the txfifo can begin
>> +	 * at a non-zero address.
>> +	 */
>> +	if (spram_type) {
> if (spram_type == DWC3_SPRAM_TYPE_SINGLE) {
> 	...
> }
>
>> +		/* Check if TXFIFOs start at non-zero addr */
>> +		tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
>> +		fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);
>> +
>> +		ram_depth -= (fifo_0_start >> 16);
>> +	}
>> +
>> +	return ram_depth;
>> +}
>> +
>>   /**
>>    * dwc3_gadget_clear_tx_fifos - Clears txfifo allocation
>>    * @dwc: pointer to the DWC3 context
>> @@ -753,7 +789,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>>   {
>>   	struct dwc3 *dwc = dep->dwc;
>>   	int fifo_0_start;
>> -	int ram1_depth;
>> +	int ram_depth;
>>   	int fifo_size;
>>   	int min_depth;
>>   	int num_in_ep;
>> @@ -773,7 +809,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>>   	if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
>>   		return 0;
>>   
>> -	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
>> +	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
>>   
>>   	switch (dwc->gadget->speed) {
>>   	case USB_SPEED_SUPER_PLUS:
>> @@ -792,10 +828,6 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>>   			break;
>>   		}
>>   		fallthrough;
>> -	case USB_SPEED_FULL:
>> -		if (usb_endpoint_xfer_bulk(dep->endpoint.desc))
>> -			num_fifos = 2;
>> -		break;
> Please take out the fallthrough above if you remove this condition.
will update it in next version.
>
>>   	default:
>>   		break;
>>   	}
>> @@ -809,7 +841,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>>   
>>   	/* 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 = ram_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
>> @@ -835,9 +867,9 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
>>   		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) {
>> +	if (dwc->last_fifo_depth >= ram_depth) {
>>   		dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
>> -			dwc->last_fifo_depth, ram1_depth,
>> +			dwc->last_fifo_depth, ram_depth,
>>   			dep->endpoint.name, fifo_size);
>>   		if (DWC3_IP_IS(DWC3))
>>   			fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
>> @@ -3090,7 +3122,7 @@ 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 ram_depth;
>>   	int ep_num = 0;
>>   
>>   	if (!dwc->do_fifo_resize)
>> @@ -3113,8 +3145,8 @@ static int dwc3_gadget_check_config(struct usb_gadget *g)
>>   	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)
>> +	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
>> +	if (fifo_size > ram_depth)
>>   		return -ENOMEM;
>>   
>>   	return 0;
>> -- 
>> 2.17.1
>>
> We may need to think a little more on how to budgeting the resource
> properly to accomodate for different requirements. If there's no single
> formula to satisfy for all platform, perhaps we may need to introduce
> parameters that users can set base on the needs of their application.
Agree. Need to introduce some parameters to control the required fifos 
by user that based their usecase.
Here's a rephrased version of your proposal:

To address the issue of determining the required number of FIFOs for 
different types of transfers, we propose introducing dynamic FIFO 
calculation for all type of EP transfers based on the maximum packet 
size, and remove hard code value for required fifos in driver,  
Additionally, we suggest introducing DT properties(tx-fifo-max-num-iso, 
tx-fifo-max-bulk and tx-fifo-max-intr) for all types of transfers 
(except control EP) to allow users to control the required FIFOs instead 
of relying solely on the tx-fifo-max-num. This approach will provide 
more flexibility and customization options for users based on their 
specific use cases.

Please let me know if you have any comments on the above approach.

Thanks,
Selva
>
> I'd like to Ack on the new change that checks single-port RAM. For the
> budgeting of fifo, let's keep the discussion going a little more.
>
> Thanks,
> Thinh
Thinh Nguyen Nov. 9, 2024, 1:05 a.m. UTC | #3
++ Alan Stern

On Fri, Nov 08, 2024, Selvarasu Ganesan wrote:

> >> +	ram_depth = spram_type ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
> >> +			DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
> > Don't use spram_type as a boolean. Perhaps define a macro for type value
> > 1 and 0 (for single vs 2-port)
> Are you expecting something like below?
> 
> #define DWC3_SINGLE_PORT_RAM     1
> #define DWC3_TW0_PORT_RAM        0

Yes. I think it's more readable if we name the variable to "ram_type"
and use the macros above as I suggested.

If you still plan to use it as boolean, please rename the variable
spram_type to is_single_port_ram (no one knows what "spram_type" mean
without the programming guide or some documention).

>

< snip >

> >>
> > We may need to think a little more on how to budgeting the resource
> > properly to accomodate for different requirements. If there's no single
> > formula to satisfy for all platform, perhaps we may need to introduce
> > parameters that users can set base on the needs of their application.

> Agree. Need to introduce some parameters to control the required fifos 
> by user that based their usecase.
> Here's a rephrased version of your proposal:
> 
> To address the issue of determining the required number of FIFOs for 
> different types of transfers, we propose introducing dynamic FIFO 
> calculation for all type of EP transfers based on the maximum packet 
> size, and remove hard code value for required fifos in driver,  

The current fifo calculation already takes on the max packet size into
account.

For SuperSpeed and above, we can guess how much fifo is needed base on
the maxburst and mult settings. However, for bulk endpoint in highspeed,
it needs a bit more checking.

> Additionally, we suggest introducing DT properties(tx-fifo-max-num-iso, 
> tx-fifo-max-bulk and tx-fifo-max-intr) for all types of transfers 

This constraint should be decided from the function driver. We should
try to keep this more generic since your gadget may be used as mass
storage device instead of UVC where bulk performance is needed more.

> (except control EP) to allow users to control the required FIFOs instead 
> of relying solely on the tx-fifo-max-num. This approach will provide 
> more flexibility and customization options for users based on their 
> specific use cases.
> 
> Please let me know if you have any comments on the above approach.
> 

How about this: Implement gadget->ops->match_ep() for dwc3 and update
the note in usb_ep_autoconfig() API.

If the function driver looks for an endpoint by passing in the
descriptor with wMaxPacketSize set to 0, mark the endpoint to used for
performance. This is closely related to the usb_ep_autoconfig() behavior
where it returns the endpoint's maxpacket_limit if wMaxPacketSize is not
provided. We just need to expand this behavior to look for performance
endpoint.

If the function driver provides the wMaxPacketSize during
usb_ep_autoconfig(), then use the minimum required fifo.

What do you think? Will this work for you?

BR,
Thinh
Selvarasu Ganesan Nov. 11, 2024, 2:39 p.m. UTC | #4
On 11/9/2024 6:35 AM, Thinh Nguyen wrote:
> ++ Alan Stern
>
> On Fri, Nov 08, 2024, Selvarasu Ganesan wrote:
>
>>>> +	ram_depth = spram_type ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
>>>> +			DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
>>> Don't use spram_type as a boolean. Perhaps define a macro for type value
>>> 1 and 0 (for single vs 2-port)
>> Are you expecting something like below?
>>
>> #define DWC3_SINGLE_PORT_RAM     1
>> #define DWC3_TW0_PORT_RAM        0
> Yes. I think it's more readable if we name the variable to "ram_type"
> and use the macros above as I suggested.
>
> If you still plan to use it as boolean, please rename the variable
> spram_type to is_single_port_ram (no one knows what "spram_type" mean
> without the programming guide or some documention).

We are fine to use variable name as a is_single_port_ram with boolean.
Please find the below updated new patch for your review.

https://lore.kernel.org/linux-usb/20241111142049.604-1-selvarasu.g@samsung.com/.


> < snip >
>
>>> We may need to think a little more on how to budgeting the resource
>>> properly to accomodate for different requirements. If there's no single
>>> formula to satisfy for all platform, perhaps we may need to introduce
>>> parameters that users can set base on the needs of their application.
>> Agree. Need to introduce some parameters to control the required fifos
>> by user that based their usecase.
>> Here's a rephrased version of your proposal:
>>
>> To address the issue of determining the required number of FIFOs for
>> different types of transfers, we propose introducing dynamic FIFO
>> calculation for all type of EP transfers based on the maximum packet
>> size, and remove hard code value for required fifos in driver,
> The current fifo calculation already takes on the max packet size into
> account.
>
> For SuperSpeed and above, we can guess how much fifo is needed base on
> the maxburst and mult settings. However, for bulk endpoint in highspeed,
> it needs a bit more checking.
Agree.
>
>> Additionally, we suggest introducing DT properties(tx-fifo-max-num-iso,
>> tx-fifo-max-bulk and tx-fifo-max-intr) for all types of transfers
> This constraint should be decided from the function driver. We should
> try to keep this more generic since your gadget may be used as mass
> storage device instead of UVC where bulk performance is needed more.
Agree.
>
>> (except control EP) to allow users to control the required FIFOs instead
>> of relying solely on the tx-fifo-max-num. This approach will provide
>> more flexibility and customization options for users based on their
>> specific use cases.
>>
>> Please let me know if you have any comments on the above approach.
>>
> How about this: Implement gadget->ops->match_ep() for dwc3 and update
> the note in usb_ep_autoconfig() API.
>
> If the function driver looks for an endpoint by passing in the
> descriptor with wMaxPacketSize set to 0, mark the endpoint to used for
> performance. This is closely related to the usb_ep_autoconfig() behavior
> where it returns the endpoint's maxpacket_limit if wMaxPacketSize is not
> provided. We just need to expand this behavior to look for performance
> endpoint.
>
> If the function driver provides the wMaxPacketSize during
> usb_ep_autoconfig(), then use the minimum required fifo.
>
> What do you think? Will this work for you?


Hi  Thinh,

Thank you for the suggestions. This method makes more sense to us, and 
we are fine proceeding with it. As we previously discussed, we plan to 
create a separate patch for allocating resources for bulk EP.
However, it may take some time on our end as we need to perform 
additional testing with all possible scenarios. In the meantime, please 
review and help to merge the patch for the single port RAM FIFO resizing 
logic.

Thanks,
Selva

>
> BR,
> Thinh
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index eaa55c0cf62f..8306b39e5c64 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -915,6 +915,7 @@  struct dwc3_hwparams {
 #define DWC3_MODE(n)		((n) & 0x7)
 
 /* HWPARAMS1 */
+#define DWC3_SPRAM_TYPE(n)	(((n) >> 23) & 1)
 #define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
 
 /* HWPARAMS3 */
@@ -925,6 +926,9 @@  struct dwc3_hwparams {
 #define DWC3_NUM_IN_EPS(p)	(((p)->hwparams3 &		\
 			(DWC3_NUM_IN_EPS_MASK)) >> 18)
 
+/* HWPARAMS6 */
+#define DWC3_RAM0_DEPTH(n)	(((n) & (0xffff0000)) >> 16)
+
 /* HWPARAMS7 */
 #define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2fed2aa01407..d3e25f7d7cd0 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -687,6 +687,42 @@  static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)
 	return fifo_size;
 }
 
+/**
+ * dwc3_gadget_calc_ram_depth - calculates the ram depth for txfifo
+ * @dwc: pointer to the DWC3 context
+ */
+static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)
+{
+	int ram_depth;
+	int fifo_0_start;
+	bool spram_type;
+	int tmp;
+
+	/* Check supporting RAM type by HW */
+	spram_type = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1);
+
+	/* If a single port RAM is utilized, then allocate TxFIFOs from
+	 * RAM0. otherwise, allocate them from RAM1.
+	 */
+	ram_depth = spram_type ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
+			DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+
+
+	/* In a single port RAM configuration, the available RAM is shared
+	 * between the RX and TX FIFOs. This means that the txfifo can begin
+	 * at a non-zero address.
+	 */
+	if (spram_type) {
+		/* Check if TXFIFOs start at non-zero addr */
+		tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
+		fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);
+
+		ram_depth -= (fifo_0_start >> 16);
+	}
+
+	return ram_depth;
+}
+
 /**
  * dwc3_gadget_clear_tx_fifos - Clears txfifo allocation
  * @dwc: pointer to the DWC3 context
@@ -753,7 +789,7 @@  static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
 {
 	struct dwc3 *dwc = dep->dwc;
 	int fifo_0_start;
-	int ram1_depth;
+	int ram_depth;
 	int fifo_size;
 	int min_depth;
 	int num_in_ep;
@@ -773,7 +809,7 @@  static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
 	if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
 		return 0;
 
-	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
 
 	switch (dwc->gadget->speed) {
 	case USB_SPEED_SUPER_PLUS:
@@ -792,10 +828,6 @@  static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
 			break;
 		}
 		fallthrough;
-	case USB_SPEED_FULL:
-		if (usb_endpoint_xfer_bulk(dep->endpoint.desc))
-			num_fifos = 2;
-		break;
 	default:
 		break;
 	}
@@ -809,7 +841,7 @@  static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
 
 	/* 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 = ram_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
@@ -835,9 +867,9 @@  static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
 		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) {
+	if (dwc->last_fifo_depth >= ram_depth) {
 		dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
-			dwc->last_fifo_depth, ram1_depth,
+			dwc->last_fifo_depth, ram_depth,
 			dep->endpoint.name, fifo_size);
 		if (DWC3_IP_IS(DWC3))
 			fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
@@ -3090,7 +3122,7 @@  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 ram_depth;
 	int ep_num = 0;
 
 	if (!dwc->do_fifo_resize)
@@ -3113,8 +3145,8 @@  static int dwc3_gadget_check_config(struct usb_gadget *g)
 	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)
+	ram_depth = dwc3_gadget_calc_ram_depth(dwc);
+	if (fifo_size > ram_depth)
 		return -ENOMEM;
 
 	return 0;