Commit Graph

5 Commits (814aef68c51503d53d07832bf882302bc75aa4bb)

Author SHA1 Message Date
Michael Brown 6e01b74a8a [dma] Provide dma_umalloc() for allocating large DMA-coherent buffers
Some devices (e.g. xHCI USB host controllers) may require the use of
large areas of host memory for private use by the device.  These
allocations cannot be satisfied from iPXE's limited heap space, and so
are currently allocated using umalloc() which will allocate external
system memory (and alter the system memory map as needed).

Provide dma_umalloc() to provide such allocations as part of the DMA
API, since there is otherwise no way to guarantee that the allocated
regions are usable for coherent DMA.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-29 11:25:40 +00:00
Michael Brown 8d337ecdae [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>
2020-11-28 20:26:28 +00:00
Michael Brown 70e6e83243 [dma] Record DMA device as part of DMA mapping if needed
Allow for dma_unmap() to be called by code other than the DMA device
driver itself.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-28 18:56:50 +00:00
Michael Brown cf12a41703 [dma] Modify DMA API to simplify calculation of medial addresses
Redefine the value stored within a DMA mapping to be the offset
between physical addresses and DMA addresses within the mapped region.

Provide a dma() wrapper function to calculate the DMA address for any
pointer within a mapped region, thereby simplifying the use cases when
a device needs to be given addresses other than the region start
address.

On a platform using the "flat" DMA implementation the DMA offset for
any mapped region is always zero, with the result that dma_map() can
be optimised away completely and dma() reduces to a straightforward
call to virt_to_phys().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-25 16:15:55 +00:00
Michael Brown dda03c884d [dma] Define a DMA API to allow for non-flat device address spaces
iPXE currently assumes that DMA-capable devices can directly address
physical memory using host addresses.  This assumption fails when
using an IOMMU.

Define an internal DMA API with two implementations: a "flat"
implementation for use in legacy BIOS or other environments in which
flat physical addressing is guaranteed to be used and all allocated
physical addresses are guaranteed to be within a 32-bit address space,
and an "operations-based" implementation for use in UEFI or other
environments in which DMA mapping may require bus-specific handling.

The purpose of the fully inlined "flat" implementation is to allow the
trivial identity DMA mappings to be optimised out at build time,
thereby avoiding an increase in code size for legacy BIOS builds.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2020-11-05 20:03:50 +00:00