diff mbox series

[net-next,v12,02/15] net: stmmac: Add multi-channel support

Message ID 5409facf916c0123e39a913c8342cc0ce8ed93db.1714046812.git.siyanteng@loongson.cn (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series stmmac: Add Loongson platform support | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 937 this patch: 937
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 10 maintainers not CCed: pabeni@redhat.com edumazet@google.com samuel@sholland.org kuba@kernel.org jernej.skrabec@gmail.com linux-sunxi@lists.linux.dev linux-stm32@st-md-mailman.stormreply.com wens@csie.org linux-arm-kernel@lists.infradead.org mcoquelin.stm32@gmail.com
netdev/build_clang success Errors and warnings before: 937 this patch: 937
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 949 this patch: 949
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 38 this patch: 38
netdev/source_inline success Was 0 now: 0

Commit Message

Yanteng Si April 25, 2024, 1:01 p.m. UTC
DW GMAC v3.x multi-channels feature is implemented as multiple
sets of the same CSRs. Here is only preliminary support, it will
be useful for the driver further evolution and for the users
having multi-channel DWGMAC v3.x devices.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
Signed-off-by: Yanteng Si <siyanteng@loongson.cn>
---
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  2 +-
 .../ethernet/stmicro/stmmac/dwmac1000_dma.c   | 32 ++++++++++---------
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   | 20 ++++++++++--
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   | 30 ++++++++---------
 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  6 ++--
 6 files changed, 55 insertions(+), 37 deletions(-)

Comments

Serge Semin May 2, 2024, 10:02 p.m. UTC | #1
On Thu, Apr 25, 2024 at 09:01:55PM +0800, Yanteng Si wrote:
> DW GMAC v3.x multi-channels feature is implemented as multiple
> sets of the same CSRs. Here is only preliminary support, it will
> be useful for the driver further evolution and for the users
> having multi-channel DWGMAC v3.x devices.

Why do you call it "preliminary"? AFAICS it's a fully functional
support with no restrictions. Am I wrong?

I would reformulate the commit message as:

"DW GMAC v3.73 can be equipped with the Audio Video (AV) feature which
enables transmission of time-sensitive traffic over bridged local area
networks (DWC Ethernet QoS Product). In that case there can be up to two
additional DMA-channels available with no Tx COE support (unless there is
vendor-specific IP-core alterations). Each channel is implemented as a
separate Control and Status register (CSR) for managing the transmit and
receive functions, descriptor handling, and interrupt handling.

Add the multi-channels DW GMAC controllers support just by making sure the
already implemented DMA-configs are performed on the per-channel basis.

Note the only currently known instance of the multi-channel DW GMAC
IP-core is the LS2K2000 GNET controller, which has been released with the
vendor-specific feature extension of having eight DMA-channels. The device
support will be added in one of the following up commits."

> 
> Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
> Signed-off-by: Yanteng Si <siyanteng@loongson.cn>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  2 +-
>  .../ethernet/stmicro/stmmac/dwmac1000_dma.c   | 32 ++++++++++---------
>  .../net/ethernet/stmicro/stmmac/dwmac_dma.h   | 20 ++++++++++--
>  .../net/ethernet/stmicro/stmmac/dwmac_lib.c   | 30 ++++++++---------
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  2 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c |  6 ++--
>  6 files changed, 55 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
> index d87079016952..cc93f73a380e 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
> @@ -395,7 +395,7 @@ static void sun8i_dwmac_dma_start_tx(struct stmmac_priv *priv,
>  	writel(v, ioaddr + EMAC_TX_CTL1);
>  }
>  
> -static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr)
> +static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)
>  {
>  	u32 v;
>  
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
> index bb82ee9b855f..f161ec9ac490 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
> @@ -70,15 +70,17 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
>  	writel(value, ioaddr + DMA_AXI_BUS_MODE);
>  }
>  
> -static void dwmac1000_dma_init(void __iomem *ioaddr,
> -			       struct stmmac_dma_cfg *dma_cfg)
> +static void dwmac1000_dma_init_channel(struct stmmac_priv *priv,
> +				       void __iomem *ioaddr,
> +				       struct stmmac_dma_cfg *dma_cfg, u32 chan)
>  {
> -	u32 value = readl(ioaddr + DMA_BUS_MODE);
>  	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
>  	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
> +	u32 value;
>  
> -	/*
> -	 * Set the DMA PBL (Programmable Burst Length) mode.
> +	value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
> +
> +	/* Set the DMA PBL (Programmable Burst Length) mode.
>  	 *
>  	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
>  	 * post 3.5 mode bit acts as 8*PBL.
> @@ -104,10 +106,10 @@ static void dwmac1000_dma_init(void __iomem *ioaddr,
>  	if (dma_cfg->aal)
>  		value |= DMA_BUS_MODE_AAL;
>  
> -	writel(value, ioaddr + DMA_BUS_MODE);
> +	writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
>  
>  	/* Mask interrupts by writing to CSR7 */
> -	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
> +	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
>  }
>  
>  static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
> @@ -116,7 +118,7 @@ static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
>  				  dma_addr_t dma_rx_phy, u32 chan)
>  {
>  	/* RX descriptor base address list must be written into DMA CSR3 */
> -	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
> +	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RCV_BASE_ADDR(chan));
>  }
>  
>  static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
> @@ -125,7 +127,7 @@ static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
>  				  dma_addr_t dma_tx_phy, u32 chan)
>  {
>  	/* TX descriptor base address list must be written into DMA CSR4 */
> -	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
> +	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
>  }
>  
>  static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)



