/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _RESCTRL_H
#define _RESCTRL_H

#include <linux/cacheinfo.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pid.h>
#include <linux/resctrl_types.h>

#ifdef CONFIG_ARCH_HAS_CPU_RESCTRL
#include <asm/resctrl.h>
#endif


#define RESCTRL_RESERVED_CLOSID		0
#define RESCTRL_RESERVED_RMID		0

#define RESCTRL_PICK_ANY_CPU		-1

#ifdef CONFIG_PROC_CPU_RESCTRL

int proc_resctrl_show(struct seq_file *m,
		      struct pid_namespace *ns,
		      struct pid *pid,
		      struct task_struct *tsk);

#endif


#define MBA_MAX_MBPS   U32_MAX


#define for_each_rdt_resource(_r)						\
	for ((_r) = resctrl_arch_get_resource(0);				\
	     (_r) && (_r)->rid < RDT_NUM_RESOURCES;				\
	     (_r) = resctrl_arch_get_resource((_r)->rid + 1))

#define for_each_capable_rdt_resource(r)				      \
	for_each_rdt_resource((r))					      \
		if ((r)->alloc_capable || (r)->mon_capable)

#define for_each_alloc_capable_rdt_resource(r)				      \
	for_each_rdt_resource((r))					      \
		if ((r)->alloc_capable)

#define for_each_mon_capable_rdt_resource(r)				      \
	for_each_rdt_resource((r))					      \
		if ((r)->mon_capable)

enum resctrl_res_level {
	RDT_RESOURCE_L3,
	RDT_RESOURCE_L2,
	RDT_RESOURCE_MBA,
	RDT_RESOURCE_SMBA,
	RDT_RESOURCE_PERF_PKG,

	
	RDT_NUM_RESOURCES,
};


enum resctrl_conf_type {
	CDP_NONE,
	CDP_CODE,
	CDP_DATA,
};

#define CDP_NUM_TYPES	(CDP_DATA + 1)


struct pseudo_lock_region {
	struct resctrl_schema	*s;
	u32			closid;
	struct rdt_ctrl_domain	*d;
	u32			cbm;
	wait_queue_head_t	lock_thread_wq;
	int			thread_done;
	int			cpu;
	unsigned int		line_size;
	unsigned int		size;
	void			*kmem;
	unsigned int		minor;
	struct dentry		*debugfs_dir;
	struct list_head	pm_reqs;
};


struct resctrl_staged_config {
	u32			new_ctrl;
	bool			have_new_ctrl;
};

enum resctrl_domain_type {
	RESCTRL_CTRL_DOMAIN,
	RESCTRL_MON_DOMAIN,
};


struct rdt_domain_hdr {
	struct list_head		list;
	int				id;
	enum resctrl_domain_type	type;
	enum resctrl_res_level		rid;
	struct cpumask			cpu_mask;
};

static inline bool domain_header_is_valid(struct rdt_domain_hdr *hdr,
					  enum resctrl_domain_type type,
					  enum resctrl_res_level rid)
{
	return !WARN_ON_ONCE(hdr->type != type || hdr->rid != rid);
}


struct rdt_ctrl_domain {
	struct rdt_domain_hdr		hdr;
	struct pseudo_lock_region	*plr;
	struct resctrl_staged_config	staged_config[CDP_NUM_TYPES];
	u32				*mbps_val;
};


struct mbm_cntr_cfg {
	enum resctrl_event_id	evtid;
	struct rdtgroup		*rdtgrp;
};


struct rdt_l3_mon_domain {
	struct rdt_domain_hdr		hdr;
	unsigned int			ci_id;
	unsigned long			*rmid_busy_llc;
	struct mbm_state		*mbm_states[QOS_NUM_L3_MBM_EVENTS];
	struct delayed_work		mbm_over;
	struct delayed_work		cqm_limbo;
	int				mbm_work_cpu;
	int				cqm_work_cpu;
	struct mbm_cntr_cfg		*cntr_cfg;
};


struct resctrl_cache {
	unsigned int	cbm_len;
	unsigned int	min_cbm_bits;
	unsigned int	shareable_bits;
	bool		arch_has_sparse_bitmasks;
	bool		arch_has_per_cpu_cfg;
	bool		io_alloc_capable;
};


enum membw_throttle_mode {
	THREAD_THROTTLE_UNDEFINED = 0,
	THREAD_THROTTLE_MAX,
	THREAD_THROTTLE_PER_THREAD,
};


struct resctrl_membw {
	u32				min_bw;
	u32				max_bw;
	u32				bw_gran;
	u32				delay_linear;
	bool				arch_needs_linear;
	enum membw_throttle_mode	throttle_mode;
	bool				mba_sc;
	u32				*mb_map;
};

struct resctrl_schema;

enum resctrl_scope {
	RESCTRL_L2_CACHE = 2,
	RESCTRL_L3_CACHE = 3,
	RESCTRL_L3_NODE,
	RESCTRL_PACKAGE,
};


enum resctrl_schema_fmt {
	RESCTRL_SCHEMA_BITMAP,
	RESCTRL_SCHEMA_RANGE,
};


