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