176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef _GPXE_IOBUF_H 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define _GPXE_IOBUF_H 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffers 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h> 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/list.h> 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffer alignment 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffers allocated via alloc_iob() are guaranteed to be 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * physically aligned to this boundary. Some cards cannot DMA across 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a 4kB boundary. With a standard Ethernet MTU, aligning to a 2kB 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * boundary is sufficient to guarantee no 4kB boundary crossings. For 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway. 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IOB_ALIGN 2048 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Minimum I/O buffer length 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * alloc_iob() will round up the allocated length to this size if 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * necessary. This is used on behalf of hardware that is not capable 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of auto-padding. 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IOB_ZLEN 64 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * A persistent I/O buffer 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This data structure encapsulates a long-lived I/O buffer. The 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * buffer may be passed between multiple owners, queued for possible 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * retransmission, etc. 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct io_buffer { 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** List of which this buffer is a member 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The list must belong to the current owner of the buffer. 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Different owners may maintain different lists (e.g. a 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * retransmission list for TCP). 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct list_head list; 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** Start of the buffer */ 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *head; 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** Start of data */ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *data; 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** End of data */ 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *tail; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** End of the buffer */ 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *end; 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Reserve space at start of I/O buffer 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length to reserve 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data Pointer to new start of buffer 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) { 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->data += len; 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->tail += len; 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return iobuf->data; 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_reserve( iobuf, len ) ( { \ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *__result; \ 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result = iob_reserve ( (iobuf), (len) ); \ 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( (iobuf)->tail <= (iobuf)->end ); \ 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result; } ) 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add data to start of I/O buffer 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length to add 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data Pointer to new start of buffer 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_push ( struct io_buffer *iobuf, size_t len ) { 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->data -= len; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return iobuf->data; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_push( iobuf, len ) ( { \ 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *__result; \ 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result = iob_push ( (iobuf), (len) ); \ 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( (iobuf)->data >= (iobuf)->head ); \ 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result; } ) 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove data from start of I/O buffer 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length to remove 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data Pointer to new start of buffer 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->data += len; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( iobuf->data <= iobuf->tail ); 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return iobuf->data; 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_pull( iobuf, len ) ( { \ 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *__result; \ 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result = iob_pull ( (iobuf), (len) ); \ 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( (iobuf)->data <= (iobuf)->tail ); \ 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result; } ) 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add data to end of I/O buffer 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length to add 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data Pointer to newly added space 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_put ( struct io_buffer *iobuf, size_t len ) { 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *old_tail = iobuf->tail; 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->tail += len; 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return old_tail; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_put( iobuf, len ) ( { \ 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *__result; \ 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result = iob_put ( (iobuf), (len) ); \ 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( (iobuf)->tail <= (iobuf)->end ); \ 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __result; } ) 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove data from end of I/O buffer 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length to remove 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_unput ( struct io_buffer *iobuf, size_t len ) { 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->tail -= len; 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_unput( iobuf, len ) do { \ 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_unput ( (iobuf), (len) ); \ 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( (iobuf)->tail >= (iobuf)->data ); \ 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ( 0 ) 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Empty an I/O buffer 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_empty ( struct io_buffer *iobuf ) { 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->tail = iobuf->data; 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate length of data in an I/O buffer 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of data in buffer 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_len ( struct io_buffer *iobuf ) { 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ( iobuf->tail - iobuf->data ); 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate available space at start of an I/O buffer 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of data available at start of buffer 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_headroom ( struct io_buffer *iobuf ) { 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ( iobuf->data - iobuf->head ); 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate available space at end of an I/O buffer 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of data available at end of buffer 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_tailroom ( struct io_buffer *iobuf ) { 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ( iobuf->end - iobuf->tail ); 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Create a temporary I/O buffer 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v data Data buffer 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len Length of data 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v max_len Length of buffer 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It is sometimes useful to use the iob_xxx() methods on temporary 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * data buffers. 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_populate ( struct io_buffer *iobuf, 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *data, size_t len, size_t max_len ) { 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->head = iobuf->data = data; 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->tail = ( data + len ); 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->end = ( data + max_len ); 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disown an I/O buffer 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * There are many functions that take ownership of the I/O buffer they 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are passed as a parameter. The caller should not retain a pointer 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to the I/O buffer. Use iob_disown() to automatically nullify the 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * caller's pointer, e.g.: 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * xfer_deliver_iob ( xfer, iob_disown ( iobuf ) ); 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This will ensure that iobuf is set to NULL for any code after the 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * call to xfer_deliver_iob(). 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_disown( iobuf ) ( { \ 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *__iobuf = (iobuf); \ 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (iobuf) = NULL; \ 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman __iobuf; } ) 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern struct io_buffer * __malloc alloc_iob ( size_t len ); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void free_iob ( struct io_buffer *iobuf ); 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ); 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* _GPXE_IOBUF_H */ 230