struct resctrl_mon {
	u32			num_rmid;
	unsigned int		mbm_cfg_mask;
	int			num_mbm_cntrs;
	bool			mbm_cntr_assignable;
	bool			mbm_assign_on_mkdir;
};


struct rdt_resource {
	int			rid;
	bool			alloc_capable;
	bool			mon_capable;
	enum resctrl_scope	ctrl_scope;
	enum resctrl_scope	mon_scope;
	struct resctrl_cache	cache;
	struct resctrl_membw	membw;
	struct resctrl_mon	mon;
	struct list_head	ctrl_domains;
	struct list_head	mon_domains;
	char			*name;
	enum resctrl_schema_fmt	schema_fmt;
	bool			cdp_capable;
};


struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l);


struct resctrl_schema {
	struct list_head		list;
	char				name[8];
	const char			*fmt_str;
	enum resctrl_conf_type		conf_type;
	struct rdt_resource		*res;
	u32				num_closid;
};

struct resctrl_cpu_defaults {
	u32 closid;
	u32 rmid;
};

struct resctrl_mon_config_info {
	struct rdt_resource		*r;
	struct rdt_l3_mon_domain	*d;
	u32				evtid;
	u32				mon_config;
};


void resctrl_arch_sync_cpu_closid_rmid(void *info);


static inline u32 resctrl_get_default_ctrl(struct rdt_resource *r)
{
	switch (r->schema_fmt) {
	case RESCTRL_SCHEMA_BITMAP:
		return BIT_MASK(r->cache.cbm_len) - 1;
	case RESCTRL_SCHEMA_RANGE:
		return r->membw.max_bw;
	}

	return WARN_ON_ONCE(1);
}


u32 resctrl_arch_get_num_closid(struct rdt_resource *r);
u32 resctrl_arch_system_num_rmid_idx(void);
int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid);

bool resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu,
			      unsigned int binary_bits, void *arch_priv);

bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid);

bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt);

static inline bool resctrl_is_mbm_event(enum resctrl_event_id eventid)
{
	return (eventid >= QOS_L3_MBM_TOTAL_EVENT_ID &&
		eventid <= QOS_L3_MBM_LOCAL_EVENT_ID);
}

u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id eventid);


#define for_each_mbm_event_id(eventid)				\
	for (eventid = QOS_L3_MBM_TOTAL_EVENT_ID;		\
	     eventid <= QOS_L3_MBM_LOCAL_EVENT_ID; eventid++)


#define for_each_mbm_idx(idx)					\
	for (idx = 0; idx < QOS_NUM_L3_MBM_EVENTS; idx++)


void resctrl_arch_mon_event_config_write(void *config_info);


void resctrl_arch_mon_event_config_read(void *config_info);


static inline u32 resctrl_get_config_index(u32 closid,
					   enum resctrl_conf_type type)
{
	switch (type) {
	default:
	case CDP_NONE:
		return closid;
	case CDP_CODE:
		return closid * 2 + 1;
	case CDP_DATA:
		return closid * 2;
	}
}

bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l);
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable);


bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r);


int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable);


int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
			    u32 closid, enum resctrl_conf_type t, u32 cfg_val);

u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
			    u32 closid, enum resctrl_conf_type type);
int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d);
int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr);
void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d);
void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr);
void resctrl_online_cpu(unsigned int cpu);
void resctrl_offline_cpu(unsigned int cpu);


void resctrl_arch_pre_mount(void);


int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
			   void *arch_priv, u64 *val, void *arch_mon_ctx);


static inline void resctrl_arch_rmid_read_context_check(void)
{
	if (!irqs_disabled())
		might_sleep();
}


struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id,
					   struct list_head **pos);


void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
			     u32 closid, u32 rmid,
			     enum resctrl_event_id eventid);


void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d);


void resctrl_arch_reset_all_ctrls(struct rdt_resource *r);


void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
			      enum resctrl_event_id evtid, u32 rmid, u32 closid,
			      u32 cntr_id, bool assign);


int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
			   u32 closid, u32 rmid, int cntr_id,
			   enum resctrl_event_id eventid, u64 *val);


void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
			     u32 closid, u32 rmid, int cntr_id,
			     enum resctrl_event_id eventid);


int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable);


bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);

extern unsigned int resctrl_rmid_realloc_threshold;
extern unsigned int resctrl_rmid_realloc_limit;

int resctrl_init(void);
void resctrl_exit(void);

#ifdef CONFIG_RESCTRL_FS_PSEUDO_LOCK
u64 resctrl_arch_get_prefetch_disable_bits(void);
int resctrl_arch_pseudo_lock_fn(void *_plr);
int resctrl_arch_measure_cycles_lat_fn(void *_plr);
int resctrl_arch_measure_l2_residency(void *_plr);
int resctrl_arch_measure_l3_residency(void *_plr);
#else
static inline u64 resctrl_arch_get_prefetch_disable_bits(void) { return 0; }
static inline int resctrl_arch_pseudo_lock_fn(void *_plr) { return 0; }
static inline int resctrl_arch_measure_cycles_lat_fn(void *_plr) { return 0; }
static inline int resctrl_arch_measure_l2_residency(void *_plr) { return 0; }
static inline int resctrl_arch_measure_l3_residency(void *_plr) { return 0; }
#endif 
#endif 
