iPXE
Functions
iobuf.c File Reference

I/O buffers. More...

#include <stdint.h>
#include <strings.h>
#include <errno.h>
#include <ipxe/malloc.h>
#include <ipxe/iobuf.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
struct io_bufferalloc_iob_raw (size_t len, size_t align, size_t offset)
 Allocate I/O buffer with specified alignment and offset.
struct io_bufferalloc_iob (size_t len)
 Allocate I/O buffer.
void free_iob (struct io_buffer *iobuf)
 Free I/O buffer.
int iob_ensure_headroom (struct io_buffer *iobuf, size_t len)
 Ensure I/O buffer has sufficient headroom.
struct io_bufferiob_concatenate (struct list_head *list)
 Concatenate I/O buffers into a single buffer.
struct io_bufferiob_split (struct io_buffer *iobuf, size_t len)
 Split I/O buffer.

Detailed Description

I/O buffers.

Definition in file iobuf.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
struct io_buffer* alloc_iob_raw ( size_t  len,
size_t  align,
size_t  offset 
) [read]

Allocate I/O buffer with specified alignment and offset.

Parameters:
lenRequired length of buffer
alignPhysical alignment
offsetOffset from physical alignment
Return values:
iobufI/O buffer, or NULL if none available

align will be rounded up to the nearest power of two.

Definition at line 48 of file iobuf.c.

References assert, io_buffer::data, data, io_buffer::end, fls, free_dma(), io_buffer::head, len, malloc(), malloc_dma_offset(), NULL, offset, and io_buffer::tail.

Referenced by alloc_iob(), alloc_iob_fail_okx(), alloc_iob_okx(), ath_rx_init(), ath_rx_tasklet(), iob_concatenate(), ipoib_alloc_iob(), and tls_newdata_process_header().

                                                                             {
        struct io_buffer *iobuf;
        size_t padding;
        size_t threshold;
        unsigned int align_log2;
        void *data;

        /* Calculate padding required below alignment boundary to
         * ensure that a correctly aligned inline struct io_buffer
         * could fit (regardless of the requested offset).
         */
        padding = ( sizeof ( *iobuf ) + __alignof__ ( *iobuf ) - 1 );

        /* Round up requested alignment to at least the size of the
         * padding, to simplify subsequent calculations.
         */
        if ( align < padding )
                align = padding;

        /* Round up alignment to the nearest power of two, avoiding
         * a potentially undefined shift operation.
         */
        align_log2 = fls ( align - 1 );
        if ( align_log2 >= ( 8 * sizeof ( align ) ) )
                return NULL;
        align = ( 1UL << align_log2 );

        /* Calculate length threshold */
        assert ( align >= padding );
        threshold = ( align - padding );

        /* Allocate buffer plus an inline descriptor as a single unit,
         * unless doing so would push the total size over the
         * alignment boundary.
         */
        if ( len <= threshold ) {

                /* Round up buffer length to ensure that struct
                 * io_buffer is aligned.
                 */
                len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) );

                /* Allocate memory for buffer plus descriptor */
                data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
                                           offset );
                if ( ! data )
                        return NULL;
                iobuf = ( data + len );

        } else {

                /* Allocate memory for buffer */
                data = malloc_dma_offset ( len, align, offset );
                if ( ! data )
                        return NULL;

                /* Allocate memory for descriptor */
                iobuf = malloc ( sizeof ( *iobuf ) );
                if ( ! iobuf ) {
                        free_dma ( data, len );
                        return NULL;
                }
        }

        /* Populate descriptor */
        iobuf->head = iobuf->data = iobuf->tail = data;
        iobuf->end = ( data + len );

        return iobuf;
}
struct io_buffer* alloc_iob ( size_t  len) [read]

Allocate I/O buffer.

Parameters:
lenRequired length of buffer
Return values:
iobufI/O buffer, or NULL if none available

The I/O buffer will be physically aligned on its own size (rounded up to the nearest power of two).

Definition at line 128 of file iobuf.c.

References alloc_iob_raw(), and IOB_ZLEN.

