171 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2022-2023, Ventana Micro Systems Inc4 * Author: Sunil V L <sunilvl@ventanamicro.com>5 *6 */7 8#define pr_fmt(fmt) "ACPI: RHCT: " fmt9 10#include <linux/acpi.h>11#include <linux/bits.h>12 13static struct acpi_table_rhct *acpi_get_rhct(void)14{15 static struct acpi_table_header *rhct;16 acpi_status status;17 18 /*19 * RHCT will be used at runtime on every CPU, so we20 * don't need to call acpi_put_table() to release the table mapping.21 */22 if (!rhct) {23 status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);24 if (ACPI_FAILURE(status)) {25 pr_warn_once("No RHCT table found\n");26 return NULL;27 }28 }29 30 return (struct acpi_table_rhct *)rhct;31}32 33/*34 * During early boot, the caller should call acpi_get_table() and pass its pointer to35 * these functions(and free up later). At run time, since this table can be used36 * multiple times, NULL may be passed in order to use the cached table.37 */38int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const char **isa)39{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);48 49 BUG_ON(acpi_disabled);50 51 if (!table) {52 rhct = acpi_get_rhct();53 if (!rhct)54 return -ENOENT;55 } else {56 rhct = (struct acpi_table_rhct *)table;57 }58 59 end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length);60 61 for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset);62 node < end;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)68 continue;69 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,75 ref_node, size_hdr);76 *isa = isa_node->isa;77 return 0;78 }79 }80 }81 }82 83 return -1;84}85 86static 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)89{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;95 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,102 ref_node, size_hdr);103 if (cbom_size && cmo_node->cbom_size <= 30) {104 if (!*cbom_size)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");108 }109 110 if (cboz_size && cmo_node->cboz_size <= 30) {111 if (!*cboz_size)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");115 }116 117 if (cbop_size && cmo_node->cbop_size <= 30) {118 if (!*cbop_size)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");122 }123 }124 }125}126 127/*128 * During early boot, the caller should call acpi_get_table() and pass its pointer to129 * these functions (and free up later). At run time, since this table can be used130 * multiple times, pass NULL so that the table remains in memory.131 */132void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,133 u32 *cboz_size, u32 *cbop_size)134{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;139 140 if (acpi_disabled)141 return;142 143 if (table) {144 rhct = (struct acpi_table_rhct *)table;145 } else {146 rhct = acpi_get_rhct();147 if (!rhct)148 return;149 }150 151 if (cbom_size)152 *cbom_size = 0;153 154 if (cboz_size)155 *cboz_size = 0;156 157 if (cbop_size)158 *cbop_size = 0;159 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);162 node < end;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);168 }169 }170}171