> @@ -153,7 +155,7 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>  					    void __iomem *ioaddr, int mode,
>  					    u32 channel, int fifosz, u8 qmode)
>  {
> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>  
>  	if (mode == SF_DMA_MODE) {
>  		pr_debug("GMAC: enable RX store and forward mode\n");
> @@ -175,14 +177,14 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>  	/* Configure flow control based on rx fifo size */
>  	csr6 = dwmac1000_configure_fc(csr6, fifosz);
>  
> -	writel(csr6, ioaddr + DMA_CONTROL);
> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>  }
>  
>  static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>  					    void __iomem *ioaddr, int mode,
>  					    u32 channel, int fifosz, u8 qmode)
>  {
> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>  
>  	if (mode == SF_DMA_MODE) {
>  		pr_debug("GMAC: enable TX store and forward mode\n");
> @@ -209,7 +211,7 @@ static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>  			csr6 |= DMA_CONTROL_TTC_256;
>  	}
>  
> -	writel(csr6, ioaddr + DMA_CONTROL);
> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>  }
>  

Just figured out that besides of the channel-related changes you also need
to have the stmmac_dma_operation_mode() method fixed. So one wouldn't
redistribute the detected Tx/Rx FIFO between the channels. Each DW GMAC
channel has separate FIFO of the same size. The databook explicitly says
about that:

"The Tx FIFO size of all selected Transmit channels is always same.
Similarly, the Rx FIFO size of all selected Receive channels is same.
These channels cannot be of different sizes."

-Serge(y)

> [...]
Yanteng Si May 10, 2024, 10:13 a.m. UTC | #2
Hi Serge

