diff mbox series

[v3,4/8] platform/x86/intel/ifs: Introduce Array Scan test to IFS

Message ID 20230301015942.462799-5-jithu.joseph@intel.com (mailing list archive)
State Changes Requested, archived
Headers show
Series Add Array BIST test support to IFS | expand

Commit Message

Joseph, Jithu March 1, 2023, 1:59 a.m. UTC
Array BIST is a new type of core test introduced under the Intel Infield
Scan (IFS) suite of tests.

Emerald Rapids (EMR) is the first CPU to support Array BIST.
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).

Make changes in the device driver init flow to register this new test
type with the device driver framework. Each test will have its own
sysfs directory (intel_ifs_0 , intel_ifs_1) under misc hierarchy to
accommodate for the differences in test type and how they are initiated.

Upcoming patches will add actual support.

Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
---
 drivers/platform/x86/intel/ifs/ifs.h  |  3 +
 drivers/platform/x86/intel/ifs/core.c | 85 +++++++++++++++++++--------
 2 files changed, 62 insertions(+), 26 deletions(-)

Comments

Hans de Goede March 13, 2023, 4:10 p.m. UTC | #1
Hi,

On 3/1/23 02:59, Jithu Joseph wrote:
> Array BIST is a new type of core test introduced under the Intel Infield
> Scan (IFS) suite of tests.
> 
> Emerald Rapids (EMR) is the first CPU to support Array BIST.
> 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).
> 
> Make changes in the device driver init flow to register this new test
> type with the device driver framework. Each test will have its own
> sysfs directory (intel_ifs_0 , intel_ifs_1) under misc hierarchy to
> accommodate for the differences in test type and how they are initiated.
> 
> Upcoming patches will add actual support.
> 
> Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
> Reviewed-by: Tony Luck <tony.luck@intel.com>
> ---
>  drivers/platform/x86/intel/ifs/ifs.h  |  3 +
>  drivers/platform/x86/intel/ifs/core.c | 85 +++++++++++++++++++--------
>  2 files changed, 62 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
> index ab168ddf28f1..b8b956e29653 100644
> --- a/drivers/platform/x86/intel/ifs/ifs.h
> +++ b/drivers/platform/x86/intel/ifs/ifs.h
> @@ -137,6 +137,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;
> diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
> index 62c44dbae757..2237aaba7078 100644
> --- a/drivers/platform/x86/intel/ifs/core.c
> +++ b/drivers/platform/x86/intel/ifs/core.c
> @@ -16,6 +16,7 @@
>  
>  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);

Note you can add driver_data to a match table like this. What you should
do here is use the driver data to point to the const ifs_hw_caps discussed
before, so what you get here is:

#define X86_MATCH(model, data)                          \
        X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6,    \
                INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, (unsigned long)(data))

static const struct ifs_hw_caps saphire_rapids_caps = {
	.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
	.test_num = 0,
};

static const struct ifs_hw_caps emerald_rapids_caps = {
	.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
	.test_num = 0,
};

static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
	X86_MATCH(SAPPHIRERAPIDS_X, &saphire_rapids_caps),
	X86_MATCH(EMERALDRAPIDS_X, &emerald_rapids_caps),
	{}
};
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);

and then drop all the code related to having an array of ifs_device structs
(of which only 1 will ever get used) and instead at the beginning of
ifs_init(void), after:

        m = x86_match_cpu(ifs_cpu_ids);
        if (!m)
                return -ENODEV;

add:

	ifs_device.hwcaps = (const struct ifs_hw_caps *)m->driver_data;

And then you can pretty much drop all the rest of this patch and we
end up with much nicer code for differentiating between the models :)

Regards,

Hans






