FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
+#include <strings.h>
#include <errno.h>
#include <ipxe/malloc.h>
#include <ipxe/iobuf.h>
*/
struct io_buffer * alloc_iob ( size_t len ) {
struct io_buffer *iobuf = NULL;
+ size_t align;
void *data;
/* Pad to minimum length */
if ( len < IOB_ZLEN )
len = IOB_ZLEN;
- /* Align buffer length */
- len = ( len + __alignof__( *iobuf ) - 1 ) &
- ~( __alignof__( *iobuf ) - 1 );
-
+ /* Align buffer length to ensure that struct io_buffer is aligned */
+ len = ( len + __alignof__ ( *iobuf ) - 1 ) &
+ ~( __alignof__ ( *iobuf ) - 1 );
+
+ /* Align buffer on its own size to avoid potential problems
+ * with boundary-crossing DMA.
+ */
+ align = ( 1 << fls ( len - 1 ) );
+
/* Allocate memory for buffer plus descriptor */
- data = malloc_dma ( len + sizeof ( *iobuf ), IOB_ALIGN );
+ data = malloc_dma ( len + sizeof ( *iobuf ), align );
if ( ! data )
return NULL;
return iobuf;
}
+
/**
* Free I/O buffer
*
#include <assert.h>
#include <ipxe/list.h>
-/**
- * I/O buffer alignment
- *
- * I/O buffers allocated via alloc_iob() are guaranteed to be
- * physically aligned to this boundary. Some cards cannot DMA across
- * a 4kB boundary. With a standard Ethernet MTU, aligning to a 2kB
- * boundary is sufficient to guarantee no 4kB boundary crossings. For
- * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
- */
-#define IOB_ALIGN 2048
-
/**
* Minimum I/O buffer length
*