diff mbox

[5/7] net: stmmac: Program RX queue size and flow control

Message ID 20170223172438.14770-6-thierry.reding@gmail.com
State Deferred, archived
Delegated to: David Miller
Headers show

Commit Message

Thierry Reding Feb. 23, 2017, 5:24 p.m. UTC
From: Thierry Reding <treding@nvidia.com>

Program the receive queue size based on the RX FIFO size and enable
hardware flow control for large FIFOs.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac4.h     | 12 +++++++
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 43 ++++++++++++++++++++++--
 2 files changed, 53 insertions(+), 2 deletions(-)

Comments

Mikko Perttunen Feb. 27, 2017, 10:09 a.m. UTC | #1
On 23.02.2017 19:24, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Program the receive queue size based on the RX FIFO size and enable
> hardware flow control for large FIFOs.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/dwmac4.h     | 12 +++++++
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 43 ++++++++++++++++++++++--
>  2 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> index db45134fddf0..9acc1f1252b3 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> @@ -180,6 +180,7 @@ enum power_event {
>  #define MTL_OP_MODE_TSF			BIT(1)
>
>  #define MTL_OP_MODE_TQS_MASK		GENMASK(24, 16)
> +#define MTL_OP_MODE_TQS_SHIFT		16
>
>  #define MTL_OP_MODE_TTC_MASK		0x70
>  #define MTL_OP_MODE_TTC_SHIFT		4
> @@ -193,6 +194,17 @@ enum power_event {
>  #define MTL_OP_MODE_TTC_384		(6 << MTL_OP_MODE_TTC_SHIFT)
>  #define MTL_OP_MODE_TTC_512		(7 << MTL_OP_MODE_TTC_SHIFT)
>
> +#define MTL_OP_MODE_RQS_MASK		GENMASK(29, 20)
> +#define MTL_OP_MODE_RQS_SHIFT		20
> +
> +#define MTL_OP_MODE_RFD_MASK		GENMASK(19, 14)
> +#define MTL_OP_MODE_RFD_SHIFT		14
> +
> +#define MTL_OP_MODE_RFA_MASK		GENMASK(13, 8)
> +#define MTL_OP_MODE_RFA_SHIFT		8
> +
> +#define MTL_OP_MODE_EHFC		BIT(7)
> +
>  #define MTL_OP_MODE_RTC_MASK		0x18
>  #define MTL_OP_MODE_RTC_SHIFT		3
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> index 8d249f3b34c8..03d230201960 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> @@ -185,8 +185,9 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
>  }
>
>  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> -				    int rxmode, u32 channel)
> +				    int rxmode, u32 channel, int rxfifosz)
>  {
> +	unsigned int rqs = rxfifosz / 256 - 1;
>  	u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
>
>  	/* Following code only done for channel 0, other channels not yet
> @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
>  	}
>
> +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
> +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
> +
> +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
> +	if (rxfifosz >= 4096) {
> +		unsigned int rfd, rfa;
> +
> +		mtl_rx_op |= MTL_OP_MODE_EHFC;
> +
> +		switch (rxfifosz) {
> +		case 4096:
> +			rfd = 0x03;
> +			rfa = 0x01;
> +			break;
> +
> +		case 8192:
> +			rfd = 0x06;
> +			rfa = 0x0a;
> +			break;
> +
> +		case 16384:
> +			rfd = 0x06;
> +			rfa = 0x12;
> +			break;
> +
> +		default:
> +			rfd = 0x06;
> +			rfa = 0x1e;
> +			break;
> +		}

Are these values correct? In the 4096 case, rfd > rfa, in all other 
cases the other way around. In any case it would be useful to have a 
comment clarifying the thresholds in bytes.

> +
> +		mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
> +		mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
> +
> +		mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
> +		mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
> +	}
> +
>  	writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
>
>  	/* Enable MTL RX overflow */
> @@ -264,7 +303,7 @@ static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
>  				      int rxmode, int rxfifosz)
>  {
>  	/* Only Channel 0 is actually configured and used */
> -	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
> +	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
>  }
>
>  static void dwmac4_get_hw_feature(void __iomem *ioaddr,
>
Joao Pinto March 2, 2017, 3:15 p.m. UTC | #2
Às 5:24 PM de 2/23/2017, Thierry Reding escreveu:
> From: Thierry Reding <treding@nvidia.com>
> 
> Program the receive queue size based on the RX FIFO size and enable
> hardware flow control for large FIFOs.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/dwmac4.h     | 12 +++++++
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 43 ++++++++++++++++++++++--
>  2 files changed, 53 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> index db45134fddf0..9acc1f1252b3 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> @@ -180,6 +180,7 @@ enum power_event {
>  #define MTL_OP_MODE_TSF			BIT(1)
>  
>  #define MTL_OP_MODE_TQS_MASK		GENMASK(24, 16)
> +#define MTL_OP_MODE_TQS_SHIFT		16
>  
>  #define MTL_OP_MODE_TTC_MASK		0x70
>  #define MTL_OP_MODE_TTC_SHIFT		4
> @@ -193,6 +194,17 @@ enum power_event {
>  #define MTL_OP_MODE_TTC_384		(6 << MTL_OP_MODE_TTC_SHIFT)
>  #define MTL_OP_MODE_TTC_512		(7 << MTL_OP_MODE_TTC_SHIFT)
>  
> +#define MTL_OP_MODE_RQS_MASK		GENMASK(29, 20)
> +#define MTL_OP_MODE_RQS_SHIFT		20
> +
> +#define MTL_OP_MODE_RFD_MASK		GENMASK(19, 14)
> +#define MTL_OP_MODE_RFD_SHIFT		14
> +
> +#define MTL_OP_MODE_RFA_MASK		GENMASK(13, 8)
> +#define MTL_OP_MODE_RFA_SHIFT		8
> +
> +#define MTL_OP_MODE_EHFC		BIT(7)
> +
>  #define MTL_OP_MODE_RTC_MASK		0x18
>  #define MTL_OP_MODE_RTC_SHIFT		3
>  
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> index 8d249f3b34c8..03d230201960 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> @@ -185,8 +185,9 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
>  }
>  
>  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> -				    int rxmode, u32 channel)
> +				    int rxmode, u32 channel, int rxfifosz)
>  {
> +	unsigned int rqs = rxfifosz / 256 - 1;
>  	u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
>  
>  	/* Following code only done for channel 0, other channels not yet
> @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
>  	}
>  
> +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
> +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
> +
> +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
> +	if (rxfifosz >= 4096) {
> +		unsigned int rfd, rfa;
> +
> +		mtl_rx_op |= MTL_OP_MODE_EHFC;
> +
> +		switch (rxfifosz) {
> +		case 4096:
> +			rfd = 0x03;
> +			rfa = 0x01;
> +			break;
> +
> +		case 8192:
> +			rfd = 0x06;
> +			rfa = 0x0a;
> +			break;
> +
> +		case 16384:
> +			rfd = 0x06;
> +			rfa = 0x12;
> +			break;
> +
> +		default:
> +			rfd = 0x06;
> +			rfa = 0x1e;
> +			break;
> +		}

Are these RFA and RFD values suitable to any setup using thresholds? Please
justify their values in oerder for other developers to understand them.

> +
> +		mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
> +		mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
> +
> +		mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
> +		mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
> +	}
> +
>  	writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
>  
>  	/* Enable MTL RX overflow */
> @@ -264,7 +303,7 @@ static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
>  				      int rxmode, int rxfifosz)
>  {
>  	/* Only Channel 0 is actually configured and used */
> -	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
> +	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);

