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 */
iob_reserve(struct io_buffer * iobuf,size_t len)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 */
iob_push(struct io_buffer * iobuf,size_t len)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 */
iob_pull(struct io_buffer * iobuf,size_t len)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 */
iob_put(struct io_buffer * iobuf,size_t len)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 */
iob_unput(struct io_buffer * iobuf,size_t len)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 */
iob_empty(struct io_buffer * iobuf)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 */
iob_len(struct io_buffer * iobuf)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 */
iob_headroom(struct io_buffer * iobuf)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 */
iob_tailroom(struct io_buffer * iobuf)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 */
iob_populate(struct io_buffer * iobuf,void * data,size_t len,size_t max_len)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