xref: /kernel/linux/linux-6.6/drivers/acpi/riscv/rhct.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2022-2023, Ventana Micro Systems Inc
462306a36Sopenharmony_ci *	Author: Sunil V L <sunilvl@ventanamicro.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt)     "ACPI: RHCT: " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/acpi.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic struct acpi_table_header *acpi_get_rhct(void)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	static struct acpi_table_header *rhct;
1562306a36Sopenharmony_ci	acpi_status status;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	/*
1862306a36Sopenharmony_ci	 * RHCT will be used at runtime on every CPU, so we
1962306a36Sopenharmony_ci	 * don't need to call acpi_put_table() to release the table mapping.
2062306a36Sopenharmony_ci	 */
2162306a36Sopenharmony_ci	if (!rhct) {
2262306a36Sopenharmony_ci		status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
2362306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
2462306a36Sopenharmony_ci			pr_warn_once("No RHCT table found\n");
2562306a36Sopenharmony_ci			return NULL;
2662306a36Sopenharmony_ci		}
2762306a36Sopenharmony_ci	}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	return rhct;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * During early boot, the caller should call acpi_get_table() and pass its pointer to
3462306a36Sopenharmony_ci * these functions(and free up later). At run time, since this table can be used
3562306a36Sopenharmony_ci * multiple times, NULL may be passed in order to use the cached table.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ciint acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const char **isa)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct acpi_rhct_node_header *node, *ref_node, *end;
4062306a36Sopenharmony_ci	u32 size_hdr = sizeof(struct acpi_rhct_node_header);
4162306a36Sopenharmony_ci	u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info);
4262306a36Sopenharmony_ci	struct acpi_rhct_hart_info *hart_info;
4362306a36Sopenharmony_ci	struct acpi_rhct_isa_string *isa_node;
4462306a36Sopenharmony_ci	struct acpi_table_rhct *rhct;
4562306a36Sopenharmony_ci	u32 *hart_info_node_offset;
4662306a36Sopenharmony_ci	u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	BUG_ON(acpi_disabled);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!table) {
5162306a36Sopenharmony_ci		rhct = (struct acpi_table_rhct *)acpi_get_rhct();
5262306a36Sopenharmony_ci		if (!rhct)
5362306a36Sopenharmony_ci			return -ENOENT;
5462306a36Sopenharmony_ci	} else {
5562306a36Sopenharmony_ci		rhct = (struct acpi_table_rhct *)table;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset);
6162306a36Sopenharmony_ci	     node < end;
6262306a36Sopenharmony_ci	     node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) {
6362306a36Sopenharmony_ci		if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) {
6462306a36Sopenharmony_ci			hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr);
6562306a36Sopenharmony_ci			hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo);
6662306a36Sopenharmony_ci			if (acpi_cpu_id != hart_info->uid)
6762306a36Sopenharmony_ci				continue;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci			for (int i = 0; i < hart_info->num_offsets; i++) {
7062306a36Sopenharmony_ci				ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header,
7162306a36Sopenharmony_ci							rhct, hart_info_node_offset[i]);
7262306a36Sopenharmony_ci				if (ref_node->type == ACPI_RHCT_NODE_TYPE_ISA_STRING) {
7362306a36Sopenharmony_ci					isa_node = ACPI_ADD_PTR(struct acpi_rhct_isa_string,
7462306a36Sopenharmony_ci								ref_node, size_hdr);
7562306a36Sopenharmony_ci					*isa = isa_node->isa;
7662306a36Sopenharmony_ci					return 0;
7762306a36Sopenharmony_ci				}
7862306a36Sopenharmony_ci			}
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return -1;
8362306a36Sopenharmony_ci}
84