Unverified Commit 0e6a6ad6 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!1071 [sync] PR-1069: support ACPI for MPAM 2.0

Merge Pull Request from: @openeuler-sync-bot 
 

Origin pull request: 
https://gitee.com/openeuler/kernel/pulls/1069 
 
PR sync from:  Yu Liao <liaoyu15@huawei.com>
 https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/thread/CQNKMRKUYC4EDBYHOMD6CXZQPZEJBMFY/ 
This patch series support ACPI for MPAM 2.0.

v5: fix unused variable warning.

v4: add PPTT null check to prevent NULL pointer deference.


Erik Kaneda (1):
  ACPICA: ACPI 6.4: PPTT: add new version of subtable type 1

Hesham Almatary (1):
  ACPICA: Add support for Arm's MPAM ACPI table version 2

Yu Liao (2):
  ACPI / PPTT: Find PPTT processor node by cache id
  ACPI/MPAM: Adapt to Arm's MPAM ACPI table version 2


-- 
2.25.1
 
 
Link:https://gitee.com/openeuler/kernel/pulls/1071

 

Reviewed-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents a61f7e3c f4e900a6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1865,7 +1865,7 @@ static int __init arm_mpam_driver_init(void)
	if (acpi_disabled)
		return platform_driver_register(&arm_mpam_driver);
	else
		return acpi_mpam_parse();
		return acpi_mpam_parse_version();
}

/*
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ACPI_IORT) 	+= iort.o
obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
obj-$(CONFIG_ACPI_MPAM) 	+= mpam.o
obj-$(CONFIG_ACPI_MPAM) 	+= mpam.o mpam_v2.o
+18 −5
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
#include <linux/nodemask.h>
#include <linux/arm_mpam.h>

extern int __init acpi_mpam_parse_table_v2(struct acpi_table_header *table,
					struct acpi_table_header *pptt);
/**
 * acpi_mpam_label_cache_component_id() - Recursivly find @min_physid
 * for all leaf CPUs below @cpu_node, use numa node id of @min_cpu_node
@@ -40,7 +42,7 @@
 * @cpu_node:  The point in the toplogy to start the walk
 * @component_id: The id labels the structure mpam_node cache
 */
static int
int
acpi_mpam_label_cache_component_id(struct acpi_table_header *table_hdr,
					struct acpi_pptt_processor *cpu_node,
					u32 *component_id)
@@ -187,10 +189,10 @@ static int __init acpi_mpam_parse_table(struct acpi_table_header *table,
			pr_warn_once("Unknown node type %u offset %ld.",
					node_hdr->type,
					(table_offset-(char *)table));
			/* fall through */
			fallthrough;
		case ACPI_MPAM_TYPE_SMMU:
			/* not yet supported */
			/* fall through */
			fallthrough;
		case ACPI_MPAM_TYPE_UNKNOWN:
			break;
		}
@@ -213,7 +215,7 @@ static int __init acpi_mpam_parse_table(struct acpi_table_header *table,
	return ret;
}

