提交 d43a6c0c 编写于 作者: W Wang ShaoBo 提交者: Zheng Zengkai

MPAM / ACPI: Refactoring MPAM init process and set MPAM ACPI as entrance

hulk inclusion
category: feature
feature: ARM MPAM support
bugzilla: 48265
CVE: NA

--------------------------------

Renaming mpam_late_init() in arch/arm64/kernel/mpam.c to mpam_init(),
traveling each MPAM ACPI cache / memory node and adding them to a list,
with that, we use the numa node id it belongs to label cache node and
proximity_domain to label memory node, once it ends, call mpam_init()
to initialize all like before.

Code was partially borrowed from James's:
http://www.linux-arm.org/git?p=linux-jm.git;a=commit;h=10fe7d6363ae96b
25f584d4a91f9d0f2fd5faf3b,"ACPI / MPAM: Parse the (draft) MPAM table
[dead]"

v3->v5: mpam.c in drivers/acpi/arm64 should not be compiled when MPAM
disabled, so we should add CONFIG_ACPI_MPAM macro and make CONFIG_MPAM
select it. Not only that, as mpam init procedure is strong correlated to
ACPI for Now (follow-up might be dependent on device tree), and CONFIG_
ACPI is not always selected under configuration, we should make CONFIG_
MPAM depends on CONFIG_ACPI before selecting CONFIG_ACPI_MPAM.
Signed-off-by: NWang ShaoBo <bobo.shaobowang@huawei.com>
Reviewed-by: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Reviewed-by: NCheng Jian <cj.chengjian@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 5c3d89e3
......@@ -993,7 +993,9 @@ config HOTPLUG_CPU
config MPAM
bool "Support Memory Partitioning and Monitoring"
default n
depends on ACPI
select RESCTRL
select ACPI_MPAM if ACPI
help
Memory Partitioning and Monitoring. More exactly Memory system
performance resource Partitioning and Monitoring
......
......@@ -95,6 +95,8 @@
*/
struct mpam_node {
/* for label mpam_node instance*/
u32 component_id;
/* MPAM node header */
u8 type; /* MPAM_SMMU, MPAM_CACHE, MPAM_MC */
u64 addr;
......@@ -105,8 +107,19 @@ struct mpam_node {
/* for debug */
char *cpus_list;
char *name;
struct list_head list;
};
int mpam_nodes_init(void);
int __init mpam_force_init(void);
int __init mpam_nodes_discovery_start(void);
void __init mpam_nodes_discovery_failed(void);
int __init mpam_nodes_discovery_complete(void);
int mpam_create_cache_node(u32 component_id, phys_addr_t hwpage_address);
int mpam_create_memory_node(u32 component_id, phys_addr_t hwpage_address);
#endif /* _ASM_ARM64_MPAM_RESOURCE_H */
......@@ -40,7 +40,13 @@ static inline void mpam_sched_in(void)
__mpam_sched_in();
}
extern int __read_mostly mpam_enabled;
enum mpam_enable_type {
enable_denied = 0,
enable_default,
enable_acpi,
};
extern enum mpam_enable_type __read_mostly mpam_enabled;
#else
......
......@@ -62,12 +62,6 @@ int max_name_width, max_data_width;
*/
bool rdt_alloc_capable;
char *mpam_types_str[] = {
"MPAM_RESOURCE_SMMU",
"MPAM_RESOURCE_CACHE",
"MPAM_RESOURCE_MC",
};
/*
* Hi1620 2P Base Address Map
*
......@@ -81,35 +75,30 @@ char *mpam_types_str[] = {
* AFF2: MPIDR.AFF2
*/
#define MPAM_BASE(suffix, offset) ((suffix) << 24 | (offset) << 16)
#define MPAM_NODE(n, t, suffix, offset) \
{ \
.name = #n, \
.type = t, \
.addr = MPAM_BASE(suffix, (offset)), \
.cpus_list = "0", \
}
static inline void mpam_node_assign_val(struct mpam_node *n,
char *name,
u8 type,
phys_addr_t hwpage_address,
u32 component_id)
{
n->name = name;
n->type = type;
n->addr = hwpage_address;
n->component_id = component_id;
n->cpus_list = "0";
}
struct mpam_node mpam_node_all[] = {
MPAM_NODE(L3TALL0, MPAM_RESOURCE_CACHE, 0x000098ULL, 0xB9),
MPAM_NODE(L3TALL1, MPAM_RESOURCE_CACHE, 0x000090ULL, 0xB9),
MPAM_NODE(L3TALL2, MPAM_RESOURCE_CACHE, 0x200098ULL, 0xB9),
MPAM_NODE(L3TALL3, MPAM_RESOURCE_CACHE, 0x200090ULL, 0xB9),
#define MPAM_NODE_NAME_SIZE (10)
MPAM_NODE(HHAALL0, MPAM_RESOURCE_MC, 0x000098ULL, 0xC1),
MPAM_NODE(HHAALL1, MPAM_RESOURCE_MC, 0x000090ULL, 0xC1),
MPAM_NODE(HHAALL2, MPAM_RESOURCE_MC, 0x200098ULL, 0xC1),
MPAM_NODE(HHAALL3, MPAM_RESOURCE_MC, 0x200090ULL, 0xC1),
};
struct mpam_node *mpam_nodes_ptr;
void mpam_nodes_unmap(void)
static int __init mpam_init(void);
static void mpam_nodes_unmap(void)
{
int i;
size_t num_nodes = ARRAY_SIZE(mpam_node_all);
struct mpam_node *n;
for (i = 0; i < num_nodes; i++) {
n = &mpam_node_all[i];
list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
if (n->base) {
iounmap(n->base);
n->base = NULL;
......@@ -117,14 +106,12 @@ void mpam_nodes_unmap(void)
}
}
int mpam_nodes_init(void)
static int mpam_nodes_init(void)
{
int i, ret = 0;
size_t num_nodes = ARRAY_SIZE(mpam_node_all);
int ret = 0;
struct mpam_node *n;
for (i = 0; i < num_nodes; i++) {
n = &mpam_node_all[i];
list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
ret |= cpulist_parse(n->cpus_list, &n->cpu_mask);
n->base = ioremap(n->addr, 0x10000);
if (!n->base) {
......@@ -136,6 +123,160 @@ int mpam_nodes_init(void)
return ret;
}
static void mpam_nodes_destroy(void)
{
struct mpam_node *n, *tmp;
if (!mpam_nodes_ptr)
return;
list_for_each_entry_safe(n, tmp, &mpam_nodes_ptr->list, list) {
kfree(n->name);
list_del(&n->list);
kfree(n);
}
list_del(&mpam_nodes_ptr->list);
kfree(mpam_nodes_ptr);
mpam_nodes_ptr = NULL;
}
int __init mpam_nodes_discovery_start(void)
{
if (!mpam_enabled)
return -EINVAL;
mpam_nodes_ptr = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
if (!mpam_nodes_ptr)
return -ENOMEM;
INIT_LIST_HEAD(&mpam_nodes_ptr->list);
return 0;
}
void __init mpam_nodes_discovery_failed(void)
{
mpam_nodes_destroy();
}
int __init mpam_nodes_discovery_complete(void)
{
return mpam_init();
}
static inline int validate_mpam_node(int type,
int component_id)
{
int ret = 0;
struct mpam_node *n;
list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
if (n->component_id == component_id &&
n->type == type) {
ret = -EINVAL;
break;
}
}
return ret;
}
int mpam_create_cache_node(u32 component_id,
phys_addr_t hwpage_address)
{
struct mpam_node *new;
char *name;
if (validate_mpam_node(MPAM_RESOURCE_CACHE, component_id))
goto skip;
new = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
if (!new)
return -ENOMEM;
name = kzalloc(MPAM_NODE_NAME_SIZE, GFP_KERNEL);
if (!name) {
kfree(new);
return -ENOMEM;
}
snprintf(name, MPAM_NODE_NAME_SIZE, "%s%d", "L3TALL", component_id);
mpam_node_assign_val(new,
name,
MPAM_RESOURCE_CACHE,
hwpage_address,
component_id);
list_add_tail(&new->list, &mpam_nodes_ptr->list);
skip:
return 0;
}
int mpam_create_memory_node(u32 component_id,
phys_addr_t hwpage_address)
{
struct mpam_node *new;
char *name;
if (validate_mpam_node(MPAM_RESOURCE_MC, component_id))
goto skip;
new = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
if (!new)
return -ENOMEM;
name = kzalloc(MPAM_NODE_NAME_SIZE, GFP_KERNEL);
if (!name) {
kfree(new);
return -ENOMEM;
}
snprintf(name, MPAM_NODE_NAME_SIZE, "%s%d", "HHAALL", component_id);
mpam_node_assign_val(new,
name,
MPAM_RESOURCE_MC,
hwpage_address,
component_id);
list_add_tail(&new->list, &mpam_nodes_ptr->list);
skip:
return 0;
}
int __init mpam_force_init(void)
{
int ret;
if (mpam_enabled != enable_default)
return 0;
ret = mpam_nodes_discovery_start();
if (ret)
return ret;
ret |= mpam_create_cache_node(0, 0x000098b90000ULL);
ret |= mpam_create_cache_node(1, 0x000090b90000ULL);
ret |= mpam_create_cache_node(2, 0x200098b90000ULL);
ret |= mpam_create_cache_node(3, 0x200090b90000ULL);
ret |= mpam_create_memory_node(0, 0x000098c10000ULL);
ret |= mpam_create_memory_node(1, 0x000090c10000ULL);
ret |= mpam_create_memory_node(2, 0x200098c10000ULL);
ret |= mpam_create_memory_node(3, 0x200090c10000ULL);
if (ret) {
mpam_nodes_discovery_failed();
pr_err("Failed to force create mpam node\n");
return -EINVAL;
}
ret = mpam_nodes_discovery_complete();
if (!ret)
pr_info("Successfully init mpam by hardcode.\n");
return 1;
}
static void
cat_wrmsr(struct rdt_domain *d, int partid);
static void
......@@ -1137,16 +1278,14 @@ static void mpam_domains_destroy(struct resctrl_resource *r)
static void mpam_domains_init(struct resctrl_resource *r)
{
int i, id = 0;
size_t num_nodes = ARRAY_SIZE(mpam_node_all);
int id = 0;
struct mpam_node *n;
struct list_head *add_pos = NULL;
struct rdt_domain *d;
struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res;
u32 val;
for (i = 0; i < num_nodes; i++) {
n = &mpam_node_all[i];
list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
if (r->rid != n->type)
continue;
......@@ -1215,25 +1354,22 @@ static void mpam_domains_init(struct resctrl_resource *r)
}
}
int __read_mostly mpam_enabled;
enum mpam_enable_type __read_mostly mpam_enabled;
static int __init mpam_setup(char *str)
{
mpam_enabled = 1;
if (!strcmp(str, "=acpi"))
mpam_enabled = enable_acpi;
else
mpam_enabled = enable_default;
return 1;
}
__setup("mpam", mpam_setup);
static int __init mpam_late_init(void)
static int __init mpam_init(void)
{
struct resctrl_resource *r;
int state, ret;
if (!mpam_enabled)
return 0;
if (!cpus_have_const_cap(ARM64_HAS_MPAM))
return -ENODEV;
rdt_alloc_capable = 1;
rdt_mon_capable = 1;
......@@ -1242,7 +1378,7 @@ static int __init mpam_late_init(void)
ret = mpam_nodes_init();
if (ret) {
pr_err("internal error: bad cpu list\n");
return ret;
goto out;
}
mpam_domains_init(&resctrl_resources_all[MPAM_RESOURCE_CACHE]);
......@@ -1251,8 +1387,10 @@ static int __init mpam_late_init(void)
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"arm64/mpam:online:",
mpam_online_cpu, mpam_offline_cpu);
if (state < 0)
return state;
if (state < 0) {
ret = state;
goto out;
}
register_resctrl_specific_files(res_specific_files, ARRAY_SIZE(res_specific_files));
......@@ -1262,7 +1400,7 @@ static int __init mpam_late_init(void)
ret = resctrl_group_init();
if (ret) {
cpuhp_remove_state(state);
return ret;
goto out;
}
for_each_resctrl_resource(r) {
......@@ -1275,11 +1413,11 @@ static int __init mpam_late_init(void)
pr_info("MPAM %s monitoring detected\n", r->name);
}
return 0;
out:
mpam_nodes_destroy();
return ret;
}
late_initcall(mpam_late_init);
/*
* __intel_rdt_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
*
......
......@@ -8,3 +8,6 @@ config ACPI_IORT
config ACPI_GTDT
bool
config ACPI_MPAM
bool
# 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
// SPDX-License-Identifier: GPL-2.0+
/*
* Common code for ARM v8 MPAM ACPI
*
* Copyright (C) 2019-2020 Huawei Technologies Co., Ltd
*
* Author: Wang ShaoBo <bobo.shaobowang@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 <asm/mpam_resource.h>
/**
* 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
* to label mpam cache node, which be signed by @component_id.
* @table_hdr: Pointer to the head of the PPTT table
* @cpu_node: The point in the toplogy to start the walk
* @component_id: The id labels the structure mpam_node cache
*/
static int
acpi_mpam_label_cache_component_id(struct acpi_table_header *table_hdr,
struct acpi_pptt_processor *cpu_node,
u32 *component_id)
{
phys_cpuid_t min_physid = PHYS_CPUID_INVALID;
struct acpi_pptt_processor *min_cpu_node = NULL;
u32 logical_cpuid;
u32 acpi_processor_id;
acpi_pptt_find_min_physid_cpu_node(table_hdr,
cpu_node,
&min_physid,
&min_cpu_node);
WARN_ON_ONCE(invalid_phys_cpuid(min_physid));
if (min_cpu_node == NULL)
return -EINVAL;
acpi_processor_id = min_cpu_node->acpi_processor_id;
logical_cpuid = acpi_map_cpuid(min_physid, acpi_processor_id);
if (invalid_logical_cpuid(logical_cpuid) ||
!cpu_present(logical_cpuid)) {
pr_err_once("Invalid logical cpuid.\n");
return -EINVAL;
}
*component_id = cpu_to_node(logical_cpuid);
return 0;
}
/**
* acpi_mpam_label_memory_component_id() - Use proximity_domain id to
* label mpam memory node, which be signed by @component_id.
* @proximity_domain: proximity_domain of ACPI MPAM memory node
* @component_id: The id labels the structure mpam_node memory
*/
static int acpi_mpam_label_memory_component_id(u8 proximity_domain,
u32 *component_id)
{
u32 nid = (u32)proximity_domain;
if (nid >= nr_online_nodes) {
pr_err_once("Invalid proximity domain\n");
return -EINVAL;
}
*component_id = nid;
return 0;
}
static int __init acpi_mpam_parse_memory(struct acpi_mpam_header *h)
{
int ret = 0;
u32 component_id;
struct acpi_mpam_node_memory *node = (struct acpi_mpam_node_memory *)h;
ret = acpi_mpam_label_memory_component_id(node->proximity_domain,
&component_id);
if (ret) {
pr_err("Failed to label memory component id\n");
return -EINVAL;
}
ret = mpam_create_memory_node(component_id,
node->header.base_address);
if (ret) {
pr_err("Failed to create memory node\n");
return -EINVAL;
}
return ret;
}
static int __init acpi_mpam_parse_cache(struct acpi_mpam_header *h,
struct acpi_table_header *pptt)
{
int ret = 0;
u32 component_id;
struct acpi_pptt_cache *pptt_cache;
struct acpi_pptt_processor *pptt_cpu_node;
struct acpi_mpam_node_cache *node = (struct acpi_mpam_node_cache *)h;
if (!pptt) {
pr_err("No PPTT table found, MPAM cannot be configured\n");
return -EINVAL;
}
pptt_cache = acpi_pptt_validate_cache_node(pptt, node->PPTT_ref);
if (!pptt_cache) {
pr_err("Broken PPTT reference in the MPAM table\n");
return -EINVAL;
}
/*
* We actually need a cpu_node, as a pointer to the PPTT cache
* description isn't unique.
*/
pptt_cpu_node = acpi_pptt_find_cache_backwards(pptt, pptt_cache);
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;
}
ret = mpam_create_cache_node(component_id,
node->header.base_address);
if (ret) {
pr_err("Failed to create cache node\n");
return -EINVAL;
}
return ret;
}
static int __init acpi_mpam_parse_table(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_header *node_hdr;
int ret = 0;
ret = mpam_nodes_discovery_start();
if (ret)
return ret;
node_hdr = (struct acpi_mpam_header *)table_offset;
while (table_offset < table_end) {
switch (node_hdr->type) {
case ACPI_MPAM_TYPE_CACHE:
ret = acpi_mpam_parse_cache(node_hdr, pptt);
break;
case ACPI_MPAM_TYPE_MEMORY:
ret = acpi_mpam_parse_memory(node_hdr);
break;
default:
pr_warn_once("Unknown node type %u offset %ld.",
node_hdr->type,
(table_offset-(char *)table));
/* fall through */
case ACPI_MPAM_TYPE_SMMU:
/* not yet supported */
/* fall through */
case ACPI_MPAM_TYPE_UNKNOWN:
break;
}
if (ret)
break;
table_offset += node_hdr->length;
node_hdr = (struct acpi_mpam_header *)table_offset;
}
if (ret) {
pr_err("discovery failed: %d\n", ret);
mpam_nodes_discovery_failed();
} else {
ret = mpam_nodes_discovery_complete();
if (!ret)
pr_info("Successfully init mpam by ACPI.\n");
}
return ret;
}
int __init acpi_mpam_parse(void)
{
struct acpi_table_header *mpam, *pptt;
acpi_status status;
int ret;
if (!cpus_have_const_cap(ARM64_HAS_MPAM))
return 0;
ret = mpam_force_init();
if (ret)
return 0;
if (acpi_disabled)
return 0;
status = acpi_get_table(ACPI_SIG_MPAM, 0, &mpam);
if (ACPI_FAILURE(status))
return -ENOENT;
/* PPTT is optional, there may be no mpam cache controls */
acpi_get_table(ACPI_SIG_PPTT, 0, &pptt);
if (ACPI_FAILURE(status))
pptt = NULL;
ret = acpi_mpam_parse_table(mpam, pptt);
acpi_put_table(pptt);
acpi_put_table(mpam);
return ret;
}
/*
* We want to run after cacheinfo_sysfs_init() has caused the cacheinfo
* structures to be populated. That runs as a device_initcall.
*/
device_initcall_sync(acpi_mpam_parse);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册