mm/iob: Support alloc IOB via malloc

Support the network interface card driver to receive zero copies of packets and send and receive giant frame packets, allowing drivers to initialize the DMA buffer to the iob structure, and we can apply for IOB with large memory

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2024-04-01 14:09:10 +08:00 committed by Xiang Xiao
parent 00d208baf6
commit b934555fd1
7 changed files with 219 additions and 13 deletions

View File

@ -88,12 +88,18 @@
# define IOB_QEMPTY(q) ((q)->qh_head == NULL)
#endif
#ifdef CONFIG_IOB_ALLOC
# define IOB_BUFSIZE(p) ((p)->io_bufsize)
#else
# define IOB_BUFSIZE(p) CONFIG_IOB_BUFSIZE
#endif
/****************************************************************************
* Public Types
****************************************************************************/
typedef CODE void (*iob_free_cb_t)(FAR void *data);
/* Represents one I/O buffer. A packet is contained by one or more I/O
* buffers in a chain. The io_pktlen is only valid for the I/O buffer at
* the head of the chain.
@ -107,16 +113,24 @@ struct iob_s
/* Payload */
#if CONFIG_IOB_BUFSIZE < 256
#if CONFIG_IOB_BUFSIZE < 256 && !defined(CONFIG_IOB_ALLOC)
uint8_t io_len; /* Length of the data in the entry */
uint8_t io_offset; /* Data begins at this offset */
#else
uint16_t io_len; /* Length of the data in the entry */
uint16_t io_offset; /* Data begins at this offset */
# ifdef CONFIG_IOB_ALLOC
uint16_t io_bufsize; /* Total length of the data buffer */
# endif
#endif
unsigned int io_pktlen; /* Total length of the packet */
#ifdef CONFIG_IOB_ALLOC
iob_free_cb_t io_free; /* Custom free callback */
FAR uint8_t *io_data;
#else
uint8_t io_data[CONFIG_IOB_BUFSIZE];
#endif
};
#if CONFIG_IOB_NCHAINS > 0
@ -205,6 +219,53 @@ FAR struct iob_s *iob_alloc(bool throttled);
FAR struct iob_s *iob_tryalloc(bool throttled);
#ifdef CONFIG_IOB_ALLOC
/****************************************************************************
* Name: iob_alloc_dynamic
*
* Description:
* Allocate an I/O buffer and playload from heap
*
* Input Parameters:
* size - The size of the io_data that is allocated.
*
* +---------+
* | IOB |
* | io_data |--+
* | buffer |<-+
* +---------+
*
****************************************************************************/
FAR struct iob_s *iob_alloc_dynamic(uint16_t size);
/****************************************************************************
* Name: iob_alloc_with_data
*
* Description:
* Allocate an I/O buffer from heap and attach the external payload
*
* 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.
*
* +---------+ +-->+--------+
* | IOB | | | data |
* | io_data |--+ +--------+
* +---------+
*
* 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.
* The free_cb is called when the iob is freed.
*
****************************************************************************/
FAR struct iob_s *iob_alloc_with_data(FAR void *data, uint16_t size,
iob_free_cb_t free_cb);
#endif
/****************************************************************************
* Name: iob_navail
*

View File

@ -103,6 +103,12 @@ config IOB_NOTIFIER_DIV
a notification will be sent only when there are a multiple of 4 IOBs
available.
config IOB_ALLOC
bool "Dynamic I/O buffer allocation"
default n
---help---
This option will enable dynamic I/O buffer allocation
config IOB_DEBUG
bool "Force I/O buffer debug"
default n

View File

@ -39,6 +39,8 @@
* Pre-processor Definitions
****************************************************************************/
#define ROUNDUP(x, y) (((x) + (y) - 1) / (y) * (y))
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_IOB_DEBUG)
# define ioberr _err
# define iobwarn _warn

View File

