cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mips-cps.h (6363B)


      1/* SPDX-License-Identifier: GPL-2.0-or-later */
      2/*
      3 * Copyright (C) 2017 Imagination Technologies
      4 * Author: Paul Burton <paul.burton@mips.com>
      5 */
      6
      7#ifndef __MIPS_ASM_MIPS_CPS_H__
      8#define __MIPS_ASM_MIPS_CPS_H__
      9
     10#include <linux/bitfield.h>
     11#include <linux/io.h>
     12#include <linux/types.h>
     13
     14extern unsigned long __cps_access_bad_size(void)
     15	__compiletime_error("Bad size for CPS accessor");
     16
     17#define CPS_ACCESSOR_A(unit, off, name)					\
     18static inline void *addr_##unit##_##name(void)				\
     19{									\
     20	return mips_##unit##_base + (off);				\
     21}
     22
     23#define CPS_ACCESSOR_R(unit, sz, name)					\
     24static inline uint##sz##_t read_##unit##_##name(void)			\
     25{									\
     26	uint64_t val64;							\
     27									\
     28	switch (sz) {							\
     29	case 32:							\
     30		return __raw_readl(addr_##unit##_##name());		\
     31									\
     32	case 64:							\
     33		if (mips_cm_is64)					\
     34			return __raw_readq(addr_##unit##_##name());	\
     35									\
     36		val64 = __raw_readl(addr_##unit##_##name() + 4);	\
     37		val64 <<= 32;						\
     38		val64 |= __raw_readl(addr_##unit##_##name());		\
     39		return val64;						\
     40									\
     41	default:							\
     42		return __cps_access_bad_size();				\
     43	}								\
     44}
     45
     46#define CPS_ACCESSOR_W(unit, sz, name)					\
     47static inline void write_##unit##_##name(uint##sz##_t val)		\
     48{									\
     49	switch (sz) {							\
     50	case 32:							\
     51		__raw_writel(val, addr_##unit##_##name());		\
     52		break;							\
     53									\
     54	case 64:							\
     55		if (mips_cm_is64) {					\
     56			__raw_writeq(val, addr_##unit##_##name());	\
     57			break;						\
     58		}							\
     59									\
     60		__raw_writel((uint64_t)val >> 32,			\
     61			     addr_##unit##_##name() + 4);		\
     62		__raw_writel(val, addr_##unit##_##name());		\
     63		break;							\
     64									\
     65	default:							\
     66		__cps_access_bad_size();				\
     67		break;							\
     68	}								\
     69}
     70
     71#define CPS_ACCESSOR_M(unit, sz, name)					\
     72static inline void change_##unit##_##name(uint##sz##_t mask,		\
     73					  uint##sz##_t val)		\
     74{									\
     75	uint##sz##_t reg_val = read_##unit##_##name();			\
     76	reg_val &= ~mask;						\
     77	reg_val |= val;							\
     78	write_##unit##_##name(reg_val);					\
     79}									\
     80									\
     81static inline void set_##unit##_##name(uint##sz##_t val)		\
     82{									\
     83	change_##unit##_##name(val, val);				\
     84}									\
     85									\
     86static inline void clear_##unit##_##name(uint##sz##_t val)		\
     87{									\
     88	change_##unit##_##name(val, 0);					\
     89}
     90
     91#define CPS_ACCESSOR_RO(unit, sz, off, name)				\
     92	CPS_ACCESSOR_A(unit, off, name)					\
     93	CPS_ACCESSOR_R(unit, sz, name)
     94
     95#define CPS_ACCESSOR_WO(unit, sz, off, name)				\
     96	CPS_ACCESSOR_A(unit, off, name)					\
     97	CPS_ACCESSOR_W(unit, sz, name)
     98
     99#define CPS_ACCESSOR_RW(unit, sz, off, name)				\
    100	CPS_ACCESSOR_A(unit, off, name)					\
    101	CPS_ACCESSOR_R(unit, sz, name)					\
    102	CPS_ACCESSOR_W(unit, sz, name)					\
    103	CPS_ACCESSOR_M(unit, sz, name)
    104
    105#include <asm/mips-cm.h>
    106#include <asm/mips-cpc.h>
    107#include <asm/mips-gic.h>
    108
    109/**
    110 * mips_cps_numclusters - return the number of clusters present in the system
    111 *
    112 * Returns the number of clusters in the system.
    113 */
    114static inline unsigned int mips_cps_numclusters(void)
    115{
    116	if (mips_cm_revision() < CM_REV_CM3_5)
    117		return 1;
    118
    119	return FIELD_GET(CM_GCR_CONFIG_NUM_CLUSTERS, read_gcr_config());
    120}
    121
    122/**
    123 * mips_cps_cluster_config - return (GCR|CPC)_CONFIG from a cluster
    124 * @cluster: the ID of the cluster whose config we want
    125 *
    126 * Read the value of GCR_CONFIG (or its CPC_CONFIG mirror) from a @cluster.
    127 *
    128 * Returns the value of GCR_CONFIG.
    129 */
    130static inline uint64_t mips_cps_cluster_config(unsigned int cluster)
    131{
    132	uint64_t config;
    133
    134	if (mips_cm_revision() < CM_REV_CM3_5) {
    135		/*
    136		 * Prior to CM 3.5 we don't have the notion of multiple
    137		 * clusters so we can trivially read the GCR_CONFIG register
    138		 * within this cluster.
    139		 */
    140		WARN_ON(cluster != 0);
    141		config = read_gcr_config();
    142	} else {
    143		/*
    144		 * From CM 3.5 onwards we read the CPC_CONFIG mirror of
    145		 * GCR_CONFIG via the redirect region, since the CPC is always
    146		 * powered up allowing us not to need to power up the CM.
    147		 */
    148		mips_cm_lock_other(cluster, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
    149		config = read_cpc_redir_config();
    150		mips_cm_unlock_other();
    151	}
    152
    153	return config;
    154}
    155
    156/**
    157 * mips_cps_numcores - return the number of cores present in a cluster
    158 * @cluster: the ID of the cluster whose core count we want
    159 *
    160 * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
    161 * zero if no Coherence Manager is present.
    162 */
    163static inline unsigned int mips_cps_numcores(unsigned int cluster)
    164{
    165	if (!mips_cm_present())
    166		return 0;
    167
    168	/* Add one before masking to handle 0xff indicating no cores */
    169	return FIELD_GET(CM_GCR_CONFIG_PCORES,
    170			 mips_cps_cluster_config(cluster) + 1);
    171}
    172
    173/**
    174 * mips_cps_numiocu - return the number of IOCUs present in a cluster
    175 * @cluster: the ID of the cluster whose IOCU count we want
    176 *
    177 * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
    178 * if no Coherence Manager is present.
    179 */
    180static inline unsigned int mips_cps_numiocu(unsigned int cluster)
    181{
    182	if (!mips_cm_present())
    183		return 0;
    184
    185	return FIELD_GET(CM_GCR_CONFIG_NUMIOCU,
    186			 mips_cps_cluster_config(cluster));
    187}
    188
    189/**
    190 * mips_cps_numvps - return the number of VPs (threads) supported by a core
    191 * @cluster: the ID of the cluster containing the core we want to examine
    192 * @core: the ID of the core whose VP count we want
    193 *
    194 * Returns the number of Virtual Processors (VPs, ie. hardware threads) that
    195 * are supported by the given @core in the given @cluster. If the core or the
    196 * kernel do not support hardware mutlti-threading this returns 1.
    197 */
    198static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int core)
    199{
    200	unsigned int cfg;
    201
    202	if (!mips_cm_present())
    203		return 1;
    204
    205	if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
    206		&& (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
    207		return 1;
    208
    209	mips_cm_lock_other(cluster, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
    210
    211	if (mips_cm_revision() < CM_REV_CM3_5) {
    212		/*
    213		 * Prior to CM 3.5 we can only have one cluster & don't have
    214		 * CPC_Cx_CONFIG, so we read GCR_Cx_CONFIG.
    215		 */
    216		cfg = read_gcr_co_config();
    217	} else {
    218		/*
    219		 * From CM 3.5 onwards we read CPC_Cx_CONFIG because the CPC is
    220		 * always powered, which allows us to not worry about powering
    221		 * up the cluster's CM here.
    222		 */
    223		cfg = read_cpc_co_config();
    224	}
    225
    226	mips_cm_unlock_other();
    227
    228	return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, cfg + 1);
    229}
    230
    231#endif /* __MIPS_ASM_MIPS_CPS_H__ */