aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2020-11-26 12:25:02 +0000
committerMichael Brown <mcb30@ipxe.org>2020-11-28 20:26:28 +0000
commit8d337ecdae3c6d555ea57996bc2280debd984a9c (patch)
tree9a572ccfe77432a735a0df76f2a91e5fe93cefcf /src/core
parent70e6e83243b77a3771756106871d6f945062a44b (diff)
downloadipxe-8d337ecdae3c6d555ea57996bc2280debd984a9c.zip
ipxe-8d337ecdae3c6d555ea57996bc2280debd984a9c.tar.gz
ipxe-8d337ecdae3c6d555ea57996bc2280debd984a9c.tar.bz2
[dma] Move I/O buffer DMA operations to iobuf.h
Include a potential DMA mapping within the definition of an I/O buffer, and move all I/O buffer DMA mapping functions from dma.h to iobuf.h. This avoids the need for drivers to maintain a separate list of DMA mappings for each I/O buffer that they may handle. Network device drivers typically do not keep track of transmit I/O buffers, since the network device core already maintains a transmit queue. Drivers will typically call netdev_tx_complete_next() to complete a transmission without first obtaining the relevant I/O buffer pointer (and will rely on the network device core automatically cancelling any pending transmissions when the device is closed). To allow this driver design approach to be retained, update the netdev_tx_complete() family of functions to automatically perform the DMA unmapping operation if required. For symmetry, also update the netdev_rx() family of functions to behave the same way. As a further convenience for drivers, allow the network device core to automatically perform DMA mapping on the transmit datapath before calling the driver's transmit() method. This avoids the need to introduce a mapping error handling code path into the typically error-free transmit methods. With these changes, the modifications required to update a typical network device driver to use the new DMA API are fairly minimal: - Allocate and free descriptor rings and similar coherent structures using dma_alloc()/dma_free() rather than malloc_phys()/free_phys() - Allocate and free receive buffers using alloc_rx_iob()/free_rx_iob() rather than alloc_iob()/free_iob() - Calculate DMA addresses using dma() or iob_dma() rather than virt_to_bus() - Set a 64-bit DMA mask if needed using dma_set_mask_64bit() and thereafter eliminate checks on DMA address ranges - Either record the DMA device in netdev->dma, or call iob_map_tx() as part of the transmit() method - Ensure that debug messages use virt_to_phys() when displaying "hardware" addresses Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/dma.c41
-rw-r--r--src/core/iobuf.c45
2 files changed, 45 insertions, 41 deletions
diff --git a/src/core/dma.c b/src/core/dma.c
index 561aec1..e5fa3f3 100644
--- a/src/core/dma.c
+++ b/src/core/dma.c
@@ -25,7 +25,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <errno.h>
-#include <ipxe/iobuf.h>
#include <ipxe/dma.h>
/** @file
@@ -139,43 +138,3 @@ PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc );
PROVIDE_DMAAPI ( op, dma_free, dma_op_free );
PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask );
PROVIDE_DMAAPI_INLINE ( op, dma_phys );
-
-/******************************************************************************
- *
- * Utility functions
- *
- ******************************************************************************
- */
-
-/**
- * Allocate and map I/O buffer for receiving data from device
- *
- * @v dma DMA device
- * @v map DMA mapping to fill in
- * @v len Length of I/O buffer
- * @ret iobuf I/O buffer, or NULL on error
- */
-struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma,
- struct dma_mapping *map,
- size_t len ) {
- struct io_buffer *iobuf;
- int rc;
-
- /* Allocate I/O buffer */
- iobuf = alloc_iob ( len );
- if ( ! iobuf )
- goto err_alloc;
-
- /* Map I/O buffer */
- if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ),
- len, DMA_RX ) ) != 0 )
- goto err_map;
-
- return iobuf;
-
- dma_unmap ( map );
- err_map:
- free_iob ( iobuf );
- err_alloc:
- return NULL;
-}
diff --git a/src/core/iobuf.c b/src/core/iobuf.c
index 941bb34..c9970bc 100644
--- a/src/core/iobuf.c
+++ b/src/core/iobuf.c
@@ -110,6 +110,7 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) {
}
/* Populate descriptor */
+ memset ( &iobuf->map, 0, sizeof ( iobuf->map ) );
iobuf->head = iobuf->data = iobuf->tail = data;
iobuf->end = ( data + len );
@@ -153,6 +154,7 @@ void free_iob ( struct io_buffer *iobuf ) {
assert ( iobuf->head <= iobuf->data );
assert ( iobuf->data <= iobuf->tail );
assert ( iobuf->tail <= iobuf->end );
+ assert ( ! dma_mapped ( &iobuf->map ) );
/* Free buffer */
len = ( iobuf->end - iobuf->head );
@@ -170,6 +172,49 @@ void free_iob ( struct io_buffer *iobuf ) {
}
/**
+ * Allocate and map I/O buffer for receive DMA
+ *
+ * @v len Length of I/O buffer
+ * @v dma DMA device
+ * @ret iobuf I/O buffer, or NULL on error
+ */
+struct io_buffer * alloc_rx_iob ( size_t len, struct dma_device *dma ) {
+ struct io_buffer *iobuf;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf )
+ goto err_alloc;
+
+ /* Map I/O buffer */
+ if ( ( rc = iob_map_rx ( iobuf, dma ) ) != 0 )
+ goto err_map;
+
+ return iobuf;
+
+ iob_unmap ( iobuf );
+ err_map:
+ free_iob ( iobuf );
+ err_alloc:
+ return NULL;
+}
+
+/**
+ * Unmap and free I/O buffer for receive DMA
+ *
+ * @v iobuf I/O buffer
+ */
+void free_rx_iob ( struct io_buffer *iobuf ) {
+
+ /* Unmap I/O buffer */
+ iob_unmap ( iobuf );
+
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+}
+
+/**
* Ensure I/O buffer has sufficient headroom
*
* @v iobuf I/O buffer