162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/* Copyright(c) 2022 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#ifndef _IFS_H_
562306a36Sopenharmony_ci#define _IFS_H_
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/**
862306a36Sopenharmony_ci * DOC: In-Field Scan
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * =============
1162306a36Sopenharmony_ci * In-Field Scan
1262306a36Sopenharmony_ci * =============
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Introduction
1562306a36Sopenharmony_ci * ------------
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * In Field Scan (IFS) is a hardware feature to run circuit level tests on
1862306a36Sopenharmony_ci * a CPU core to detect problems that are not caught by parity or ECC checks.
1962306a36Sopenharmony_ci * Future CPUs will support more than one type of test which will show up
2062306a36Sopenharmony_ci * with a new platform-device instance-id.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * IFS Image
2462306a36Sopenharmony_ci * ---------
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Intel provides a firmware file containing the scan tests via
2762306a36Sopenharmony_ci * github [#f1]_.  Similar to microcode there is a separate file for each
2862306a36Sopenharmony_ci * family-model-stepping. IFS Images are not applicable for some test types.
2962306a36Sopenharmony_ci * Wherever applicable the sysfs directory would provide a "current_batch" file
3062306a36Sopenharmony_ci * (see below) for loading the image.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * IFS Image Loading
3462306a36Sopenharmony_ci * -----------------
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * The driver loads the tests into memory reserved BIOS local to each CPU
3762306a36Sopenharmony_ci * socket in a two step process using writes to MSRs to first load the
3862306a36Sopenharmony_ci * SHA hashes for the test. Then the tests themselves. Status MSRs provide
3962306a36Sopenharmony_ci * feedback on the success/failure of these steps.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * The test files are kept in a fixed location: /lib/firmware/intel/ifs_<n>/
4262306a36Sopenharmony_ci * For e.g if there are 3 test files, they would be named in the following
4362306a36Sopenharmony_ci * fashion:
4462306a36Sopenharmony_ci * ff-mm-ss-01.scan
4562306a36Sopenharmony_ci * ff-mm-ss-02.scan
4662306a36Sopenharmony_ci * ff-mm-ss-03.scan
4762306a36Sopenharmony_ci * (where ff refers to family, mm indicates model and ss indicates stepping)
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * A different test file can be loaded by writing the numerical portion
5062306a36Sopenharmony_ci * (e.g 1, 2 or 3 in the above scenario) into the curent_batch file.
5162306a36Sopenharmony_ci * To load ff-mm-ss-02.scan, the following command can be used::
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci *   # echo 2 > /sys/devices/virtual/misc/intel_ifs_<n>/current_batch
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * The above file can also be read to know the currently loaded image.
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * Running tests
5862306a36Sopenharmony_ci * -------------
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * Tests are run by the driver synchronizing execution of all threads on a
6162306a36Sopenharmony_ci * core and then writing to the ACTIVATE_SCAN MSR on all threads. Instruction
6262306a36Sopenharmony_ci * execution continues when:
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * 1) All tests have completed.
6562306a36Sopenharmony_ci * 2) Execution was interrupted.
6662306a36Sopenharmony_ci * 3) A test detected a problem.
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Note that ALL THREADS ON THE CORE ARE EFFECTIVELY OFFLINE FOR THE
6962306a36Sopenharmony_ci * DURATION OF THE TEST. This can be up to 200 milliseconds. If the system
7062306a36Sopenharmony_ci * is running latency sensitive applications that cannot tolerate an
7162306a36Sopenharmony_ci * interruption of this magnitude, the system administrator must arrange
7262306a36Sopenharmony_ci * to migrate those applications to other cores before running a core test.
7362306a36Sopenharmony_ci * It may also be necessary to redirect interrupts to other CPUs.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * In all cases reading the corresponding test's STATUS MSR provides details on what
7662306a36Sopenharmony_ci * happened. The driver makes the value of this MSR visible to applications
7762306a36Sopenharmony_ci * via the "details" file (see below). Interrupted tests may be restarted.
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * The IFS driver provides sysfs interfaces via /sys/devices/virtual/misc/intel_ifs_<n>/
8062306a36Sopenharmony_ci * to control execution:
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Test a specific core::
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci *   # echo <cpu#> > /sys/devices/virtual/misc/intel_ifs_<n>/run_test
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * when HT is enabled any of the sibling cpu# can be specified to test
8762306a36Sopenharmony_ci * its corresponding physical core. Since the tests are per physical core,
8862306a36Sopenharmony_ci * the result of testing any thread is same. All siblings must be online
8962306a36Sopenharmony_ci * to run a core test. It is only necessary to test one thread.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * For e.g. to test core corresponding to cpu5
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci *   # echo 5 > /sys/devices/virtual/misc/intel_ifs_<n>/run_test
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Results of the last test is provided in /sys::
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci *   $ cat /sys/devices/virtual/misc/intel_ifs_<n>/status
9862306a36Sopenharmony_ci *   pass
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Status can be one of pass, fail, untested
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * Additional details of the last test is provided by the details file::
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *   $ cat /sys/devices/virtual/misc/intel_ifs_<n>/details
10562306a36Sopenharmony_ci *   0x8081
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * The details file reports the hex value of the test specific status MSR.
10862306a36Sopenharmony_ci * Hardware defined error codes are documented in volume 4 of the Intel
10962306a36Sopenharmony_ci * Software Developer's Manual but the error_code field may contain one of
11062306a36Sopenharmony_ci * the following driver defined software codes:
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * +------+--------------------+
11362306a36Sopenharmony_ci * | 0xFD | Software timeout   |
11462306a36Sopenharmony_ci * +------+--------------------+
11562306a36Sopenharmony_ci * | 0xFE | Partial completion |
11662306a36Sopenharmony_ci * +------+--------------------+
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * Driver design choices
11962306a36Sopenharmony_ci * ---------------------
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * 1) The ACTIVATE_SCAN MSR allows for running any consecutive subrange of
12262306a36Sopenharmony_ci * available tests. But the driver always tries to run all tests and only
12362306a36Sopenharmony_ci * uses the subrange feature to restart an interrupted test.
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * 2) Hardware allows for some number of cores to be tested in parallel.
12662306a36Sopenharmony_ci * The driver does not make use of this, it only tests one core at a time.
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * .. [#f1] https://github.com/intel/TBD
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_ci#include <linux/device.h>
13162306a36Sopenharmony_ci#include <linux/miscdevice.h>
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#define MSR_ARRAY_BIST				0x00000105
13462306a36Sopenharmony_ci#define MSR_COPY_SCAN_HASHES			0x000002c2
13562306a36Sopenharmony_ci#define MSR_SCAN_HASHES_STATUS			0x000002c3
13662306a36Sopenharmony_ci#define MSR_AUTHENTICATE_AND_COPY_CHUNK		0x000002c4
13762306a36Sopenharmony_ci#define MSR_CHUNKS_AUTHENTICATION_STATUS	0x000002c5
13862306a36Sopenharmony_ci#define MSR_ACTIVATE_SCAN			0x000002c6
13962306a36Sopenharmony_ci#define MSR_SCAN_STATUS				0x000002c7
14062306a36Sopenharmony_ci#define SCAN_NOT_TESTED				0
14162306a36Sopenharmony_ci#define SCAN_TEST_PASS				1
14262306a36Sopenharmony_ci#define SCAN_TEST_FAIL				2
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define IFS_TYPE_SAF			0
14562306a36Sopenharmony_ci#define IFS_TYPE_ARRAY_BIST		1
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/* MSR_SCAN_HASHES_STATUS bit fields */
14862306a36Sopenharmony_ciunion ifs_scan_hashes_status {
14962306a36Sopenharmony_ci	u64	data;
15062306a36Sopenharmony_ci	struct {
15162306a36Sopenharmony_ci		u32	chunk_size	:16;
15262306a36Sopenharmony_ci		u32	num_chunks	:8;
15362306a36Sopenharmony_ci		u32	rsvd1		:8;
15462306a36Sopenharmony_ci		u32	error_code	:8;
15562306a36Sopenharmony_ci		u32	rsvd2		:11;
15662306a36Sopenharmony_ci		u32	max_core_limit	:12;
15762306a36Sopenharmony_ci		u32	valid		:1;
15862306a36Sopenharmony_ci	};
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/* MSR_CHUNKS_AUTH_STATUS bit fields */
16262306a36Sopenharmony_ciunion ifs_chunks_auth_status {
16362306a36Sopenharmony_ci	u64	data;
16462306a36Sopenharmony_ci	struct {
16562306a36Sopenharmony_ci		u32	valid_chunks	:8;
16662306a36Sopenharmony_ci		u32	total_chunks	:8;
16762306a36Sopenharmony_ci		u32	rsvd1		:16;
16862306a36Sopenharmony_ci		u32	error_code	:8;
16962306a36Sopenharmony_ci		u32	rsvd2		:24;
17062306a36Sopenharmony_ci	};
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* MSR_ACTIVATE_SCAN bit fields */
17462306a36Sopenharmony_ciunion ifs_scan {
17562306a36Sopenharmony_ci	u64	data;
17662306a36Sopenharmony_ci	struct {
17762306a36Sopenharmony_ci		u32	start	:8;
17862306a36Sopenharmony_ci		u32	stop	:8;
17962306a36Sopenharmony_ci		u32	rsvd	:16;
18062306a36Sopenharmony_ci		u32	delay	:31;
18162306a36Sopenharmony_ci		u32	sigmce	:1;
18262306a36Sopenharmony_ci	};
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/* MSR_SCAN_STATUS bit fields */
18662306a36Sopenharmony_ciunion ifs_status {
18762306a36Sopenharmony_ci	u64	data;
18862306a36Sopenharmony_ci	struct {
18962306a36Sopenharmony_ci		u32	chunk_num		:8;
19062306a36Sopenharmony_ci		u32	chunk_stop_index	:8;
19162306a36Sopenharmony_ci		u32	rsvd1			:16;
19262306a36Sopenharmony_ci		u32	error_code		:8;
19362306a36Sopenharmony_ci		u32	rsvd2			:22;
19462306a36Sopenharmony_ci		u32	control_error		:1;
19562306a36Sopenharmony_ci		u32	signature_error		:1;
19662306a36Sopenharmony_ci	};
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/* MSR_ARRAY_BIST bit fields */
20062306a36Sopenharmony_ciunion ifs_array {
20162306a36Sopenharmony_ci	u64	data;
20262306a36Sopenharmony_ci	struct {
20362306a36Sopenharmony_ci		u32	array_bitmask;
20462306a36Sopenharmony_ci		u16	array_bank;
20562306a36Sopenharmony_ci		u16	rsvd			:15;
20662306a36Sopenharmony_ci		u16	ctrl_result		:1;
20762306a36Sopenharmony_ci	};
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/*
21162306a36Sopenharmony_ci * Driver populated error-codes
21262306a36Sopenharmony_ci * 0xFD: Test timed out before completing all the chunks.
21362306a36Sopenharmony_ci * 0xFE: not all scan chunks were executed. Maximum forward progress retries exceeded.
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_ci#define IFS_SW_TIMEOUT				0xFD
21662306a36Sopenharmony_ci#define IFS_SW_PARTIAL_COMPLETION		0xFE
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistruct ifs_test_caps {
21962306a36Sopenharmony_ci	int	integrity_cap_bit;
22062306a36Sopenharmony_ci	int	test_num;
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/**
22462306a36Sopenharmony_ci * struct ifs_data - attributes related to intel IFS driver
22562306a36Sopenharmony_ci * @loaded_version: stores the currently loaded ifs image version.
22662306a36Sopenharmony_ci * @loaded: If a valid test binary has been loaded into the memory
22762306a36Sopenharmony_ci * @loading_error: Error occurred on another CPU while loading image
22862306a36Sopenharmony_ci * @valid_chunks: number of chunks which could be validated.
22962306a36Sopenharmony_ci * @status: it holds simple status pass/fail/untested
23062306a36Sopenharmony_ci * @scan_details: opaque scan status code from h/w
23162306a36Sopenharmony_ci * @cur_batch: number indicating the currently loaded test file
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_cistruct ifs_data {
23462306a36Sopenharmony_ci	int	loaded_version;
23562306a36Sopenharmony_ci	bool	loaded;
23662306a36Sopenharmony_ci	bool	loading_error;
23762306a36Sopenharmony_ci	int	valid_chunks;
23862306a36Sopenharmony_ci	int	status;
23962306a36Sopenharmony_ci	u64	scan_details;
24062306a36Sopenharmony_ci	u32	cur_batch;
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistruct ifs_work {
24462306a36Sopenharmony_ci	struct work_struct w;
24562306a36Sopenharmony_ci	struct device *dev;
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistruct ifs_device {
24962306a36Sopenharmony_ci	const struct ifs_test_caps *test_caps;
25062306a36Sopenharmony_ci	struct ifs_data rw_data;
25162306a36Sopenharmony_ci	struct miscdevice misc;
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline struct ifs_data *ifs_get_data(struct device *dev)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct miscdevice *m = dev_get_drvdata(dev);
25762306a36Sopenharmony_ci	struct ifs_device *d = container_of(m, struct ifs_device, misc);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return &d->rw_data;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic inline const struct ifs_test_caps *ifs_get_test_caps(struct device *dev)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct miscdevice *m = dev_get_drvdata(dev);
26562306a36Sopenharmony_ci	struct ifs_device *d = container_of(m, struct ifs_device, misc);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return d->test_caps;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ciextern bool *ifs_pkg_auth;
27162306a36Sopenharmony_ciint ifs_load_firmware(struct device *dev);
27262306a36Sopenharmony_ciint do_core_test(int cpu, struct device *dev);
27362306a36Sopenharmony_ciextern struct attribute *plat_ifs_attrs[];
27462306a36Sopenharmony_ciextern struct attribute *plat_ifs_array_attrs[];
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#endif
277