在 2024/5/3 06:02, Serge Semin 写道:
> On Thu, Apr 25, 2024 at 09:01:55PM +0800, Yanteng Si wrote:
>> DW GMAC v3.x multi-channels feature is implemented as multiple
>> sets of the same CSRs. Here is only preliminary support, it will
>> be useful for the driver further evolution and for the users
>> having multi-channel DWGMAC v3.x devices.
> Why do you call it "preliminary"? AFAICS it's a fully functional
> support with no restrictions. Am I wrong?
>
> I would reformulate the commit message as:
>
> "DW GMAC v3.73 can be equipped with the Audio Video (AV) feature which
> enables transmission of time-sensitive traffic over bridged local area
> networks (DWC Ethernet QoS Product). In that case there can be up to two
> additional DMA-channels available with no Tx COE support (unless there is
> vendor-specific IP-core alterations). Each channel is implemented as a
> separate Control and Status register (CSR) for managing the transmit and
> receive functions, descriptor handling, and interrupt handling.
>
> Add the multi-channels DW GMAC controllers support just by making sure the
> already implemented DMA-configs are performed on the per-channel basis.
>
> Note the only currently known instance of the multi-channel DW GMAC
> IP-core is the LS2K2000 GNET controller, which has been released with the
> vendor-specific feature extension of having eight DMA-channels. The device
> support will be added in one of the following up commits."
OK.
>
>
>> @@ -153,7 +155,7 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>>   					    void __iomem *ioaddr, int mode,
>>   					    u32 channel, int fifosz, u8 qmode)
>>   {
>> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
>> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>>   
>>   	if (mode == SF_DMA_MODE) {
>>   		pr_debug("GMAC: enable RX store and forward mode\n");
>> @@ -175,14 +177,14 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>>   	/* Configure flow control based on rx fifo size */
>>   	csr6 = dwmac1000_configure_fc(csr6, fifosz);
>>   
>> -	writel(csr6, ioaddr + DMA_CONTROL);
>> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>>   }
>>   
>>   static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>>   					    void __iomem *ioaddr, int mode,
>>   					    u32 channel, int fifosz, u8 qmode)
>>   {
>> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
>> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>>   
>>   	if (mode == SF_DMA_MODE) {
>>   		pr_debug("GMAC: enable TX store and forward mode\n");
>> @@ -209,7 +211,7 @@ static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>>   			csr6 |= DMA_CONTROL_TTC_256;
>>   	}
>>   
>> -	writel(csr6, ioaddr + DMA_CONTROL);
>> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>>   }
>>   
> Just figured out that besides of the channel-related changes you also need
> to have the stmmac_dma_operation_mode() method fixed. So one wouldn't
> redistribute the detected Tx/Rx FIFO between the channels. Each DW GMAC
> channel has separate FIFO of the same size. The databook explicitly says
> about that:
>
> "The Tx FIFO size of all selected Transmit channels is always same.
> Similarly, the Rx FIFO size of all selected Receive channels is same.
> These channels cannot be of different sizes."
>
Should I do this, right?

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 33d04243b4d8..9d4148daee68 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2371,8 +2371,13 @@ static void stmmac_dma_operation_mode(struct 
stmmac_priv *priv)
                 txfifosz = priv->dma_cap.tx_fifo_size;

         /* Adjust for real per queue fifo size */
