未验证 提交 aaae3642 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!787 Intel: Support In Field Scan(IFS) Array BIST

Merge Pull Request from: @allen-shi 
 
Intel In Field Scan (IFS) is a hardware feature to run circuit level tests on a CPU core to detect problems that are not caught by parity or ECC checks.

IFS Scan At Field(SAF) multi-blob images supported in [PR471](https://gitee.com/openeuler/kernel/pulls/471) and [PR580](https://gitee.com/openeuler/kernel/pulls/580)

IFS Array BIST performs tests on some portions of the core logic such as caches and register files. These are different portions of the silicon compared to the parts tested by the first test type i.e Scan at Field (SAF). Emerald Rapids (EMR) is the first CPU to support Array BIST.

This PR is to support In Field Scan(IFS) Array BIST and includes 9 commits totally.
It is upstreamed in v6.4-rc1.
https://lore.kernel.org/lkml/20230322003359.213046-1-jithu.joseph@intel.com/

 
 **Intel-Kernel Issue** 
[#I73EG8](https://gitee.com/openeuler/intel-kernel/issues/I73EG8)

 **Test** 
Built and run the kernel successfully on openEuler 22.03 LTS SP1.
Test is PASS on EMR platform.

 **Known Issue** 
N/A

 **Default config change** 
N/A 
 
Link:https://gitee.com/openeuler/kernel/pulls/787 

Reviewed-by: Jason Zeng <jason.zeng@intel.com> 
Reviewed-by: Jialin Zhang <zhangjialin11@huawei.com> 
Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
Device instance to test mapping
intel_ifs_0 -> Scan Test
intel_ifs_1 -> Array BIST test
What: /sys/devices/virtual/misc/intel_ifs_<N>/run_test What: /sys/devices/virtual/misc/intel_ifs_<N>/run_test
Date: Nov 16 2022 Date: Nov 16 2022
KernelVersion: 6.2 KernelVersion: 6.2
...@@ -8,6 +12,7 @@ Description: Write <cpu#> to trigger IFS test for one online core. ...@@ -8,6 +12,7 @@ Description: Write <cpu#> to trigger IFS test for one online core.
completes the test for the core containing that thread. completes the test for the core containing that thread.
Example: to test the core containing cpu5: echo 5 > Example: to test the core containing cpu5: echo 5 >
/sys/devices/virtual/misc/intel_ifs_<N>/run_test /sys/devices/virtual/misc/intel_ifs_<N>/run_test
Devices: all
What: /sys/devices/virtual/misc/intel_ifs_<N>/status What: /sys/devices/virtual/misc/intel_ifs_<N>/status
Date: Nov 16 2022 Date: Nov 16 2022
...@@ -15,21 +20,25 @@ KernelVersion: 6.2 ...@@ -15,21 +20,25 @@ KernelVersion: 6.2
Contact: "Jithu Joseph" <jithu.joseph@intel.com> Contact: "Jithu Joseph" <jithu.joseph@intel.com>
Description: The status of the last test. It can be one of "pass", "fail" Description: The status of the last test. It can be one of "pass", "fail"
or "untested". or "untested".
Devices: all
What: /sys/devices/virtual/misc/intel_ifs_<N>/details What: /sys/devices/virtual/misc/intel_ifs_<N>/details
Date: Nov 16 2022 Date: Nov 16 2022
KernelVersion: 6.2 KernelVersion: 6.2
Contact: "Jithu Joseph" <jithu.joseph@intel.com> Contact: "Jithu Joseph" <jithu.joseph@intel.com>
Description: Additional information regarding the last test. The details file reports Description: Additional information regarding the last test. The details file reports
the hex value of the SCAN_STATUS MSR. Note that the error_code field the hex value of the STATUS MSR for this test. Note that the error_code field
may contain driver defined software code not defined in the Intel SDM. may contain driver defined software code not defined in the Intel SDM.
Devices: all
What: /sys/devices/virtual/misc/intel_ifs_<N>/image_version What: /sys/devices/virtual/misc/intel_ifs_<N>/image_version
Date: Nov 16 2022 Date: Nov 16 2022
KernelVersion: 6.2 KernelVersion: 6.2
Contact: "Jithu Joseph" <jithu.joseph@intel.com> Contact: "Jithu Joseph" <jithu.joseph@intel.com>
Description: Version (hexadecimal) of loaded IFS binary image. If no scan image Description: Version (hexadecimal) of loaded IFS test image. If no test image
is loaded reports "none". is loaded reports "none". Only present for device instances where a test image
is applicable.
Devices: intel_ifs_0
What: /sys/devices/virtual/misc/intel_ifs_<N>/current_batch What: /sys/devices/virtual/misc/intel_ifs_<N>/current_batch
Date: Nov 16 2022 Date: Nov 16 2022
...@@ -39,3 +48,5 @@ Description: Write a number less than or equal to 0xff to load an IFS test image ...@@ -39,3 +48,5 @@ Description: Write a number less than or equal to 0xff to load an IFS test image
The number written treated as the 2 digit suffix in the following file name: The number written treated as the 2 digit suffix in the following file name:
/lib/firmware/intel/ifs_<N>/ff-mm-ss-02x.scan /lib/firmware/intel/ifs_<N>/ff-mm-ss-02x.scan
Reading the file will provide the suffix of the currently loaded IFS test image. Reading the file will provide the suffix of the currently loaded IFS test image.
This file is present only for device instances where a test image is applicable.
Devices: intel_ifs_0
...@@ -196,6 +196,8 @@ ...@@ -196,6 +196,8 @@
/* Abbreviated from Intel SDM name IA32_INTEGRITY_CAPABILITIES */ /* Abbreviated from Intel SDM name IA32_INTEGRITY_CAPABILITIES */
#define MSR_INTEGRITY_CAPS 0x000002d9 #define MSR_INTEGRITY_CAPS 0x000002d9
#define MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT 2
#define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT)
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 #define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) #define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT)
......
...@@ -16,27 +16,63 @@ ...@@ -16,27 +16,63 @@
static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
X86_MATCH(SAPPHIRERAPIDS_X), X86_MATCH(SAPPHIRERAPIDS_X),
X86_MATCH(EMERALDRAPIDS_X),
{} {}
}; };
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
static struct ifs_device ifs_device = { ATTRIBUTE_GROUPS(plat_ifs);
.data = { ATTRIBUTE_GROUPS(plat_ifs_array);
.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
.test_num = 0, bool *ifs_pkg_auth;
static const struct ifs_test_caps scan_test = {
.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
.test_num = IFS_TYPE_SAF,
};
static const struct ifs_test_caps array_test = {
.integrity_cap_bit = MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT,
.test_num = IFS_TYPE_ARRAY_BIST,
};
static struct ifs_device ifs_devices[] = {
[IFS_TYPE_SAF] = {
.test_caps = &scan_test,
.misc = {
.name = "intel_ifs_0",
.minor = MISC_DYNAMIC_MINOR,
.groups = plat_ifs_groups,
},
}, },
.misc = { [IFS_TYPE_ARRAY_BIST] = {
.name = "intel_ifs_0", .test_caps = &array_test,
.nodename = "intel_ifs/0", .misc = {
.minor = MISC_DYNAMIC_MINOR, .name = "intel_ifs_1",
.minor = MISC_DYNAMIC_MINOR,
.groups = plat_ifs_array_groups,
},
}, },
}; };
#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
static void ifs_cleanup(void)
{
int i;
for (i = 0; i < IFS_NUMTESTS; i++) {
if (ifs_devices[i].misc.this_device)
misc_deregister(&ifs_devices[i].misc);
}
kfree(ifs_pkg_auth);
}
static int __init ifs_init(void) static int __init ifs_init(void)
{ {
const struct x86_cpu_id *m; const struct x86_cpu_id *m;
u64 msrval; u64 msrval;
int ret; int i, ret;
m = x86_match_cpu(ifs_cpu_ids); m = x86_match_cpu(ifs_cpu_ids);
if (!m) if (!m)
...@@ -51,28 +87,27 @@ static int __init ifs_init(void) ...@@ -51,28 +87,27 @@ static int __init ifs_init(void)
if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval)) if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
return -ENODEV; return -ENODEV;
ifs_device.misc.groups = ifs_get_groups(); ifs_pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL);
if (!ifs_pkg_auth)
if (!(msrval & BIT(ifs_device.data.integrity_cap_bit)))
return -ENODEV;
ifs_device.data.pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL);
if (!ifs_device.data.pkg_auth)
return -ENOMEM; return -ENOMEM;
ret = misc_register(&ifs_device.misc); for (i = 0; i < IFS_NUMTESTS; i++) {
if (ret) { if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit)))
kfree(ifs_device.data.pkg_auth); continue;
return ret; ret = misc_register(&ifs_devices[i].misc);
if (ret)
goto err_exit;
} }
return 0; return 0;
err_exit:
ifs_cleanup();
return ret;
} }
static void __exit ifs_exit(void) static void __exit ifs_exit(void)
{ {
misc_deregister(&ifs_device.misc); ifs_cleanup();
kfree(ifs_device.data.pkg_auth);
} }
module_init(ifs_init); module_init(ifs_init);
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* In Field Scan (IFS) is a hardware feature to run circuit level tests on * In Field Scan (IFS) is a hardware feature to run circuit level tests on
* a CPU core to detect problems that are not caught by parity or ECC checks. * a CPU core to detect problems that are not caught by parity or ECC checks.
* Future CPUs will support more than one type of test which will show up * Future CPUs will support more than one type of test which will show up
* with a new platform-device instance-id, for now only .0 is exposed. * with a new platform-device instance-id.
* *
* *
* IFS Image * IFS Image
...@@ -25,7 +25,10 @@ ...@@ -25,7 +25,10 @@
* *
* Intel provides a firmware file containing the scan tests via * Intel provides a firmware file containing the scan tests via
* github [#f1]_. Similar to microcode there is a separate file for each * github [#f1]_. Similar to microcode there is a separate file for each
* family-model-stepping. * family-model-stepping. IFS Images are not applicable for some test types.
* Wherever applicable the sysfs directory would provide a "current_batch" file
* (see below) for loading the image.
*
* *
* IFS Image Loading * IFS Image Loading
* ----------------- * -----------------
...@@ -35,7 +38,7 @@ ...@@ -35,7 +38,7 @@
* SHA hashes for the test. Then the tests themselves. Status MSRs provide * SHA hashes for the test. Then the tests themselves. Status MSRs provide
* feedback on the success/failure of these steps. * feedback on the success/failure of these steps.
* *
* The test files are kept in a fixed location: /lib/firmware/intel/ifs_0/ * The test files are kept in a fixed location: /lib/firmware/intel/ifs_<n>/
* For e.g if there are 3 test files, they would be named in the following * For e.g if there are 3 test files, they would be named in the following
* fashion: * fashion:
* ff-mm-ss-01.scan * ff-mm-ss-01.scan
...@@ -47,7 +50,7 @@ ...@@ -47,7 +50,7 @@
* (e.g 1, 2 or 3 in the above scenario) into the curent_batch file. * (e.g 1, 2 or 3 in the above scenario) into the curent_batch file.
* To load ff-mm-ss-02.scan, the following command can be used:: * To load ff-mm-ss-02.scan, the following command can be used::
* *
* # echo 2 > /sys/devices/virtual/misc/intel_ifs_0/current_batch * # echo 2 > /sys/devices/virtual/misc/intel_ifs_<n>/current_batch
* *
* The above file can also be read to know the currently loaded image. * The above file can also be read to know the currently loaded image.
* *
...@@ -69,16 +72,16 @@ ...@@ -69,16 +72,16 @@
* to migrate those applications to other cores before running a core test. * to migrate those applications to other cores before running a core test.
* It may also be necessary to redirect interrupts to other CPUs. * It may also be necessary to redirect interrupts to other CPUs.
* *
* In all cases reading the SCAN_STATUS MSR provides details on what * In all cases reading the corresponding test's STATUS MSR provides details on what
* happened. The driver makes the value of this MSR visible to applications * happened. The driver makes the value of this MSR visible to applications
* via the "details" file (see below). Interrupted tests may be restarted. * via the "details" file (see below). Interrupted tests may be restarted.
* *
* The IFS driver provides sysfs interfaces via /sys/devices/virtual/misc/intel_ifs_0/ * The IFS driver provides sysfs interfaces via /sys/devices/virtual/misc/intel_ifs_<n>/
* to control execution: * to control execution:
* *
* Test a specific core:: * Test a specific core::
* *
* # echo <cpu#> > /sys/devices/virtual/misc/intel_ifs_0/run_test * # echo <cpu#> > /sys/devices/virtual/misc/intel_ifs_<n>/run_test
* *
* when HT is enabled any of the sibling cpu# can be specified to test * when HT is enabled any of the sibling cpu# can be specified to test
* its corresponding physical core. Since the tests are per physical core, * its corresponding physical core. Since the tests are per physical core,
...@@ -87,21 +90,21 @@ ...@@ -87,21 +90,21 @@
* *
* For e.g. to test core corresponding to cpu5 * For e.g. to test core corresponding to cpu5
* *
* # echo 5 > /sys/devices/virtual/misc/intel_ifs_0/run_test * # echo 5 > /sys/devices/virtual/misc/intel_ifs_<n>/run_test
* *
* Results of the last test is provided in /sys:: * Results of the last test is provided in /sys::
* *
* $ cat /sys/devices/virtual/misc/intel_ifs_0/status * $ cat /sys/devices/virtual/misc/intel_ifs_<n>/status
* pass * pass
* *
* Status can be one of pass, fail, untested * Status can be one of pass, fail, untested
* *
* Additional details of the last test is provided by the details file:: * Additional details of the last test is provided by the details file::
* *
* $ cat /sys/devices/virtual/misc/intel_ifs_0/details * $ cat /sys/devices/virtual/misc/intel_ifs_<n>/details
* 0x8081 * 0x8081
* *
* The details file reports the hex value of the SCAN_STATUS MSR. * The details file reports the hex value of the test specific status MSR.
* Hardware defined error codes are documented in volume 4 of the Intel * Hardware defined error codes are documented in volume 4 of the Intel
* Software Developer's Manual but the error_code field may contain one of * Software Developer's Manual but the error_code field may contain one of
* the following driver defined software codes: * the following driver defined software codes:
...@@ -127,6 +130,7 @@ ...@@ -127,6 +130,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#define MSR_ARRAY_BIST 0x00000105
#define MSR_COPY_SCAN_HASHES 0x000002c2 #define MSR_COPY_SCAN_HASHES 0x000002c2
#define MSR_SCAN_HASHES_STATUS 0x000002c3 #define MSR_SCAN_HASHES_STATUS 0x000002c3
#define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4 #define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4
...@@ -137,6 +141,9 @@ ...@@ -137,6 +141,9 @@
#define SCAN_TEST_PASS 1 #define SCAN_TEST_PASS 1
#define SCAN_TEST_FAIL 2 #define SCAN_TEST_FAIL 2
#define IFS_TYPE_SAF 0
#define IFS_TYPE_ARRAY_BIST 1
/* MSR_SCAN_HASHES_STATUS bit fields */ /* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status { union ifs_scan_hashes_status {
u64 data; u64 data;
...@@ -189,6 +196,17 @@ union ifs_status { ...@@ -189,6 +196,17 @@ union ifs_status {
}; };
}; };
/* MSR_ARRAY_BIST bit fields */
union ifs_array {
u64 data;
struct {
u32 array_bitmask;
u16 array_bank;
u16 rsvd :15;
u16 ctrl_result :1;
};
};
/* /*
* Driver populated error-codes * Driver populated error-codes
* 0xFD: Test timed out before completing all the chunks. * 0xFD: Test timed out before completing all the chunks.
...@@ -197,22 +215,22 @@ union ifs_status { ...@@ -197,22 +215,22 @@ union ifs_status {
#define IFS_SW_TIMEOUT 0xFD #define IFS_SW_TIMEOUT 0xFD
#define IFS_SW_PARTIAL_COMPLETION 0xFE #define IFS_SW_PARTIAL_COMPLETION 0xFE
struct ifs_test_caps {
int integrity_cap_bit;
int test_num;
};
/** /**
* struct ifs_data - attributes related to intel IFS driver * struct ifs_data - attributes related to intel IFS driver
* @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test
* @loaded_version: stores the currently loaded ifs image version. * @loaded_version: stores the currently loaded ifs image version.
* @pkg_auth: array of bool storing per package auth status
* @loaded: If a valid test binary has been loaded into the memory * @loaded: If a valid test binary has been loaded into the memory
* @loading_error: Error occurred on another CPU while loading image * @loading_error: Error occurred on another CPU while loading image
* @valid_chunks: number of chunks which could be validated. * @valid_chunks: number of chunks which could be validated.
* @status: it holds simple status pass/fail/untested * @status: it holds simple status pass/fail/untested
* @scan_details: opaque scan status code from h/w * @scan_details: opaque scan status code from h/w
* @cur_batch: number indicating the currently loaded test file * @cur_batch: number indicating the currently loaded test file
* @test_num: number indicating the test type
*/ */
struct ifs_data { struct ifs_data {
int integrity_cap_bit;
bool *pkg_auth;
int loaded_version; int loaded_version;
bool loaded; bool loaded;
bool loading_error; bool loading_error;
...@@ -220,7 +238,6 @@ struct ifs_data { ...@@ -220,7 +238,6 @@ struct ifs_data {
int status; int status;
u64 scan_details; u64 scan_details;
u32 cur_batch; u32 cur_batch;
int test_num;
}; };
struct ifs_work { struct ifs_work {
...@@ -229,7 +246,8 @@ struct ifs_work { ...@@ -229,7 +246,8 @@ struct ifs_work {
}; };
struct ifs_device { struct ifs_device {
struct ifs_data data; const struct ifs_test_caps *test_caps;
struct ifs_data rw_data;
struct miscdevice misc; struct miscdevice misc;
}; };
...@@ -238,11 +256,21 @@ static inline struct ifs_data *ifs_get_data(struct device *dev) ...@@ -238,11 +256,21 @@ static inline struct ifs_data *ifs_get_data(struct device *dev)
struct miscdevice *m = dev_get_drvdata(dev); struct miscdevice *m = dev_get_drvdata(dev);
struct ifs_device *d = container_of(m, struct ifs_device, misc); struct ifs_device *d = container_of(m, struct ifs_device, misc);
return &d->data; return &d->rw_data;
}
static inline const struct ifs_test_caps *ifs_get_test_caps(struct device *dev)
{
struct miscdevice *m = dev_get_drvdata(dev);
struct ifs_device *d = container_of(m, struct ifs_device, misc);
return d->test_caps;
} }
extern bool *ifs_pkg_auth;
int ifs_load_firmware(struct device *dev); int ifs_load_firmware(struct device *dev);
int do_core_test(int cpu, struct device *dev); int do_core_test(int cpu, struct device *dev);
const struct attribute_group **ifs_get_groups(void); extern struct attribute *plat_ifs_attrs[];
extern struct attribute *plat_ifs_array_attrs[];
#endif #endif
...@@ -192,7 +192,7 @@ static int scan_chunks_sanity_check(struct device *dev) ...@@ -192,7 +192,7 @@ static int scan_chunks_sanity_check(struct device *dev)
struct ifs_work local_work; struct ifs_work local_work;
int curr_pkg, cpu, ret; int curr_pkg, cpu, ret;
memset(ifsd->pkg_auth, 0, (topology_max_packages() * sizeof(bool))); memset(ifs_pkg_auth, 0, (topology_max_packages() * sizeof(bool)));
ret = validate_ifs_metadata(dev); ret = validate_ifs_metadata(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -204,7 +204,7 @@ static int scan_chunks_sanity_check(struct device *dev) ...@@ -204,7 +204,7 @@ static int scan_chunks_sanity_check(struct device *dev)
cpus_read_lock(); cpus_read_lock();
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
curr_pkg = topology_physical_package_id(cpu); curr_pkg = topology_physical_package_id(cpu);
if (ifsd->pkg_auth[curr_pkg]) if (ifs_pkg_auth[curr_pkg])
continue; continue;
reinit_completion(&ifs_done); reinit_completion(&ifs_done);
local_work.dev = dev; local_work.dev = dev;
...@@ -215,7 +215,7 @@ static int scan_chunks_sanity_check(struct device *dev) ...@@ -215,7 +215,7 @@ static int scan_chunks_sanity_check(struct device *dev)
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
ifsd->pkg_auth[curr_pkg] = 1; ifs_pkg_auth[curr_pkg] = 1;
} }
ret = 0; ret = 0;
out: out:
...@@ -257,13 +257,14 @@ static int image_sanity_check(struct device *dev, const struct microcode_header_ ...@@ -257,13 +257,14 @@ static int image_sanity_check(struct device *dev, const struct microcode_header_
*/ */
int ifs_load_firmware(struct device *dev) int ifs_load_firmware(struct device *dev)
{ {
const struct ifs_test_caps *test = ifs_get_test_caps(dev);
struct ifs_data *ifsd = ifs_get_data(dev); struct ifs_data *ifsd = ifs_get_data(dev);
const struct firmware *fw; const struct firmware *fw;
char scan_path[64]; char scan_path[64];
int ret = -EINVAL; int ret = -EINVAL;
snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.scan", snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.scan",
ifsd->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model, test->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model,
boot_cpu_data.x86_stepping, ifsd->cur_batch); boot_cpu_data.x86_stepping, ifsd->cur_batch);
ret = request_firmware_direct(&fw, scan_path, dev); ret = request_firmware_direct(&fw, scan_path, dev);
......
...@@ -229,6 +229,85 @@ static void ifs_test_core(int cpu, struct device *dev) ...@@ -229,6 +229,85 @@ static void ifs_test_core(int cpu, struct device *dev)
} }
} }
#define SPINUNIT 100 /* 100 nsec */
static atomic_t array_cpus_out;
/*
* Simplified cpu sibling rendezvous loop based on microcode loader __wait_for_cpus()
*/
static void wait_for_sibling_cpu(atomic_t *t, long long timeout)
{
int cpu = smp_processor_id();
const struct cpumask *smt_mask = cpu_smt_mask(cpu);
int all_cpus = cpumask_weight(smt_mask);
atomic_inc(t);
while (atomic_read(t) < all_cpus) {
if (timeout < SPINUNIT)
return;
ndelay(SPINUNIT);
timeout -= SPINUNIT;
touch_nmi_watchdog();
}
}
static int do_array_test(void *data)
{
union ifs_array *command = data;
int cpu = smp_processor_id();
int first;
/*
* Only one logical CPU on a core needs to trigger the Array test via MSR write.
*/
first = cpumask_first(cpu_smt_mask(cpu));
if (cpu == first) {
wrmsrl(MSR_ARRAY_BIST, command->data);
/* Pass back the result of the test */
rdmsrl(MSR_ARRAY_BIST, command->data);
}
/* Tests complete faster if the sibling is spinning here */
wait_for_sibling_cpu(&array_cpus_out, NSEC_PER_SEC);
return 0;
}
static void ifs_array_test_core(int cpu, struct device *dev)
{
union ifs_array command = {};
bool timed_out = false;
struct ifs_data *ifsd;
unsigned long timeout;
ifsd = ifs_get_data(dev);
command.array_bitmask = ~0U;
timeout = jiffies + HZ / 2;
do {
if (time_after(jiffies, timeout)) {
timed_out = true;
break;
}
atomic_set(&array_cpus_out, 0);
stop_core_cpuslocked(cpu, do_array_test, &command);
if (command.ctrl_result)
break;
} while (command.array_bitmask);
ifsd->scan_details = command.data;
if (command.ctrl_result)
ifsd->status = SCAN_TEST_FAIL;
else if (timed_out || command.array_bitmask)
ifsd->status = SCAN_NOT_TESTED;
else
ifsd->status = SCAN_TEST_PASS;
}
/* /*
* Initiate per core test. It wakes up work queue threads on the target cpu and * Initiate per core test. It wakes up work queue threads on the target cpu and
* its sibling cpu. Once all sibling threads wake up, the scan test gets executed and * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and
...@@ -236,6 +315,8 @@ static void ifs_test_core(int cpu, struct device *dev) ...@@ -236,6 +315,8 @@ static void ifs_test_core(int cpu, struct device *dev)
*/ */
int do_core_test(int cpu, struct device *dev) int do_core_test(int cpu, struct device *dev)
{ {
const struct ifs_test_caps *test = ifs_get_test_caps(dev);
struct ifs_data *ifsd = ifs_get_data(dev);
int ret = 0; int ret = 0;
/* Prevent CPUs from being taken offline during the scan test */ /* Prevent CPUs from being taken offline during the scan test */
...@@ -247,7 +328,18 @@ int do_core_test(int cpu, struct device *dev) ...@@ -247,7 +328,18 @@ int do_core_test(int cpu, struct device *dev)
goto out; goto out;
} }
ifs_test_core(cpu, dev); switch (test->test_num) {
case IFS_TYPE_SAF:
if (!ifsd->loaded)
return -EPERM;
ifs_test_core(cpu, dev);
break;
case IFS_TYPE_ARRAY_BIST:
ifs_array_test_core(cpu, dev);
break;
default:
return -EINVAL;
}
out: out:
cpus_read_unlock(); cpus_read_unlock();
return ret; return ret;
......
...@@ -64,7 +64,6 @@ static ssize_t run_test_store(struct device *dev, ...@@ -64,7 +64,6 @@ static ssize_t run_test_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct ifs_data *ifsd = ifs_get_data(dev);
unsigned int cpu; unsigned int cpu;
int rc; int rc;
...@@ -75,10 +74,7 @@ static ssize_t run_test_store(struct device *dev, ...@@ -75,10 +74,7 @@ static ssize_t run_test_store(struct device *dev,
if (down_interruptible(&ifs_sem)) if (down_interruptible(&ifs_sem))
return -EINTR; return -EINTR;
if (!ifsd->loaded) rc = do_core_test(cpu, dev);
rc = -EPERM;
else
rc = do_core_test(cpu, dev);
up(&ifs_sem); up(&ifs_sem);
...@@ -141,7 +137,7 @@ static ssize_t image_version_show(struct device *dev, ...@@ -141,7 +137,7 @@ static ssize_t image_version_show(struct device *dev,
static DEVICE_ATTR_RO(image_version); static DEVICE_ATTR_RO(image_version);
/* global scan sysfs attributes */ /* global scan sysfs attributes */
static struct attribute *plat_ifs_attrs[] = { struct attribute *plat_ifs_attrs[] = {
&dev_attr_details.attr, &dev_attr_details.attr,
&dev_attr_status.attr, &dev_attr_status.attr,
&dev_attr_run_test.attr, &dev_attr_run_test.attr,
...@@ -150,9 +146,10 @@ static struct attribute *plat_ifs_attrs[] = { ...@@ -150,9 +146,10 @@ static struct attribute *plat_ifs_attrs[] = {
NULL NULL
}; };
ATTRIBUTE_GROUPS(plat_ifs); /* global array sysfs attributes */
struct attribute *plat_ifs_array_attrs[] = {
const struct attribute_group **ifs_get_groups(void) &dev_attr_details.attr,
{ &dev_attr_status.attr,
return plat_ifs_groups; &dev_attr_run_test.attr,
} NULL
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册