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