xref: /openbmc/linux/drivers/acpi/riscv/rhct.c (revision e6b9d8ed)
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