Referenced by a3c90x_refill_rx_ring(), acm_control_receive(), aoecmd_tx(), arp_tx_request(), ath5k_rx_iob_alloc(), atl1e_clean_rx_irq(), axge_in_complete(), b44_init_rx_ring(), b44_rx_refill(), ccmp_decrypt(), ccmp_encrypt(), efab_fill_rx_queue(), efi_snp_transmit(), efi_usb_sync_transfer(), efx_hunt_rxq_fill(), ena_refill_rx(), eoib_duplicate(), exanic_poll_rx(), fcoe_alloc_iob(), fcoe_fip_tx_keepalive(), fcoe_fip_tx_solicitation(), fcoe_fip_tx_vlan(), fragment_reassemble(), gdbudp_send(), http_rx_chunk_data(), http_tx_request(), hunt_mcdi_init(), ib_mi_send(), icplus_refill_rx(), ifec_get_rx_desc(), igbvf_refill_rx_ring(), igbvf_setup_rx_resources(), intel_refill_rx(), iob_split(), jme_make_new_rx_buf(), legacy_poll(), loopback_test(), myri10ge_net_open(), myri10ge_net_poll(), myson_refill_rx(), natsemi_refill_rx(), ncm_in_complete(), ndp_tx_ll_addr(), net80211_accum_frags(), net80211_probe_start(), net80211_probe_step(), net80211_send_assoc(), net80211_send_auth(), net80211_send_disassoc(), netfront_refill_rx(), nii_poll_rx(), nv_alloc_rx(), oncrpc_call(), pcnet32_refill_rx_ring(), phantom_refill_rx_ring(), ping_alloc_iob(), pnic_poll(), pxenv_undi_transmit(), realtek_legacy_poll_rx(), realtek_refill_rx(), rhine_refill_rx(), rndis_alloc_iob(), rtl818x_handle_rx(), rtl818x_init_rx_ring(), sis190_alloc_rx_iob(), skge_rx_refill(), sky2_rx_alloc(), snpnet_poll_rx(), tcp_xmit_reset(), tcp_xmit_sack(), tg3_alloc_rx_iob(), tkip_decrypt(), tkip_encrypt(), txnic_refill_rq(), udp_xfer_alloc_iob(), undinet_poll(), usb_control(), usb_prefill(), usb_refill(), velocity_refill_rx(), virtnet_refill_rx_virtqueue(), vmbus_xfer_page_iobufs(), vmxnet3_refill_rx(), vxge_hw_ring_replenish(), vxge_hw_vpath_poll_rx(), wep_decrypt(), wep_encrypt(), wpa_alloc_frame(), and xfer_alloc_iob().

                                            {

        /* Pad to minimum length */
        if ( len < IOB_ZLEN )
                len = IOB_ZLEN;

        /* Align buffer on its own size to avoid potential problems
         * with boundary-crossing DMA.
         */
        return alloc_iob_raw ( len, len, 0 );
}
void free_iob ( struct io_buffer iobuf)

Free I/O buffer.

Parameters:
iobufI/O buffer

Definition at line 145 of file iobuf.c.

References assert, io_buffer::data, io_buffer::end, free, free_dma(), io_buffer::head, len, and io_buffer::tail.

