Skip to content

Commit 64355e7

Browse files
committed
lib: utils/fdt: Cache CPU intc phandle->hartid lookups
CLINT/PLIC/PLMT/PLICSW probing walks `interrupts-extended` and for each entry resolves the CPU intc phandle to a hartid via `fdt_node_offset_by_phandle()` + `fdt_parent_offset()` + `fdt_parse_hart_id()`. Both libfdt helpers are O(FDT_size) linear scans of the structure block, so on an N-hart system each driver pays O(N * FDT_size), and the same handful of intc phandles is re-resolved across multiple drivers (PLIC + MSWI + MTIMER + ...). Build a small cache by walking `/cpus` once: for each cpu node, record its child intc node's phandle paired with the parsed hartid. Subsequent lookups become an O(harts) linear scan over the cache instead of two full FDT walks per entry. The cache is keyed on the FDT pointer so a new fdt invalidates it implicitly. Also move the hwirq filter ahead of the phandle resolution at each callsite so non-matching `interrupts-extended` entries skip the lookup entirely. Measured on 8-hart system (release build, mtime @ 25MHz, 1M ticks = 40 ms): sbi_irqchip_init: 15.08M -> 3.64M (~4.15x; 603 -> 146 ms) sbi_ipi_init: 14.75M -> 2.82M (~5.23x; 590 -> 113 ms) sbi_timer_init: 14.86M -> 2.94M (~5.06x; 594 -> 118 ms) combined: 44.69M -> 9.39M (~4.76x; 1788 -> 376 ms) Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
1 parent 1cdfbc6 commit 64355e7

3 files changed

Lines changed: 91 additions & 50 deletions

File tree

include/sbi_utils/fdt/fdt_helper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ bool fdt_node_is_enabled(const void *fdt, int nodeoff);
4848

4949
int fdt_parse_hart_id(const void *fdt, int cpu_offset, u32 *hartid);
5050

51+
int fdt_parse_hart_id_by_phandle(const void *fdt, u32 phandle, u32 *hartid);
52+
5153
int fdt_parse_max_enabled_hart_id(const void *fdt, u32 *max_hartid);
5254

5355
int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long *cbom_block_size);

lib/utils/fdt/fdt_helper.c

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,79 @@ int fdt_parse_hart_id(const void *fdt, int cpu_offset, u32 *hartid)
246246
return 0;
247247
}
248248

249+
struct fdt_cpu_intc_entry {
250+
u32 phandle;
251+
u32 hartid;
252+
};
253+
254+
static struct {
255+
const void *fdt;
256+
unsigned int n_entries;
257+
struct fdt_cpu_intc_entry entries[SBI_HARTMASK_MAX_BITS];
258+
} fdt_cpu_intc_cache;
259+
260+
static void fdt_cpu_intc_cache_build(const void *fdt)
261+
{
262+
int cpus_offset, cpu_offset, intc_offset, len;
263+
const fdt32_t *prop;
264+
unsigned int n = 0;
265+
u32 hartid;
266+
267+
if (!fdt || fdt_cpu_intc_cache.fdt == fdt)
268+
return;
269+
270+
fdt_cpu_intc_cache.fdt = NULL;
271+
fdt_cpu_intc_cache.n_entries = 0;
272+
273+
cpus_offset = fdt_path_offset(fdt, "/cpus");
274+
if (cpus_offset < 0)
275+
return;
276+
277+
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
278+
if (n >= SBI_HARTMASK_MAX_BITS)
279+
break;
280+
if (fdt_parse_hart_id(fdt, cpu_offset, &hartid))
281+
continue;
282+
283+
fdt_for_each_subnode(intc_offset, fdt, cpu_offset) {
284+
if (!fdt_getprop(fdt, intc_offset,
285+
"interrupt-controller", NULL))
286+
continue;
287+
prop = fdt_getprop(fdt, intc_offset, "phandle", &len);
288+
if (!prop || len < (int)sizeof(fdt32_t))
289+
continue;
290+
fdt_cpu_intc_cache.entries[n].phandle =
291+
fdt32_to_cpu(*prop);
292+
fdt_cpu_intc_cache.entries[n].hartid = hartid;
293+
n++;
294+
break;
295+
}
296+
}
297+
298+
fdt_cpu_intc_cache.fdt = fdt;
299+
fdt_cpu_intc_cache.n_entries = n;
300+
}
301+
302+
int fdt_parse_hart_id_by_phandle(const void *fdt, u32 phandle, u32 *hartid)
303+
{
304+
unsigned int i;
305+
306+
if (!fdt)
307+
return SBI_EINVAL;
308+
309+
fdt_cpu_intc_cache_build(fdt);
310+
311+
for (i = 0; i < fdt_cpu_intc_cache.n_entries; i++) {
312+
if (fdt_cpu_intc_cache.entries[i].phandle == phandle) {
313+
if (hartid)
314+
*hartid = fdt_cpu_intc_cache.entries[i].hartid;
315+
return 0;
316+
}
317+
}
318+
319+
return SBI_ENODEV;
320+
}
321+
249322
int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long *cbom_block_size)
250323
{
251324
int len;
@@ -968,7 +1041,7 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
9681041
u32 *out_first_hartid, u32 *out_hart_count)
9691042
{
9701043
const fdt32_t *val;
971-
int i, rc, count, cpu_offset, cpu_intc_offset;
1044+
int i, rc, count;
9721045
u32 phandle, hwirq, hartid, first_hartid, last_hartid;
9731046
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
9741047

@@ -1003,24 +1076,16 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
10031076
phandle = fdt32_to_cpu(val[2 * i]);
10041077
hwirq = fdt32_to_cpu(val[(2 * i) + 1]);
10051078

1006-
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
1007-
if (cpu_intc_offset < 0)
1079+
if (match_hwirq != hwirq)
10081080
continue;
10091081

1010-
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
1011-
if (cpu_offset < 0)
1082+
if (fdt_parse_hart_id_by_phandle(fdt, phandle, &hartid))
10121083
continue;
10131084

1014-
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
1015-
if (rc)
1016-
continue;
1017-
1018-
if (match_hwirq == hwirq) {
1019-
if (hartid < first_hartid)
1020-
first_hartid = hartid;
1021-
if (hartid > last_hartid)
1022-
last_hartid = hartid;
1023-
}
1085+
if (hartid < first_hartid)
1086+
first_hartid = hartid;
1087+
if (hartid > last_hartid)
1088+
last_hartid = hartid;
10241089
}
10251090

