Commit f0218c23 authored by Wang ShaoBo's avatar Wang ShaoBo Committed by Zheng Zengkai
Browse files

arm64/mpam: Migrate old MSCs' discovery process to new branch



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

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

We used to make use of mpam_node structure to initialize MSCs and directly
use resctrl_resource structure to store the MSCs' probing information
before, it's a good choice until we support multiple MSC's node per domain,
so far this new framework mpam_device->mpam_component->mpam_class has been
constructed, we should make MPAM setup process compatible with this new
framework firstly.

At present, we only parsed the base address to create the mpam devices, but
did not deal with the interruption registration issue, which will be dealt
with later.

We will continue to update discovery process from MPAM ACPI tlb according to
latest MPAM ACPI spec.

Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Reviewed-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: default avatarCheng Jian <cj.chengjian@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 8a1b4a0d
Loading
Loading
Loading
Loading
+0 −33
Original line number Diff line number Diff line
@@ -207,37 +207,4 @@
/* hard code for mbw_max max-percentage's cresponding masks */
#define MBA_MAX_WD 63u

/*
 * emulate the mpam nodes
 * These should be reported by ACPI MPAM Table.
 */

struct mpam_node {
	/* for label mpam_node instance*/
	u32 component_id;
	/* MPAM node header */
	u8              type;   /* MPAM_SMMU, MPAM_CACHE, MPAM_MC */
	u64             addr;
	void __iomem	*base;
	struct cpumask  cpu_mask;
	u64		default_ctrl;

	/* for debug */
	char            *cpus_list;
	char		*name;
	struct list_head list;
};

int __init mpam_force_init(void);

int __init mpam_nodes_discovery_start(void);

void __init mpam_nodes_discovery_failed(void);

int __init mpam_nodes_discovery_complete(void);

int mpam_create_cache_node(u32 component_id, phys_addr_t hwpage_address);

int mpam_create_memory_node(u32 component_id, phys_addr_t hwpage_address);

#endif /* _ASM_ARM64_MPAM_RESOURCE_H */
+0 −8
Original line number Diff line number Diff line
@@ -40,14 +40,6 @@ static inline void mpam_sched_in(void)
		__mpam_sched_in();
}

enum mpam_enable_type {
	enable_denied = 0,
	enable_default,
	enable_acpi,
};

extern enum mpam_enable_type __read_mostly mpam_enabled;

#else

static inline void mpam_sched_in(void) {}
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@
#include <linux/types.h>
#include <linux/cpu.h>
#include <linux/cacheinfo.h>
#include <asm/mpam.h>
#include <linux/arm_mpam.h>
#include <asm/mpam_resource.h>
#include <asm/mpam.h>

+1 −7
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <linux/err.h>
#include <linux/cpumask.h>
#include <linux/types.h>
#include <linux/arm_mpam.h>
#include "mpam_internal.h"

struct mpam_config;
@@ -15,13 +16,6 @@ struct mpam_config;
 */
#define SZ_MPAM_DEVICE  (3 * SZ_4K)

enum mpam_class_types {
	MPAM_CLASS_SMMU,
	MPAM_CLASS_CACHE,   /* Well known caches, e.g. L2 */
	MPAM_CLASS_MEMORY,  /* Main memory */
	MPAM_CLASS_UNKNOWN, /* Everything else, e.g. TLBs etc */
};