-       rxfifosz /= rx_channels_count;
-       txfifosz /= tx_channels_count;
+       if ((priv->synopsys_id != DWMAC_CORE_3_40) ||
+           (priv->synopsys_id != DWMAC_CORE_3_50) ||
+           (priv->synopsys_id != DWMAC_CORE_3_70)) {
+               rxfifosz /= rx_channels_count;
+               txfifosz /= tx_channels_count;
+       }
+

         if (priv->plat->force_thresh_dma_mode) {
                 txmode = tc;


Thanks,

Yanteng
Serge Semin May 13, 2024, 9:45 a.m. UTC | #3
On Fri, May 10, 2024 at 06:13:40PM +0800, Yanteng Si wrote:
> Hi Serge
> 
> 在 2024/5/3 06:02, Serge Semin 写道:
> > On Thu, Apr 25, 2024 at 09:01:55PM +0800, Yanteng Si wrote:
> > > DW GMAC v3.x multi-channels feature is implemented as multiple
> > > sets of the same CSRs. Here is only preliminary support, it will
> > > be useful for the driver further evolution and for the users
> > > having multi-channel DWGMAC v3.x devices.
> > Why do you call it "preliminary"? AFAICS it's a fully functional
> > support with no restrictions. Am I wrong?
> > 
> > I would reformulate the commit message as:
> > 
> > "DW GMAC v3.73 can be equipped with the Audio Video (AV) feature which
> > enables transmission of time-sensitive traffic over bridged local area
> > networks (DWC Ethernet QoS Product). In that case there can be up to two
> > additional DMA-channels available with no Tx COE support (unless there is
> > vendor-specific IP-core alterations). Each channel is implemented as a
> > separate Control and Status register (CSR) for managing the transmit and
> > receive functions, descriptor handling, and interrupt handling.
> > 
> > Add the multi-channels DW GMAC controllers support just by making sure the
> > already implemented DMA-configs are performed on the per-channel basis.
> > 
> > Note the only currently known instance of the multi-channel DW GMAC
> > IP-core is the LS2K2000 GNET controller, which has been released with the
> > vendor-specific feature extension of having eight DMA-channels. The device
> > support will be added in one of the following up commits."
> OK.
> > 
> > 
> > > @@ -153,7 +155,7 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
> > >   					    void __iomem *ioaddr, int mode,
> > >   					    u32 channel, int fifosz, u8 qmode)
> > >   {
> > > -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
> > > +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
> > >   	if (mode == SF_DMA_MODE) {
> > >   		pr_debug("GMAC: enable RX store and forward mode\n");
> > > @@ -175,14 +177,14 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
> > >   	/* Configure flow control based on rx fifo size */
> > >   	csr6 = dwmac1000_configure_fc(csr6, fifosz);
> > > -	writel(csr6, ioaddr + DMA_CONTROL);
> > > +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
> > >   }
> > >   static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
> > >   					    void __iomem *ioaddr, int mode,
> > >   					    u32 channel, int fifosz, u8 qmode)
> > >   {
> > > -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
> > > +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
> > >   	if (mode == SF_DMA_MODE) {
> > >   		pr_debug("GMAC: enable TX store and forward mode\n");
> > > @@ -209,7 +211,7 @@ static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
> > >   			csr6 |= DMA_CONTROL_TTC_256;
> > >   	}
> > > -	writel(csr6, ioaddr + DMA_CONTROL);
> > > +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
> > >   }
> > Just figured out that besides of the channel-related changes you also need
> > to have the stmmac_dma_operation_mode() method fixed. So one wouldn't
> > redistribute the detected Tx/Rx FIFO between the channels. Each DW GMAC
> > channel has separate FIFO of the same size. The databook explicitly says
> > about that:
> > 
> > "The Tx FIFO size of all selected Transmit channels is always same.
> > Similarly, the Rx FIFO size of all selected Receive channels is same.
> > These channels cannot be of different sizes."
> > 