int __init acpi_mpam_parse(void)
int __init acpi_mpam_parse_version(void)
{
	struct acpi_table_header *mpam, *pptt;
	acpi_status status;
@@ -234,7 +236,18 @@ int __init acpi_mpam_parse(void)
	if (ACPI_FAILURE(status))
		pptt = NULL;

	/*
	 * The BIOS of Kunpeng 920 supports MPAM ACPI 1.0, but the ACPI
	 * revision is wrongly written as 1, so distinguished by
	 * oem_table_id here.
	 */
	if (mpam->revision == 0 || strncmp(mpam->oem_table_id, "HIP08", 5) == 0)
		ret = acpi_mpam_parse_table(mpam, pptt);
	else if (mpam->revision == 1)
		ret = acpi_mpam_parse_table_v2(mpam, pptt);
	else
		pr_err("unsupported MPAM ACPI version: %u\n", mpam->revision);

	acpi_put_table(pptt);
	acpi_put_table(mpam);

+175 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
/*
 * Common code for ARM v8 MPAM ACPI 2.0
 *
 * Copyright (C) 2019-2022 Huawei Technologies Co., Ltd
 *
 * Author: Yu Liao <liaoyu15@huawei.com>
 *
 * Code was partially borrowed from http://www.linux-arm.org/git?p=
 * linux-jm.git;a=commit;h=10fe7d6363ae96b25f584d4a91f9d0f2fd5faf3b.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

/* Parse the MPAM ACPI table feeding the discovered nodes into the driver */
#define pr_fmt(fmt) "ACPI MPAM: " fmt

#include <linux/acpi.h>
#include <acpi/processor.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/cacheinfo.h>
#include <linux/string.h>
#include <linux/nodemask.h>
#include <linux/arm_mpam.h>

extern int
acpi_mpam_label_cache_component_id(struct acpi_table_header *table_hdr,
					struct acpi_pptt_processor *cpu_node,
					u32 *component_id);

static int __init acpi_mpam_parse_cache_v2(struct acpi_mpam_msc_node *msc,
						struct acpi_table_header *pptt)
{
	int ret = 0;
	int level;
	u32 component_id;
	struct mpam_device *dev;
	struct cacheinfo *ci;
	struct acpi_pptt_processor *pptt_cpu_node;
	struct acpi_mpam_resource_node *resources;

	resources = (struct acpi_mpam_resource_node *)(msc + 1);

	pptt_cpu_node = find_acpi_processor_node_from_cache_id(resources->locator.cache_locator.cache_reference);
	if (!pptt_cpu_node) {
		pr_err("Failed to find processor cpu node\n");
		return -EINVAL;
	}

	ret = acpi_mpam_label_cache_component_id(pptt, pptt_cpu_node,
					&component_id);
	if (ret) {
		pr_err("Failed to label cache component id\n");
		return -EINVAL;
	}

	cpus_read_lock();
	ci = cacheinfo_shared_cpu_map_search(pptt_cpu_node);
	if (!ci) {
		pr_err_once("No CPU has cache with PPTT reference %#llx",
				resources->locator.cache_locator.cache_reference);
		pr_err_once("All CPUs must be online to probe mpam.\n");
		cpus_read_unlock();
		return -ENODEV;
	}

	level = ci->level;
	ci = NULL;
	cpus_read_unlock();

	/*
	 * Possible we can get cpu-affinity in next MPAM ACPI version,
	 * now we have to set it to NULL and use default possible_aff-
	 * inity.
	 */
	dev = mpam_device_create_cache(level, component_id, NULL,
				msc->base_address);
	if (IS_ERR(dev)) {
		pr_err("Failed to create cache node\n");
		return -EINVAL;
	}

	return mpam_register_device_irq(dev,
		msc->overflow_interrupt, msc->overflow_interrupt_flags,
		msc->error_interrupt, msc->error_interrupt_flags);
}

static int __init acpi_mpam_parse_memory_v2(struct acpi_mpam_msc_node *msc)
{
	u32 component_id;
	struct mpam_device *dev;
	struct acpi_mpam_resource_node *resources;

	resources = (struct acpi_mpam_resource_node *)(msc + 1);

	component_id = acpi_map_pxm_to_node(resources->locator.memory_locator.proximity_domain);
	if (component_id == NUMA_NO_NODE)
		component_id = 0;

	dev = mpam_device_create_memory(component_id, msc->base_address);
	if (IS_ERR(dev)) {
		pr_err("Failed to create memory node\n");
		return -EINVAL;
	}

	return mpam_register_device_irq(dev,
		msc->overflow_interrupt, msc->overflow_interrupt_flags,
		msc->error_interrupt, msc->error_interrupt_flags);
}

int __init acpi_mpam_parse_table_v2(struct acpi_table_header *table,
					struct acpi_table_header *pptt)
{
	char *table_offset = (char *)(table + 1);
	char *table_end = (char *)table + table->length;
	struct acpi_mpam_msc_node *node_hdr;
	struct acpi_mpam_resource_node *resources;
	int ret = 0;

	ret = mpam_discovery_start();

	if (ret)
		return ret;

	node_hdr = (struct acpi_mpam_msc_node *)table_offset;
	resources = (struct acpi_mpam_resource_node *)(node_hdr + 1);

	while (table_offset < table_end) {
		switch (resources->locator_type) {

		case ACPI_MPAM_LOCATION_TYPE_PROCESSOR_CACHE:
			ret = acpi_mpam_parse_cache_v2(node_hdr, pptt);
			break;
		case ACPI_MPAM_LOCATION_TYPE_MEMORY:
			ret = acpi_mpam_parse_memory_v2(node_hdr);
			break;
		default:
			pr_warn_once("Unknown node type %u offset %ld.",
					(resources->locator_type),
					(table_offset-(char *)table));
			fallthrough;
		case ACPI_MPAM_LOCATION_TYPE_SMMU:
			/* not yet supported */
			fallthrough;
		case ACPI_MPAM_TYPE_UNKNOWN:
			break;
		}
		if (ret)
			break;

		table_offset += node_hdr->length;
		node_hdr = (struct acpi_mpam_msc_node *)table_offset;
		resources = (struct acpi_mpam_resource_node *)(node_hdr + 1);
	}

	if (ret) {
		pr_err("discovery failed: %d\n", ret);
		mpam_discovery_failed();
	} else {
		ret = mpam_discovery_complete();
		if (!ret)
			pr_info("Successfully init mpam by ACPI.\n");
	}

	return ret;
}
+55 −0
Original line number Diff line number Diff line
@@ -958,3 +958,58 @@ int __init acpi_pptt_init(void)

	return 0;
}

struct acpi_pptt_processor *find_acpi_processor_node_from_cache_id(u32 cache_id)
{
	u32 acpi_cpu_id;
	acpi_status status;
	int level, cpu, num_levels;
	struct acpi_pptt_cache *cache;
	struct acpi_table_header *table;
	struct acpi_pptt_cache_v1 *cache_v1;
	struct acpi_pptt_processor *cpu_node;

	status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
	if (ACPI_FAILURE(status)) {
		acpi_pptt_warn_missing();
		return NULL;
	}

	if (table->revision < 3) {
		acpi_put_table(table);
		return NULL;
	}

	/*
	 * If we found the cache first, we'd still need to walk from each CPU
	 * to find the level...
	 */
	for_each_possible_cpu(cpu) {
		acpi_cpu_id = get_acpi_id_for_cpu(cpu);
		cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
		if (!cpu_node)
			break;
		num_levels = acpi_count_levels(table, cpu_node);

		for (level = 0; level <= num_levels; level++) {
			cache = acpi_find_cache_node(table, acpi_cpu_id,
						     ACPI_PPTT_CACHE_TYPE_UNIFIED,
						     level, &cpu_node);
			if (!cache)
				continue;

			cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1,
						cache,
						sizeof(struct acpi_pptt_cache));

			if (cache->flags & ACPI_PPTT_CACHE_ID_VALID &&
			    cache_v1->cache_id == cache_id) {
				acpi_put_table(table);
				return cpu_node;
			}
		}
	}

	acpi_put_table(table);
	return NULL;
}
Loading