diff --git a/Documentation/components/mm/index.rst b/Documentation/components/mm/index.rst index aabe8355039..e2a9988bbdb 100644 --- a/Documentation/components/mm/index.rst +++ b/Documentation/components/mm/index.rst @@ -232,3 +232,9 @@ available for usage by drivers. The I/O buffers have these properties: it is removed from the free list; when a buffer is freed it is returned to the free list. #. The calling application will wait if there are not free buffers. +#. IOBs can be chained together to form larger buffers. +#. The extension interface ``iob_init_with_data`` supports external + buffer init as iob structure when CONFIG_IOB_ALLOC is enabled. This + interface allows different protocol modules to use their own unique + I/O buffer sources and allocation strategies without interfering with + each other. diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index 0dea9b47998..f2914762371 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -266,6 +266,33 @@ FAR struct iob_s *iob_alloc_dynamic(uint16_t size); FAR struct iob_s *iob_alloc_with_data(FAR void *data, uint16_t size, iob_free_cb_t free_cb); + +/**************************************************************************** + * Name: iob_init_with_data + * + * Description: + * Initialize an I/O buffer and playload + * + * Input Parameters: + * data - Make io_data point to a specific address, the caller is + * responsible for the memory management. The caller should + * ensure that the memory is not freed before the iob is freed, + * and caller need to reserve space for alignment. + * size - The size of the data parameter + * free_cb - Notify the caller when the iob is freed. The caller can + * perform additional operations on the data before it is freed. + * + * +---------+ + * | IOB | + * | io_data |--+ + * | buffer |<-+ + * +---------+ + * + ****************************************************************************/ + +FAR struct iob_s *iob_init_with_data(FAR void *data, uint16_t size, + iob_free_cb_t free_cb); + #endif /**************************************************************************** diff --git a/mm/iob/iob_alloc.c b/mm/iob/iob_alloc.c index a0fb94ec523..921b9d3b48a 100644 --- a/mm/iob/iob_alloc.c +++ b/mm/iob/iob_alloc.c @@ -226,7 +226,7 @@ static FAR struct iob_s *iob_allocwait(bool throttled, unsigned int timeout) * Name: iob_free_dynamic * * Description: - * Dummy free callback function, do nothing. + * Free the I/O buffer and payload to the heap * * Input Parameters: * data - @@ -235,6 +235,7 @@ static FAR struct iob_s *iob_allocwait(bool throttled, unsigned int timeout) static void iob_free_dynamic(FAR void *data) { + kmm_free(data); } #endif @@ -396,4 +397,45 @@ FAR struct iob_s *iob_alloc_with_data(FAR void *data, uint16_t size, return iob; } + +/**************************************************************************** + * Name: iob_init_with_data + * + * Description: + * Initialize an I/O buffer and playload + * + * Input Parameters: + * data - Make io_data point to a specific address, the caller is + * responsible for the memory management. The caller should + * ensure that the memory is not freed before the iob is freed, + * and caller need to reserve space for alignment. + * size - The size of the data parameter + * free_cb - Notify the caller when the iob is freed. The caller can + * perform additional operations on the data before it is freed. + * + * +---------+ + * | IOB | + * | io_data |--+ + * | buffer |<-+ + * +---------+ + * + ****************************************************************************/ + +FAR struct iob_s *iob_init_with_data(FAR void *data, uint16_t size, + iob_free_cb_t free_cb) +{ + FAR struct iob_s *iob = (FAR struct iob_s *)data; + + iob->io_flink = NULL; /* Not in a chain */ + iob->io_len = 0; /* Length of the data in the entry */ + iob->io_offset = 0; /* Offset to the beginning of data */ + iob->io_pktlen = 0; /* Total length of the packet */ + iob->io_free = free_cb; /* Customer free callback */ + iob->io_data = (FAR uint8_t *)ALIGN_UP((uintptr_t)(iob + 1), + CONFIG_IOB_ALIGNMENT); + iob->io_bufsize = ((FAR uint8_t *)data + size) - iob->io_data; + + return iob; +} + #endif diff --git a/mm/iob/iob_free.c b/mm/iob/iob_free.c index 86af4304d26..7d734adc880 100644 --- a/mm/iob/iob_free.c +++ b/mm/iob/iob_free.c @@ -35,6 +35,7 @@ #ifdef CONFIG_IOB_ALLOC # include #endif +#include #include #include "iob.h" @@ -120,8 +121,18 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob) #ifdef CONFIG_IOB_ALLOC if (iob->io_free != NULL) { - iob->io_free(iob->io_data); - kmm_free(iob); + FAR uint8_t *io_data = (FAR uint8_t *)ALIGN_UP((uintptr_t)(iob + 1), + CONFIG_IOB_ALIGNMENT); + if (iob->io_data == io_data) + { + iob->io_free(iob); + } + else + { + iob->io_free(iob->io_data); + kmm_free(iob); + } + return next; } #endif