diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index d4046bccb2..bc3dfd3bce 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -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 diff --git a/wireless/ieee802154/Kconfig b/wireless/ieee802154/Kconfig index aa3f16219c..77f194d6ef 100644 --- a/wireless/ieee802154/Kconfig +++ b/wireless/ieee802154/Kconfig @@ -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 diff --git a/wireless/ieee802154/Make.defs b/wireless/ieee802154/Make.defs index da84b153a7..73354b2609 100644 --- a/wireless/ieee802154/Make.defs +++ b/wireless/ieee802154/Make.defs @@ -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) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 0f548841c2..46073765b6 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -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); diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h index b98fa0d360..152046b61f 100644 --- a/wireless/ieee802154/mac802154.h +++ b/wireless/ieee802154/mac802154.h @@ -58,6 +58,8 @@ * Public Function Prototypes ****************************************************************************/ +struct iob_s; /* Forward reference */ + /**************************************************************************** * Name: mac802154_bind * diff --git a/wireless/ieee802154/mac802154_indalloc.c b/wireless/ieee802154/mac802154_indalloc.c new file mode 100644 index 0000000000..84ec3b131a --- /dev/null +++ b/wireless/ieee802154/mac802154_indalloc.c @@ -0,0 +1,367 @@ +/**************************************************************************** + * wireless/ieee802154_indalloc.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include + +#include +#include + +#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 +}