|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | +/* |
| 3 | + * Copyright (C) 2022-2023, Ventana Micro Systems Inc |
| 4 | + * Author: Sunil V L <[email protected]> |
| 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 | +} |
0 commit comments