1*e6b9d8edSSunil V L // SPDX-License-Identifier: GPL-2.0-only
2*e6b9d8edSSunil V L /*
3*e6b9d8edSSunil V L * Copyright (C) 2022-2023, Ventana Micro Systems Inc
4*e6b9d8edSSunil V L * Author: Sunil V L <sunilvl@ventanamicro.com>
5*e6b9d8edSSunil V L *
6*e6b9d8edSSunil V L */
7*e6b9d8edSSunil V L
8*e6b9d8edSSunil V L #define pr_fmt(fmt) "ACPI: RHCT: " fmt
9*e6b9d8edSSunil V L
10*e6b9d8edSSunil V L #include <linux/acpi.h>
11*e6b9d8edSSunil V L
acpi_get_rhct(void)12*e6b9d8edSSunil V L static struct acpi_table_header *acpi_get_rhct(void)
13*e6b9d8edSSunil V L {
14*e6b9d8edSSunil V L static struct acpi_table_header *rhct;
15*e6b9d8edSSunil V L acpi_status status;
16*e6b9d8edSSunil V L
17*e6b9d8edSSunil V L /*
18*e6b9d8edSSunil V L * RHCT will be used at runtime on every CPU, so we
19*e6b9d8edSSunil V L * don't need to call acpi_put_table() to release the table mapping.
20*e6b9d8edSSunil V L */
21*e6b9d8edSSunil V L if (!rhct) {
22*e6b9d8edSSunil V L status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
23*e6b9d8edSSunil V L if (ACPI_FAILURE(status)) {
24*e6b9d8edSSunil V L pr_warn_once("No RHCT table found\n");
25*e6b9d8edSSunil V L return NULL;
26*e6b9d8edSSunil V L }
27*e6b9d8edSSunil V L }
28*e6b9d8edSSunil V L
29*e6b9d8edSSunil V L return rhct;
30*e6b9d8edSSunil V L }
31*e6b9d8edSSunil V L
32*e6b9d8edSSunil V L /*
33*e6b9d8edSSunil V L * During early boot, the caller should call acpi_get_table() and pass its pointer to
34*e6b9d8edSSunil V L * these functions(and free up later). At run time, since this table can be used
35*e6b9d8edSSunil V L * multiple times, NULL may be passed in order to use the cached table.
36*e6b9d8edSSunil V L */
acpi_get_riscv_isa(struct acpi_table_header * table,unsigned int cpu,const char ** isa)37*e6b9d8edSSunil V L int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const char **isa)
38*e6b9d8edSSunil V L {
39*e6b9d8edSSunil V L struct acpi_rhct_node_header *node, *ref_node, *end;
40*e6b9d8edSSunil V L u32 size_hdr = sizeof(struct acpi_rhct_node_header);
41*e6b9d8edSSunil V L u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info);
42*e6b9d8edSSunil V L struct acpi_rhct_hart_info *hart_info;
43*e6b9d8edSSunil V L struct acpi_rhct_isa_string *isa_node;
44*e6b9d8edSSunil V L struct acpi_table_rhct *rhct;
45*e6b9d8edSSunil V L u32 *hart_info_node_offset;
46*e6b9d8edSSunil V L u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
47*e6b9d8edSSunil V L
48*e6b9d8edSSunil V L BUG_ON(acpi_disabled);
49*e6b9d8edSSunil V L
50*e6b9d8edSSunil V L if (!table) {
51*e6b9d8edSSunil V L rhct = (struct acpi_table_rhct *)acpi_get_rhct();
52*e6b9d8edSSunil V L if (!rhct)
53*e6b9d8edSSunil V L return -ENOENT;
54*e6b9d8edSSunil V L } else {
55*e6b9d8edSSunil V L rhct = (struct acpi_table_rhct *)table;
56*e6b9d8edSSunil V L }
57*e6b9d8edSSunil V L
58*e6b9d8edSSunil V L end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length);
59*e6b9d8edSSunil V L
60*e6b9d8edSSunil V L for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset);
61*e6b9d8edSSunil V L node < end;
62*e6b9d8edSSunil V L node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) {
63*e6b9d8edSSunil V L if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) {
64*e6b9d8edSSunil V L hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr);
65*e6b9d8edSSunil V L hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo);
66*e6b9d8edSSunil V L if (acpi_cpu_id != hart_info->uid)
67*e6b9d8edSSunil V L continue;
68*e6b9d8edSSunil V L
69*e6b9d8edSSunil V L for (int i = 0; i < hart_info->num_offsets; i++) {
70*e6b9d8edSSunil V L ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header,
71*e6b9d8edSSunil V L rhct, hart_info_node_offset[i]);
72*e6b9d8edSSunil V L if (ref_node->type == ACPI_RHCT_NODE_TYPE_ISA_STRING) {
73*e6b9d8edSSunil V L isa_node = ACPI_ADD_PTR(struct acpi_rhct_isa_string,
74*e6b9d8edSSunil V L ref_node, size_hdr);
75*e6b9d8edSSunil V L *isa = isa_node->isa;
76*e6b9d8edSSunil V L return 0;
77*e6b9d8edSSunil V L }
78*e6b9d8edSSunil V L }
79*e6b9d8edSSunil V L }
80*e6b9d8edSSunil V L }
81*e6b9d8edSSunil V L
82*e6b9d8edSSunil V L return -1;
83*e6b9d8edSSunil V L }
84