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:
Min Li 2024-12-19 17:38:48 +08:00 committed by 小龙
parent ae47be59cf
commit e1ccf88ee9
25 changed files with 1403 additions and 414 deletions

View File

@ -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>;
};
};

View File

@ -0,0 +1 @@
CONFIG_KUNPENG_MPAM=y

View File

@ -0,0 +1 @@
CONFIG_KUNPENG_RESCTRL=y

View File

@ -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 !!! */

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# ACPI Configuration for ARM64
#
config ACPI_MPAM
bool

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
ccflags-y := -I$(srctree)/$(src)/../include
obj-$(CONFIG_KUNPENG_RESCTRL) += resctrlfs.o

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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, &para);
/*
* 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, &para);
}
}
}
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, &para);
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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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