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

intel_sseu_debugfs.c (8764B)


      1// SPDX-License-Identifier: MIT
      2
      3/*
      4 * Copyright © 2020 Intel Corporation
      5 */
      6
      7#include <linux/string_helpers.h>
      8
      9#include "i915_drv.h"
     10#include "intel_gt_debugfs.h"
     11#include "intel_gt_regs.h"
     12#include "intel_sseu_debugfs.h"
     13
     14static void sseu_copy_subslices(const struct sseu_dev_info *sseu,
     15				int slice, u8 *to_mask)
     16{
     17	int offset = slice * sseu->ss_stride;
     18
     19	memcpy(&to_mask[offset], &sseu->subslice_mask[offset], sseu->ss_stride);
     20}
     21
     22static void cherryview_sseu_device_status(struct intel_gt *gt,
     23					  struct sseu_dev_info *sseu)
     24{
     25#define SS_MAX 2
     26	struct intel_uncore *uncore = gt->uncore;
     27	const int ss_max = SS_MAX;
     28	u32 sig1[SS_MAX], sig2[SS_MAX];
     29	int ss;
     30
     31	sig1[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG1);
     32	sig1[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG1);
     33	sig2[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG2);
     34	sig2[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG2);
     35
     36	for (ss = 0; ss < ss_max; ss++) {
     37		unsigned int eu_cnt;
     38
     39		if (sig1[ss] & CHV_SS_PG_ENABLE)
     40			/* skip disabled subslice */
     41			continue;
     42
     43		sseu->slice_mask = BIT(0);
     44		sseu->subslice_mask[0] |= BIT(ss);
     45		eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
     46			 ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
     47			 ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
     48			 ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
     49		sseu->eu_total += eu_cnt;
     50		sseu->eu_per_subslice = max_t(unsigned int,
     51					      sseu->eu_per_subslice, eu_cnt);
     52	}
     53#undef SS_MAX
     54}
     55
     56static void gen11_sseu_device_status(struct intel_gt *gt,
     57				     struct sseu_dev_info *sseu)
     58{
     59#define SS_MAX 8
     60	struct intel_uncore *uncore = gt->uncore;
     61	const struct intel_gt_info *info = &gt->info;
     62	u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
     63	int s, ss;
     64
     65	for (s = 0; s < info->sseu.max_slices; s++) {
     66		/*
     67		 * FIXME: Valid SS Mask respects the spec and read
     68		 * only valid bits for those registers, excluding reserved
     69		 * although this seems wrong because it would leave many
     70		 * subslices without ACK.
     71		 */
     72		s_reg[s] = intel_uncore_read(uncore, GEN10_SLICE_PGCTL_ACK(s)) &
     73			GEN10_PGCTL_VALID_SS_MASK(s);
     74		eu_reg[2 * s] = intel_uncore_read(uncore,
     75						  GEN10_SS01_EU_PGCTL_ACK(s));
     76		eu_reg[2 * s + 1] = intel_uncore_read(uncore,
     77						      GEN10_SS23_EU_PGCTL_ACK(s));
     78	}
     79
     80	eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
     81		     GEN9_PGCTL_SSA_EU19_ACK |
     82		     GEN9_PGCTL_SSA_EU210_ACK |
     83		     GEN9_PGCTL_SSA_EU311_ACK;
     84	eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
     85		     GEN9_PGCTL_SSB_EU19_ACK |
     86		     GEN9_PGCTL_SSB_EU210_ACK |
     87		     GEN9_PGCTL_SSB_EU311_ACK;
     88
     89	for (s = 0; s < info->sseu.max_slices; s++) {
     90		if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
     91			/* skip disabled slice */
     92			continue;
     93
     94		sseu->slice_mask |= BIT(s);
     95		sseu_copy_subslices(&info->sseu, s, sseu->subslice_mask);
     96
     97		for (ss = 0; ss < info->sseu.max_subslices; ss++) {
     98			unsigned int eu_cnt;
     99
    100			if (info->sseu.has_subslice_pg &&
    101			    !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
    102				/* skip disabled subslice */
    103				continue;
    104
    105			eu_cnt = 2 * hweight32(eu_reg[2 * s + ss / 2] &
    106					       eu_mask[ss % 2]);
    107			sseu->eu_total += eu_cnt;
    108			sseu->eu_per_subslice = max_t(unsigned int,
    109						      sseu->eu_per_subslice,
    110						      eu_cnt);
    111		}
    112	}
    113#undef SS_MAX
    114}
    115
    116static void gen9_sseu_device_status(struct intel_gt *gt,
    117				    struct sseu_dev_info *sseu)
    118{
    119#define SS_MAX 3
    120	struct intel_uncore *uncore = gt->uncore;
    121	const struct intel_gt_info *info = &gt->info;
    122	u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
    123	int s, ss;
    124
    125	for (s = 0; s < info->sseu.max_slices; s++) {
    126		s_reg[s] = intel_uncore_read(uncore, GEN9_SLICE_PGCTL_ACK(s));
    127		eu_reg[2 * s] =
    128			intel_uncore_read(uncore, GEN9_SS01_EU_PGCTL_ACK(s));
    129		eu_reg[2 * s + 1] =
    130			intel_uncore_read(uncore, GEN9_SS23_EU_PGCTL_ACK(s));
    131	}
    132
    133	eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
    134		     GEN9_PGCTL_SSA_EU19_ACK |
    135		     GEN9_PGCTL_SSA_EU210_ACK |
    136		     GEN9_PGCTL_SSA_EU311_ACK;
    137	eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
    138		     GEN9_PGCTL_SSB_EU19_ACK |
    139		     GEN9_PGCTL_SSB_EU210_ACK |
    140		     GEN9_PGCTL_SSB_EU311_ACK;
    141
    142	for (s = 0; s < info->sseu.max_slices; s++) {
    143		if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
    144			/* skip disabled slice */
    145			continue;
    146
    147		sseu->slice_mask |= BIT(s);
    148
    149		if (IS_GEN9_BC(gt->i915))
    150			sseu_copy_subslices(&info->sseu, s,
    151					    sseu->subslice_mask);
    152
    153		for (ss = 0; ss < info->sseu.max_subslices; ss++) {
    154			unsigned int eu_cnt;
    155			u8 ss_idx = s * info->sseu.ss_stride +
    156				    ss / BITS_PER_BYTE;
    157
    158			if (IS_GEN9_LP(gt->i915)) {
    159				if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
    160					/* skip disabled subslice */
    161					continue;
    162
    163				sseu->subslice_mask[ss_idx] |=
    164					BIT(ss % BITS_PER_BYTE);
    165			}
    166
    167			eu_cnt = eu_reg[2 * s + ss / 2] & eu_mask[ss % 2];
    168			eu_cnt = 2 * hweight32(eu_cnt);
    169
    170			sseu->eu_total += eu_cnt;
    171			sseu->eu_per_subslice = max_t(unsigned int,
    172						      sseu->eu_per_subslice,
    173						      eu_cnt);
    174		}
    175	}
    176#undef SS_MAX
    177}
    178
    179static void bdw_sseu_device_status(struct intel_gt *gt,
    180				   struct sseu_dev_info *sseu)
    181{
    182	const struct intel_gt_info *info = &gt->info;
    183	u32 slice_info = intel_uncore_read(gt->uncore, GEN8_GT_SLICE_INFO);
    184	int s;
    185
    186	sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
    187
    188	if (sseu->slice_mask) {
    189		sseu->eu_per_subslice = info->sseu.eu_per_subslice;
    190		for (s = 0; s < fls(sseu->slice_mask); s++)
    191			sseu_copy_subslices(&info->sseu, s,
    192					    sseu->subslice_mask);
    193		sseu->eu_total = sseu->eu_per_subslice *
    194				 intel_sseu_subslice_total(sseu);
    195
    196		/* subtract fused off EU(s) from enabled slice(s) */
    197		for (s = 0; s < fls(sseu->slice_mask); s++) {
    198			u8 subslice_7eu = info->sseu.subslice_7eu[s];
    199
    200			sseu->eu_total -= hweight8(subslice_7eu);
    201		}
    202	}
    203}
    204
    205static void i915_print_sseu_info(struct seq_file *m,
    206				 bool is_available_info,
    207				 bool has_pooled_eu,
    208				 const struct sseu_dev_info *sseu)
    209{
    210	const char *type = is_available_info ? "Available" : "Enabled";
    211	int s;
    212
    213	seq_printf(m, "  %s Slice Mask: %04x\n", type,
    214		   sseu->slice_mask);
    215	seq_printf(m, "  %s Slice Total: %u\n", type,
    216		   hweight8(sseu->slice_mask));
    217	seq_printf(m, "  %s Subslice Total: %u\n", type,
    218		   intel_sseu_subslice_total(sseu));
    219	for (s = 0; s < fls(sseu->slice_mask); s++) {
    220		seq_printf(m, "  %s Slice%i subslices: %u\n", type,
    221			   s, intel_sseu_subslices_per_slice(sseu, s));
    222	}
    223	seq_printf(m, "  %s EU Total: %u\n", type,
    224		   sseu->eu_total);
    225	seq_printf(m, "  %s EU Per Subslice: %u\n", type,
    226		   sseu->eu_per_subslice);
    227
    228	if (!is_available_info)
    229		return;
    230
    231	seq_printf(m, "  Has Pooled EU: %s\n", str_yes_no(has_pooled_eu));
    232	if (has_pooled_eu)
    233		seq_printf(m, "  Min EU in pool: %u\n", sseu->min_eu_in_pool);
    234
    235	seq_printf(m, "  Has Slice Power Gating: %s\n",
    236		   str_yes_no(sseu->has_slice_pg));
    237	seq_printf(m, "  Has Subslice Power Gating: %s\n",
    238		   str_yes_no(sseu->has_subslice_pg));
    239	seq_printf(m, "  Has EU Power Gating: %s\n",
    240		   str_yes_no(sseu->has_eu_pg));
    241}
    242
    243/*
    244 * this is called from top-level debugfs as well, so we can't get the gt from
    245 * the seq_file.
    246 */
    247int intel_sseu_status(struct seq_file *m, struct intel_gt *gt)
    248{
    249	struct drm_i915_private *i915 = gt->i915;
    250	const struct intel_gt_info *info = &gt->info;
    251	struct sseu_dev_info *sseu;
    252	intel_wakeref_t wakeref;
    253
    254	if (GRAPHICS_VER(i915) < 8)
    255		return -ENODEV;
    256
    257	seq_puts(m, "SSEU Device Info\n");
    258	i915_print_sseu_info(m, true, HAS_POOLED_EU(i915), &info->sseu);
    259
    260	seq_puts(m, "SSEU Device Status\n");
    261
    262	sseu = kzalloc(sizeof(*sseu), GFP_KERNEL);
    263	if (!sseu)
    264		return -ENOMEM;
    265
    266	intel_sseu_set_info(sseu, info->sseu.max_slices,
    267			    info->sseu.max_subslices,
    268			    info->sseu.max_eus_per_subslice);
    269
    270	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
    271		if (IS_CHERRYVIEW(i915))
    272			cherryview_sseu_device_status(gt, sseu);
    273		else if (IS_BROADWELL(i915))
    274			bdw_sseu_device_status(gt, sseu);
    275		else if (GRAPHICS_VER(i915) == 9)
    276			gen9_sseu_device_status(gt, sseu);
    277		else if (GRAPHICS_VER(i915) >= 11)
    278			gen11_sseu_device_status(gt, sseu);
    279	}
    280
    281	i915_print_sseu_info(m, false, HAS_POOLED_EU(i915), sseu);
    282
    283	kfree(sseu);
    284
    285	return 0;
    286}
    287
    288static int sseu_status_show(struct seq_file *m, void *unused)
    289{
    290	struct intel_gt *gt = m->private;
    291
    292	return intel_sseu_status(m, gt);
    293}
    294DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);
    295
    296static int sseu_topology_show(struct seq_file *m, void *unused)
    297{
    298	struct intel_gt *gt = m->private;
    299	struct drm_printer p = drm_seq_file_printer(m);
    300
    301	intel_sseu_print_topology(gt->i915, &gt->info.sseu, &p);
    302
    303	return 0;
    304}
    305DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);
    306
    307void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root)
    308{
    309	static const struct intel_gt_debugfs_file files[] = {
    310		{ "sseu_status", &sseu_status_fops, NULL },
    311		{ "sseu_topology", &sseu_topology_fops, NULL },
    312	};
    313
    314	intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);
    315}