1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2022-2023, Ventana Micro Systems Inc
4 * Author: Sunil V L <sunilvl@ventanamicro.com>
8 #define pr_fmt(fmt) "ACPI: RHCT: " fmt
10 #include <linux/acpi.h>
11 #include <linux/bits.h>
13 static struct acpi_table_rhct
*acpi_get_rhct(void)
15 static struct acpi_table_header
*rhct
;
19 * RHCT will be used at runtime on every CPU, so we
20 * don't need to call acpi_put_table() to release the table mapping.
23 status
= acpi_get_table(ACPI_SIG_RHCT
, 0, &rhct
);
24 if (ACPI_FAILURE(status
)) {
25 pr_warn_once("No RHCT table found\n");
30 return (struct acpi_table_rhct
*)rhct
;
34 * During early boot, the caller should call acpi_get_table() and pass its pointer to
35 * these functions(and free up later). At run time, since this table can be used
36 * multiple times, NULL may be passed in order to use the cached table.
38 int acpi_get_riscv_isa(struct acpi_table_header
*table
, unsigned int cpu
, const char **isa
)
40 struct acpi_rhct_node_header
*node
, *ref_node
, *end
;
41 u32 size_hdr
= sizeof(struct acpi_rhct_node_header
);
42 u32 size_hartinfo
= sizeof(struct acpi_rhct_hart_info
);
43 struct acpi_rhct_hart_info
*hart_info
;
44 struct acpi_rhct_isa_string
*isa_node
;
45 struct acpi_table_rhct
*rhct
;
46 u32
*hart_info_node_offset
;
47 u32 acpi_cpu_id
= get_acpi_id_for_cpu(cpu
);
49 BUG_ON(acpi_disabled
);
52 rhct
= acpi_get_rhct();
56 rhct
= (struct acpi_table_rhct
*)table
;
59 end
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, rhct
, rhct
->header
.length
);
61 for (node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, rhct
, rhct
->node_offset
);
63 node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, node
, node
->length
)) {
64 if (node
->type
== ACPI_RHCT_NODE_TYPE_HART_INFO
) {
65 hart_info
= ACPI_ADD_PTR(struct acpi_rhct_hart_info
, node
, size_hdr
);
66 hart_info_node_offset
= ACPI_ADD_PTR(u32
, hart_info
, size_hartinfo
);
67 if (acpi_cpu_id
!= hart_info
->uid
)
70 for (int i
= 0; i
< hart_info
->num_offsets
; i
++) {
71 ref_node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
,
72 rhct
, hart_info_node_offset
[i
]);
73 if (ref_node
->type
== ACPI_RHCT_NODE_TYPE_ISA_STRING
) {
74 isa_node
= ACPI_ADD_PTR(struct acpi_rhct_isa_string
,
86 static void acpi_parse_hart_info_cmo_node(struct acpi_table_rhct
*rhct
,
87 struct acpi_rhct_hart_info
*hart_info
,
88 u32
*cbom_size
, u32
*cboz_size
, u32
*cbop_size
)
90 u32 size_hartinfo
= sizeof(struct acpi_rhct_hart_info
);
91 u32 size_hdr
= sizeof(struct acpi_rhct_node_header
);
92 struct acpi_rhct_node_header
*ref_node
;
93 struct acpi_rhct_cmo_node
*cmo_node
;
94 u32
*hart_info_node_offset
;
96 hart_info_node_offset
= ACPI_ADD_PTR(u32
, hart_info
, size_hartinfo
);
97 for (int i
= 0; i
< hart_info
->num_offsets
; i
++) {
98 ref_node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
,
99 rhct
, hart_info_node_offset
[i
]);
100 if (ref_node
->type
== ACPI_RHCT_NODE_TYPE_CMO
) {
101 cmo_node
= ACPI_ADD_PTR(struct acpi_rhct_cmo_node
,
103 if (cbom_size
&& cmo_node
->cbom_size
<= 30) {
105 *cbom_size
= BIT(cmo_node
->cbom_size
);
106 else if (*cbom_size
!= BIT(cmo_node
->cbom_size
))
107 pr_warn("CBOM size is not the same across harts\n");
110 if (cboz_size
&& cmo_node
->cboz_size
<= 30) {
112 *cboz_size
= BIT(cmo_node
->cboz_size
);
113 else if (*cboz_size
!= BIT(cmo_node
->cboz_size
))
114 pr_warn("CBOZ size is not the same across harts\n");
117 if (cbop_size
&& cmo_node
->cbop_size
<= 30) {
119 *cbop_size
= BIT(cmo_node
->cbop_size
);
120 else if (*cbop_size
!= BIT(cmo_node
->cbop_size
))
121 pr_warn("CBOP size is not the same across harts\n");
128 * During early boot, the caller should call acpi_get_table() and pass its pointer to
129 * these functions (and free up later). At run time, since this table can be used
130 * multiple times, pass NULL so that the table remains in memory.
132 void acpi_get_cbo_block_size(struct acpi_table_header
*table
, u32
*cbom_size
,
133 u32
*cboz_size
, u32
*cbop_size
)
135 u32 size_hdr
= sizeof(struct acpi_rhct_node_header
);
136 struct acpi_rhct_node_header
*node
, *end
;
137 struct acpi_rhct_hart_info
*hart_info
;
138 struct acpi_table_rhct
*rhct
;
144 rhct
= (struct acpi_table_rhct
*)table
;
146 rhct
= acpi_get_rhct();
160 end
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, rhct
, rhct
->header
.length
);
161 for (node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, rhct
, rhct
->node_offset
);
163 node
= ACPI_ADD_PTR(struct acpi_rhct_node_header
, node
, node
->length
)) {
164 if (node
->type
== ACPI_RHCT_NODE_TYPE_HART_INFO
) {
165 hart_info
= ACPI_ADD_PTR(struct acpi_rhct_hart_info
, node
, size_hdr
);
166 acpi_parse_hart_info_cmo_node(rhct
, hart_info
, cbom_size
,
167 cboz_size
, cbop_size
);