diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/platform/x86/intel/ifs | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/platform/x86/intel/ifs')
| -rw-r--r-- | drivers/platform/x86/intel/ifs/core.c | 81 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/ifs/ifs.h | 68 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/ifs/load.c | 11 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/ifs/runtest.c | 94 | ||||
| -rw-r--r-- | drivers/platform/x86/intel/ifs/sysfs.c | 23 | 
5 files changed, 215 insertions, 62 deletions
diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index 206a617c2e02..306f886b52d2 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -16,27 +16,63 @@  static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {  	X86_MATCH(SAPPHIRERAPIDS_X), +	X86_MATCH(EMERALDRAPIDS_X),  	{}  };  MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); -static struct ifs_device ifs_device = { -	.data = { -		.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT, -		.test_num = 0, +ATTRIBUTE_GROUPS(plat_ifs); +ATTRIBUTE_GROUPS(plat_ifs_array); + +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 = { -		.name = "intel_ifs_0", -		.nodename = "intel_ifs/0", -		.minor = MISC_DYNAMIC_MINOR, +	[IFS_TYPE_ARRAY_BIST] = { +		.test_caps = &array_test, +		.misc = { +			.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)  {  	const struct x86_cpu_id *m;  	u64 msrval; -	int ret; +	int i, ret;  	m = x86_match_cpu(ifs_cpu_ids);  	if (!m) @@ -51,28 +87,27 @@ static int __init ifs_init(void)  	if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))  		return -ENODEV; -	ifs_device.misc.groups = ifs_get_groups(); - -	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) +	ifs_pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL); +	if (!ifs_pkg_auth)  		return -ENOMEM; -	ret = misc_register(&ifs_device.misc); -	if (ret) { -		kfree(ifs_device.data.pkg_auth); -		return ret; +	for (i = 0; i < IFS_NUMTESTS; i++) { +		if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit))) +			continue; +		ret = misc_register(&ifs_devices[i].misc); +		if (ret) +			goto err_exit;  	} -  	return 0; + +err_exit: +	ifs_cleanup(); +	return ret;  }  static void __exit ifs_exit(void)  { -	misc_deregister(&ifs_device.misc); -	kfree(ifs_device.data.pkg_auth); +	ifs_cleanup();  }  module_init(ifs_init); diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 046e39304fd5..93191855890f 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -17,7 +17,7 @@   * 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.   * 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 @@ -25,7 +25,10 @@   *   * Intel provides a firmware file containing the scan tests via   * 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   * ----------------- @@ -35,7 +38,7 @@   * SHA hashes for the test. Then the tests themselves. Status MSRs provide   * 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   * fashion:   * ff-mm-ss-01.scan @@ -47,7 +50,7 @@   * (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::   * - *   # 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.   * @@ -69,16 +72,16 @@   * to migrate those applications to other cores before running a core test.   * 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   * 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:   *   * 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   * its corresponding physical core. Since the tests are per physical core, @@ -87,21 +90,21 @@   *   * 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::   * - *   $ cat /sys/devices/virtual/misc/intel_ifs_0/status + *   $ cat /sys/devices/virtual/misc/intel_ifs_<n>/status   *   pass   *   * Status can be one of pass, fail, untested   *   * 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   * - * 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   * Software Developer's Manual but the error_code field may contain one of   * the following driver defined software codes: @@ -127,6 +130,7 @@  #include <linux/device.h>  #include <linux/miscdevice.h> +#define MSR_ARRAY_BIST				0x00000105  #define MSR_COPY_SCAN_HASHES			0x000002c2  #define MSR_SCAN_HASHES_STATUS			0x000002c3  #define MSR_AUTHENTICATE_AND_COPY_CHUNK		0x000002c4 @@ -137,6 +141,9 @@  #define SCAN_TEST_PASS				1  #define SCAN_TEST_FAIL				2 +#define IFS_TYPE_SAF			0 +#define IFS_TYPE_ARRAY_BIST		1 +  /* MSR_SCAN_HASHES_STATUS bit fields */  union ifs_scan_hashes_status {  	u64	data; @@ -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   * 0xFD: Test timed out before completing all the chunks. @@ -197,22 +215,22 @@ union ifs_status {  #define IFS_SW_TIMEOUT				0xFD  #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 - * @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test   * @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   * @loading_error: Error occurred on another CPU while loading image   * @valid_chunks: number of chunks which could be validated.   * @status: it holds simple status pass/fail/untested   * @scan_details: opaque scan status code from h/w   * @cur_batch: number indicating the currently loaded test file - * @test_num: number indicating the test type   */  struct ifs_data { -	int	integrity_cap_bit; -	bool	*pkg_auth;  	int	loaded_version;  	bool	loaded;  	bool	loading_error; @@ -220,7 +238,6 @@ struct ifs_data {  	int	status;  	u64	scan_details;  	u32	cur_batch; -	int	test_num;  };  struct ifs_work { @@ -229,7 +246,8 @@ struct ifs_work {  };  struct ifs_device { -	struct ifs_data data; +	const struct ifs_test_caps *test_caps; +	struct ifs_data rw_data;  	struct miscdevice misc;  }; @@ -238,11 +256,21 @@ static inline struct ifs_data *ifs_get_data(struct device *dev)  	struct miscdevice *m = dev_get_drvdata(dev);  	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 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 diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index c5c24e6fdc43..e6ae8265f3a3 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -192,7 +192,7 @@ static int scan_chunks_sanity_check(struct device *dev)  	struct ifs_work local_work;  	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);  	if (ret)  		return ret; @@ -204,18 +204,18 @@ static int scan_chunks_sanity_check(struct device *dev)  	cpus_read_lock();  	for_each_online_cpu(cpu) {  		curr_pkg = topology_physical_package_id(cpu); -		if (ifsd->pkg_auth[curr_pkg]) +		if (ifs_pkg_auth[curr_pkg])  			continue;  		reinit_completion(&ifs_done);  		local_work.dev = dev; -		INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks); +		INIT_WORK_ONSTACK(&local_work.w, copy_hashes_authenticate_chunks);  		schedule_work_on(cpu, &local_work.w);  		wait_for_completion(&ifs_done);  		if (ifsd->loading_error) {  			ret = -EIO;  			goto out;  		} -		ifsd->pkg_auth[curr_pkg] = 1; +		ifs_pkg_auth[curr_pkg] = 1;  	}  	ret = 0;  out: @@ -257,13 +257,14 @@ static int image_sanity_check(struct device *dev, const struct microcode_header_   */  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);  	const struct firmware *fw;  	char scan_path[64];  	int ret = -EINVAL;  	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);  	ret = request_firmware_direct(&fw, scan_path, dev); diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 0bfd8fcdd7e8..1061eb7ec399 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -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   * 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)   */  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;  	/* Prevent CPUs from being taken offline during the scan test */ @@ -247,7 +328,18 @@ int do_core_test(int cpu, struct device *dev)  		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:  	cpus_read_unlock();  	return ret; diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c index ee636a76b083..01b7502f46b0 100644 --- a/drivers/platform/x86/intel/ifs/sysfs.c +++ b/drivers/platform/x86/intel/ifs/sysfs.c @@ -13,7 +13,7 @@   * Protects against simultaneous tests on multiple cores, or   * reloading can file while a test is in progress   */ -static DEFINE_SEMAPHORE(ifs_sem); +static DEFINE_SEMAPHORE(ifs_sem, 1);  /*   * The sysfs interface to check additional details of last test @@ -64,7 +64,6 @@ 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; @@ -75,10 +74,7 @@ static ssize_t run_test_store(struct device *dev,  	if (down_interruptible(&ifs_sem))  		return -EINTR; -	if (!ifsd->loaded) -		rc = -EPERM; -	else -		rc = do_core_test(cpu, dev); +	rc = do_core_test(cpu, dev);  	up(&ifs_sem); @@ -141,7 +137,7 @@ static ssize_t image_version_show(struct device *dev,  static DEVICE_ATTR_RO(image_version);  /* global scan sysfs attributes */ -static struct attribute *plat_ifs_attrs[] = { +struct attribute *plat_ifs_attrs[] = {  	&dev_attr_details.attr,  	&dev_attr_status.attr,  	&dev_attr_run_test.attr, @@ -150,9 +146,10 @@ static struct attribute *plat_ifs_attrs[] = {  	NULL  }; -ATTRIBUTE_GROUPS(plat_ifs); - -const struct attribute_group **ifs_get_groups(void) -{ -	return plat_ifs_groups; -} +/* global array sysfs attributes */ +struct attribute *plat_ifs_array_attrs[] = { +	&dev_attr_details.attr, +	&dev_attr_status.attr, +	&dev_attr_run_test.attr, +	NULL +};  |