diff mbox

[v3,net-next,01/11] net: stmmac: prepare dma op mode config for multiple queues

Message ID efde5ec3d6873d0b2ad5b806f230f5804257915d.1489575025.git.jpinto@synopsys.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Joao Pinto March 15, 2017, 11:04 a.m. UTC
This patch prepares DMA Operation Mode configuration for multiple queues.
The work consisted on breaking the DMA operation Mode configuration function
into RX and TX scope and adapting its mechanism in stmmac_main.

Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v1->v3:
- Just to keep up the patch-set version

 drivers/net/ethernet/stmicro/stmmac/common.h      |   3 +
 drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c  | 118 +++++++++++-----------
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  82 +++++++++++----
 3 files changed, 124 insertions(+), 79 deletions(-)

Comments

Jan Kiszka May 8, 2017, 6:56 a.m. UTC | #1
On 2017-03-15 12:04, Joao Pinto wrote:
> This patch prepares DMA Operation Mode configuration for multiple queues.
> The work consisted on breaking the DMA operation Mode configuration function
> into RX and TX scope and adapting its mechanism in stmmac_main.
> 
> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
> ---
> changes v1->v3:
> - Just to keep up the patch-set version
> 
>  drivers/net/ethernet/stmicro/stmmac/common.h      |   3 +
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c  | 118 +++++++++++-----------
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  82 +++++++++++----
>  3 files changed, 124 insertions(+), 79 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index 9f0d26d..13bd3d4 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -424,6 +424,9 @@ struct stmmac_dma_ops {
>  	 * An invalid value enables the store-and-forward mode */
>  	void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
>  			 int rxfifosz);
> +	void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
> +			    int fifosz);
> +	void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel);
>  	/* To track extra statistic (if supported) */
>  	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
>  				   void __iomem *ioaddr);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> index 6ac6b26..6285e8a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
> @@ -182,70 +182,26 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
>  		writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(i));
>  }
>  
> -static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
> -				    int rxmode, u32 channel, int rxfifosz)
> +static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
> +				       u32 channel, int fifosz)
>  {
> -	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
> -	 * supported.
> -	 */
> -	mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
> -
> -	if (txmode == SF_DMA_MODE) {
> -		pr_debug("GMAC: enable TX store and forward mode\n");
> -		/* Transmit COE type 2 cannot be done in cut-through mode. */
> -		mtl_tx_op |= MTL_OP_MODE_TSF;
> -	} else {
> -		pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
> -		mtl_tx_op &= ~MTL_OP_MODE_TSF;
> -		mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
> -		/* Set the transmit threshold */
> -		if (txmode <= 32)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_32;
> -		else if (txmode <= 64)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_64;
> -		else if (txmode <= 96)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_96;
> -		else if (txmode <= 128)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_128;
> -		else if (txmode <= 192)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_192;
> -		else if (txmode <= 256)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_256;
> -		else if (txmode <= 384)
> -			mtl_tx_op |= MTL_OP_MODE_TTC_384;
> -		else
> -			mtl_tx_op |= MTL_OP_MODE_TTC_512;
> -	}
> -	/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
> -	 * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
> -	 * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
> -	 * with reset values: TXQEN off, TQS 256 bytes.
> -	 *
> -	 * Write the bits in both cases, since it will have no effect when RO.
> -	 * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
> -	 * be RO, however, writing the whole TQS field will result in a value
> -	 * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
> -	 */
> -	mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
> -	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
> +	unsigned int rqs = fifosz / 256 - 1;
> +	u32 mtl_rx_op, mtl_rx_int;
>  
>  	mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
>  
> -	if (rxmode == SF_DMA_MODE) {
> +	if (mode == SF_DMA_MODE) {
>  		pr_debug("GMAC: enable RX store and forward mode\n");
>  		mtl_rx_op |= MTL_OP_MODE_RSF;
>  	} else {
> -		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
> +		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
>  		mtl_rx_op &= ~MTL_OP_MODE_RSF;
>  		mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
> -		if (rxmode <= 32)
> +		if (mode <= 32)
>  			mtl_rx_op |= MTL_OP_MODE_RTC_32;
> -		else if (rxmode <= 64)
> +		else if (mode <= 64)
>  			mtl_rx_op |= MTL_OP_MODE_RTC_64;
> -		else if (rxmode <= 96)
> +		else if (mode <= 96)
>  			mtl_rx_op |= MTL_OP_MODE_RTC_96;
>  		else
>  			mtl_rx_op |= MTL_OP_MODE_RTC_128;
> @@ -255,7 +211,7 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>  	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) {
> +	if (fifosz >= 4096) {
>  		unsigned int rfd, rfa;
>  
>  		mtl_rx_op |= MTL_OP_MODE_EHFC;
> @@ -266,7 +222,7 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>  		 * Set Threshold for Deactivating Flow Control to min 1 frame,
>  		 * i.e. 1500 bytes.
>  		 */
> -		switch (rxfifosz) {
> +		switch (fifosz) {
>  		case 4096:
>  			/* This violates the above formula because of FIFO size
>  			 * limit therefore overflow may occur in spite of this.
> @@ -306,11 +262,49 @@ static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
>  	       ioaddr + MTL_CHAN_INT_CTRL(channel));
>  }
>  
> -static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
> -				      int rxmode, int rxfifosz)
> +static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
> +				       u32 channel)
>  {
> -	/* Only Channel 0 is actually configured and used */
> -	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
> +	u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
> +
> +	if (mode == SF_DMA_MODE) {
> +		pr_debug("GMAC: enable TX store and forward mode\n");
> +		/* Transmit COE type 2 cannot be done in cut-through mode. */
> +		mtl_tx_op |= MTL_OP_MODE_TSF;
> +	} else {
> +		pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
> +		mtl_tx_op &= ~MTL_OP_MODE_TSF;
> +		mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
> +		/* Set the transmit threshold */
> +		if (mode <= 32)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_32;
> +		else if (mode <= 64)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_64;
> +		else if (mode <= 96)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_96;
> +		else if (mode <= 128)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_128;
> +		else if (mode <= 192)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_192;
> +		else if (mode <= 256)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_256;
> +		else if (mode <= 384)
> +			mtl_tx_op |= MTL_OP_MODE_TTC_384;
> +		else
> +			mtl_tx_op |= MTL_OP_MODE_TTC_512;
> +	}
> +	/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
> +	 * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
> +	 * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
> +	 * with reset values: TXQEN off, TQS 256 bytes.
> +	 *
> +	 * Write the bits in both cases, since it will have no effect when RO.
> +	 * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
> +	 * be RO, however, writing the whole TQS field will result in a value
> +	 * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
> +	 */
> +	mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
> +	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
>  }
>  
>  static void dwmac4_get_hw_feature(void __iomem *ioaddr,
> @@ -387,7 +381,8 @@ const struct stmmac_dma_ops dwmac4_dma_ops = {
>  	.init = dwmac4_dma_init,
>  	.axi = dwmac4_dma_axi,
>  	.dump_regs = dwmac4_dump_dma_regs,
> -	.dma_mode = dwmac4_dma_operation_mode,
> +	.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
> +	.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
>  	.enable_dma_irq = dwmac4_enable_dma_irq,
>  	.disable_dma_irq = dwmac4_disable_dma_irq,
>  	.start_tx = dwmac4_dma_start_tx,
> @@ -409,7 +404,8 @@ const struct stmmac_dma_ops dwmac410_dma_ops = {
>  	.init = dwmac4_dma_init,
>  	.axi = dwmac4_dma_axi,
>  	.dump_regs = dwmac4_dump_dma_regs,
> -	.dma_mode = dwmac4_dma_operation_mode,
> +	.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
> +	.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
>  	.enable_dma_irq = dwmac410_enable_dma_irq,
>  	.disable_dma_irq = dwmac4_disable_dma_irq,
>  	.start_tx = dwmac4_dma_start_tx,
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index ec363e1..c4e4a53 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -1285,14 +1285,20 @@ static void stmmac_mac_enable_rx_queues(struct stmmac_priv *priv)
>   */
>  static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
>  {
> +	u32 rx_channels_count = priv->plat->rx_queues_to_use;
> +	u32 tx_channels_count = priv->plat->tx_queues_to_use;
>  	int rxfifosz = priv->plat->rx_fifo_size;
> +	u32 txmode = 0;
> +	u32 rxmode = 0;
> +	u32 chan = 0;
>  
>  	if (rxfifosz == 0)
>  		rxfifosz = priv->dma_cap.rx_fifo_size;
>  
> -	if (priv->plat->force_thresh_dma_mode)
> -		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
> -	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
> +	if (priv->plat->force_thresh_dma_mode) {
> +		txmode = tc;
> +		rxmode = tc;
> +	} else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
>  		/*
>  		 * In case of GMAC, SF mode can be enabled
>  		 * to perform the TX COE in HW. This depends on:
> @@ -1300,12 +1306,26 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
>  		 * 2) There is no bugged Jumbo frame support
>  		 *    that needs to not insert csum in the TDES.
>  		 */
> -		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE,
> -					rxfifosz);
> +		txmode = SF_DMA_MODE;
> +		rxmode = SF_DMA_MODE;
>  		priv->xstats.threshold = SF_DMA_MODE;
> -	} else
> -		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE,
> +	} else {
> +		txmode = tc;
> +		rxmode = SF_DMA_MODE;
> +	}
> +
> +	/* configure all channels */
> +	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
> +		for (chan = 0; chan < rx_channels_count; chan++)
> +			priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
> +						   rxfifosz);
> +
> +		for (chan = 0; chan < tx_channels_count; chan++)
> +			priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
> +	} else {
> +		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
>  					rxfifosz);
> +	}
>  }
>  
>  /**
> @@ -1444,6 +1464,34 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
>  }
>  
>  /**
> + *  stmmac_set_dma_operation_mode - Set DMA operation mode by channel
> + *  @priv: driver private structure
> + *  @txmode: TX operating mode
> + *  @rxmode: RX operating mode
> + *  @chan: channel index
> + *  Description: it is used for configuring of the DMA operation mode in
> + *  runtime in order to program the tx/rx DMA thresholds or Store-And-Forward
> + *  mode.
> + */
> +static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
> +					  u32 rxmode, u32 chan)
> +{
> +	int rxfifosz = priv->plat->rx_fifo_size;
> +
> +	if (rxfifosz == 0)
> +		rxfifosz = priv->dma_cap.rx_fifo_size;
> +
> +	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
> +		priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
> +					   rxfifosz);
> +		priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
> +	} else {
> +		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
> +					rxfifosz);
> +	}
> +}
> +
> +/**
>   * stmmac_dma_interrupt - DMA ISR
>   * @priv: driver private structure
>   * Description: this is the DMA ISR. It is called by the main ISR.
> @@ -1452,11 +1500,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
>   */
>  static void stmmac_dma_interrupt(struct stmmac_priv *priv)
>  {
> +	u32 chan = STMMAC_CHAN0;
>  	int status;
> -	int rxfifosz = priv->plat->rx_fifo_size;
> -
> -	if (rxfifosz == 0)
> -		rxfifosz = priv->dma_cap.rx_fifo_size;
>  
>  	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
>  	if (likely((status & handle_rx)) || (status & handle_tx)) {
> @@ -1471,11 +1516,12 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
>  		    (tc <= 256)) {
>  			tc += 64;
>  			if (priv->plat->force_thresh_dma_mode)
> -				priv->hw->dma->dma_mode(priv->ioaddr, tc, tc,
> -							rxfifosz);
> +				stmmac_set_dma_operation_mode(priv->ioaddr,
> +							      tc, tc, chan);
>  			else
> -				priv->hw->dma->dma_mode(priv->ioaddr, tc,
> -							SF_DMA_MODE, rxfifosz);
> +				stmmac_set_dma_operation_mode(priv->ioaddr, tc,
> +							     SF_DMA_MODE, chan);
> +
>  			priv->xstats.threshold = tc;
>  		}
>  	} else if (unlikely(status == tx_hard_error))
> @@ -1749,6 +1795,9 @@ static void stmmac_mtl_configuration(struct stmmac_priv *priv)
>  	/* Enable MAC RX Queues */
>  	if (rx_queues_count > 1 && priv->hw->mac->rx_queue_enable)
>  		stmmac_mac_enable_rx_queues(priv);
> +
> +	/* Set the HW DMA mode and the COE */
> +	stmmac_dma_operation_mode(priv);
>  }
>  
>  /**
> @@ -1812,9 +1861,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
>  	else
>  		stmmac_set_mac(priv->ioaddr, true);
>  
> -	/* Set the HW DMA mode and the COE */
> -	stmmac_dma_operation_mode(priv);
> -
>  	stmmac_mmc_setup(priv);
>  
>  	if (init_ptp) {
> 

Starting with this patch, the stmmac-based network adapters of the Intel
Quark SoC stop working. I'm getting an IP via DHCP, I can ping, but TCP
connections can no longer be established.

Moving on a few patches (didn't bisect the exact one yet), the TX
watchdog starts to fire, and DHCP fails completely. And if I go to
current master in Linus tree (reverting an unrelated boot regression), I
even get a crash in stmmac_xmit.

Here are some details about the hw from dma_cap POV, if this helps:

==============================
        DMA HW features
==============================
        10/100 Mbps: Y
        1000 Mbps: N
        Half duplex: Y
        Hash Filter: Y
        Multiple MAC address registers: N
        PCS (TBI/SGMII/RTBI PHY interfaces): N
        SMA (MDIO) Interface: Y
        PMT Remote wake up: N
        PMT Magic Frame: N
        RMON module: Y
        IEEE 1588-2002 Time Stamp: N
        IEEE 1588-2008 Advanced Time Stamp: Y
        802.3az - Energy-Efficient Ethernet (EEE): N
        AV features: N
        Checksum Offload in TX: Y
        IP Checksum Offload (type1) in RX: N
        IP Checksum Offload (type2) in RX: Y
        RXFIFO > 2048bytes: Y
        Number of Additional RX channel: 0
        Number of Additional TX channel: 0
        Enhanced descriptors: Y

Given the number of different failure modes, my feeling is that there
are multiple regressions coming with these patches...

I've tested on the IOT2000 board, but I suspect the Galileo Gen2 will be
affected equally. If you don't have access to any such device, let me
know what I can debug for you.

Jan
Andy Shevchenko May 8, 2017, 9:36 a.m. UTC | #2
On Mon, May 8, 2017 at 9:56 AM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> On 2017-03-15 12:04, Joao Pinto wrote:
>> This patch prepares DMA Operation Mode configuration for multiple queues.
>> The work consisted on breaking the DMA operation Mode configuration function
>> into RX and TX scope and adapting its mechanism in stmmac_main.

> Starting with this patch, the stmmac-based network adapters of the Intel
> Quark SoC stop working. I'm getting an IP via DHCP, I can ping, but TCP
> connections can no longer be established.
>
> Moving on a few patches (didn't bisect the exact one yet), the TX
> watchdog starts to fire, and DHCP fails completely. And if I go to
> current master in Linus tree (reverting an unrelated boot regression), I
> even get a crash in stmmac_xmit.
>
> Here are some details about the hw from dma_cap POV, if this helps:
>
> ==============================
>         DMA HW features
> ==============================
>         10/100 Mbps: Y
>         1000 Mbps: N
>         Half duplex: Y
>         Hash Filter: Y
>         Multiple MAC address registers: N
>         PCS (TBI/SGMII/RTBI PHY interfaces): N
>         SMA (MDIO) Interface: Y
>         PMT Remote wake up: N
>         PMT Magic Frame: N
>         RMON module: Y
>         IEEE 1588-2002 Time Stamp: N
>         IEEE 1588-2008 Advanced Time Stamp: Y
>         802.3az - Energy-Efficient Ethernet (EEE): N
>         AV features: N
>         Checksum Offload in TX: Y
>         IP Checksum Offload (type1) in RX: N
>         IP Checksum Offload (type2) in RX: Y
>         RXFIFO > 2048bytes: Y
>         Number of Additional RX channel: 0
>         Number of Additional TX channel: 0
>         Enhanced descriptors: Y
>
> Given the number of different failure modes, my feeling is that there
> are multiple regressions coming with these patches...
>
> I've tested on the IOT2000 board, but I suspect the Galileo Gen2 will be
> affected equally. If you don't have access to any such device, let me
> know what I can debug for you.

JFYI: With today's linux-next when _kexec:ed_ kernel boots I tried and
got the following:


# ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferre[  130.403995] random: fast init done
d_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
   link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
   link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
4: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
   link/sit 0.0.0.0 brd 0.0.0.0
# udhcpc -i eth0
udhcpc: started, v1.26.2
[  140.825131] stmmaceth 0000:00:14.6 eth0: device MAC address 98:4f:ee:05:ac:47
[  140.834304] Generic PHY stmmac-a6:01: attached PHY driver [Generic
PHY] (mii_bus:phy_addr=stmmac-a6:01, irq=-1)
[  140.930871] stmmaceth 0000:00:14.6 eth0: IEEE 1588-2008 Advanced
Timestamp supported
[  140.941109] stmmaceth 0000:00:14.6 eth0: registered PTP clock
[  140.953626] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
udhcpc: sending discover
[  142.979557] stmmaceth 0000:00:14.6 eth0: Link is Up - 100Mbps/Full
- flow control off
[  142.988756] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[  142.998810] BUG: unable to handle kernel NULL pointer dereference at   (null)
[  143.006193] IP: stmmac_xmit+0xf1/0x1080
[  143.010168] *pde = 00000000
[  143.010177]
[  143.014762] Oops: 0002 [#1]
[  143.017672] Modules linked in: at24 nvmem_core pwm_pca9685
[  143.023338] CPU: 0 PID: 0 Comm: swapper Not tainted 4.11.0-next-20170508+ #2
[  143.030539] task: c8533580 task.stack: c852c000
[  143.035237] EIP: stmmac_xmit+0xf1/0x1080
[  143.039302] EFLAGS: 00010216 CPU: 0
[  143.042915] EAX: 00000000 EBX: 00000050 ECX: 00000000 EDX: ceb6a0c0
[  143.049326] ESI: 00000000 EDI: cdd16000 EBP: cdc25d70 ESP: cdc25d20
[  143.055735]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
[  143.061271] CR0: 80050033 CR2: 00000000 CR3: 0eb5c000 CR4: 00100010
[  143.067671] Call Trace:
[  143.070238]  <SOFTIRQ>
[  143.072763]  dev_hard_start_xmit+0x7c/0x1a0
[  143.077120]  sch_direct_xmit+0xf0/0x120
[  143.081130]  __dev_queue_xmit+0x181/0x430
[  143.085311]  ? eth_commit_mac_addr_change+0x20/0x20
[  143.090362]  dev_queue_xmit+0xa/0x10
[  143.094100]  neigh_resolve_output+0xdb/0x190
[  143.098561]  ip6_finish_output2+0x184/0x500
[  143.102945]  ip6_finish_output+0x91/0xe0
[  143.107057]  ? ip6_finish_output+0x91/0xe0
[  143.111338]  ip6_output+0x36/0x110
[  143.114924]  ? ip6_fragment+0xb00/0xb00
[  143.118935]  mld_sendpack+0x191/0x2b0
[  143.122769]  ? mld_newpack+0xda/0x180
[  143.126598]  ? ipv6_icmp_sysctl_init+0x30/0x30
[  143.131224]  mld_ifc_timer_expire+0x158/0x240
[  143.135756]  ? find_next_bit+0xa/0x10
[  143.139584]  ? mld_dad_timer_expire+0x50/0x50
[  143.144112]  call_timer_fn+0x2a/0xf0
[  143.147862]  ? mld_dad_timer_expire+0x50/0x50
[  143.152395]  run_timer_softirq+0x158/0x300
[  143.156668]  ? file_free_rcu+0x1e/0x30
[  143.160589]  __do_softirq+0xc4/0x200
[  143.164341]  ? __hrtimer_tasklet_trampoline+0x30/0x30
[  143.169575]  do_softirq_own_stack+0x1e/0x30
[  143.173902]  </SOFTIRQ>
[  143.176502]  irq_exit+0x95/0xa0
[  143.179812]  smp_apic_timer_interrupt+0x31/0x40
[  143.184530]  apic_timer_interrupt+0x32/0x40
[  143.188889] EIP: default_idle+0xc/0x70
[  143.192774] EFLAGS: 00000246 CPU: 0
[  143.196386] EAX: 00000000 EBX: 00000000 ECX: 00000001 EDX: 00000000
[  143.202795] ESI: 00000000 EDI: c8533580 EBP: c852df54 ESP: c852df4c
[  143.209205]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
[  143.214780]  arch_cpu_idle+0x9/0x10
[  143.218446]  default_idle_call+0x17/0x30
[  143.222551]  do_idle+0xed/0x130
[  143.225873]  cpu_startup_entry+0x15/0x20
[  143.229965]  rest_init+0x5c/0x60
[  143.233370]  start_kernel+0x313/0x318
[  143.237221]  i386_start_kernel+0x98/0x9c
[  143.241315]  startup_32_smp+0x16b/0x16d
[  143.245289] Code: 84 45 06 00 00 c1 e2 05 03 94 c7 9c 09 00 00 89
55 b0 8b 45 c8 8b 75 bc 8b 55 d8 8d 1c 80 89
75 e4 c1 e3 03 8b 84 1f a4 09 00 00 <89> 14 b0 8b 87 40 0d 00 00 8b 40
24 85 c0 89 45 b8 0f 85 68 02
[  143.264746] EIP: stmmac_xmit+0xf1/0x1080 SS:ESP: 0068:cdc25d20
[  143.270727] CR2: 0000000000000000
[  143.274175] ---[ end trace 79da8ef70f8b98d7 ]---
[  143.278925] Kernel panic - not syncing: Fatal exception in interrupt
[  143.285433] Kernel Offset: 0x6a00000 from 0xc1000000 (relocation
range: 0xc0000000-0xd05effff)
[  143.294268] ---[ end Kernel panic - not syncing: Fatal exception in interrupt
Joao Pinto May 8, 2017, 9:54 a.m. UTC | #3
Hi Andy and Jan,

Às 10:36 AM de 5/8/2017, Andy Shevchenko escreveu:
> On Mon, May 8, 2017 at 9:56 AM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>> On 2017-03-15 12:04, Joao Pinto wrote:
>>> This patch prepares DMA Operation Mode configuration for multiple queues.
>>> The work consisted on breaking the DMA operation Mode configuration function
>>> into RX and TX scope and adapting its mechanism in stmmac_main.
> 
>> Starting with this patch, the stmmac-based network adapters of the Intel
>> Quark SoC stop working. I'm getting an IP via DHCP, I can ping, but TCP
>> connections can no longer be established.
>>
>> Moving on a few patches (didn't bisect the exact one yet), the TX
>> watchdog starts to fire, and DHCP fails completely. And if I go to
>> current master in Linus tree (reverting an unrelated boot regression), I
>> even get a crash in stmmac_xmit.
>>
>> Here are some details about the hw from dma_cap POV, if this helps:
>>
>> ==============================
>>         DMA HW features
>> ==============================
>>         10/100 Mbps: Y
>>         1000 Mbps: N
>>         Half duplex: Y
>>         Hash Filter: Y
>>         Multiple MAC address registers: N
>>         PCS (TBI/SGMII/RTBI PHY interfaces): N
>>         SMA (MDIO) Interface: Y
>>         PMT Remote wake up: N
>>         PMT Magic Frame: N
>>         RMON module: Y
>>         IEEE 1588-2002 Time Stamp: N
>>         IEEE 1588-2008 Advanced Time Stamp: Y
>>         802.3az - Energy-Efficient Ethernet (EEE): N
>>         AV features: N
>>         Checksum Offload in TX: Y
>>         IP Checksum Offload (type1) in RX: N
>>         IP Checksum Offload (type2) in RX: Y
>>         RXFIFO > 2048bytes: Y
>>         Number of Additional RX channel: 0
>>         Number of Additional TX channel: 0
>>         Enhanced descriptors: Y
>>
>> Given the number of different failure modes, my feeling is that there
>> are multiple regressions coming with these patches...
>>
>> I've tested on the IOT2000 board, but I suspect the Galileo Gen2 will be
>> affected equally. If you don't have access to any such device, let me
>> know what I can debug for you.
> 
> JFYI: With today's linux-next when _kexec:ed_ kernel boots I tried and
> got the following:
> 
> 
> # ip a s
> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
>    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
>    inet 127.0.0.1/8 scope host lo
>       valid_lft forever preferred_lft forever
>    inet6 ::1/128 scope host
>       valid_lft forever preferre[  130.403995] random: fast init done
> d_lft forever
> 2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
>    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
> 3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
>    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
> 4: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
>    link/sit 0.0.0.0 brd 0.0.0.0
> # udhcpc -i eth0
> udhcpc: started, v1.26.2
> [  140.825131] stmmaceth 0000:00:14.6 eth0: device MAC address 98:4f:ee:05:ac:47
> [  140.834304] Generic PHY stmmac-a6:01: attached PHY driver [Generic
> PHY] (mii_bus:phy_addr=stmmac-a6:01, irq=-1)
> [  140.930871] stmmaceth 0000:00:14.6 eth0: IEEE 1588-2008 Advanced
> Timestamp supported
> [  140.941109] stmmaceth 0000:00:14.6 eth0: registered PTP clock
> [  140.953626] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
> udhcpc: sending discover
> [  142.979557] stmmaceth 0000:00:14.6 eth0: Link is Up - 100Mbps/Full
> - flow control off
> [  142.988756] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
> [  142.998810] BUG: unable to handle kernel NULL pointer dereference at   (null)
> [  143.006193] IP: stmmac_xmit+0xf1/0x1080
> [  143.010168] *pde = 00000000
> [  143.010177]
> [  143.014762] Oops: 0002 [#1]
> [  143.017672] Modules linked in: at24 nvmem_core pwm_pca9685
> [  143.023338] CPU: 0 PID: 0 Comm: swapper Not tainted 4.11.0-next-20170508+ #2
> [  143.030539] task: c8533580 task.stack: c852c000
> [  143.035237] EIP: stmmac_xmit+0xf1/0x1080
> [  143.039302] EFLAGS: 00010216 CPU: 0
> [  143.042915] EAX: 00000000 EBX: 00000050 ECX: 00000000 EDX: ceb6a0c0
> [  143.049326] ESI: 00000000 EDI: cdd16000 EBP: cdc25d70 ESP: cdc25d20
> [  143.055735]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
> [  143.061271] CR0: 80050033 CR2: 00000000 CR3: 0eb5c000 CR4: 00100010
> [  143.067671] Call Trace:
> [  143.070238]  <SOFTIRQ>
> [  143.072763]  dev_hard_start_xmit+0x7c/0x1a0
> [  143.077120]  sch_direct_xmit+0xf0/0x120
> [  143.081130]  __dev_queue_xmit+0x181/0x430
> [  143.085311]  ? eth_commit_mac_addr_change+0x20/0x20
> [  143.090362]  dev_queue_xmit+0xa/0x10
> [  143.094100]  neigh_resolve_output+0xdb/0x190
> [  143.098561]  ip6_finish_output2+0x184/0x500
> [  143.102945]  ip6_finish_output+0x91/0xe0
> [  143.107057]  ? ip6_finish_output+0x91/0xe0
> [  143.111338]  ip6_output+0x36/0x110
> [  143.114924]  ? ip6_fragment+0xb00/0xb00
> [  143.118935]  mld_sendpack+0x191/0x2b0
> [  143.122769]  ? mld_newpack+0xda/0x180
> [  143.126598]  ? ipv6_icmp_sysctl_init+0x30/0x30
> [  143.131224]  mld_ifc_timer_expire+0x158/0x240
> [  143.135756]  ? find_next_bit+0xa/0x10
> [  143.139584]  ? mld_dad_timer_expire+0x50/0x50
> [  143.144112]  call_timer_fn+0x2a/0xf0
> [  143.147862]  ? mld_dad_timer_expire+0x50/0x50
> [  143.152395]  run_timer_softirq+0x158/0x300
> [  143.156668]  ? file_free_rcu+0x1e/0x30
> [  143.160589]  __do_softirq+0xc4/0x200
> [  143.164341]  ? __hrtimer_tasklet_trampoline+0x30/0x30
> [  143.169575]  do_softirq_own_stack+0x1e/0x30
> [  143.173902]  </SOFTIRQ>
> [  143.176502]  irq_exit+0x95/0xa0
> [  143.179812]  smp_apic_timer_interrupt+0x31/0x40
> [  143.184530]  apic_timer_interrupt+0x32/0x40
> [  143.188889] EIP: default_idle+0xc/0x70
> [  143.192774] EFLAGS: 00000246 CPU: 0
> [  143.196386] EAX: 00000000 EBX: 00000000 ECX: 00000001 EDX: 00000000
> [  143.202795] ESI: 00000000 EDI: c8533580 EBP: c852df54 ESP: c852df4c
> [  143.209205]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
> [  143.214780]  arch_cpu_idle+0x9/0x10
> [  143.218446]  default_idle_call+0x17/0x30
> [  143.222551]  do_idle+0xed/0x130
> [  143.225873]  cpu_startup_entry+0x15/0x20
> [  143.229965]  rest_init+0x5c/0x60
> [  143.233370]  start_kernel+0x313/0x318
> [  143.237221]  i386_start_kernel+0x98/0x9c
> [  143.241315]  startup_32_smp+0x16b/0x16d
> [  143.245289] Code: 84 45 06 00 00 c1 e2 05 03 94 c7 9c 09 00 00 89
> 55 b0 8b 45 c8 8b 75 bc 8b 55 d8 8d 1c 80 89
> 75 e4 c1 e3 03 8b 84 1f a4 09 00 00 <89> 14 b0 8b 87 40 0d 00 00 8b 40
> 24 85 c0 89 45 b8 0f 85 68 02
> [  143.264746] EIP: stmmac_xmit+0xf1/0x1080 SS:ESP: 0068:cdc25d20
> [  143.270727] CR2: 0000000000000000
> [  143.274175] ---[ end trace 79da8ef70f8b98d7 ]---
> [  143.278925] Kernel panic - not syncing: Fatal exception in interrupt
> [  143.285433] Kernel Offset: 0x6a00000 from 0xc1000000 (relocation
> range: 0xc0000000-0xd05effff)
> [  143.294268] ---[ end Kernel panic - not syncing: Fatal exception in interrupt
> 
> 

Are you using the same version of Ethernet IP, 10/100?
Could you please verify if the crash you are experiencing is this place?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c#n2956

I would say that for rather old IPs, the napi is not capable of giving a valid
queue number. Could you please print the queue index returned by this line?

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c#n2948

Thank you.

Joao Pinto
diff mbox

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 9f0d26d..13bd3d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -424,6 +424,9 @@  struct stmmac_dma_ops {
 	 * An invalid value enables the store-and-forward mode */
 	void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
 			 int rxfifosz);
+	void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
+			    int fifosz);
+	void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel);
 	/* To track extra statistic (if supported) */
 	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
 				   void __iomem *ioaddr);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 6ac6b26..6285e8a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -182,70 +182,26 @@  static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
 		writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(i));
 }
 
-static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
-				    int rxmode, u32 channel, int rxfifosz)
+static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
+				       u32 channel, int fifosz)
 {
-	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
-	 * supported.
-	 */
-	mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
-
-	if (txmode == SF_DMA_MODE) {
-		pr_debug("GMAC: enable TX store and forward mode\n");
-		/* Transmit COE type 2 cannot be done in cut-through mode. */
-		mtl_tx_op |= MTL_OP_MODE_TSF;
-	} else {
-		pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
-		mtl_tx_op &= ~MTL_OP_MODE_TSF;
-		mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
-		/* Set the transmit threshold */
-		if (txmode <= 32)
-			mtl_tx_op |= MTL_OP_MODE_TTC_32;
-		else if (txmode <= 64)
-			mtl_tx_op |= MTL_OP_MODE_TTC_64;
-		else if (txmode <= 96)
-			mtl_tx_op |= MTL_OP_MODE_TTC_96;
-		else if (txmode <= 128)
-			mtl_tx_op |= MTL_OP_MODE_TTC_128;
-		else if (txmode <= 192)
-			mtl_tx_op |= MTL_OP_MODE_TTC_192;
-		else if (txmode <= 256)
-			mtl_tx_op |= MTL_OP_MODE_TTC_256;
-		else if (txmode <= 384)
-			mtl_tx_op |= MTL_OP_MODE_TTC_384;
-		else
-			mtl_tx_op |= MTL_OP_MODE_TTC_512;
-	}
-	/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
-	 * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
-	 * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
-	 * with reset values: TXQEN off, TQS 256 bytes.
-	 *
-	 * Write the bits in both cases, since it will have no effect when RO.
-	 * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
-	 * be RO, however, writing the whole TQS field will result in a value
-	 * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
-	 */
-	mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
-	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
+	unsigned int rqs = fifosz / 256 - 1;
+	u32 mtl_rx_op, mtl_rx_int;
 
 	mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
 
-	if (rxmode == SF_DMA_MODE) {
+	if (mode == SF_DMA_MODE) {
 		pr_debug("GMAC: enable RX store and forward mode\n");
 		mtl_rx_op |= MTL_OP_MODE_RSF;
 	} else {
-		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
+		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
 		mtl_rx_op &= ~MTL_OP_MODE_RSF;
 		mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
-		if (rxmode <= 32)
+		if (mode <= 32)
 			mtl_rx_op |= MTL_OP_MODE_RTC_32;
-		else if (rxmode <= 64)
+		else if (mode <= 64)
 			mtl_rx_op |= MTL_OP_MODE_RTC_64;
-		else if (rxmode <= 96)
+		else if (mode <= 96)
 			mtl_rx_op |= MTL_OP_MODE_RTC_96;
 		else
 			mtl_rx_op |= MTL_OP_MODE_RTC_128;
@@ -255,7 +211,7 @@  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
 	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) {
+	if (fifosz >= 4096) {
 		unsigned int rfd, rfa;
 
 		mtl_rx_op |= MTL_OP_MODE_EHFC;
@@ -266,7 +222,7 @@  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
 		 * Set Threshold for Deactivating Flow Control to min 1 frame,
 		 * i.e. 1500 bytes.
 		 */
-		switch (rxfifosz) {
+		switch (fifosz) {
 		case 4096:
 			/* This violates the above formula because of FIFO size
 			 * limit therefore overflow may occur in spite of this.
@@ -306,11 +262,49 @@  static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
 	       ioaddr + MTL_CHAN_INT_CTRL(channel));
 }
 
-static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
-				      int rxmode, int rxfifosz)
+static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
+				       u32 channel)
 {
-	/* Only Channel 0 is actually configured and used */
-	dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0, rxfifosz);
+	u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
+
+	if (mode == SF_DMA_MODE) {
+		pr_debug("GMAC: enable TX store and forward mode\n");
+		/* Transmit COE type 2 cannot be done in cut-through mode. */
+		mtl_tx_op |= MTL_OP_MODE_TSF;
+	} else {
+		pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
+		mtl_tx_op &= ~MTL_OP_MODE_TSF;
+		mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
+		/* Set the transmit threshold */
+		if (mode <= 32)
+			mtl_tx_op |= MTL_OP_MODE_TTC_32;
+		else if (mode <= 64)
+			mtl_tx_op |= MTL_OP_MODE_TTC_64;
+		else if (mode <= 96)
+			mtl_tx_op |= MTL_OP_MODE_TTC_96;
+		else if (mode <= 128)
+			mtl_tx_op |= MTL_OP_MODE_TTC_128;
+		else if (mode <= 192)
+			mtl_tx_op |= MTL_OP_MODE_TTC_192;
+		else if (mode <= 256)
+			mtl_tx_op |= MTL_OP_MODE_TTC_256;
+		else if (mode <= 384)
+			mtl_tx_op |= MTL_OP_MODE_TTC_384;
+		else
+			mtl_tx_op |= MTL_OP_MODE_TTC_512;
+	}
+	/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
+	 * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
+	 * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
+	 * with reset values: TXQEN off, TQS 256 bytes.
+	 *
+	 * Write the bits in both cases, since it will have no effect when RO.
+	 * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
+	 * be RO, however, writing the whole TQS field will result in a value
+	 * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
+	 */
+	mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
+	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
 }
 
 static void dwmac4_get_hw_feature(void __iomem *ioaddr,
@@ -387,7 +381,8 @@  const struct stmmac_dma_ops dwmac4_dma_ops = {
 	.init = dwmac4_dma_init,
 	.axi = dwmac4_dma_axi,
 	.dump_regs = dwmac4_dump_dma_regs,
-	.dma_mode = dwmac4_dma_operation_mode,
+	.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
+	.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
 	.enable_dma_irq = dwmac4_enable_dma_irq,
 	.disable_dma_irq = dwmac4_disable_dma_irq,
 	.start_tx = dwmac4_dma_start_tx,
@@ -409,7 +404,8 @@  const struct stmmac_dma_ops dwmac410_dma_ops = {
 	.init = dwmac4_dma_init,
 	.axi = dwmac4_dma_axi,
 	.dump_regs = dwmac4_dump_dma_regs,
-	.dma_mode = dwmac4_dma_operation_mode,
+	.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
+	.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
 	.enable_dma_irq = dwmac410_enable_dma_irq,
 	.disable_dma_irq = dwmac4_disable_dma_irq,
 	.start_tx = dwmac4_dma_start_tx,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ec363e1..c4e4a53 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1285,14 +1285,20 @@  static void stmmac_mac_enable_rx_queues(struct stmmac_priv *priv)
  */
 static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 {
+	u32 rx_channels_count = priv->plat->rx_queues_to_use;
+	u32 tx_channels_count = priv->plat->tx_queues_to_use;
 	int rxfifosz = priv->plat->rx_fifo_size;
+	u32 txmode = 0;
+	u32 rxmode = 0;
+	u32 chan = 0;
 
 	if (rxfifosz == 0)
 		rxfifosz = priv->dma_cap.rx_fifo_size;
 
-	if (priv->plat->force_thresh_dma_mode)
-		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
-	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
+	if (priv->plat->force_thresh_dma_mode) {
+		txmode = tc;
+		rxmode = tc;
+	} else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
 		/*
 		 * In case of GMAC, SF mode can be enabled
 		 * to perform the TX COE in HW. This depends on:
@@ -1300,12 +1306,26 @@  static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 		 * 2) There is no bugged Jumbo frame support
 		 *    that needs to not insert csum in the TDES.
 		 */
-		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE,
-					rxfifosz);
+		txmode = SF_DMA_MODE;
+		rxmode = SF_DMA_MODE;
 		priv->xstats.threshold = SF_DMA_MODE;
-	} else
-		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE,
+	} else {
+		txmode = tc;
+		rxmode = SF_DMA_MODE;
+	}
+
+	/* configure all channels */
+	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+		for (chan = 0; chan < rx_channels_count; chan++)
+			priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
+						   rxfifosz);
+
+		for (chan = 0; chan < tx_channels_count; chan++)
+			priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
+	} else {
+		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
 					rxfifosz);
+	}
 }
 
 /**
@@ -1444,6 +1464,34 @@  static void stmmac_tx_err(struct stmmac_priv *priv)
 }
 
 /**
+ *  stmmac_set_dma_operation_mode - Set DMA operation mode by channel
+ *  @priv: driver private structure
+ *  @txmode: TX operating mode
+ *  @rxmode: RX operating mode
+ *  @chan: channel index
+ *  Description: it is used for configuring of the DMA operation mode in
+ *  runtime in order to program the tx/rx DMA thresholds or Store-And-Forward
+ *  mode.
+ */
+static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
+					  u32 rxmode, u32 chan)
+{
+	int rxfifosz = priv->plat->rx_fifo_size;
+
+	if (rxfifosz == 0)
+		rxfifosz = priv->dma_cap.rx_fifo_size;
+
+	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+		priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
+					   rxfifosz);
+		priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
+	} else {
+		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
+					rxfifosz);
+	}
+}
+
+/**
  * stmmac_dma_interrupt - DMA ISR
  * @priv: driver private structure
  * Description: this is the DMA ISR. It is called by the main ISR.
@@ -1452,11 +1500,8 @@  static void stmmac_tx_err(struct stmmac_priv *priv)
  */
 static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 {
+	u32 chan = STMMAC_CHAN0;
 	int status;
-	int rxfifosz = priv->plat->rx_fifo_size;
-
-	if (rxfifosz == 0)
-		rxfifosz = priv->dma_cap.rx_fifo_size;
 
 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
 	if (likely((status & handle_rx)) || (status & handle_tx)) {
@@ -1471,11 +1516,12 @@  static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 		    (tc <= 256)) {
 			tc += 64;
 			if (priv->plat->force_thresh_dma_mode)
-				priv->hw->dma->dma_mode(priv->ioaddr, tc, tc,
-							rxfifosz);
+				stmmac_set_dma_operation_mode(priv->ioaddr,
+							      tc, tc, chan);
 			else
-				priv->hw->dma->dma_mode(priv->ioaddr, tc,
-							SF_DMA_MODE, rxfifosz);
+				stmmac_set_dma_operation_mode(priv->ioaddr, tc,
+							     SF_DMA_MODE, chan);
+
 			priv->xstats.threshold = tc;
 		}
 	} else if (unlikely(status == tx_hard_error))
@@ -1749,6 +1795,9 @@  static void stmmac_mtl_configuration(struct stmmac_priv *priv)
 	/* Enable MAC RX Queues */
 	if (rx_queues_count > 1 && priv->hw->mac->rx_queue_enable)
 		stmmac_mac_enable_rx_queues(priv);
+
+	/* Set the HW DMA mode and the COE */
+	stmmac_dma_operation_mode(priv);
 }
 
 /**
@@ -1812,9 +1861,6 @@  static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 	else
 		stmmac_set_mac(priv->ioaddr, true);
 
-	/* Set the HW DMA mode and the COE */
-	stmmac_dma_operation_mode(priv);
-
 	stmmac_mmc_setup(priv);
 
 	if (init_ptp) {