@ -30,6 +30,9 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#ifdef CONFIG_IOB_ALLOC
# include <nuttx/kmalloc.h>
#endif
#include <nuttx/mm/iob.h>
#include "iob.h"
@ -197,6 +200,23 @@ static FAR struct iob_s *iob_allocwait(bool throttled, unsigned int timeout)
return iob;
}
#ifdef CONFIG_IOB_ALLOC
/****************************************************************************
* Name: iob_free_dynamic
*
* Description:
* Dummy free callback function, do nothing.
*
* Input Parameters:
* data -
*
****************************************************************************/
static void iob_free_dynamic(FAR void *data)
{
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -329,3 +349,91 @@ FAR struct iob_s *iob_tryalloc(bool throttled)
spin_unlock_irqrestore(&g_iob_lock, flags);
return NULL;
}
#ifdef CONFIG_IOB_ALLOC
/****************************************************************************
* Name: iob_alloc_dynamic
*
* Description:
* Allocate an I/O buffer and playload from heap
*
* Input Parameters:
* size - The size of the io_data that is allocated.
*
* +---------+
* | IOB |
* | io_data |--+
* | buffer |<-+
* +---------+
*
****************************************************************************/
FAR struct iob_s *iob_alloc_dynamic(uint16_t size)
{
FAR struct iob_s *iob;
size_t alignsize;
alignsize = ROUNDUP(sizeof(struct iob_s), CONFIG_IOB_ALIGNMENT) + size;
iob = kmm_memalign(CONFIG_IOB_ALIGNMENT, alignsize);
if (iob)
{
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_bufsize = size; /* Total length of the iob buffer */
iob->io_pktlen = 0; /* Total length of the packet */
iob->io_free = iob_free_dynamic; /* Customer free callback */
iob->io_data = (FAR uint8_t *)ROUNDUP((uintptr_t)(iob + 1),
CONFIG_IOB_ALIGNMENT);
}
return iob;
}
/****************************************************************************
* Name: iob_alloc_with_data
*
* Description:
* Allocate an I/O buffer from heap and attach the external payload
*
* 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.
*
* +---------+ +-->+--------+
* | IOB | | | data |
* | io_data |--+ +--------+
* +---------+
*
* 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.
* The free_cb is called when the iob is freed.
*
****************************************************************************/
FAR struct iob_s *iob_alloc_with_data(FAR void *data, uint16_t size,
iob_free_cb_t free_cb)
{
FAR struct iob_s *iob;
DEBUGASSERT(free_cb != NULL);
iob = kmm_malloc(sizeof(struct iob_s));
if (iob)
{
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_bufsize = size; /* Total length of the iob buffer */
iob->io_pktlen = 0; /* Total length of the packet */
iob->io_free = free_cb; /* Customer free callback */
iob->io_data = data;
}
return iob;
}
#endif

View File

@ -30,6 +30,9 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#ifdef CONFIG_IOB_ALLOC
# include <nuttx/kmalloc.h>
#endif
#include <nuttx/mm/iob.h>
#include "iob.h"
@ -112,6 +115,15 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
next, next->io_pktlen, next->io_len);
}
#ifdef CONFIG_IOB_ALLOC
if (iob->io_free != NULL)
{
iob->io_free(iob->io_data);
kmm_free(iob);
return next;
}
#endif
/* Free the I/O buffer by adding it to the head of the free or the
* committed list. We don't know what context we are called from so
* we use extreme measures to protect the free list: We disable

View File

@ -34,11 +34,15 @@
* Pre-processor Definitions
****************************************************************************/
#define ROUNDUP(x, y) (((x) + (y) - 1) / (y) * (y))
/* Fix the I/O Buffer size with specified alignment size */
#ifdef CONFIG_IOB_ALLOC
# define IOB_ALIGN_SIZE ROUNDUP(sizeof(struct iob_s) + CONFIG_IOB_BUFSIZE, \
CONFIG_IOB_ALIGNMENT)
#else
# define IOB_ALIGN_SIZE ROUNDUP(sizeof(struct iob_s), CONFIG_IOB_ALIGNMENT)
#endif
#define IOB_BUFFER_SIZE (IOB_ALIGN_SIZE * CONFIG_IOB_NBUFFERS + \
CONFIG_IOB_ALIGNMENT - 1)
@ -139,6 +143,10 @@ void iob_initialize(void)
/* Add the pre-allocate I/O buffer to the head of the free list */
iob->io_flink = g_iob_freelist;
#ifdef CONFIG_IOB_ALLOC
iob->io_bufsize = CONFIG_IOB_BUFSIZE;
iob->io_data = (FAR uint8_t *)(iob + 1);
#endif
g_iob_freelist = iob;
}

View File

@ -49,9 +49,9 @@ int iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen,
{
FAR struct iob_s *penultimate;
FAR struct iob_s *next;
uint16_t offset = 0;
int remain = pktlen;
int ninqueue = 0;
int nrequire;
int nrequire = 0;
uint16_t len;
/* The data offset must be less than CONFIG_IOB_BUFSIZE */
@ -67,19 +67,28 @@ int iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen,
while (next != NULL)
{
ninqueue++;
offset += next->io_offset;
penultimate = next;
if (remain > 0)
{
nrequire++;
remain -= IOB_BUFSIZE(next) - next->io_offset;
}
next = next->io_flink;
}
/* Trim inqueue entries if needed */
if (remain > 0)
{
nrequire += (remain + CONFIG_IOB_BUFSIZE - 1) / CONFIG_IOB_BUFSIZE;
}
nrequire = (pktlen + offset + IOB_BUFSIZE(iob) - 1) / IOB_BUFSIZE(iob);
if (nrequire == 0)
{
nrequire = 1;
}
/* Trim inqueue entries if needed */
if (nrequire < ninqueue)
{
/* Loop until complete the trim */