[PATCH 1/1] irq-gic: add capability to set bypass flag in GIC

Rob Herring robherring2 at gmail.com
Mon Nov 25 10:43:48 EST 2013


On Sat, Nov 23, 2013 at 2:41 AM, Anup Patel <anup at brainfault.org> wrote:
> On Wed, Nov 20, 2013 at 4:28 PM, Marc Zyngier <marc.zyngier at arm.com> wrote:
>> [dropping <patches at apm.com> from the CC list, as someone seems to have
>>  tripped on the config file, and I'm tired of getting bounces]
>>
>> Feng,
>>
>> On 19/11/13 21:42, Feng Kan wrote:
>>> The GIC-400 implementation allows for FIQ and IRQ bypass. In the
>>> X-Gene implementation, the FIQ bypass must be enabled at all time.
>>> Otherwise, some PPI will appear as FIQ and cause kernel problem.
>>
>> How comes? Are only PPIs affected? When you say "some PPIs", can you be
>> more specific?
>>
>>> Signed-off-by: Feng Kan <fkan at apm.com>
>>> ---
>>>  drivers/irqchip/irq-gic.c       |   15 +++++++++++----
>>>  include/linux/irqchip/arm-gic.h |    4 ++--
>>>  2 files changed, 13 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>>> index d0e9480..aa7342e 100644
>>> --- a/drivers/irqchip/irq-gic.c
>>> +++ b/drivers/irqchip/irq-gic.c
>>> @@ -65,6 +65,7 @@ struct gic_chip_data {
>>>  #endif
>>>       struct irq_domain *domain;
>>>       unsigned int gic_irqs;
>>> +     unsigned int bypass_flag;
>>>  #ifdef CONFIG_GIC_NON_BANKED
>>>       void __iomem *(*get_base)(union gic_base *);
>>>  #endif
>>> @@ -450,7 +451,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
>>>               writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
>>>
>>>       writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
>>> -     writel_relaxed(1, base + GIC_CPU_CTRL);
>>> +     writel_relaxed(gic->bypass_flag | 1, base + GIC_CPU_CTRL);
>>>  }
>>>
>>>  void gic_cpu_if_down(void)
>>> @@ -591,7 +592,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
>>>               writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
>>>
>>>       writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
>>> -     writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
>>> +     writel_relaxed(gic_data[gic_nr].bypass_flag | 1, cpu_base + GIC_CPU_CTRL);
>>>  }
>>>
>>>  static int gic_notifier(struct notifier_block *self, unsigned long cmd,      void *v)
>>> @@ -733,7 +734,8 @@ const struct irq_domain_ops gic_irq_domain_ops = {
>>>
>>>  void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>>                          void __iomem *dist_base, void __iomem *cpu_base,
>>> -                        u32 percpu_offset, struct device_node *node)
>>> +                        u32 percpu_offset, u32 bypass_val,
>>> +                        struct device_node *node)
>>>  {
>>>       irq_hw_number_t hwirq_base;
>>>       struct gic_chip_data *gic;
>>> @@ -821,6 +823,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
>>>
>>>       set_handle_irq(gic_handle_irq);
>>>
>>> +     gic->bypass_flag = (bypass_val & 0xf) << 4;
>>
>> Beware, the top 2 bits are reserved on GICv1, and shouldn't be messed with.
>>
>>>       gic_chip.flags |= gic_arch_extn.flags;
>>>       gic_dist_init(gic);
>>>       gic_cpu_init(gic);
>>> @@ -835,6 +838,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>>       void __iomem *cpu_base;
>>>       void __iomem *dist_base;
>>>       u32 percpu_offset;
>>> +     u32 bypass_val;
>>>       int irq;
>>>
>>>       if (WARN_ON(!node))
>>> @@ -849,7 +853,10 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>>       if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
>>>               percpu_offset = 0;
>>>
>>> -     gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
>>> +     if (of_property_read_u32(node, "bypass-flags", &bypass_val))
>>> +             bypass_val = 0;
>>
>> [adding Mark on Cc, so he can comment on the DT parts]
>>
>> Where's the DT documentation update? Also, as this is an
>> implementation-specific quirk, you should consider using a separate
>> compatible string and move the handling of this issue into some X-Gene
>> specific code.
>
> Adding separate compatible string for X-Gene specific GIC will break
> VGIC code for X-Gene because VGIC code looks for DT node compatible
> to "arm,cortex-a15-gic". We don't want to break currently working VGIC
> code for X-Gene.
>
> The Legacy-IRQ bypass disable and Legacy-FIQ bypass disable is a
> feature of GIC-400 and its not X-Gene specific. The only difference in X-Gene
> is that we use PPI31 (Legacy-IRQ) for timer and PPI28 (Legacy-FIQ) for perf
> event. The issue is that IRQBypDisGrp0, FIQBypDisGrp0, IRQBypDisGrp1
> and FIQBypDisGrp1 bits are 0 by default and for X-Gene we need to set
> these bits to 1 so that GIC-400 does not bypass PPI31 (Legacy-IRQ) and
> PPI28 (Legacy-FIQ).
>
> We should have more cleaner and optional device tree binding for GIC
> which can help us set IRQBypDisGrp0, FIQBypDisGrp0, IRQBypDisGrp1
> and FIQBypDisGrp1 bits for X-Gene.

IIRC, all these bits are secure mode only (or only a subset are
banked). Whether an SoC supports secure mode or not, the current
policy for the kernel is to do any secure mode setup in firmware or
bootloader.

Rob



More information about the linux-arm-kernel mailing list