Referenced by __vxge_hw_ring_delete(), a3c90x_free_rx_iobuf(), acm_control_receive(), acm_in_complete(), acm_intr_complete(), alloc_iob_okx(), aoe_rx(), aoecmd_rx(), arp_rx(), ath5k_rxbuf_free(), ath9k_stop(), ath9k_tx(), ath_rx_cleanup(), axge_in_complete(), axge_intr_complete(), b44_free_rx_ring(), b44_rx_refill(), ccmp_decrypt(), dhcp_deliver(), dhcp_tx(), dhcpv6_rx(), dm96xx_in_complete(), dm96xx_intr_complete(), dns_xfer_deliver(), eapol_key_rx(), eapol_rx(), ecm_in_complete(), ecm_intr_complete(), efab_free_resources(), efab_receive(), efi_download_deliver_iob(), efi_local_step(), efi_pxe_udp_close(), efi_pxe_udp_deliver(), efi_pxe_udp_read(), efi_pxe_udp_write(), efi_snp_flush(), efi_snp_receive(), efi_snp_transmit(), efi_usb_sync_transfer(), efx_hunt_close(), ena_empty_rx(), eoib_heartbeat_rx(), eth_slow_marker_rx(), eth_slow_rx(), fc_els_rx(), fc_ns_query_deliver(), fc_port_deliver(), fc_xchg_rx(), fc_xchg_tx(), fcoe_deliver(), fcoe_fip_rx(), fcoe_rx(), fcpcmd_recv_rddata(), fcpcmd_recv_rsp(), fcpcmd_recv_unknown(), fcpcmd_recv_xfer_rdy(), fragment_expired(), fragment_reassemble(), free_tls(), ftp_control_deliver(), gdbudp_recv(), http_conn_deliver(), http_content_deliver(), http_tx_request(), hunt_mcdi_fini(), ib_cmrc_complete_recv(), ib_cmrc_complete_send(), ib_cmrc_xfer_deliver(), ib_complete_recv(), ib_complete_send(), ib_mi_complete_recv(), ib_mi_send(), ib_refill_recv(), icmp_rx_echo_reply(), icmp_rx_echo_request(), icmp_tx_echo_request(), icmpv4_rx(), icmpv6_rx(), icplus_close(), ifec_free(), igbvf_free_rx_resources(), intel_empty_rx(), iob_concatenate(), ipv4_rx(), ipv4_tx(), ipv6_rx(), ipv6_tx(), iscsi_socket_deliver(), jme_free_rx_buf(), legacy_poll(), loopback_wait(), lotest_flush(), lotest_rx(), myri10ge_net_close(), myri10ge_net_open(), myson_close(), natsemi_close(), ncm_intr_complete(), ndp_rx_neighbour(), ndp_rx_router_advertisement(), net80211_free_frags(), net80211_free_wlan(), net80211_handle_mgmt(), net80211_probe_finish_all(), net80211_probe_finish_best(), net80211_probe_step(), net80211_rx(), net80211_rx_frag(), net80211_tx_mgmt(), net_discard(), net_poll(), net_rx(), netdev_rx_err(), netdev_tx_err(), netfront_close(), netvsc_recv_data(), nfs_deliver(), nfs_mount_deliver(), nfs_pm_deliver(), nii_close(), ntp_deliver(), nv_free_rxtx_resources(), pcnet32_free_rx_resources(), peerblk_deliver(), peerblk_raw_rx(), peerblk_retrieval_rx(), peerdisc_socket_rx(), phantom_close(), ping_rx(), pinger_deliver(), posix_file_free(), posix_file_xfer_deliver(), pxe_tftp_xfer_deliver(), pxe_udp_deliver(), pxenv_udp_close(), pxenv_udp_read(), pxenv_undi_isr(), pxenv_undi_transmit(), rarp_rx(), read_user(), realtek_close(), rhine_close(), rndis_rx_initialise(), rndis_rx_query_oid(), rndis_rx_set_oid(), rndis_rx_status(), rndis_tx_complete_err(), rndis_tx_halt(), rndis_tx_initialise(), rndis_tx_oid(), rtl818x_free_rx_ring(), sis190_free(), skge_rx_clean(), sky2_rx_clean(), slam_mc_socket_deliver(), slam_socket_deliver(), slam_tx_nack(), smsc75xx_in_complete(), smsc95xx_in_complete(), smscusb_intr_complete(), snpnet_close(), srpdev_deliver(), stp_rx(), tcp_close(), tcp_discard(), tcp_process_tx_queue(), tcp_rx(), tcp_rx_data(), tcp_rx_enqueue(), tcpip_rx(), tcpip_tx(), tftp_rx(), tftp_rx_data(), tg3_rx_iob_free(), tkip_decrypt(), tls_cipherstream_deliver(), tls_new_record(), tls_newdata_process_header(), tls_plainstream_deliver(), tls_send_plaintext(), txnic_destroy_rq(), udp_rx(), udp_tx(), unregister_usb(), usb_control(), usb_flush(), velocity_close(), virtnet_close(), vlan_rx(), vmbus_xfer_page_iobufs(), vxge_hw_ring_replenish(), wep_decrypt(), xcm_deliver(), xfer_deliver(), and xferbuf_deliver().

                                          {
        size_t len;

        /* Allow free_iob(NULL) to be valid */
        if ( ! iobuf )
                return;

        /* Sanity checks */
        assert ( iobuf->head <= iobuf->data );
        assert ( iobuf->data <= iobuf->tail );
        assert ( iobuf->tail <= iobuf->end );

        /* Free buffer */
        len = ( iobuf->end - iobuf->head );
        if ( iobuf->end == iobuf ) {

                /* Descriptor is inline */
                free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );

        } else {

                /* Descriptor is detached */
                free_dma ( iobuf->head, len );
                free ( iobuf );
        }
}
int iob_ensure_headroom ( struct io_buffer iobuf,
size_t  len 
)

