You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

iobuf.c 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdint.h>
  25. #include <strings.h>
  26. #include <errno.h>
  27. #include <ipxe/malloc.h>
  28. #include <ipxe/iobuf.h>
  29. /** @file
  30. *
  31. * I/O buffers
  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. size_t padding;
  47. size_t threshold;
  48. unsigned int align_log2;
  49. void *data;
  50. /* Calculate padding required below alignment boundary to
  51. * ensure that a correctly aligned inline struct io_buffer
  52. * could fit (regardless of the requested offset).
  53. */
  54. padding = ( sizeof ( *iobuf ) + __alignof__ ( *iobuf ) - 1 );
  55. /* Round up requested alignment to at least the size of the
  56. * padding, to simplify subsequent calculations.
  57. */
  58. if ( align < padding )
  59. align = padding;
  60. /* Round up alignment to the nearest power of two, avoiding
  61. * a potentially undefined shift operation.
  62. */
  63. align_log2 = fls ( align - 1 );
  64. if ( align_log2 >= ( 8 * sizeof ( align ) ) )
  65. return NULL;
  66. align = ( 1UL << align_log2 );
  67. /* Calculate length threshold */
  68. assert ( align >= padding );
  69. threshold = ( align - padding );
  70. /* Allocate buffer plus an inline descriptor as a single unit,
  71. * unless doing so would push the total size over the
  72. * alignment boundary.
  73. */
  74. if ( len <= threshold ) {
  75. /* Round up buffer length to ensure that struct
  76. * io_buffer is aligned.
  77. */
  78. len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) );
  79. /* Allocate memory for buffer plus descriptor */
  80. data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
  81. offset );
  82. if ( ! data )
  83. return NULL;
  84. iobuf = ( data + len );
  85. } else {
  86. /* Allocate memory for buffer */
  87. data = malloc_dma_offset ( len, align, offset );
  88. if ( ! data )
  89. return NULL;
  90. /* Allocate memory for descriptor */
  91. iobuf = malloc ( sizeof ( *iobuf ) );
  92. if ( ! iobuf ) {
  93. free_dma ( data, len );
  94. return NULL;
  95. }
  96. }
  97. /* Populate descriptor */
  98. iobuf->head = iobuf->data = iobuf->tail = data;
  99. iobuf->end = ( data + len );
  100. return iobuf;
  101. }
  102. /**
  103. * Allocate I/O buffer
  104. *
  105. * @v len Required length of buffer
  106. * @ret iobuf I/O buffer, or NULL if none available
  107. *
  108. * The I/O buffer will be physically aligned on its own size (rounded
  109. * up to the nearest power of two).
  110. */
  111. struct io_buffer * alloc_iob ( size_t len ) {
  112. /* Pad to minimum length */
  113. if ( len < IOB_ZLEN )
  114. len = IOB_ZLEN;
  115. /* Align buffer on its own size to avoid potential problems
  116. * with boundary-crossing DMA.
  117. */
  118. return alloc_iob_raw ( len, len, 0 );
  119. }
  120. /**
  121. * Free I/O buffer
  122. *
  123. * @v iobuf I/O buffer
  124. */
  125. void free_iob ( struct io_buffer *iobuf ) {
  126. size_t len;
  127. /* Allow free_iob(NULL) to be valid */
  128. if ( ! iobuf )
  129. return;
  130. /* Sanity checks */
  131. assert ( iobuf->head <= iobuf->data );
  132. assert ( iobuf->data <= iobuf->tail );
  133. assert ( iobuf->tail <= iobuf->end );
  134. /* Free buffer */
  135. len = ( iobuf->end - iobuf->head );
  136. if ( iobuf->end == iobuf ) {
  137. /* Descriptor is inline */
  138. free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );
  139. } else {
  140. /* Descriptor is detached */
  141. free_dma ( iobuf->head, len );
  142. free ( iobuf );
  143. }
  144. }
  145. /**
  146. * Ensure I/O buffer has sufficient headroom
  147. *
  148. * @v iobuf I/O buffer
  149. * @v len Required headroom
  150. *
  151. * This function currently only checks for the required headroom; it
  152. * does not reallocate the I/O buffer if required. If we ever have a
  153. * code path that requires this functionality, it's a fairly trivial
  154. * change to make.
  155. */
  156. int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
  157. if ( iob_headroom ( iobuf ) >= len )
  158. return 0;
  159. return -ENOBUFS;
  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. /* If the list contains only a single entry, avoid an
  175. * unnecessary additional allocation.
  176. */
  177. if ( list_is_singular ( list ) ) {
  178. iobuf = list_first_entry ( list, struct io_buffer, list );
  179. INIT_LIST_HEAD ( list );
  180. return iobuf;
  181. }
  182. /* Calculate total length */
  183. list_for_each_entry ( iobuf, list, list )
  184. len += iob_len ( iobuf );
  185. /* Allocate new I/O buffer */
  186. concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
  187. if ( ! concatenated )
  188. return NULL;
  189. /* Move data to new I/O buffer */
  190. list_for_each_entry_safe ( iobuf, tmp, list, list ) {
  191. list_del ( &iobuf->list );
  192. memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
  193. iobuf->data, iob_len ( iobuf ) );
  194. free_iob ( iobuf );
  195. }
  196. return concatenated;
  197. }
  198. /**
  199. * Split I/O buffer
  200. *
  201. * @v iobuf I/O buffer
  202. * @v len Length to split into a new I/O buffer
  203. * @ret split New I/O buffer, or NULL on allocation failure
  204. *
  205. * Split the first @c len bytes of the existing I/O buffer into a
  206. * separate I/O buffer. The resulting buffers are likely to have no
  207. * headroom or tailroom.
  208. *
  209. * If this call fails, then the original buffer will be unmodified.
  210. */
  211. struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len ) {
  212. struct io_buffer *split;
  213. /* Sanity checks */
  214. assert ( len <= iob_len ( iobuf ) );
  215. /* Allocate new I/O buffer */
  216. split = alloc_iob ( len );
  217. if ( ! split )
  218. return NULL;
  219. /* Copy in data */
  220. memcpy ( iob_put ( split, len ), iobuf->data, len );
  221. iob_pull ( iobuf, len );
  222. return split;
  223. }