diff mbox

[kvm-unit-tests,3/4] arm/arm64: GICv2: add GICD_ITARGETSR testing

Message ID 20161117175752.16475-4-andre.przywara@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andre Przywara Nov. 17, 2016, 5:57 p.m. UTC
Some tests for the ITARGETS registers.
Bits corresponding to non-existent CPUs must be RAZ/WI.
These registers must be byte-accessible, also check that accesses beyond
the implemented IRQ limit are actually read-as-zero/write-ignore.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h |  1 +
 2 files changed, 55 insertions(+)

Comments

Andrew Jones Nov. 18, 2016, 2:20 p.m. UTC | #1
On Thu, Nov 17, 2016 at 05:57:51PM +0000, Andre Przywara wrote:
> Some tests for the ITARGETS registers.
> Bits corresponding to non-existent CPUs must be RAZ/WI.
> These registers must be byte-accessible, also check that accesses beyond
> the implemented IRQ limit are actually read-as-zero/write-ignore.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm/asm/gic.h |  1 +
>  2 files changed, 55 insertions(+)
> 
> diff --git a/arm/gic.c b/arm/gic.c
> index a27da2c..02b1be1 100644
> --- a/arm/gic.c
> +++ b/arm/gic.c
> @@ -397,6 +397,57 @@ static bool test_priorities(int nr_irqs, void *priptr)
>  	return true;
>  }
>  
> +static bool test_targets(int nr_irqs)
> +{
> +	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
> +	u32 orig_targets;
> +	u32 cpu_mask;
> +	u32 pattern, reg;
> +
> +	orig_targets = readl(targetsptr + 32);
> +	report_prefix_push("ITARGETSR");
> +
> +	cpu_mask = (1 << nr_cpus) - 1;

Shouldn't this be 1 << (nr_cpus - 1) ?

Is this test always going to be gicv2-only? We should probably comment it,
if so. We don't want to risk this being run when nr_cpus can be larger
than 8.

> +	cpu_mask |= cpu_mask << 8;
> +	cpu_mask |= cpu_mask << 16;
> +
> +	/* Check that bits for non implemented CPUs are RAZ/WI. */
> +	if (nr_cpus < 8) {
> +		writel(0xffffffff, targetsptr + 32);
> +		report("bits for %d non-existent CPUs masked",
> +		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);
> +	} else {
> +		report_skip("CPU masking (all CPUs implemented)");
> +	}
> +
> +	report("accesses beyond limit RAZ/WI",
> +	       test_readonly_32(targetsptr + nr_irqs, true));
> +
> +	pattern = 0x0103020f;
> +	writel(pattern, targetsptr + 32);
> +	reg = readl(targetsptr + 32);
> +	report("register content preserved (%08x => %08x)",
> +	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
> +
> +	/*
> +	 * The TARGETS registers are byte accessible, do a byte-wide
> +	 * read and write of known content to check for this.
> +	 */
> +	reg = readb(targetsptr + 33);
> +	report("byte reads successful (0x%08x => 0x%02x)",
> +	       reg == (BYTE(pattern, 1) & cpu_mask),
> +	       pattern & cpu_mask, reg);
> +
> +	pattern = REPLACE_BYTE(pattern, 2, 0x04);
> +	writeb(BYTE(pattern, 2), targetsptr + 34);
> +	reg = readl(targetsptr + 32);
> +	report("byte writes successful (0x%02x => 0x%08x)",
> +	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);

Last patch also had a byte addressability test. Maybe we should make
a helper function?

> +
> +	writel(orig_targets, targetsptr + 32);
> +	return true;

Function can/should be void.

> +}
> +
>  static int gic_test_mmio(int gic_version)
>  {
>  	u32 reg;
> @@ -436,6 +487,9 @@ static int gic_test_mmio(int gic_version)
>  
>  	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
>  
> +	if (gic_version == 2)
> +		test_targets(nr_irqs);
> +
>  	return 0;
>  }
>  
> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> index cef748d..6f170cb 100644
> --- a/lib/arm/asm/gic.h
> +++ b/lib/arm/asm/gic.h
> @@ -14,6 +14,7 @@
>  #define GICD_IGROUPR			0x0080
>  #define GICD_ISENABLER			0x0100
>  #define GICD_IPRIORITYR			0x0400
> +#define GICD_ITARGETSR			0x0800
>  #define GICD_SGIR			0x0f00
>  #define GICD_ICPIDR2			0x0fe8
>  
> -- 
> 2.9.0
> 
>

Thanks,
drew
Eric Auger Nov. 23, 2016, 1:24 p.m. UTC | #2
Hi,

On 18/11/2016 15:20, Andrew Jones wrote:
> On Thu, Nov 17, 2016 at 05:57:51PM +0000, Andre Przywara wrote:
>> Some tests for the ITARGETS registers.
>> Bits corresponding to non-existent CPUs must be RAZ/WI.
>> These registers must be byte-accessible, also check that accesses beyond
>> the implemented IRQ limit are actually read-as-zero/write-ignore.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  lib/arm/asm/gic.h |  1 +
>>  2 files changed, 55 insertions(+)
>>
>> diff --git a/arm/gic.c b/arm/gic.c
>> index a27da2c..02b1be1 100644
>> --- a/arm/gic.c
>> +++ b/arm/gic.c
>> @@ -397,6 +397,57 @@ static bool test_priorities(int nr_irqs, void *priptr)
>>  	return true;
>>  }
>>  
>> +static bool test_targets(int nr_irqs)
>> +{
>> +	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
>> +	u32 orig_targets;
>> +	u32 cpu_mask;
>> +	u32 pattern, reg;
>> +
>> +	orig_targets = readl(targetsptr + 32);
>> +	report_prefix_push("ITARGETSR");
>> +
>> +	cpu_mask = (1 << nr_cpus) - 1;
> 
> Shouldn't this be 1 << (nr_cpus - 1) ?
original looks correct to me.
> 
> Is this test always going to be gicv2-only? We should probably comment it,
> if so. We don't want to risk this being run when nr_cpus can be larger
> than 8.
> 
>> +	cpu_mask |= cpu_mask << 8;
>> +	cpu_mask |= cpu_mask << 16;
Don't we miss the 4th byte mask?

Thanks

Eric
>> +
>> +	/* Check that bits for non implemented CPUs are RAZ/WI. */
>> +	if (nr_cpus < 8) {
>> +		writel(0xffffffff, targetsptr + 32);
>> +		report("bits for %d non-existent CPUs masked",
>> +		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);
>> +	} else {
>> +		report_skip("CPU masking (all CPUs implemented)");
>> +	}
>> +
>> +	report("accesses beyond limit RAZ/WI",
>> +	       test_readonly_32(targetsptr + nr_irqs, true));
>> +
>> +	pattern = 0x0103020f;
>> +	writel(pattern, targetsptr + 32);
>> +	reg = readl(targetsptr + 32);
>> +	report("register content preserved (%08x => %08x)",
>> +	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
>> +
>> +	/*
>> +	 * The TARGETS registers are byte accessible, do a byte-wide
>> +	 * read and write of known content to check for this.
>> +	 */
>> +	reg = readb(targetsptr + 33);
>> +	report("byte reads successful (0x%08x => 0x%02x)",
>> +	       reg == (BYTE(pattern, 1) & cpu_mask),
>> +	       pattern & cpu_mask, reg);
>> +
>> +	pattern = REPLACE_BYTE(pattern, 2, 0x04);
>> +	writeb(BYTE(pattern, 2), targetsptr + 34);
>> +	reg = readl(targetsptr + 32);
>> +	report("byte writes successful (0x%02x => 0x%08x)",
>> +	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);
> 
> Last patch also had a byte addressability test. Maybe we should make
> a helper function?
> 
>> +
>> +	writel(orig_targets, targetsptr + 32);
>> +	return true;
> 
> Function can/should be void.
> 
>> +}
>> +
>>  static int gic_test_mmio(int gic_version)
>>  {
>>  	u32 reg;
>> @@ -436,6 +487,9 @@ static int gic_test_mmio(int gic_version)
>>  
>>  	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
>>  
>> +	if (gic_version == 2)
>> +		test_targets(nr_irqs);
>> +
>>  	return 0;
>>  }
>>  
>> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
>> index cef748d..6f170cb 100644
>> --- a/lib/arm/asm/gic.h
>> +++ b/lib/arm/asm/gic.h
>> @@ -14,6 +14,7 @@
>>  #define GICD_IGROUPR			0x0080
>>  #define GICD_ISENABLER			0x0100
>>  #define GICD_IPRIORITYR			0x0400
>> +#define GICD_ITARGETSR			0x0800
>>  #define GICD_SGIR			0x0f00
>>  #define GICD_ICPIDR2			0x0fe8
>>  
>> -- 
>> 2.9.0
>>
>>
> 
> Thanks,
> drew
>
Eric Auger Nov. 23, 2016, 1:51 p.m. UTC | #3
Hi Andre,

On 23/11/2016 14:24, Auger Eric wrote:
> Hi,
> 
> On 18/11/2016 15:20, Andrew Jones wrote:
>> On Thu, Nov 17, 2016 at 05:57:51PM +0000, Andre Przywara wrote:
>>> Some tests for the ITARGETS registers.
>>> Bits corresponding to non-existent CPUs must be RAZ/WI.
>>> These registers must be byte-accessible, also check that accesses beyond
>>> the implemented IRQ limit are actually read-as-zero/write-ignore.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  lib/arm/asm/gic.h |  1 +
>>>  2 files changed, 55 insertions(+)
>>>
>>> diff --git a/arm/gic.c b/arm/gic.c
>>> index a27da2c..02b1be1 100644
>>> --- a/arm/gic.c
>>> +++ b/arm/gic.c
>>> @@ -397,6 +397,57 @@ static bool test_priorities(int nr_irqs, void *priptr)
>>>  	return true;
>>>  }
>>>  
>>> +static bool test_targets(int nr_irqs)
>>> +{
>>> +	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
>>> +	u32 orig_targets;
>>> +	u32 cpu_mask;
>>> +	u32 pattern, reg;
>>> +
>>> +	orig_targets = readl(targetsptr + 32);
>>> +	report_prefix_push("ITARGETSR");
>>> +
>>> +	cpu_mask = (1 << nr_cpus) - 1;
>>
>> Shouldn't this be 1 << (nr_cpus - 1) ?
> original looks correct to me.
>>
>> Is this test always going to be gicv2-only? We should probably comment it,
>> if so. We don't want to risk this being run when nr_cpus can be larger
>> than 8.
>>
>>> +	cpu_mask |= cpu_mask << 8;
>>> +	cpu_mask |= cpu_mask << 16;
> Don't we miss the 4th byte mask?
> 
> Thanks
> 
> Eric
>>> +
>>> +	/* Check that bits for non implemented CPUs are RAZ/WI. */
>>> +	if (nr_cpus < 8) {
>>> +		writel(0xffffffff, targetsptr + 32);
>>> +		report("bits for %d non-existent CPUs masked",
>>> +		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);

yep on AMD overdrive with smp=4 I get:

FAIL: gicv2: mmio: ITARGETSR: bits for 4 non-existent CPUs masked

Thanks

Eric

>>> +	} else {
>>> +		report_skip("CPU masking (all CPUs implemented)");
>>> +	}
>>> +
>>> +	report("accesses beyond limit RAZ/WI",
>>> +	       test_readonly_32(targetsptr + nr_irqs, true));
>>> +
>>> +	pattern = 0x0103020f;
>>> +	writel(pattern, targetsptr + 32);
>>> +	reg = readl(targetsptr + 32);
>>> +	report("register content preserved (%08x => %08x)",
>>> +	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
>>> +
>>> +	/*
>>> +	 * The TARGETS registers are byte accessible, do a byte-wide
>>> +	 * read and write of known content to check for this.
>>> +	 */
>>> +	reg = readb(targetsptr + 33);
>>> +	report("byte reads successful (0x%08x => 0x%02x)",
>>> +	       reg == (BYTE(pattern, 1) & cpu_mask),
>>> +	       pattern & cpu_mask, reg);
>>> +
>>> +	pattern = REPLACE_BYTE(pattern, 2, 0x04);
>>> +	writeb(BYTE(pattern, 2), targetsptr + 34);
>>> +	reg = readl(targetsptr + 32);
>>> +	report("byte writes successful (0x%02x => 0x%08x)",
>>> +	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);
>>
>> Last patch also had a byte addressability test. Maybe we should make
>> a helper function?
>>
>>> +
>>> +	writel(orig_targets, targetsptr + 32);
>>> +	return true;
>>
>> Function can/should be void.
>>
>>> +}
>>> +
>>>  static int gic_test_mmio(int gic_version)
>>>  {
>>>  	u32 reg;
>>> @@ -436,6 +487,9 @@ static int gic_test_mmio(int gic_version)
>>>  
>>>  	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
>>>  
>>> +	if (gic_version == 2)
>>> +		test_targets(nr_irqs);
>>> +
>>>  	return 0;
>>>  }
>>>  
>>> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
>>> index cef748d..6f170cb 100644
>>> --- a/lib/arm/asm/gic.h
>>> +++ b/lib/arm/asm/gic.h
>>> @@ -14,6 +14,7 @@
>>>  #define GICD_IGROUPR			0x0080
>>>  #define GICD_ISENABLER			0x0100
>>>  #define GICD_IPRIORITYR			0x0400
>>> +#define GICD_ITARGETSR			0x0800
>>>  #define GICD_SGIR			0x0f00
>>>  #define GICD_ICPIDR2			0x0fe8
>>>  
>>> -- 
>>> 2.9.0
>>>
>>>
>>
>> Thanks,
>> drew
>>
Andre Przywara Nov. 23, 2016, 2:13 p.m. UTC | #4
Hi Eric,

thanks for having such a close look (as always!).

On 23/11/16 13:51, Auger Eric wrote:
> Hi Andre,
> 
> On 23/11/2016 14:24, Auger Eric wrote:
>> Hi,
>>
>> On 18/11/2016 15:20, Andrew Jones wrote:
>>> On Thu, Nov 17, 2016 at 05:57:51PM +0000, Andre Przywara wrote:
>>>> Some tests for the ITARGETS registers.
>>>> Bits corresponding to non-existent CPUs must be RAZ/WI.
>>>> These registers must be byte-accessible, also check that accesses beyond
>>>> the implemented IRQ limit are actually read-as-zero/write-ignore.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>>  arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  lib/arm/asm/gic.h |  1 +
>>>>  2 files changed, 55 insertions(+)
>>>>
>>>> diff --git a/arm/gic.c b/arm/gic.c
>>>> index a27da2c..02b1be1 100644
>>>> --- a/arm/gic.c
>>>> +++ b/arm/gic.c
>>>> @@ -397,6 +397,57 @@ static bool test_priorities(int nr_irqs, void *priptr)
>>>>  	return true;
>>>>  }
>>>>  
>>>> +static bool test_targets(int nr_irqs)
>>>> +{
>>>> +	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
>>>> +	u32 orig_targets;
>>>> +	u32 cpu_mask;
>>>> +	u32 pattern, reg;
>>>> +
>>>> +	orig_targets = readl(targetsptr + 32);
>>>> +	report_prefix_push("ITARGETSR");
>>>> +
>>>> +	cpu_mask = (1 << nr_cpus) - 1;
>>>
>>> Shouldn't this be 1 << (nr_cpus - 1) ?
>> original looks correct to me.
>>>
>>> Is this test always going to be gicv2-only? We should probably comment it,
>>> if so. We don't want to risk this being run when nr_cpus can be larger
>>> than 8.
>>>
>>>> +	cpu_mask |= cpu_mask << 8;

So this instruction is supposed to copy bits[7:0] into bits[15:8] (not
caring about the other bits, which are zero anyway).

>>>> +	cpu_mask |= cpu_mask << 16;

And this one copies bits[15:0] into bits[31:16].

>> Don't we miss the 4th byte mask?

I don't think so, the idea is just to copy the lowest byte into all the
other three bytes of that word and thus to propagate the byte mask for
one IRQ into a word covering four interrupts. Does that make sense?
I take it this deserves a comment then ...

>>>> +
>>>> +	/* Check that bits for non implemented CPUs are RAZ/WI. */
>>>> +	if (nr_cpus < 8) {
>>>> +		writel(0xffffffff, targetsptr + 32);
>>>> +		report("bits for %d non-existent CPUs masked",
>>>> +		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);
> 
> yep on AMD overdrive with smp=4 I get:
> 
> FAIL: gicv2: mmio: ITARGETSR: bits for 4 non-existent CPUs masked

I guess because you don't have
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/468296.html
in your host kernel?
This was one of the two genuine bugs I spotted with this.

Cheers,
Andre.

>>>> +	} else {
>>>> +		report_skip("CPU masking (all CPUs implemented)");
>>>> +	}
>>>> +
>>>> +	report("accesses beyond limit RAZ/WI",
>>>> +	       test_readonly_32(targetsptr + nr_irqs, true));
>>>> +
>>>> +	pattern = 0x0103020f;
>>>> +	writel(pattern, targetsptr + 32);
>>>> +	reg = readl(targetsptr + 32);
>>>> +	report("register content preserved (%08x => %08x)",
>>>> +	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
>>>> +
>>>> +	/*
>>>> +	 * The TARGETS registers are byte accessible, do a byte-wide
>>>> +	 * read and write of known content to check for this.
>>>> +	 */
>>>> +	reg = readb(targetsptr + 33);
>>>> +	report("byte reads successful (0x%08x => 0x%02x)",
>>>> +	       reg == (BYTE(pattern, 1) & cpu_mask),
>>>> +	       pattern & cpu_mask, reg);
>>>> +
>>>> +	pattern = REPLACE_BYTE(pattern, 2, 0x04);
>>>> +	writeb(BYTE(pattern, 2), targetsptr + 34);
>>>> +	reg = readl(targetsptr + 32);
>>>> +	report("byte writes successful (0x%02x => 0x%08x)",
>>>> +	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);
>>>
>>> Last patch also had a byte addressability test. Maybe we should make
>>> a helper function?
>>>
>>>> +
>>>> +	writel(orig_targets, targetsptr + 32);
>>>> +	return true;
>>>
>>> Function can/should be void.
>>>
>>>> +}
>>>> +
>>>>  static int gic_test_mmio(int gic_version)
>>>>  {
>>>>  	u32 reg;
>>>> @@ -436,6 +487,9 @@ static int gic_test_mmio(int gic_version)
>>>>  
>>>>  	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
>>>>  
>>>> +	if (gic_version == 2)
>>>> +		test_targets(nr_irqs);
>>>> +
>>>>  	return 0;
>>>>  }
>>>>  
>>>> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
>>>> index cef748d..6f170cb 100644
>>>> --- a/lib/arm/asm/gic.h
>>>> +++ b/lib/arm/asm/gic.h
>>>> @@ -14,6 +14,7 @@
>>>>  #define GICD_IGROUPR			0x0080
>>>>  #define GICD_ISENABLER			0x0100
>>>>  #define GICD_IPRIORITYR			0x0400
>>>> +#define GICD_ITARGETSR			0x0800
>>>>  #define GICD_SGIR			0x0f00
>>>>  #define GICD_ICPIDR2			0x0fe8
>>>>  
>>>> -- 
>>>> 2.9.0
>>>>
>>>>
>>>
>>> Thanks,
>>> drew
>>>
Eric Auger Nov. 23, 2016, 2:57 p.m. UTC | #5
Hi Andre,
On 23/11/2016 15:13, Andre Przywara wrote:
> Hi Eric,
> 
> thanks for having such a close look (as always!).
> 
> On 23/11/16 13:51, Auger Eric wrote:
>> Hi Andre,
>>
>> On 23/11/2016 14:24, Auger Eric wrote:
>>> Hi,
>>>
>>> On 18/11/2016 15:20, Andrew Jones wrote:
>>>> On Thu, Nov 17, 2016 at 05:57:51PM +0000, Andre Przywara wrote:
>>>>> Some tests for the ITARGETS registers.
>>>>> Bits corresponding to non-existent CPUs must be RAZ/WI.
>>>>> These registers must be byte-accessible, also check that accesses beyond
>>>>> the implemented IRQ limit are actually read-as-zero/write-ignore.
>>>>>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>>  arm/gic.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  lib/arm/asm/gic.h |  1 +
>>>>>  2 files changed, 55 insertions(+)
>>>>>
>>>>> diff --git a/arm/gic.c b/arm/gic.c
>>>>> index a27da2c..02b1be1 100644
>>>>> --- a/arm/gic.c
>>>>> +++ b/arm/gic.c
>>>>> @@ -397,6 +397,57 @@ static bool test_priorities(int nr_irqs, void *priptr)
>>>>>  	return true;
>>>>>  }
>>>>>  
>>>>> +static bool test_targets(int nr_irqs)
>>>>> +{
>>>>> +	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
>>>>> +	u32 orig_targets;
>>>>> +	u32 cpu_mask;
>>>>> +	u32 pattern, reg;
>>>>> +
>>>>> +	orig_targets = readl(targetsptr + 32);
>>>>> +	report_prefix_push("ITARGETSR");
>>>>> +
>>>>> +	cpu_mask = (1 << nr_cpus) - 1;
>>>>
>>>> Shouldn't this be 1 << (nr_cpus - 1) ?
>>> original looks correct to me.
>>>>
>>>> Is this test always going to be gicv2-only? We should probably comment it,
>>>> if so. We don't want to risk this being run when nr_cpus can be larger
>>>> than 8.
>>>>
>>>>> +	cpu_mask |= cpu_mask << 8;
> 
> So this instruction is supposed to copy bits[7:0] into bits[15:8] (not
> caring about the other bits, which are zero anyway).
> 
>>>>> +	cpu_mask |= cpu_mask << 16;
> 
> And this one copies bits[15:0] into bits[31:16].
> 
>>> Don't we miss the 4th byte mask?
> 
> I don't think so, the idea is just to copy the lowest byte into all the
> other three bytes of that word and thus to propagate the byte mask for
> one IRQ into a word covering four interrupts. Does that make sense?

Hum yes that's fully correct. Sorry for the noise.
> I take it this deserves a comment then ...
> 
>>>>> +
>>>>> +	/* Check that bits for non implemented CPUs are RAZ/WI. */
>>>>> +	if (nr_cpus < 8) {
>>>>> +		writel(0xffffffff, targetsptr + 32);
>>>>> +		report("bits for %d non-existent CPUs masked",
>>>>> +		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);
>>
>> yep on AMD overdrive with smp=4 I get:
>>
>> FAIL: gicv2: mmio: ITARGETSR: bits for 4 non-existent CPUs masked
> 
> I guess because you don't have
> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/468296.html
> in your host kernel?
> This was one of the two genuine bugs I spotted with this.

Ah ok cool!

Cheers

Eric
> 
> Cheers,
> Andre.
> 
>>>>> +	} else {
>>>>> +		report_skip("CPU masking (all CPUs implemented)");
>>>>> +	}
>>>>> +
>>>>> +	report("accesses beyond limit RAZ/WI",
>>>>> +	       test_readonly_32(targetsptr + nr_irqs, true));
>>>>> +
>>>>> +	pattern = 0x0103020f;
>>>>> +	writel(pattern, targetsptr + 32);
>>>>> +	reg = readl(targetsptr + 32);
>>>>> +	report("register content preserved (%08x => %08x)",
>>>>> +	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
>>>>> +
>>>>> +	/*
>>>>> +	 * The TARGETS registers are byte accessible, do a byte-wide
>>>>> +	 * read and write of known content to check for this.
>>>>> +	 */
>>>>> +	reg = readb(targetsptr + 33);
>>>>> +	report("byte reads successful (0x%08x => 0x%02x)",
>>>>> +	       reg == (BYTE(pattern, 1) & cpu_mask),
>>>>> +	       pattern & cpu_mask, reg);
>>>>> +
>>>>> +	pattern = REPLACE_BYTE(pattern, 2, 0x04);
>>>>> +	writeb(BYTE(pattern, 2), targetsptr + 34);
>>>>> +	reg = readl(targetsptr + 32);
>>>>> +	report("byte writes successful (0x%02x => 0x%08x)",
>>>>> +	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);
>>>>
>>>> Last patch also had a byte addressability test. Maybe we should make
>>>> a helper function?
>>>>
>>>>> +
>>>>> +	writel(orig_targets, targetsptr + 32);
>>>>> +	return true;
>>>>
>>>> Function can/should be void.
>>>>
>>>>> +}
>>>>> +
>>>>>  static int gic_test_mmio(int gic_version)
>>>>>  {
>>>>>  	u32 reg;
>>>>> @@ -436,6 +487,9 @@ static int gic_test_mmio(int gic_version)
>>>>>  
>>>>>  	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
>>>>>  
>>>>> +	if (gic_version == 2)
>>>>> +		test_targets(nr_irqs);
>>>>> +
>>>>>  	return 0;
>>>>>  }
>>>>>  
>>>>> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
>>>>> index cef748d..6f170cb 100644
>>>>> --- a/lib/arm/asm/gic.h
>>>>> +++ b/lib/arm/asm/gic.h
>>>>> @@ -14,6 +14,7 @@
>>>>>  #define GICD_IGROUPR			0x0080
>>>>>  #define GICD_ISENABLER			0x0100
>>>>>  #define GICD_IPRIORITYR			0x0400
>>>>> +#define GICD_ITARGETSR			0x0800
>>>>>  #define GICD_SGIR			0x0f00
>>>>>  #define GICD_ICPIDR2			0x0fe8
>>>>>  
>>>>> -- 
>>>>> 2.9.0
>>>>>
>>>>>
>>>>
>>>> Thanks,
>>>> drew
>>>>
>
diff mbox

Patch

diff --git a/arm/gic.c b/arm/gic.c
index a27da2c..02b1be1 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -397,6 +397,57 @@  static bool test_priorities(int nr_irqs, void *priptr)
 	return true;
 }
 
