• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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