/*
 * An mpam_device corresponds to an MSC, an interface to a component's cache
 * or bandwidth controls. It is associated with a set of CPUs, and a component.
+3 −357
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/sched/signal.h>
#include <linux/sched/task.h>
#include <linux/resctrlfs.h>
#include <linux/arm_mpam.h>

#include <asm/mpam_sched.h>
#include <asm/mpam_resource.h>
@@ -90,208 +91,6 @@ void mpam_resctrl_clear_default_cpu(unsigned int cpu)
	cpumask_clear_cpu(cpu, &resctrl_group_default.cpu_mask);
}

static inline void mpam_node_assign_val(struct mpam_node *n,
				char *name,
				u8 type,
				phys_addr_t hwpage_address,
				u32 component_id)
{
	n->name = name;
	n->type = type;
	n->addr = hwpage_address;
	n->component_id = component_id;
	n->cpus_list = "0";
}

#define MPAM_NODE_NAME_SIZE (10)

struct mpam_node *mpam_nodes_ptr;

static int __init mpam_init(void);

static void mpam_nodes_unmap(void)
{
	struct mpam_node *n;

	list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
		if (n->base) {
			iounmap(n->base);
			n->base = NULL;
		}
	}
}

static int mpam_nodes_init(void)
{
	int ret = 0;
	struct mpam_node *n;

	list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
		ret |= cpulist_parse(n->cpus_list, &n->cpu_mask);
		n->base = ioremap(n->addr, 0x10000);
		if (!n->base) {
			mpam_nodes_unmap();
			return -ENOMEM;
		}
	}

	return ret;
}

static void mpam_nodes_destroy(void)
{
	struct mpam_node *n, *tmp;

	if (!mpam_nodes_ptr)
		return;

	list_for_each_entry_safe(n, tmp, &mpam_nodes_ptr->list, list) {
		kfree(n->name);
		list_del(&n->list);
		kfree(n);
	}

	list_del(&mpam_nodes_ptr->list);
	kfree(mpam_nodes_ptr);
	mpam_nodes_ptr = NULL;
}

int __init mpam_nodes_discovery_start(void)
{
	if (!mpam_enabled)
		return -EINVAL;

	mpam_nodes_ptr = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
	if (!mpam_nodes_ptr)
		return -ENOMEM;

	INIT_LIST_HEAD(&mpam_nodes_ptr->list);

	return 0;
}

void __init mpam_nodes_discovery_failed(void)
{
	mpam_nodes_destroy();
}

int __init mpam_nodes_discovery_complete(void)
{
	return mpam_init();
}

static inline int validate_mpam_node(int type,
				int component_id)
{
	int ret = 0;
	struct mpam_node *n;

	list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
		if (n->component_id == component_id &&
				n->type == type) {
			ret = -EINVAL;
			break;
		}
	}

	return ret;
}

int mpam_create_cache_node(u32 component_id,
			phys_addr_t hwpage_address)
{
	struct mpam_node *new;
	char *name;

	if (validate_mpam_node(RDT_RESOURCE_L3, component_id))
		goto skip;

	new = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
	if (!new)
		return -ENOMEM;

	name = kzalloc(MPAM_NODE_NAME_SIZE, GFP_KERNEL);
	if (!name) {
		kfree(new);
		return -ENOMEM;
	}
	snprintf(name, MPAM_NODE_NAME_SIZE, "%s%d", "L3TALL", component_id);

	mpam_node_assign_val(new,
			name,
			RDT_RESOURCE_L3,
			hwpage_address,
			component_id);
	list_add_tail(&new->list, &mpam_nodes_ptr->list);

skip:
	return 0;
}

int mpam_create_memory_node(u32 component_id,
			phys_addr_t hwpage_address)
{
	struct mpam_node *new;
	char *name;

	if (validate_mpam_node(RDT_RESOURCE_MC, component_id))
		goto skip;

	new = kzalloc(sizeof(struct mpam_node), GFP_KERNEL);
	if (!new)
		return -ENOMEM;

	name = kzalloc(MPAM_NODE_NAME_SIZE, GFP_KERNEL);
	if (!name) {
		kfree(new);
		return -ENOMEM;
	}
	snprintf(name, MPAM_NODE_NAME_SIZE, "%s%d", "HHAALL", component_id);

	mpam_node_assign_val(new,
			name,
			RDT_RESOURCE_MC,
			hwpage_address,
			component_id);
	list_add_tail(&new->list, &mpam_nodes_ptr->list);

skip:
	return 0;

}

int __init mpam_force_init(void)
{
	int ret;

	if (mpam_enabled != enable_default)
		return 0;

	ret = mpam_nodes_discovery_start();
	if (ret)
		return ret;

	ret |= mpam_create_cache_node(0, 0x000098b90000ULL);
	ret |= mpam_create_cache_node(1, 0x000090b90000ULL);
	ret |= mpam_create_cache_node(2, 0x200098b90000ULL);
	ret |= mpam_create_cache_node(3, 0x200090b90000ULL);
	ret |= mpam_create_memory_node(0, 0x000098c10000ULL);
	ret |= mpam_create_memory_node(1, 0x000090c10000ULL);
	ret |= mpam_create_memory_node(2, 0x200098c10000ULL);
	ret |= mpam_create_memory_node(3, 0x200090c10000ULL);
	if (ret) {
		mpam_nodes_discovery_failed();
		pr_err("Failed to force create mpam node\n");
		return -EINVAL;
	}

	ret = mpam_nodes_discovery_complete();
	if (!ret)
		pr_info("Successfully init mpam by hardcode.\n");

	return 1;
}

static void
cat_wrmsr(struct rdt_domain *d, int partid);
static void
@@ -535,19 +334,6 @@ void closid_free(int closid)
	closid_free_map |= 1 << closid;
}

static int mpam_online_cpu(unsigned int cpu)
{
	return mpam_resctrl_set_default_cpu(cpu);
}

/* remove related resource when cpu offline */
static int mpam_offline_cpu(unsigned int cpu)
{
	mpam_resctrl_clear_default_cpu(cpu);

	return 0;
}

