Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1590670 authored by Alexey Brodkin's avatar Alexey Brodkin Committed by David S. Miller
Browse files

stmmac: troubleshoot unexpected bits in des0 & des1



Current implementation of descriptor init procedure only takes
care about setting/clearing ownership flag in "des0"/"des1"
fields while it is perfectly possible to get unexpected bits
set because of the following factors:

 [1] On driver probe underlying memory allocated with
     dma_alloc_coherent() might not be zeroed and so
     it will be filled with garbage.

 [2] During driver operation some bits could be set by SD/MMC
     controller (for example error flags etc).

And unexpected and/or randomly set flags in "des0"/"des1"
fields may lead to unpredictable behavior of GMAC DMA block.

This change addresses both items above with:

 [1] Use of dma_zalloc_coherent() instead of simple
     dma_alloc_coherent() to make sure allocated memory is
     zeroed. That shouldn't affect performance because
     this allocation only happens once on driver probe.

 [2] Do explicit zeroing of both "des0" and "des1" fields
     of all buffer descriptors during initialization of
     DMA transfer.

And while at it fixed identation of dma_free_coherent()
counterpart as well.

Signed-off-by: default avatarAlexey Brodkin <abrodkin@synopsys.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: arc-linux-dev@synopsys.com
Cc: linux-kernel@vger.kernel.org
Cc: stable@vger.kernel.org
Cc: David Miller <davem@davemloft.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 34b99df4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -158,6 +158,8 @@ struct dma_desc {
			u32 buffer2_size:13;
			u32 reserved4:3;
		} etx;		/* -- enhanced -- */

		u64 all_flags;
	} des01;
	unsigned int des2;
	unsigned int des3;
+2 −1
Original line number Diff line number Diff line
@@ -240,6 +240,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
				  int mode, int end)
{
	p->des01.all_flags = 0;
	p->des01.erx.own = 1;
	p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;

@@ -254,7 +255,7 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,

static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
	p->des01.etx.own = 0;
	p->des01.all_flags = 0;
	if (mode == STMMAC_CHAIN_MODE)
		ehn_desc_tx_set_on_chain(p, end);
	else
+2 −1
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
			       int end)
{
	p->des01.all_flags = 0;
	p->des01.rx.own = 1;
	p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;

@@ -137,7 +138,7 @@ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,

static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
	p->des01.tx.own = 0;
	p->des01.all_flags = 0;
	if (mode == STMMAC_CHAIN_MODE)
		ndesc_tx_set_on_chain(p, end);
	else
+22 −22
Original line number Diff line number Diff line
@@ -1189,7 +1189,7 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
		goto err_tx_skbuff;

	if (priv->extend_desc) {
		priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
		priv->dma_erx = dma_zalloc_coherent(priv->device, rxsize *
						    sizeof(struct
							   dma_extended_desc),
						    &priv->dma_rx_phy,
@@ -1197,7 +1197,7 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
		if (!priv->dma_erx)
			goto err_dma;

		priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
		priv->dma_etx = dma_zalloc_coherent(priv->device, txsize *
						    sizeof(struct
							   dma_extended_desc),
						    &priv->dma_tx_phy,
@@ -1209,14 +1209,14 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
			goto err_dma;
		}
	} else {
		priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
		priv->dma_rx = dma_zalloc_coherent(priv->device, rxsize *
						   sizeof(struct dma_desc),
						   &priv->dma_rx_phy,
						   GFP_KERNEL);
		if (!priv->dma_rx)
			goto err_dma;

		priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
		priv->dma_tx = dma_zalloc_coherent(priv->device, txsize *
						   sizeof(struct dma_desc),
						   &priv->dma_tx_phy,
						   GFP_KERNEL);