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