From be1c87b72237f633c4f4b05bcb133acf2967d788 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 5 Nov 2020 19:08:48 +0000 Subject: [malloc] Rename malloc_dma() to malloc_phys() The malloc_dma() function allocates memory with specified physical alignment, and is typically (though not exclusively) used to allocate memory for DMA. Rename to malloc_phys() to more closely match the functionality, and to create name space for functions that specifically allocate and map DMA-capable buffers. Signed-off-by: Michael Brown --- src/core/iobuf.c | 12 ++++++------ src/core/malloc.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core') diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 0ee53e038..941bb3446 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -88,8 +88,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) ); /* Allocate memory for buffer plus descriptor */ - data = malloc_dma_offset ( len + sizeof ( *iobuf ), align, - offset ); + data = malloc_phys_offset ( len + sizeof ( *iobuf ), align, + offset ); if ( ! data ) return NULL; iobuf = ( data + len ); @@ -97,14 +97,14 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { } else { /* Allocate memory for buffer */ - data = malloc_dma_offset ( len, align, offset ); + data = malloc_phys_offset ( len, align, offset ); if ( ! data ) return NULL; /* Allocate memory for descriptor */ iobuf = malloc ( sizeof ( *iobuf ) ); if ( ! iobuf ) { - free_dma ( data, len ); + free_phys ( data, len ); return NULL; } } @@ -159,12 +159,12 @@ void free_iob ( struct io_buffer *iobuf ) { if ( iobuf->end == iobuf ) { /* Descriptor is inline */ - free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); + free_phys ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); } else { /* Descriptor is detached */ - free_dma ( iobuf->head, len ); + free_phys ( iobuf->head, len ); free ( iobuf ); } } diff --git a/src/core/malloc.c b/src/core/malloc.c index 0a7843a14..8499ab45a 100644 --- a/src/core/malloc.c +++ b/src/core/malloc.c @@ -596,8 +596,8 @@ void * malloc ( size_t size ) { * * @v ptr Memory allocated by malloc(), or NULL * - * Memory allocated with malloc_dma() cannot be freed with free(); it - * must be freed with free_dma() instead. + * Memory allocated with malloc_phys() cannot be freed with free(); it + * must be freed with free_phys() instead. * * If @c ptr is NULL, no action is taken. */ -- cgit v1.2.3-55-g7522 From dda03c884d70d18546bb2d02f92acb4c4da28fc8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:18:49 +0000 Subject: [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 --- src/config/defaults/efi.h | 1 + src/config/defaults/linux.h | 1 + src/config/defaults/pcbios.h | 1 + src/core/dma.c | 179 +++++++++++++++++++++++ src/include/ipxe/dma.h | 334 +++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + 6 files changed, 517 insertions(+) create mode 100644 src/core/dma.c create mode 100644 src/include/ipxe/dma.h (limited to 'src/core') diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 0979887fc..9ef34ab62 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define UACCESS_EFI #define IOMAP_VIRT #define PCIAPI_EFI +#define DMAAPI_OP #define CONSOLE_EFI #define TIMER_EFI #define UMALLOC_EFI diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 75fd617f9..98d2dafec 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define TIME_LINUX #define REBOOT_NULL #define PCIAPI_LINUX +#define DMAAPI_FLAT #define DRIVERS_LINUX diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 41afb9033..83835805a 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define UACCESS_LIBRM #define IOAPI_X86 #define PCIAPI_PCBIOS +#define DMAAPI_FLAT #define TIMER_PCBIOS #define CONSOLE_PCBIOS #define NAP_PCBIOS diff --git a/src/core/dma.c b/src/core/dma.c new file mode 100644 index 000000000..9fc0c5453 --- /dev/null +++ b/src/core/dma.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +/** @file + * + * DMA mappings + * + */ + +/****************************************************************************** + * + * Flat address space DMA API + * + ****************************************************************************** + */ + +PROVIDE_DMAAPI_INLINE ( flat, dma_map ); +PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); +PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); +PROVIDE_DMAAPI_INLINE ( flat, dma_free ); +PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); + +/****************************************************************************** + * + * Operations-based DMA API + * + ****************************************************************************** + */ + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static int dma_op_map ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return -ENODEV; + return op->map ( dma, addr, len, flags, map ); +} + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +static void dma_op_unmap ( struct dma_device *dma, struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + assert ( op != NULL ); + op->unmap ( dma, map ); +} + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +static void * dma_op_alloc ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return NULL; + return op->alloc ( dma, len, align, map ); +} + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +static void dma_op_free ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + assert ( op != NULL ); + op->free ( dma, addr, len, map ); +} + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +static void dma_op_set_mask ( struct dma_device *dma, physaddr_t mask ) { + struct dma_operations *op = dma->op; + + if ( op ) + op->set_mask ( dma, mask ); +} + +PROVIDE_DMAAPI ( op, dma_map, dma_op_map ); +PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); +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 ); + +/****************************************************************************** + * + * Utility functions + * + ****************************************************************************** + */ + +/** + * Allocate and map I/O buffer for receiving data from device + * + * @v dma DMA device + * @v len Length of I/O buffer + * @v map DMA mapping to fill in + * @ret iobuf I/O buffer, or NULL on error + */ +struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, + struct dma_mapping *map ) { + 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, virt_to_phys ( iobuf->data ), len, + DMA_RX, map ) ) != 0 ) + goto err_map; + + return iobuf; + + dma_unmap ( dma, map ); + err_map: + free_iob ( iobuf ); + err_alloc: + return NULL; +} diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h new file mode 100644 index 000000000..d3db061f7 --- /dev/null +++ b/src/include/ipxe/dma.h @@ -0,0 +1,334 @@ +#ifndef _IPXE_DMA_H +#define _IPXE_DMA_H + +/** @file + * + * DMA mappings + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +#ifdef DMAAPI_OP +#define DMAAPI_PREFIX_op +#else +#define DMAAPI_PREFIX_op __op_ +#endif + +#ifdef DMAAPI_FLAT +#define DMAAPI_PREFIX_flat +#else +#define DMAAPI_PREFIX_flat __flat_ +#endif + +/** A DMA mapping */ +struct dma_mapping { + /** Device-side address */ + physaddr_t addr; +}; + +/** A DMA-capable device */ +struct dma_device { + /** DMA operations */ + struct dma_operations *op; + /** Addressable space mask */ + physaddr_t mask; + /** Total number of mappings (for debugging) */ + unsigned int mapped; + /** Total number of allocations (for debugging) */ + unsigned int allocated; +}; + +/** DMA operations */ +struct dma_operations { + /** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ + int ( * map ) ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ); + /** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ + void ( * unmap ) ( struct dma_device *dma, struct dma_mapping *map ); + /** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ + void * ( * alloc ) ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ); + /** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ + void ( * free ) ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ); + /** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ + void ( * set_mask ) ( struct dma_device *dma, physaddr_t mask ); +}; + +/** Device will read data from host memory */ +#define DMA_TX 0x01 + +/** Device will write data to host memory */ +#define DMA_RX 0x02 + +/** Device will both read data from and write data to host memory */ +#define DMA_BI ( DMA_TX | DMA_RX ) + +/** + * Calculate static inline DMA I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define DMAAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( DMAAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a DMA I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_DMAAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( DMAAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline DMA I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_DMAAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( DMAAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static inline __always_inline int +DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, physaddr_t addr, + size_t len __unused, int flags __unused, + struct dma_mapping *map ) { + + /* Use physical address as device address */ + map->addr = addr; + + /* Increment mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped++; + + return 0; +} + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, + struct dma_mapping *map __unused ) { + + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped--; +} + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +static inline __always_inline void * +DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, size_t len, + size_t align, struct dma_mapping *map ) { + void *addr; + + /* Allocate buffer */ + addr = malloc_phys ( len, align ); + map->addr = virt_to_phys ( addr ); + + /* Increment allocation count (for debugging) */ + if ( DBG_LOG && addr ) + dma->allocated++; + + return addr; +} + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_free ) ( struct dma_device *dma, + void *addr, size_t len, + struct dma_mapping *map __unused ) { + + /* Free buffer */ + free_phys ( addr, len ); + + /* Decrement allocation count (for debugging) */ + if ( DBG_LOG ) + dma->allocated--; +} + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_set_mask ) ( struct dma_device *dma __unused, + physaddr_t mask __unused ) { + + /* Nothing to do */ +} + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +int dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ); + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +void dma_unmap ( struct dma_device *dma, struct dma_mapping *map ); + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +void * dma_alloc ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ); + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +void dma_free ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ); + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +void dma_set_mask ( struct dma_device *dma, physaddr_t mask ); + +/** + * Initialise DMA device + * + * @v dma DMA device + * @v op DMA operations + */ +static inline __always_inline void dma_init ( struct dma_device *dma, + struct dma_operations *op ) { + + /* Set operations table */ + dma->op = op; +} + +/** + * Set 64-bit addressable space mask + * + * @v dma DMA device + */ +static inline __always_inline void +dma_set_mask_64bit ( struct dma_device *dma ) { + + /* Set mask to maximum physical address */ + dma_set_mask ( dma, ~( ( physaddr_t ) 0 ) ); +} + +/** + * Map I/O buffer for transmitting data to device + * + * @v dma DMA device + * @v iobuf I/O buffer + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static inline __always_inline int +dma_map_tx_iob ( struct dma_device *dma, struct io_buffer *iobuf, + struct dma_mapping *map ) { + + /* Map I/O buffer */ + return dma_map ( dma, virt_to_phys ( iobuf->data ), iob_len ( iobuf ), + DMA_TX, map ); +} + +extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, + struct dma_mapping *map ); + +#endif /* _IPXE_DMA_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 8238d4925..1c41feff3 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -75,6 +75,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_sanboot ( ERRFILE_CORE | 0x00230000 ) #define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 ) #define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 ) +#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) -- cgit v1.2.3-55-g7522 From cf12a41703a8b2292e5d2d7528c2733c37869681 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Nov 2020 15:52:00 +0000 Subject: [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 --- src/core/dma.c | 2 ++ src/drivers/net/intel.c | 10 ++---- src/drivers/net/intelxl.c | 33 ++++++-------------- src/drivers/net/intelxlvf.c | 6 ++-- src/drivers/net/realtek.c | 27 +++++++++-------- src/include/ipxe/dma.h | 74 +++++++++++++++++++++++++++++++++++++++------ src/interface/efi/efi_pci.c | 6 ++-- 7 files changed, 100 insertions(+), 58 deletions(-) (limited to 'src/core') diff --git a/src/core/dma.c b/src/core/dma.c index 9fc0c5453..3bf6957b9 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -46,6 +46,7 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); PROVIDE_DMAAPI_INLINE ( flat, dma_free ); PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); +PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); /****************************************************************************** * @@ -138,6 +139,7 @@ PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); 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 ); /****************************************************************************** * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 408101bad..5c6dc2143 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -513,7 +513,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( address & 0xffffffffUL ), ( intel->regs + ring->reg + INTEL_xDBAL ) ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { @@ -571,7 +571,6 @@ void intel_refill_rx ( struct intel_nic *intel ) { struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; - physaddr_t address; unsigned int refilled = 0; /* Refill ring */ @@ -596,8 +595,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { intel->rx.ring.prod++; /* Populate receive descriptor */ - address = map->addr; - intel->rx.ring.describe ( rx, address, 0 ); + intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -762,7 +760,6 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; - physaddr_t address; size_t len; int rc; @@ -783,9 +780,8 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { intel->tx.ring.prod++; /* Populate transmit descriptor */ - address = map->addr; len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, address, len ); + intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); wmb(); /* Notify card that there are packets ready to transmit */ diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 14a5858f3..0808c784a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -152,7 +152,8 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, } /* Configure interrupt zero to write to dummy location */ - pci_msix_map ( &intelxl->msix.cap, 0, intelxl->msix.map.addr, 0 ); + pci_msix_map ( &intelxl->msix.cap, 0, + dma ( &intelxl->msix.map, &intelxl->msix.msg ), 0 ); /* Enable dummy interrupt zero */ pci_msix_unmask ( &intelxl->msix.cap, 0 ); @@ -230,22 +231,6 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, return 0; } -/** - * Get DMA address for admin descriptor or buffer entry - * - * @v admin Admin queue - * @v addr Virtual address - * @ret addr DMA address - */ -static physaddr_t intelxl_admin_address ( struct intelxl_admin *admin, - void *addr ) { - size_t offset; - - /* Calculate offset within mapped area */ - offset = ( addr - ( ( void * ) admin->buf ) ); - return ( admin->map.addr + offset ); -} - /** * Enable admin queue * @@ -270,7 +255,7 @@ static void intelxl_enable_admin ( struct intelxl_nic *intelxl, admin->index = 0; /* Program queue address */ - address = intelxl_admin_address ( admin, admin->desc ); + address = dma ( &admin->map, admin->desc ); writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { writel ( ( ( ( uint64_t ) address ) >> 32 ), @@ -365,7 +350,7 @@ static void intelxl_admin_event_init ( struct intelxl_nic *intelxl, /* Initialise descriptor */ evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ]; buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ]; - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); evt->len = cpu_to_le16 ( sizeof ( *buf ) ); evt->params.buffer.high = cpu_to_le32 ( address >> 32 ); @@ -410,7 +395,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) { /* Populate data buffer address if applicable */ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); cmd->params.buffer.high = cpu_to_le32 ( address >> 32 ); cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL ); } @@ -1267,6 +1252,7 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl, */ static int intelxl_create_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { + physaddr_t address; int rc; /* Allocate descriptor ring */ @@ -1274,7 +1260,8 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl, goto err_alloc; /* Program queue context */ - if ( ( rc = ring->context ( intelxl, ring->map.addr ) ) != 0 ) + address = dma ( &ring->map, ring->desc.raw ); + if ( ( rc = ring->context ( intelxl, address ) ) != 0 ) goto err_context; /* Enable ring */ @@ -1346,7 +1333,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { intelxl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->flags = 0; DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", @@ -1537,7 +1524,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( map->addr ); + tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index 61ac5e5c0..f944b4daa 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,12 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( intelxl->tx.ring.map.addr ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, + intelxl->tx.ring.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( intelxl->rx.ring.map.addr ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, + intelxl->rx.ring.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 0f3038d36..bca52266f 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -506,6 +506,7 @@ static void realtek_check_link ( struct net_device *netdev ) { * @ret rc Return status code */ static int realtek_create_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -513,17 +514,16 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rtl->rxbuf.data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, - &rtl->rxbuf.map ); - if ( ! rtl->rxbuf.data ) + rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + if ( ! rxbuf->data ) return -ENOMEM; /* Program buffer address */ - writel ( rtl->rxbuf.map.addr, rtl->regs + RTL_RBSTART ); + writel ( dma ( &rxbuf->map, rxbuf->data ), rtl->regs + RTL_RBSTART ); DBGC ( rtl, "REALTEK %p receive buffer is at [%08lx,%08lx,%08lx)\n", - rtl, virt_to_phys ( rtl->rxbuf.data ), - ( virt_to_phys ( rtl->rxbuf.data ) + RTL_RXBUF_LEN ), - ( virt_to_phys ( rtl->rxbuf.data ) + len ) ); + rtl, virt_to_phys ( rxbuf->data ), + ( virt_to_phys ( rxbuf->data ) + RTL_RXBUF_LEN ), + ( virt_to_phys ( rxbuf->data ) + len ) ); return 0; } @@ -534,6 +534,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { * @v rtl Realtek device */ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -544,9 +545,9 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rtl->rxbuf.data, len, &rtl->rxbuf.map ); - rtl->rxbuf.data = NULL; - rtl->rxbuf.offset = 0; + dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + rxbuf->data = NULL; + rxbuf->offset = 0; } /** @@ -574,7 +575,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( ( ( uint64_t ) address ) >> 32 ), rtl->regs + ring->reg + 4 ); writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); @@ -648,7 +649,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { rtl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | @@ -797,7 +798,7 @@ static int realtek_transmit ( struct net_device *netdev, /* Map I/O buffer */ if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) return rc; - address = map->addr; + address = dma ( map, iobuf->data ); /* Update producer index */ rtl->tx.ring.prod++; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 878e03f11..0577493c7 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -30,8 +30,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** A DMA mapping */ struct dma_mapping { - /** Device-side address */ - physaddr_t addr; + /** Address offset + * + * This is the value that must be added to a physical address + * within the mapping in order to produce the corresponding + * device-side DMA address. + */ + physaddr_t offset; /** Platform mapping token */ void *token; }; @@ -148,12 +153,10 @@ struct dma_operations { * @ret rc Return status code */ static inline __always_inline int -DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, physaddr_t addr, +DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + physaddr_t addr __unused, size_t len __unused, int flags __unused, - struct dma_mapping *map ) { - - /* Use physical address as device address */ - map->addr = addr; + struct dma_mapping *map __unused ) { /* Increment mapping count (for debugging) */ if ( DBG_LOG ) @@ -187,13 +190,13 @@ DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * -DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, size_t len, - size_t align, struct dma_mapping *map ) { +DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, + size_t len, size_t align, + struct dma_mapping *map __unused ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - map->addr = virt_to_phys ( addr ); /* Increment allocation count (for debugging) */ if ( DBG_LOG && addr ) @@ -236,6 +239,35 @@ DMAAPI_INLINE ( flat, dma_set_mask ) ( struct dma_device *dma __unused, /* Nothing to do */ } +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( flat, dma_phys ) ( struct dma_mapping *map __unused, + physaddr_t addr ) { + + /* Use physical address as device address */ + return addr; +} + +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { + + /* Adjust physical address using mapping offset */ + return ( addr + map->offset ); +} + /** * Map buffer for DMA * @@ -288,6 +320,28 @@ void dma_free ( struct dma_device *dma, void *addr, size_t len, */ void dma_set_mask ( struct dma_device *dma, physaddr_t mask ); +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); + +/** + * Get DMA address from virtual address + * + * @v map DMA mapping + * @v addr Virtual address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t dma ( struct dma_mapping *map, + void *addr ) { + + return dma_phys ( map, virt_to_phys ( addr ) ); +} + /** * Initialise DMA device * diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 6c6ac5c77..e33a8980d 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,7 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, int rc; /* Sanity check */ - assert ( map->addr == 0 ); + assert ( map->offset == 0 ); assert ( map->token == NULL ); /* Determine operation */ @@ -374,7 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ - map->addr = bus; + map->offset = ( bus - addr ); map->token = mapping; /* Increment mapping count (for debugging) */ @@ -408,7 +408,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ - map->addr = 0; + map->offset = 0; map->token = NULL; /* Decrement mapping count (for debugging) */ -- cgit v1.2.3-55-g7522 From 70e6e83243b77a3771756106871d6f945062a44b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 27 Nov 2020 11:27:22 +0000 Subject: [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 --- src/core/dma.c | 52 +++++++++---------- src/drivers/net/intel.c | 18 +++---- src/drivers/net/intelxl.c | 40 +++++++-------- src/drivers/net/realtek.c | 23 +++++---- src/include/ipxe/dma.h | 121 +++++++++++++++++++++++++------------------- src/interface/efi/efi_pci.c | 25 ++++----- 6 files changed, 150 insertions(+), 129 deletions(-) (limited to 'src/core') diff --git a/src/core/dma.c b/src/core/dma.c index 3bf6957b9..561aec1e1 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -59,66 +59,65 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int dma_op_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int dma_op_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct dma_operations *op = dma->op; if ( ! op ) return -ENODEV; - return op->map ( dma, addr, len, flags, map ); + return op->map ( dma, map, addr, len, flags ); } /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -static void dma_op_unmap ( struct dma_device *dma, struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_unmap ( struct dma_mapping *map ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->unmap ( dma, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->unmap ( dma, map ); } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * dma_op_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ) { +static void * dma_op_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ) { struct dma_operations *op = dma->op; if ( ! op ) return NULL; - return op->alloc ( dma, len, align, map ); + return op->alloc ( dma, map, len, align ); } /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void dma_op_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->free ( dma, addr, len, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->free ( dma, map, addr, len ); } /** @@ -152,12 +151,13 @@ PROVIDE_DMAAPI_INLINE ( op, dma_phys ); * Allocate and map I/O buffer for receiving data from device * * @v dma DMA device - * @v len Length of I/O buffer * @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, size_t len, - struct dma_mapping *map ) { +struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ) { struct io_buffer *iobuf; int rc; @@ -167,13 +167,13 @@ struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, goto err_alloc; /* Map I/O buffer */ - if ( ( rc = dma_map ( dma, virt_to_phys ( iobuf->data ), len, - DMA_RX, map ) ) != 0 ) + if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ), + len, DMA_RX ) ) != 0 ) goto err_map; return iobuf; - dma_unmap ( dma, map ); + dma_unmap ( map ); err_map: free_iob ( iobuf ); err_alloc: diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 5c6dc2143..93c5fd1f6 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -504,8 +504,8 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = dma_alloc ( intel->dma, ring->len, ring->len, - &ring->map ); + ring->desc = dma_alloc ( intel->dma, &ring->map, ring->len, + ring->len ); if ( ! ring->desc ) return -ENOMEM; @@ -554,7 +554,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - dma_free ( intel->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; @@ -584,7 +584,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { assert ( intel->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, INTEL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -630,7 +630,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { if ( intel->rx.iobuf[i] ) { - dma_unmap ( intel->dma, &intel->rx.map[i] ); + dma_unmap ( &intel->rx.map[i] ); free_iob ( intel->rx.iobuf[i] ); } intel->rx.iobuf[i] = NULL; @@ -639,7 +639,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Unmap incomplete transmit buffers */ for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); } } @@ -773,7 +773,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intel->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -822,7 +822,7 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -854,7 +854,7 @@ void intel_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->rx.map[rx_idx] ); + dma_unmap ( &intel->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intel->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 0808c784a..5de432a6a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -136,9 +136,9 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, int rc; /* Map dummy target location */ - if ( ( rc = dma_map ( intelxl->dma, virt_to_phys ( &intelxl->msix.msg ), - sizeof ( intelxl->msix.msg ), DMA_RX, - &intelxl->msix.map ) ) != 0 ) { + if ( ( rc = dma_map ( intelxl->dma, &intelxl->msix.map, + virt_to_phys ( &intelxl->msix.msg ), + sizeof ( intelxl->msix.msg ), DMA_RX ) ) != 0 ) { DBGC ( intelxl, "INTELXL %p could not map MSI-X target: %s\n", intelxl, strerror ( rc ) ); goto err_map; @@ -162,7 +162,7 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); err_enable: - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); err_map: return rc; } @@ -183,7 +183,7 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); /* Unmap dummy target location */ - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); } /****************************************************************************** @@ -215,8 +215,8 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = dma_alloc ( intelxl->dma, ( buf_len + len ), - INTELXL_ALIGN, &admin->map ); + admin->buf = dma_alloc ( intelxl->dma, &admin->map, ( buf_len + len ), + INTELXL_ALIGN ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); @@ -291,13 +291,13 @@ static void intelxl_disable_admin ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v admin Admin queue */ -static void intelxl_free_admin ( struct intelxl_nic *intelxl, +static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, struct intelxl_admin *admin ) { size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - dma_free ( intelxl->dma, admin->buf, ( buf_len + len ), &admin->map ); + dma_free ( &admin->map, admin->buf, ( buf_len + len ) ); } /** @@ -945,8 +945,8 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int rc; /* Allocate descriptor ring */ - ring->desc.raw = dma_alloc ( intelxl->dma, ring->len, INTELXL_ALIGN, - &ring->map ); + ring->desc.raw = dma_alloc ( intelxl->dma, &ring->map, ring->len, + INTELXL_ALIGN ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; @@ -969,7 +969,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, return 0; - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); err_alloc: return rc; } @@ -980,11 +980,11 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v ring Descriptor ring */ -void intelxl_free_ring ( struct intelxl_nic *intelxl, +void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, struct intelxl_ring *ring ) { /* Free descriptor ring */ - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); ring->desc.raw = NULL; } @@ -1322,7 +1322,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { assert ( intelxl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, intelxl->mfs, map ); + iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -1365,7 +1365,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( intelxl->dma, &intelxl->rx.map[i] ); + dma_unmap ( &intelxl->rx.map[i] ); free_iob ( intelxl->rx.iobuf[i] ); } intelxl->rx.iobuf[i] = NULL; @@ -1374,7 +1374,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Unmap incomplete transmit buffers */ for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); } } @@ -1516,7 +1516,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intelxl->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -1564,7 +1564,7 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { intelxl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -1597,7 +1597,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->rx.map[rx_idx] ); + dma_unmap ( &intelxl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intelxl->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index bca52266f..47d435f72 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -514,7 +514,8 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + rxbuf->data = dma_alloc ( rtl->dma, &rxbuf->map, len, + RTL_RXBUF_ALIGN ); if ( ! rxbuf->data ) return -ENOMEM; @@ -545,7 +546,7 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + dma_free ( &rxbuf->map, rxbuf->data, len ); rxbuf->data = NULL; rxbuf->offset = 0; } @@ -566,8 +567,8 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = dma_alloc ( rtl->dma, ring->len, RTL_RING_ALIGN, - &ring->map ); + ring->desc = dma_alloc ( rtl->dma, &ring->map, ring->len, + RTL_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -608,7 +609,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - dma_free ( rtl->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; } @@ -638,7 +639,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { assert ( rtl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, RTL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ return; @@ -748,7 +749,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { if ( rtl->rx.iobuf[i] ) { - dma_unmap ( rtl->dma, &rtl->rx.map[i] ); + dma_unmap ( &rtl->rx.map[i] ); free_iob ( rtl->rx.iobuf[i] ); } rtl->rx.iobuf[i] = NULL; @@ -756,7 +757,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Unmap any incomplete transmit buffers */ for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( rtl->dma, &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); + dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); /* Destroy transmit descriptor ring */ realtek_destroy_ring ( rtl, &rtl->tx.ring ); @@ -796,7 +797,7 @@ static int realtek_transmit ( struct net_device *netdev, iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) return rc; address = dma ( map, iobuf->data ); @@ -870,7 +871,7 @@ static void realtek_poll_tx ( struct net_device *netdev ) { DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( rtl->dma, &rtl->tx.map[tx_idx] ); + dma_unmap ( &rtl->tx.map[tx_idx] ); /* Complete TX descriptor */ rtl->tx.ring.cons++; @@ -964,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { return; /* Unmap buffer */ - dma_unmap ( rtl->dma, &rtl->rx.map[rx_idx] ); + dma_unmap ( &rtl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = rtl->rx.iobuf[rx_idx]; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 0577493c7..842c9d6ef 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -37,6 +37,8 @@ struct dma_mapping { * device-side DMA address. */ physaddr_t offset; + /** DMA device (if unmapping is required) */ + struct dma_device *dma; /** Platform mapping token */ void *token; }; @@ -59,14 +61,14 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ - int ( * map ) ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); + int ( * map ) ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * @@ -78,23 +80,23 @@ struct dma_operations { * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ - void * ( * alloc ) ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); + void * ( * alloc ) ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ - void ( * free ) ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); + void ( * free ) ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ); /** * Set addressable space mask * @@ -146,21 +148,23 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ static inline __always_inline int DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + struct dma_mapping *map, physaddr_t addr __unused, - size_t len __unused, int flags __unused, - struct dma_mapping *map __unused ) { + size_t len __unused, int flags __unused ) { /* Increment mapping count (for debugging) */ - if ( DBG_LOG ) + if ( DBG_LOG ) { + map->dma = dma; dma->mapped++; + } return 0; } @@ -168,39 +172,42 @@ DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_mapping *map ) { /* Decrement mapping count (for debugging) */ - if ( DBG_LOG ) - dma->mapped--; + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, - size_t len, size_t align, - struct dma_mapping *map __unused ) { + struct dma_mapping *map, + size_t len, size_t align ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - /* Increment allocation count (for debugging) */ - if ( DBG_LOG && addr ) - dma->allocated++; + /* Increment mapping count (for debugging) */ + if ( DBG_LOG && addr ) { + map->dma = dma; + dma->mapped++; + } return addr; } @@ -208,22 +215,23 @@ DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_free ) ( struct dma_device *dma, - void *addr, size_t len, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, + void *addr, size_t len ) { /* Free buffer */ free_phys ( addr, len ); - /* Decrement allocation count (for debugging) */ - if ( DBG_LOG ) - dma->allocated--; + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** @@ -272,45 +280,42 @@ DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -int dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); +int dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -void dma_unmap ( struct dma_device *dma, struct dma_mapping *map ); +void dma_unmap ( struct dma_mapping *map ); /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -void * dma_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); +void * dma_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -void dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); +void dma_free ( struct dma_mapping *map, void *addr, size_t len ); /** * Set addressable space mask @@ -339,9 +344,22 @@ physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); static inline __always_inline physaddr_t dma ( struct dma_mapping *map, void *addr ) { + /* Get DMA address from corresponding physical address */ return dma_phys ( map, virt_to_phys ( addr ) ); } +/** + * Check if DMA unmapping is required + * + * @v map DMA mapping + * @v unmap Unmapping is required + */ +static inline __always_inline int dma_mapped ( struct dma_mapping *map ) { + + /* Unmapping is required if a DMA device was recorded */ + return ( map->dma != NULL ); +} + /** * Initialise DMA device * @@ -371,20 +389,21 @@ dma_set_mask_64bit ( struct dma_device *dma ) { * Map I/O buffer for transmitting data to device * * @v dma DMA device - * @v iobuf I/O buffer * @v map DMA mapping to fill in + * @v iobuf I/O buffer * @ret rc Return status code */ static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct io_buffer *iobuf, - struct dma_mapping *map ) { +dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, + struct io_buffer *iobuf ) { /* Map I/O buffer */ - return dma_map ( dma, virt_to_phys ( iobuf->data ), iob_len ( iobuf ), - DMA_TX, map ); + return dma_map ( dma, map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); } -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, - struct dma_mapping *map ); +extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ); #endif /* _IPXE_DMA_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index e33a8980d..7687ffb43 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -315,14 +315,14 @@ PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -374,6 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ + map->dma = dma; map->offset = ( bus - addr ); map->token = mapping; @@ -420,14 +421,14 @@ static void efipci_dma_unmap ( struct dma_device *dma, * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, - size_t align __unused, - struct dma_mapping *map ) { +static void * efipci_dma_alloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align __unused ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -451,8 +452,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, } /* Map buffer */ - if ( ( rc = efipci_dma_map ( dma, virt_to_phys ( addr ), len, DMA_BI, - map ) ) != 0 ) + if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ), + len, DMA_BI ) ) != 0 ) goto err_map; /* Increment allocation count (for debugging) */ @@ -472,12 +473,12 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void efipci_dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { +static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; -- cgit v1.2.3-55-g7522 From 8d337ecdae3c6d555ea57996bc2280debd984a9c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 26 Nov 2020 12:25:02 +0000 Subject: [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 --- src/core/dma.c | 41 ------------- src/core/iobuf.c | 45 +++++++++++++++ src/drivers/net/intel.c | 120 ++++++++++++++------------------------ src/drivers/net/intel.h | 46 +++++---------- src/drivers/net/intelx.c | 21 +++---- src/drivers/net/intelxl.c | 134 ++++++++++++++++--------------------------- src/drivers/net/intelxl.h | 30 +++------- src/drivers/net/intelxlvf.c | 33 +++++------ src/drivers/net/intelxvf.c | 21 +++---- src/drivers/net/realtek.c | 101 ++++++++++++++------------------ src/drivers/net/realtek.h | 24 ++------ src/include/ipxe/dma.h | 22 ------- src/include/ipxe/iobuf.h | 55 ++++++++++++++++++ src/include/ipxe/netdevice.h | 6 ++ src/interface/efi/efi_pci.c | 2 + src/net/netdevice.c | 32 +++++++++++ 16 files changed, 342 insertions(+), 391 deletions(-) (limited to 'src/core') diff --git a/src/core/dma.c b/src/core/dma.c index 561aec1e1..e5fa3f323 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -25,7 +25,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /** @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 941bb3446..c9970bc76 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 ); @@ -169,6 +171,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 * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 93c5fd1f6..83492961f 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -568,34 +568,30 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { void intel_refill_rx ( struct intel_nic *intel ) { struct intel_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intel->rx.ring.prod - - intel->rx.ring.cons ) < INTEL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; - map = &intel->rx.map[rx_idx]; - assert ( intel->rx.iobuf[rx_idx] == NULL ); + while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( INTEL_RX_MAX_LEN, intel->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intel->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intel->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Populate receive descriptor */ - intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); + intel->rx.describe ( rx, iob_dma ( iobuf ), 0 ); + + /* Record I/O buffer */ + assert ( intel->rx_iobuf[rx_idx] == NULL ); + intel->rx_iobuf[rx_idx] = iobuf; DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -606,40 +602,27 @@ void intel_refill_rx ( struct intel_nic *intel ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); + rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); profile_start ( &intel_vm_refill_profiler ); - writel ( rx_tail, - intel->regs + intel->rx.ring.reg + INTEL_xDT ); + writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); profile_stop ( &intel_vm_refill_profiler ); profile_exclude ( &intel_vm_refill_profiler ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intel Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intel_flush ( struct intel_nic *intel ) { +void intel_empty_rx ( struct intel_nic *intel ) { unsigned int i; - unsigned int tx_idx; /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { - if ( intel->rx.iobuf[i] ) { - dma_unmap ( &intel->rx.map[i] ); - free_iob ( intel->rx.iobuf[i] ); - } - intel->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( &intel->tx.map[tx_idx] ); + if ( intel->rx_iobuf[i] ) + free_rx_iob ( intel->rx_iobuf[i] ); + intel->rx_iobuf[i] = NULL; } } @@ -670,11 +653,11 @@ static int intel_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -713,9 +696,9 @@ static int intel_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -735,13 +718,13 @@ static void intel_close ( struct net_device *netdev ) { writel ( 0, intel->regs + INTEL_TCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intel_reset ( intel ); @@ -757,37 +740,27 @@ static void intel_close ( struct net_device *netdev ) { int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intel->tx.ring.prod - intel->tx.ring.cons ) >= INTEL_TX_FILL ) { + if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) { DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); return -ENOBUFS; } - tx_idx = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; - map = &intel->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intel->tx.ring.prod++; + tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC ); + tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); + intel->tx.describe ( tx, iob_dma ( iobuf ), len ); wmb(); /* Notify card that there are packets ready to transmit */ profile_start ( &intel_vm_tx_profiler ); - tx_tail = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - writel ( tx_tail, intel->regs + intel->tx.ring.reg + INTEL_xDT ); + writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); profile_stop ( &intel_vm_tx_profiler ); profile_exclude ( &intel_vm_tx_profiler ); @@ -809,11 +782,11 @@ void intel_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intel->tx.ring.cons != intel->tx.ring.prod ) { + while ( intel->tx.cons != intel->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intel->tx.ring.cons % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; + tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Stop if descriptor is still in use */ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) @@ -821,12 +794,9 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intel->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intel->tx.ring.cons++; + intel->tx.cons++; } } @@ -843,22 +813,19 @@ void intel_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intel->rx.ring.cons != intel->rx.ring.prod ) { + while ( intel->rx.cons != intel->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.cons % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; + rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intel->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intel->rx.iobuf[rx_idx]; - intel->rx.iobuf[rx_idx] = NULL; + iobuf = intel->rx_iobuf[rx_idx]; + intel->rx_iobuf[rx_idx] = NULL; len = le16_to_cpu ( rx->length ); iob_put ( iobuf, len ); @@ -873,7 +840,7 @@ void intel_poll_rx ( struct net_device *netdev ) { intel, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - intel->rx.ring.cons++; + intel->rx.cons++; } } @@ -981,9 +948,9 @@ static int intel_probe ( struct pci_device *pci ) { memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); intel->flags = pci->id->driver_data; - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTEL_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTEL_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -999,6 +966,7 @@ static int intel_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intel_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h index 731b5f225..4f51a80f6 100644 --- a/src/drivers/net/intel.h +++ b/src/drivers/net/intel.h @@ -276,24 +276,6 @@ intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl, mbox->mem = mem; } -/** Transmit ring */ -struct intel_tx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct intel_rx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTEL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_RX_DESC]; -}; - /** An Intel network card */ struct intel_nic { /** Registers */ @@ -317,10 +299,12 @@ struct intel_nic { /** Mailbox */ struct intel_mailbox mbox; - /** Transmit ring */ - struct intel_tx_ring tx; - /** Receive ring */ - struct intel_rx_ring rx; + /** Transmit descriptor ring */ + struct intel_ring tx; + /** Receive descriptor ring */ + struct intel_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; }; /** Driver flags */ @@ -349,14 +333,14 @@ static inline void intel_diag ( struct intel_nic *intel ) { DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) " "RX %04x(%02x)/%04x(%02x)\n", intel, - ( intel->tx.ring.cons & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDH ), - ( intel->tx.ring.prod & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDT ), - ( intel->rx.ring.cons & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDH ), - ( intel->rx.ring.prod & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDT ) ); + ( intel->tx.cons & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDH ), + ( intel->tx.prod & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDT ), + ( intel->rx.cons & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDH ), + ( intel->rx.prod & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDT ) ); } extern void intel_describe_tx ( struct intel_descriptor *tx, @@ -371,7 +355,7 @@ extern int intel_create_ring ( struct intel_nic *intel, extern void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ); extern void intel_refill_rx ( struct intel_nic *intel ); -extern void intel_flush ( struct intel_nic *intel ); +extern void intel_empty_rx ( struct intel_nic *intel ); extern int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intel_poll_tx ( struct net_device *netdev ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 364ec76c5..ccf6b0648 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -185,11 +185,11 @@ static int intelx_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -263,9 +263,9 @@ static int intelx_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -291,13 +291,13 @@ static void intelx_close ( struct net_device *netdev ) { writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intelx_reset ( intel ); @@ -395,9 +395,9 @@ static int intelx_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELX_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELX_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -413,6 +413,7 @@ static int intelx_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intelx_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 5de432a6a..ac9e37c5a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1306,36 +1306,32 @@ static void intelxl_destroy_ring ( struct intelxl_nic *intelxl, static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { struct intelxl_rx_data_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intelxl->rx.ring.prod - - intelxl->rx.ring.cons ) < INTELXL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - rx = &intelxl->rx.ring.desc.rx[rx_idx].data; - map = &intelxl->rx.map[rx_idx]; - assert ( intelxl->rx.iobuf[rx_idx] == NULL ); + while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); + iobuf = alloc_rx_iob ( intelxl->mfs, intelxl->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intelxl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intelxl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC ); + rx = &intelxl->rx.desc.rx[rx_idx].data; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->flags = 0; + /* Record I/O buffer */ + assert ( intelxl->rx_iobuf[rx_idx] == NULL ); + intelxl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", intelxl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + intelxl->mfs ) ); @@ -1345,36 +1341,24 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - writel ( rx_tail, ( intelxl->regs + intelxl->rx.ring.tail ) ); + rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC ); + writel ( rx_tail, ( intelxl->regs + intelxl->rx.tail ) ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intelxl Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intelxl_flush ( struct intelxl_nic *intelxl ) { +void intelxl_empty_rx ( struct intelxl_nic *intelxl ) { unsigned int i; - unsigned int tx_idx; /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { - if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( &intelxl->rx.map[i] ); - free_iob ( intelxl->rx.iobuf[i] ); - } - intelxl->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( &intelxl->tx.map[tx_idx] ); + if ( intelxl->rx_iobuf[i] ) + free_rx_iob ( intelxl->rx_iobuf[i] ); + intelxl->rx_iobuf[i] = NULL; } } @@ -1415,7 +1399,7 @@ static int intelxl_open ( struct net_device *netdev ) { /* Associate transmit queue to PF */ writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF | INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ), - ( intelxl->regs + intelxl->tx.ring.reg + INTELXL_QXX_CTL ) ); + ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) ); /* Clear transmit pre queue disable */ queue = ( intelxl->base + intelxl->queue ); @@ -1427,11 +1411,11 @@ static int intelxl_open ( struct net_device *netdev ) { writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) ); /* Create receive descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_create_rx; /* Create transmit descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_create_tx; /* Fill receive ring */ @@ -1449,9 +1433,9 @@ static int intelxl_open ( struct net_device *netdev ) { INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ), ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); err_create_tx: - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); err_create_rx: return rc; } @@ -1479,13 +1463,13 @@ static void intelxl_close ( struct net_device *netdev ) { udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); /* Destroy transmit descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); /* Destroy receive descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** @@ -1498,41 +1482,30 @@ static void intelxl_close ( struct net_device *netdev ) { int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intelxl_nic *intelxl = netdev->priv; struct intelxl_tx_data_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intelxl->tx.ring.prod - - intelxl->tx.ring.cons ) >= INTELXL_TX_FILL ) { + if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) { DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n", intelxl ); return -ENOBUFS; } - tx_idx = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - tx = &intelxl->tx.ring.desc.tx[tx_idx].data; - map = &intelxl->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intelxl->tx.ring.prod++; + tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC ); + tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC ); + tx = &intelxl->tx.desc.tx[tx_idx].data; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); wmb(); /* Notify card that there are packets ready to transmit */ - tx_tail = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - writel ( tx_tail, ( intelxl->regs + intelxl->tx.ring.tail ) ); + writel ( tx_tail, ( intelxl->regs + intelxl->tx.tail ) ); DBGC2 ( intelxl, "INTELXL %p TX %d is [%08lx,%08lx)\n", intelxl, tx_idx, virt_to_phys ( iobuf->data ), @@ -1551,11 +1524,11 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intelxl->tx.ring.cons != intelxl->tx.ring.prod ) { + while ( intelxl->tx.cons != intelxl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intelxl->tx.ring.cons % INTELXL_TX_NUM_DESC ); - tx_wb = &intelxl->tx.ring.desc.tx[tx_idx].wb; + tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC ); + tx_wb = &intelxl->tx.desc.tx[tx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) ) @@ -1563,12 +1536,9 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { DBGC2 ( intelxl, "INTELXL %p TX %d complete\n", intelxl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intelxl->tx.ring.cons++; + intelxl->tx.cons++; } } @@ -1586,22 +1556,19 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intelxl->rx.ring.cons != intelxl->rx.ring.prod ) { + while ( intelxl->rx.cons != intelxl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.cons % INTELXL_RX_NUM_DESC ); - rx_wb = &intelxl->rx.ring.desc.rx[rx_idx].wb; + rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC ); + rx_wb = &intelxl->rx.desc.rx[rx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intelxl->rx.iobuf[rx_idx]; - intelxl->rx.iobuf[rx_idx] = NULL; + iobuf = intelxl->rx_iobuf[rx_idx]; + intelxl->rx_iobuf[rx_idx] = NULL; len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) ); iob_put ( iobuf, len ); @@ -1623,7 +1590,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { "%zd)\n", intelxl, rx_idx, len ); vlan_netdev_rx ( netdev, tag, iobuf ); } - intelxl->rx.ring.cons++; + intelxl->rx.cons++; } } @@ -1710,11 +1677,11 @@ static int intelxl_probe ( struct pci_device *pci ) { &intelxl_admin_offsets ); intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT, &intelxl_admin_offsets ); - intelxl_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), intelxl_context_tx ); - intelxl_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), intelxl_context_rx ); /* Fix up PCI device */ @@ -1730,6 +1697,7 @@ static int intelxl_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Reset the NIC */ if ( ( rc = intelxl_reset ( intelxl ) ) != 0 ) @@ -1775,10 +1743,10 @@ static int intelxl_probe ( struct pci_device *pci ) { goto err_admin_promisc; /* Configure queue register addresses */ - intelxl->tx.ring.reg = INTELXL_QTX ( intelxl->queue ); - intelxl->tx.ring.tail = ( intelxl->tx.ring.reg + INTELXL_QXX_TAIL ); - intelxl->rx.ring.reg = INTELXL_QRX ( intelxl->queue ); - intelxl->rx.ring.tail = ( intelxl->rx.ring.reg + INTELXL_QXX_TAIL ); + intelxl->tx.reg = INTELXL_QTX ( intelxl->queue ); + intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL ); + intelxl->rx.reg = INTELXL_QRX ( intelxl->queue ); + intelxl->rx.tail = ( intelxl->rx.reg + INTELXL_QXX_TAIL ); /* Configure interrupt causes */ writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE | diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index cffc0da96..a4a776d28 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -1030,24 +1030,6 @@ union intelxl_receive_address { uint8_t raw[ETH_ALEN]; }; -/** Transmit ring */ -struct intelxl_tx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTELXL_TX_NUM_DESC]; -}; - -/** Receive ring */ -struct intelxl_rx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTELXL_RX_NUM_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTELXL_RX_NUM_DESC]; -}; - /** MSI-X interrupt */ struct intelxl_msix { /** PCI capability */ @@ -1098,10 +1080,12 @@ struct intelxl_nic { /** Current VF event data buffer */ union intelxl_admin_buffer vbuf; - /** Transmit ring */ - struct intelxl_tx_ring tx; - /** Receive ring */ - struct intelxl_rx_ring rx; + /** Transmit descriptor ring */ + struct intelxl_ring tx; + /** Receive descriptor ring */ + struct intelxl_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC]; }; extern int intelxl_msix_enable ( struct intelxl_nic *intelxl, @@ -1121,7 +1105,7 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); extern void intelxl_free_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); -extern void intelxl_flush ( struct intelxl_nic *intelxl ); +extern void intelxl_empty_rx ( struct intelxl_nic *intelxl ); extern int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intelxl_poll ( struct net_device *netdev ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index f944b4daa..752de7815 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,14 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, - intelxl->tx.ring.desc.raw ) ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.map, + intelxl->tx.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, - intelxl->rx.ring.desc.raw ) ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.map, + intelxl->rx.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) @@ -501,11 +501,11 @@ static int intelxlvf_open ( struct net_device *netdev ) { INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) ); /* Allocate transmit descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_alloc_tx; /* Allocate receive descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_alloc_rx; /* Configure queues */ @@ -531,9 +531,9 @@ static int intelxlvf_open ( struct net_device *netdev ) { err_enable: err_irq_map: err_configure: - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); err_alloc_rx: - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); err_alloc_tx: return rc; } @@ -554,13 +554,13 @@ static void intelxlvf_close ( struct net_device *netdev ) { } /* Free receive descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); /* Free transmit descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** Network device operations */ @@ -605,11 +605,11 @@ static int intelxlvf_probe ( struct pci_device *pci ) { &intelxlvf_admin_command_offsets ); intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN, &intelxlvf_admin_event_offsets ); - intelxlvf_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), INTELXLVF_QTX_TAIL ); - intelxlvf_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), INTELXLVF_QRX_TAIL ); /* Fix up PCI device */ @@ -625,6 +625,7 @@ static int intelxlvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Locate PCI Express capability */ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP ); diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index a650979ef..f0ba091d5 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -276,11 +276,11 @@ static int intelxvf_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Allocate interrupt vectors */ @@ -317,9 +317,9 @@ static int intelxvf_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: err_mbox_set_mtu: err_mbox_set_mac: @@ -337,13 +337,13 @@ static void intelxvf_close ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the function */ intelxvf_reset ( intel ); @@ -447,9 +447,9 @@ static int intelxvf_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELXVF_TD(0), + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD(0), intel_describe_tx_adv ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELXVF_RD(0), + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD(0), intel_describe_rx ); /* Fix up PCI device */ @@ -465,6 +465,7 @@ static int intelxvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the function */ intelxvf_reset ( intel ); diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 47d435f72..0af3416d5 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -621,7 +621,6 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, static void realtek_refill_rx ( struct realtek_nic *rtl ) { struct realtek_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; int is_last; @@ -629,34 +628,32 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { if ( rtl->legacy ) return; - while ( ( rtl->rx.ring.prod - rtl->rx.ring.cons ) < RTL_NUM_RX_DESC ) { - - /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.prod % RTL_NUM_RX_DESC ); - is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); - rx = &rtl->rx.ring.desc[rx_idx]; - map = &rtl->rx.map[rx_idx]; - assert ( rtl->rx.iobuf[rx_idx] == NULL ); + while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( RTL_RX_MAX_LEN, rtl->dma ); if ( ! iobuf ) { /* Wait for next refill */ return; } - rtl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - rtl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC ); + is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); + rx = &rtl->rx.desc[rx_idx]; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); wmb(); + /* Record I/O buffer */ + assert ( rtl->rx_iobuf[rx_idx] == NULL ); + rtl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( rtl, "REALTEK %p RX %d is [%lx,%lx)\n", rtl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + RTL_RX_MAX_LEN ) ); @@ -676,11 +673,11 @@ static int realtek_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->tx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->rx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) goto err_create_rx; /* Create receive buffer */ @@ -721,9 +718,9 @@ static int realtek_open ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); err_create_buffer: - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); err_create_rx: - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); err_create_tx: return rc; } @@ -744,23 +741,17 @@ static void realtek_close ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); /* Destroy receive descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { - if ( rtl->rx.iobuf[i] ) { - dma_unmap ( &rtl->rx.map[i] ); - free_iob ( rtl->rx.iobuf[i] ); - } - rtl->rx.iobuf[i] = NULL; + if ( rtl->rx_iobuf[i] ) + free_rx_iob ( rtl->rx_iobuf[i] ); + rtl->rx_iobuf[i] = NULL; } - /* Unmap any incomplete transmit buffers */ - for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); - /* Destroy transmit descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); /* Reset legacy transmit descriptor index, if applicable */ if ( rtl->legacy ) @@ -778,37 +769,33 @@ static int realtek_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct realtek_nic *rtl = netdev->priv; struct realtek_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; - physaddr_t address; int is_last; int rc; /* Get next transmit descriptor */ - if ( ( rtl->tx.ring.prod - rtl->tx.ring.cons ) >= RTL_NUM_TX_DESC ) { + if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { netdev_tx_defer ( netdev, iobuf ); return 0; } - tx_idx = ( rtl->tx.ring.prod % RTL_NUM_TX_DESC ); - map = &rtl->tx.map[tx_idx]; + tx_idx = ( rtl->tx.prod % RTL_NUM_TX_DESC ); /* Pad and align packet, if needed */ if ( rtl->legacy ) iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) + if ( ( rc = iob_map_tx ( iobuf, rtl->dma ) ) != 0 ) return rc; - address = dma ( map, iobuf->data ); /* Update producer index */ - rtl->tx.ring.prod++; + rtl->tx.prod++; /* Transmit packet */ if ( rtl->legacy ) { /* Add to transmit ring */ - writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) ); + writel ( iob_dma ( iobuf ), rtl->regs + RTL_TSAD ( tx_idx ) ); writel ( ( RTL_TSD_ERTXTH_DEFAULT | iob_len ( iobuf ) ), rtl->regs + RTL_TSD ( tx_idx ) ); @@ -816,8 +803,8 @@ static int realtek_transmit ( struct net_device *netdev, /* Populate transmit descriptor */ is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); - tx = &rtl->tx.ring.desc[tx_idx]; - tx->address = cpu_to_le64 ( address ); + tx = &rtl->tx.desc[tx_idx]; + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); wmb(); tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | @@ -847,10 +834,10 @@ static void realtek_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( rtl->tx.ring.cons != rtl->tx.ring.prod ) { + while ( rtl->tx.cons != rtl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( rtl->tx.ring.cons % RTL_NUM_TX_DESC ); + tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); /* Stop if descriptor is still in use */ if ( rtl->legacy ) { @@ -863,18 +850,15 @@ static void realtek_poll_tx ( struct net_device *netdev ) { } else { /* Check ownership bit in descriptor */ - tx = &rtl->tx.ring.desc[tx_idx]; + tx = &rtl->tx.desc[tx_idx]; if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; } DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &rtl->tx.map[tx_idx] ); - /* Complete TX descriptor */ - rtl->tx.ring.cons++; + rtl->tx.cons++; netdev_tx_complete_next ( netdev ); } } @@ -954,22 +938,19 @@ static void realtek_poll_rx ( struct net_device *netdev ) { } /* Check for received packets */ - while ( rtl->rx.ring.cons != rtl->rx.ring.prod ) { + while ( rtl->rx.cons != rtl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.cons % RTL_NUM_RX_DESC ); - rx = &rtl->rx.ring.desc[rx_idx]; + rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC ); + rx = &rtl->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; - /* Unmap buffer */ - dma_unmap ( &rtl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = rtl->rx.iobuf[rx_idx]; - rtl->rx.iobuf[rx_idx] = NULL; + iobuf = rtl->rx_iobuf[rx_idx]; + rtl->rx_iobuf[rx_idx] = NULL; len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); @@ -984,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { "%zd)\n", rtl, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - rtl->rx.ring.cons++; + rtl->rx.cons++; } } @@ -1128,9 +1109,8 @@ static int realtek_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( rtl, 0, sizeof ( *rtl ) ); - rtl->dma = &pci->dma; - realtek_init_ring ( &rtl->tx.ring, RTL_NUM_TX_DESC, RTL_TNPDS ); - realtek_init_ring ( &rtl->rx.ring, RTL_NUM_RX_DESC, RTL_RDSAR ); + realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS ); + realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1142,6 +1122,9 @@ static int realtek_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + rtl->dma = &pci->dma; + /* Reset the NIC */ if ( ( rc = realtek_reset ( rtl ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h index c7cb7e422..d4642fd76 100644 --- a/src/drivers/net/realtek.h +++ b/src/drivers/net/realtek.h @@ -274,24 +274,6 @@ realtek_init_ring ( struct realtek_ring *ring, unsigned int count, ring->reg = reg; } -/** Transmit ring */ -struct realtek_tx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct realtek_rx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[RTL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_RX_DESC]; -}; - /** Receive buffer (legacy mode *) */ struct realtek_rx_buffer { /** Buffer */ @@ -327,9 +309,11 @@ struct realtek_nic { unsigned int tppoll; /** Transmit descriptor ring */ - struct realtek_tx_ring tx; + struct realtek_ring tx; /** Receive descriptor ring */ - struct realtek_rx_ring rx; + struct realtek_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; /** Receive buffer (legacy mode) */ struct realtek_rx_buffer rxbuf; }; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 842c9d6ef..b3fa24e47 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -12,7 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -385,25 +384,4 @@ dma_set_mask_64bit ( struct dma_device *dma ) { dma_set_mask ( dma, ~( ( physaddr_t ) 0 ) ); } -/** - * Map I/O buffer for transmitting data to device - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, - struct io_buffer *iobuf ) { - - /* Map I/O buffer */ - return dma_map ( dma, map, virt_to_phys ( iobuf->data ), - iob_len ( iobuf ), DMA_TX ); -} - -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, - struct dma_mapping *map, - size_t len ); - #endif /* _IPXE_DMA_H */ diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index b40ade350..630a7753c 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** * Minimum I/O buffer length @@ -38,6 +39,9 @@ struct io_buffer { */ struct list_head list; + /** DMA mapping */ + struct dma_mapping map; + /** Start of the buffer */ void *head; /** Start of data */ @@ -210,10 +214,61 @@ static inline void iob_populate ( struct io_buffer *iobuf, (iobuf) = NULL; \ __iobuf; } ) +/** + * Map I/O buffer for transmit DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); +} + +/** + * Map empty I/O buffer for receive DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + assert ( iob_len ( iobuf ) == 0 ); + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_tailroom ( iobuf ), DMA_RX ); +} + +/** + * Get I/O buffer DMA address + * + * @v iobuf I/O buffer + * @ret addr DMA address + */ +static inline __always_inline physaddr_t iob_dma ( struct io_buffer *iobuf ) { + return dma ( &iobuf->map, iobuf->data ); +} + +/** + * Unmap I/O buffer for DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline void iob_unmap ( struct io_buffer *iobuf ) { + dma_unmap ( &iobuf->map ); +} + extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align, size_t offset ); extern struct io_buffer * __malloc alloc_iob ( size_t len ); extern void free_iob ( struct io_buffer *iobuf ); +extern struct io_buffer * __malloc alloc_rx_iob ( size_t len, + struct dma_device *dma ); +extern void free_rx_iob ( struct io_buffer *iobuf ); extern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ); extern struct io_buffer * iob_concatenate ( struct list_head *list ); diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index d498ab697..b9c651c71 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -246,6 +246,10 @@ struct net_device_operations { * * This method is guaranteed to be called only when the device * is open. + * + * If the network device has an associated DMA device, then + * the I/O buffer will be automatically mapped for transmit + * DMA. */ int ( * transmit ) ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -358,6 +362,8 @@ struct net_device { char name[NETDEV_NAME_LEN]; /** Underlying hardware device */ struct device *dev; + /** DMA device */ + struct dma_device *dma; /** Network device operations */ struct net_device_operations *op; diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 7687ffb43..8c30c9514 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,6 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, int rc; /* Sanity check */ + assert ( map->dma == NULL ); assert ( map->offset == 0 ); assert ( map->token == NULL ); @@ -409,6 +410,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ + map->dma = NULL; map->offset = 0; map->token = NULL; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3b02e64bd..f3feca26b 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -307,6 +307,12 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) goto err; + /* Map for DMA, if required */ + if ( netdev->dma && ( ! dma_mapped ( &iobuf->map ) ) ) { + if ( ( rc = iob_map_tx ( iobuf, netdev->dma ) ) != 0 ) + goto err; + } + /* Transmit packet */ if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; @@ -340,6 +346,9 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { * Failure to do this will cause the retransmitted packet to be * immediately redeferred (which will result in out-of-order * transmissions and other nastiness). + * + * I/O buffers that have been mapped for DMA will remain mapped while + * present in the deferred transmit queue. */ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { @@ -365,6 +374,9 @@ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { * * The packet is discarded and a TX error is recorded. This function * takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_tx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -379,6 +391,10 @@ void netdev_tx_err ( struct net_device *netdev, netdev->name, iobuf, strerror ( rc ) ); } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); } @@ -466,6 +482,9 @@ static void netdev_tx_flush ( struct net_device *netdev ) { * * The packet is added to the network device's RX queue. This * function takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { int rc; @@ -479,6 +498,10 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { return; } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->rx_queue ); @@ -497,6 +520,9 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { * takes ownership of the I/O buffer. @c iobuf may be NULL if, for * example, the net device wishes to report an error due to being * unable to allocate an I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -504,6 +530,10 @@ void netdev_rx_err ( struct net_device *netdev, DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", netdev->name, iobuf, strerror ( rc ) ); + /* Unmap I/O buffer, if required */ + if ( iobuf && dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); @@ -1178,6 +1208,8 @@ static unsigned int net_discard ( void ) { /* Discard first deferred packet */ list_del ( &iobuf->list ); + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); free_iob ( iobuf ); /* Report discard */ -- cgit v1.2.3-55-g7522 From 6e01b74a8ac6a3c3c6806ae286df033f71962f9a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 29 Nov 2020 10:55:14 +0000 Subject: [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 --- src/core/dma.c | 39 +++++++++++++++++++ src/include/ipxe/dma.h | 93 +++++++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_pci.c | 34 +++++++++++++++++ 3 files changed, 166 insertions(+) (limited to 'src/core') diff --git a/src/core/dma.c b/src/core/dma.c index e5fa3f323..5d6868216 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -44,6 +44,8 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_map ); PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); PROVIDE_DMAAPI_INLINE ( flat, dma_free ); +PROVIDE_DMAAPI_INLINE ( flat, dma_umalloc ); +PROVIDE_DMAAPI_INLINE ( flat, dma_ufree ); PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); @@ -119,6 +121,41 @@ static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { dma->op->free ( dma, map, addr, len ); } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static userptr_t dma_op_umalloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return UNULL; + return op->umalloc ( dma, map, len, align ); +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static void dma_op_ufree ( struct dma_mapping *map, userptr_t addr, + size_t len ) { + struct dma_device *dma = map->dma; + + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->ufree ( dma, map, addr, len ); +} + /** * Set addressable space mask * @@ -136,5 +173,7 @@ PROVIDE_DMAAPI ( op, dma_map, dma_op_map ); PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); +PROVIDE_DMAAPI ( op, dma_umalloc, dma_op_umalloc ); +PROVIDE_DMAAPI ( op, dma_ufree, dma_op_ufree ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); PROVIDE_DMAAPI_INLINE ( op, dma_phys ); diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index b3fa24e47..385e4baf7 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -13,6 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #ifdef DMAAPI_OP @@ -96,6 +97,28 @@ struct dma_operations { */ void ( * free ) ( struct dma_device *dma, struct dma_mapping *map, void *addr, size_t len ); + /** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ + userptr_t ( * umalloc ) ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ); + /** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ + void ( * ufree ) ( struct dma_device *dma, struct dma_mapping *map, + userptr_t addr, size_t len ); /** * Set addressable space mask * @@ -233,6 +256,55 @@ DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, } } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static inline __always_inline userptr_t +DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align __unused ) { + userptr_t addr; + + /* Allocate buffer */ + addr = umalloc ( len ); + + /* Increment mapping count (for debugging) */ + if ( DBG_LOG && addr ) { + map->dma = dma; + dma->mapped++; + } + + return addr; +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_ufree ) ( struct dma_mapping *map, + userptr_t addr, size_t len __unused ) { + + /* Free buffer */ + ufree ( addr ); + + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } +} + /** * Set addressable space mask * @@ -316,6 +388,27 @@ void * dma_alloc ( struct dma_device *dma, struct dma_mapping *map, */ void dma_free ( struct dma_mapping *map, void *addr, size_t len ); +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +void dma_ufree ( struct dma_mapping *map, userptr_t addr, size_t len ); + /** * Set addressable space mask * diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 9f6bf952b..6b32fd6a9 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -504,6 +504,38 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, dma->allocated--; } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static userptr_t efipci_dma_umalloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ) { + void *addr; + + addr = efipci_dma_alloc ( dma, map, len, align ); + return virt_to_user ( addr ); +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static void efipci_dma_ufree ( struct dma_device *dma, struct dma_mapping *map, + userptr_t addr, size_t len ) { + + efipci_dma_free ( dma, map, user_to_virt ( addr, 0 ), len ); +} + /** * Set addressable space mask * @@ -542,6 +574,8 @@ static struct dma_operations efipci_dma_operations = { .unmap = efipci_dma_unmap, .alloc = efipci_dma_alloc, .free = efipci_dma_free, + .umalloc = efipci_dma_umalloc, + .ufree = efipci_dma_ufree, .set_mask = efipci_dma_set_mask, }; -- cgit v1.2.3-55-g7522 From cb0ba2f8253bc4ed3b301928c4a84d6ca1e7593b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Dec 2020 13:48:35 +0000 Subject: [interface] Ignore any attempts to plug in the null interface Allow intf_plug() and intf_plug_plug() to be called safely on interfaces that may be the null interface. Signed-off-by: Michael Brown --- src/core/interface.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/core') diff --git a/src/core/interface.c b/src/core/interface.c index 402aa4541..05e7e4777 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -81,9 +81,14 @@ struct interface null_intf = INTF_INIT ( null_intf_desc ); * interface is updated to point to the new destination interface. */ void intf_plug ( struct interface *intf, struct interface *dest ) { + + if ( intf == &null_intf ) + return; + DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n", INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) ); + intf_get ( dest ); intf_put ( intf->dest ); intf->dest = dest; -- cgit v1.2.3-55-g7522 From 09fe2bbd343a46010e89d848e5887bfb5fc3f6f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Dec 2020 13:49:47 +0000 Subject: [interface] Provide intf_insert() to insert a filter interface Generalise the filter interface insertion logic from block_translate() and expose as intf_insert(), allowing a filter interface to be inserted on any existing interface. Signed-off-by: Michael Brown --- src/core/blocktrans.c | 4 +--- src/core/interface.c | 17 +++++++++++++++++ src/include/ipxe/interface.h | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/blocktrans.c b/src/core/blocktrans.c index 3f32f9cf8..f9dcb95d2 100644 --- a/src/core/blocktrans.c +++ b/src/core/blocktrans.c @@ -242,9 +242,7 @@ int block_translate ( struct interface *block, userptr_t buffer, size_t size ) { } /* Attach to interfaces, mortalise self, and return */ - assert ( block->dest != &null_intf ); - intf_plug_plug ( &blktrans->xfer, block->dest ); - intf_plug_plug ( &blktrans->block, block ); + intf_insert ( block, &blktrans->block, &blktrans->xfer ); ref_put ( &blktrans->refcnt ); DBGC2 ( blktrans, "BLKTRANS %p created", blktrans ); diff --git a/src/core/interface.c b/src/core/interface.c index 05e7e4777..34a4180a5 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -390,6 +390,23 @@ void intfs_restart ( int rc, ... ) { va_end ( intfs ); } +/** + * Insert a filter interface + * + * @v intf Object interface + * @v upper Upper end of filter + * @v lower Lower end of filter + */ +void intf_insert ( struct interface *intf, struct interface *upper, + struct interface *lower ) { + struct interface *dest = intf->dest; + + intf_get ( dest ); + intf_plug_plug ( intf, upper ); + intf_plug_plug ( lower, dest ); + intf_put ( dest ); +} + /** * Poke an object interface * diff --git a/src/include/ipxe/interface.h b/src/include/ipxe/interface.h index 9281aeef5..19f58a4b4 100644 --- a/src/include/ipxe/interface.h +++ b/src/include/ipxe/interface.h @@ -169,6 +169,8 @@ extern void intfs_shutdown ( int rc, ... ) __attribute__ (( sentinel )); extern void intf_restart ( struct interface *intf, int rc ); extern void intfs_vrestart ( va_list intfs, int rc ); extern void intfs_restart ( int rc, ... ) __attribute__ (( sentinel )); +extern void intf_insert ( struct interface *intf, struct interface *upper, + struct interface *lower ); extern void intf_poke ( struct interface *intf, void ( type ) ( struct interface *intf ) ); -- cgit v1.2.3-55-g7522 From 99ac69b8a9a48207913e98ac6b357c029b0eef81 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 20 Jan 2021 18:03:16 +0000 Subject: [image] Provide image_set_data() Extract part of the logic in initrd_init() to a standalone function image_set_data(). Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 21 +++++++++------------ src/core/image.c | 24 ++++++++++++++++++++++++ src/include/ipxe/image.h | 1 + 3 files changed, 34 insertions(+), 12 deletions(-) (limited to 'src/core') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index f96b23af4..4de3bfafe 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -38,7 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include /** Command line physical address @@ -202,23 +201,21 @@ static int initrd_init ( void ) { rc = -ENOMEM; goto err_alloc_image; } + + /* Set image name */ if ( ( rc = image_set_name ( image, "" ) ) != 0 ) { DBGC ( colour, "RUNTIME could not set image name: %s\n", strerror ( rc ) ); goto err_set_name; } - /* Allocate and copy initrd content */ - image->data = umalloc ( initrd_len ); - if ( ! image->data ) { - DBGC ( colour, "RUNTIME could not allocate %d bytes for " - "initrd\n", initrd_len ); - rc = -ENOMEM; - goto err_umalloc; + /* Set image content */ + if ( ( rc = image_set_data ( image, phys_to_user ( initrd_phys ), + initrd_len ) ) != 0 ) { + DBGC ( colour, "RUNTIME could not set image data: %s\n", + strerror ( rc ) ); + goto err_set_data; } - image->len = initrd_len; - memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0, - initrd_len ); /* Mark initrd as consumed */ initrd_phys = 0; @@ -236,7 +233,7 @@ static int initrd_init ( void ) { return 0; err_register_image: - err_umalloc: + err_set_data: err_set_name: image_put ( image ); err_alloc_image: diff --git a/src/core/image.c b/src/core/image.c index 078ce1bb9..54b998025 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -175,6 +175,30 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) { return 0; } +/** + * Set image data + * + * @v image Image + * @v data Image data + * @v len Length of image data + * @ret rc Return status code + */ +int image_set_data ( struct image *image, userptr_t data, size_t len ) { + userptr_t new; + + /* (Re)allocate image data */ + new = urealloc ( image->data, len ); + if ( ! new ) + return -ENOMEM; + image->data = new; + + /* Copy in new image data */ + memcpy_user ( image->data, 0, data, 0, len ); + image->len = len; + + return 0; +} + /** * Determine image type * diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 2e7eb4cee..4c3877607 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -175,6 +175,7 @@ extern struct image * alloc_image ( struct uri *uri ); extern int image_set_uri ( struct image *image, struct uri *uri ); extern int image_set_name ( struct image *image, const char *name ); extern int image_set_cmdline ( struct image *image, const char *cmdline ); +extern int image_set_data ( struct image *image, userptr_t data, size_t len ); extern int register_image ( struct image *image ); extern void unregister_image ( struct image *image ); struct image * find_image ( const char *name ); -- cgit v1.2.3-55-g7522 From 989a7a8032db02eb0524bd78a674d3b087dea3a6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 25 Jan 2021 16:18:28 +0000 Subject: [image] Provide image_memory() Consolidate the remaining logic common to initrd_init() and imgmem() into a shared image_memory() function. Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 44 +++++----------------------------------- src/core/image.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/hci/commands/image_mem_cmd.c | 4 +--- src/include/ipxe/image.h | 2 ++ src/include/usr/imgmgmt.h | 3 +-- src/usr/imgmgmt.c | 41 ++++++++----------------------------- 6 files changed, 62 insertions(+), 76 deletions(-) (limited to 'src/core') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index 4de3bfafe..02072b5bf 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -179,7 +179,6 @@ static int cmdline_init ( void ) { */ static int initrd_init ( void ) { struct image *image; - int rc; /* Do nothing if no initrd was specified */ if ( ! initrd_phys ) { @@ -193,51 +192,18 @@ static int initrd_init ( void ) { DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n", initrd_phys, ( initrd_phys + initrd_len ) ); - /* Allocate image */ - image = alloc_image ( NULL ); + /* Create initrd image */ + image = image_memory ( "", phys_to_user ( initrd_phys ), + initrd_len ); if ( ! image ) { - DBGC ( colour, "RUNTIME could not allocate image for " - "initrd\n" ); - rc = -ENOMEM; - goto err_alloc_image; - } - - /* Set image name */ - if ( ( rc = image_set_name ( image, "" ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not set image name: %s\n", - strerror ( rc ) ); - goto err_set_name; - } - - /* Set image content */ - if ( ( rc = image_set_data ( image, phys_to_user ( initrd_phys ), - initrd_len ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not set image data: %s\n", - strerror ( rc ) ); - goto err_set_data; + DBGC ( colour, "RUNTIME could not create initrd image\n" ); + return -ENOMEM; } /* Mark initrd as consumed */ initrd_phys = 0; - /* Register image */ - if ( ( rc = register_image ( image ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not register initrd: %s\n", - strerror ( rc ) ); - goto err_register_image; - } - - /* Drop our reference to the image */ - image_put ( image ); - return 0; - - err_register_image: - err_set_data: - err_set_name: - image_put ( image ); - err_alloc_image: - return rc; } /** diff --git a/src/core/image.c b/src/core/image.c index 54b998025..9fe77c54c 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -505,3 +505,47 @@ int image_set_trust ( int require_trusted, int permanent ) { return 0; } + +/** + * Create registered image from block of memory + * + * @v name Name + * @v data Image data + * @v len Length + * @ret image Image, or NULL on error + */ +struct image * image_memory ( const char *name, userptr_t data, size_t len ) { + struct image *image; + int rc; + + /* Allocate image */ + image = alloc_image ( NULL ); + if ( ! image ) { + rc = -ENOMEM; + goto err_alloc_image; + } + + /* Set name */ + if ( ( rc = image_set_name ( image, name ) ) != 0 ) + goto err_set_name; + + /* Set data */ + if ( ( rc = image_set_data ( image, data, len ) ) != 0 ) + goto err_set_data; + + /* Register image */ + if ( ( rc = register_image ( image ) ) != 0 ) + goto err_register; + + /* Drop local reference to image */ + image_put ( image ); + + return image; + + err_register: + err_set_data: + err_set_name: + image_put ( image ); + err_alloc_image: + return NULL; +} diff --git a/src/hci/commands/image_mem_cmd.c b/src/hci/commands/image_mem_cmd.c index 61d50534d..c8bfab1ad 100644 --- a/src/hci/commands/image_mem_cmd.c +++ b/src/hci/commands/image_mem_cmd.c @@ -60,7 +60,6 @@ static struct command_descriptor imgmem_cmd = */ static int imgmem_exec ( int argc, char **argv ) { struct imgmem_options opts; - struct image *image; unsigned int data; unsigned int len; int rc; @@ -82,8 +81,7 @@ static int imgmem_exec ( int argc, char **argv ) { return rc; /* Create image */ - if ( ( rc = imgmem ( phys_to_user ( data ), len, opts.name, - &image ) ) != 0 ) + if ( ( rc = imgmem ( opts.name, phys_to_user ( data ), len ) ) != 0 ) return rc; return 0; diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 4c3877607..4fd270081 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -184,6 +184,8 @@ extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); extern struct image * image_find_selected ( void ); extern int image_set_trust ( int require_trusted, int permanent ); +extern struct image * image_memory ( const char *name, userptr_t data, + size_t len ); extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ); extern int image_asn1 ( struct image *image, size_t offset, struct asn1_cursor **cursor ); diff --git a/src/include/usr/imgmgmt.h b/src/include/usr/imgmgmt.h index c59cf1a0b..14fb7cbc6 100644 --- a/src/include/usr/imgmgmt.h +++ b/src/include/usr/imgmgmt.h @@ -18,7 +18,6 @@ extern int imgdownload_string ( const char *uri_string, unsigned long timeout, extern int imgacquire ( const char *name, unsigned long timeout, struct image **image ); extern void imgstat ( struct image *image ); -extern int imgmem ( userptr_t data, size_t len, const char *name, - struct image **image ); +extern int imgmem ( const char *name, userptr_t data, size_t len ); #endif /* _USR_IMGMGMT_H */ diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index bf4c745ea..f8d149153 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -173,43 +173,20 @@ void imgstat ( struct image *image ) { /** * Create image from block of memory * + * @v name Name * @v data Image data * @v len Length - * @v name Name - * @v image Image to fill in * @ret rc Return status code */ -int imgmem ( userptr_t data, size_t len, const char *name, - struct image **image ) { - int rc; - - /* Allocate image */ - *image = alloc_image ( NULL ); - if ( ! *image ) { - rc = -ENOMEM; - goto err_alloc_image; - } - - /* Set name */ - if ( ( rc = image_set_name ( *image, name ) ) != 0 ) - goto err_set_name; +int imgmem ( const char *name, userptr_t data, size_t len ) { + struct image *image; - /* Set data */ - if ( ( rc = image_set_data ( *image, data, len ) ) != 0 ) { - printf ( "Could not set image data: %s\n", strerror ( rc ) ); - goto err_set_data; - } - - /* Register image */ - if ( ( rc = register_image ( *image ) ) != 0 ) { - printf ( "Could not register image: %s\n", strerror ( rc ) ); - goto err_register_image; + /* Create image */ + image = image_memory ( name, data, len ); + if ( ! image ) { + printf ( "Could not create image\n" ); + return -ENOMEM; } - err_register_image: - err_set_data: - err_set_name: - image_put ( *image ); - err_alloc_image: - return rc; + return 0; } -- cgit v1.2.3-55-g7522 From 057674bb1f766db8b4c6593dc238ea68e4f38028 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Feb 2021 15:59:52 +0000 Subject: [pxe] Split out platform-independent portions of cachedhcp.c Split out the portions of cachedhcp.c that can be shared between BIOS and UEFI (both of which can provide a buffer containing a previously obtained DHCP packet, and neither of which provide a means to determine the length of this DHCP packet). Signed-off-by: Michael Brown --- src/arch/x86/core/cachedhcp.c | 179 ------------------------- src/arch/x86/interface/pcbios/bios_cachedhcp.c | 76 +++++++++++ src/core/cachedhcp.c | 158 ++++++++++++++++++++++ src/include/ipxe/cachedhcp.h | 17 +++ src/include/ipxe/errfile.h | 1 + 5 files changed, 252 insertions(+), 179 deletions(-) delete mode 100644 src/arch/x86/core/cachedhcp.c create mode 100644 src/arch/x86/interface/pcbios/bios_cachedhcp.c create mode 100644 src/core/cachedhcp.c create mode 100644 src/include/ipxe/cachedhcp.h (limited to 'src/core') diff --git a/src/arch/x86/core/cachedhcp.c b/src/arch/x86/core/cachedhcp.c deleted file mode 100644 index dffafe3c9..000000000 --- a/src/arch/x86/core/cachedhcp.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2013 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include -#include -#include -#include -#include -#include -#include - -/** @file - * - * Cached DHCP packet - * - */ - -/** Cached DHCPACK physical address - * - * This can be set by the prefix. - */ -uint32_t __bss16 ( cached_dhcpack_phys ); -#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) - -/** Colour for debug messages */ -#define colour &cached_dhcpack_phys - -/** Cached DHCPACK */ -static struct dhcp_packet *cached_dhcpack; - -/** - * Cached DHCPACK startup function - * - */ -static void cachedhcp_init ( void ) { - struct dhcp_packet *dhcppkt; - struct dhcp_packet *tmp; - struct dhcphdr *dhcphdr; - size_t max_len; - size_t len; - - /* Do nothing if no cached DHCPACK is present */ - if ( ! cached_dhcpack_phys ) { - DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); - return; - } - - /* No reliable way to determine length before parsing packet; - * start by assuming maximum length permitted by PXE. - */ - max_len = sizeof ( BOOTPLAYER_t ); - - /* Allocate and populate DHCP packet */ - dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len ); - if ( ! dhcppkt ) { - DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); - return; - } - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); - copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0, - max_len ); - dhcppkt_init ( dhcppkt, dhcphdr, max_len ); - - /* Shrink packet to required length. If reallocation fails, - * just continue to use the original packet and waste the - * unused space. - */ - len = dhcppkt_len ( dhcppkt ); - assert ( len <= max_len ); - tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); - if ( tmp ) - dhcppkt = tmp; - - /* Reinitialise packet at new address */ - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); - dhcppkt_init ( dhcppkt, dhcphdr, len ); - - /* Store as cached DHCPACK, and mark original copy as consumed */ - DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n", - cached_dhcpack_phys, len ); - cached_dhcpack = dhcppkt; - cached_dhcpack_phys = 0; -} - -/** - * Cached DHCPACK startup function - * - */ -static void cachedhcp_startup ( void ) { - - /* If cached DHCP packet was not claimed by any network device - * during startup, then free it. - */ - if ( cached_dhcpack ) { - DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); - dhcppkt_put ( cached_dhcpack ); - cached_dhcpack = NULL; - } -} - -/** Cached DHCPACK initialisation function */ -struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = cachedhcp_init, -}; - -/** Cached DHCPACK startup function */ -struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { - .name = "cachedhcp", - .startup = cachedhcp_startup, -}; - -/** - * Apply cached DHCPACK to network device, if applicable - * - * @v netdev Network device - * @ret rc Return status code - */ -static int cachedhcp_probe ( struct net_device *netdev ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; - int rc; - - /* Do nothing unless we have a cached DHCPACK */ - if ( ! cached_dhcpack ) - return 0; - - /* Do nothing unless cached DHCPACK's MAC address matches this - * network device. - */ - if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, - ll_protocol->ll_addr_len ) != 0 ) { - DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", - netdev->name ); - return 0; - } - DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); - - /* Register as DHCP settings for this network device */ - if ( ( rc = register_settings ( &cached_dhcpack->settings, - netdev_settings ( netdev ), - DHCP_SETTINGS_NAME ) ) != 0 ) { - DBGC ( colour, "CACHEDHCP could not register settings: %s\n", - strerror ( rc ) ); - return rc; - } - - /* Claim cached DHCPACK */ - dhcppkt_put ( cached_dhcpack ); - cached_dhcpack = NULL; - - return 0; -} - -/** Cached DHCP packet network device driver */ -struct net_driver cachedhcp_driver __net_driver = { - .name = "cachedhcp", - .probe = cachedhcp_probe, -}; diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c new file mode 100644 index 000000000..3d38699f7 --- /dev/null +++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cached_dhcpack_phys ); +#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) + +/** Colour for debug messages */ +#define colour &cached_dhcpack_phys + +/** + * Cached DHCPACK initialisation function + * + */ +static void cachedhcp_init ( void ) { + int rc; + + /* Do nothing if no cached DHCPACK is present */ + if ( ! cached_dhcpack_phys ) { + DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); + return; + } + + /* Record cached DHCPACK */ + if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ), + sizeof ( BOOTPLAYER_t ) ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n", + strerror ( rc ) ); + return; + } + + /* Mark as consumed */ + cached_dhcpack_phys = 0; +} + +/** Cached DHCPACK initialisation function */ +struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = cachedhcp_init, +}; diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c new file mode 100644 index 000000000..0e7da4bf2 --- /dev/null +++ b/src/core/cachedhcp.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK */ +static struct dhcp_packet *cached_dhcpack; + +/** Colour for debug messages */ +#define colour &cached_dhcpack + +/** + * Record cached DHCPACK + * + * @v data DHCPACK packet buffer + * @v max_len Maximum possible length + * @ret rc Return status code + */ +int cachedhcp_record ( userptr_t data, size_t max_len ) { + struct dhcp_packet *dhcppkt; + struct dhcp_packet *tmp; + struct dhcphdr *dhcphdr; + size_t len; + + /* Allocate and populate DHCP packet */ + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len ); + if ( ! dhcppkt ) { + DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); + return -ENOMEM; + } + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + copy_from_user ( dhcphdr, data, 0, max_len ); + dhcppkt_init ( dhcppkt, dhcphdr, max_len ); + + /* Shrink packet to required length. If reallocation fails, + * just continue to use the original packet and waste the + * unused space. + */ + len = dhcppkt_len ( dhcppkt ); + assert ( len <= max_len ); + tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); + if ( tmp ) + dhcppkt = tmp; + + /* Reinitialise packet at new address */ + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Store as cached DHCPACK, and mark original copy as consumed */ + DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n", + user_to_phys ( data, 0 ), len, max_len ); + cached_dhcpack = dhcppkt; + + return 0; +} + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_startup ( void ) { + + /* If cached DHCP packet was not claimed by any network device + * during startup, then free it. + */ + if ( cached_dhcpack ) { + DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + } +} + +/** Cached DHCPACK startup function */ +struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { + .name = "cachedhcp", + .startup = cachedhcp_startup, +}; + +/** + * Apply cached DHCPACK to network device, if applicable + * + * @v netdev Network device + * @ret rc Return status code + */ +static int cachedhcp_probe ( struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Do nothing unless we have a cached DHCPACK */ + if ( ! cached_dhcpack ) + return 0; + + /* Do nothing unless cached DHCPACK's MAC address matches this + * network device. + */ + if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", + netdev->name ); + return 0; + } + DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); + + /* Register as DHCP settings for this network device */ + if ( ( rc = register_settings ( &cached_dhcpack->settings, + netdev_settings ( netdev ), + DHCP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not register settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Claim cached DHCPACK */ + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + + return 0; +} + +/** Cached DHCP packet network device driver */ +struct net_driver cachedhcp_driver __net_driver = { + .name = "cachedhcp", + .probe = cachedhcp_probe, +}; diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h new file mode 100644 index 000000000..7765c6455 --- /dev/null +++ b/src/include/ipxe/cachedhcp.h @@ -0,0 +1,17 @@ +#ifndef _IPXE_CACHEDHCP_H +#define _IPXE_CACHEDHCP_H + +/** @file + * + * Cached DHCP packet + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +extern int cachedhcp_record ( userptr_t data, size_t max_len ); + +#endif /* _IPXE_CACHEDHCP_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index f14cb8619..4c1c334d8 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -76,6 +76,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 ) #define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 ) #define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 ) +#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) -- cgit v1.2.3-55-g7522 From 0956fb52c4d435701749bf2eff0d1b171361e0f1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 28 Feb 2021 23:58:06 +0000 Subject: [acpi] Use a fixed colour for debug messages Signed-off-by: Michael Brown --- src/core/acpi.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/core') diff --git a/src/core/acpi.c b/src/core/acpi.c index e6912afa2..19b708271 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -35,6 +35,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** Colour for debug messages */ +#define colour FADT_SIGNATURE + /****************************************************************************** * * Utility functions @@ -106,17 +109,17 @@ userptr_t acpi_find ( uint32_t signature, unsigned int index ) { /* Read RSDT header */ copy_from_user ( &acpi, rsdt, 0, sizeof ( acpi ) ); if ( acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) { - DBGC ( rsdt, "RSDT %#08lx has invalid signature:\n", + DBGC ( colour, "RSDT %#08lx has invalid signature:\n", user_to_phys ( rsdt, 0 ) ); - DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi, + DBGC_HDA ( colour, user_to_phys ( rsdt, 0 ), &acpi, sizeof ( acpi ) ); return UNULL; } len = le32_to_cpu ( acpi.length ); if ( len < sizeof ( rsdtab->acpi ) ) { - DBGC ( rsdt, "RSDT %#08lx has invalid length:\n", + DBGC ( colour, "RSDT %#08lx has invalid length:\n", user_to_phys ( rsdt, 0 ) ); - DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi, + DBGC_HDA ( colour, user_to_phys ( rsdt, 0 ), &acpi, sizeof ( acpi ) ); return UNULL; } @@ -147,20 +150,20 @@ userptr_t acpi_find ( uint32_t signature, unsigned int index ) { /* Check table integrity */ if ( acpi_checksum ( table ) != 0 ) { - DBGC ( rsdt, "RSDT %#08lx found %s with bad checksum " - "at %08lx\n", user_to_phys ( rsdt, 0 ), + DBGC ( colour, "RSDT %#08lx found %s with bad " + "checksum at %08lx\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ), user_to_phys ( table, 0 ) ); break; } - DBGC ( rsdt, "RSDT %#08lx found %s at %08lx\n", + DBGC ( colour, "RSDT %#08lx found %s at %08lx\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ), user_to_phys ( table, 0 ) ); return table; } - DBGC ( rsdt, "RSDT %#08lx could not find %s\n", + DBGC ( colour, "RSDT %#08lx could not find %s\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ) ); return UNULL; } @@ -288,7 +291,7 @@ int acpi_sx ( uint32_t signature ) { return sx; } - DBGC ( rsdt, "RSDT %#08lx could not find \\_Sx \"%s\"\n", + DBGC ( colour, "RSDT %#08lx could not find \\_Sx \"%s\"\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ) ); return -ENOENT; } -- cgit v1.2.3-55-g7522 From d175936b78abc2b137a5a1e66ad7cf79b5849058 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 28 Feb 2021 23:59:15 +0000 Subject: [acpi] Eliminate redundant acpi_find_rsdt() in acpi_sx() The result from acpi_find_rsdt() is used only for the debug message. Simplify the debug message and remove the otherwise redundant call to acpi_find_rsdt(). Signed-off-by: Michael Brown --- src/core/acpi.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'src/core') diff --git a/src/core/acpi.c b/src/core/acpi.c index 19b708271..75511736d 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -259,20 +259,12 @@ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) { */ int acpi_sx ( uint32_t signature ) { struct acpi_fadt fadtab; - userptr_t rsdt; userptr_t fadt; userptr_t dsdt; userptr_t ssdt; unsigned int i; int sx; - /* Locate RSDT */ - rsdt = acpi_find_rsdt(); - if ( ! rsdt ) { - DBG ( "RSDT not found\n" ); - return -ENOENT; - } - /* Try DSDT first */ fadt = acpi_find ( FADT_SIGNATURE, 0 ); if ( fadt ) { @@ -291,8 +283,8 @@ int acpi_sx ( uint32_t signature ) { return sx; } - DBGC ( colour, "RSDT %#08lx could not find \\_Sx \"%s\"\n", - user_to_phys ( rsdt, 0 ), acpi_name ( signature ) ); + DBGC ( colour, "ACPI could not find \\_Sx \"%s\"\n", + acpi_name ( signature ) ); return -ENOENT; } -- cgit v1.2.3-55-g7522 From 9776f6ece1104cc32de3249844a8a7387112f32f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Mar 2021 00:08:23 +0000 Subject: [acpi] Allow for platforms that provide ACPI tables individually The ACPI API currently expects platforms to provide access to a single contiguous ACPI table. Some platforms (e.g. Linux userspace) do not provide a convenient way to obtain the entire ACPI table, but do provide access to individual tables. All iPXE consumers of the ACPI API require access only to individual tables. Redefine the internal API to make acpi_find() an API method, with all existing implementations delegating to the current RSDT-based implementation. Signed-off-by: Michael Brown --- src/arch/x86/include/ipxe/rsdp.h | 13 +++++++++++++ src/arch/x86/interface/pcbios/rsdp.c | 1 + src/core/acpi.c | 4 ++-- src/core/null_acpi.c | 2 +- src/include/ipxe/acpi.h | 12 +++++++++++- src/include/ipxe/efi/efi_acpi.h | 13 +++++++++++++ src/include/ipxe/null_acpi.h | 6 ++++-- src/interface/efi/efi_acpi.c | 1 + 8 files changed, 46 insertions(+), 6 deletions(-) (limited to 'src/core') diff --git a/src/arch/x86/include/ipxe/rsdp.h b/src/arch/x86/include/ipxe/rsdp.h index 7e32c0011..14afcd774 100644 --- a/src/arch/x86/include/ipxe/rsdp.h +++ b/src/arch/x86/include/ipxe/rsdp.h @@ -15,4 +15,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_rsdp __rsdp_ #endif +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( rsdp, acpi_find ) ( uint32_t signature, unsigned int index ) { + + return acpi_find_via_rsdt ( signature, index ); +} + #endif /* _IPXE_RSDP_H */ diff --git a/src/arch/x86/interface/pcbios/rsdp.c b/src/arch/x86/interface/pcbios/rsdp.c index 8da0b5588..3c67b7525 100644 --- a/src/arch/x86/interface/pcbios/rsdp.c +++ b/src/arch/x86/interface/pcbios/rsdp.c @@ -123,3 +123,4 @@ static userptr_t rsdp_find_rsdt ( void ) { } PROVIDE_ACPI ( rsdp, acpi_find_rsdt, rsdp_find_rsdt ); +PROVIDE_ACPI_INLINE ( rsdp, acpi_find ); diff --git a/src/core/acpi.c b/src/core/acpi.c index 75511736d..52eb63a04 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -83,13 +83,13 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { } /** - * Locate ACPI table + * Locate ACPI table via RSDT * * @v signature Requested table signature * @v index Requested index of table with this signature * @ret table Table, or UNULL if not found */ -userptr_t acpi_find ( uint32_t signature, unsigned int index ) { +userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { struct acpi_header acpi; struct acpi_rsdt *rsdtab; typeof ( rsdtab->entry[0] ) entry; diff --git a/src/core/null_acpi.c b/src/core/null_acpi.c index 90c784855..acca37872 100644 --- a/src/core/null_acpi.c +++ b/src/core/null_acpi.c @@ -1,3 +1,3 @@ #include -PROVIDE_ACPI_INLINE ( null, acpi_find_rsdt ); +PROVIDE_ACPI_INLINE ( null, acpi_find ); diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index f979ace45..6d19f05fa 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -355,6 +355,8 @@ struct acpi_model { #define PROVIDE_ACPI_INLINE( _subsys, _api_func ) \ PROVIDE_SINGLE_API_INLINE ( ACPI_PREFIX_ ## _subsys, _api_func ) +extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); + /* Include all architecture-independent ACPI API headers */ #include #include @@ -369,13 +371,21 @@ struct acpi_model { */ userptr_t acpi_find_rsdt ( void ); +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +userptr_t acpi_find ( uint32_t signature, unsigned int index ); + extern struct acpi_descriptor * acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) extern void acpi_fix_checksum ( struct acpi_header *acpi ); -extern userptr_t acpi_find ( uint32_t signature, unsigned int index ); extern int acpi_sx ( uint32_t signature ); extern void acpi_add ( struct acpi_descriptor *desc ); extern void acpi_del ( struct acpi_descriptor *desc ); diff --git a/src/include/ipxe/efi/efi_acpi.h b/src/include/ipxe/efi/efi_acpi.h index 01456f137..a698863a6 100644 --- a/src/include/ipxe/efi/efi_acpi.h +++ b/src/include/ipxe/efi/efi_acpi.h @@ -15,4 +15,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_efi __efi_ #endif +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( efi, acpi_find ) ( uint32_t signature, unsigned int index ) { + + return acpi_find_via_rsdt ( signature, index ); +} + #endif /* _IPXE_EFI_ACPI_H */ diff --git a/src/include/ipxe/null_acpi.h b/src/include/ipxe/null_acpi.h index 1e469e33d..cedb02839 100644 --- a/src/include/ipxe/null_acpi.h +++ b/src/include/ipxe/null_acpi.h @@ -15,8 +15,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_null __null_ #endif -static inline __always_inline userptr_t -ACPI_INLINE ( null, acpi_find_rsdt ) ( void ) { +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( null, acpi_find ) ( uint32_t signature __unused, + unsigned int index __unused ) { + return UNULL; } diff --git a/src/interface/efi/efi_acpi.c b/src/interface/efi/efi_acpi.c index a347eaf3a..07a225632 100644 --- a/src/interface/efi/efi_acpi.c +++ b/src/interface/efi/efi_acpi.c @@ -54,3 +54,4 @@ static userptr_t efi_find_rsdt ( void ) { } PROVIDE_ACPI ( efi, acpi_find_rsdt, efi_find_rsdt ); +PROVIDE_ACPI_INLINE ( efi, acpi_find ); -- cgit v1.2.3-55-g7522