brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · caa2c16 Raw
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