Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / iobuf.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <strings.h>
24 #include <errno.h>
25 #include <ipxe/malloc.h>
26 #include <ipxe/iobuf.h>
27
28 /** @file
29  *
30  * I/O buffers
31  *
32  */
33
34 /**
35  * Allocate I/O buffer with specified alignment and offset
36  *
37  * @v len       Required length of buffer
38  * @v align     Physical alignment
39  * @v offset    Offset from physical alignment
40  * @ret iobuf   I/O buffer, or NULL if none available
41  *
42  * @c align will be rounded up to the nearest power of two.
43  */
44 struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) {
45         struct io_buffer *iobuf;
46         void *data;
47
48         /* Align buffer length to ensure that struct io_buffer is aligned */
49         len = ( len + __alignof__ ( *iobuf ) - 1 ) &
50                 ~( __alignof__ ( *iobuf ) - 1 );
51
52         /* Round up alignment to the nearest power of two */
53         align = ( 1 << fls ( align - 1 ) );
54
55         /* Allocate buffer plus descriptor as a single unit, unless
56          * doing so will push the total size over the alignment
57          * boundary.
58          */
59         if ( ( len + sizeof ( *iobuf ) ) <= align ) {
60
61                 /* Allocate memory for buffer plus descriptor */
62                 data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
63                                            offset );
64                 if ( ! data )
65                         return NULL;
66                 iobuf = ( data + len );
67
68         } else {
69
70                 /* Allocate memory for buffer */
71                 data = malloc_dma_offset ( len, align, offset );
72                 if ( ! data )
73                         return NULL;
74
75                 /* Allocate memory for descriptor */
76                 iobuf = malloc ( sizeof ( *iobuf ) );
77                 if ( ! iobuf ) {
78                         free_dma ( data, len );
79                         return NULL;
80                 }
81         }
82
83         /* Populate descriptor */
84         iobuf->head = iobuf->data = iobuf->tail = data;
85         iobuf->end = ( data + len );
86
87         return iobuf;
88 }
89
90 /**
91  * Allocate I/O buffer
92  *
93  * @v len       Required length of buffer
94  * @ret iobuf   I/O buffer, or NULL if none available
95  *
96  * The I/O buffer will be physically aligned on its own size (rounded
97  * up to the nearest power of two).
98  */
99 struct io_buffer * alloc_iob ( size_t len ) {
100
101         /* Pad to minimum length */
102         if ( len < IOB_ZLEN )
103                 len = IOB_ZLEN;
104
105         /* Align buffer on its own size to avoid potential problems
106          * with boundary-crossing DMA.
107          */
108         return alloc_iob_raw ( len, len, 0 );
109 }
110
111 /**
112  * Free I/O buffer
113  *
114  * @v iobuf     I/O buffer
115  */
116 void free_iob ( struct io_buffer *iobuf ) {
117         size_t len;
118
119         /* Allow free_iob(NULL) to be valid */
120         if ( ! iobuf )
121                 return;
122
123         /* Sanity checks */
124         assert ( iobuf->head <= iobuf->data );
125         assert ( iobuf->data <= iobuf->tail );
126         assert ( iobuf->tail <= iobuf->end );
127
128         /* Free buffer */
129         len = ( iobuf->end - iobuf->head );
130         if ( iobuf->end == iobuf ) {
131
132                 /* Descriptor is inline */
133                 free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );
134
135         } else {
136
137                 /* Descriptor is detached */
138                 free_dma ( iobuf->head, len );
139                 free ( iobuf );
140         }
141 }
142
143 /**
144  * Ensure I/O buffer has sufficient headroom
145  *
146  * @v iobuf     I/O buffer
147  * @v len       Required headroom
148  *
149  * This function currently only checks for the required headroom; it
150  * does not reallocate the I/O buffer if required.  If we ever have a
151  * code path that requires this functionality, it's a fairly trivial
152  * change to make.
153  */
154 int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
155
156         if ( iob_headroom ( iobuf ) >= len )
157                 return 0;
158         return -ENOBUFS;
159 }
160
161 /**
162  * Concatenate I/O buffers into a single buffer
163  *
164  * @v list      List of I/O buffers
165  * @ret iobuf   Concatenated I/O buffer, or NULL on allocation failure
166  *
167  * After a successful concatenation, the list will be empty.
168  */
169 struct io_buffer * iob_concatenate ( struct list_head *list ) {
170         struct io_buffer *iobuf;
171         struct io_buffer *tmp;
172         struct io_buffer *concatenated;
173         size_t len = 0;
174
175         /* If the list contains only a single entry, avoid an
176          * unnecessary additional allocation.
177          */
178         if ( list_is_singular ( list ) ) {
179                 iobuf = list_first_entry ( list, struct io_buffer, list );
180                 INIT_LIST_HEAD ( list );
181                 return iobuf;
182         }
183
184         /* Calculate total length */
185         list_for_each_entry ( iobuf, list, list )
186                 len += iob_len ( iobuf );
187
188         /* Allocate new I/O buffer */
189         concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
190         if ( ! concatenated )
191                 return NULL;
192
193         /* Move data to new I/O buffer */
194         list_for_each_entry_safe ( iobuf, tmp, list, list ) {
195                 list_del ( &iobuf->list );
196                 memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
197                          iobuf->data, iob_len ( iobuf ) );
198                 free_iob ( iobuf );
199         }
200
201         return concatenated;
202 }