Commit e37caef1 authored by Yang Yingliang's avatar Yang Yingliang Committed by Zheng Zengkai
Browse files

resctrlfs: mpam: Build basic framework for mpam



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

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

Build basic framework for mpam.

Signed-off-by: default avatarXie XiuQi <xiexiuqi@huawei.com>
Reviewed-by: default avatarHanjun Guo <guohanjun@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Reviewed-by: default avatarCheng Jian <cj.chengjian@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 6065f551
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -990,6 +990,14 @@ config HOTPLUG_CPU
	  Say Y here to experiment with turning CPUs off and on.  CPUs
	  can be controlled through /sys/devices/system/cpu.

config MPAM
	bool "Support Memory Partitioning and Monitoring"
	default n
	select RESCTRL
	help
	  Memory Partitioning and Monitoring. More exactly Memory system
	  performance resource Partitioning and Monitoring

# Common NUMA Features
config NUMA
	bool "NUMA Memory Allocation and Scheduler Support"
+335 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_ARM64_MPAM_H
#define _ASM_ARM64_MPAM_H

#include <linux/sched.h>
#include <linux/kernfs.h>
#include <linux/jump_label.h>

#include <linux/seq_buf.h>
#include <linux/seq_file.h>

/* MPAM register */
#define SYS_MPAM0_EL1			sys_reg(3, 0, 10, 5, 1)
#define SYS_MPAM1_EL1			sys_reg(3, 0, 10, 5, 0)
#define SYS_MPAM2_EL2			sys_reg(3, 4, 10, 5, 0)
#define SYS_MPAM3_EL3			sys_reg(3, 6, 10, 5, 0)
#define SYS_MPAM1_EL12			sys_reg(3, 5, 10, 5, 0)
#define SYS_MPAMHCR_EL2			sys_reg(3, 4, 10, 4, 0)
#define SYS_MPAMVPMV_EL2		sys_reg(3, 4, 10, 4, 1)
#define SYS_MPAMVPMn_EL2(n)		sys_reg(3, 4, 10, 6, n)
#define SYS_MPAMIDR_EL1			sys_reg(3, 0, 10, 4, 4)

#define MPAM_MASK(n)			((1UL << n) - 1)
/* plan to use GENMASK(n, 0) instead */

/*
 * MPAMx_ELn:
 * 15:0		PARTID_I
 * 31:16	PARTID_D
 * 39:32	PMG_I
 * 47:40	PMG_D
 * 48		TRAPMPAM1EL1
 * 49		TRAPMPAM0EL1
 * 61:49	Reserved
 * 62		TRAPLOWER
 * 63		MPAMEN
 */
#define PARTID_BITS			(16)
#define PMG_BITS			(8)
#define PARTID_MASK			MPAM_MASK(PARTID_BITS)
#define PMG_MASK			MPAM_MASK(PMG_BITS)

#define PARTID_I_SHIFT			(0)
#define PARTID_D_SHIFT			(PARTID_I_SHIFT + PARTID_BITS)
#define PMG_I_SHIFT			(PARTID_D_SHIFT + PARTID_BITS)
#define PMG_D_SHIFT			(PMG_I_SHIFT + PMG_BITS)

#define PARTID_I_MASK			(PARTID_MASK << PARTID_I_SHIFT)
#define PARTID_D_MASK			(PARTID_MASK << PARTID_D_SHIFT)
#define PARTID_I_CLR(r)			((r) & ~PARTID_I_MASK)
#define PARTID_D_CLR(r)			((r) & ~PARTID_D_MASK)
#define PARTID_CLR(r)			(PARTID_I_CLR(r) & PARTID_D_CLR(r))

#define PARTID_I_SET(r, id)		(PARTID_I_CLR(r) | ((id) << PARTID_I_SHIFT))
#define PARTID_D_SET(r, id)		(PARTID_D_CLR(r) | ((id) << PARTID_D_SHIFT))
#define PARTID_SET(r, id)		(PARTID_CLR(r) | ((id) << PARTID_I_SHIFT) | ((id) << PARTID_D_SHIFT))

#define PMG_I_MASK			(PMG_MASK << PMG_I_SHIFT)
#define PMG_D_MASK			(PMG_MASK << PMG_D_SHIFT)
#define PMG_I_CLR(r)			((r) & ~PMG_I_MASK)
#define PMG_D_CLR(r)			((r) & ~PMG_D_MASK)
#define PMG_CLR(r)			(PMG_I_CLR(r) & PMG_D_CLR(r))