Why not configure tx fifo as well, you already getting it from the features
register.

>  }
>  
>  static void dwmac4_get_hw_feature(void __iomem *ioaddr,
> 

Thanks.
Thierry Reding March 9, 2017, 7:42 p.m. UTC | #3
On Mon, Feb 27, 2017 at 12:09:02PM +0200, Mikko Perttunen wrote:
> On 23.02.2017 19:24, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Program the receive queue size based on the RX FIFO size and enable
> > hardware flow control for large FIFOs.
> > 
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> >  drivers/net/ethernet/stmicro/stmmac/dwmac4.h     | 12 +++++++
> >  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 43 ++++++++++++++++++++++--
> >  2 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > index db45134fddf0..9acc1f1252b3 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > @@ -180,6 +180,7 @@ enum power_event {
> >  #define MTL_OP_MODE_TSF			BIT(1)
> > 
> >  #define MTL_OP_MODE_TQS_MASK		GENMASK(24, 16)
> > +#define MTL_OP_MODE_TQS_SHIFT		16
> > 
> >  #define MTL_OP_MODE_TTC_MASK		0x70
> >  #define MTL_OP_MODE_TTC_SHIFT		4
> > @@ -193,6 +194,17 @@ enum power_event {
> >  #define MTL_OP_MODE_TTC_384		(6 << MTL_OP_MODE_TTC_SHIFT)
> >  #define MTL_OP_MODE_TTC_512		(7 << MTL_OP_MODE_TTC_SHIFT)
> > 
> > +#define MTL_OP_MODE_RQS_MASK		GENMASK(29, 20)
> > +#define MTL_OP_MODE_RQS_SHIFT		20
> > +
> > +#define MTL_OP_MODE_RFD_MASK		GENMASK(19, 14)
> > +#define MTL_OP_MODE_RFD_SHIFT		14
> > +
> > +#define MTL_OP_MODE_RFA_MASK		GENMASK(13, 8)
> > +#define MTL_OP_MODE_RFA_SHIFT		8
> > +
> > +#define MTL_OP_MODE_EHFC		BIT(7)
> > +
> >  #define MTL_OP_MODE_RTC_MASK		0x18
> >  #define MTL_OP_MODE_RTC_SHIFT		3
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > index 8d249f3b34c8..03d230201960 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > @@ -185,8 +185,9 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
> >  }
> > 
> >  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> > -				    int rxmode, u32 channel)
> > +				    int rxmode, u32 channel, int rxfifosz)
> >  {
> > +	unsigned int rqs = rxfifosz / 256 - 1;
> >  	u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
> > 
> >  	/* Following code only done for channel 0, other channels not yet
> > @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> >  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
> >  	}
> > 
> > +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
> > +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
> > +
> > +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
> > +	if (rxfifosz >= 4096) {
> > +		unsigned int rfd, rfa;
> > +
> > +		mtl_rx_op |= MTL_OP_MODE_EHFC;
> > +
> > +		switch (rxfifosz) {
> > +		case 4096:
> > +			rfd = 0x03;
> > +			rfa = 0x01;
> > +			break;
> > +
> > +		case 8192:
> > +			rfd = 0x06;
> > +			rfa = 0x0a;
> > +			break;
> > +
> > +		case 16384:
> > +			rfd = 0x06;
> > +			rfa = 0x12;
> > +			break;
> > +
> > +		default:
> > +			rfd = 0x06;
> > +			rfa = 0x1e;
> > +			break;
> > +		}
> 
> Are these values correct? In the 4096 case, rfd > rfa, in all other cases
> the other way around. In any case it would be useful to have a comment
> clarifying the thresholds in bytes.

I'll investigate. To be honest I simply took this from Stephen's U-Boot
driver since that's already tested. I trust Stephen, so I didn't bother
double-checking.

Thierry
Thierry Reding March 9, 2017, 7:44 p.m. UTC | #4
On Thu, Mar 02, 2017 at 03:15:12PM +0000, Joao Pinto wrote:
> Às 5:24 PM de 2/23/2017, Thierry Reding escreveu:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Program the receive queue size based on the RX FIFO size and enable
> > hardware flow control for large FIFOs.
> > 
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> >  drivers/net/ethernet/stmicro/stmmac/dwmac4.h     | 12 +++++++
> >  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 43 ++++++++++++++++++++++--
> >  2 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > index db45134fddf0..9acc1f1252b3 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
> > @@ -180,6 +180,7 @@ enum power_event {
> >  #define MTL_OP_MODE_TSF			BIT(1)
> >  
> >  #define MTL_OP_MODE_TQS_MASK		GENMASK(24, 16)
> > +#define MTL_OP_MODE_TQS_SHIFT		16
> >  
> >  #define MTL_OP_MODE_TTC_MASK		0x70
> >  #define MTL_OP_MODE_TTC_SHIFT		4
> > @@ -193,6 +194,17 @@ enum power_event {
> >  #define MTL_OP_MODE_TTC_384		(6 << MTL_OP_MODE_TTC_SHIFT)
> >  #define MTL_OP_MODE_TTC_512		(7 << MTL_OP_MODE_TTC_SHIFT)
> >  
> > +#define MTL_OP_MODE_RQS_MASK		GENMASK(29, 20)
> > +#define MTL_OP_MODE_RQS_SHIFT		20
> > +
> > +#define MTL_OP_MODE_RFD_MASK		GENMASK(19, 14)
> > +#define MTL_OP_MODE_RFD_SHIFT		14
> > +
> > +#define MTL_OP_MODE_RFA_MASK		GENMASK(13, 8)
> > +#define MTL_OP_MODE_RFA_SHIFT		8
> > +
> > +#define MTL_OP_MODE_EHFC		BIT(7)
> > +
> >  #define MTL_OP_MODE_RTC_MASK		0x18
> >  #define MTL_OP_MODE_RTC_SHIFT		3
> >  
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > index 8d249f3b34c8..03d230201960 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> > @@ -185,8 +185,9 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
> >  }
> >  
> >  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> > -				    int rxmode, u32 channel)
> > +				    int rxmode, u32 channel, int rxfifosz)
> >  {
> > +	unsigned int rqs = rxfifosz / 256 - 1;
> >  	u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
> >  
> >  	/* Following code only done for channel 0, other channels not yet
> > @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> >  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
> >  	}
> >  
> > +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
> > +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
> > +
> > +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
> > +	if (rxfifosz >= 4096) {
> > +		unsigned int rfd, rfa;
> > +
> > +		mtl_rx_op |= MTL_OP_MODE_EHFC;
> > +
> > +		switch (rxfifosz) {
> > +		case 4096:
> > +			rfd = 0x03;
> > +			rfa = 0x01;
> > +			break;
> > +
> > +		case 8192:
> > +			rfd = 0x06;
> > +			rfa = 0x0a;
> > +			break;
> > +
> > +		case 16384:
> > +			rfd = 0x06;
> > +			rfa = 0x12;
> > +			break;
> > +
> > +		default:
> > +			rfd = 0x06;
> > +			rfa = 0x1e;
> > +			break;
> > +		}
> 
> Are these RFA and RFD values suitable to any setup using thresholds? Please
> justify their values in oerder for other developers to understand them.
> 
> > +
> > +		mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
> > +		mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
> > +
> > +		mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
> > +		mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
> > +	}
> > +
> >  	writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
> >  
> >  	/* Enable MTL RX overflow */
> > @@ -264,7 +303,7 @@ static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
> >  				      int rxmode, int rxfifosz)
> >  {
> >  	/* Only Channel 0 is actually configured and used */
> > -	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
> > +	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
> 
> Why not configure tx fifo as well, you already getting it from the features
> register.

Primarily I'm not initializing TX FIFO here because we don't pass the
size into this function. Secondarily, the default seems to work fine,
and therefore changing it didn't seem relevant.

Thierry
Stephen Warren March 9, 2017, 8:18 p.m. UTC | #5
On 03/09/2017 12:42 PM, Thierry Reding wrote:
> On Mon, Feb 27, 2017 at 12:09:02PM +0200, Mikko Perttunen wrote:
>> On 23.02.2017 19:24, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Program the receive queue size based on the RX FIFO size and enable
>>> hardware flow control for large FIFOs.

>>> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c

>>> @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>>>  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
>>>  	}
>>>
>>> +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
>>> +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
>>> +
>>> +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
>>> +	if (rxfifosz >= 4096) {
>>> +		unsigned int rfd, rfa;
>>> +
>>> +		mtl_rx_op |= MTL_OP_MODE_EHFC;
>>> +
>>> +		switch (rxfifosz) {
>>> +		case 4096:
>>> +			rfd = 0x03;
>>> +			rfa = 0x01;
>>> +			break;
>>> +
>>> +		case 8192:
>>> +			rfd = 0x06;
>>> +			rfa = 0x0a;
>>> +			break;
>>> +
>>> +		case 16384:
>>> +			rfd = 0x06;
>>> +			rfa = 0x12;
>>> +			break;
>>> +
>>> +		default:
>>> +			rfd = 0x06;
>>> +			rfa = 0x1e;
>>> +			break;
>>> +		}
>>
>> Are these values correct? In the 4096 case, rfd > rfa, in all other cases
>> the other way around. In any case it would be useful to have a comment
>> clarifying the thresholds in bytes.
>
> I'll investigate. To be honest I simply took this from Stephen's U-Boot
> driver since that's already tested. I trust Stephen, so I didn't bother
> double-checking.

I don't recall for sure, but I think these values came directly from 
either the upstream kernel (the non-stmmac driver) or NV downstream 
kernel EQoS driver, and I re-used them without investigating. I'm not 
even sure if the outer if() expression is true; these numbers might not 
even end up being used?
Thierry Reding March 9, 2017, 8:44 p.m. UTC | #6
On Thu, Mar 09, 2017 at 01:18:11PM -0700, Stephen Warren wrote:
> On 03/09/2017 12:42 PM, Thierry Reding wrote:
> > On Mon, Feb 27, 2017 at 12:09:02PM +0200, Mikko Perttunen wrote:
> > > On 23.02.2017 19:24, Thierry Reding wrote:
> > > > From: Thierry Reding <treding@nvidia.com>
> > > > 
> > > > Program the receive queue size based on the RX FIFO size and enable
> > > > hardware flow control for large FIFOs.
> 
> > > > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> 
> > > > @@ -252,6 +253,44 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> > > >  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
> > > >  	}
> > > > 
> > > > +	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
> > > > +	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
> > > > +
> > > > +	/* enable flow control only if each channel gets 4 KiB or more FIFO */
> > > > +	if (rxfifosz >= 4096) {
> > > > +		unsigned int rfd, rfa;
> > > > +
> > > > +		mtl_rx_op |= MTL_OP_MODE_EHFC;
> > > > +
> > > > +		switch (rxfifosz) {
> > > > +		case 4096:
> > > > +			rfd = 0x03;
> > > > +			rfa = 0x01;
> > > > +			break;
> > > > +
> > > > +		case 8192:
> > > > +			rfd = 0x06;
> > > > +			rfa = 0x0a;
> > > > +			break;
> > > > +
> > > > +		case 16384:
> > > > +			rfd = 0x06;
> > > > +			rfa = 0x12;
> > > > +			break;
> > > > +
> > > > +		default:
> > > > +			rfd = 0x06;
> > > > +			rfa = 0x1e;
> > > > +			break;
> > > > +		}
> > > 
> > > Are these values correct? In the 4096 case, rfd > rfa, in all other cases
> > > the other way around. In any case it would be useful to have a comment
> > > clarifying the thresholds in bytes.
> > 
> > I'll investigate. To be honest I simply took this from Stephen's U-Boot
> > driver since that's already tested. I trust Stephen, so I didn't bother
> > double-checking.
> 
> I don't recall for sure, but I think these values came directly from either
> the upstream kernel (the non-stmmac driver) or NV downstream kernel EQoS
> driver, and I re-used them without investigating. I'm not even sure if the
> outer if() expression is true; these numbers might not even end up being
> used?

Yes they are, and they were even the key to making the STMMAC driver
work on Tegra186. Without programming these fields the driver would fail
to receive any packets.

I noticed that you had comments in the U-Boot driver that I had left out
(most likely because I forgot to add them after cleaning up after the
hacking session). Here's the original extract from U-Boot:

		/*
		 * Set Threshold for Activating Flow Contol space for min 2
		 * frames ie, (1500 * 1) = 1500 bytes.
		 *
		 * Set Threshold for Deactivating Flow Contol for space of
		 * min 1 frame (frame size 1500bytes) in receive fifo
		 */
		if (rqs == ((4096 / 256) - 1)) {
			/*
			 * This violates the above formula because of FIFO size
			 * limit therefore overflow may occur inspite of this.
			 */
			rfd = 0x3;	/* Full-3K */
			rfa = 0x1;	/* Full-1.5K */
		} else if (rqs == ((8192 / 256) - 1)) {
			rfd = 0x6;	/* Full-4K */
			rfa = 0xa;	/* Full-6K */
		} else if (rqs == ((16384 / 256) - 1)) {
			rfd = 0x6;	/* Full-4K */
			rfa = 0x12;	/* Full-10K */
		} else {
			rfd = 0x6;	/* Full-4K */
			rfa = 0x1E;	/* Full-16K */
		}

Two things are strange about this:

	1) the first comment says "2 frames", but the threshold value is
	   clearly just one frame

	2) the first set of rfd/rfa values has a wrong comment, by my
	   understanding: Full-3K should really be Full-2.5K