> Should I do this, right?
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 33d04243b4d8..9d4148daee68 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -2371,8 +2371,13 @@ static void stmmac_dma_operation_mode(struct
> stmmac_priv *priv)
>                 txfifosz = priv->dma_cap.tx_fifo_size;
> 
>         /* Adjust for real per queue fifo size */
> -       rxfifosz /= rx_channels_count;
> -       txfifosz /= tx_channels_count;
> +       if ((priv->synopsys_id != DWMAC_CORE_3_40) ||
> +           (priv->synopsys_id != DWMAC_CORE_3_50) ||
> +           (priv->synopsys_id != DWMAC_CORE_3_70)) {
> +               rxfifosz /= rx_channels_count;
> +               txfifosz /= tx_channels_count;
> +       }
> +
> 
>         if (priv->plat->force_thresh_dma_mode) {
>                 txmode = tc;

Seeing the shared FIFO memory is specific for the DW QoS Eth and DW
xGMAC IP-cores let's use the has_gmac4 and has_xgmac flags instead:

--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2371,8 +2371,13 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 	if (txfifosz == 0)
 		txfifosz = priv->dma_cap.tx_fifo_size;
 
-	/* Adjust for real per queue fifo size */
-	rxfifosz /= rx_channels_count;
-	txfifosz /= tx_channels_count;
+	/* Split up the shared Tx/Rx FIFO memory on DW QoS Eth and DW XGMAC */
+	if (priv->plat->has_gmac4 || priv->plat->has_xgmac) {
+		rxfifosz /= rx_channels_count;
+		txfifosz /= tx_channels_count;
+	}
 
 	if (priv->plat->force_thresh_dma_mode) {
 		txmode = tc;

-Serge(y)
> 
> 
> Thanks,
> 
> Yanteng
>
Yanteng Si May 13, 2024, 9:49 a.m. UTC | #4
在 2024/5/13 17:45, Serge Semin 写道:
> On Fri, May 10, 2024 at 06:13:40PM +0800, Yanteng Si wrote:
>> Hi Serge
>>
>> 在 2024/5/3 06:02, Serge Semin 写道:
>>> On Thu, Apr 25, 2024 at 09:01:55PM +0800, Yanteng Si wrote:
>>>> DW GMAC v3.x multi-channels feature is implemented as multiple
>>>> sets of the same CSRs. Here is only preliminary support, it will
>>>> be useful for the driver further evolution and for the users
>>>> having multi-channel DWGMAC v3.x devices.
>>> Why do you call it "preliminary"? AFAICS it's a fully functional
>>> support with no restrictions. Am I wrong?
>>>
>>> I would reformulate the commit message as:
>>>
>>> "DW GMAC v3.73 can be equipped with the Audio Video (AV) feature which
>>> enables transmission of time-sensitive traffic over bridged local area
>>> networks (DWC Ethernet QoS Product). In that case there can be up to two
>>> additional DMA-channels available with no Tx COE support (unless there is
>>> vendor-specific IP-core alterations). Each channel is implemented as a
>>> separate Control and Status register (CSR) for managing the transmit and
>>> receive functions, descriptor handling, and interrupt handling.
>>>
>>> Add the multi-channels DW GMAC controllers support just by making sure the
>>> already implemented DMA-configs are performed on the per-channel basis.
>>>
>>> Note the only currently known instance of the multi-channel DW GMAC
>>> IP-core is the LS2K2000 GNET controller, which has been released with the
>>> vendor-specific feature extension of having eight DMA-channels. The device
>>> support will be added in one of the following up commits."
>> OK.
>>>> @@ -153,7 +155,7 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>>>>    					    void __iomem *ioaddr, int mode,
>>>>    					    u32 channel, int fifosz, u8 qmode)
>>>>    {
>>>> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
>>>> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>>>>    	if (mode == SF_DMA_MODE) {
>>>>    		pr_debug("GMAC: enable RX store and forward mode\n");
>>>> @@ -175,14 +177,14 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
>>>>    	/* Configure flow control based on rx fifo size */
>>>>    	csr6 = dwmac1000_configure_fc(csr6, fifosz);
>>>> -	writel(csr6, ioaddr + DMA_CONTROL);
>>>> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>>>>    }
>>>>    static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>>>>    					    void __iomem *ioaddr, int mode,
>>>>    					    u32 channel, int fifosz, u8 qmode)
>>>>    {
>>>> -	u32 csr6 = readl(ioaddr + DMA_CONTROL);
>>>> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
>>>>    	if (mode == SF_DMA_MODE) {
>>>>    		pr_debug("GMAC: enable TX store and forward mode\n");
>>>> @@ -209,7 +211,7 @@ static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
>>>>    			csr6 |= DMA_CONTROL_TTC_256;
>>>>    	}
>>>> -	writel(csr6, ioaddr + DMA_CONTROL);
>>>> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
>>>>    }
>>> Just figured out that besides of the channel-related changes you also need
>>> to have the stmmac_dma_operation_mode() method fixed. So one wouldn't
>>> redistribute the detected Tx/Rx FIFO between the channels. Each DW GMAC
>>> channel has separate FIFO of the same size. The databook explicitly says
>>> about that:
>>>
>>> "The Tx FIFO size of all selected Transmit channels is always same.
>>> Similarly, the Rx FIFO size of all selected Receive channels is same.
>>> These channels cannot be of different sizes."
>>>
>> Should I do this, right?
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> index 33d04243b4d8..9d4148daee68 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> @@ -2371,8 +2371,13 @@ static void stmmac_dma_operation_mode(struct
>> stmmac_priv *priv)
>>                  txfifosz = priv->dma_cap.tx_fifo_size;
>>
>>          /* Adjust for real per queue fifo size */
>> -       rxfifosz /= rx_channels_count;
>> -       txfifosz /= tx_channels_count;
>> +       if ((priv->synopsys_id != DWMAC_CORE_3_40) ||
>> +           (priv->synopsys_id != DWMAC_CORE_3_50) ||
>> +           (priv->synopsys_id != DWMAC_CORE_3_70)) {
>> +               rxfifosz /= rx_channels_count;
>> +               txfifosz /= tx_channels_count;
>> +       }
>> +
>>
>>          if (priv->plat->force_thresh_dma_mode) {
>>                  txmode = tc;
> Seeing the shared FIFO memory is specific for the DW QoS Eth and DW
> xGMAC IP-cores let's use the has_gmac4 and has_xgmac flags instead:
>
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -2371,8 +2371,13 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
>   	if (txfifosz == 0)
>   		txfifosz = priv->dma_cap.tx_fifo_size;
>   
> -	/* Adjust for real per queue fifo size */
> -	rxfifosz /= rx_channels_count;
> -	txfifosz /= tx_channels_count;
> +	/* Split up the shared Tx/Rx FIFO memory on DW QoS Eth and DW XGMAC */
> +	if (priv->plat->has_gmac4 || priv->plat->has_xgmac) {
> +		rxfifosz /= rx_channels_count;
> +		txfifosz /= tx_channels_count;
> +	}
>   
>   	if (priv->plat->force_thresh_dma_mode) {
>   		txmode = tc;

OK.


Thanks,

Yanteng
diff mbox series

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index d87079016952..cc93f73a380e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -395,7 +395,7 @@  static void sun8i_dwmac_dma_start_tx(struct stmmac_priv *priv,
 	writel(v, ioaddr + EMAC_TX_CTL1);
 }
 
-static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr)
+static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)
 {
 	u32 v;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index bb82ee9b855f..f161ec9ac490 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -70,15 +70,17 @@  static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
 	writel(value, ioaddr + DMA_AXI_BUS_MODE);
 }
 
-static void dwmac1000_dma_init(void __iomem *ioaddr,
-			       struct stmmac_dma_cfg *dma_cfg)
+static void dwmac1000_dma_init_channel(struct stmmac_priv *priv,
+				       void __iomem *ioaddr,
+				       struct stmmac_dma_cfg *dma_cfg, u32 chan)
 {
-	u32 value = readl(ioaddr + DMA_BUS_MODE);
 	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
 	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+	u32 value;
 
-	/*
-	 * Set the DMA PBL (Programmable Burst Length) mode.
+	value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
+
+	/* Set the DMA PBL (Programmable Burst Length) mode.
 	 *
 	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
 	 * post 3.5 mode bit acts as 8*PBL.
@@ -104,10 +106,10 @@  static void dwmac1000_dma_init(void __iomem *ioaddr,
 	if (dma_cfg->aal)
 		value |= DMA_BUS_MODE_AAL;
 
-	writel(value, ioaddr + DMA_BUS_MODE);
+	writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
 
 	/* Mask interrupts by writing to CSR7 */
-	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
 static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
@@ -116,7 +118,7 @@  static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
 				  dma_addr_t dma_rx_phy, u32 chan)
 {
 	/* RX descriptor base address list must be written into DMA CSR3 */
-	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
+	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RCV_BASE_ADDR(chan));
 }
 
 static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