#define PMG_I_SET(r, id)		(PMG_I_CLR(r) | ((id) << PMG_I_SHIFT))
#define PMG_D_SET(r, id)		(PMG_D_CLR(r) | ((id) << PMG_D_SHIFT))
#define PMG_SET(r, id)			(PMG_CLR(r) | ((id) << PMG_I_SHIFT) | ((id) << PMG_D_SHIFT))

#define TRAPMPAM1EL1_SHIFT		(PMG_D_SHIFT + PMG_BITS)
#define TRAPMPAM0EL1_SHIFT		(TRAPMPAM1EL1_SHIFT + 1)
#define TRAPLOWER_SHIFT			(TRAPMPAM0EL1_SHIFT + 13)
#define MPAMEN_SHIFT			(TRAPLOWER_SHIFT + 1)

/*
 * MPAMHCR_EL2:
 * 0		EL0_VPMEN
 * 1		EL1_VPMEN
 * 7:2		Reserved
 * 8		GSTAPP_PLK
 * 30:9		Reserved
 * 31		TRAP_MPAMIDR_EL1
 * 63:32	Reserved
 */
#define EL0_VPMEN_SHIFT			(0)
#define EL1_VPMEN_SHIFT			(EL0_VPMEN_SHIFT + 1)
#define GSTAPP_PLK_SHIFT		(8)
#define TRAP_MPAMIDR_EL1_SHIFT		(31)

/*
 * MPAMIDR_EL1:
 * 15:0		PARTID_MAX
 * 16		Reserved
 * 17		HAS_HCR
 * 20:18	VPMR_MAX
 * 31:21	Reserved
 * 39:32	PMG_MAX
 * 63:40	Reserved
 */
#define VPMR_MAX_BITS			(3)
#define PARTID_MAX_SHIFT		(0)
#define HAS_HCR_SHIFT			(PARTID_MAX_SHIFT + PARTID_BITS + 1)
#define VPMR_MAX_SHIFT			(HAS_HCR_SHIFT + 1)
#define PMG_MAX_SHIFT			(VPMR_MAX_SHIFT + VPMR_MAX_BITS + 11)
#define VPMR_MASK			MPAM_MASK(VPMR_MAX_BITS)

/*
 * MPAMVPMV_EL2:
 * 31:0		VPM_V
 * 63:32	Reserved
 */
#define VPM_V_BITS			32

DECLARE_STATIC_KEY_FALSE(resctrl_enable_key);
DECLARE_STATIC_KEY_FALSE(resctrl_mon_enable_key);

extern bool rdt_alloc_capable;
extern bool rdt_mon_capable;

enum rdt_group_type {
	RDTCTRL_GROUP = 0,
	RDTMON_GROUP,
	RDT_NUM_GROUP,
};

/**
 * struct mongroup - store mon group's data in resctrl fs.
 * @mon_data_kn		kernlfs node for the mon_data directory
 * @parent:			parent rdtgrp
 * @crdtgrp_list:		child rdtgroup node list
 * @rmid:			rmid for this rdtgroup
 */
struct mongroup {
	struct kernfs_node	*mon_data_kn;
	struct rdtgroup		*parent;
	struct list_head	crdtgrp_list;
	u32			rmid;
};

/**
 * struct rdtgroup - store rdtgroup's data in resctrl file system.
 * @kn:				kernfs node
 * @resctrl_group_list:		linked list for all rdtgroups
 * @closid:			closid for this rdtgroup
 * #endif
 * @cpu_mask:			CPUs assigned to this rdtgroup
 * @flags:			status bits
 * @waitcount:			how many cpus expect to find this
 *				group when they acquire resctrl_group_mutex
 * @type:			indicates type of this rdtgroup - either
 *				monitor only or ctrl_mon group
 * @mon:			mongroup related data
 */
struct rdtgroup {
	struct kernfs_node	*kn;
	struct list_head	resctrl_group_list;
	u32			closid;
	struct cpumask		cpu_mask;
	int			flags;
	atomic_t		waitcount;
	enum rdt_group_type	type;
	struct mongroup		mon;
};