Ensure I/O buffer has sufficient headroom.

Parameters:
iobufI/O buffer
lenRequired headroom

This function currently only checks for the required headroom; it does not reallocate the I/O buffer if required. If we ever have a code path that requires this functionality, it's a fairly trivial change to make.

Definition at line 183 of file iobuf.c.

References ENOBUFS, and iob_headroom().

Referenced by axge_out_transmit(), dm96xx_out_transmit(), efi_pxe_udp_deliver(), ncm_out_transmit(), pxe_udp_deliver(), smsc75xx_out_transmit(), smsc95xx_out_transmit(), and udp_tx().

                                                                {

        if ( iob_headroom ( iobuf ) >= len )
                return 0;
        return -ENOBUFS;
}
struct io_buffer* iob_concatenate ( struct list_head list) [read]

Concatenate I/O buffers into a single buffer.

Parameters:
listList of I/O buffers
Return values:
iobufConcatenated I/O buffer, or NULL on allocation failure

After a successful concatenation, the list will be empty.

Definition at line 198 of file iobuf.c.

References alloc_iob_raw(), io_buffer::data, free_iob(), INIT_LIST_HEAD, iob_len(), iob_put, len, io_buffer::list, list_del, list_first_entry, list_for_each_entry, list_for_each_entry_safe, list_is_singular, memcpy(), and NULL.

Referenced by tls_new_record().

                                                              {
        struct io_buffer *iobuf;
        struct io_buffer *tmp;
        struct io_buffer *concatenated;
        size_t len = 0;

        /* If the list contains only a single entry, avoid an
         * unnecessary additional allocation.
         */
        if ( list_is_singular ( list ) ) {
                iobuf = list_first_entry ( list, struct io_buffer, list );
                INIT_LIST_HEAD ( list );
                return iobuf;
        }

        /* Calculate total length */
        list_for_each_entry ( iobuf, list, list )
                len += iob_len ( iobuf );

        /* Allocate new I/O buffer */
        concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
        if ( ! concatenated )
                return NULL;

        /* Move data to new I/O buffer */
        list_for_each_entry_safe ( iobuf, tmp, list, list ) {
                list_del ( &iobuf->list );
                memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
                         iobuf->data, iob_len ( iobuf ) );
                free_iob ( iobuf );
        }

        return concatenated;
}
struct io_buffer* iob_split ( struct io_buffer iobuf,
size_t  len 
) [read]

Split I/O buffer.

Parameters:
iobufI/O buffer
lenLength to split into a new I/O buffer
Return values:
splitNew I/O buffer, or NULL on allocation failure

Split the first len bytes of the existing I/O buffer into a separate I/O buffer. The resulting buffers are likely to have no headroom or tailroom.

If this call fails, then the original buffer will be unmodified.

Definition at line 246 of file iobuf.c.

References alloc_iob(), assert, io_buffer::data, iob_len(), iob_pull, iob_put, memcpy(), and NULL.

                                                                     {
        struct io_buffer *split;

        /* Sanity checks */
        assert ( len <= iob_len ( iobuf ) );

        /* Allocate new I/O buffer */
        split = alloc_iob ( len );
        if ( ! split )
                return NULL;

        /* Copy in data */
        memcpy ( iob_put ( split, len ), iobuf->data, len );
        iob_pull ( iobuf, len );
        return split;
}