1 #ifndef _IPXE_IOBUF_H
2 #define _IPXE_IOBUF_H
3
4 /** @file
5 *
6 * I/O buffers
7 *
8 */
9
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
12 #include <stdint.h>
13 #include <assert.h>
14 #include <ipxe/list.h>
15 #include <ipxe/dma.h>
16
17 /**
18 * Minimum I/O buffer length
19 *
20 * alloc_iob() will round up the allocated length to this size if
21 * necessary. This is used on behalf of hardware that is not capable
22 * of auto-padding.
23 */
24 #define IOB_ZLEN 128
25
26 /**
27 * A persistent I/O buffer
28 *
29 * This data structure encapsulates a long-lived I/O buffer. The
30 * buffer may be passed between multiple owners, queued for possible
31 * retransmission, etc.
32 */
33 struct io_buffer {
34 /** List of which this buffer is a member
35 *
36 * The list must belong to the current owner of the buffer.
37 * Different owners may maintain different lists (e.g. a
38 * retransmission list for TCP).
39 */
40 struct list_head list;
41
42 /** DMA mapping */
43 struct dma_mapping map;
44
45 /** Start of the buffer */
46 void *head;
47 /** Start of data */
48 void *data;
49 /** End of data */
50 void *tail;
51 /** End of the buffer */
52 void *end;
53 };
54
55 /**
56 * Reserve space at start of I/O buffer
57 *
58 * @v iobuf I/O buffer
59 * @v len Length to reserve
60 * @ret data Pointer to new start of buffer
61 */
iob_reserve(struct io_buffer * iobuf,size_t len)62 static inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
63 iobuf->data += len;
64 iobuf->tail += len;
65 return iobuf->data;
66 }
67 #define iob_reserve( iobuf, len ) ( { \
68 void *__result; \
69 __result = iob_reserve ( (iobuf), (len) ); \
70 assert ( (iobuf)->tail <= (iobuf)->end ); \
71 __result; } )
72
73 /**
74 * Add data to start of I/O buffer
75 *
76 * @v iobuf I/O buffer
77 * @v len Length to add
78 * @ret data Pointer to new start of buffer
79 */
iob_push(struct io_buffer * iobuf,size_t len)80 static inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
81 iobuf->data -= len;
82 return iobuf->data;
83 }
84 #define iob_push( iobuf, len ) ( { \
85 void *__result; \
86 __result = iob_push ( (iobuf), (len) ); \
87 assert ( (iobuf)->data >= (iobuf)->head ); \
88 __result; } )
89
90 /**
91 * Remove data from start of I/O buffer
92 *
93 * @v iobuf I/O buffer
94 * @v len Length to remove
95 * @ret data Pointer to new start of buffer
96 */
iob_pull(struct io_buffer * iobuf,size_t len)97 static inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
98 iobuf->data += len;
99 assert ( iobuf->data <= iobuf->tail );
100 return iobuf->data;
101 }
102 #define iob_pull( iobuf, len ) ( { \
103 void *__result; \
104 __result = iob_pull ( (iobuf), (len) ); \
105 assert ( (iobuf)->data <= (iobuf)->tail ); \
106 __result; } )
107
108 /**
109 * Add data to end of I/O buffer
110 *
111 * @v iobuf I/O buffer
112 * @v len Length to add
113 * @ret data Pointer to newly added space
114 */
iob_put(struct io_buffer * iobuf,size_t len)115 static inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
116 void *old_tail = iobuf->tail;
117 iobuf->tail += len;
118 return old_tail;
119 }
120 #define iob_put( iobuf, len ) ( { \
121 void *__result; \
122 __result = iob_put ( (iobuf), (len) ); \
123 assert ( (iobuf)->tail <= (iobuf)->end ); \
124 __result; } )
125
126 /**
127 * Remove data from end of I/O buffer
128 *
129 * @v iobuf I/O buffer
130 * @v len Length to remove
131 */
iob_unput(struct io_buffer * iobuf,size_t len)132 static inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
133 iobuf->tail -= len;
134 }
135 #define iob_unput( iobuf, len ) do { \
136 iob_unput ( (iobuf), (len) ); \
137 assert ( (iobuf)->tail >= (iobuf)->data ); \
138 } while ( 0 )
139
140 /**
141 * Empty an I/O buffer
142 *
143 * @v iobuf I/O buffer
144 */
iob_empty(struct io_buffer * iobuf)145 static inline void iob_empty ( struct io_buffer *iobuf ) {
146 iobuf->tail = iobuf->data;
147 }
148
149 /**
150 * Calculate length of data in an I/O buffer
151 *
152 * @v iobuf I/O buffer
153 * @ret len Length of data in buffer
154 */
iob_len(struct io_buffer * iobuf)155 static inline size_t iob_len ( struct io_buffer *iobuf ) {
156 return ( iobuf->tail - iobuf->data );
157 }
158
159 /**
160 * Calculate available space at start of an I/O buffer
161 *
162 * @v iobuf I/O buffer
163 * @ret len Length of data available at start of buffer
164 */
iob_headroom(struct io_buffer * iobuf)165 static inline size_t iob_headroom ( struct io_buffer *iobuf ) {
166 return ( iobuf->data - iobuf->head );
167 }
168
169 /**
170 * Calculate available space at end of an I/O buffer
171 *
172 * @v iobuf I/O buffer
173 * @ret len Length of data available at end of buffer
174 */
iob_tailroom(struct io_buffer * iobuf)175 static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
176 return ( iobuf->end - iobuf->tail );
177 }
178
179 /**
180 * Create a temporary I/O buffer
181 *
182 * @v iobuf I/O buffer
183 * @v data Data buffer
184 * @v len Length of data
185 * @v max_len Length of buffer
186 *
187 * It is sometimes useful to use the iob_xxx() methods on temporary
188 * data buffers.
189 */
iob_populate(struct io_buffer * iobuf,void * data,size_t len,size_t max_len)190 static inline void iob_populate ( struct io_buffer *iobuf,
191 void *data, size_t len, size_t max_len ) {
192 iobuf->head = iobuf->data = data;
193 iobuf->tail = ( data + len );
194 iobuf->end = ( data + max_len );
195 }
196
197 /**
198 * Disown an I/O buffer
199 *
200 * @v iobuf I/O buffer
201 *
202 * There are many functions that take ownership of the I/O buffer they
203 * are passed as a parameter. The caller should not retain a pointer
204 * to the I/O buffer. Use iob_disown() to automatically nullify the
205 * caller's pointer, e.g.:
206 *
207 * xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
208 *
209 * This will ensure that iobuf is set to NULL for any code after the
210 * call to xfer_deliver_iob().
211 */
212 #define iob_disown( iobuf ) ( { \
213 struct io_buffer *__iobuf = (iobuf); \
214 (iobuf) = NULL; \
215 __iobuf; } )
216
217 /**
218 * Map I/O buffer for DMA
219 *
220 * @v iobuf I/O buffer
221 * @v dma DMA device
222 * @v len Length to map
223 * @v flags Mapping flags
224 * @ret rc Return status code
225 */
iob_map(struct io_buffer * iobuf,struct dma_device * dma,size_t len,int flags)226 static inline __always_inline int iob_map ( struct io_buffer *iobuf,
227 struct dma_device *dma,
228 size_t len, int flags ) {
229 return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ),
230 len, flags );
231 }
232
233 /**
234 * Map I/O buffer for transmit DMA
235 *
236 * @v iobuf I/O buffer
237 * @v dma DMA device
238 * @ret rc Return status code
239 */
iob_map_tx(struct io_buffer * iobuf,struct dma_device * dma)240 static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf,
241 struct dma_device *dma ) {
242 return iob_map ( iobuf, dma, iob_len ( iobuf ), DMA_TX );
243 }
244
245 /**
246 * Map empty I/O buffer for receive DMA
247 *
248 * @v iobuf I/O buffer
249 * @v dma DMA device
250 * @ret rc Return status code
251 */
iob_map_rx(struct io_buffer * iobuf,struct dma_device * dma)252 static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf,
253 struct dma_device *dma ) {
254 assert ( iob_len ( iobuf ) == 0 );
255 return iob_map ( iobuf, dma, iob_tailroom ( iobuf ), DMA_RX );
256 }
257
258 /**
259 * Get I/O buffer DMA address
260 *
261 * @v iobuf I/O buffer
262 * @ret addr DMA address
263 */
iob_dma(struct io_buffer * iobuf)264 static inline __always_inline physaddr_t iob_dma ( struct io_buffer *iobuf ) {
265 return dma ( &iobuf->map, iobuf->data );
266 }
267
268 /**
269 * Unmap I/O buffer for DMA
270 *
271 * @v iobuf I/O buffer
272 * @v dma DMA device
273 * @ret rc Return status code
274 */
iob_unmap(struct io_buffer * iobuf)275 static inline __always_inline void iob_unmap ( struct io_buffer *iobuf ) {
276 dma_unmap ( &iobuf->map );
277 }
278
279 extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align,
280 size_t offset );
281 extern struct io_buffer * __malloc alloc_iob ( size_t len );
282 extern void free_iob ( struct io_buffer *iobuf );
283 extern struct io_buffer * __malloc alloc_rx_iob ( size_t len,
284 struct dma_device *dma );
285 extern void free_rx_iob ( struct io_buffer *iobuf );
286 extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
287 extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
288 extern struct io_buffer * iob_concatenate ( struct list_head *list );
289 extern struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len );
290
291 #endif /* _IPXE_IOBUF_H */
292