Commit 28d9fab4 authored by Esben Haabendal's avatar Esben Haabendal Committed by David S. Miller

net: ll_temac: Add memory-barriers for TX BD access

Add a couple of memory-barriers to ensure correct ordering of read/write
access to TX BDs.

In xmit_done, we should ensure that reading the additional BD fields are
only done after STS_CTRL_APP0_CMPLT bit is set.

When xmit_done marks the BD as free by setting APP0=0, we need to ensure
that the other BD fields are reset first, so we avoid racing with the xmit
path, which writes to the same fields.

Finally, making sure to read APP0 of next BD after the current BD, ensures
that we see all available buffers.
Signed-off-by: default avatarEsben Haabendal <esben@geanix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6aa32217
...@@ -774,12 +774,15 @@ static void temac_start_xmit_done(struct net_device *ndev) ...@@ -774,12 +774,15 @@ static void temac_start_xmit_done(struct net_device *ndev)
stat = be32_to_cpu(cur_p->app0); stat = be32_to_cpu(cur_p->app0);
while (stat & STS_CTRL_APP0_CMPLT) { while (stat & STS_CTRL_APP0_CMPLT) {
/* Make sure that the other fields are read after bd is
* released by dma
*/
rmb();
dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys), dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
be32_to_cpu(cur_p->len), DMA_TO_DEVICE); be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
skb = (struct sk_buff *)ptr_from_txbd(cur_p); skb = (struct sk_buff *)ptr_from_txbd(cur_p);
if (skb) if (skb)
dev_consume_skb_irq(skb); dev_consume_skb_irq(skb);
cur_p->app0 = 0;
cur_p->app1 = 0; cur_p->app1 = 0;
cur_p->app2 = 0; cur_p->app2 = 0;
cur_p->app3 = 0; cur_p->app3 = 0;
...@@ -788,6 +791,12 @@ static void temac_start_xmit_done(struct net_device *ndev) ...@@ -788,6 +791,12 @@ static void temac_start_xmit_done(struct net_device *ndev)
ndev->stats.tx_packets++; ndev->stats.tx_packets++;
ndev->stats.tx_bytes += be32_to_cpu(cur_p->len); ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
/* app0 must be visible last, as it is used to flag
* availability of the bd
*/
smp_mb();
cur_p->app0 = 0;
lp->tx_bd_ci++; lp->tx_bd_ci++;
if (lp->tx_bd_ci >= lp->tx_bd_num) if (lp->tx_bd_ci >= lp->tx_bd_num)
lp->tx_bd_ci = 0; lp->tx_bd_ci = 0;
...@@ -814,6 +823,9 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) ...@@ -814,6 +823,9 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
if (cur_p->app0) if (cur_p->app0)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
/* Make sure to read next bd app0 after this one */
rmb();
tail++; tail++;
if (tail >= lp->tx_bd_num) if (tail >= lp->tx_bd_num)
tail = 0; tail = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment