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