+static bool test_targets(int nr_irqs)
+{
+	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
+	u32 orig_targets;
+	u32 cpu_mask;
+	u32 pattern, reg;
+
+	orig_targets = readl(targetsptr + 32);
+	report_prefix_push("ITARGETSR");
+
+	cpu_mask = (1 << nr_cpus) - 1;
+	cpu_mask |= cpu_mask << 8;
+	cpu_mask |= cpu_mask << 16;
+
+	/* Check that bits for non implemented CPUs are RAZ/WI. */
+	if (nr_cpus < 8) {
+		writel(0xffffffff, targetsptr + 32);
+		report("bits for %d non-existent CPUs masked",
+		       !(readl(targetsptr + 32) & ~cpu_mask), 8 - nr_cpus);
+	} else {
+		report_skip("CPU masking (all CPUs implemented)");
+	}
+
+	report("accesses beyond limit RAZ/WI",
+	       test_readonly_32(targetsptr + nr_irqs, true));
+
+	pattern = 0x0103020f;
+	writel(pattern, targetsptr + 32);
+	reg = readl(targetsptr + 32);
+	report("register content preserved (%08x => %08x)",
+	       reg == (pattern & cpu_mask), pattern & cpu_mask, reg);
+
+	/*
+	 * The TARGETS registers are byte accessible, do a byte-wide
+	 * read and write of known content to check for this.
+	 */
+	reg = readb(targetsptr + 33);
+	report("byte reads successful (0x%08x => 0x%02x)",
+	       reg == (BYTE(pattern, 1) & cpu_mask),
+	       pattern & cpu_mask, reg);
+
+	pattern = REPLACE_BYTE(pattern, 2, 0x04);
+	writeb(BYTE(pattern, 2), targetsptr + 34);
+	reg = readl(targetsptr + 32);
+	report("byte writes successful (0x%02x => 0x%08x)",
+	       reg == (pattern & cpu_mask), BYTE(pattern, 2), reg);
+
+	writel(orig_targets, targetsptr + 32);
+	return true;
+}
+
 static int gic_test_mmio(int gic_version)
 {
 	u32 reg;
@@ -436,6 +487,9 @@  static int gic_test_mmio(int gic_version)
 
 	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
 
+	if (gic_version == 2)
+		test_targets(nr_irqs);
+
 	return 0;
 }
 
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index cef748d..6f170cb 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -14,6 +14,7 @@ 
 #define GICD_IGROUPR			0x0080
 #define GICD_ISENABLER			0x0100
 #define GICD_IPRIORITYR			0x0400
+#define GICD_ITARGETSR			0x0800
 #define GICD_SGIR			0x0f00
 #define GICD_ICPIDR2			0x0fe8