diff mbox series

[kvm-unit-tests,04/10] s390x: smp: Test local interrupts after cpu reset

Message ID 20200324081251.28810-5-frankja@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390x: smp: Improve smp code part 2 | expand

Commit Message

Janosch Frank March 24, 2020, 8:12 a.m. UTC
Local interrupts (external and emergency call) should be cleared after
any cpu reset.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 s390x/smp.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Comments

Cornelia Huck March 24, 2020, 12:06 p.m. UTC | #1
On Tue, 24 Mar 2020 04:12:45 -0400
Janosch Frank <frankja@linux.ibm.com> wrote:

> Local interrupts (external and emergency call) should be cleared after
> any cpu reset.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  s390x/smp.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 

Reviewed-by: Cornelia Huck <cohuck@redhat.com>
David Hildenbrand March 31, 2020, 9:07 a.m. UTC | #2
On 24.03.20 09:12, Janosch Frank wrote:
> Local interrupts (external and emergency call) should be cleared after
> any cpu reset.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  s390x/smp.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/s390x/smp.c b/s390x/smp.c
> index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
> --- a/s390x/smp.c
> +++ b/s390x/smp.c
> @@ -243,6 +243,20 @@ static void test_reset_initial(void)
>  	report_prefix_pop();
>  }
>  
> +static void test_local_ints(void)
> +{
> +	unsigned long mask;
> +
> +	expect_ext_int();
> +	/* Open masks for ecall and emcall */
> +	ctl_set_bit(0, 13);
> +	ctl_set_bit(0, 14);
> +	mask = extract_psw_mask();
> +	mask |= PSW_MASK_EXT;
> +	load_psw_mask(mask);
> +	set_flag(1);
> +}
> +
>  static void test_reset(void)
>  {
>  	struct psw psw;
> @@ -251,10 +265,18 @@ static void test_reset(void)
>  	psw.addr = (unsigned long)test_func;
>  
>  	report_prefix_push("cpu reset");
> +	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
> +	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
>  	smp_cpu_start(1, psw);
>  
>  	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
>  	report(smp_cpu_stopped(1), "cpu stopped");
> +
> +	set_flag(0);
> +	psw.addr = (unsigned long)test_local_ints;
> +	smp_cpu_start(1, psw);
> +	wait_for_flag();
> +	report(true, "local interrupts cleared");


How can you be sure they were actually cleared/delivered?
Janosch Frank March 31, 2020, 9:28 a.m. UTC | #3
On 3/31/20 11:07 AM, David Hildenbrand wrote:
> On 24.03.20 09:12, Janosch Frank wrote:
>> Local interrupts (external and emergency call) should be cleared after
>> any cpu reset.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  s390x/smp.c | 22 ++++++++++++++++++++++
>>  1 file changed, 22 insertions(+)
>>
>> diff --git a/s390x/smp.c b/s390x/smp.c
>> index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
>> --- a/s390x/smp.c
>> +++ b/s390x/smp.c
>> @@ -243,6 +243,20 @@ static void test_reset_initial(void)
>>  	report_prefix_pop();
>>  }
>>  
>> +static void test_local_ints(void)
>> +{
>> +	unsigned long mask;
>> +
>> +	expect_ext_int();
>> +	/* Open masks for ecall and emcall */
>> +	ctl_set_bit(0, 13);
>> +	ctl_set_bit(0, 14);
>> +	mask = extract_psw_mask();
>> +	mask |= PSW_MASK_EXT;
>> +	load_psw_mask(mask);
>> +	set_flag(1);
>> +}
>> +
>>  static void test_reset(void)
>>  {
>>  	struct psw psw;
>> @@ -251,10 +265,18 @@ static void test_reset(void)
>>  	psw.addr = (unsigned long)test_func;
>>  
>>  	report_prefix_push("cpu reset");
>> +	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
>> +	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
>>  	smp_cpu_start(1, psw);
>>  
>>  	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
>>  	report(smp_cpu_stopped(1), "cpu stopped");
>> +
>> +	set_flag(0);
>> +	psw.addr = (unsigned long)test_local_ints;
>> +	smp_cpu_start(1, psw);
>> +	wait_for_flag();
>> +	report(true, "local interrupts cleared");
> 
> 
> How can you be sure they were actually cleared/delivered?
> 
Because cpu 1 would get a ext int it didn't expect and would do a
report_abort() as pecified in lib/s390x/interrupt.c
David Hildenbrand March 31, 2020, 5:27 p.m. UTC | #4
On 31.03.20 11:28, Janosch Frank wrote:
> On 3/31/20 11:07 AM, David Hildenbrand wrote:
>> On 24.03.20 09:12, Janosch Frank wrote:
>>> Local interrupts (external and emergency call) should be cleared after
>>> any cpu reset.
>>>
>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>> ---
>>>  s390x/smp.c | 22 ++++++++++++++++++++++
>>>  1 file changed, 22 insertions(+)
>>>
>>> diff --git a/s390x/smp.c b/s390x/smp.c
>>> index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
>>> --- a/s390x/smp.c
>>> +++ b/s390x/smp.c
>>> @@ -243,6 +243,20 @@ static void test_reset_initial(void)
>>>  	report_prefix_pop();
>>>  }
>>>  
>>> +static void test_local_ints(void)
>>> +{
>>> +	unsigned long mask;
>>> +
>>> +	expect_ext_int();
>>> +	/* Open masks for ecall and emcall */
>>> +	ctl_set_bit(0, 13);
>>> +	ctl_set_bit(0, 14);
>>> +	mask = extract_psw_mask();
>>> +	mask |= PSW_MASK_EXT;
>>> +	load_psw_mask(mask);
>>> +	set_flag(1);
>>> +}
>>> +
>>>  static void test_reset(void)
>>>  {
>>>  	struct psw psw;
>>> @@ -251,10 +265,18 @@ static void test_reset(void)
>>>  	psw.addr = (unsigned long)test_func;
>>>  
>>>  	report_prefix_push("cpu reset");
>>> +	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
>>> +	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
>>>  	smp_cpu_start(1, psw);
>>>  
>>>  	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
>>>  	report(smp_cpu_stopped(1), "cpu stopped");
>>> +
>>> +	set_flag(0);
>>> +	psw.addr = (unsigned long)test_local_ints;
>>> +	smp_cpu_start(1, psw);
>>> +	wait_for_flag();
>>> +	report(true, "local interrupts cleared");
>>
>>
>> How can you be sure they were actually cleared/delivered?
>>
> Because cpu 1 would get a ext int it didn't expect and would do a
> report_abort() as pecified in lib/s390x/interrupt.c

But what if it *didn't* get the interrupts delivered.

Then cpu 1 will simply (test_local_ints()) unlock interrupts, load the
psw mask, set the flag and be done with it. What am I missing? How can
you be sure the interrupts on cpu 1 were actually delivered?
Janosch Frank April 1, 2020, 7:19 a.m. UTC | #5
On 3/31/20 7:27 PM, David Hildenbrand wrote:
> On 31.03.20 11:28, Janosch Frank wrote:
>> On 3/31/20 11:07 AM, David Hildenbrand wrote:
>>> On 24.03.20 09:12, Janosch Frank wrote:
>>>> Local interrupts (external and emergency call) should be cleared after
>>>> any cpu reset.
>>>>
>>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>>> ---
>>>>  s390x/smp.c | 22 ++++++++++++++++++++++
>>>>  1 file changed, 22 insertions(+)
>>>>
>>>> diff --git a/s390x/smp.c b/s390x/smp.c
>>>> index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
>>>> --- a/s390x/smp.c
>>>> +++ b/s390x/smp.c
>>>> @@ -243,6 +243,20 @@ static void test_reset_initial(void)
>>>>  	report_prefix_pop();
>>>>  }
>>>>  
>>>> +static void test_local_ints(void)
>>>> +{
>>>> +	unsigned long mask;
>>>> +
>>>> +	expect_ext_int();
>>>> +	/* Open masks for ecall and emcall */
>>>> +	ctl_set_bit(0, 13);
>>>> +	ctl_set_bit(0, 14);
>>>> +	mask = extract_psw_mask();
>>>> +	mask |= PSW_MASK_EXT;
>>>> +	load_psw_mask(mask);
>>>> +	set_flag(1);
>>>> +}
>>>> +
>>>>  static void test_reset(void)
>>>>  {
>>>>  	struct psw psw;
>>>> @@ -251,10 +265,18 @@ static void test_reset(void)
>>>>  	psw.addr = (unsigned long)test_func;
>>>>  
>>>>  	report_prefix_push("cpu reset");
>>>> +	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
>>>> +	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
>>>>  	smp_cpu_start(1, psw);
>>>>  
>>>>  	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
>>>>  	report(smp_cpu_stopped(1), "cpu stopped");
>>>> +
>>>> +	set_flag(0);
>>>> +	psw.addr = (unsigned long)test_local_ints;
>>>> +	smp_cpu_start(1, psw);
>>>> +	wait_for_flag();
>>>> +	report(true, "local interrupts cleared");
>>>
>>>
>>> How can you be sure they were actually cleared/delivered?
>>>
>> Because cpu 1 would get a ext int it didn't expect and would do a
>> report_abort() as pecified in lib/s390x/interrupt.c
> 
> But what if it *didn't* get the interrupts delivered.

Well, the target is still looping until the reset initial test is
executed and from personal experience I can say that this test bites
rather fast.

We could execute an instruction with a mandatory exit which will prompt
KVM to inject any remaining IRQs before setting the flag to 1.

Unfortunately we do not have a polling instruction for non-IO interrupts
at the moment to verify this test.

> 
> Then cpu 1 will simply (test_local_ints()) unlock interrupts, load the
> psw mask, set the flag and be done with it. What am I missing? How can
> you be sure the interrupts on cpu 1 were actually delivered?
>
David Hildenbrand April 6, 2020, 9:27 a.m. UTC | #6
On 01.04.20 09:19, Janosch Frank wrote:
> On 3/31/20 7:27 PM, David Hildenbrand wrote:
>> On 31.03.20 11:28, Janosch Frank wrote:
>>> On 3/31/20 11:07 AM, David Hildenbrand wrote:
>>>> On 24.03.20 09:12, Janosch Frank wrote:
>>>>> Local interrupts (external and emergency call) should be cleared after
>>>>> any cpu reset.
>>>>>
>>>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>>>> ---
>>>>>  s390x/smp.c | 22 ++++++++++++++++++++++
>>>>>  1 file changed, 22 insertions(+)
>>>>>
>>>>> diff --git a/s390x/smp.c b/s390x/smp.c
>>>>> index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
>>>>> --- a/s390x/smp.c
>>>>> +++ b/s390x/smp.c
>>>>> @@ -243,6 +243,20 @@ static void test_reset_initial(void)
>>>>>  	report_prefix_pop();
>>>>>  }
>>>>>  
>>>>> +static void test_local_ints(void)
>>>>> +{
>>>>> +	unsigned long mask;
>>>>> +
>>>>> +	expect_ext_int();
>>>>> +	/* Open masks for ecall and emcall */
>>>>> +	ctl_set_bit(0, 13);
>>>>> +	ctl_set_bit(0, 14);
>>>>> +	mask = extract_psw_mask();
>>>>> +	mask |= PSW_MASK_EXT;
>>>>> +	load_psw_mask(mask);
>>>>> +	set_flag(1);
>>>>> +}
>>>>> +
>>>>>  static void test_reset(void)
>>>>>  {
>>>>>  	struct psw psw;
>>>>> @@ -251,10 +265,18 @@ static void test_reset(void)
>>>>>  	psw.addr = (unsigned long)test_func;
>>>>>  
>>>>>  	report_prefix_push("cpu reset");
>>>>> +	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
>>>>> +	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
>>>>>  	smp_cpu_start(1, psw);
>>>>>  
>>>>>  	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
>>>>>  	report(smp_cpu_stopped(1), "cpu stopped");
>>>>> +
>>>>> +	set_flag(0);
>>>>> +	psw.addr = (unsigned long)test_local_ints;
>>>>> +	smp_cpu_start(1, psw);
>>>>> +	wait_for_flag();
>>>>> +	report(true, "local interrupts cleared");
>>>>
>>>>
>>>> How can you be sure they were actually cleared/delivered?
>>>>
>>> Because cpu 1 would get a ext int it didn't expect and would do a
>>> report_abort() as pecified in lib/s390x/interrupt.c
>>
>> But what if it *didn't* get the interrupts delivered.
> 
> Well, the target is still looping until the reset initial test is
> executed and from personal experience I can say that this test bites
> rather fast.
> 
> We could execute an instruction with a mandatory exit which will prompt
> KVM to inject any remaining IRQs before setting the flag to 1.
> 
> Unfortunately we do not have a polling instruction for non-IO interrupts
> at the moment to verify this test.


I'd expect you should do something like this in your test instead

static void test_local_ints(void)
{
	unsigned long mask;

	/* Enable external interrupts */
	mask = extract_psw_mask();
	mask |= PSW_MASK_EXT;
	load_psw_mask(mask);

	expect_ext_int();
	/* Open masks for external call */
	ctl_set_bit(0, 13);
	if (lc->ext_int_code != $TODO1)
	       return;

	expect_ext_int();
	/* Open masks for emergency call */
	ctl_set_bit(0, 14);
	if (lc->ext_int_code != $TODO2)
	       return;

	set_flag(1);
}
diff mbox series

Patch

diff --git a/s390x/smp.c b/s390x/smp.c
index 8a6cd1d8b17d76c6..a8e3dd7aac0c788c 100644
--- a/s390x/smp.c
+++ b/s390x/smp.c
@@ -243,6 +243,20 @@  static void test_reset_initial(void)
 	report_prefix_pop();
 }
 
+static void test_local_ints(void)
+{
+	unsigned long mask;
+
+	expect_ext_int();
+	/* Open masks for ecall and emcall */
+	ctl_set_bit(0, 13);
+	ctl_set_bit(0, 14);
+	mask = extract_psw_mask();
+	mask |= PSW_MASK_EXT;
+	load_psw_mask(mask);
+	set_flag(1);
+}
+
 static void test_reset(void)
 {
 	struct psw psw;
@@ -251,10 +265,18 @@  static void test_reset(void)
 	psw.addr = (unsigned long)test_func;
 
 	report_prefix_push("cpu reset");
+	sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL);
+	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
 	smp_cpu_start(1, psw);
 
 	sigp_retry(1, SIGP_CPU_RESET, 0, NULL);
 	report(smp_cpu_stopped(1), "cpu stopped");
+
+	set_flag(0);
+	psw.addr = (unsigned long)test_local_ints;
+	smp_cpu_start(1, psw);
+	wait_for_flag();
+	report(true, "local interrupts cleared");
 	report_prefix_pop();
 }