> @@ -24,23 +25,51 @@ ATTRIBUTE_GROUPS(plat_ifs);
>  
>  bool *ifs_pkg_auth;
>  
> -static struct ifs_device ifs_device = {
> -	.ro_data = {
> -		.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> -		.test_num = 0,
> +static struct ifs_device ifs_devices[] = {
> +	[IFS_TYPE_SAF] = {
> +		.ro_data = {
> +			.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> +			.test_num = IFS_TYPE_SAF,
> +		},
> +		.misc = {
> +			.name = "intel_ifs_0",
> +			.minor = MISC_DYNAMIC_MINOR,
> +			.groups = plat_ifs_groups,
> +		},
>  	},
> -	.misc = {
> -		.name = "intel_ifs_0",
> -		.minor = MISC_DYNAMIC_MINOR,
> -		.groups = plat_ifs_groups,
> +	[IFS_TYPE_ARRAY_BIST] = {
> +		.ro_data = {
> +			.integrity_cap_bit = MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT,
> +			.test_num = IFS_TYPE_ARRAY_BIST,
> +		},
> +		.misc = {
> +			.name = "intel_ifs_1",
> +			.minor = MISC_DYNAMIC_MINOR,
> +		},
>  	},
>  };
>  
> +#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_devices[i].rw_data);
> +		}
> +	}
> +	kfree(ifs_pkg_auth);
> +}
> +
>  static int __init ifs_init(void)
>  {
>  	const struct x86_cpu_id *m;
>  	struct ifs_data *ifsd;
>  	u64 msrval;
> +	int i, ret;
>  
>  	m = x86_match_cpu(ifs_cpu_ids);
>  	if (!m)
> @@ -55,35 +84,39 @@ static int __init ifs_init(void)
>  	if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
>  		return -ENODEV;
>  
> -	if (!(msrval & BIT(ifs_device.ro_data.integrity_cap_bit)))
> -		return -ENODEV;
> -
>  	ifs_pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL);
>  	if (!ifs_pkg_auth)
>  		return -ENOMEM;
>  
> -	ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
> -	if (!ifsd)
> -		return -ENOMEM;
> -
> -	ifsd->ro_info = &ifs_device.ro_data;
> -	ifs_device.rw_data = ifsd;
> -
> -	if (misc_register(&ifs_device.misc)) {
> -		kfree(ifsd);
> -		kfree(ifs_pkg_auth);
> -		return -ENODEV;
> +	for (i = 0; i < IFS_NUMTESTS; i++) {
> +		ifsd = NULL;
> +		if (!(msrval & BIT(ifs_devices[i].ro_data.integrity_cap_bit)))
> +			continue;
> +
> +		ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
> +		if (!ifsd) {
> +			ret = -ENOMEM;
> +			goto err_exit;
> +		}
> +		ifsd->ro_info = &ifs_devices[i].ro_data;
> +		ifs_devices[i].rw_data = ifsd;
> +
> +		if (misc_register(&ifs_devices[i].misc)) {
> +			ret = -ENODEV;
> +			kfree(ifsd);
> +			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.rw_data);
> -	kfree(ifs_pkg_auth);
> +	ifs_cleanup();
>  }
>  
>  module_init(ifs_init);
Hans de Goede March 13, 2023, 4:29 p.m. UTC | #2
Hi,

On 3/13/23 17:10, Hans de Goede wrote:
> Hi,
> 
> On 3/1/23 02:59, Jithu Joseph wrote:
>> Array BIST is a new type of core test introduced under the Intel Infield
>> Scan (IFS) suite of tests.
>>
>> Emerald Rapids (EMR) is the first CPU to support Array BIST.
>> 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).
>>
>> Make changes in the device driver init flow to register this new test
>> type with the device driver framework. Each test will have its own
>> sysfs directory (intel_ifs_0 , intel_ifs_1) under misc hierarchy to
>> accommodate for the differences in test type and how they are initiated.
>>
>> Upcoming patches will add actual support.
>>
>> Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
>> Reviewed-by: Tony Luck <tony.luck@intel.com>
>> ---
>>  drivers/platform/x86/intel/ifs/ifs.h  |  3 +
>>  drivers/platform/x86/intel/ifs/core.c | 85 +++++++++++++++++++--------
>>  2 files changed, 62 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
>> index ab168ddf28f1..b8b956e29653 100644
>> --- a/drivers/platform/x86/intel/ifs/ifs.h
>> +++ b/drivers/platform/x86/intel/ifs/ifs.h
>> @@ -137,6 +137,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;
>> diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
>> index 62c44dbae757..2237aaba7078 100644
>> --- a/drivers/platform/x86/intel/ifs/core.c
>> +++ b/drivers/platform/x86/intel/ifs/core.c
>> @@ -16,6 +16,7 @@
>>  
>>  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);
> 
> Note you can add driver_data to a match table like this. What you should
> do here is use the driver data to point to the const ifs_hw_caps discussed
> before, so what you get here is:
> 
> #define X86_MATCH(model, data)                          \
>         X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6,    \
>                 INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, (unsigned long)(data))
> 
> static const struct ifs_hw_caps saphire_rapids_caps = {
> 	.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> 	.test_num = 0,
> };
> 
> static const struct ifs_hw_caps emerald_rapids_caps = {
> 	.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> 	.test_num = 0,
> };
> 
> static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
> 	X86_MATCH(SAPPHIRERAPIDS_X, &saphire_rapids_caps),
> 	X86_MATCH(EMERALDRAPIDS_X, &emerald_rapids_caps),
> 	{}
> };
> MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
> 
> and then drop all the code related to having an array of ifs_device structs
> (of which only 1 will ever get used) and instead at the beginning of
> ifs_init(void), after:
> 
>         m = x86_match_cpu(ifs_cpu_ids);
>         if (!m)
>                 return -ENODEV;
> 
> add:
> 
> 	ifs_device.hwcaps = (const struct ifs_hw_caps *)m->driver_data;
> 
> And then you can pretty much drop all the rest of this patch and we
> end up with much nicer code for differentiating between the models :)