extern int max_name_width, max_data_width;

/* rdtgroup.flags */
#define	RDT_DELETED		1

/**
 * struct rdt_domain - group of cpus sharing an RDT resource
 * @list:	all instances of this resource
 * @id:		unique id for this instance
 * @cpu_mask:	which cpus share this resource
 * @rmid_busy_llc:
 *		bitmap of which limbo RMIDs are above threshold
 * @mbm_total:	saved state for MBM total bandwidth
 * @mbm_local:	saved state for MBM local bandwidth
 * @mbm_over:	worker to periodically read MBM h/w counters
 * @cqm_limbo:	worker to periodically read CQM h/w counters
 * @mbm_work_cpu:
 *		worker cpu for MBM h/w counters
 * @cqm_work_cpu:
 *		worker cpu for CQM h/w counters
 * @ctrl_val:	array of cache or mem ctrl values (indexed by CLOSID)
 * @new_ctrl:	new ctrl value to be loaded
 * @have_new_ctrl: did user provide new_ctrl for this domain
 */
struct rdt_domain {
	struct list_head	list;
	int			id;
	struct cpumask		cpu_mask;
	void __iomem		*base;

	/* arch specific fields */
	u32			*ctrl_val;
	u32			new_ctrl;
	bool			have_new_ctrl;

	/* for debug */
	char			*cpus_list;
};

extern struct mutex resctrl_group_mutex;

extern struct resctrl_resource resctrl_resources_all[];

int __init resctrl_group_init(void);

enum {
	MPAM_RESOURCE_SMMU,
	MPAM_RESOURCE_CACHE,
	MPAM_RESOURCE_MC,

	/* Must be the last */
	MPAM_NUM_RESOURCES,
};

void rdt_last_cmd_clear(void);
void rdt_last_cmd_puts(const char *s);
void rdt_last_cmd_printf(const char *fmt, ...);

int alloc_rmid(void);
void free_rmid(u32 rmid);
int resctrl_group_mondata_show(struct seq_file *m, void *arg);
void rmdir_mondata_subdir_allrdtgrp(struct resctrl_resource *r,
				    unsigned int dom_id);
void mkdir_mondata_subdir_allrdtgrp(struct resctrl_resource *r,
				    struct rdt_domain *d);

void closid_init(void);
int closid_alloc(void);
void closid_free(int closid);

int cdp_enable(int level, int data_type, int code_type);
void resctrl_resource_reset(void);
void release_rdtgroupfs_options(void);
int parse_rdtgroupfs_options(char *data);

static inline int __resctrl_group_show_options(struct seq_file *seq)
{
	return 0;
}

void post_resctrl_mount(void);

#define MPAM_SYS_REG_DEBUG

#ifdef MPAM_SYS_REG_DEBUG
static inline u64 mpam_read_sysreg_s(u64 reg, char *name)
{
	pr_info("cpu %2d (cur: %s(%d)): read_sysreg_s: %s (addr %016llx)\n",
		smp_processor_id(), current->comm, current->pid, name, reg);
	return 0;
}
#else
#define mpam_read_sysreg_s(reg, name) read_sysreg_s(reg)
#endif

#ifdef MPAM_SYS_REG_DEBUG
static inline u64 mpam_write_sysreg_s(u64 v, u64 reg, char *name)
{
	pr_info("cpu %2d (cur %s(%d)): write_sysreg_s: %s (addr %016llx), value %016llx\n",
		smp_processor_id(), current->comm, current->pid, name, reg, v);
	return 0;
}
#else
#define mpam_write_sysreg_s(v, r, n) write_sysreg_s(v, r)
#endif

#ifdef MPAM_SYS_REG_DEBUG
static inline u32 mpam_readl(const volatile void __iomem *addr)
{
	return pr_info("readl: %016llx\n", (u64)addr);
}
#else
#define mpam_readl(addr) readl(addr)
#endif

#ifdef MPAM_SYS_REG_DEBUG
static inline u32 mpam_writel(u64 v, const volatile void __iomem *addr)
{
	return pr_info("writel: %016llx to %016llx\n", v, (u64)addr);
}
#else
#define mpam_writel(v, addr) writel(v, addr)
#endif

/**
 * struct msr_param - set a range of MSRs from a domain
 * @res:	The resource to use
 * @value:	value
 */