10261091
if ((last_hartid >= first_hartid) && first_hartid != -1U) {
@@ -1056,29 +1121,19 @@ int fdt_parse_plmt_node(const void *fdt, int nodeoffset, unsigned long *plmt_bas
10561121

10571122
hcount = 0;
10581123
for (i = 0; i < (count / 2); i++) {
1059-
int cpu_offset, cpu_intc_offset;
1060-
10611124
phandle = fdt32_to_cpu(val[2 * i]);
10621125
hwirq = fdt32_to_cpu(val[2 * i + 1]);
10631126

1064-
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
1065-
if (cpu_intc_offset < 0)
1127+
if (hwirq != IRQ_M_TIMER)
10661128
continue;
10671129

1068-
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
1069-
if (cpu_offset < 0)
1070-
continue;
1071-
1072-
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
1073-
1074-
if (rc)
1130+
if (fdt_parse_hart_id_by_phandle(fdt, phandle, &hartid))
10751131
continue;
10761132

10771133
if (SBI_HARTMASK_MAX_BITS <= sbi_hartid_to_hartindex(hartid))
10781134
continue;
10791135

1080-
if (hwirq == IRQ_M_TIMER)
1081-
hcount++;
1136+
hcount++;
10821137
}
10831138

10841139
*hart_count = hcount;
@@ -1112,29 +1167,19 @@ int fdt_parse_plicsw_node(const void *fdt, int nodeoffset, unsigned long *plicsw
11121167

11131168
hcount = 0;
11141169
for (i = 0; i < (count / 2); i++) {
1115-
int cpu_offset, cpu_intc_offset;
1116-
11171170
phandle = fdt32_to_cpu(val[2 * i]);
11181171
hwirq = fdt32_to_cpu(val[2 * i + 1]);
11191172

1120-
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
1121-
if (cpu_intc_offset < 0)
1122-
continue;
1123-
1124-
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
1125-
if (cpu_offset < 0)
1173+
if (hwirq != IRQ_M_SOFT)
11261174
continue;
11271175

1128-
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
1129-
1130-
if (rc)
1176+
if (fdt_parse_hart_id_by_phandle(fdt, phandle, &hartid))
11311177
continue;
11321178

11331179
if (SBI_HARTMASK_MAX_BITS <= sbi_hartid_to_hartindex(hartid))
11341180
continue;
11351181

1136-
if (hwirq == IRQ_M_SOFT)
1137-
hcount++;
1182+
hcount++;
11381183
}
11391184

11401185
*hart_count = hcount;

lib/utils/irqchip/fdt_irqchip_plic.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static int irqchip_plic_update_context_map(const void *fdt, int nodeoff,
2222
{
2323
const fdt32_t *val;
2424
u32 phandle, hwirq, hartid, hartindex;
25-
int i, err, count, cpu_offset, cpu_intc_offset;
25+
int i, count;
2626

2727
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
2828
if (!val || count < sizeof(fdt32_t))
@@ -33,16 +33,10 @@ static int irqchip_plic_update_context_map(const void *fdt, int nodeoff,
3333
phandle = fdt32_to_cpu(val[i]);
3434
hwirq = fdt32_to_cpu(val[i + 1]);
3535

36-
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
37-
if (cpu_intc_offset < 0)
36+
if (hwirq != IRQ_M_EXT && hwirq != IRQ_S_EXT)
3837
continue;
3938

40-
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
41-
if (cpu_offset < 0)
42-
continue;
43-
44-
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
45-
if (err)
39+
if (fdt_parse_hart_id_by_phandle(fdt, phandle, &hartid))
4640
continue;
4741

4842
hartindex = sbi_hartid_to_hartindex(hartid);

0 commit comments

Comments
 (0)