anolis: arm64: refactor kunpeng mpam frame
ANBZ: #11194 immigrate newest kunpeng mpam code from openeuler (branch OLK-5.10) for incompatibility between yitian and kunpeng. old mpam code for kunpeng920 located in dir drivers/staging/kunpeng in anck is cleaned, and then transfer newest kunpeng mpam from openeuler, The detailed code information for the transfer is as follows ------------------------------------------------------------------------------------ | location in openeuler localtion in anck | ------------------------------------------------------------------------------------ | arch/arm64/kernel/mpam drivers/staging/kunpeng/mpam | drivers/acpi/arm64/ drivers/staging/kunpeng/acpi | arch/arm64/include/asm/mpam.h drivers/staging/kunpeng/include/mpam.h | include/linux/arm_mpam.h drivers/staging/kunpeng/include/arm_mpam.h | arch/arm64/include/asm/resctrl.h drivers/staging/kunpeng/include/resctrl.h | include/linux/resctrlfs.h drivers/staging/kunpeng/include/resctrlfs.h | fs/resctrlfs.c drivers/staging/kunpeng/fs/resctrlfs.c Another thing we done is that some kconfigs in kunpeng-mpam have modified for distiction with kconfigs in anck-mpam. as follow: ---------------------------------------------------------------------------------- | kconfig in openeuler -> kconfig in anck | ---------------------------------------------------------------------------------- CONFIG_MPAM -> CONFIG_KUNPENG_MPAM CONFIG_RESCTRL -> CONFIG_KUNPENG_RESCTRL ---------------------------------------------------------------------------------- | file in openeuler | original commit id corresponding the moment | ---------------------------------------------------------------------------------- arch/arm64/include/asm/mpam.h commit 0c564931c303I ("arm64/mpam: Split header files into suitable location"") ---------------------------------------------------------------------------------- include/linux/arm_mpam.h commit f4e900a6d5b3 ("ACPI/MPAM: Adapt to Arm's MPAM ACPI table version 2") ---------------------------------------------------------------------------------- arch/arm64/include/asm/resctrl.h commit ecb0378feba9 ("!4605 arm64/mpam: support resctrl fs to show mounting option") --------------------------------------------------------------------------------- include/linux/resctrlfs.h commit 0c564931c303 ("arm64/mpam: Split header files into suitable location") --------------------------------------------------------------------------------- fs/resctrlfs.c commit 7b6834233c8d ("mpam/resctrl: Fix use-after-free due to inaccurate refcount of rdtgroup") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/Makefile commit faf9a4c3d180 ("arm64/mpam: Pick MPAM resources and events for resctrl_res exported") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_ctrlmon.c commit bcb362eb2391 ("arm64/mpam: Fix softlockup when reading mondata") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_device.c commit 0376d22925d3 ("arm64/mpam: Fix repeated enabling in mpam_enable()") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_device.h commit 44513976e11e ("arm64/mpam: Enabling registering and logging error interrupts") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_internal.h commit b610437610c0 ("arm64/mpam: implement CPU_PM notifier") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_mon.c commit 7d3cd1a29f54 ("arm64/mpam: Add wait queue for monitor alloc and free") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_resctrl.c commit 3b7f60097b31 ("arm64/mpam: Fix wrong seconds to jiffies conversion") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_resource.h commit 0c564931c303 ("arm64/mpam: Split header files into suitable location") --------------------------------------------------------------------------------- arch/arm64/kernel/mpam/mpam_setup.c commit 3967a956f80c ("arm64/mpam: Remove warning about no msc corresponding to the online cpu") --------------------------------------------------------------------------------- drivers/acpi/arm64/Kconfig commit d43a6c0c538f ("MPAM / ACPI: Refactoring MPAM init process and set MPAM ACPI as entrance") --------------------------------------------------------------------------------- drivers/acpi/arm64/Makefile commit f4e900a6d5b3 ("ACPI/MPAM: Adapt to Arm's MPAM ACPI table version 2") --------------------------------------------------------------------------------- drivers/acpi/arm64/mpam.c commit 6c9da3314c65 ("mpam: Fix uninitialized value") --------------------------------------------------------------------------------- drivers/acpi/arm64/mpam_v2.c commit f4e900a6d5b3 ("ACPI/MPAM: Adapt to Arm's MPAM ACPI table version 2") Signed-off-by: Min Li <gumi@linux.alibaba.com> Reviewed-by: Guanghui Feng <guanghuifeng@linux.alibaba.com> Reviewed-by: Jay Chen <jkchen@linux.alibaba.com> Reviewed-by: Guixin Liu <kanie@linux.alibaba.com> Reviewed-by: Xunlei Pang <xlpang@linux.alibaba.com> Link: https://gitee.com/anolis/cloud-kernel/pulls/4258
This commit is contained in:
parent
ae47be59cf
commit
e1ccf88ee9
|
@ -0,0 +1,57 @@
|
|||
Memory System Resource Partitioning and Monitoring (MPAM), for Armv8-A
|
||||
----------------------------------------------------------
|
||||
|
||||
The MPAM is used to limit memory bandwidth and cache usage for ARM platform.
|
||||
The required properties for driver is:
|
||||
compatible = "arm,mpam"; /* MPAM for Arm */
|
||||
reg = <>; /* mpam device base register */
|
||||
|
||||
The property type must be included, it is used to indicate type of mpam
|
||||
device for the node. There are several type of mpam device:
|
||||
MPAM_CLASS_SMMU = 0,
|
||||
MPAM_CLASS_CACHE, /* Well known caches, e.g. L2 */
|
||||
MPAM_CLASS_MEMORY, /* Main memory */
|
||||
MPAM_CLASS_UNKNOWN, /* Everything else, e.g. TLBs etc */
|
||||
|
||||
The type of memory is set as:
|
||||
type = <2>;
|
||||
The type of cache is set as:
|
||||
type = <1>;
|
||||
|
||||
MPAM support interrupt for error and overflow, the error-interrupt and
|
||||
overflow-interrupt are defined in "Memory System Resource Partitioning
|
||||
and Monitoring (MPAM), for Armv8-A", MPAM interrupts(section 8.8).
|
||||
overflow-interrupt = <0>;
|
||||
overflow-flags = <0>;
|
||||
error-interrupt = <0>;
|
||||
error-interrupt-flags = <0>;
|
||||
|
||||
Example:
|
||||
|
||||
mpam {
|
||||
compatible = "arm,mpam";
|
||||
|
||||
mpam_memory0 {
|
||||
reg = <0x0 0x10000000 0x0 0x10000>;
|
||||
type = <2>; /* memory type */
|
||||
numa-node-id = <0>;
|
||||
overflow-interrupt = <0>;
|
||||
overflow-flags = <0>;
|
||||
error-interrupt = <0>;
|
||||
error-interrupt-flags = <0>;
|
||||
not-ready-max = <0>;
|
||||
};
|
||||
|
||||
mpam_cache0 {
|
||||
reg = <0x0 0x20000000 0x0 0x10000>;
|
||||
type = <1>; /* cache type */
|
||||
cache-id = <0>;
|
||||
cache-level = <3>;
|
||||
overflow-interrupt = <0>;
|
||||
overflow-flags = <0>;
|
||||
error-interrupt = <0>;
|
||||
error-interrupt-flags = <0>;
|
||||
not-ready-max = <0>;
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
CONFIG_KUNPENG_MPAM=y
|
|
@ -0,0 +1 @@
|
|||
CONFIG_KUNPENG_RESCTRL=y
|
|
@ -1318,3 +1318,62 @@ int acpi_pptt_get_cpumask_from_cache_id_and_level(u32 cache_id, u32 cache_level,
|
|||
acpi_put_table(table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only for kunpeng !!! */
|
||||
#ifdef CONFIG_KUNPENG_MPAM
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
/* Only for kunpeng !!! */
|
|
@ -120,4 +120,8 @@ source "drivers/staging/hikey9xx/Kconfig"
|
|||
|
||||
source "drivers/staging/kunpeng/acpi/Kconfig"
|
||||
|
||||
source "drivers/staging/kunpeng/fs/Kconfig"
|
||||
|
||||
source "drivers/staging/kunpeng/Kconfig"
|
||||
|
||||
endif # STAGING
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# ACPI Configuration for ARM64
|
||||
#
|
||||
|
||||
config KUNPENG_MPAM
|
||||
bool "Support Memory Partitioning and Monitoring"
|
||||
default n
|
||||
depends on ACPI
|
||||
select KUNPENG_RESCTRL
|
||||
select ACPI_MPAM if ACPI
|
||||
help
|
||||
Memory Partitioning and Monitoring. More exactly Memory system
|
||||
performance resource Partitioning and Monitoring
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_ARCH_HISI) += mpam/
|
||||
obj-$(CONFIG_ARCH_HISI) += acpi/
|
||||
obj-$(CONFIG_KUNPENG_RESCTRL) += fs/
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# ACPI Configuration for ARM64
|
||||
#
|
||||
|
||||
config ACPI_MPAM
|
||||
bool
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
ccflags-y := -I$(srctree)/$(src)/../include
|
||||
obj-$(CONFIG_ACPI_MPAM) += mpam.o
|
||||
|
||||
obj-$(CONFIG_ACPI_MPAM) += mpam.o mpam_v2.o
|
||||
|
|
|
@ -30,9 +30,10 @@
|
|||
#include <linux/cacheinfo.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <asm/mpam_sched.h>
|
||||
#include <arm_mpam.h>
|
||||
#include "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
|
||||
|
@ -41,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)
|
||||
|
@ -72,42 +73,17 @@ acpi_mpam_label_cache_component_id(struct acpi_table_header *table_hdr,
|
|||
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)
|
||||
static int __init acpi_mpam_parse_memory(struct acpi_mpam_header *h)
|
||||
{
|
||||
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 kunpeng_acpi_mpam_parse_memory(struct kunpeng_acpi_mpam_header *h)
|
||||
{
|
||||
int ret;
|
||||
u32 component_id;
|
||||
struct mpam_device *dev;
|
||||
struct kunpeng_acpi_mpam_node_memory *node = (struct kunpeng_acpi_mpam_node_memory *)h;
|
||||
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;
|
||||
}
|
||||
component_id = acpi_map_pxm_to_node(node->proximity_domain);
|
||||
if (component_id == NUMA_NO_NODE)
|
||||
component_id = 0;
|
||||
|
||||
dev = mpam_device_create_memory(component_id,
|
||||
node->header.base_address);
|
||||
dev = mpam_device_create_memory(component_id, node->header.base_address);
|
||||
if (IS_ERR(dev)) {
|
||||
pr_err("Failed to create memory node\n");
|
||||
return -EINVAL;
|
||||
|
@ -118,7 +94,7 @@ static int __init kunpeng_acpi_mpam_parse_memory(struct kunpeng_acpi_mpam_header
|
|||
node->header.error_interrupt, node->header.error_interrupt_flags);
|
||||
}
|
||||
|
||||
static int __init kunpeng_acpi_mpam_parse_cache(struct kunpeng_acpi_mpam_header *h,
|
||||
static int __init acpi_mpam_parse_cache(struct acpi_mpam_header *h,
|
||||
struct acpi_table_header *pptt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -128,7 +104,7 @@ static int __init kunpeng_acpi_mpam_parse_cache(struct kunpeng_acpi_mpam_header
|
|||
struct cacheinfo *ci;
|
||||
struct acpi_pptt_cache *pptt_cache;
|
||||
struct acpi_pptt_processor *pptt_cpu_node;
|
||||
struct kunpeng_acpi_mpam_node_cache *node = (struct kunpeng_acpi_mpam_node_cache *)h;
|
||||
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");
|
||||
|
@ -186,12 +162,12 @@ static int __init kunpeng_acpi_mpam_parse_cache(struct kunpeng_acpi_mpam_header
|
|||
node->header.error_interrupt, node->header.error_interrupt_flags);
|
||||
}
|
||||
|
||||
static int __init kunpeng_acpi_mpam_parse_table(struct acpi_table_header *table,
|
||||
struct acpi_table_header *pptt)
|
||||
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 kunpeng_acpi_mpam_header *node_hdr;
|
||||
struct acpi_mpam_header *node_hdr;
|
||||
int ret = 0;
|
||||
|
||||
ret = mpam_discovery_start();
|
||||
|
@ -199,32 +175,32 @@ static int __init kunpeng_acpi_mpam_parse_table(struct acpi_table_header *table,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
node_hdr = (struct kunpeng_acpi_mpam_header *)table_offset;
|
||||
node_hdr = (struct acpi_mpam_header *)table_offset;
|
||||
while (table_offset < table_end) {
|
||||
switch (node_hdr->type) {
|
||||
|
||||
case KUNPENG_ACPI_MPAM_TYPE_CACHE:
|
||||
ret = kunpeng_acpi_mpam_parse_cache(node_hdr, pptt);
|
||||
case ACPI_MPAM_TYPE_CACHE:
|
||||
ret = acpi_mpam_parse_cache(node_hdr, pptt);
|
||||
break;
|
||||
case KUNPENG_ACPI_MPAM_TYPE_MEMORY:
|
||||
ret = kunpeng_acpi_mpam_parse_memory(node_hdr);
|
||||
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 KUNPENG_ACPI_MPAM_TYPE_SMMU:
|
||||
fallthrough;
|
||||
case ACPI_MPAM_TYPE_SMMU:
|
||||
/* not yet supported */
|
||||
/* fall through */
|
||||
case KUNPENG_ACPI_MPAM_TYPE_UNKNOWN:
|
||||
fallthrough;
|
||||
case ACPI_MPAM_TYPE_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
table_offset += node_hdr->length;
|
||||
node_hdr = (struct kunpeng_acpi_mpam_header *)table_offset;
|
||||
node_hdr = (struct acpi_mpam_header *)table_offset;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
|
@ -239,41 +215,41 @@ static int __init kunpeng_acpi_mpam_parse_table(struct acpi_table_header *table,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int __init kunpeng_acpi_mpam_parse(void)
|
||||
int __init acpi_mpam_parse_version(void)
|
||||
{
|
||||
struct acpi_table_header *mpam, *pptt;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!cpus_have_const_cap(ARM64_MPAM))
|
||||
return 0;
|
||||
|
||||
if (acpi_disabled || kunpeng_mpam_enabled != KUNPENG_MPAM_ENABLE_ACPI)
|
||||
if (acpi_disabled || kunpeng_mpam_enabled != MPAM_ENABLE_ACPI)
|
||||
return 0;
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_MPAM, 0, &mpam);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENOENT;
|
||||
|
||||
if (strncmp(mpam->oem_id, "HISI", 4)) {
|
||||
acpi_put_table(mpam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 = kunpeng_acpi_mpam_parse_table(mpam, pptt);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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(kunpeng_acpi_mpam_parse);
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
// 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 "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;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
|
||||
config KUNPENG_RESCTRL
|
||||
bool "Support Memory Partitioning and Monitoring"
|
||||
default n
|
||||
depends on KUNPENG_MPAM
|
||||
select KERNFS
|
||||
help
|
||||
Memory Partitioning and Monitoring. More exactly Memory system
|
||||
performance resource Partitioning and Monitoring
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
ccflags-y := -I$(srctree)/$(src)/../include
|
||||
|
||||
obj-$(CONFIG_KUNPENG_RESCTRL) += resctrlfs.o
|
|
@ -36,12 +36,12 @@
|
|||
#include <linux/sched/task.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include "resctrlfs.h"
|
||||
|
||||
#include <uapi/linux/magic.h>
|
||||
|
||||
#include <resctrlfs.h>
|
||||
#include <resctrl.h>
|
||||
#include <mpam.h>
|
||||
#include "resctrl.h"
|
||||
#include "mpam.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(resctrl_enable_key);
|
||||
DEFINE_STATIC_KEY_FALSE(resctrl_mon_enable_key);
|
||||
|
@ -211,8 +211,7 @@ void resctrl_group_kn_unlock(struct kernfs_node *kn)
|
|||
if (atomic_dec_and_test(&rdtgrp->waitcount) &&
|
||||
(rdtgrp->flags & RDT_DELETED)) {
|
||||
kernfs_unbreak_active_protection(kn);
|
||||
kernfs_put(rdtgrp->kn);
|
||||
kfree(rdtgrp);
|
||||
rdtgroup_remove(rdtgrp);
|
||||
} else {
|
||||
kernfs_unbreak_active_protection(kn);
|
||||
}
|
||||
|
@ -272,12 +271,6 @@ mongroup_create_dir(struct kernfs_node *parent_kn, struct resctrl_group *prgrp,
|
|||
if (dest_kn)
|
||||
*dest_kn = kn;
|
||||
|
||||
/*
|
||||
* This extra ref will be put in kernfs_remove() and guarantees
|
||||
* that @rdtgrp->kn is always accessible.
|
||||
*/
|
||||
kernfs_get(kn);
|
||||
|
||||
ret = resctrl_group_kn_set_ugid(kn);
|
||||
if (ret)
|
||||
goto out_destroy;
|
||||
|
@ -394,13 +387,11 @@ static int resctrl_get_tree(struct fs_context *fc)
|
|||
|
||||
if (resctrl_mon_capable) {
|
||||
ret = mongroup_create_dir(resctrl_group_default.kn,
|
||||
NULL, "mon_groups",
|
||||
&resctrl_group_default, "mon_groups",
|
||||
&kn_mongrp);
|
||||
if (ret)
|
||||
goto out_info;
|
||||
|
||||
kernfs_get(kn_mongrp);
|
||||
|
||||
ret = mkdir_mondata_all_prepare(&resctrl_group_default);
|
||||
if (ret < 0)
|
||||
goto out_mongrp;
|
||||
|
@ -410,7 +401,6 @@ static int resctrl_get_tree(struct fs_context *fc)
|
|||
if (ret)
|
||||
goto out_mongrp;
|
||||
|
||||
kernfs_get(kn_mondata);
|
||||
resctrl_group_default.mon.mon_data_kn = kn_mondata;
|
||||
}
|
||||
|
||||
|
@ -495,7 +485,10 @@ static void free_all_child_rdtgrp(struct resctrl_group *rdtgrp)
|
|||
/* rmid may not be used */
|
||||
rmid_free(sentry->mon.rmid);
|
||||
list_del(&sentry->mon.crdtgrp_list);
|
||||
kfree(sentry);
|
||||
if (atomic_read(&sentry->waitcount) != 0)
|
||||
sentry->flags = RDT_DELETED;
|
||||
else
|
||||
rdtgroup_remove(sentry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +522,10 @@ static void rmdir_all_sub(void)
|
|||
|
||||
kernfs_remove(rdtgrp->kn);
|
||||
list_del(&rdtgrp->resctrl_group_list);
|
||||
kfree(rdtgrp);
|
||||
if (atomic_read(&rdtgrp->waitcount) != 0)
|
||||
rdtgrp->flags = RDT_DELETED;
|
||||
else
|
||||
rdtgroup_remove(rdtgrp);
|
||||
}
|
||||
/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
|
||||
update_closid_rmid(cpu_online_mask, &resctrl_group_default);
|
||||
|
@ -622,12 +618,11 @@ static int resctrl_parse_param(struct fs_context *fc, struct fs_parameter *param
|
|||
case Opt_caPrio:
|
||||
ctx->enable_caPrio = true;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void resctrl_fs_context_free(struct fs_context *fc)
|
||||
|
@ -677,41 +672,43 @@ static int find_rdtgrp_allocable_rmid(struct resctrl_group *rdtgrp)
|
|||
struct list_head *head;
|
||||
|
||||
prgrp = rdtgrp->mon.parent;
|
||||
if (prgrp == &resctrl_group_default) {
|
||||
rmid = rmid_alloc(-1);
|
||||
if (rmid < 0)
|
||||
return rmid;
|
||||
} else {
|
||||
do {
|
||||
rmid = rmid_alloc(prgrp->closid.reqpartid);
|
||||
if (rmid >= 0)
|
||||
break;
|
||||
|
||||
head = &prgrp->mon.crdtgrp_list;
|
||||
list_for_each_entry(entry, head, mon.crdtgrp_list) {
|
||||
if (entry == rdtgrp)
|
||||
continue;
|
||||
rmid = rmid_alloc(entry->closid.reqpartid);
|
||||
if (rmid >= 0)
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
/*
|
||||
* Create ctrl group under root group, just allocate new partid
|
||||
*/
|
||||
if (rdtgrp->type == RDTCTRL_GROUP)
|
||||
goto rmid_realloc;
|
||||
|
||||
rmid = rmid_alloc(prgrp->closid.reqpartid);
|
||||
if (rmid >= 0)
|
||||
goto rmid_attach;
|
||||
|
||||
head = &prgrp->mon.crdtgrp_list;
|
||||
list_for_each_entry(entry, head, mon.crdtgrp_list) {
|
||||
if (entry == rdtgrp)
|
||||
continue;
|
||||
|
||||
rmid = rmid_alloc(entry->closid.reqpartid);
|
||||
if (rmid >= 0)
|
||||
goto rmid_attach;
|
||||
}
|
||||
|
||||
rmid_realloc:
|
||||
rmid = rmid_alloc(-1);
|
||||
if (rmid < 0)
|
||||
rmid = rmid_alloc(-1);
|
||||
return rmid;
|
||||
|
||||
rmid_attach:
|
||||
ret = mpam_rmid_to_partid_pmg(rmid, &reqpartid, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rdtgrp->mon.rmid = rmid;
|
||||
rdtgrp->closid.reqpartid = reqpartid;
|
||||
|
||||
return rmid;
|
||||
}
|
||||
|
||||
static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
|
||||
struct kernfs_node *prgrp_kn,
|
||||
const char *name, umode_t mode,
|
||||
enum rdt_group_type rtype, struct resctrl_group **r)
|
||||
{
|
||||
|
@ -720,7 +717,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
|
|||
uint files = 0;
|
||||
int ret;
|
||||
|
||||
prdtgrp = resctrl_group_kn_lock_live(prgrp_kn);
|
||||
prdtgrp = resctrl_group_kn_lock_live(parent_kn);
|
||||
kunpeng_rdt_last_cmd_clear();
|
||||
if (!prdtgrp) {
|
||||
ret = -ENODEV;
|
||||
|
@ -749,7 +746,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
|
|||
ret = closid_alloc();
|
||||
if (ret < 0) {
|
||||
kunpeng_rdt_last_cmd_puts("out of CLOSIDs\n");
|
||||
goto out_unlock;
|
||||
goto out_free_rdtgrp;
|
||||
}
|
||||
rdtgrp->closid.intpartid = ret;
|
||||
}
|
||||
|
@ -776,7 +773,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
|
|||
* kernfs_remove() will drop the reference count on "kn" which
|
||||
* will free it. But we still need it to stick around for the
|
||||
* resctrl_group_kn_unlock(kn} call below. Take one extra reference
|
||||
* here, which will be dropped inside resctrl_group_kn_unlock().
|
||||
* here, which will be dropped inside rdtgroup_remove().
|
||||
*/
|
||||
kernfs_get(kn);
|
||||
|
||||
|
@ -809,29 +806,31 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
|
|||
kernfs_activate(kn);
|
||||
|
||||
/*
|
||||
* The caller unlocks the prgrp_kn upon success.
|
||||
* The caller unlocks the parent_kn upon success.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
out_prepare_clean:
|
||||
mkdir_mondata_all_prepare_clean(rdtgrp);
|
||||
out_destroy:
|
||||
kernfs_put(rdtgrp->kn);
|
||||
kernfs_remove(rdtgrp->kn);
|
||||
out_free_rmid:
|
||||
rmid_free(rdtgrp->mon.rmid);
|
||||
kfree(rdtgrp);
|
||||
out_free_closid:
|
||||
if (rdtgrp->type == RDTCTRL_GROUP)
|
||||
kunpeng_closid_free(rdtgrp->closid.intpartid);
|
||||
out_free_rdtgrp:
|
||||
kfree(rdtgrp);
|
||||
out_unlock:
|
||||
resctrl_group_kn_unlock(prgrp_kn);
|
||||
resctrl_group_kn_unlock(parent_kn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mkdir_resctrl_prepare_clean(struct resctrl_group *rgrp)
|
||||
{
|
||||
kernfs_remove(rgrp->kn);
|
||||
kfree(rgrp);
|
||||
rdtgroup_remove(rgrp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -840,14 +839,12 @@ static void mkdir_resctrl_prepare_clean(struct resctrl_group *rgrp)
|
|||
* to monitor a subset of tasks and cpus in its parent ctrl_mon group.
|
||||
*/
|
||||
static int resctrl_group_mkdir_mon(struct kernfs_node *parent_kn,
|
||||
struct kernfs_node *prgrp_kn,
|
||||
const char *name,
|
||||
umode_t mode)
|
||||
const char *name, umode_t mode)
|
||||
{
|
||||
struct resctrl_group *rdtgrp, *prgrp;
|
||||
int ret;
|
||||
|
||||
ret = mkdir_resctrl_prepare(parent_kn, prgrp_kn, name, mode, RDTMON_GROUP,
|
||||
ret = mkdir_resctrl_prepare(parent_kn, name, mode, RDTMON_GROUP,
|
||||
&rdtgrp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -865,7 +862,7 @@ static int resctrl_group_mkdir_mon(struct kernfs_node *parent_kn,
|
|||
*/
|
||||
ret = resctrl_update_groups_config(prgrp);
|
||||
|
||||
resctrl_group_kn_unlock(prgrp_kn);
|
||||
resctrl_group_kn_unlock(parent_kn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -874,14 +871,13 @@ static int resctrl_group_mkdir_mon(struct kernfs_node *parent_kn,
|
|||
* to allocate and monitor resources.
|
||||
*/
|
||||
static int resctrl_group_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
|
||||
struct kernfs_node *prgrp_kn,
|
||||
const char *name, umode_t mode)
|
||||
{
|
||||
struct resctrl_group *rdtgrp;
|
||||
struct kernfs_node *kn;
|
||||
int ret;
|
||||
|
||||
ret = mkdir_resctrl_prepare(parent_kn, prgrp_kn, name, mode, RDTCTRL_GROUP,
|
||||
ret = mkdir_resctrl_prepare(parent_kn, name, mode, RDTCTRL_GROUP,
|
||||
&rdtgrp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -899,7 +895,7 @@ static int resctrl_group_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
|
|||
* Create an empty mon_groups directory to hold the subset
|
||||
* of tasks and cpus to monitor.
|
||||
*/
|
||||
ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL);
|
||||
ret = mongroup_create_dir(kn, rdtgrp, "mon_groups", NULL);
|
||||
if (ret) {
|
||||
kunpeng_rdt_last_cmd_puts("kernfs subdir error\n");
|
||||
goto out_list_del;
|
||||
|
@ -913,7 +909,7 @@ out_list_del:
|
|||
out_common_fail:
|
||||
mkdir_resctrl_prepare_clean(rdtgrp);
|
||||
out_unlock:
|
||||
resctrl_group_kn_unlock(prgrp_kn);
|
||||
resctrl_group_kn_unlock(parent_kn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -946,19 +942,19 @@ static int resctrl_group_mkdir(struct kernfs_node *parent_kn, const char *name,
|
|||
* subdirectory
|
||||
*/
|
||||
if (resctrl_alloc_capable && parent_kn == resctrl_group_default.kn)
|
||||
return resctrl_group_mkdir_ctrl_mon(parent_kn, parent_kn, name, mode);
|
||||
return resctrl_group_mkdir_ctrl_mon(parent_kn, name, mode);
|
||||
|
||||
/*
|
||||
* If RDT monitoring is supported and the parent directory is a valid
|
||||
* "mon_groups" directory, add a monitoring subdirectory.
|
||||
*/
|
||||
if (resctrl_mon_capable && is_mon_groups(parent_kn, name))
|
||||
return resctrl_group_mkdir_mon(parent_kn, parent_kn->parent, name, mode);
|
||||
return resctrl_group_mkdir_mon(parent_kn, name, mode);
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void resctrl_group_rm_mon(struct resctrl_group *rdtgrp,
|
||||
static int resctrl_group_rmdir_mon(struct kernfs_node *kn, struct resctrl_group *rdtgrp,
|
||||
cpumask_var_t tmpmask)
|
||||
{
|
||||
struct resctrl_group *prdtgrp = rdtgrp->mon.parent;
|
||||
|
@ -989,24 +985,14 @@ static void resctrl_group_rm_mon(struct resctrl_group *rdtgrp,
|
|||
*/
|
||||
WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
|
||||
list_del(&rdtgrp->mon.crdtgrp_list);
|
||||
}
|
||||
|
||||
static int resctrl_group_rmdir_mon(struct kernfs_node *kn, struct resctrl_group *rdtgrp,
|
||||
cpumask_var_t tmpmask)
|
||||
{
|
||||
resctrl_group_rm_mon(rdtgrp, tmpmask);
|
||||
|
||||
/*
|
||||
* one extra hold on this, will drop when we kfree(rdtgrp)
|
||||
* in resctrl_group_kn_unlock()
|
||||
*/
|
||||
kernfs_get(kn);
|
||||
kernfs_remove(rdtgrp->kn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void resctrl_group_rm_ctrl(struct resctrl_group *rdtgrp, cpumask_var_t tmpmask)
|
||||
static int resctrl_group_rmdir_ctrl(struct kernfs_node *kn, struct resctrl_group *rdtgrp,
|
||||
cpumask_var_t tmpmask)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
|
@ -1032,30 +1018,18 @@ static void resctrl_group_rm_ctrl(struct resctrl_group *rdtgrp, cpumask_var_t tm
|
|||
cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
|
||||
update_closid_rmid(tmpmask, NULL);
|
||||
|
||||
rdtgrp->flags |= RDT_DELETED;
|
||||
kunpeng_closid_free(rdtgrp->closid.intpartid);
|
||||
rmid_free(rdtgrp->mon.rmid);
|
||||
|
||||
rdtgrp->flags |= RDT_DELETED;
|
||||
list_del(&rdtgrp->resctrl_group_list);
|
||||
|
||||
kernfs_remove(rdtgrp->kn);
|
||||
/*
|
||||
* Free all the child monitor group rmids.
|
||||
*/
|
||||
free_all_child_rdtgrp(rdtgrp);
|
||||
|
||||
list_del(&rdtgrp->resctrl_group_list);
|
||||
}
|
||||
|
||||
static int resctrl_group_rmdir_ctrl(struct kernfs_node *kn, struct resctrl_group *rdtgrp,
|
||||
cpumask_var_t tmpmask)
|
||||
{
|
||||
resctrl_group_rm_ctrl(rdtgrp, tmpmask);
|
||||
|
||||
/*
|
||||
* one extra hold on this, will drop when we kfree(rdtgrp)
|
||||
* in resctrl_group_kn_unlock()
|
||||
*/
|
||||
kernfs_get(kn);
|
||||
kernfs_remove(rdtgrp->kn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1082,7 +1056,8 @@ static int resctrl_group_rmdir(struct kernfs_node *kn)
|
|||
* If the resctrl_group is a mon group and parent directory
|
||||
* is a valid "mon_groups" directory, remove the mon group.
|
||||
*/
|
||||
if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == resctrl_group_default.kn)
|
||||
if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == resctrl_group_default.kn &&
|
||||
rdtgrp != &resctrl_group_default)
|
||||
ret = resctrl_group_rmdir_ctrl(kn, rdtgrp, tmpmask);
|
||||
else if (rdtgrp->type == RDTMON_GROUP &&
|
||||
is_mon_groups(parent_kn, kn->name))
|
||||
|
@ -1115,7 +1090,7 @@ static void resctrl_group_default_init(struct resctrl_group *r)
|
|||
r->type = RDTCTRL_GROUP;
|
||||
}
|
||||
|
||||
static int __init resctrl_group_setup_root(void)
|
||||
static int resctrl_group_setup_root(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1155,7 +1130,7 @@ out:
|
|||
*
|
||||
* Return: 0 on success or -errno
|
||||
*/
|
||||
int __init resctrl_group_init(void)
|
||||
int resctrl_group_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
@ -7,72 +7,186 @@
|
|||
#include <linux/cpumask.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* */
|
||||
/*
|
||||
* MPAM - Memory Partitioning and Monitoring table (Kunpeng)
|
||||
* MPAM - Memory Partitioning and Monitoring table
|
||||
*
|
||||
* Conforms to "MPAM ACPI Description 1.0",
|
||||
* Null 0, 2017. Copyright 2017 ARM Limited or its affiliates.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#define ACPI_SIG_MPAM "MPAM" /* Memory Partitioning and Monitoring Table */
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct kunpeng_acpi_table_mpam {
|
||||
struct acpi_table_header header;/* Common ACPI table header */
|
||||
};
|
||||
/*
|
||||
* The reason for comment this struct is that the struct has been defined in actbl3.h
|
||||
* and there is no caller to this struct, so we annotate it here.
|
||||
*/
|
||||
|
||||
//struct acpi_table_mpam {
|
||||
// struct acpi_table_header header;/* Common ACPI table header */
|
||||
//};
|
||||
|
||||
|
||||
/* Subtable header for MPAM */
|
||||
|
||||
struct kunpeng_acpi_mpam_header {
|
||||
u8 type;
|
||||
u16 length;
|
||||
u8 reserved;
|
||||
u64 base_address;
|
||||
u32 overflow_interrupt;
|
||||
u32 overflow_flags;
|
||||
u32 error_interrupt;
|
||||
u32 error_interrupt_flags;
|
||||
u32 not_ready_max;
|
||||
u32 offset;
|
||||
struct acpi_mpam_header {
|
||||
u8 type;
|
||||
u16 length;
|
||||
u8 reserved;
|
||||
u64 base_address;
|
||||
u32 overflow_interrupt;
|
||||
u32 overflow_flags;
|
||||
u32 error_interrupt;
|
||||
u32 error_interrupt_flags;
|
||||
u32 not_ready_max;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
/* Values for subtable type in ACPI_MPAM_NODE_HEADER */
|
||||
|
||||
enum KunpengAcpiMpamType {
|
||||
KUNPENG_ACPI_MPAM_TYPE_SMMU = 0,
|
||||
KUNPENG_ACPI_MPAM_TYPE_CACHE = 1,
|
||||
KUNPENG_ACPI_MPAM_TYPE_MEMORY = 2,
|
||||
KUNPENG_ACPI_MPAM_TYPE_UNKNOWN = 3
|
||||
enum AcpiMpamType {
|
||||
ACPI_MPAM_TYPE_SMMU = 0,
|
||||
ACPI_MPAM_TYPE_CACHE = 1,
|
||||
ACPI_MPAM_TYPE_MEMORY = 2,
|
||||
ACPI_MPAM_TYPE_UNKNOWN = 3
|
||||
};
|
||||
|
||||
/* Flags */
|
||||
#define KUNPENG_MPAM_ACPI_MPAM_IRQ_FLAGS (1) /* Interrupt mode */
|
||||
#define ACPI_MPAM_IRQ_FLAGS (1) /* Interrupt mode */
|
||||
|
||||
/*
|
||||
* MPAM Subtables
|
||||
*/
|
||||
struct kunpeng_acpi_mpam_node_smmu {
|
||||
struct kunpeng_acpi_mpam_header header;
|
||||
u32 IORT_ref;
|
||||
struct acpi_mpam_node_smmu {
|
||||
struct acpi_mpam_header header;
|
||||
u32 IORT_ref;
|
||||
};
|
||||
|
||||
struct kunpeng_acpi_mpam_node_cache {
|
||||
struct kunpeng_acpi_mpam_header header;
|
||||
u32 PPTT_ref;
|
||||
struct acpi_mpam_node_cache {
|
||||
struct acpi_mpam_header header;
|
||||
u32 PPTT_ref;
|
||||
};
|
||||
|
||||
struct kunpeng_acpi_mpam_node_memory {
|
||||
struct kunpeng_acpi_mpam_header header;
|
||||
u8 proximity_domain;
|
||||
u8 reserved1[3];
|
||||
struct acpi_mpam_node_memory {
|
||||
struct acpi_mpam_header header;
|
||||
u8 proximity_domain;
|
||||
u8 reserved1[3];
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* MPAM - Memory System Resource Partitioning and Monitoring
|
||||
*
|
||||
* Conforms to "ACPI for Memory System Resource Partitioning and Monitoring 2.0"
|
||||
* Document number: ARM DEN 0065, December, 2022.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* MPAM RIS locator types. Table 11, Location types */
|
||||
enum acpi_mpam_locator_type {
|
||||
// ACPI_MPAM_LOCATION_TYPE_PROCESSOR_CACHE = 0,
|
||||
// ACPI_MPAM_LOCATION_TYPE_MEMORY = 1,
|
||||
// ACPI_MPAM_LOCATION_TYPE_SMMU = 2,
|
||||
// ACPI_MPAM_LOCATION_TYPE_MEMORY_CACHE = 3,
|
||||
// ACPI_MPAM_LOCATION_TYPE_ACPI_DEVICE = 4,
|
||||
ACPI_MPAM_LOCATION_TYPE_INTERCONNECT = 5,
|
||||
ACPI_MPAM_LOCATION_TYPE_UNKNOWN = 0xFF
|
||||
};
|
||||
|
||||
/* MPAM Functional dependency descriptor. Table 10 */
|
||||
struct acpi_mpam_func_deps {
|
||||
u32 producer;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/* MPAM Processor cache locator descriptor. Table 13 */
|
||||
struct acpi_mpam_resource_cache_locator {
|
||||
u64 cache_reference;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/* MPAM Memory locator descriptor. Table 14 */
|
||||
struct acpi_mpam_resource_memory_locator {
|
||||
u64 proximity_domain;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/* MPAM SMMU locator descriptor. Table 15 */
|
||||
struct acpi_mpam_resource_smmu_locator {
|
||||
u64 smmu_interface;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/* MPAM Memory-side cache locator descriptor. Table 16 */
|
||||
struct acpi_mpam_resource_memcache_locator {
|
||||
u8 reserved[7];
|
||||
u8 level;
|
||||
u32 reference;
|
||||
};
|
||||
|
||||
/* MPAM ACPI device locator descriptor. Table 17 */
|
||||
struct acpi_mpam_resource_acpi_locator {
|
||||
u64 acpi_hw_id;
|
||||
u32 acpi_unique_id;
|
||||
};
|
||||
|
||||
/* MPAM Interconnect locator descriptor. Table 18 */
|
||||
struct acpi_mpam_resource_interconnect_locator {
|
||||
u64 inter_connect_desc_tbl_off;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/* MPAM Locator structure. Table 12 */
|
||||
struct acpi_mpam_resource_generic_locator {
|
||||
u64 descriptor1;
|
||||
u32 descriptor2;
|
||||
};
|
||||
|
||||
union acpi_mpam_resource_locator {
|
||||
struct acpi_mpam_resource_cache_locator cache_locator;
|
||||
struct acpi_mpam_resource_memory_locator memory_locator;
|
||||
struct acpi_mpam_resource_smmu_locator smmu_locator;
|
||||
struct acpi_mpam_resource_memcache_locator mem_cache_locator;
|
||||
struct acpi_mpam_resource_acpi_locator acpi_locator;
|
||||
struct acpi_mpam_resource_interconnect_locator interconnect_ifc_locator;
|
||||
struct acpi_mpam_resource_generic_locator generic_locator;
|
||||
};
|
||||
|
||||
/* Memory System Component Resource Node Structure Table 9 */
|
||||
struct acpi_mpam_resource_node {
|
||||
u32 identifier;
|
||||
u8 ris_index;
|
||||
u16 reserved1;
|
||||
u8 locator_type;
|
||||
union acpi_mpam_resource_locator locator;
|
||||
u32 num_functional_deps;
|
||||
};
|
||||
|
||||
/* Memory System Component (MSC) Node Structure. Table 4 */
|
||||
struct acpi_mpam_msc_node {
|
||||
u16 length;
|
||||
u8 interface_type;
|
||||
u8 reserved;
|
||||
u32 identifier;
|
||||
u64 base_address;
|
||||
u32 mmio_size;
|
||||
u32 overflow_interrupt;
|
||||
u32 overflow_interrupt_flags;
|
||||
u32 reserved1;
|
||||
u32 overflow_interrupt_affinity;
|
||||
u32 error_interrupt;
|
||||
u32 error_interrupt_flags;
|
||||
u32 reserved2;
|
||||
u32 error_interrupt_affinity;
|
||||
u32 max_nrdy_usec;
|
||||
u64 hardware_id_linked_device;
|
||||
u32 instance_id_linked_device;
|
||||
u32 num_resouce_nodes;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
/* End of Kunpeng MPAM ACPI Definitions */
|
||||
|
||||
struct mpam_device;
|
||||
|
||||
enum mpam_class_types {
|
||||
|
@ -82,7 +196,7 @@ enum mpam_class_types {
|
|||
MPAM_CLASS_UNKNOWN, /* Everything else, e.g. TLBs etc */
|
||||
};
|
||||
|
||||
struct mpam_device * __init
|
||||
struct mpam_device *
|
||||
__mpam_device_create(u8 level_idx, enum mpam_class_types type,
|
||||
int component_id, const struct cpumask *fw_affinity,
|
||||
phys_addr_t hwpage_address);
|
||||
|
@ -110,7 +224,7 @@ mpam_device_create_cache(u8 level_idx, int cache_id,
|
|||
* which will be exported as resctrl domains. MSCs for memory must
|
||||
* be accessible from any cpu.
|
||||
*/
|
||||
static inline struct mpam_device * __init
|
||||
static inline struct mpam_device *
|
||||
mpam_device_create_memory(int nid, phys_addr_t hwpage_address)
|
||||
{
|
||||
struct cpumask dev_affinity;
|
||||
|
@ -120,16 +234,17 @@ mpam_device_create_memory(int nid, phys_addr_t hwpage_address)
|
|||
return __mpam_device_create(~0, MPAM_CLASS_MEMORY, nid,
|
||||
&dev_affinity, hwpage_address);
|
||||
}
|
||||
int __init mpam_discovery_start(void);
|
||||
int __init mpam_discovery_complete(void);
|
||||
void __init mpam_discovery_failed(void);
|
||||
int mpam_discovery_start(void);
|
||||
int mpam_discovery_complete(void);
|
||||
void mpam_discovery_failed(void);
|
||||
|
||||
enum kunpeng_mpam_enable_type {
|
||||
KUNPENG_MPAM_ENABLE_DENIED = 0,
|
||||
KUNPENG_MPAM_ENABLE_ACPI,
|
||||
enum mpam_enable_type {
|
||||
MPAM_ENABLE_DENIED = 0,
|
||||
MPAM_ENABLE_ACPI,
|
||||
MPAM_ENABLE_OF,
|
||||
};
|
||||
|
||||
extern enum kunpeng_mpam_enable_type kunpeng_mpam_enabled;
|
||||
extern enum mpam_enable_type kunpeng_mpam_enabled;
|
||||
|
||||
#define MPAM_IRQ_MODE_LEVEL 0x1
|
||||
#define MPAM_IRQ_FLAGS_MASK 0x7f
|
||||
|
@ -137,12 +252,12 @@ extern enum kunpeng_mpam_enable_type kunpeng_mpam_enabled;
|
|||
#define mpam_irq_flags_to_acpi(x) ((x & MPAM_IRQ_MODE_LEVEL) ? \
|
||||
ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE)
|
||||
|
||||
void __init mpam_device_set_error_irq(struct mpam_device *dev, u32 irq,
|
||||
void mpam_device_set_error_irq(struct mpam_device *dev, u32 irq,
|
||||
u32 flags);
|
||||
void __init mpam_device_set_overflow_irq(struct mpam_device *dev, u32 irq,
|
||||
void mpam_device_set_overflow_irq(struct mpam_device *dev, u32 irq,
|
||||
u32 flags);
|
||||
|
||||
static inline int __init mpam_register_device_irq(struct mpam_device *dev,
|
||||
static inline int mpam_register_device_irq(struct mpam_device *dev,
|
||||
u32 overflow_interrupt, u32 overflow_flags,
|
||||
u32 error_interrupt, u32 error_flags)
|
||||
{
|
||||
|
@ -181,4 +296,6 @@ static inline int __init mpam_register_device_irq(struct mpam_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int __init acpi_mpam_parse_version(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef _ASM_ARM64_MPAM_H
|
||||
#define _ASM_ARM64_MPAM_H
|
||||
|
||||
#ifdef CONFIG_ARM64_MPAM
|
||||
#ifdef CONFIG_KUNPENG_MPAM
|
||||
extern int mpam_rmid_to_partid_pmg(int rmid, int *partid, int *pmg);
|
||||
#else
|
||||
static inline int mpam_rmid_to_partid_pmg(int rmid, int *partid, int *pmg)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#ifndef _ASM_ARM64_RESCTRL_H
|
||||
#define _ASM_ARM64_RESCTRL_H
|
||||
|
||||
#include <resctrlfs.h>
|
||||
#include "resctrlfs.h"
|
||||
#include <asm/mpam_sched.h>
|
||||
|
||||
#include "mpam.h"
|
||||
|
||||
#if defined(CONFIG_ARM64_MPAM)
|
||||
#if defined(CONFIG_KUNPENG_RESCTRL) && defined(CONFIG_KUNPENG_MPAM)
|
||||
|
||||
#define resctrl_group rdtgroup
|
||||
#define resctrl_alloc_capable rdt_alloc_capable
|
||||
|
@ -163,6 +162,7 @@ struct rdtgroup {
|
|||
atomic_t waitcount;
|
||||
enum rdt_group_type type;
|
||||
struct mongroup mon;
|
||||
int resync;
|
||||
};
|
||||
|
||||
enum resctrl_ctrl_type {
|
||||
|
@ -295,6 +295,7 @@ do { \
|
|||
struct resctrl_staged_config {
|
||||
hw_closid_t hw_closid;
|
||||
u32 new_ctrl[SCHEMA_NUM_CTRL_TYPE];
|
||||
bool ctrl_updated[SCHEMA_NUM_CTRL_TYPE];
|
||||
bool have_new_ctrl;
|
||||
enum resctrl_conf_type conf_type;
|
||||
enum resctrl_ctrl_type ctrl_type;
|
||||
|
@ -412,16 +413,13 @@ void resctrl_resource_reset(void);
|
|||
|
||||
int resctrl_group_init_alloc(struct rdtgroup *rdtgrp);
|
||||
|
||||
static inline int __resctrl_group_show_options(struct seq_file *seq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int __resctrl_group_show_options(struct seq_file *seq);
|
||||
|
||||
int resctrl_update_groups_config(struct rdtgroup *rdtgrp);
|
||||
|
||||
#define RESCTRL_MAX_CLOSID 32
|
||||
|
||||
int __init resctrl_group_init(void);
|
||||
int resctrl_group_init(void);
|
||||
|
||||
void post_resctrl_mount(void);
|
||||
|
||||
|
@ -545,5 +543,23 @@ DEFINE_INLINE_CTRL_FEATURE_ENABLE_FUNC(caPbm);
|
|||
DEFINE_INLINE_CTRL_FEATURE_ENABLE_FUNC(caMax);
|
||||
DEFINE_INLINE_CTRL_FEATURE_ENABLE_FUNC(caPrio);
|
||||
|
||||
/**
|
||||
* rdtgroup_remove - the helper to remove resource group safely
|
||||
* @rdtgrp: resource group to remove
|
||||
*
|
||||
* On resource group creation via a mkdir, an extra kernfs_node reference is
|
||||
* taken to ensure that the rdtgroup structure remains accessible for the
|
||||
* rdtgroup_kn_unlock() calls where it is removed.
|
||||
*
|
||||
* Drop the extra reference here, then free the rdtgroup structure.
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static inline void rdtgroup_remove(struct rdtgroup *rdtgrp)
|
||||
{
|
||||
kernfs_put(rdtgrp->kn);
|
||||
kfree(rdtgrp);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* _ASM_ARM64_RESCTRL_H */
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
ccflags-y := -I$(srctree)/$(src)/../include
|
||||
|
||||
obj-$(CONFIG_ARM64_MPAM) += mpam_resctrl.o mpam_mon.o mpam_ctrlmon.o\
|
||||
mpam_device.o mpam_setup.o resctrlfs.o
|
||||
|
||||
|
||||
obj-$(CONFIG_KUNPENG_MPAM) += mpam_resctrl.o mpam_mon.o \
|
||||
mpam_ctrlmon.o mpam_device.o mpam_setup.o
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#include <linux/kernfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include "asm/mpam.h"
|
||||
|
||||
#include <mpam.h>
|
||||
#include "mpam_resource.h"
|
||||
#include "mpam_internal.h"
|
||||
|
||||
|
@ -185,6 +185,53 @@ resctrl_dom_ctrl_config(bool cdp_both_ctrl, struct resctrl_resource *r,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resync resctrl group domain ctrls, use rdtgrp->resync to indicate
|
||||
* whether the resync procedure will be called. When resync==1, all
|
||||
* domain ctrls of this group be synchronized again. This happens
|
||||
* when rmid of this group is changed, and all configurations need to
|
||||
* be remapped again accordingly.
|
||||
*/
|
||||
static void resctrl_group_resync_domain_ctrls(struct rdtgroup *rdtgrp,
|
||||
struct resctrl_resource *r, struct rdt_domain *dom)
|
||||
{
|
||||
int i;
|
||||
int staged_start, staged_end;
|
||||
struct resctrl_staged_config *cfg;
|
||||
struct sd_closid closid;
|
||||
struct list_head *head;
|
||||
struct rdtgroup *entry;
|
||||
struct msr_param para;
|
||||
bool cdp_both_ctrl;
|
||||
|
||||
cfg = dom->staged_cfg;
|
||||
para.closid = &closid;
|
||||
|
||||
staged_start = (r->cdp_enable) ? CDP_CODE : CDP_BOTH;
|
||||
staged_end = (r->cdp_enable) ? CDP_DATA : CDP_BOTH;
|
||||
|
||||
for (i = staged_start; i <= staged_end; i++) {
|
||||
cdp_both_ctrl = cfg[i].cdp_both_ctrl;
|
||||
|
||||
resctrl_cdp_mpamid_map_val(rdtgrp->closid.intpartid,
|
||||
cfg[i].conf_type, closid.intpartid);
|
||||
resctrl_cdp_mpamid_map_val(rdtgrp->closid.reqpartid,
|
||||
cfg[i].conf_type, closid.reqpartid);
|
||||
resctrl_dom_ctrl_config(cdp_both_ctrl, r, dom, ¶);
|
||||
|
||||
/*
|
||||
* we should synchronize all child mon groups'
|
||||
* configuration from this ctrl rdtgrp
|
||||
*/
|
||||
head = &rdtgrp->mon.crdtgrp_list;
|
||||
list_for_each_entry(entry, head, mon.crdtgrp_list) {
|
||||
resctrl_cdp_mpamid_map_val(entry->closid.reqpartid,
|
||||
cfg[i].conf_type, closid.reqpartid);
|
||||
resctrl_dom_ctrl_config(cdp_both_ctrl, r, dom, ¶);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resctrl_group_update_domain_ctrls(struct rdtgroup *rdtgrp,
|
||||
struct resctrl_resource *r, struct rdt_domain *dom)
|
||||
{
|
||||
|
@ -205,14 +252,13 @@ static void resctrl_group_update_domain_ctrls(struct rdtgroup *rdtgrp,
|
|||
continue;
|
||||
update_on = false;
|
||||
cdp_both_ctrl = cfg[i].cdp_both_ctrl;
|
||||
/*
|
||||
* for ctrl group configuration, hw_closid of cfg[i] equals
|
||||
* to rdtgrp->closid.intpartid.
|
||||
*/
|
||||
closid.intpartid = hw_closid_val(cfg[i].hw_closid);
|
||||
|
||||
resctrl_cdp_mpamid_map_val(rdtgrp->closid.intpartid,
|
||||
cfg[i].conf_type, closid.intpartid);
|
||||
for_each_ctrl_type(type) {
|
||||
/* if ctrl group's config has changed, refresh it first. */
|
||||
if (dom->ctrl_val[closid.intpartid] != cfg[i].new_ctrl) {
|
||||
if (dom->ctrl_val[type][closid.intpartid] != cfg[i].new_ctrl[type] &&
|
||||
cfg[i].ctrl_updated[type] == true) {
|
||||
/*
|
||||
* duplicate ctrl group's configuration indexed
|
||||
* by intpartid from domain ctrl_val array.
|
||||
|
@ -223,6 +269,7 @@ static void resctrl_group_update_domain_ctrls(struct rdtgroup *rdtgrp,
|
|||
dom->ctrl_val[type][closid.intpartid] =
|
||||
cfg[i].new_ctrl[type];
|
||||
dom->have_new_ctrl = true;
|
||||
cfg[i].ctrl_updated[type] = false;
|
||||
update_on = true;
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +285,7 @@ static void resctrl_group_update_domain_ctrls(struct rdtgroup *rdtgrp,
|
|||
resctrl_cdp_mpamid_map_val(entry->closid.reqpartid,
|
||||
cfg[i].conf_type, closid.reqpartid);
|
||||
resctrl_dom_ctrl_config(cdp_both_ctrl, r, dom, ¶);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +295,12 @@ static int resctrl_group_update_domains(struct rdtgroup *rdtgrp,
|
|||
{
|
||||
struct rdt_domain *d;
|
||||
|
||||
list_for_each_entry(d, &r->domains, list)
|
||||
resctrl_group_update_domain_ctrls(rdtgrp, r, d);
|
||||
list_for_each_entry(d, &r->domains, list) {
|
||||
if (rdtgrp->resync)
|
||||
resctrl_group_resync_domain_ctrls(rdtgrp, r, d);
|
||||
else
|
||||
resctrl_group_update_domain_ctrls(rdtgrp, r, d);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -343,6 +395,7 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
|
|||
struct mpam_resctrl_res *res;
|
||||
enum resctrl_conf_type conf_type;
|
||||
struct resctrl_staged_config *cfg;
|
||||
enum resctrl_ctrl_type t;
|
||||
char *tok, *resname;
|
||||
u32 closid;
|
||||
int ret = 0;
|
||||
|
@ -365,13 +418,17 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
|
|||
for_each_supported_resctrl_exports(res) {
|
||||
r = &res->resctrl_res;
|
||||
|
||||
if (r->alloc_enabled) {
|
||||
list_for_each_entry(dom, &r->domains, list) {
|
||||
dom->have_new_ctrl = false;
|
||||
for_each_conf_type(conf_type) {
|
||||
cfg = &dom->staged_cfg[conf_type];
|
||||
cfg->have_new_ctrl = false;
|
||||
if (!r->alloc_enabled)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(dom, &r->domains, list) {
|
||||
dom->have_new_ctrl = false;
|
||||
for_each_conf_type(conf_type) {
|
||||
cfg = &dom->staged_cfg[conf_type];
|
||||
for_each_ctrl_type(t) {
|
||||
cfg->ctrl_updated[t] = false;
|
||||
}
|
||||
cfg->have_new_ctrl = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,6 +659,8 @@ int resctrl_group_mondata_show(struct seq_file *m, void *arg)
|
|||
r->rid), type, md.u.mon);
|
||||
|
||||
usage += resctrl_dom_mon_data(r, d, md.priv);
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -663,20 +722,31 @@ static int resctrl_mkdir_mondata_dom(struct kernfs_node *parent_kn,
|
|||
|
||||
md.u.cdp_both_mon = s->cdp_mc_both;
|
||||
|
||||
snprintf(name, sizeof(name), "mon_%s_%02d", s->name, d->id);
|
||||
kn = __kernfs_create_file(parent_kn, name, 0444,
|
||||
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
|
||||
&kf_mondata_ops, md.priv, NULL, NULL);
|
||||
if (IS_ERR(kn))
|
||||
return PTR_ERR(kn);
|
||||
|
||||
ret = resctrl_group_kn_set_ugid(kn);
|
||||
if (ret) {
|
||||
pr_info("%s: create name %s, error ret %d\n", __func__, name, ret);
|
||||
kernfs_remove(kn);
|
||||
return ret;
|
||||
if (!parent_kn) {
|
||||
pr_err("%s: error parent_kn null\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "mon_%s_%02d", s->name, d->id);
|
||||
kn = kernfs_find_and_get(parent_kn, name);
|
||||
if (!kn) {
|
||||
kn = __kernfs_create_file(parent_kn, name, 0444,
|
||||
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
|
||||
&kf_mondata_ops, md.priv, NULL, NULL);
|
||||
if (IS_ERR(kn))
|
||||
return PTR_ERR(kn);
|
||||
|
||||
ret = resctrl_group_kn_set_ugid(kn);
|
||||
if (ret) {
|
||||
pr_info("%s: create name %s, error ret %d\n",
|
||||
__func__, name, ret);
|
||||
kernfs_remove(kn);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
kn->priv = md.priv;
|
||||
|
||||
/* Could we remove the MATCH_* param ? */
|
||||
rr->mon_write(d, md.priv);
|
||||
|
||||
|
@ -705,7 +775,7 @@ int resctrl_mkdir_mondata_all_subdir(struct kernfs_node *parent_kn,
|
|||
{
|
||||
struct resctrl_schema *s;
|
||||
struct resctrl_resource *r;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Create the subdirectories for each domain. Note that all events
|
||||
|
@ -740,7 +810,6 @@ static int resctrl_group_mkdir_info_resdir(struct resctrl_resource *r,
|
|||
if (IS_ERR(kn_subdir))
|
||||
return PTR_ERR(kn_subdir);
|
||||
|
||||
kernfs_get(kn_subdir);
|
||||
ret = resctrl_group_kn_set_ugid(kn_subdir);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -766,7 +835,6 @@ int resctrl_group_create_info_dir(struct kernfs_node *parent_kn,
|
|||
*kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
|
||||
if (IS_ERR(*kn_info))
|
||||
return PTR_ERR(*kn_info);
|
||||
kernfs_get(*kn_info);
|
||||
|
||||
ret = resctrl_group_add_files(*kn_info, RF_TOP_INFO);
|
||||
if (ret)
|
||||
|
@ -801,12 +869,6 @@ int resctrl_group_create_info_dir(struct kernfs_node *parent_kn,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
m This extra ref will be put in kernfs_remove() and guarantees
|
||||
* that @rdtgrp->kn is always accessible.
|
||||
*/
|
||||
kernfs_get(*kn_info);
|
||||
|
||||
ret = resctrl_group_kn_set_ugid(*kn_info);
|
||||
if (ret)
|
||||
goto out_destroy;
|
||||
|
@ -840,11 +902,13 @@ static void rdtgroup_init_mba(struct resctrl_schema *s, u32 closid)
|
|||
cfg = &d->staged_cfg[CDP_BOTH];
|
||||
cfg->cdp_both_ctrl = s->cdp_mc_both;
|
||||
cfg->new_ctrl[SCHEMA_COMM] = rr->ctrl_features[SCHEMA_COMM].default_ctrl;
|
||||
cfg->ctrl_updated[SCHEMA_COMM] = true;
|
||||
resctrl_cdp_mpamid_map(closid, CDP_BOTH, cfg->hw_closid);
|
||||
cfg->have_new_ctrl = true;
|
||||
/* Set extension ctrl default value, e.g. priority/hardlimit */
|
||||
for_each_extend_ctrl_type(t) {
|
||||
cfg->new_ctrl[t] = rr->ctrl_features[t].default_ctrl;
|
||||
cfg->ctrl_updated[t] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -892,11 +956,12 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
|
|||
if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) <
|
||||
r->cache.min_cbm_bits) {
|
||||
kunpeng_rdt_last_cmd_printf("No space on %s:%d\n",
|
||||
r->name, d->id);
|
||||
r->name, d->id);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
resctrl_cdp_mpamid_map(closid, conf_type, cfg->hw_closid);
|
||||
cfg->ctrl_updated[SCHEMA_COMM] = true;
|
||||
cfg->have_new_ctrl = true;
|
||||
|
||||
/*
|
||||
|
@ -906,6 +971,7 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
|
|||
for_each_extend_ctrl_type(ctrl_type) {
|
||||
cfg->new_ctrl[ctrl_type] =
|
||||
rr->ctrl_features[ctrl_type].default_ctrl;
|
||||
cfg->ctrl_updated[ctrl_type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,5 +1020,42 @@ int resctrl_update_groups_config(struct rdtgroup *rdtgrp)
|
|||
}
|
||||
}
|
||||
|
||||
/* after resync all configurations, restore resync to 0 */
|
||||
rdtgrp->resync = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __resctrl_group_show_options(struct seq_file *seq)
|
||||
{
|
||||
struct resctrl_resource *res;
|
||||
struct raw_resctrl_resource *r;
|
||||
|
||||
res = mpam_resctrl_get_resource(RDT_RESOURCE_L3);
|
||||
if (res && res->cdp_enable)
|
||||
seq_puts(seq, ",cdpl3");
|
||||
|
||||
res = mpam_resctrl_get_resource(RDT_RESOURCE_L2);
|
||||
if (res && res->cdp_enable)
|
||||
seq_puts(seq, ",cdpl2");
|
||||
|
||||
r = mpam_get_raw_resctrl_resource(RDT_RESOURCE_L3);
|
||||
if (r && r->ctrl_features[SCHEMA_PBM].enabled)
|
||||
seq_puts(seq, ",caPbm");
|
||||
if (r && r->ctrl_features[SCHEMA_MAX].enabled)
|
||||
seq_puts(seq, ",caMax");
|
||||
if (r && r->ctrl_features[SCHEMA_PRI].enabled)
|
||||
seq_puts(seq, ",caPrio");
|
||||
|
||||
r = mpam_get_raw_resctrl_resource(RDT_RESOURCE_MC);
|
||||
if (r && r->ctrl_features[SCHEMA_MAX].enabled)
|
||||
seq_puts(seq, ",mbMax");
|
||||
if (r && r->ctrl_features[SCHEMA_MIN].enabled)
|
||||
seq_puts(seq, ",mbMin");
|
||||
if (r && r->ctrl_features[SCHEMA_HDL].enabled)
|
||||
seq_puts(seq, ",mbHdl");
|
||||
if (r && r->ctrl_features[SCHEMA_PRI].enabled)
|
||||
seq_puts(seq, ",mbPrio");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,12 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cacheinfo.h>
|
||||
#include "arm_mpam.h"
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
|
||||
#include <arm_mpam.h>
|
||||
#include "mpam_resource.h"
|
||||
#include "mpam_device.h"
|
||||
#include "mpam_internal.h"
|
||||
|
@ -435,7 +439,7 @@ static irqreturn_t mpam_handle_error_irq(int irq, void *data)
|
|||
return IRQ_NONE;
|
||||
|
||||
/* No-one expects MPAM errors! */
|
||||
if (device_errcode <= _MPAM_NUM_ERRCODE)
|
||||
if (device_errcode < _MPAM_NUM_ERRCODE)
|
||||
pr_err_ratelimited("unexpected error '%s' [esr:%x]\n",
|
||||
mpam_msc_err_str[device_errcode],
|
||||
device_esr);
|
||||
|
@ -496,7 +500,7 @@ static void mpam_enable_irqs(void)
|
|||
rc = request_irq(irq, mpam_handle_error_irq, request_flags,
|
||||
"MPAM ERR IRQ", dev);
|
||||
if (rc) {
|
||||
pr_err_ratelimited("Failed to register irq %u\n", irq);
|
||||
pr_warn_ratelimited("Not support to register irq %u\n", irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -529,17 +533,42 @@ static void mpam_disable_irqs(void)
|
|||
}
|
||||
}
|
||||
|
||||
static struct notifier_block mpam_notifier_block;
|
||||
static int cpu_pm_mpam_notify(struct notifier_block *b,
|
||||
unsigned long cmd, void *v)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CPU_PM_ENTER:
|
||||
break;
|
||||
case CPU_PM_EXIT:
|
||||
case CPU_PM_ENTER_FAILED:
|
||||
mpam_restore_context();
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int cpu_pm_mpam_register(void)
|
||||
{
|
||||
mpam_notifier_block.notifier_call = cpu_pm_mpam_notify;
|
||||
return cpu_pm_register_notifier(&mpam_notifier_block);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable mpam once all devices have been probed.
|
||||
* Scheduled by mpam_discovery_complete() once all devices have been created.
|
||||
* Also scheduled when new devices are probed when new CPUs come online.
|
||||
*/
|
||||
static void __init mpam_enable(struct work_struct *work)
|
||||
static void mpam_enable(struct work_struct *work)
|
||||
{
|
||||
int err;
|
||||
unsigned long flags;
|
||||
struct mpam_device *dev;
|
||||
bool all_devices_probed = true;
|
||||
static atomic_t once;
|
||||
|
||||
/* Have we probed all the devices? */
|
||||
mutex_lock(&mpam_devices_lock);
|
||||
|
@ -554,7 +583,7 @@ static void __init mpam_enable(struct work_struct *work)
|
|||
}
|
||||
mutex_unlock(&mpam_devices_lock);
|
||||
|
||||
if (!all_devices_probed)
|
||||
if (!(all_devices_probed && !atomic_fetch_inc(&once)))
|
||||
return;
|
||||
|
||||
mutex_lock(&mpam_devices_lock);
|
||||
|
@ -599,6 +628,8 @@ static void __init mpam_enable(struct work_struct *work)
|
|||
if (mpam_cpuhp_state <= 0)
|
||||
pr_err("Failed to re-register 'dyn' cpuhp callbacks");
|
||||
mutex_unlock(&mpam_cpuhp_lock);
|
||||
|
||||
cpu_pm_mpam_register();
|
||||
}
|
||||
|
||||
static void mpam_failed(struct work_struct *work)
|
||||
|
@ -617,7 +648,7 @@ static void mpam_failed(struct work_struct *work)
|
|||
mutex_unlock(&mpam_cpuhp_lock);
|
||||
}
|
||||
|
||||
static struct mpam_device * __init
|
||||
static struct mpam_device *
|
||||
mpam_device_alloc(struct mpam_component *comp)
|
||||
{
|
||||
struct mpam_device *dev;
|
||||
|
@ -652,7 +683,7 @@ static void mpam_devices_destroy(struct mpam_component *comp)
|
|||
}
|
||||
}
|
||||
|
||||
static struct mpam_component * __init mpam_component_alloc(int id)
|
||||
static struct mpam_component *mpam_component_alloc(int id)
|
||||
{
|
||||
struct mpam_component *comp;
|
||||
|
||||
|
@ -690,7 +721,7 @@ struct mpam_component *mpam_component_get(struct mpam_class *class, int id,
|
|||
return comp;
|
||||
}
|
||||
|
||||
static struct mpam_class * __init mpam_class_alloc(u8 level_idx,
|
||||
static struct mpam_class *mpam_class_alloc(u8 level_idx,
|
||||
enum mpam_class_types type)
|
||||
{
|
||||
struct mpam_class *class;
|
||||
|
@ -729,7 +760,7 @@ static void mpam_class_destroy(struct mpam_class *class)
|
|||
}
|
||||
}
|
||||
|
||||
static struct mpam_class * __init mpam_class_get(u8 level_idx,
|
||||
static struct mpam_class *mpam_class_get(u8 level_idx,
|
||||
enum mpam_class_types type,
|
||||
bool alloc)
|
||||
{
|
||||
|
@ -759,7 +790,7 @@ static struct mpam_class * __init mpam_class_get(u8 level_idx,
|
|||
* class/component structures may be allocated.
|
||||
* Returns the new device, or an ERR_PTR().
|
||||
*/
|
||||
struct mpam_device * __init
|
||||
struct mpam_device *
|
||||
__mpam_device_create(u8 level_idx, enum mpam_class_types type,
|
||||
int component_id, const struct cpumask *fw_affinity,
|
||||
phys_addr_t hwpage_address)
|
||||
|
@ -808,7 +839,7 @@ __mpam_device_create(u8 level_idx, enum mpam_class_types type,
|
|||
return dev;
|
||||
}
|
||||
|
||||
void __init mpam_device_set_error_irq(struct mpam_device *dev, u32 irq,
|
||||
void mpam_device_set_error_irq(struct mpam_device *dev, u32 irq,
|
||||
u32 flags)
|
||||
{
|
||||
unsigned long irq_save_flags;
|
||||
|
@ -819,7 +850,7 @@ void __init mpam_device_set_error_irq(struct mpam_device *dev, u32 irq,
|
|||
spin_unlock_irqrestore(&dev->lock, irq_save_flags);
|
||||
}
|
||||
|
||||
void __init mpam_device_set_overflow_irq(struct mpam_device *dev, u32 irq,
|
||||
void mpam_device_set_overflow_irq(struct mpam_device *dev, u32 irq,
|
||||
u32 flags)
|
||||
{
|
||||
unsigned long irq_save_flags;
|
||||
|
@ -862,7 +893,7 @@ static inline u16 mpam_cpu_max_pmg(void)
|
|||
/*
|
||||
* prepare for initializing devices.
|
||||
*/
|
||||
int __init mpam_discovery_start(void)
|
||||
int mpam_discovery_start(void)
|
||||
{
|
||||
if (!mpam_cpus_have_feature())
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -1092,7 +1123,7 @@ static int mpam_cpu_offline(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init mpam_discovery_complete(void)
|
||||
int mpam_discovery_complete(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -1109,7 +1140,7 @@ int __init mpam_discovery_complete(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void __init mpam_discovery_failed(void)
|
||||
void mpam_discovery_failed(void)
|
||||
{
|
||||
struct mpam_class *class, *tmp;
|
||||
|
||||
|
@ -1696,3 +1727,175 @@ void mpam_component_get_config(struct mpam_component *comp,
|
|||
{
|
||||
mpam_component_get_config_local(comp, args, result);
|
||||
}
|
||||
|
||||
#define ARM_MPAM_PDEV_NAME "arm-mpam"
|
||||
|
||||
static const struct of_device_id arm_mpam_of_device_ids[] = {
|
||||
{.compatible = "arm,mpam"},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int of_mpam_parse_irq(struct device_node *node,
|
||||
struct mpam_device *dev)
|
||||
{
|
||||
u32 overflow_interrupt, overflow_flags;
|
||||
u32 error_interrupt, error_interrupt_flags;
|
||||
|
||||
of_property_read_u32(node, "overflow-interrupt", &overflow_interrupt);
|
||||
of_property_read_u32(node, "overflow-flags", &overflow_flags);
|
||||
of_property_read_u32(node, "error-interrupt", &error_interrupt);
|
||||
of_property_read_u32(node, "error-interrupt-flags",
|
||||
&error_interrupt_flags);
|
||||
|
||||
return mpam_register_device_irq(dev,
|
||||
overflow_interrupt, overflow_flags,
|
||||
error_interrupt, error_interrupt_flags);
|
||||
}
|
||||
|
||||
static int of_mpam_parse_cache(struct platform_device *pdev,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct mpam_device *dev;
|
||||
int cache_level, cache_id;
|
||||
u64 reg_value[2];
|
||||
|
||||
if (of_property_read_u32(node, "cache-level", &cache_level)) {
|
||||
dev_err(&pdev->dev, "missing cache level property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(node, "cache-id", &cache_id)) {
|
||||
dev_err(&pdev->dev, "missing cache id property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Base address */
|
||||
if (of_property_read_u64_array(node, "reg", reg_value, 2)) {
|
||||
dev_err(&pdev->dev, "missing io resource property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = mpam_device_create_cache(cache_level, cache_id, NULL,
|
||||
reg_value[0]);
|
||||
if (IS_ERR(dev)) {
|
||||
dev_err(&pdev->dev, "Failed to create cache node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return of_mpam_parse_irq(node, dev);
|
||||
}
|
||||
|
||||
static int of_mpam_parse_memory(struct platform_device *pdev,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct mpam_device *dev;
|
||||
int numa_id;
|
||||
u64 reg_value[2];
|
||||
|
||||
if (of_property_read_u32(node, "numa-node-id", &numa_id)) {
|
||||
dev_err(&pdev->dev, "missing numa node id property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Base address */
|
||||
if (of_property_read_u64_array(node, "reg", reg_value, 2)) {
|
||||
dev_err(&pdev->dev, "missing io resource property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = mpam_device_create_memory(numa_id, reg_value[0]);
|
||||
if (IS_ERR(dev)) {
|
||||
dev_err(&pdev->dev, "Failed to create memory node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return of_mpam_parse_irq(node, dev);
|
||||
}
|
||||
|
||||
static int of_mpam_add_child(struct platform_device *pdev,
|
||||
struct device_node *node)
|
||||
{
|
||||
enum mpam_class_types type;
|
||||
|
||||
if (of_property_read_u32(node, "type", &type)) {
|
||||
dev_err(&pdev->dev, "missing type property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MPAM_CLASS_CACHE:
|
||||
return of_mpam_parse_cache(pdev, node);
|
||||
case MPAM_CLASS_MEMORY:
|
||||
return of_mpam_parse_memory(pdev, node);
|
||||
default:
|
||||
pr_warn_once("Unknown node type %u.\n", type);
|
||||
return -EINVAL;
|
||||
/* fall through */
|
||||
case MPAM_CLASS_SMMU:
|
||||
/* not yet supported */
|
||||
/* fall through */
|
||||
case MPAM_CLASS_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_mpam_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *child = NULL;
|
||||
|
||||
if (!cpus_have_const_cap(ARM64_MPAM))
|
||||
return 0;
|
||||
|
||||
if (!acpi_disabled || kunpeng_mpam_enabled != MPAM_ENABLE_OF)
|
||||
return 0;
|
||||
|
||||
if (!node || !of_match_node(arm_mpam_of_device_ids, pdev->dev.of_node))
|
||||
return -EINVAL;
|
||||
|
||||
ret = mpam_discovery_start();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
ret = of_mpam_add_child(pdev, child);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
mpam_discovery_failed();
|
||||
} else {
|
||||
ret = mpam_discovery_complete();
|
||||
if (!ret)
|
||||
pr_info("Successfully init mpam by DT.\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver arm_mpam_driver = {
|
||||
.driver = {
|
||||
.name = ARM_MPAM_PDEV_NAME,
|
||||
.of_match_table = arm_mpam_of_device_ids,
|
||||
},
|
||||
.probe = arm_mpam_device_probe,
|
||||
};
|
||||
|
||||
static int __init arm_mpam_driver_init(void)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return platform_driver_register(&arm_mpam_driver);
|
||||
else
|
||||
return acpi_mpam_parse_version();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(arm_mpam_driver_init);
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <arm_mpam.h>
|
||||
#include "arm_mpam.h"
|
||||
|
||||
struct mpam_config;
|
||||
|
||||
|
@ -111,7 +110,7 @@ struct mpam_class {
|
|||
|
||||
struct mutex lock;
|
||||
|
||||
/* member of mpam_classes */
|
||||
/* member of kunpeng_mpam_classes */
|
||||
struct list_head classes_list;
|
||||
|
||||
u16 cmax_wd;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef _ASM_ARM64_MPAM_INTERNAL_H
|
||||
#define _ASM_ARM64_MPAM_INTERNAL_H
|
||||
|
||||
#include <resctrl.h>
|
||||
#include "resctrl.h"
|
||||
|
||||
typedef u32 mpam_features_t;
|
||||
|
||||
|
@ -329,7 +329,7 @@ int kunpeng_mpam_resctrl_setup(void);
|
|||
struct raw_resctrl_resource *
|
||||
mpam_get_raw_resctrl_resource(u32 level);
|
||||
|
||||
int __init mpam_resctrl_init(void);
|
||||
int mpam_resctrl_init(void);
|
||||
|
||||
int mpam_resctrl_set_default_cpu(unsigned int cpu);
|
||||
void mpam_resctrl_clear_default_cpu(unsigned int cpu);
|
||||
|
@ -342,4 +342,6 @@ int rmid_mon_ptrs_init(u32 nr_rmids);
|
|||
struct resctrl_resource *
|
||||
mpam_resctrl_get_resource(enum resctrl_resource_level level);
|
||||
|
||||
void mpam_restore_context(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,12 +32,12 @@
|
|||
#include <linux/task_work.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <asm/io.h>
|
||||
#include "arm_mpam.h"
|
||||
|
||||
#include <asm/mpam_sched.h>
|
||||
#include "mpam.h"
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
#include <arm_mpam.h>
|
||||
#include <mpam.h>
|
||||
#include "mpam_device.h"
|
||||
#include "mpam_resource.h"
|
||||
#include "mpam_internal.h"
|
||||
|
@ -310,13 +310,23 @@ parse_cache(char *buf, struct resctrl_resource *r,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data))
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data)) {
|
||||
kunpeng_rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data >= rr->ctrl_features[type].max_wd)
|
||||
if (data >= rr->ctrl_features[type].max_wd) {
|
||||
kunpeng_rdt_last_cmd_puts("Mask out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == SCHEMA_COMM && data == 0) {
|
||||
kunpeng_rdt_last_cmd_puts("No allowed CPBM to be set to 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg->new_ctrl[type] = data;
|
||||
cfg->ctrl_updated[type] = true;
|
||||
cfg->have_new_ctrl = true;
|
||||
|
||||
return 0;
|
||||
|
@ -335,30 +345,33 @@ parse_bw(char *buf, struct resctrl_resource *r,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data)) {
|
||||
kunpeng_rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (rr->ctrl_features[type].evt) {
|
||||
case QOS_MBA_MAX_EVENT_ID:
|
||||
case QOS_MBA_PBM_EVENT_ID:
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data))
|
||||
return -EINVAL;
|
||||
data = (data < r->mbw.min_bw) ? r->mbw.min_bw : data;
|
||||
data = roundup(data, r->mbw.bw_gran);
|
||||
break;
|
||||
case QOS_MBA_MIN_EVENT_ID:
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data))
|
||||
if (data < r->mbw.min_bw || data >= rr->ctrl_features[type].max_wd) {
|
||||
kunpeng_rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", data,
|
||||
r->mbw.min_bw, rr->ctrl_features[type].max_wd - 1);
|
||||
return -EINVAL;
|
||||
/* for mbw min feature, 0 of setting is allowed */
|
||||
}
|
||||
data = roundup(data, r->mbw.bw_gran);
|
||||
break;
|
||||
default:
|
||||
if (kstrtoul(buf, rr->ctrl_features[type].base, &data))
|
||||
if (data >= rr->ctrl_features[type].max_wd) {
|
||||
kunpeng_rdt_last_cmd_printf("MB value %ld exceed %d\n", data,
|
||||
rr->ctrl_features[type].max_wd - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (data >= rr->ctrl_features[type].max_wd)
|
||||
return -EINVAL;
|
||||
|
||||
cfg->new_ctrl[type] = data;
|
||||
cfg->ctrl_updated[type] = true;
|
||||
cfg->have_new_ctrl = true;
|
||||
|
||||
return 0;
|
||||
|
@ -455,7 +468,7 @@ static u64 cache_rdmon(struct rdt_domain *d, void *md_priv)
|
|||
* We should judge if return is OK, it is possible affected
|
||||
* by NRDY bit.
|
||||
*/
|
||||
timeout = READ_ONCE(jiffies) + (1*SEC_CONVERSION);
|
||||
timeout = READ_ONCE(jiffies) + msecs_to_jiffies(1000);
|
||||
do {
|
||||
if (time_after(READ_ONCE(jiffies), timeout)) {
|
||||
err = -ETIMEDOUT;
|
||||
|
@ -496,7 +509,7 @@ static u64 mbw_rdmon(struct rdt_domain *d, void *md_priv)
|
|||
* We should judge if return is OK, it is possible affected
|
||||
* by NRDY bit.
|
||||
*/
|
||||
timeout = READ_ONCE(jiffies) + (1*SEC_CONVERSION);
|
||||
timeout = READ_ONCE(jiffies) + msecs_to_jiffies(1000);
|
||||
do {
|
||||
if (time_after(READ_ONCE(jiffies), timeout)) {
|
||||
err = -ETIMEDOUT;
|
||||
|
@ -632,23 +645,24 @@ int closid_bitmap_init(void)
|
|||
* @rows: Number of bits for remap_body[:] bitmap
|
||||
* @clos: Number of bitmaps
|
||||
* @nr_usage: Number rmid we have
|
||||
* @stride: Step stride from transforming rmid to partid and pmg
|
||||
* @step_size: Step size from traversing the point of matrix once
|
||||
* @step_cnt: Indicates how many times to traverse(.e.g if cdp;step_cnt=2)
|
||||
* @remap_body: Storing bitmaps' entry and itself
|
||||
* @remap_enabled: Does remap_body init done
|
||||
*/
|
||||
struct rmid_transform {
|
||||
u32 rows;
|
||||
u32 cols;
|
||||
u32 nr_usage;
|
||||
int stride;
|
||||
int step_size;
|
||||
int step_cnt;
|
||||
unsigned long **remap_body;
|
||||
bool remap_enabled;
|
||||
};
|
||||
static struct rmid_transform rmid_remap_matrix;
|
||||
DEFINE_STATIC_KEY_FALSE(rmid_remap_enable_key);
|
||||
|
||||
static u32 get_nr_rmids(void)
|
||||
{
|
||||
if (!rmid_remap_matrix.remap_enabled)
|
||||
if (!static_branch_likely(&rmid_remap_enable_key))
|
||||
return 0;
|
||||
|
||||
return rmid_remap_matrix.nr_usage;
|
||||
|
@ -687,9 +701,17 @@ static int set_rmid_remap_matrix(u32 rows, u32 cols)
|
|||
*/
|
||||
hw_alloc_times_validate(times, flag);
|
||||
rmid_remap_matrix.cols = rounddown(cols, times);
|
||||
rmid_remap_matrix.stride = times;
|
||||
rmid_remap_matrix.step_cnt = times;
|
||||
if (times > rmid_remap_matrix.cols)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* if only pmg(Performance Monitor Group)
|
||||
* work on the monitor, step_size must be
|
||||
* set to maximum number of columns,
|
||||
* otherwise set it to 1, such as kunpeng
|
||||
* 920 does.
|
||||
*/
|
||||
rmid_remap_matrix.step_size = 1;
|
||||
|
||||
/*
|
||||
* first row of rmid remap matrix is used for indicating
|
||||
|
@ -733,7 +755,8 @@ static int set_rmid_remap_matrix(u32 rows, u32 cols)
|
|||
0, rmid_remap_matrix.rows);
|
||||
}
|
||||
|
||||
rmid_remap_matrix.remap_enabled = 1;
|
||||
/* make column entry of rmid matrix visible */
|
||||
static_branch_enable_cpuslocked(&rmid_remap_enable_key);
|
||||
|
||||
return 0;
|
||||
clean:
|
||||
|
@ -748,6 +771,9 @@ clean:
|
|||
rmid_remap_matrix.remap_body = NULL;
|
||||
}
|
||||
|
||||
/* if recreation failed, cannot use rmid remap matrix */
|
||||
static_branch_disable_cpuslocked(&rmid_remap_enable_key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -761,37 +787,102 @@ static u32 probe_rmid_remap_matrix_rows(void)
|
|||
return (u32)mpam_sysprops_num_pmg();
|
||||
}
|
||||
|
||||
static inline unsigned long **__rmid_remap_bmp(int col)
|
||||
static inline unsigned long **__rmid_remap_bmp(u32 col)
|
||||
{
|
||||
if (!rmid_remap_matrix.remap_enabled)
|
||||
if (!static_branch_likely(&rmid_remap_enable_key))
|
||||
return NULL;
|
||||
|
||||
if ((u32)col >= rmid_remap_matrix.cols)
|
||||
if (col >= rmid_remap_matrix.cols)
|
||||
return NULL;
|
||||
|
||||
return rmid_remap_matrix.remap_body + col;
|
||||
}
|
||||
|
||||
#define for_each_rmid_remap_bmp(bmp) \
|
||||
for (bmp = __rmid_remap_bmp(0); \
|
||||
bmp <= __rmid_remap_bmp(rmid_remap_matrix.cols - 1); \
|
||||
bmp++)
|
||||
/*
|
||||
* these macros defines how can we traverse rmid remap matrix, there are
|
||||
* three scenarios:
|
||||
*
|
||||
* (1) step_size is default set to 1, if only PMG(NR_PMG=4) works, makes
|
||||
* it equals to number of columns, step_cnt means how many times are
|
||||
* allocated and released each time, at this time rmid remap matrix
|
||||
* looks like:
|
||||
*
|
||||
* ^
|
||||
* |
|
||||
* ------column------>
|
||||
*
|
||||
* RMID 0 1 2 3 (step_size=1)
|
||||
* `---'
|
||||
* `--> (step_cnt=2 if cdp enabled)
|
||||
*
|
||||
* RMID 0 1 2 3 (step_size=1)
|
||||
* `--
|
||||
* `--> (step_cnt=1 if cdp disabled)
|
||||
*
|
||||
* (2) if PARTID(NR_PARTID=4) and PMG(NR_PMG=4) works together, at this
|
||||
* time rmid remap matrix looks like:
|
||||
*
|
||||
* ------------row------------>
|
||||
* |
|
||||
* | RMID 0 1 2 3 (step_size=1)
|
||||
* | `---'
|
||||
* | `--> (step_cnt=2 if cdp enabled)
|
||||
* | 4 5 6 7
|
||||
* | 8 9 10 11
|
||||
* v 12 13 14 15
|
||||
*
|
||||
* (3) step_size not equal to 1, cross-line traversal, but this scenario
|
||||
* did not happen yet.
|
||||
*/
|
||||
|
||||
#define for_each_valid_rmid_remap_bmp(bmp) \
|
||||
for_each_rmid_remap_bmp(bmp) \
|
||||
if (bmp && *bmp)
|
||||
#define __xy_initialize(x, y, from) \
|
||||
(x = from, y = 0)
|
||||
#define __xy_overflow(x, y) \
|
||||
(y >= rmid_remap_matrix.cols)
|
||||
#define __x_forward(x) \
|
||||
(x = (x + 1) % rmid_remap_matrix.cols)
|
||||
#define __y_forward(x, y) \
|
||||
(y += ((x) ? 0 : 1))
|
||||
|
||||
#define STRIDE_CHK(stride) \
|
||||
(stride == rmid_remap_matrix.stride)
|
||||
#define __step_xy_initialize(step, x, y, from) \
|
||||
(x = from, step = 1, y = 0)
|
||||
#define __step_align(from) \
|
||||
(!(from % (rmid_remap_matrix.step_size * \
|
||||
rmid_remap_matrix.step_cnt)))
|
||||
#define __step_overflow(step) \
|
||||
(__xy_overflow(x, y) || \
|
||||
(step > rmid_remap_matrix.step_cnt))
|
||||
#define __step_x_forward(x) \
|
||||
__x_forward(x)
|
||||
#define __step_forward(step, x) \
|
||||
(step += ((x % rmid_remap_matrix.step_size) ? 0 : 1))
|
||||
#define __step_y_forward(x, y) \
|
||||
__y_forward(x, y)
|
||||
|
||||
#define STRIDE_INC_CHK(stride) \
|
||||
(++stride == rmid_remap_matrix.stride)
|
||||
#define for_each_rmid_transform_point_step_from(p_entry, step, x, y, from) \
|
||||
for (__step_xy_initialize(step, x, y, from), \
|
||||
(p_entry) = __rmid_remap_bmp((from)); \
|
||||
__step_align(from) && !__step_overflow(step); \
|
||||
__step_x_forward(x), \
|
||||
__step_forward(step, x), \
|
||||
__step_y_forward(x, y), \
|
||||
(p_entry) = __rmid_remap_bmp(x)) \
|
||||
if (unlikely(((p_entry) == NULL) || \
|
||||
(*p_entry) == NULL)) \
|
||||
WARN_ON_ONCE(1); \
|
||||
else
|
||||
|
||||
#define STRIDE_CHK_AND_WARN(stride) \
|
||||
do { \
|
||||
if (!STRIDE_CHK(stride)) \
|
||||
WARN_ON_ONCE("Unexpected stride\n"); \
|
||||
} while (0)
|
||||
#define for_each_rmid_transform_point_from(p_entry, x, y, from) \
|
||||
for (__xy_initialize(x, y, from), \
|
||||
(p_entry) = __rmid_remap_bmp((from)); \
|
||||
!__xy_overflow(x, y); \
|
||||
__x_forward(x), \
|
||||
__y_forward(x, y), \
|
||||
(p_entry) = __rmid_remap_bmp(x)) \
|
||||
if (unlikely(((p_entry) == NULL) || \
|
||||
(*p_entry) == NULL)) \
|
||||
WARN_ON_ONCE(1); \
|
||||
else
|
||||
|
||||
static void set_rmid_remap_bmp_occ(unsigned long *bmp)
|
||||
{
|
||||
|
@ -803,6 +894,11 @@ static void unset_rmid_remap_bmp_occ(unsigned long *bmp)
|
|||
set_bit(0, bmp);
|
||||
}
|
||||
|
||||
static int is_rmid_remap_bmp_bdr_set(unsigned long *bmp, int b)
|
||||
{
|
||||
return (test_bit(b + 1, bmp) == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void rmid_remap_bmp_bdr_set(unsigned long *bmp, int b)
|
||||
{
|
||||
set_bit(b + 1, bmp);
|
||||
|
@ -826,6 +922,33 @@ static int is_rmid_remap_bmp_full(unsigned long *bmp)
|
|||
bitmap_full(bmp, rmid_remap_matrix.rows));
|
||||
}
|
||||
|
||||
static int rmid_remap_bmp_find_step_entry(int partid, bool exclusive)
|
||||
{
|
||||
int x, y;
|
||||
unsigned long **bmp;
|
||||
|
||||
if (rmid_remap_matrix.step_size ==
|
||||
rmid_remap_matrix.cols)
|
||||
return 0;
|
||||
|
||||
/* step entry should be non-occupied and aligned */
|
||||
bmp = __rmid_remap_bmp(partid);
|
||||
if (bmp)
|
||||
return ((exclusive && is_rmid_remap_bmp_occ(*bmp)) ||
|
||||
!__step_align(partid)) ? -ENOSPC : partid;
|
||||
|
||||
for_each_rmid_transform_point_from(bmp, x, y, 0) {
|
||||
/*
|
||||
* do not waste partid resource, start
|
||||
* from step aligned position.
|
||||
*/
|
||||
if (__step_align(x) && !is_rmid_remap_bmp_occ(*bmp))
|
||||
return x;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static int rmid_remap_bmp_alloc_pmg(unsigned long *bmp)
|
||||
{
|
||||
int pos;
|
||||
|
@ -840,8 +963,7 @@ static int rmid_remap_bmp_alloc_pmg(unsigned long *bmp)
|
|||
|
||||
static int rmid_remap_matrix_init(void)
|
||||
{
|
||||
int stride = 0;
|
||||
int ret;
|
||||
int x, y, step, ret;
|
||||
u32 cols, rows;
|
||||
unsigned long **bmp;
|
||||
|
||||
|
@ -858,15 +980,11 @@ static int rmid_remap_matrix_init(void)
|
|||
* default rmid, otherwise drop partid = 0 and
|
||||
* partid = 1 for LxCACHE, LxDATA reservation.
|
||||
*/
|
||||
for_each_valid_rmid_remap_bmp(bmp) {
|
||||
for_each_rmid_transform_point_step_from(bmp, step, x, y, 0) {
|
||||
set_rmid_remap_bmp_occ(*bmp);
|
||||
rmid_remap_bmp_bdr_clear(*bmp, 0);
|
||||
if (STRIDE_INC_CHK(stride))
|
||||
break;
|
||||
rmid_remap_bmp_alloc_pmg(*bmp);
|
||||
}
|
||||
|
||||
STRIDE_CHK_AND_WARN(stride);
|
||||
|
||||
ret = rmid_mon_ptrs_init(rmid_remap_matrix.nr_usage);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -909,99 +1027,83 @@ static int rmid_to_partid_pmg(int rmid, int *partid, int *pmg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __rmid_alloc(int partid)
|
||||
static int __rmid_alloc(int partid, int pmg, bool exclusive)
|
||||
{
|
||||
int stride = 0;
|
||||
int partid_sel = 0;
|
||||
int ret, pmg;
|
||||
int rmid[2] = {-1, -1};
|
||||
unsigned long **cmp, **bmp;
|
||||
int x, y, step, ret, rmid;
|
||||
bool checkpmg = false;
|
||||
unsigned long **bmp;
|
||||
|
||||
if (partid >= 0) {
|
||||
cmp = __rmid_remap_bmp(partid);
|
||||
if (!cmp) {
|
||||
ret = -EINVAL;
|
||||
if (pmg >= 0)
|
||||
checkpmg = true;
|
||||
|
||||
/* traverse from first non-occupied and step-aligned entry */
|
||||
ret = rmid_remap_bmp_find_step_entry(partid, exclusive);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
partid = ret;
|
||||
|
||||
for_each_rmid_transform_point_step_from(bmp, step, x, y, partid) {
|
||||
set_rmid_remap_bmp_occ(*bmp);
|
||||
|
||||
/* checking if the given pmg is available */
|
||||
if (checkpmg) {
|
||||
/*
|
||||
* it can only happened in step_size aligned
|
||||
* position, so it does not exist pmgs cleared
|
||||
* before.
|
||||
*/
|
||||
if (is_rmid_remap_bmp_bdr_set(*bmp, pmg + y)) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
rmid_remap_bmp_bdr_clear(*bmp, pmg + y);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* alloc available pmg */
|
||||
ret = rmid_remap_bmp_alloc_pmg(*bmp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
for_each_valid_rmid_remap_bmp(bmp) {
|
||||
if (bmp < cmp)
|
||||
continue;
|
||||
set_rmid_remap_bmp_occ(*bmp);
|
||||
|
||||
ret = rmid_remap_bmp_alloc_pmg(*bmp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/* always return first pmg */
|
||||
if (pmg < 0)
|
||||
pmg = ret;
|
||||
rmid[stride] = to_rmid(partid + stride, pmg);
|
||||
if (STRIDE_INC_CHK(stride))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for_each_valid_rmid_remap_bmp(bmp) {
|
||||
partid_sel++;
|
||||
|
||||
if (is_rmid_remap_bmp_occ(*bmp))
|
||||
continue;
|
||||
set_rmid_remap_bmp_occ(*bmp);
|
||||
|
||||
ret = rmid_remap_bmp_alloc_pmg(*bmp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
pmg = ret;
|
||||
rmid[stride] = to_rmid(partid_sel - 1, pmg);
|
||||
if (STRIDE_INC_CHK(stride))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!STRIDE_CHK(stride)) {
|
||||
rmid = to_rmid(partid, pmg);
|
||||
if (!is_rmid_valid(rmid)) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = assoc_rmid_with_mon(rmid[0]);
|
||||
if (ret)
|
||||
ret = assoc_rmid_with_mon(rmid);
|
||||
if (ret) {
|
||||
rmid_free(rmid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return rmid[0];
|
||||
return rmid;
|
||||
out:
|
||||
rmid_free(rmid[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rmid_alloc(int partid)
|
||||
{
|
||||
return __rmid_alloc(partid);
|
||||
return __rmid_alloc(partid, -1, false);
|
||||
}
|
||||
|
||||
void rmid_free(int rmid)
|
||||
{
|
||||
int stride = 0;
|
||||
int partid, pmg;
|
||||
unsigned long **bmp, **cmp;
|
||||
int x, y, step, partid, pmg;
|
||||
unsigned long **bmp;
|
||||
|
||||
if (rmid_to_partid_pmg(rmid, &partid, &pmg))
|
||||
return;
|
||||
|
||||
cmp = __rmid_remap_bmp(partid);
|
||||
if (!cmp)
|
||||
return;
|
||||
|
||||
for_each_valid_rmid_remap_bmp(bmp) {
|
||||
if (bmp < cmp)
|
||||
continue;
|
||||
|
||||
rmid_remap_bmp_bdr_set(*bmp, pmg);
|
||||
|
||||
for_each_rmid_transform_point_step_from(bmp, step, x, y, partid) {
|
||||
rmid_remap_bmp_bdr_set(*bmp, pmg + y);
|
||||
if (is_rmid_remap_bmp_full(*bmp))
|
||||
unset_rmid_remap_bmp_occ(*bmp);
|
||||
|
||||
if (STRIDE_INC_CHK(stride))
|
||||
break;
|
||||
}
|
||||
|
||||
STRIDE_CHK_AND_WARN(stride);
|
||||
|
||||
deassoc_rmid_with_mon(rmid);
|
||||
}
|
||||
|
||||
|
@ -1043,7 +1145,7 @@ void kunpeng_closid_free(int closid)
|
|||
* Choose a width for the resource name and resource data based on the
|
||||
* resource that has widest name and cbm.
|
||||
*/
|
||||
static __init void mpam_init_padding(void)
|
||||
static void mpam_init_padding(void)
|
||||
{
|
||||
int cl;
|
||||
struct mpam_resctrl_res *res;
|
||||
|
@ -1246,7 +1348,7 @@ static void move_myself(struct callback_head *head)
|
|||
(rdtgrp->flags & RDT_DELETED)) {
|
||||
current->closid = 0;
|
||||
current->rmid = 0;
|
||||
kfree(rdtgrp);
|
||||
rdtgroup_remove(rdtgrp);
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
|
@ -1263,7 +1365,7 @@ int __resctrl_group_move_task(struct task_struct *tsk,
|
|||
struct task_move_callback *callback;
|
||||
int ret;
|
||||
|
||||
callback = kzalloc(sizeof(*callback), GFP_KERNEL);
|
||||
callback = kzalloc(sizeof(*callback), GFP_NOWAIT);
|
||||
if (!callback)
|
||||
return -ENOMEM;
|
||||
callback->work.func = move_myself;
|
||||
|
@ -1758,18 +1860,14 @@ static ssize_t resctrl_group_tasks_write(struct kernfs_open_file *of,
|
|||
static void show_resctrl_tasks(struct rdtgroup *r, struct seq_file *s)
|
||||
{
|
||||
struct task_struct *p, *t;
|
||||
pid_t pid;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(p, t) {
|
||||
if ((r->type == RDTMON_GROUP &&
|
||||
t->rmid == resctrl_navie_rmid(r->mon.rmid)) ||
|
||||
(r->type == RDTCTRL_GROUP &&
|
||||
t->closid == resctrl_navie_closid(r->closid))) {
|
||||
pid = task_pid_vnr(t);
|
||||
if (pid)
|
||||
seq_printf(s, "%d\n", pid);
|
||||
}
|
||||
t->closid == resctrl_navie_closid(r->closid)))
|
||||
seq_printf(s, "%d\n", t->pid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -1813,6 +1911,129 @@ static int resctrl_group_rmid_show(struct kernfs_open_file *of,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t resctrl_group_rmid_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct rdtgroup *rdtgrp;
|
||||
int ret = 0;
|
||||
int partid;
|
||||
bool exclusive;
|
||||
int pmg;
|
||||
int rmid;
|
||||
int old_rmid;
|
||||
int old_reqpartid;
|
||||
struct task_struct *p, *t;
|
||||
|
||||
if (kstrtoint(strstrip(buf), 0, &rmid) || rmid < 0)
|
||||
return -EINVAL;
|
||||
|
||||
rdtgrp = resctrl_group_kn_lock_live(of->kn);
|
||||
if (!rdtgrp) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
kunpeng_rdt_last_cmd_clear();
|
||||
|
||||
if (rmid == 0 || rdtgrp->mon.rmid == 0) {
|
||||
ret = -EINVAL;
|
||||
kunpeng_rdt_last_cmd_puts("default rmid 0 is always kept\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = rmid_to_partid_pmg(rmid, &partid, &pmg);
|
||||
if (ret < 0) {
|
||||
ret = -EINVAL;
|
||||
kunpeng_rdt_last_cmd_puts("invalid rmid\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (rmid == rdtgrp->mon.rmid)
|
||||
goto unlock;
|
||||
|
||||
if (rdtgrp->type != RDTCTRL_GROUP ||
|
||||
!list_empty(&rdtgrp->mon.crdtgrp_list)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
kunpeng_rdt_last_cmd_puts("unsupported operation\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
old_rmid = rdtgrp->mon.rmid;
|
||||
old_reqpartid = rdtgrp->closid.reqpartid;
|
||||
|
||||
exclusive = (partid == old_reqpartid) ? false : true;
|
||||
ret = __rmid_alloc(partid, pmg, exclusive);
|
||||
if (ret < 0) {
|
||||
kunpeng_rdt_last_cmd_puts("set rmid failed\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* we use intpartid as group control, use reqpartid for config
|
||||
* synchronization and monitor, only update the reqpartid
|
||||
*/
|
||||
rdtgrp->closid.reqpartid = partid;
|
||||
rdtgrp->mon.rmid = rmid;
|
||||
|
||||
/* update rmid for mondata */
|
||||
ret = resctrl_mkdir_mondata_all_subdir(rdtgrp->mon.mon_data_kn, rdtgrp);
|
||||
if (ret) {
|
||||
kunpeng_rdt_last_cmd_puts("update rmid for mondata failed\n");
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
/* resync groups configuration */
|
||||
rdtgrp->resync = 1;
|
||||
ret = resctrl_update_groups_config(rdtgrp);
|
||||
if (ret) {
|
||||
kunpeng_rdt_last_cmd_puts("update groups config failed\n");
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(p, t) {
|
||||
if (t->closid == rdtgrp->closid.intpartid) {
|
||||
ret = __resctrl_group_move_task(t, rdtgrp);
|
||||
if (ret) {
|
||||
read_unlock(&tasklist_lock);
|
||||
goto rollback;
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
update_closid_rmid(&rdtgrp->cpu_mask, rdtgrp);
|
||||
rmid_free(old_rmid);
|
||||
|
||||
unlock:
|
||||
resctrl_group_kn_unlock(of->kn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nbytes;
|
||||
|
||||
rollback:
|
||||
rdtgrp->mon.rmid = old_rmid;
|
||||
rdtgrp->closid.reqpartid = old_reqpartid;
|
||||
|
||||
/* the old rmid is valid, so mkdir mondata here won't fail */
|
||||
resctrl_mkdir_mondata_all_subdir(rdtgrp->mon.mon_data_kn, rdtgrp);
|
||||
|
||||
rdtgrp->resync = 1;
|
||||
WARN_ON_ONCE(resctrl_update_groups_config(rdtgrp));
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(p, t) {
|
||||
if (t->closid == rdtgrp->closid.intpartid)
|
||||
WARN_ON_ONCE(__resctrl_group_move_task(t, rdtgrp));
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
rmid_free(rmid);
|
||||
resctrl_group_kn_unlock(of->kn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* rdtgroup information files for one cache resource. */
|
||||
static struct rftype res_specific_files[] = {
|
||||
{
|
||||
|
@ -1912,8 +2133,9 @@ static struct rftype res_specific_files[] = {
|
|||
},
|
||||
{
|
||||
.name = "rmid",
|
||||
.mode = 0444,
|
||||
.mode = 0644,
|
||||
.kf_ops = &resctrl_group_kf_single_ops,
|
||||
.write = resctrl_group_rmid_write,
|
||||
.seq_show = resctrl_group_rmid_show,
|
||||
.fflags = RFTYPE_BASE,
|
||||
},
|
||||
|
@ -1952,17 +2174,19 @@ struct rdt_domain *mpam_find_domain(struct resctrl_resource *r, int id,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
enum kunpeng_mpam_enable_type __read_mostly kunpeng_mpam_enabled;
|
||||
static int __init kunpeng_mpam_setup(char *str)
|
||||
enum mpam_enable_type __read_mostly kunpeng_mpam_enabled;
|
||||
static int __init mpam_setup(char *str)
|
||||
{
|
||||
if (!strcmp(str, "=acpi"))
|
||||
kunpeng_mpam_enabled = KUNPENG_MPAM_ENABLE_ACPI;
|
||||
kunpeng_mpam_enabled = MPAM_ENABLE_ACPI;
|
||||
else if (!strcmp(str, "=of"))
|
||||
kunpeng_mpam_enabled = MPAM_ENABLE_OF;
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("kpmpam", kunpeng_mpam_setup);
|
||||
__setup("mpam", mpam_setup);
|
||||
|
||||
int __init mpam_resctrl_init(void)
|
||||
int mpam_resctrl_init(void)
|
||||
{
|
||||
mpam_init_padding();
|
||||
|
||||
|
@ -2053,6 +2277,16 @@ void __mpam_sched_in(void)
|
|||
}
|
||||
}
|
||||
|
||||
void mpam_restore_context(void)
|
||||
{
|
||||
struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
|
||||
|
||||
state->cur_rmid = 0;
|
||||
state->cur_closid = 0;
|
||||
|
||||
mpam_sched_in();
|
||||
}
|
||||
|
||||
static void
|
||||
mpam_update_from_resctrl_cfg(struct mpam_resctrl_res *res,
|
||||
u32 resctrl_cfg, enum rdt_event_id evt,
|
||||
|
@ -2071,6 +2305,8 @@ mpam_update_from_resctrl_cfg(struct mpam_resctrl_res *res,
|
|||
case QOS_MBA_MAX_EVENT_ID:
|
||||
range = MBW_MAX_BWA_FRACT(res->class->bwa_wd);
|
||||
mpam_cfg->mbw_max = (resctrl_cfg * range) / (MAX_MBA_BW - 1);
|
||||
/* correct mbw_max if remainder is too large */
|
||||
mpam_cfg->mbw_max += ((resctrl_cfg * range) % (MAX_MBA_BW - 1)) / range;
|
||||
mpam_cfg->mbw_max =
|
||||
(mpam_cfg->mbw_max > range) ? range : mpam_cfg->mbw_max;
|
||||
mpam_set_feature(mpam_feat_mbw_max, &mpam_cfg->valid);
|
||||
|
@ -2078,6 +2314,8 @@ mpam_update_from_resctrl_cfg(struct mpam_resctrl_res *res,
|
|||
case QOS_MBA_MIN_EVENT_ID:
|
||||
range = MBW_MAX_BWA_FRACT(res->class->bwa_wd);
|
||||
mpam_cfg->mbw_min = (resctrl_cfg * range) / (MAX_MBA_BW - 1);
|
||||
/* correct mbw_min if remainder is too large */
|
||||
mpam_cfg->mbw_min += ((resctrl_cfg * range) % (MAX_MBA_BW - 1)) / range;
|
||||
mpam_cfg->mbw_min =
|
||||
(mpam_cfg->mbw_min > range) ? range : mpam_cfg->mbw_min;
|
||||
mpam_set_feature(mpam_feat_mbw_min, &mpam_cfg->valid);
|
||||
|
|
|
@ -56,7 +56,7 @@ mpam_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int mpam_resctrl_setup_domain(unsigned int cpu,
|
||||
static int kunpeng_mpam_resctrl_setup_domain(unsigned int cpu,
|
||||
struct mpam_resctrl_res *res)
|
||||
{
|
||||
struct rdt_domain *d;
|
||||
|
@ -65,7 +65,7 @@ static int mpam_resctrl_setup_domain(unsigned int cpu,
|
|||
struct mpam_component *comp_iter, *comp;
|
||||
u32 num_partid;
|
||||
u32 **ctrlval_ptr;
|
||||
enum resctrl_ctrl_type type;
|
||||
enum resctrl_ctrl_type type, type_free;
|
||||
struct list_head *tmp;
|
||||
|
||||
num_partid = mpam_sysprops_num_partid();
|
||||
|
@ -78,9 +78,11 @@ static int mpam_resctrl_setup_domain(unsigned int cpu,
|
|||
}
|
||||
}
|
||||
|
||||
/* cpu with unknown exported component? */
|
||||
if (WARN_ON_ONCE(!comp))
|
||||
if (!comp) {
|
||||
pr_info_once("There is no msc corresponding to CPU%d.\n", cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
|
||||
if (!dom)
|
||||
|
@ -96,6 +98,12 @@ static int mpam_resctrl_setup_domain(unsigned int cpu,
|
|||
*ctrlval_ptr = kmalloc_array(num_partid,
|
||||
sizeof(**ctrlval_ptr), GFP_KERNEL);
|
||||
if (!*ctrlval_ptr) {
|
||||
for_each_ctrl_type(type_free) {
|
||||
if (type_free == type)
|
||||
break;
|
||||
ctrlval_ptr = &dom->resctrl_dom.ctrl_val[type_free];
|
||||
kfree(*ctrlval_ptr);
|
||||
}
|
||||
kfree(dom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -128,7 +136,7 @@ int mpam_resctrl_cpu_online(unsigned int cpu)
|
|||
if (dom) {
|
||||
cpumask_set_cpu(cpu, &dom->resctrl_dom.cpu_mask);
|
||||
} else {
|
||||
ret = mpam_resctrl_setup_domain(cpu, res);
|
||||
ret = kunpeng_mpam_resctrl_setup_domain(cpu, res);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -156,13 +164,16 @@ int mpam_resctrl_cpu_offline(unsigned int cpu)
|
|||
struct rdt_domain *d;
|
||||
struct mpam_resctrl_res *res;
|
||||
struct mpam_resctrl_dom *dom;
|
||||
u32 **ctrlval_ptr;
|
||||
enum resctrl_ctrl_type type;
|
||||
|
||||
for_each_supported_resctrl_exports(res) {
|
||||
d = resctrl_get_domain_from_cpu(cpu, &res->resctrl_res);
|
||||
|
||||
/* cpu with unknown exported component? */
|
||||
if (WARN_ON_ONCE(!d))
|
||||
if (!d) {
|
||||
pr_info_once("There is no msc corresponding to CPU%d.\n", cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
cpumask_clear_cpu(cpu, &d->cpu_mask);
|
||||
|
||||
|
@ -171,7 +182,14 @@ int mpam_resctrl_cpu_offline(unsigned int cpu)
|
|||
|
||||
list_del(&d->list);
|
||||
dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom);
|
||||
for_each_ctrl_type(type) {
|
||||
ctrlval_ptr = &dom->resctrl_dom.ctrl_val[type];
|
||||
kfree(*ctrlval_ptr);
|
||||
}
|
||||
|
||||
kfree(dom);
|
||||
|
||||
res->resctrl_res.dom_num--;
|
||||
}
|
||||
|
||||
mpam_resctrl_clear_default_cpu(cpu);
|
||||
|
@ -335,6 +353,7 @@ static void mpam_resctrl_pick_event_mbm_local(void)
|
|||
|
||||
if (mpam_has_feature(mpam_feat_msmon_mbwu, res->class->features)) {
|
||||
res->resctrl_res.mon_capable = true;
|
||||
rdt_mon_capable = true;
|
||||
mpam_resctrl_events[QOS_L3_MBM_LOCAL_EVENT_ID] = *res;
|
||||
}
|
||||
}
|
||||
|
@ -416,6 +435,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res)
|
|||
* of 1 would appear too fine to make percentage conversions.
|
||||
*/
|
||||
r->mbw.bw_gran = GRAN_MBA_BW;
|
||||
/* do not allow mbw_max/min below mbw.bw_gran */
|
||||
if (r->mbw.min_bw < r->mbw.bw_gran)
|
||||
r->mbw.min_bw = r->mbw.bw_gran;
|
||||
|
||||
/* We will only pick a class that can monitor and control */
|
||||
r->alloc_capable = true;
|
||||
|
|
|
@ -1386,6 +1386,9 @@ int acpi_pptt_get_cpus_from_container(u32 acpi_cpu_id, cpumask_t *cpus);
|
|||
int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus);
|
||||
int acpi_pptt_get_cpumask_from_cache_id_and_level(u32 cache_id, u32 cache_level,
|
||||
cpumask_t *cpus);
|
||||
#ifdef CONFIG_KUNPENG_MPAM
|
||||
struct acpi_pptt_processor *find_acpi_processor_node_from_cache_id(u32 cache_id);
|
||||
#endif
|
||||
#else
|
||||
static inline int acpi_pptt_cpu_is_thread(unsigned int cpu)
|
||||
{
|
||||
|
@ -1445,6 +1448,12 @@ static inline int acpi_pptt_get_cpumask_from_cache_id_and_level(u32 cache_id,
|
|||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifdef CONFIG_KUNPENG_MPAM
|
||||
static inline struct acpi_pptt_processor *find_acpi_processor_node_from_cache_id(u32 cache_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_PCC
|
||||
|
|
Loading…
Reference in New Issue