struct msr_param {
	struct resctrl_resource	*res;
	u64			value;
};

/**
 * struct resctrl_resource - attributes of an RDT resource
 * @rid:		The index of the resource
 * @alloc_enabled:	Is allocation enabled on this machine
 * @mon_enabled:		Is monitoring enabled for this feature
 * @alloc_capable:	Is allocation available on this machine
 * @mon_capable:		Is monitor feature available on this machine
 * @name:		Name to use in "schemata" file
 * @num_closid:		Number of CLOSIDs available
 * @cache_level:	Which cache level defines scope of this resource
 * @default_ctrl:	Specifies default cache cbm or memory B/W percent.
 * @msr_base:		Base MSR address for CBMs
 * @msr_update:		Function pointer to update QOS MSRs
 * @data_width:		Character width of data when displaying
 * @domains:		All domains for this resource
 * @cache:		Cache allocation related data
 * @format_str:		Per resource format string to show domain value
 * @parse_ctrlval:	Per resource function pointer to parse control values
 * @evt_list:			List of monitoring events
 * @num_rmid:			Number of RMIDs available
 * @mon_scale:			cqm counter * mon_scale = occupancy in bytes
 * @fflags:			flags to choose base and info files
 */

struct raw_resctrl_resource {
	int			num_partid;
	u32			default_ctrl;
	void (*msr_update)	(struct rdt_domain *d, int partid);
	u64  (*msr_read)	(struct rdt_domain *d, int partid);
	int			data_width;
	const char		*format_str;
	int (*parse_ctrlval)	(char *buf, struct raw_resctrl_resource *r,
				 struct rdt_domain *d);
	int			num_pmg;
};

int parse_cbm(char *buf, struct raw_resctrl_resource *r, struct rdt_domain *d);

#endif /* _ASM_ARM64_MPAM_H */
+84 −0
Original line number Diff line number Diff line
/* mpam resource: like L3, memory */

#ifndef _ASM_ARM64_MPAM_RESOURCE_H
#define _ASM_ARM64_MPAM_RESOURCE_H

#include <linux/bitops.h>

#define MPAMF_IDR		0x0000
#define MPAMF_SIDR		0x0008
#define MPAMF_MSMON_IDR		0x0080
#define MPAMF_IMPL_IDR		0x0028
#define MPAMF_CPOR_IDR		0x0030
#define MPAMF_CCAP_IDR		0x0038
#define MPAMF_MBW_IDR		0x0040
#define MPAMF_PRI_IDR		0x0048
#define MPAMF_CSUMON_IDR	0x0088
#define MPAMF_MBWUMON_IDR	0x0090
#define MPAMF_PARTID_NRW_IDR	0x0050
#define MPAMF_IIDR		0x0018
#define MPAMF_AIDR		0x0020
#define MPAMCFG_PART_SEL	0x0100
#define MPAMCFG_CPBM		0x1000
#define MPAMCFG_CMAX		0x0108
#define MPAMCFG_MBW_MIN		0x0200
#define MPAMCFG_MBW_MAX		0x0208
#define MPAMCFG_MBW_WINWD	0x0220
#define MPAMCFG_MBW_PBM		0x2000
#define MPAMCFG_PRI		0x0400
#define MPAMCFG_MBW_PROP	0x0500
#define MPAMCFG_INTPARTID	0x0600
#define MSMON_CFG_MON_SEL	0x0800
#define MSMON_CFG_CSU_FLT	0x0810
#define MSMON_CFG_CSU_CTL	0x0818
#define MSMON_CFG_MBWU_FLT	0x0820
#define MSMON_CFG_MBWU_CTL	0x0828
#define MSMON_CSU		0x0840
#define MSMON_CSU_CAPTURE	0x0848
#define MSMON_MBWU		0x0860
#define MSMON_MBWU_CAPTURE	0x0868
#define MSMON_CAPT_EVNT		0x0808
#define MPAMF_ESR		0x00F8
#define MPAMF_ECR		0x00F0

#define HAS_CCAP_PART		BIT(24)
#define HAS_CPOR_PART		BIT(25)
#define HAS_MBW_PART		BIT(26)
#define HAS_PRI_PART		BIT(27)
#define HAS_IMPL_IDR		BIT(29)
#define HAS_MSMON		BIT(30)

