Moved iobuf.h assertions outside the static inline functions, so that
[people/sha0/gpxe.git] / src / include / gpxe / iobuf.h
1 #ifndef _GPXE_IOBUF_H
2 #define _GPXE_IOBUF_H
3
4 /** @file
5  *
6  * I/O buffers
7  *
8  */
9
10 #include <stdint.h>
11 #include <assert.h>
12 #include <gpxe/list.h>
13
14 /**
15  * I/O buffer alignment
16  *
17  * I/O buffers allocated via alloc_iob() are guaranteed to be
18  * physically aligned to this boundary.  Some cards cannot DMA across
19  * a 4kB boundary.  With a standard Ethernet MTU, aligning to a 2kB
20  * boundary is sufficient to guarantee no 4kB boundary crossings.  For
21  * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
22  */
23 #define IOB_ALIGN 2048
24
25 /**
26  * Minimum I/O buffer length
27  *
28  * alloc_iob() will round up the allocated length to this size if
29  * necessary.  This is used on behalf of hardware that is not capable
30  * of auto-padding.
31  */
32 #define IOB_ZLEN 64
33
34 /**
35  * A persistent I/O buffer
36  *
37  * This data structure encapsulates a long-lived I/O buffer.  The
38  * buffer may be passed between multiple owners, queued for possible
39  * retransmission, etc.
40  */
41 struct io_buffer {
42         /** List of which this buffer is a member
43          *
44          * The list must belong to the current owner of the buffer.
45          * Different owners may maintain different lists (e.g. a
46          * retransmission list for TCP).
47          */
48         struct list_head list;
49
50         /** Start of the buffer */
51         void *head;
52         /** Start of data */
53         void *data;
54         /** End of data */
55         void *tail;
56         /** End of the buffer */
57         void *end;
58 };
59
60 /**
61  * Reserve space at start of I/O buffer
62  *
63  * @v iobuf     I/O buffer
64  * @v len       Length to reserve
65  * @ret data    Pointer to new start of buffer
66  */
67 static inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
68         iobuf->data += len;
69         iobuf->tail += len;
70         return iobuf->data;
71 }
72 #define iob_reserve( iobuf, len ) ( {                   \
73         void *__result;                                 \
74         __result = iob_reserve ( (iobuf), (len) );      \
75         assert ( (iobuf)->tail <= (iobuf)->end );       \
76         __result; } )
77
78 /**
79  * Add data to start of I/O buffer
80  *
81  * @v iobuf     I/O buffer
82  * @v len       Length to add
83  * @ret data    Pointer to new start of buffer
84  */
85 static inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
86         iobuf->data -= len;
87         return iobuf->data;
88 }
89 #define iob_push( iobuf, len ) ( {                      \
90         void *__result;                                 \
91         __result = iob_push ( (iobuf), (len) );         \
92         assert ( (iobuf)->data >= (iobuf)->head );      \
93         __result; } )
94
95 /**
96  * Remove data from start of I/O buffer
97  *
98  * @v iobuf     I/O buffer
99  * @v len       Length to remove
100  * @ret data    Pointer to new start of buffer
101  */
102 static inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
103         iobuf->data += len;
104         assert ( iobuf->data <= iobuf->tail );
105         return iobuf->data;
106 }
107 #define iob_pull( iobuf, len ) ( {                      \
108         void *__result;                                 \
109         __result = iob_pull ( (iobuf), (len) );         \
110         assert ( (iobuf)->data <= (iobuf)->tail );      \
111         __result; } )
112
113 /**
114  * Add data to end of I/O buffer
115  *
116  * @v iobuf     I/O buffer
117  * @v len       Length to add
118  * @ret data    Pointer to newly added space
119  */
120 static inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
121         void *old_tail = iobuf->tail;
122         iobuf->tail += len;
123         return old_tail;
124 }
125 #define iob_put( iobuf, len ) ( {                       \
126         void *__result;                                 \
127         __result = iob_put ( (iobuf), (len) );          \
128         assert ( (iobuf)->tail <= (iobuf)->end );       \
129         __result; } )
130
131 /**
132  * Remove data from end of I/O buffer
133  *
134  * @v iobuf     I/O buffer
135  * @v len       Length to remove
136  */
137 static inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
138         iobuf->tail -= len;
139 }
140 #define iob_unput( iobuf, len ) do {                    \
141         iob_unput ( (iobuf), (len) );                   \
142         assert ( (iobuf)->tail >= (iobuf)->data );      \
143         } while ( 0 )
144
145 /**
146  * Empty an I/O buffer
147  *
148  * @v iobuf     I/O buffer
149  */
150 static inline void iob_empty ( struct io_buffer *iobuf ) {
151         iobuf->tail = iobuf->data;
152 }
153
154 /**
155  * Calculate length of data in an I/O buffer
156  *
157  * @v iobuf     I/O buffer
158  * @ret len     Length of data in buffer
159  */
160 static inline size_t iob_len ( struct io_buffer *iobuf ) {
161         return ( iobuf->tail - iobuf->data );
162 }
163
164 /**
165  * Calculate available space at start of an I/O buffer
166  *
167  * @v iobuf     I/O buffer
168  * @ret len     Length of data available at start of buffer
169  */
170 static inline size_t iob_headroom ( struct io_buffer *iobuf ) {
171         return ( iobuf->data - iobuf->head );
172 }
173
174 /**
175  * Calculate available space at end of an I/O buffer
176  *
177  * @v iobuf     I/O buffer
178  * @ret len     Length of data available at end of buffer
179  */
180 static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
181         return ( iobuf->end - iobuf->tail );
182 }
183
184 extern struct io_buffer * __malloc alloc_iob ( size_t len );
185 extern void free_iob ( struct io_buffer *iobuf );
186 extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
187 extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
188
189 #endif /* _GPXE_IOBUF_H */