Initial implementation assumed a single IFS test image file with a fixed name ff-mm-ss.scan. (where ff, mm, ss refers to family, model and stepping of the core). Subsequently, it became evident that supporting more than one test image file is needed to provide more comprehensive test coverage. (Test coverage in this scenario refers to testing more transistors in the core to identify faults). The other alternative of increasing the size of a single scan test image file would not work as the upper bound is limited by the size of memory area reserved by BIOS for loading IFS test image. Introduce "current_batch" file which accepts a number. Writing a number to the current_batch file would load the test image file by name ff-mm-ss-<xy>.scan, where <xy> is the number written to the "current_batch" file in hex. Range check of the input is done to verify it not greater than 0xff. For e.g if the scan test image comprises of 6 files, they would be named: 06-8f-06-01.scan 06-8f-06-02.scan 06-8f-06-03.scan 06-8f-06-04.scan 06-8f-06-05.scan 06-8f-06-06.scan And writing 3 to current_batch would result in loading 06-8f-06-03.scan above. The file can also be read to know the currently loaded file. And testing a system looks like: for each scan file do load the IFS test image file (write to the batch file) for each core do test the core with this set of tests done done Qualify few error messages with the test image file suffix to provide better context. [ bp: Massage commit message. Add link to the discussion. ] Signed-off-by: Jithu Joseph <jithu.joseph@intel.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Tony Luck <tony.luck@intel.com> Reviewed-by: Sohil Mehta <sohil.mehta@intel.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20221107225323.2733518-13-jithu.joseph@intel.com
159 lines
3.4 KiB
C
159 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* Copyright(c) 2022 Intel Corporation. */
|
|
|
|
#include <linux/cpu.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "ifs.h"
|
|
|
|
/*
|
|
* Protects against simultaneous tests on multiple cores, or
|
|
* reloading can file while a test is in progress
|
|
*/
|
|
static DEFINE_SEMAPHORE(ifs_sem);
|
|
|
|
/*
|
|
* The sysfs interface to check additional details of last test
|
|
* cat /sys/devices/system/platform/ifs/details
|
|
*/
|
|
static ssize_t details_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
|
|
return sysfs_emit(buf, "%#llx\n", ifsd->scan_details);
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(details);
|
|
|
|
static const char * const status_msg[] = {
|
|
[SCAN_NOT_TESTED] = "untested",
|
|
[SCAN_TEST_PASS] = "pass",
|
|
[SCAN_TEST_FAIL] = "fail"
|
|
};
|
|
|
|
/*
|
|
* The sysfs interface to check the test status:
|
|
* To check the status of last test
|
|
* cat /sys/devices/platform/ifs/status
|
|
*/
|
|
static ssize_t status_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
|
|
return sysfs_emit(buf, "%s\n", status_msg[ifsd->status]);
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(status);
|
|
|
|
/*
|
|
* The sysfs interface for single core testing
|
|
* To start test, for example, cpu5
|
|
* echo 5 > /sys/devices/platform/ifs/run_test
|
|
* To check the result:
|
|
* cat /sys/devices/platform/ifs/result
|
|
* The sibling core gets tested at the same time.
|
|
*/
|
|
static ssize_t run_test_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
unsigned int cpu;
|
|
int rc;
|
|
|
|
rc = kstrtouint(buf, 0, &cpu);
|
|
if (rc < 0 || cpu >= nr_cpu_ids)
|
|
return -EINVAL;
|
|
|
|
if (down_interruptible(&ifs_sem))
|
|
return -EINTR;
|
|
|
|
if (!ifsd->loaded)
|
|
rc = -EPERM;
|
|
else
|
|
rc = do_core_test(cpu, dev);
|
|
|
|
up(&ifs_sem);
|
|
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static DEVICE_ATTR_WO(run_test);
|
|
|
|
static ssize_t current_batch_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
unsigned int cur_batch;
|
|
int rc;
|
|
|
|
rc = kstrtouint(buf, 0, &cur_batch);
|
|
if (rc < 0 || cur_batch > 0xff)
|
|
return -EINVAL;
|
|
|
|
if (down_interruptible(&ifs_sem))
|
|
return -EINTR;
|
|
|
|
ifsd->cur_batch = cur_batch;
|
|
|
|
rc = ifs_load_firmware(dev);
|
|
|
|
up(&ifs_sem);
|
|
|
|
return (rc == 0) ? count : rc;
|
|
}
|
|
|
|
static ssize_t current_batch_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
|
|
if (!ifsd->loaded)
|
|
return sysfs_emit(buf, "none\n");
|
|
else
|
|
return sysfs_emit(buf, "0x%02x\n", ifsd->cur_batch);
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(current_batch);
|
|
|
|
/*
|
|
* Display currently loaded IFS image version.
|
|
*/
|
|
static ssize_t image_version_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct ifs_data *ifsd = ifs_get_data(dev);
|
|
|
|
if (!ifsd->loaded)
|
|
return sysfs_emit(buf, "%s\n", "none");
|
|
else
|
|
return sysfs_emit(buf, "%#x\n", ifsd->loaded_version);
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(image_version);
|
|
|
|
/* global scan sysfs attributes */
|
|
static struct attribute *plat_ifs_attrs[] = {
|
|
&dev_attr_details.attr,
|
|
&dev_attr_status.attr,
|
|
&dev_attr_run_test.attr,
|
|
&dev_attr_current_batch.attr,
|
|
&dev_attr_image_version.attr,
|
|
NULL
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(plat_ifs);
|
|
|
|
const struct attribute_group **ifs_get_groups(void)
|
|
{
|
|
return plat_ifs_groups;
|
|
}
|