176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef _GPXE_IOBUF_H
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define _GPXE_IOBUF_H
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffers
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER );
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h>
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/list.h>
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffer alignment
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I/O buffers allocated via alloc_iob() are guaranteed to be
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * physically aligned to this boundary.  Some cards cannot DMA across
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a 4kB boundary.  With a standard Ethernet MTU, aligning to a 2kB
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * boundary is sufficient to guarantee no 4kB boundary crossings.  For
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IOB_ALIGN 2048
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Minimum I/O buffer length
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * alloc_iob() will round up the allocated length to this size if
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * necessary.  This is used on behalf of hardware that is not capable
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of auto-padding.
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define IOB_ZLEN 64
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * A persistent I/O buffer
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This data structure encapsulates a long-lived I/O buffer.  The
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * buffer may be passed between multiple owners, queued for possible
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * retransmission, etc.
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct io_buffer {
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** List of which this buffer is a member
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * The list must belong to the current owner of the buffer.
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Different owners may maintain different lists (e.g. a
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * retransmission list for TCP).
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct list_head list;
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** Start of the buffer */
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *head;
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** Start of data */
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *data;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** End of data */
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *tail;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** End of the buffer */
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        void *end;
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Reserve space at start of I/O buffer
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length to reserve
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data	Pointer to new start of buffer
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->data += len;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->tail += len;
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return iobuf->data;
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_reserve( iobuf, len ) ( {			\
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *__result;					\
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result = iob_reserve ( (iobuf), (len) );	\
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( (iobuf)->tail <= (iobuf)->end );	\
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result; } )
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add data to start of I/O buffer
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length to add
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data	Pointer to new start of buffer
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->data -= len;
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return iobuf->data;
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_push( iobuf, len ) ( {			\
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *__result;					\
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result = iob_push ( (iobuf), (len) );		\
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( (iobuf)->data >= (iobuf)->head );	\
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result; } )
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove data from start of I/O buffer
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length to remove
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data	Pointer to new start of buffer
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->data += len;
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( iobuf->data <= iobuf->tail );
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return iobuf->data;
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_pull( iobuf, len ) ( {			\
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *__result;					\
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result = iob_pull ( (iobuf), (len) );		\
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( (iobuf)->data <= (iobuf)->tail );	\
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result; } )
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add data to end of I/O buffer
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length to add
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret data	Pointer to newly added space
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *old_tail = iobuf->tail;
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->tail += len;
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return old_tail;
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_put( iobuf, len ) ( {			\
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *__result;					\
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result = iob_put ( (iobuf), (len) );		\
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( (iobuf)->tail <= (iobuf)->end );	\
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__result; } )
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove data from end of I/O buffer
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length to remove
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->tail -= len;
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_unput( iobuf, len ) do {			\
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iob_unput ( (iobuf), (len) );			\
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	assert ( (iobuf)->tail >= (iobuf)->data );	\
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} while ( 0 )
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Empty an I/O buffer
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_empty ( struct io_buffer *iobuf ) {
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->tail = iobuf->data;
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate length of data in an I/O buffer
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len	Length of data in buffer
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_len ( struct io_buffer *iobuf ) {
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ( iobuf->tail - iobuf->data );
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate available space at start of an I/O buffer
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len	Length of data available at start of buffer
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_headroom ( struct io_buffer *iobuf ) {
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ( iobuf->data - iobuf->head );
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Calculate available space at end of an I/O buffer
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len	Length of data available at end of buffer
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ( iobuf->end - iobuf->tail );
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Create a temporary I/O buffer
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v data	Data buffer
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len	Length of data
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v max_len	Length of buffer
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It is sometimes useful to use the iob_xxx() methods on temporary
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * data buffers.
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void iob_populate ( struct io_buffer *iobuf,
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  void *data, size_t len, size_t max_len ) {
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->head = iobuf->data = data;
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->tail = ( data + len );
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf->end = ( data + max_len );
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disown an I/O buffer
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * There are many functions that take ownership of the I/O buffer they
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are passed as a parameter.  The caller should not retain a pointer
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to the I/O buffer.  Use iob_disown() to automatically nullify the
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * caller's pointer, e.g.:
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *     xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This will ensure that iobuf is set to NULL for any code after the
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * call to xfer_deliver_iob().
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define iob_disown( iobuf ) ( {				\
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct io_buffer *__iobuf = (iobuf);		\
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	(iobuf) = NULL;					\
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__iobuf; } )
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern struct io_buffer * __malloc alloc_iob ( size_t len );
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void free_iob ( struct io_buffer *iobuf );
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* _GPXE_IOBUF_H */
230