Home | History | Annotate | Download | only in gpxe
      1 #ifndef _GPXE_IOBUF_H
      2 #define _GPXE_IOBUF_H
      3 
      4 /** @file
      5  *
      6  * I/O buffers
      7  *
      8  */
      9 
     10 FILE_LICENCE ( GPL2_OR_LATER );
     11 
     12 #include <stdint.h>
     13 #include <assert.h>
     14 #include <gpxe/list.h>
     15 
     16 /**
     17  * I/O buffer alignment
     18  *
     19  * I/O buffers allocated via alloc_iob() are guaranteed to be
     20  * physically aligned to this boundary.  Some cards cannot DMA across
     21  * a 4kB boundary.  With a standard Ethernet MTU, aligning to a 2kB
     22  * boundary is sufficient to guarantee no 4kB boundary crossings.  For
     23  * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
     24  */
     25 #define IOB_ALIGN 2048
     26 
     27 /**
     28  * Minimum I/O buffer length
     29  *
     30  * alloc_iob() will round up the allocated length to this size if
     31  * necessary.  This is used on behalf of hardware that is not capable
     32  * of auto-padding.
     33  */
     34 #define IOB_ZLEN 64
     35 
     36 /**
     37  * A persistent I/O buffer
     38  *
     39  * This data structure encapsulates a long-lived I/O buffer.  The
     40  * buffer may be passed between multiple owners, queued for possible
     41  * retransmission, etc.
     42  */
     43 struct io_buffer {
     44 	/** List of which this buffer is a member
     45 	 *
     46 	 * The list must belong to the current owner of the buffer.
     47 	 * Different owners may maintain different lists (e.g. a
     48 	 * retransmission list for TCP).
     49 	 */
     50 	struct list_head list;
     51 
     52 	/** Start of the buffer */
     53 	void *head;
     54 	/** Start of data */
     55 	void *data;
     56 	/** End of data */
     57 	void *tail;
     58 	/** End of the buffer */
     59         void *end;
     60 };
     61 
     62 /**
     63  * Reserve space at start of I/O buffer
     64  *
     65  * @v iobuf	I/O buffer
     66  * @v len	Length to reserve
     67  * @ret data	Pointer to new start of buffer
     68  */
     69 static inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
     70 	iobuf->data += len;
     71 	iobuf->tail += len;
     72 	return iobuf->data;
     73 }
     74 #define iob_reserve( iobuf, len ) ( {			\
     75 	void *__result;					\
     76 	__result = iob_reserve ( (iobuf), (len) );	\
     77 	assert ( (iobuf)->tail <= (iobuf)->end );	\
     78 	__result; } )
     79 
     80 /**
     81  * Add data to start of I/O buffer
     82  *
     83  * @v iobuf	I/O buffer
     84  * @v len	Length to add
     85  * @ret data	Pointer to new start of buffer
     86  */
     87 static inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
     88 	iobuf->data -= len;
     89 	return iobuf->data;
     90 }
     91 #define iob_push( iobuf, len ) ( {			\
     92 	void *__result;					\
     93 	__result = iob_push ( (iobuf), (len) );		\
     94 	assert ( (iobuf)->data >= (iobuf)->head );	\
     95 	__result; } )
     96 
     97 /**
     98  * Remove data from start of I/O buffer
     99  *
    100  * @v iobuf	I/O buffer
    101  * @v len	Length to remove
    102  * @ret data	Pointer to new start of buffer
    103  */
    104 static inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
    105 	iobuf->data += len;
    106 	assert ( iobuf->data <= iobuf->tail );
    107 	return iobuf->data;
    108 }
    109 #define iob_pull( iobuf, len ) ( {			\
    110 	void *__result;					\
    111 	__result = iob_pull ( (iobuf), (len) );		\
    112 	assert ( (iobuf)->data <= (iobuf)->tail );	\
    113 	__result; } )
    114 
    115 /**
    116  * Add data to end of I/O buffer
    117  *
    118  * @v iobuf	I/O buffer
    119  * @v len	Length to add
    120  * @ret data	Pointer to newly added space
    121  */
    122 static inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
    123 	void *old_tail = iobuf->tail;
    124 	iobuf->tail += len;
    125 	return old_tail;
    126 }
    127 #define iob_put( iobuf, len ) ( {			\
    128 	void *__result;					\
    129 	__result = iob_put ( (iobuf), (len) );		\
    130 	assert ( (iobuf)->tail <= (iobuf)->end );	\
    131 	__result; } )
    132 
    133 /**
    134  * Remove data from end of I/O buffer
    135  *
    136  * @v iobuf	I/O buffer
    137  * @v len	Length to remove
    138  */
    139 static inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
    140 	iobuf->tail -= len;
    141 }
    142 #define iob_unput( iobuf, len ) do {			\
    143 	iob_unput ( (iobuf), (len) );			\
    144 	assert ( (iobuf)->tail >= (iobuf)->data );	\
    145 	} while ( 0 )
    146 
    147 /**
    148  * Empty an I/O buffer
    149  *
    150  * @v iobuf	I/O buffer
    151  */
    152 static inline void iob_empty ( struct io_buffer *iobuf ) {
    153 	iobuf->tail = iobuf->data;
    154 }
    155 
    156 /**
    157  * Calculate length of data in an I/O buffer
    158  *
    159  * @v iobuf	I/O buffer
    160  * @ret len	Length of data in buffer
    161  */
    162 static inline size_t iob_len ( struct io_buffer *iobuf ) {
    163 	return ( iobuf->tail - iobuf->data );
    164 }
    165 
    166 /**
    167  * Calculate available space at start of an I/O buffer
    168  *
    169  * @v iobuf	I/O buffer
    170  * @ret len	Length of data available at start of buffer
    171  */
    172 static inline size_t iob_headroom ( struct io_buffer *iobuf ) {
    173 	return ( iobuf->data - iobuf->head );
    174 }
    175 
    176 /**
    177  * Calculate available space at end of an I/O buffer
    178  *
    179  * @v iobuf	I/O buffer
    180  * @ret len	Length of data available at end of buffer
    181  */
    182 static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
    183 	return ( iobuf->end - iobuf->tail );
    184 }
    185 
    186 /**
    187  * Create a temporary I/O buffer
    188  *
    189  * @v iobuf	I/O buffer
    190  * @v data	Data buffer
    191  * @v len	Length of data
    192  * @v max_len	Length of buffer
    193  *
    194  * It is sometimes useful to use the iob_xxx() methods on temporary
    195  * data buffers.
    196  */
    197 static inline void iob_populate ( struct io_buffer *iobuf,
    198 				  void *data, size_t len, size_t max_len ) {
    199 	iobuf->head = iobuf->data = data;
    200 	iobuf->tail = ( data + len );
    201 	iobuf->end = ( data + max_len );
    202 }
    203 
    204 /**
    205  * Disown an I/O buffer
    206  *
    207  * @v iobuf	I/O buffer
    208  *
    209  * There are many functions that take ownership of the I/O buffer they
    210  * are passed as a parameter.  The caller should not retain a pointer
    211  * to the I/O buffer.  Use iob_disown() to automatically nullify the
    212  * caller's pointer, e.g.:
    213  *
    214  *     xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
    215  *
    216  * This will ensure that iobuf is set to NULL for any code after the
    217  * call to xfer_deliver_iob().
    218  */
    219 #define iob_disown( iobuf ) ( {				\
    220 	struct io_buffer *__iobuf = (iobuf);		\
    221 	(iobuf) = NULL;					\
    222 	__iobuf; } )
    223 
    224 extern struct io_buffer * __malloc alloc_iob ( size_t len );
    225 extern void free_iob ( struct io_buffer *iobuf );
    226 extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
    227 extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
    228 
    229 #endif /* _GPXE_IOBUF_H */
    230