Drivers/Net/MarvellYukon: Don't re-use DMA buffers
Change the receive buffers to be single-use only. This involves a few
changes that work together:
1. Change msk_newbuf() to not attempt to re-use or free a buffer,
2. Change msk_rxeof() free the buffer when it is done with it,
3. Store a temporary copy of the received data for passing to
the Receive Queue,
4. Call the required Flush() and Unmap() on the DMA buffer.
In addition this means failure to allocate a new buffer is a failure
of msk_rxeof().
Note that this change makes the driver work the way the FreeBSD driver
(from which this driver was derived) works, and this simply removes an
optimization (the code in msk_newbuf() which re-uses the buffers. This
removal of the optimization is done for two reasons:
1. The optimization failed to work for 64-bit DMA transfers;
2. The UEFI specification, version 2.6, section 13.4 requires calls to
Flush() and Unmap() before reading a DMA write buffer from the CPU,
which doesn't fit with the optimization as it existed.
Reverting back to the behavior as it was in the FreeBSD driver solves
number 1 and 2 above, and makes this driver more consistent with
something we know to be working. There is slightly more overhead, but
it is more consistent with the UEFI standard.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Alan Ott <alan@softiron.co.uk>
[ardb: replaced struct assignment with gBS->CopyMem()]
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
diff --git a/Drivers/Net/MarvellYukonDxe/if_msk.c b/Drivers/Net/MarvellYukonDxe/if_msk.c
index d2102dc..2b505c3 100644
--- a/Drivers/Net/MarvellYukonDxe/if_msk.c
+++ b/Drivers/Net/MarvellYukonDxe/if_msk.c
@@ -581,13 +581,6 @@
rxd = &sc_if->msk_cdata.msk_rxdesc[idx];
- if ((rxd->rx_m.Buf != NULL) && (rxd->rx_m.Length >= Length)) {
- return EFI_ALREADY_STARTED;
- } else if (rxd->rx_m.Buf != NULL) {
- mPciIo->Unmap (mPciIo, rxd->rx_m.DmaMapping);
- mPciIo->FreeBuffer (mPciIo, EFI_SIZE_TO_PAGES (rxd->rx_m.Length), rxd->rx_m.Buf);
- }
-
Status = mPciIo->AllocateBuffer (mPciIo, AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (Length), &Buffer, 0);
if (EFI_ERROR (Status)) {
return Status;
@@ -1848,6 +1841,7 @@
struct msk_rxdesc *rxd;
INTN cons;
INTN rxlen;
+ MSK_DMA_BUF m;
DEBUG ((EFI_D_NET, "Marvell Yukon: rxeof\n"));
@@ -1871,26 +1865,41 @@
break;
}
+ rxd = &sc_if->msk_cdata.msk_rxdesc[cons];
+
+ gBS->CopyMem (&m, &rxd->rx_m, sizeof(m));
+
Status = msk_newbuf (sc_if, cons);
if (EFI_ERROR (Status)) {
+ // This is a dropped packet, but we aren't counting drops
// Reuse old buffer
msk_discard_rxbuf (sc_if, cons);
+ break;
}
+
+ Status = mPciIo->Flush (mPciIo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_NET, "Marvell Yukon: failed to Flush DMA\n"));
+ }
+
+ Status = mPciIo->Unmap (mPciIo, rxd->rx_m.DmaMapping);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_NET, "Marvell Yukon: failed to Unmap DMA\n"));
+ }
+
Status = gBS->AllocatePool (EfiBootServicesData,
sizeof (MSK_LINKED_DMA_BUF),
(VOID**) &m_link);
if (!EFI_ERROR (Status)) {
gBS->SetMem (m_link, sizeof (MSK_LINKED_DMA_BUF), 0);
- rxd = &sc_if->msk_cdata.msk_rxdesc[cons];
-
m_link->Signature = RX_MBUF_SIGNATURE;
Status = gBS->AllocatePool (EfiBootServicesData,
len,
(VOID**) &m_link->DmaBuf.Buf);
if(!EFI_ERROR (Status)) {
- gBS->CopyMem (m_link->DmaBuf.Buf, rxd->rx_m.Buf, len);
+ gBS->CopyMem (m_link->DmaBuf.Buf, m.Buf, len);
m_link->DmaBuf.Length = len;
- m_link->DmaBuf.DmaMapping = rxd->rx_m.DmaMapping;
+ m_link->DmaBuf.DmaMapping = NULL;
InsertTailList (&mSoftc->ReceiveQueueHead, &m_link->Link);
} else {
@@ -1899,6 +1908,8 @@
} else {
DEBUG ((EFI_D_NET, "Marvell Yukon: failed to allocate receive buffer link. Dropping Frame\n"));
}
+
+ mPciIo->FreeBuffer (mPciIo, EFI_SIZE_TO_PAGES (m.Length), m.Buf);
} while (0);
MSK_INC (sc_if->msk_cdata.msk_rx_cons, MSK_RX_RING_CNT);