| From foo@baz Tue May 22 21:05:16 CEST 2018 |
| From: "hpreg@vmware.com" <hpreg@vmware.com> |
| Date: Mon, 14 May 2018 08:14:49 -0400 |
| Subject: vmxnet3: use DMA memory barriers where required |
| |
| From: "hpreg@vmware.com" <hpreg@vmware.com> |
| |
| [ Upstream commit f3002c1374fb2367c9d8dbb28852791ef90d2bac ] |
| |
| The gen bits must be read first from (resp. written last to) DMA memory. |
| The proper way to enforce this on Linux is to call dma_rmb() (resp. |
| dma_wmb()). |
| |
| Signed-off-by: Regis Duchesne <hpreg@vmware.com> |
| Acked-by: Ronak Doshi <doshir@vmware.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/vmxnet3/vmxnet3_drv.c | 22 ++++++++++++++++++++++ |
| 1 file changed, 22 insertions(+) |
| |
| --- a/drivers/net/vmxnet3/vmxnet3_drv.c |
| +++ b/drivers/net/vmxnet3/vmxnet3_drv.c |
| @@ -369,6 +369,11 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx |
| |
| gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; |
| while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) { |
| + /* Prevent any &gdesc->tcd field from being (speculatively) |
| + * read before (&gdesc->tcd)->gen is read. |
| + */ |
| + dma_rmb(); |
| + |
| completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX( |
| &gdesc->tcd), tq, adapter->pdev, |
| adapter); |
| @@ -1099,6 +1104,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, str |
| gdesc->txd.tci = skb_vlan_tag_get(skb); |
| } |
| |
| + /* Ensure that the write to (&gdesc->txd)->gen will be observed after |
| + * all other writes to &gdesc->txd. |
| + */ |
| + dma_wmb(); |
| + |
| /* finally flips the GEN bit of the SOP desc. */ |
| gdesc->dword[2] = cpu_to_le32(le32_to_cpu(gdesc->dword[2]) ^ |
| VMXNET3_TXD_GEN); |
| @@ -1286,6 +1296,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx |
| */ |
| break; |
| } |
| + |
| + /* Prevent any rcd field from being (speculatively) read before |
| + * rcd->gen is read. |
| + */ |
| + dma_rmb(); |
| + |
| BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2 && |
| rcd->rqID != rq->dataRingQid); |
| idx = rcd->rxdIdx; |
| @@ -1515,6 +1531,12 @@ rcd_done: |
| ring->next2comp = idx; |
| num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring); |
| ring = rq->rx_ring + ring_idx; |
| + |
| + /* Ensure that the writes to rxd->gen bits will be observed |
| + * after all other writes to rxd objects. |
| + */ |
| + dma_wmb(); |
| + |
| while (num_to_alloc) { |
| vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd, |
| &rxCmdDesc); |