@@ -125,7 +127,7 @@  static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
 				  dma_addr_t dma_tx_phy, u32 chan)
 {
 	/* TX descriptor base address list must be written into DMA CSR4 */
-	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
+	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
 }
 
 static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
@@ -153,7 +155,7 @@  static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
 					    void __iomem *ioaddr, int mode,
 					    u32 channel, int fifosz, u8 qmode)
 {
-	u32 csr6 = readl(ioaddr + DMA_CONTROL);
+	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
 
 	if (mode == SF_DMA_MODE) {
 		pr_debug("GMAC: enable RX store and forward mode\n");
@@ -175,14 +177,14 @@  static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
 	/* Configure flow control based on rx fifo size */
 	csr6 = dwmac1000_configure_fc(csr6, fifosz);
 
-	writel(csr6, ioaddr + DMA_CONTROL);
+	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
 }
 
 static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
 					    void __iomem *ioaddr, int mode,
 					    u32 channel, int fifosz, u8 qmode)
 {
-	u32 csr6 = readl(ioaddr + DMA_CONTROL);
+	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
 
 	if (mode == SF_DMA_MODE) {
 		pr_debug("GMAC: enable TX store and forward mode\n");
@@ -209,7 +211,7 @@  static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
 			csr6 |= DMA_CONTROL_TTC_256;
 	}
 
-	writel(csr6, ioaddr + DMA_CONTROL);
+	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
 }
 
 static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv,
@@ -271,12 +273,12 @@  static int dwmac1000_get_hw_feature(void __iomem *ioaddr,
 static void dwmac1000_rx_watchdog(struct stmmac_priv *priv,
 				  void __iomem *ioaddr, u32 riwt, u32 queue)
 {
-	writel(riwt, ioaddr + DMA_RX_WATCHDOG);
+	writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
 }
 
 const struct stmmac_dma_ops dwmac1000_dma_ops = {
 	.reset = dwmac_dma_reset,
-	.init = dwmac1000_dma_init,
+	.init_chan = dwmac1000_dma_init_channel,
 	.init_rx_chan = dwmac1000_dma_init_rx,
 	.init_tx_chan = dwmac1000_dma_init_tx,
 	.axi = dwmac1000_dma_axi,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 72672391675f..363a85469594 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -22,6 +22,23 @@ 
 #define DMA_INTR_ENA		0x0000101c	/* Interrupt Enable */
 #define DMA_MISSED_FRAME_CTR	0x00001020	/* Missed Frame Counter */
 
+/* Following DMA defines are channels oriented */
+#define DMA_CHAN_BASE_OFFSET			0x100
+
+static inline u32 dma_chan_base_addr(u32 base, u32 chan)
+{
+	return base + chan * DMA_CHAN_BASE_OFFSET;
+}
+
+#define DMA_CHAN_XMT_POLL_DEMAND(chan)	dma_chan_base_addr(DMA_XMT_POLL_DEMAND, chan)
+#define DMA_CHAN_INTR_ENA(chan)	dma_chan_base_addr(DMA_INTR_ENA, chan)
+#define DMA_CHAN_CONTROL(chan)		dma_chan_base_addr(DMA_CONTROL, chan)
+#define DMA_CHAN_STATUS(chan)		dma_chan_base_addr(DMA_STATUS, chan)
+#define DMA_CHAN_BUS_MODE(chan)	dma_chan_base_addr(DMA_BUS_MODE, chan)
+#define DMA_CHAN_RCV_BASE_ADDR(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR, chan)
+#define DMA_CHAN_TX_BASE_ADDR(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR, chan)
+#define DMA_CHAN_RX_WATCHDOG(chan)	dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
+
 /* SW Reset */
 #define DMA_BUS_MODE_SFT_RESET	0x00000001	/* Software Reset */
 
@@ -152,7 +169,7 @@ 
 #define NUM_DWMAC1000_DMA_REGS	23
 #define NUM_DWMAC4_DMA_REGS	27
 
-void dwmac_enable_dma_transmission(void __iomem *ioaddr);
+void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan);
 void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
 			  u32 chan, bool rx, bool tx);
 void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -168,5 +185,4 @@  void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
 int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
 			struct stmmac_extra_stats *x, u32 chan, u32 dir);
 int dwmac_dma_reset(void __iomem *ioaddr);