/* MPAMF_IDR */
/* TODO */

#define CPBM_WD_MASK		0xFFFF
#define CPBM_MASK		0x7FFF

#define BWA_WD			6		/* hard code for P680 */
#define MBW_MAX_MASK		0xFC00
#define MBW_MAX_HARDLIM		BIT(31)

/* [FIXME] hard code for hardlim */
#define MBW_MAX_SET(v)		(MBW_MAX_HARDLIM|((v) << (15 - BWA_WD)))
#define MBW_MAX_GET(v)		(((v) & MBW_MAX_MASK) >> (15 - BWA_WD))
/*
 * emulate the mpam nodes
 * These should be reported by ACPI MPAM Table.
 */

struct mpam_node {
	/* 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;
};

int mpam_nodes_init(void);

#endif /* _ASM_ARM64_MPAM_RESOURCE_H */
+48 −0
Original line number Diff line number Diff line
#ifndef _ASM_ARM64_MPAM_SCHED_H
#define _ASM_ARM64_MPAM_SCHED_H

#ifdef CONFIG_MPAM

#include <linux/sched.h>
#include <linux/jump_label.h>

/**
 * struct intel_pqr_state - State cache for the PQR MSR
 * @cur_rmid:		The cached Resource Monitoring ID
 * @cur_closid:	The cached Class Of Service ID
 * @default_rmid:	The user assigned Resource Monitoring ID
 * @default_closid:	The user assigned cached Class Of Service ID
 *
 * The upper 32 bits of IA32_PQR_ASSOC contain closid and the
 * lower 10 bits rmid. The update to IA32_PQR_ASSOC always
 * contains both parts, so we need to cache them. This also
 * stores the user configured per cpu CLOSID and RMID.
 *
 * The cache also helps to avoid pointless updates if the value does
 * not change.
 */
struct intel_pqr_state {
	u32			cur_rmid;
	u32			cur_closid;
	u32			default_rmid;
	u32			default_closid;
};

DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);

extern void __mpam_sched_in(void);
DECLARE_STATIC_KEY_FALSE(resctrl_enable_key);

static inline void mpam_sched_in(void)
{
	if (static_branch_likely(&resctrl_enable_key))
		__mpam_sched_in();
}

#else

static inline void mpam_sched_in(void) {}

#endif /* CONFIG_MPAM */

#endif
+66 −0
Original line number Diff line number Diff line
#ifndef _ASM_ARM64_RESCTRL_H
#define _ASM_ARM64_RESCTRL_H

#include <asm/mpam_sched.h>
#include <asm/mpam.h>

#define resctrl_group rdtgroup
#define resctrl_alloc_capable rdt_alloc_capable
#define resctrl_mon_capable rdt_mon_capable

static inline int alloc_mon_id(void)
{

	return alloc_rmid();
}

static inline void free_mon_id(u32 id)
{
	free_rmid(id);
}

void pmg_init(void);
static inline void resctrl_id_init(void)
{
	closid_init();
	pmg_init();
}

static inline int resctrl_id_alloc(void)
{
	return closid_alloc();
}

static inline void resctrl_id_free(int id)
{
	closid_free(id);
}

void update_cpu_closid_rmid(void *info);
void update_closid_rmid(const struct cpumask *cpu_mask, struct resctrl_group *r);
int __resctrl_group_move_task(struct task_struct *tsk,
				struct resctrl_group *rdtgrp);

ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of,
				char *buf, size_t nbytes, loff_t off);

int resctrl_group_schemata_show(struct kernfs_open_file *of,
				struct seq_file *s, void *v);

#define release_resctrl_group_fs_options release_rdtgroupfs_options
#define parse_resctrl_group_fs_options parse_rdtgroupfs_options

#define for_each_resctrl_resource(r)					\
	for (r = resctrl_resources_all;					\
	     r < resctrl_resources_all + MPAM_NUM_RESOURCES;		\
	     r++)							\

int mkdir_mondata_all(struct kernfs_node *parent_kn,
			     struct resctrl_group *prgrp,
			     struct kernfs_node **dest_kn);

int
mongroup_create_dir(struct kernfs_node *parent_kn, struct resctrl_group *prgrp,
		    char *name, struct kernfs_node **dest_kn);

#endif /* _ASM_ARM64_RESCTRL_H */
Loading