1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-09-24 GuEe-GUI the first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #define DBG_TAG "rtdm.numa"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 #include <drivers/pic.h>
19
20 struct numa_memory
21 {
22 rt_list_t list;
23
24 int nid;
25 rt_uint64_t start;
26 rt_uint64_t end;
27
28 union
29 {
30 void *ofw_node;
31 };
32 };
33
34 static rt_bool_t numa_enabled = RT_FALSE;
35 static int cpu_numa_map[RT_CPUS_NR] rt_section(".bss.noclean.numa");
36 static rt_list_t numa_memory_nodes rt_section(".bss.noclean.numa");
37
rt_numa_cpu_id(int cpuid)38 int rt_numa_cpu_id(int cpuid)
39 {
40 if (!numa_enabled)
41 {
42 return -RT_ENOSYS;
43 }
44
45 return cpuid < RT_ARRAY_SIZE(cpu_numa_map) ? cpu_numa_map[cpuid] : -RT_EINVAL;
46 }
47
rt_numa_device_id(struct rt_device * dev)48 int rt_numa_device_id(struct rt_device *dev)
49 {
50 rt_uint32_t nid = (rt_uint32_t)-RT_ENOSYS;
51
52 if (!numa_enabled)
53 {
54 return nid;
55 }
56
57 return rt_dm_dev_prop_read_u32(dev, "numa-node-id", &nid) ? : (int)nid;
58 }
59
rt_numa_memory_affinity(rt_uint64_t phy_addr,rt_bitmap_t * out_affinity)60 rt_err_t rt_numa_memory_affinity(rt_uint64_t phy_addr, rt_bitmap_t *out_affinity)
61 {
62 struct numa_memory *nm;
63
64 if (!out_affinity)
65 {
66 return -RT_EINVAL;
67 }
68
69 if (!numa_enabled)
70 {
71 /* Default to CPU#0 */
72 RT_IRQ_AFFINITY_SET(out_affinity, 0);
73
74 return RT_EOK;
75 }
76
77 rt_memset(out_affinity, 0, sizeof(*out_affinity) * RT_BITMAP_LEN(RT_CPUS_NR));
78
79 rt_list_for_each_entry(nm, &numa_memory_nodes, list)
80 {
81 if (phy_addr >= nm->start && phy_addr < nm->end)
82 {
83 for (int i = 0; i < RT_ARRAY_SIZE(cpu_numa_map); ++i)
84 {
85 if (cpu_numa_map[i] == nm->nid)
86 {
87 RT_IRQ_AFFINITY_SET(out_affinity, i);
88 }
89 }
90
91 return RT_EOK;
92 }
93 }
94
95 return -RT_EEMPTY;
96 }
97
98 #ifdef RT_USING_OFW
numa_ofw_init(void)99 static int numa_ofw_init(void)
100 {
101 int i = 0;
102 rt_uint32_t nid;
103 const char *numa_conf;
104 struct rt_ofw_node *np = RT_NULL;
105
106 numa_conf = rt_ofw_bootargs_select("numa=", 0);
107
108 if (!numa_conf || rt_strcmp(numa_conf, "on"))
109 {
110 return (int)RT_EOK;
111 }
112
113 numa_enabled = RT_TRUE;
114
115 for (int i = 0; i < RT_ARRAY_SIZE(cpu_numa_map); ++i)
116 {
117 cpu_numa_map[i] = -RT_ENOSYS;
118 }
119
120 rt_list_init(&numa_memory_nodes);
121
122 rt_ofw_foreach_cpu_node(np)
123 {
124 rt_ofw_prop_read_u32(np, "numa-node-id", (rt_uint32_t *)&cpu_numa_map[i]);
125
126 if (++i >= RT_CPUS_NR)
127 {
128 break;
129 }
130 }
131
132 rt_ofw_foreach_node_by_type(np, "memory")
133 {
134 if (!rt_ofw_prop_read_u32(np, "numa-node-id", &nid))
135 {
136 int mem_nr = rt_ofw_get_address_count(np);
137
138 for (i = 0; i < mem_nr; ++i)
139 {
140 rt_uint64_t addr, size;
141 struct numa_memory *nm;
142
143 if (rt_ofw_get_address(np, i, &addr, &size))
144 {
145 continue;
146 }
147
148 nm = rt_malloc(sizeof(*nm));
149
150 if (!nm)
151 {
152 LOG_E("No memory to record NUMA[%d] memory[%p, %p] info",
153 nid, addr, addr + size);
154
155 return (int)-RT_ENOMEM;
156 }
157
158 nm->start = addr;
159 nm->end = addr + size;
160 nm->ofw_node = np;
161
162 rt_list_init(&nm->list);
163 rt_list_insert_before(&numa_memory_nodes, &nm->list);
164 }
165 }
166 }
167
168 return 0;
169 }
170 INIT_CORE_EXPORT(numa_ofw_init);
171 #endif /* RT_USING_OFW */
172