-
 #endif /* __DWMAC_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 85e18f9a22f9..4846bf49c576 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -28,65 +28,65 @@  int dwmac_dma_reset(void __iomem *ioaddr)
 }
 
 /* CSR1 enables the transmit DMA to check for new descriptor */
-void dwmac_enable_dma_transmission(void __iomem *ioaddr)
+void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)
 {
-	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
+	writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));
 }
 
 void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
 			  u32 chan, bool rx, bool tx)
 {
-	u32 value = readl(ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
 
 	if (rx)
 		value |= DMA_INTR_DEFAULT_RX;
 	if (tx)
 		value |= DMA_INTR_DEFAULT_TX;
 
-	writel(value, ioaddr + DMA_INTR_ENA);
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
 void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
 			   u32 chan, bool rx, bool tx)
 {
-	u32 value = readl(ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
 
 	if (rx)
 		value &= ~DMA_INTR_DEFAULT_RX;
 	if (tx)
 		value &= ~DMA_INTR_DEFAULT_TX;
 
-	writel(value, ioaddr + DMA_INTR_ENA);
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
 void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
 			u32 chan)
 {
-	u32 value = readl(ioaddr + DMA_CONTROL);
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
 	value |= DMA_CONTROL_ST;
-	writel(value, ioaddr + DMA_CONTROL);
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
 }
 
 void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
 {
-	u32 value = readl(ioaddr + DMA_CONTROL);
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
 	value &= ~DMA_CONTROL_ST;
-	writel(value, ioaddr + DMA_CONTROL);
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
 }
 
 void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
 			u32 chan)
 {
-	u32 value = readl(ioaddr + DMA_CONTROL);
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
 	value |= DMA_CONTROL_SR;
-	writel(value, ioaddr + DMA_CONTROL);
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
 }
 
 void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
 {
-	u32 value = readl(ioaddr + DMA_CONTROL);
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
 	value &= ~DMA_CONTROL_SR;
-	writel(value, ioaddr + DMA_CONTROL);
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
 }
 
 #ifdef DWMAC_DMA_DEBUG
@@ -165,7 +165,7 @@  int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
 	struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
 	int ret = 0;
 	/* read the status register (CSR5) */
-	u32 intr_status = readl(ioaddr + DMA_STATUS);
+	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
 
 #ifdef DWMAC_DMA_DEBUG
 	/* Enable it to monitor DMA rx/tx status in case of critical problems */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 413441eb6ea0..d807ee4b066e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -197,7 +197,7 @@  struct stmmac_dma_ops {
 	/* To track extra statistic (if supported) */
 	void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x,
 				  void __iomem *ioaddr);
-	void (*enable_dma_transmission) (void __iomem *ioaddr);
+	void (*enable_dma_transmission)(void __iomem *ioaddr, u32 chan);
 	void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			       u32 chan, bool rx, bool tx);
 	void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 188514ca6c47..9ae28f4bafaa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2556,7 +2556,7 @@  static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
 				       true, priv->mode, true, true,
 				       xdp_desc.len);
 
-		stmmac_enable_dma_transmission(priv, priv->ioaddr);
+		stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 		xsk_tx_metadata_to_compl(meta,
 					 &tx_q->tx_skbuff_dma[entry].xsk_meta);
@@ -4752,7 +4752,7 @@  static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len);
 
-	stmmac_enable_dma_transmission(priv, priv->ioaddr);
+	stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 	stmmac_flush_tx_descriptors(priv, queue);
 	stmmac_tx_timer_arm(priv, queue);
@@ -4979,7 +4979,7 @@  static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
 		u64_stats_update_end(&txq_stats->q_syncp);
 	}
 
-	stmmac_enable_dma_transmission(priv, priv->ioaddr);
+	stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 	entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
 	tx_q->cur_tx = entry;