1 /*
2 * Copyright (c) 2021 Carlo Caione, <ccaione@baylibre.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/sys/sys_heap.h>
10 #include <zephyr/mem_mgmt/mem_attr.h>
11 #include <zephyr/sys/multi_heap.h>
12 #include <zephyr/dt-bindings/memory-attr/memory-attr.h>
13 #include <zephyr/dt-bindings/memory-attr/memory-attr-sw.h>
14
15 struct ma_heap {
16 struct sys_heap heap;
17 uint32_t attr;
18 };
19
20 struct {
21 struct ma_heap ma_heaps[MAX_MULTI_HEAPS];
22 struct sys_multi_heap multi_heap;
23 int nheaps;
24 } mah_data;
25
mah_choice(struct sys_multi_heap * m_heap,void * cfg,size_t align,size_t size)26 static void *mah_choice(struct sys_multi_heap *m_heap, void *cfg, size_t align, size_t size)
27 {
28 uint32_t attr;
29 void *block;
30
31 if (size == 0) {
32 return NULL;
33 }
34
35 attr = (uint32_t)(long) cfg;
36
37 /* Set in case the user requested a non-existing attr */
38 block = NULL;
39
40 for (size_t hdx = 0; hdx < mah_data.nheaps; hdx++) {
41 struct ma_heap *h;
42
43 h = &mah_data.ma_heaps[hdx];
44
45 if (h->attr != attr) {
46 continue;
47 }
48
49 block = sys_heap_aligned_alloc(&h->heap, align, size);
50 if (block != NULL) {
51 break;
52 }
53 }
54
55 return block;
56 }
57
mem_attr_heap_free(void * block)58 void mem_attr_heap_free(void *block)
59 {
60 sys_multi_heap_free(&mah_data.multi_heap, block);
61 }
62
mem_attr_heap_alloc(uint32_t attr,size_t bytes)63 void *mem_attr_heap_alloc(uint32_t attr, size_t bytes)
64 {
65 return sys_multi_heap_alloc(&mah_data.multi_heap,
66 (void *)(long) attr, bytes);
67 }
68
mem_attr_heap_aligned_alloc(uint32_t attr,size_t align,size_t bytes)69 void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes)
70 {
71 return sys_multi_heap_aligned_alloc(&mah_data.multi_heap,
72 (void *)(long) attr, align, bytes);
73 }
74
mem_attr_heap_get_region(void * addr)75 const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr)
76 {
77 const struct sys_multi_heap_rec *heap_rec;
78
79 heap_rec = sys_multi_heap_get_heap(&mah_data.multi_heap, addr);
80
81 return (const struct mem_attr_region_t *) heap_rec->user_data;
82 }
83
ma_heap_add(const struct mem_attr_region_t * region,uint32_t attr)84 static int ma_heap_add(const struct mem_attr_region_t *region, uint32_t attr)
85 {
86 struct ma_heap *mh;
87 struct sys_heap *h;
88
89 /* No more heaps available */
90 if (mah_data.nheaps >= MAX_MULTI_HEAPS) {
91 return -ENOMEM;
92 }
93
94 mh = &mah_data.ma_heaps[mah_data.nheaps++];
95 h = &mh->heap;
96
97 mh->attr = attr;
98
99 sys_heap_init(h, (void *) region->dt_addr, region->dt_size);
100 sys_multi_heap_add_heap(&mah_data.multi_heap, h, (void *) region);
101
102 return 0;
103 }
104
105
mem_attr_heap_pool_init(void)106 int mem_attr_heap_pool_init(void)
107 {
108 const struct mem_attr_region_t *regions;
109 static atomic_t state;
110 size_t num_regions;
111
112 if (!atomic_cas(&state, 0, 1)) {
113 return -EALREADY;
114 }
115
116 sys_multi_heap_init(&mah_data.multi_heap, mah_choice);
117
118 num_regions = mem_attr_get_regions(®ions);
119
120 for (size_t idx = 0; idx < num_regions; idx++) {
121 uint32_t sw_attr;
122
123 sw_attr = DT_MEM_SW_ATTR_GET(regions[idx].dt_attr);
124
125 /* No SW attribute is present */
126 if (!sw_attr) {
127 continue;
128 }
129
130 if (ma_heap_add(®ions[idx], sw_attr)) {
131 return -ENOMEM;
132 }
133 }
134
135 return 0;
136 }
137