ieee 802.15.4: Add a pool-based memory allocator for RX frame meta-data.

This commit is contained in:
Gregory Nutt 2017-05-05 12:50:34 -06:00
parent 0eb7ec046e
commit 3fcdc28a59
6 changed files with 468 additions and 0 deletions

View file

@ -652,10 +652,13 @@ struct ieee802154_data_conf_s
struct ieee802154_data_ind_s
{
FAR struct ieee802154_data_ind_s *flink;
struct ieee802154_addr_s src; /* Source addressing information */
struct ieee802154_addr_s dest; /* Destination addressing infromation */
uint8_t lqi; /* Link Quality Index */
uint8_t dsn; /* Data Sequence Number */
uint8_t pool; /* Memory pool (Needed for deallocation) */
uint32_t timestamp; /* Time of received frame */
#ifdef CONFIG_IEEE802154_SECURITY

View file

@ -60,6 +60,35 @@ config IEEE802154_NTXDESC
endif # IEEE802154_MAC
config IEEE802154_IND_PREALLOC
int "Number of pre-allocated meta-data structures"
default 20
---help---
This specifies the total number of preallocated meta data structures
must be allocated with each incoming packet. These may be allocated
from either from tasking logic or from interrupt level logic.
config IEEE802154_IND_IRQRESERVE
int "Rserved pre-allocated meta-data structures"
default 10
---help---
If meta-data structures can be allocated from interrupt handlers,
then this specifies the number of pre-allocatd meta-data structures
that are reserved for for use only by interrupt handlers. This may
be zero to reserve no meta-data structures for interrupt handlers.
In that case, the allocation will fail if tasking logic has
allocated them all.
Interrupt logic will first attempt to allocate fromt the general,
pre-allocated structure pool that will contain up to (size
CONFIG_IEEE802154_IND_PREALLOC - CONFIG_IEEE802154_IND_IRQRESERVE)
entries. If that fails, then it will try to take a structure from
the reserve (size CONFIG_IEEE802154_IND_IRQRESERVE).
Non-interrupt logic will also first attempt to allocate fromt the
general, pre-allocated structure pool. If that fails, it will
dynamically allocate the meta data structure with an additional cost in performance.
config IEEE802154_NETDEV
bool "IEEE802154 6loWPAN Network Device"
default n

View file

@ -37,6 +37,8 @@ ifeq ($(CONFIG_WIRELESS_IEEE802154),y)
# Include IEEE 802.15.4 support
CSRCS += mac802154_indalloc.c
# Include wireless devices build support
ifeq ($(CONFIG_IEEE802154_MAC),y)

View file

@ -1605,3 +1605,68 @@ int mac802154_resp_orphan(MACHANDLE mac,
(FAR struct ieee802154_privmac_s *)mac;
return -ENOTTY;
}
/****************************************************************************
* Name: ieee802154_indpool_initialize
*
* Description:
* This function initializes the meta-data allocator. This function must
* be called early in the initialization sequence before any radios
* begin operation.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_indpool_initialize(void);
/****************************************************************************
* Name: ieee802154_ind_allocate
*
* Description:
* The ieee802154_ind_allocate function will get a free meta-data
* structure for use by the IEEE 802.15.4 MAC.
*
* Interrupt handling logic will first attempt to allocate from the
* g_indfree list. If that list is empty, it will attempt to allocate
* from its reserve, g_indfree_irq. If that list is empty, then the
* allocation fails (NULL is returned).
*
* Non-interrupt handler logic will attempt to allocate from g_indfree
* list. If that the list is empty, then the meta-data structure will be
* allocated from the dynamic memory pool.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure. All user fields in this
* structure have been zeroed. On a failure to allocate, NULL is
* returned.
*
****************************************************************************/
FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void);
/****************************************************************************
* Name: ieee802154_ind_free
*
* Description:
* The ieee802154_ind_free function will return a meta-data structure to
* the free pool of messages if it was a pre-allocated meta-data
* structure. If the meta-data structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* ind - meta-data structure to free
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind);

View file

@ -58,6 +58,8 @@
* Public Function Prototypes
****************************************************************************/
struct iob_s; /* Forward reference */
/****************************************************************************
* Name: mac802154_bind
*

View file

@ -0,0 +1,367 @@
/****************************************************************************
* wireless/ieee802154_indalloc.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <string.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#include "mac802154.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if !defined(CONFIG_IEEE802154_IND_PREALLOC) || CONFIG_IEEE802154_IND_PREALLOC < 0
# undef CONFIG_IEEE802154_IND_PREALLOC
# define CONFIG_IEEE802154_IND_PREALLOC 20
#endif
#if !defined(CONFIG_IEEE802154_IND_IRQRESERVE) || CONFIG_IEEE802154_IND_IRQRESERVE < 0
# undef CONFIG_IEEE802154_IND_IRQRESERVE
# define CONFIG_IEEE802154_IND_IRQRESERVE 10
#endif
#if CONFIG_IEEE802154_IND_IRQRESERVE > CONFIG_IEEE802154_IND_PREALLOC
# undef CONFIG_IEEE802154_IND_IRQRESERVE
# define CONFIG_IEEE802154_IND_IRQRESERVE CONFIG_IEEE802154_IND_PREALLOC
#endif
/* Memory Pools */
#define POOL_IND_GENERAL 0
#define POOL_IND_IRQ 1
#define POOL_IND_DYNAMIC 2
/****************************************************************************
* Private Data
****************************************************************************/
#if CONFIG_IEEE802154_IND_PREALLOC > 0
#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE
/* The g_indfree is a list of meta-data structures that are available for
* general use. The number of messages in this list is a system configuration
* item.
*/
static struct ieee802154_data_ind_s *g_indfree;
#endif
#if CONFIG_IEEE802154_IND_IRQRESERVE > 0
/* The g_indfree_irq is a list of meta-data structures that are reserved for
* use by only by interrupt handlers.
*/
static struct ieee802154_data_ind_s *g_indfree_irq;
#endif
/* Pool of pre-allocated meta-data stuctures */
static struct ieee802154_data_ind_s g_indpool[CONFIG_IEEE802154_IND_PREALLOC];
#endif /* CONFIG_IEEE802154_IND_PREALLOC > 0 */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ieee802154_indpool_initialize
*
* Description:
* This function initializes the meta-data allocator. This function must
* be called early in the initialization sequence before any radios
* begin operation.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_indpool_initialize(void)
{
#if CONFIG_IEEE802154_IND_PREALLOC > 0
FAR struct ieee802154_data_ind_s *pool = g_indpool;
int remaining = CONFIG_IEEE802154_IND_PREALLOC;
#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE
/* Initialize g_indfree, thelist of meta-data structures that are available
* for general use.
*/
g_indfree = NULL;
while (remaining > CONFIG_IEEE802154_IND_IRQRESERVE)
{
FAR struct ieee802154_data_ind_s *ind = pool;
/* Add the next meta data structure from the pool to the list of
* general structures.
*/
ind->flink = g_indfree;
g_indfree = ind;
/* Set up for the next structure from the pool */
pool++;
remaining--;
}
#endif
#if CONFIG_IEEE802154_IND_IRQRESERVE > 0
/* Initialize g_indfree_irq is a list of meta-data structures reserved for
* use by only by interrupt handlers.
*/
g_indfree_irq = NULL;
while (remaining > 0)
{
FAR struct ieee802154_data_ind_s *ind = pool;
/* Add the next meta data structure from the pool to the list of
* general structures.
*/
ind->flink = g_indfree_irq;
g_indfree_irq = ind;
/* Set up for the next structure from the pool */
pool++;
remaining--;
}
#endif
#endif /* CONFIG_IEEE802154_IND_PREALLOC > 0 */
}
/****************************************************************************
* Name: ieee802154_ind_allocate
*
* Description:
* The ieee802154_ind_allocate function will get a free meta-data
* structure for use by the IEEE 802.15.4 MAC.
*
* Interrupt handling logic will first attempt to allocate from the
* g_indfree list. If that list is empty, it will attempt to allocate
* from its reserve, g_indfree_irq. If that list is empty, then the
* allocation fails (NULL is returned).
*
* Non-interrupt handler logic will attempt to allocate from g_indfree
* list. If that the list is empty, then the meta-data structure will be
* allocated from the dynamic memory pool.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure. All user fields in this
* structure have been zeroed. On a failure to allocate, NULL is
* returned.
*
****************************************************************************/
FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void)
{
#if CONFIG_IEEE802154_IND_PREALLOC > 0
FAR struct ieee802154_data_ind_s *ind;
irqstate_t flags;
uint8_t pool;
/* If we were called from an interrupt handler, then try to get the meta-
* data structure from generally available list of messages. If this fails,
* then try the list of messages reserved for interrupt handlers
*/
flags = enter_critical_section(); /* Always necessary in SMP mode */
if (up_interrupt_context())
{
#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE
/* Try the general free list */
if (g_indfree != NULL)
{
ind = g_indfree;
g_indfree = ind->flink;
leave_critical_section(flags);
pool = POOL_IND_GENERAL;
}
else
#endif
#if CONFIG_IEEE802154_IND_IRQRESERVE > 0
/* Try the list list reserved for interrupt handlers */
if (g_indfree_irq != NULL)
{
ind = g_indfree_irq;
g_indfree_irq = ind->flink;
leave_critical_section(flags);
pool = POOL_IND_IRQ;
}
else
#endif
{
leave_critical_section(flags);
return NULL;
}
}
/* We were not called from an interrupt handler. */
else
{
#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE
/* Try the general free list */
if (g_indfree != NULL)
{
ind = g_indfree;
g_indfree = ind->flink;
leave_critical_section(flags);
pool = POOL_IND_GENERAL;
}
else
#endif
{
/* If we cannot a meta-data structure from the free list, then we
* will have to allocate one from the kernal memory pool.
*/
leave_critical_section(flags);
ind = (FAR struct ieee802154_data_ind_s *)
kmm_malloc((sizeof (struct ieee802154_data_ind_s)));
/* Check if we allocated the meta-data structure */
if (ind != NULL)
{
/* Yes... remember that this meta-data structure was dynamically allocated */
pool = POOL_IND_DYNAMIC;
}
}
}
/* We have successfully allocated memory from some source.
* Zero and tag the alloated meta-data structure.
*/
memset(ind, 0, sizeof(struct ieee802154_data_ind_s));
ind->pool = pool;
return ind;
#else
return NULL;
#endif
}
/****************************************************************************
* Name: ieee802154_ind_free
*
* Description:
* The ieee802154_ind_free function will return a meta-data structure to
* the free pool of messages if it was a pre-allocated meta-data
* structure. If the meta-data structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* ind - meta-data structure to free
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind)
{
#if CONFIG_IEEE802154_IND_PREALLOC > 0
irqstate_t flags;
#if CONFIG_IEEE802154_IND_PREALLOC > CONFIG_IEEE802154_IND_IRQRESERVE
/* If this is a generally available pre-allocated meta-data structure,
* then just put it back in the free list.
*/
if (ind->pool == POOL_IND_GENERAL)
{
/* Make sure we avoid concurrent access to the free
* list from interrupt handlers.
*/
flags = enter_critical_section();
ind->flink = g_indfree;
g_indfree = ind;
leave_critical_section(flags);
}
else
#endif
#if CONFIG_IEEE802154_IND_IRQRESERVE > 0
/* If this is a meta-data structure pre-allocated for interrupts,
* then put it back in the correct free list.
*/
if (ind->pool == POOL_IND_IRQ)
{
/* Make sure we avoid concurrent access to the free
* list from interrupt handlers.
*/
flags = enter_critical_section();
ind->flink = g_indfree_irq;
g_indfree_irq = ind;
leave_critical_section(flags);
}
else
#endif
{
/* Otherwise, deallocate it. */
DEBUGASSERT(ind->pool == POOL_IND_DYNAMIC);
sched_kfree(ind);
}
#endif
}