提交 7e66740a 编写于 作者: W Wang ShaoBo 提交者: Yang Yingliang

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

hulk inclusion
category: feature
bugzilla: 28055
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>
上级 ac4dbb75
...@@ -770,7 +770,9 @@ config ARM64_ERR_RECOV ...@@ -770,7 +770,9 @@ config ARM64_ERR_RECOV
config MPAM config MPAM
bool "Support Memory Partitioning and Monitoring" bool "Support Memory Partitioning and Monitoring"
default n default n
depends on ACPI
select RESCTRL select RESCTRL
select ACPI_MPAM if ACPI
help help
Memory Partitioning and Monitoring. More exactly Memory system Memory Partitioning and Monitoring. More exactly Memory system
performance resource Partitioning and Monitoring performance resource Partitioning and Monitoring
......
...@@ -95,6 +95,8 @@ ...@@ -95,6 +95,8 @@
*/ */
struct mpam_node { struct mpam_node {
/* for label mpam_node instance*/
u32 component_id;
/* MPAM node header */ /* MPAM node header */
u8 type; /* MPAM_SMMU, MPAM_CACHE, MPAM_MC */ u8 type; /* MPAM_SMMU, MPAM_CACHE, MPAM_MC */
u64 addr; u64 addr;
...@@ -105,8 +107,19 @@ struct mpam_node { ...@@ -105,8 +107,19 @@ struct mpam_node {
/* for debug */ /* for debug */
char *cpus_list; char *cpus_list;
char *name; 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 */ #endif /* _ASM_ARM64_MPAM_RESOURCE_H */
...@@ -40,7 +40,13 @@ static inline void mpam_sched_in(void) ...@@ -40,7 +40,13 @@ static inline void mpam_sched_in(void)
__mpam_sched_in(); __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 #else
......
...@@ -67,12 +67,6 @@ int max_name_width, max_data_width; ...@@ -67,12 +67,6 @@ int max_name_width, max_data_width;
*/ */
bool rdt_alloc_capable; bool rdt_alloc_capable;
char *mpam_types_str[] = {
"MPAM_RESOURCE_SMMU",
"MPAM_RESOURCE_CACHE",
"MPAM_RESOURCE_MC",
};
/* /*
* Hi1620 2P Base Address Map * Hi1620 2P Base Address Map
* *
...@@ -86,35 +80,30 @@ char *mpam_types_str[] = { ...@@ -86,35 +80,30 @@ char *mpam_types_str[] = {
* AFF2: MPIDR.AFF2 * AFF2: MPIDR.AFF2
*/ */
#define MPAM_BASE(suffix, offset) ((suffix) << 24 | (offset) << 16) static inline void mpam_node_assign_val(struct mpam_node *n,
#define MPAM_NODE(n, t, suffix, offset) \ char *name,
{ \ u8 type,
.name = #n, \ phys_addr_t hwpage_address,
.type = t, \ u32 component_id)
.addr = MPAM_BASE(suffix, (offset)), \ {
.cpus_list = "0", \ 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[] = { #define MPAM_NODE_NAME_SIZE (10)
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),
MPAM_NODE(HHAALL0, MPAM_RESOURCE_MC, 0x000098ULL, 0xC1), struct mpam_node *mpam_nodes_ptr;
MPAM_NODE(HHAALL1, MPAM_RESOURCE_MC, 0x000090ULL, 0xC1),
MPAM_NODE(HHAALL2, MPAM_RESOURCE_MC, 0x200098ULL, 0xC1),
MPAM_NODE(HHAALL3, MPAM_RESOURCE_MC, 0x200090ULL, 0xC1),
};
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; struct mpam_node *n;
for (i = 0; i < num_nodes; i++) { list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
n = &mpam_node_all[i];
if (n->base) { if (n->base) {
iounmap(n->base); iounmap(n->base);
n->base = NULL; n->base = NULL;
...@@ -122,14 +111,12 @@ void mpam_nodes_unmap(void) ...@@ -122,14 +111,12 @@ void mpam_nodes_unmap(void)
} }
} }
int mpam_nodes_init(void) static int mpam_nodes_init(void)
{ {
int i, ret = 0; int ret = 0;
size_t num_nodes = ARRAY_SIZE(mpam_node_all);
struct mpam_node *n; struct mpam_node *n;
for (i = 0; i < num_nodes; i++) { list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
n = &mpam_node_all[i];
ret |= cpulist_parse(n->cpus_list, &n->cpu_mask); ret |= cpulist_parse(n->cpus_list, &n->cpu_mask);
n->base = ioremap(n->addr, 0x10000); n->base = ioremap(n->addr, 0x10000);
if (!n->base) { if (!n->base) {
...@@ -141,6 +128,160 @@ int mpam_nodes_init(void) ...@@ -141,6 +128,160 @@ int mpam_nodes_init(void)
return ret; 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 static void
cat_wrmsr(struct rdt_domain *d, int partid); cat_wrmsr(struct rdt_domain *d, int partid);
static void static void
...@@ -1142,16 +1283,14 @@ static void mpam_domains_destroy(struct resctrl_resource *r) ...@@ -1142,16 +1283,14 @@ static void mpam_domains_destroy(struct resctrl_resource *r)
static void mpam_domains_init(struct resctrl_resource *r) static void mpam_domains_init(struct resctrl_resource *r)
{ {
int i, id = 0; int id = 0;
size_t num_nodes = ARRAY_SIZE(mpam_node_all);
struct mpam_node *n; struct mpam_node *n;
struct list_head *add_pos = NULL; struct list_head *add_pos = NULL;
struct rdt_domain *d; struct rdt_domain *d;
struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res; struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res;
u32 val; u32 val;
for (i = 0; i < num_nodes; i++) { list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
n = &mpam_node_all[i];
if (r->rid != n->type) if (r->rid != n->type)
continue; continue;
...@@ -1220,25 +1359,22 @@ static void mpam_domains_init(struct resctrl_resource *r) ...@@ -1220,25 +1359,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) 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; return 1;
} }
__setup("mpam", mpam_setup); __setup("mpam", mpam_setup);
static int __init mpam_late_init(void) static int __init mpam_init(void)
{ {
struct resctrl_resource *r; struct resctrl_resource *r;
int state, ret; int state, ret;
if (!mpam_enabled)
return 0;
if (!cpus_have_const_cap(ARM64_HAS_MPAM))
return -ENODEV;
rdt_alloc_capable = 1; rdt_alloc_capable = 1;
rdt_mon_capable = 1; rdt_mon_capable = 1;
...@@ -1247,7 +1383,7 @@ static int __init mpam_late_init(void) ...@@ -1247,7 +1383,7 @@ static int __init mpam_late_init(void)
ret = mpam_nodes_init(); ret = mpam_nodes_init();
if (ret) { if (ret) {
pr_err("internal error: bad cpu list\n"); pr_err("internal error: bad cpu list\n");
return ret; goto out;
} }
mpam_domains_init(&resctrl_resources_all[MPAM_RESOURCE_CACHE]); mpam_domains_init(&resctrl_resources_all[MPAM_RESOURCE_CACHE]);
...@@ -1256,8 +1392,10 @@ static int __init mpam_late_init(void) ...@@ -1256,8 +1392,10 @@ static int __init mpam_late_init(void)
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"arm64/mpam:online:", "arm64/mpam:online:",
mpam_online_cpu, mpam_offline_cpu); mpam_online_cpu, mpam_offline_cpu);
if (state < 0) if (state < 0) {
return state; ret = state;
goto out;
}
register_resctrl_specific_files(res_specific_files, ARRAY_SIZE(res_specific_files)); register_resctrl_specific_files(res_specific_files, ARRAY_SIZE(res_specific_files));
...@@ -1267,7 +1405,7 @@ static int __init mpam_late_init(void) ...@@ -1267,7 +1405,7 @@ static int __init mpam_late_init(void)
ret = resctrl_group_init(); ret = resctrl_group_init();
if (ret) { if (ret) {
cpuhp_remove_state(state); cpuhp_remove_state(state);
return ret; goto out;
} }
for_each_resctrl_resource(r) { for_each_resctrl_resource(r) {
...@@ -1280,11 +1418,11 @@ static int __init mpam_late_init(void) ...@@ -1280,11 +1418,11 @@ static int __init mpam_late_init(void)
pr_info("MPAM %s monitoring detected\n", r->name); 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 * __intel_rdt_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
* *
......
...@@ -7,3 +7,6 @@ config ACPI_IORT ...@@ -7,3 +7,6 @@ config ACPI_IORT
config ACPI_GTDT config ACPI_GTDT
bool bool
config ACPI_MPAM
bool
obj-$(CONFIG_ACPI_IORT) += iort.o obj-$(CONFIG_ACPI_IORT) += iort.o
obj-$(CONFIG_ACPI_GTDT) += gtdt.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.
先完成此消息的编辑!
想要评论请 注册