1 /*
2  * Copyright (c) 2020 - 2023, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /**
36  * @file nrf_802154_buffer_allocator.c
37  * @brief Buffer allocation for 802.15.4 receptions and transmissions.
38  */
39 
40 #include "nrf_802154_buffer_allocator.h"
41 
42 #include "nrf_802154_serialization_crit_sect.h"
43 
44 #include <assert.h>
45 #include <stdbool.h>
46 #include <stdint.h>
47 
buffer_alloc(nrf_802154_buffer_t * p_buffer_pool,size_t buffer_pool_len)48 static uint8_t * buffer_alloc(nrf_802154_buffer_t * p_buffer_pool, size_t buffer_pool_len)
49 {
50     nrf_802154_buffer_t * p_buffer  = NULL;
51     bool                  success   = false;
52     bool                  retry     = false;
53     uint32_t              crit_sect = 0UL;
54 
55     do
56     {
57         retry = false;
58 
59         // Iterate over the buffer pool to search for a free buffer
60         for (uint32_t i = 0; i < buffer_pool_len; i++)
61         {
62             p_buffer = &p_buffer_pool[i];
63 
64             if (!p_buffer->taken)
65             {
66                 // Free buffer detected. Enter critical section to take it
67                 nrf_802154_serialization_crit_sect_enter(&crit_sect);
68 
69                 if (p_buffer->taken)
70                 {
71                     // The allocation was preempted and the buffer was taken by higher priority
72                     // Reiterate over the buffer pool and search for a free buffer again
73                     retry = true;
74                 }
75                 else
76                 {
77                     // The allocation can be performed safely
78                     p_buffer->taken = true;
79                     success         = true;
80                 }
81 
82                 nrf_802154_serialization_crit_sect_exit(crit_sect);
83 
84                 break;
85             }
86         }
87     }
88     while (retry);
89 
90     return success ? p_buffer->data : NULL;
91 }
92 
buffer_free(nrf_802154_buffer_t * p_buffer_to_free,nrf_802154_buffer_t * p_buffer_pool,size_t buffer_pool_len)93 static void buffer_free(nrf_802154_buffer_t * p_buffer_to_free,
94                         nrf_802154_buffer_t * p_buffer_pool,
95                         size_t                buffer_pool_len)
96 {
97     uint32_t crit_sect = 0UL;
98     size_t   idx       =
99         ((uintptr_t)p_buffer_to_free - (uintptr_t)p_buffer_pool) / sizeof(nrf_802154_buffer_t);
100 
101     assert(idx < buffer_pool_len);
102 
103     nrf_802154_serialization_crit_sect_enter(&crit_sect);
104 
105     p_buffer_pool[idx].taken = false;
106 
107     nrf_802154_serialization_crit_sect_exit(crit_sect);
108 }
109 
nrf_802154_buffer_allocator_init(nrf_802154_buffer_allocator_t * p_obj,void * p_memory,size_t memsize)110 void nrf_802154_buffer_allocator_init(nrf_802154_buffer_allocator_t * p_obj,
111                                       void                          * p_memory,
112                                       size_t                          memsize)
113 {
114     size_t capacity = memsize / sizeof(nrf_802154_buffer_t);
115 
116     assert((capacity == 0U) || ((capacity != 0U) && (p_memory != NULL)));
117 
118     p_obj->p_memory = p_memory;
119     p_obj->capacity = capacity;
120 
121     nrf_802154_buffer_t * p_buffer = (nrf_802154_buffer_t *)p_obj->p_memory;
122 
123     for (size_t i = 0; i < p_obj->capacity; i++)
124     {
125         p_buffer[i].taken = false;
126     }
127 }
128 
nrf_802154_buffer_allocator_alloc(const nrf_802154_buffer_allocator_t * p_obj)129 void * nrf_802154_buffer_allocator_alloc(const nrf_802154_buffer_allocator_t * p_obj)
130 {
131     return buffer_alloc((nrf_802154_buffer_t *)p_obj->p_memory, p_obj->capacity);
132 }
133 
nrf_802154_buffer_allocator_free(const nrf_802154_buffer_allocator_t * p_obj,void * p_buffer)134 void nrf_802154_buffer_allocator_free(const nrf_802154_buffer_allocator_t * p_obj,
135                                       void                                * p_buffer)
136 {
137     buffer_free(p_buffer, (nrf_802154_buffer_t *)p_obj->p_memory, p_obj->capacity);
138 }
139