/*
 * Choose a width for the resource name and resource data based on the
 * resource that has widest name and cbm.
@@ -1301,156 +1087,16 @@ struct rdt_domain *mpam_find_domain(struct resctrl_resource *r, int id,
	return NULL;
}

static void mpam_domains_destroy(struct resctrl_resource *r)
{
	struct list_head *pos, *q;
	struct rdt_domain *d;

	list_for_each_safe(pos, q, &r->domains) {
		d = list_entry(pos, struct rdt_domain, list);
		list_del(pos);
		if (d) {
			kfree(d->ctrl_val);
			kfree(d);
		}
	}
}

static void mpam_domains_init(struct resctrl_resource *r)
{
	int id = 0;
	struct mpam_node *n;
	struct list_head *add_pos = NULL;
	struct rdt_domain *d;
	struct raw_resctrl_resource *rr = (struct raw_resctrl_resource *)r->res;
	u32 val;

	list_for_each_entry(n, &mpam_nodes_ptr->list, list) {
		if (r->rid != n->type)
			continue;

		d = mpam_find_domain(r, id, &add_pos);
		if (IS_ERR(d)) {
			mpam_domains_destroy(r);
			pr_warn("Could't find cache id %d\n", id);
			return;
		}

		if (!d)
			d = kzalloc(sizeof(*d), GFP_KERNEL);
		else
			continue;

		if (!d) {
			mpam_domains_destroy(r);
			return;
		}

		d->id = id;
		d->base = n->base;
		cpumask_copy(&d->cpu_mask, &n->cpu_mask);
		rr->default_ctrl = n->default_ctrl;

		val = mpam_readl(d->base + MPAMF_IDR);
		rr->num_partid = MPAMF_IDR_PARTID_MAX_GET(val) + 1;
		rr->num_pmg = MPAMF_IDR_PMG_MAX_GET(val) + 1;

		r->mon_capable = MPAMF_IDR_HAS_MSMON(val);
		r->mon_enabled = MPAMF_IDR_HAS_MSMON(val);

		if (r->rid == RDT_RESOURCE_L3) {
			r->alloc_capable = MPAMF_IDR_HAS_CPOR_PART(val);
			r->alloc_enabled = MPAMF_IDR_HAS_CPOR_PART(val);

			val = mpam_readl(d->base + MPAMF_CSUMON_IDR);
			rr->num_mon = MPAMF_IDR_NUM_MON(val);
		} else if (r->rid == RDT_RESOURCE_MC) {
			r->alloc_capable = MPAMF_IDR_HAS_MBW_PART(val);
			r->alloc_enabled = MPAMF_IDR_HAS_MBW_PART(val);

			val = mpam_readl(d->base + MPAMF_MBWUMON_IDR);
			rr->num_mon = MPAMF_IDR_NUM_MON(val);
		}

		r->alloc_capable = 1;
		r->alloc_enabled = 1;
		r->mon_capable = 1;
		r->mon_enabled = 1;

		d->cpus_list = n->cpus_list;

		d->ctrl_val = kmalloc_array(rr->num_partid, sizeof(*d->ctrl_val), GFP_KERNEL);
		if (!d->ctrl_val) {
			kfree(d);
			mpam_domains_destroy(r);

			return;
		}

		if (add_pos)
			list_add_tail(&d->list, add_pos);

		id++;
	}
}

enum mpam_enable_type __read_mostly mpam_enabled;
static int __init mpam_setup(char *str)
{
	if (!strcmp(str, "=acpi"))
		mpam_enabled = enable_acpi;
	else
		mpam_enabled = enable_default;
		mpam_enabled = MPAM_ENABLE_ACPI;

	return 1;
}
__setup("mpam", mpam_setup);

static int __init mpam_init(void)
{
	struct resctrl_resource *r;
	int state, ret;

	rdt_alloc_capable = 1;
	rdt_mon_capable = 1;

	ret = mpam_nodes_init();
	if (ret) {
		pr_err("internal error: bad cpu list\n");
		goto out;
	}

	mpam_domains_init(&resctrl_resources_all[RDT_RESOURCE_L3]);
	mpam_domains_init(&resctrl_resources_all[RDT_RESOURCE_MC]);

	state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
				  "arm64/mpam:online:",
				  mpam_online_cpu, mpam_offline_cpu);
	if (state < 0) {
		ret = state;
		goto out;
	}

	ret = mpam_resctrl_init();
	if (ret) {
		cpuhp_remove_state(state);
		goto out;
	}

	for_each_resctrl_resource(r) {
		if (r->alloc_capable)
			pr_info("MPAM %s allocation detected\n", r->name);
	}

	for_each_resctrl_resource(r) {
		if (r->mon_capable)
			pr_info("MPAM %s monitoring detected\n", r->name);
	}

out:
	mpam_nodes_destroy();
	return ret;
}

int __init mpam_resctrl_init(void)
{
	mpam_init_padding();
Loading