Upon reading the rest of the series, I think the above might be based
on me misunderstanding this bit.

If I understand things correctly then what is new with emerald_rapids
is support for a second set/type of tests called " Array Scan test"
and the old test method / test-type is also still supported.

And you have chosen to register 2 misc-devices , one per supported
test type ?

Have I understood that correcty?

May I ask why use 1 misc device per test-type. Why not just add
a single new sysfs_attr to the existing misc device to trigger
the new test-type ?

Regards,

Hans


>> @@ -24,23 +25,51 @@ ATTRIBUTE_GROUPS(plat_ifs);
>>  
>>  bool *ifs_pkg_auth;
>>  
>> -static struct ifs_device ifs_device = {
>> -	.ro_data = {
>> -		.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
>> -		.test_num = 0,
>> +static struct ifs_device ifs_devices[] = {
>> +	[IFS_TYPE_SAF] = {
>> +		.ro_data = {
>> +			.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
>> +			.test_num = IFS_TYPE_SAF,
>> +		},
>> +		.misc = {
>> +			.name = "intel_ifs_0",
>> +			.minor = MISC_DYNAMIC_MINOR,
>> +			.groups = plat_ifs_groups,
>> +		},
>>  	},
>> -	.misc = {
>> -		.name = "intel_ifs_0",
>> -		.minor = MISC_DYNAMIC_MINOR,
>> -		.groups = plat_ifs_groups,
>> +	[IFS_TYPE_ARRAY_BIST] = {
>> +		.ro_data = {
>> +			.integrity_cap_bit = MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT,
>> +			.test_num = IFS_TYPE_ARRAY_BIST,
>> +		},
>> +		.misc = {
>> +			.name = "intel_ifs_1",
>> +			.minor = MISC_DYNAMIC_MINOR,
>> +		},
>>  	},
>>  };
>>  
>> +#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_devices[i].rw_data);
>> +		}
>> +	}
>> +	kfree(ifs_pkg_auth);
>> +}
>> +
>>  static int __init ifs_init(void)
>>  {
>>  	const struct x86_cpu_id *m;
>>  	struct ifs_data *ifsd;
>>  	u64 msrval;
>> +	int i, ret;
>>  
>>  	m = x86_match_cpu(ifs_cpu_ids);
>>  	if (!m)
>> @@ -55,35 +84,39 @@ static int __init ifs_init(void)
>>  	if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
>>  		return -ENODEV;
>>  
>> -	if (!(msrval & BIT(ifs_device.ro_data.integrity_cap_bit)))
>> -		return -ENODEV;
>> -
>>  	ifs_pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL);
>>  	if (!ifs_pkg_auth)
>>  		return -ENOMEM;
>>  
>> -	ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
>> -	if (!ifsd)
>> -		return -ENOMEM;
>> -
>> -	ifsd->ro_info = &ifs_device.ro_data;
>> -	ifs_device.rw_data = ifsd;
>> -
>> -	if (misc_register(&ifs_device.misc)) {
>> -		kfree(ifsd);
>> -		kfree(ifs_pkg_auth);
>> -		return -ENODEV;
>> +	for (i = 0; i < IFS_NUMTESTS; i++) {
>> +		ifsd = NULL;
>> +		if (!(msrval & BIT(ifs_devices[i].ro_data.integrity_cap_bit)))
>> +			continue;
>> +
>> +		ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
>> +		if (!ifsd) {
>> +			ret = -ENOMEM;
>> +			goto err_exit;
>> +		}
>> +		ifsd->ro_info = &ifs_devices[i].ro_data;
>> +		ifs_devices[i].rw_data = ifsd;
>> +
>> +		if (misc_register(&ifs_devices[i].misc)) {
>> +			ret = -ENODEV;
>> +			kfree(ifsd);
>> +			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.rw_data);
>> -	kfree(ifs_pkg_auth);
>> +	ifs_cleanup();
>>  }
>>  
>>  module_init(ifs_init);
Tony Luck March 13, 2023, 5:21 p.m. UTC | #3
> Upon reading the rest of the series, I think the above might be based
> on me misunderstanding this bit.
>
> If I understand things correctly then what is new with emerald_rapids
> is support for a second set/type of tests called " Array Scan test"
> and the old test method / test-type is also still supported.

Yes. Emerald Rapids supports the new array scan test *in addition to*
the existing scan test.  Future CPUs will support both of these tests
and may add additional tests. Further in the future if some new tests
cover the same functionality as older tests, some of the older tests
may be dropped.

So the INTEGRITY_CAPABILITIES MSR is a bitmap enumerating
which tests are supported on each model.

> And you have chosen to register 2 misc-devices , one per supported
> test type ?
>
> Have I understood that correctly?

Yes.

> May I ask why use 1 misc device per test-type. Why not just add
> a single new sysfs_attr to the existing misc device to trigger
> the new test-type ?

That's an interesting idea. So we'd have:

# echo $cpu > run_test
# cat status
...
# cat details
...

for our first type of test (introduced with Sapphire Rapids). Then
in the same directory add a new file to run the array test (on Emerald
Rapids andother future CPUs that support it)

# echo $cpu > run_array_test
# cat status
...
# cat details
...

But I see a problem with the "current_batch" file (that will show up if a future
test also needs to load some test data ... spoiler ... it will).

We can't do:

# echo 2 > current_batch
  ... what should this load, don't know until the user types one of

# echo $cpu > run_test

or

# echo $cpu > run_${name}_test

Perhaps also have per test type names to load the test images?

# echo 2 > current_${name}_batch
# echo $cpu > run_${name}_test


I'm not sure this is better than splitting the tests into different directories.

-Tony
Joseph, Jithu March 15, 2023, 7:29 p.m. UTC | #4
On 3/13/2023 10:21 AM, Luck, Tony wrote:

> 
> 
> I'm not sure this is better than splitting the tests into different directories.
> 

To provide a bit more context to Tony's response - 
There are similarities between tests (one of the test inputs is cpu number , which is 
common among different tests , so are the test outputs described via status / details attributes)
and some differences too (distinct to each test are the test patterns, some tests needs to
load test patterns appropriate for that test type and some does not)

Current approach of keeping each test's attributes in its own directory (intel_ifs_n)
allows the driver to account for the differences naturally, for e.g load test file
suited for a specific test. (I.e if the load is issued from intel_ifs_<n> , the driver
will load test patterns from /lib/firmware/intel/ifs/ifs_<n>/ff-mm-ss-xx.<type_n>).
If load is not applicable for a test type , test directory doesn’t show load and image_version attributes). 