The encoding of these values is essentially:

	threshold = full - (1K + value * 0.5K)

Here's my updated version from the kernel driver:

		/*
		 * Set Threshold for Activating Flow Control to min 2 frames,
		 * i.e. 1500 * 2 = 3000 bytes.
		 *
		 * Set Threshold for Deactivating Flow Control to min 1 frame,
		 * i.e. 1500 bytes.
		 */
		switch (rxfifosz) {
		case 4096:
			/*
			 * This violates the above formula because of FIFO size
			 * limit therefore overflow may occur in spite of this.
			 */
			rfd = 0x03; /* Full-2.5K */
			rfa = 0x01; /* Full-1.5K */
			break;

		case 8192:
			rfd = 0x06; /* Full-4K */
			rfa = 0x0a; /* Full-6K */
			break;

		case 16384:
			rfd = 0x06; /* Full-4K */
			rfa = 0x12; /* Full-10K */
			break;

		default:
			rfd = 0x06; /* Full-4K */
			rfa = 0x1e; /* Full-16K */
			break;
		}

As best as I can tell these values are within the constraints given in
the TRM and they also make sense to me for the purposes they're used
for.

Thierry
diff mbox

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index db45134fddf0..9acc1f1252b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -180,6 +180,7 @@  enum power_event {
 #define MTL_OP_MODE_TSF			BIT(1)
 
 #define MTL_OP_MODE_TQS_MASK		GENMASK(24, 16)
+#define MTL_OP_MODE_TQS_SHIFT		16
 
 #define MTL_OP_MODE_TTC_MASK		0x70
 #define MTL_OP_MODE_TTC_SHIFT		4
@@ -193,6 +194,17 @@  enum power_event {
 #define MTL_OP_MODE_TTC_384		(6 << MTL_OP_MODE_TTC_SHIFT)
 #define MTL_OP_MODE_TTC_512		(7 << MTL_OP_MODE_TTC_SHIFT)
 
+#define MTL_OP_MODE_RQS_MASK		GENMASK(29, 20)
+#define MTL_OP_MODE_RQS_SHIFT		20
+
+#define MTL_OP_MODE_RFD_MASK		GENMASK(19, 14)
+#define MTL_OP_MODE_RFD_SHIFT		14
+
+#define MTL_OP_MODE_RFA_MASK		GENMASK(13, 8)
+#define MTL_OP_MODE_RFA_SHIFT		8
+
+#define MTL_OP_MODE_EHFC		BIT(7)
+
 #define MTL_OP_MODE_RTC_MASK		0x18
 #define MTL_OP_MODE_RTC_SHIFT		3
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 8d249f3b34c8..03d230201960 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -185,8 +185,9 @@  static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
 }
 
 static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
-				    int rxmode, u32 channel)
+				    int rxmode, u32 channel, int rxfifosz)
 {
+	unsigned int rqs = rxfifosz / 256 - 1;
 	u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
 
 	/* Following code only done for channel 0, other channels not yet
@@ -252,6 +253,44 @@  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
 			mtl_rx_op |= MTL_OP_MODE_RTC_128;
 	}
 
+	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
+	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
+
+	/* enable flow control only if each channel gets 4 KiB or more FIFO */
+	if (rxfifosz >= 4096) {
+		unsigned int rfd, rfa;
+
+		mtl_rx_op |= MTL_OP_MODE_EHFC;
+
+		switch (rxfifosz) {
+		case 4096:
+			rfd = 0x03;
+			rfa = 0x01;
+			break;
+
+		case 8192:
+			rfd = 0x06;
+			rfa = 0x0a;
+			break;
+
+		case 16384:
+			rfd = 0x06;
+			rfa = 0x12;
+			break;
+
+		default:
+			rfd = 0x06;
+			rfa = 0x1e;
+			break;
+		}
+
+		mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
+		mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
+
+		mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
+		mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
+	}
+
 	writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
 
 	/* Enable MTL RX overflow */
@@ -264,7 +303,7 @@  static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
 				      int rxmode, int rxfifosz)
 {
 	/* Only Channel 0 is actually configured and used */
-	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
+	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
 }
 
 static void dwmac4_get_hw_feature(void __iomem *ioaddr,