| From foo@baz Sun May 27 17:33:38 CEST 2018 |
| From: Niklas Cassel <niklas.cassel@axis.com> |
| Date: Mon, 26 Feb 2018 22:47:06 +0100 |
| Subject: net: stmmac: ensure that the MSS desc is the last desc to set the own bit |
| |
| From: Niklas Cassel <niklas.cassel@axis.com> |
| |
| [ Upstream commit 15d2ee42a3087089e73ad52fd8c1b37ab496b87c ] |
| |
| A dma_wmb() is used to guarantee the ordering, with respect to |
| other writes, to cache coherent DMA memory. |
| |
| There is a dma_wmb() in prepare_tx_desc()/prepare_tso_tx_desc() which |
| ensures that TDES0/1/2 is written before TDES3 (which contains the own |
| bit), for First Desc. |
| |
| However, in the rare case that MSS changes, there will be a MSS |
| context descriptor in front of the regular DMA descriptors: |
| |
| <MSS desc> <- DMA Next Descriptor |
| <First Desc> |
| <desc n> |
| <Last Desc> |
| |
| Thus, for this special case, we need a dma_wmb() |
| after prepare_tso_tx_desc()/before writing the own bit to the MSS desc, |
| so that we flush the write to TDES3 for First Desc, |
| in order to ensure that the MSS descriptor is the last descriptor to |
| set the own bit. |
| |
| Signed-off-by: Niklas Cassel <niklas.cassel@axis.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 ++++++++- |
| 1 file changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |
| +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |
| @@ -2141,8 +2141,15 @@ static netdev_tx_t stmmac_tso_xmit(struc |
| tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len)); |
| |
| /* If context desc is used to change MSS */ |
| - if (mss_desc) |
| + if (mss_desc) { |
| + /* Make sure that first descriptor has been completely |
| + * written, including its own bit. This is because MSS is |
| + * actually before first descriptor, so we need to make |
| + * sure that MSS's own bit is the last thing written. |
| + */ |
| + dma_wmb(); |
| priv->hw->desc->set_tx_owner(mss_desc); |
| + } |
| |
| /* The own bit must be the latest setting done when prepare the |
| * descriptor and then barrier is needed to make sure that |