As Tony mentioned, similar effect might be achieved using distinct load / run (and image_version)
files for each test type, but the current approach of organizing files per test feels a little
bit more intuitive. 

Grouping attributes per test was the original design intent , when the first test was introduced,
as indicated by the existing ABI doc (Documentation/ABI/testing/sysfs-platform-intel-ifs),
wherein attributes are described under /sys/devices/virtual/misc/intel_ifs_<N>/ …

Hans, Shall I revise the series incorporating the rest of your comments ?

Jithu
Hans de Goede March 16, 2023, 9:50 a.m. UTC | #5
Hi,

On 3/15/23 20:29, Joseph, Jithu wrote:
> 
> 
> On 3/13/2023 10:21 AM, Luck, Tony wrote:
> 
>>
>>
>> I'm not sure this is better than splitting the tests into different directories.
>>
> 
> To provide a bit more context to Tony's response - 
> There are similarities between tests (one of the test inputs is cpu number , which is 
> common among different tests , so are the test outputs described via status / details attributes)
> and some differences too (distinct to each test are the test patterns, some tests needs to
> load test patterns appropriate for that test type and some does not)
> 
> Current approach of keeping each test's attributes in its own directory (intel_ifs_n)
> allows the driver to account for the differences naturally, for e.g load test file
> suited for a specific test. (I.e if the load is issued from intel_ifs_<n> , the driver
> will load test patterns from /lib/firmware/intel/ifs/ifs_<n>/ff-mm-ss-xx.<type_n>).
> If load is not applicable for a test type , test directory doesn’t show load and image_version attributes). 
> 
> As Tony mentioned, similar effect might be achieved using distinct load / run (and image_version)
> files for each test type, but the current approach of organizing files per test feels a little
> bit more intuitive. 
> 
> Grouping attributes per test was the original design intent , when the first test was introduced,
> as indicated by the existing ABI doc (Documentation/ABI/testing/sysfs-platform-intel-ifs),
> wherein attributes are described under /sys/devices/virtual/misc/intel_ifs_<N>/ …

