[PATCH v2] irqchip/gicv3: Add support for Range Selector (RS) feature
Marc Zyngier
marc.zyngier at arm.com
Thu Oct 5 11:00:44 PDT 2017
On 05/10/17 18:49, Shanker Donthineni wrote:
> Hi Marc,
>
> On 10/05/2017 05:43 AM, Marc Zyngier wrote:
>> On 20/09/17 04:21, Shanker Donthineni wrote:
>>> A new feature Range Selector (RS) has been added to GIC specification
>>> in order to support more than 16 CPUs at affinity level 0. New fields
>>> are introduced in SGI system registers (ICC_SGI0R_EL1, ICC_SGI1R_EL1
>>> and ICC_ASGI1R_EL1) to relax an artificial limit of 16 at level 0.
>>>
>>> - A new RSS field in ICC_CTLR_EL3, ICC_CTLR_EL1 and ICV_CTLR_EL1:
>>> [18] - Range Selector Support (RSS)
>>> 0b0 = Targeted SGIs with affinity level 0 values of 0-15 are supported.
>>> 0b1 = Targeted SGIs with affinity level 0 values of 0-255 are supported.
>>>
>>> - A new RS field in ICC_SGI0R_EL1, ICC_SGI1R_EL1 and ICC_ASGI1R_EL1:
>>> [47:44] - RangeSelector (RS) which group of 16 TargetList[n] field
>>> TargetList[n] represents aff0 value ((RS*16)+n)
>>> When ICC_CTLR_EL3.RSS==0 or ICC_CTLR_EL1.RSS==0, RS is RES0.
>>>
>>> - A new RSS field in GICD_TYPER:
>>> [26] - Range Selector Support (RSS)
>>> 0b0 = Targeted SGIs with affinity level 0 values of 0-15 are supported.
>>> 0b1 = Targeted SGIs with affinity level 0 values of 0-255 are supported.
>>>
>>> Signed-off-by: Shanker Donthineni <shankerd at codeaurora.org>
>>> ---
>>> Changes since v1:
>>> - Addrssed Marc's review comments on RSS validation checks.
>>> - Apply code changes to gic_compute_target_list() to support RSS feature.
>>> - Fix the compilation on ARM32.
>>>
>>> arch/arm/include/asm/arch_gicv3.h | 5 ++++
>>> arch/arm64/include/asm/arch_gicv3.h | 5 ++++
>>> drivers/irqchip/irq-gic-v3.c | 60 +++++++++++++++++++++++++++++++------
>>> include/linux/irqchip/arm-gic-v3.h | 4 +++
>>> 4 files changed, 65 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
>>> index 2747590..4a3b3c2 100644
>>> --- a/arch/arm/include/asm/arch_gicv3.h
>>> +++ b/arch/arm/include/asm/arch_gicv3.h
>>> @@ -196,6 +196,11 @@ static inline void gic_write_ctlr(u32 val)
>>> isb();
>>> }
>>>
>>> +static inline u32 gic_read_ctlr(void)
>>> +{
>>> + return read_sysreg(ICC_CTLR);
>>> +}
>>> +
>>> static inline void gic_write_grpen1(u32 val)
>>> {
>>> write_sysreg(val, ICC_IGRPEN1);
>>> diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
>>> index 8cef47f..aa2c795 100644
>>> --- a/arch/arm64/include/asm/arch_gicv3.h
>>> +++ b/arch/arm64/include/asm/arch_gicv3.h
>>> @@ -87,6 +87,11 @@ static inline void gic_write_ctlr(u32 val)
>>> isb();
>>> }
>>>
>>> +static inline u32 gic_read_ctlr(void)
>>> +{
>>> + return read_sysreg_s(SYS_ICC_CTLR_EL1);
>>> +}
>>> +
>>> static inline void gic_write_grpen1(u32 val)
>>> {
>>> write_sysreg_s(val, SYS_ICC_IGRPEN1_EL1);
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index 984c3ec..2d56f2b 100644
>>> --- a/drivers/irqchip/irq-gic-v3.c
>>> +++ b/drivers/irqchip/irq-gic-v3.c
>>> @@ -55,6 +55,7 @@ struct gic_chip_data {
>>> struct irq_domain *domain;
>>> u64 redist_stride;
>>> u32 nr_redist_regions;
>>> + bool has_rss;
>>> unsigned int irq_nr;
>>> struct partition_desc *ppi_descs[16];
>>> };
>>> @@ -63,7 +64,9 @@ struct gic_chip_data {
>>> static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
>>>
>>> static struct gic_kvm_info gic_v3_kvm_info;
>>> +static DEFINE_PER_CPU(bool, has_rss);
>>>
>>> +#define MPIDR_RS(mpidr) (((mpidr) & 0xF0UL) >> 4)
>>> #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist))
>>> #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
>>> #define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K)
>>> @@ -483,6 +486,10 @@ static int gic_populate_rdist(void)
>>>
>>> static void gic_cpu_sys_reg_init(void)
>>> {
>>> + int i, cpu = smp_processor_id();
>>> + u64 mpidr = cpu_logical_map(cpu);
>>> + bool need_rss = false;
>>> +
>>> /*
>>> * Need to check that the SRE bit has actually been set. If
>>> * not, it means that SRE is disabled at EL2. We're going to
>>> @@ -514,6 +521,40 @@ static void gic_cpu_sys_reg_init(void)
>>>
>>> /* ... and let's hit the road... */
>>> gic_write_grpen1(1);
>>> +
>>> + /* Keep the RSS capability status in per_cpu variable */
>>> + per_cpu(has_rss, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS);
>>> +
>>> + /* Check all the CPUs have capable of sending SGIs to other CPUs */
>>> + for_each_online_cpu(i) {
>>> + if (cpu == i)
>>> + continue;
>>> +
>>> + if (MPIDR_RS(mpidr) && (!per_cpu(has_rss, i))) {
>>> + pr_crit("CPU%d has no RSS, SGIs aren't reachable to CPU%d",
>>> + i, cpu);
>>> + continue;
>>> + }
>>> +
>>> + if (MPIDR_RS(cpu_logical_map(i)) && (!per_cpu(has_rss, cpu))) {
>>> + pr_crit("CPU%d has no RSS, SGIs aren't reachable to CPU%d",
>>> + cpu, i);
>>> + continue;
>>> + }
>>> +
>>> + if (MPIDR_RS(mpidr) || MPIDR_RS(cpu_logical_map(i)))
>>> + need_rss = true;
>>> + }
>>
>> The logic feels a bit clumsy, and fails to warn if the first CPU needs
>> RSS while the distributor doesn't have it. Yes, that's the ultimate
>> corner case, but hey, we might as well do the right thing... ;-)
>>
>
> Agree with you it won't warn on systems booted with a single core. In case of
> multicore boot it warns while booting the secondary cores and covers all
> the combination of CPUs. Anyway I like simplified idea with a fewer lines of
> code that does the same purpose.
>
>
>> How about something like:
>>
>> for_each_online_cpu(i) {
>> bool have_rss = per_cpu(has_rss, i) || per_cpu(has_rss, cpu);
>> need_rss = MPIDR_RS(mpidr) || MPIDR_RS(cpu_logical_map(i);
>>
>> if (need_rss != have_rss)
>> pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n",
>> cpu, mpidr, i, cpu_logical_map(i));
>> }
>>
>
> This code should work with minor changes on top of the above code snippet.
>
> for_each_online_cpu(i) {
> bool have_rss = per_cpu(has_rss, i) && per_cpu(has_rss, cpu);
> need_rss = MPIDR_RS(mpidr) || MPIDR_RS(cpu_logical_map(i)) || need_rss;
Ah, I managed to kill a single character that made it work.
At some point, it said:
need_rss |= MPIDR_RS(mpidr) || MPIDR_RS(cpu_logical_map(i);
And looking at it a bit more closely, you can init need_rss to
MPIDR_RS(mpidr) at the beginning of the function, and make this
need_rss |= MPIDR_RS(cpu_logical_map(i);
Have a play with it anyway, I haven't looked too closely at it...
> if (need_rss != have_rss)
> pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n",
> cpu, mpidr, i, cpu_logical_map(i));
> }
>
>> which is informative enough.
>>
>>> +
>>> + /**
>>> + * GIC spec says, when ICC_CTLR_EL1.RSS==1 and GICD_TYPER.RSS==0,
>>> + * writing ICC_ASGI1R_EL1 register with RS != 0 is a CONSTRAINED
>>> + * UNPREDICTABLE choice of :
>>> + * - The write is ignored.
>>> + * - The RS field is treated as 0.
>>> + */
>>> + if (need_rss && (!gic_data.has_rss))
>>> + pr_crit("RSS support is required but GICD doesn't support it\n");
>>
>> This can be turn to a pr_crit_once, as there is no need to scream for
>> each CPU (the thing is dead anyway).
>>
>
> I'll fix in v3.
Great, thanks.
M.
--
Jazz is not dead. It just smells funny...
More information about the linux-arm-kernel
mailing list