Ok I see, lets go with 1 intel_ifs device per test-type then.

If I understood things correctly esp. also with the /lib/firmware path then the <N> in intel_ifs_<N> basically specifies the test-type, correct ?

If I have that correct please add this to the ABI documentation in the form of a list with

intel_ifs_<N> <-> test-type

mappings. And also add documentation to each attribute for which test-types the attribute is valid (this can be "all" for e.g. status, to avoid churn when adding more test types).

> Hans, Shall I revise the series incorporating the rest of your comments ?

Yes please.

Regards,

Hans
Joseph, Jithu March 16, 2023, 7:44 p.m. UTC | #6
On 3/16/2023 2:50 AM, Hans de Goede wrote:

> Ok I see, lets go with 1 intel_ifs device per test-type then.
> 
> If I understood things correctly esp. also with the /lib/firmware path then the <N> in intel_ifs_<N> basically specifies the test-type, correct ?
> 

Correct

> If I have that correct please add this to the ABI documentation in the form of a list with
> 
> intel_ifs_<N> <-> test-type
> 
> mappings. And also add documentation to each attribute for which test-types the attribute is valid (this can be "all" for e.g. status, to avoid churn when adding more test types).

Will do. Thanks for the review comments

Jithu
diff mbox series

Patch

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index ab168ddf28f1..b8b956e29653 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -137,6 +137,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;
diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
index 62c44dbae757..2237aaba7078 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -16,6 +16,7 @@ 
 
 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);
@@ -24,23 +25,51 @@  ATTRIBUTE_GROUPS(plat_ifs);
 
 bool *ifs_pkg_auth;
 
-static struct ifs_device ifs_device = {
-	.ro_data = {
-		.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
-		.test_num = 0,
+static struct ifs_device ifs_devices[] = {
+	[IFS_TYPE_SAF] = {
+		.ro_data = {
+			.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
+			.test_num = IFS_TYPE_SAF,
+		},
+		.misc = {
+			.name = "intel_ifs_0",
+			.minor = MISC_DYNAMIC_MINOR,
+			.groups = plat_ifs_groups,
+		},
 	},
-	.misc = {
-		.name = "intel_ifs_0",
-		.minor = MISC_DYNAMIC_MINOR,
-		.groups = plat_ifs_groups,
+	[IFS_TYPE_ARRAY_BIST] = {
+		.ro_data = {
+			.integrity_cap_bit = MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT,
+			.test_num = IFS_TYPE_ARRAY_BIST,
+		},
+		.misc = {
+			.name = "intel_ifs_1",
+			.minor = MISC_DYNAMIC_MINOR,
+		},
 	},
 };
 
+#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_devices[i].rw_data);
+		}
+	}
+	kfree(ifs_pkg_auth);
+}
+
 static int __init ifs_init(void)
 {
 	const struct x86_cpu_id *m;
 	struct ifs_data *ifsd;
 	u64 msrval;
+	int i, ret;
 
 	m = x86_match_cpu(ifs_cpu_ids);
 	if (!m)
@@ -55,35 +84,39 @@  static int __init ifs_init(void)
 	if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
 		return -ENODEV;
 
-	if (!(msrval & BIT(ifs_device.ro_data.integrity_cap_bit)))
-		return -ENODEV;
-
 	ifs_pkg_auth = kmalloc_array(topology_max_packages(), sizeof(bool), GFP_KERNEL);
 	if (!ifs_pkg_auth)
 		return -ENOMEM;
 
-	ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
-	if (!ifsd)
-		return -ENOMEM;
-
-	ifsd->ro_info = &ifs_device.ro_data;
-	ifs_device.rw_data = ifsd;
-
-	if (misc_register(&ifs_device.misc)) {
-		kfree(ifsd);
-		kfree(ifs_pkg_auth);
-		return -ENODEV;
+	for (i = 0; i < IFS_NUMTESTS; i++) {
+		ifsd = NULL;
+		if (!(msrval & BIT(ifs_devices[i].ro_data.integrity_cap_bit)))
+			continue;
+
+		ifsd = kzalloc(sizeof(*ifsd), GFP_KERNEL);
+		if (!ifsd) {
+			ret = -ENOMEM;
+			goto err_exit;
+		}
+		ifsd->ro_info = &ifs_devices[i].ro_data;
+		ifs_devices[i].rw_data = ifsd;
+
+		if (misc_register(&ifs_devices[i].misc)) {
+			ret = -ENODEV;
+			kfree(ifsd);
+			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.rw_data);
-	kfree(ifs_pkg_auth);
+	ifs_cleanup();
 }
 
 module_init(ifs_init);