arm/arm64: GICv2 driver does not have irq_disable implemented

Duc Dang dhdang at apm.com
Fri Oct 9 16:35:03 PDT 2015


On Fri, Oct 9, 2015 at 3:21 PM, Duc Dang <dhdang at apm.com> wrote:
> On Fri, Oct 9, 2015 at 2:52 PM, Thomas Gleixner <tglx at linutronix.de> wrote:
>> On Fri, 9 Oct 2015, Duc Dang wrote:
>>> On Fri, Oct 9, 2015 at 10:52 AM, Thomas Gleixner <tglx at linutronix.de> wrote:
>>> > On Fri, 9 Oct 2015, Duc Dang wrote:
>>> >> In APM ARM64 X-Gene Enet controller driver, we use disable_irq_nosync to
>>> >> disable interrupt before calling __napi_schedule to schedule packet handler
>>> >> to process the Tx/Rx packets.
>>> >
>>> > Which is wrong to begin with. Disable the interrupt at the device
>>> > level not at the interrupt line level.
>>> >
>>> We could not disable the interrupt at Enet controller level due to the
>>> controller limitation. As you said, using  disable_irq_nosync is wrong
>>> but it looks like that the only option that we have.
>>
>> Oh well.
>>
>>> Do you have any suggestion about different approach that we could try?
>>
>> Try the patch below and add
>>
>>     irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
>>
>> to your driver before requesting the interrupt. Unset it when freeing
>> the interrupt.
>
> Thanks, Thomas!
>
> We will try and let you know soon.

Hi  Thomas,

We use irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY) in our X-Gene
Ethernet driver along with your patch and interrupt count works as
expected.

Are you going to commit your patch soon?

We will post the patch for our X-Gene Ethernet driver after your patch
is available.

Thanks,
>
>>
>> Thanks,
>>
>>         tglx
>>
>> 8<--------------
>>
>> Subject: genirq: Add flag to force mask in disable_irq[_nosync]()
>> From: Thomas Gleixner <tglx at linutronix.de>
>> Date: Fri, 09 Oct 2015 23:28:58 +0200
>>
>> If an irq chip does not implement the irq_disable callback, then we
>> use a lazy approach for disabling the interrupt. That means that the
>> interrupt is marked disabled, but the interrupt line is not
>> immediately masked in the interrupt chip. It only becomes masked if
>> the interrupt is raised while it's marked disabled. We use this to avoid
>> possibly expensive mask/unmask operations for common case operations.
>>
>> Unfortunately there are devices which do not allow the interrupt to be
>> disabled easily at the device level. They are forced to use
>> disable_irq_nosync(). This can result in taking each interrupt twice.
>>
>> Instead of enforcing the non lazy mode on all interrupts of a irq
>> chip, provide a settings flag, which can be set by the driver for that
>> particular interrupt line.
>>
>> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
>> ---
>>  include/linux/irq.h   |    4 +++-
>>  kernel/irq/chip.c     |    9 +++++++++
>>  kernel/irq/settings.h |    7 +++++++
>>  3 files changed, 19 insertions(+), 1 deletion(-)
>>
>> Index: tip/include/linux/irq.h
>> ===================================================================
>> --- tip.orig/include/linux/irq.h
>> +++ tip/include/linux/irq.h
>> @@ -72,6 +72,7 @@ enum irqchip_irq_state;
>>   * IRQ_IS_POLLED               - Always polled by another interrupt. Exclude
>>   *                               it from the spurious interrupt detection
>>   *                               mechanism and from core side polling.
>> + * IRQ_DISABLE_UNLAZY          - Disable lazy irq disable
>>   */
>>  enum {
>>         IRQ_TYPE_NONE           = 0x00000000,
>> @@ -97,13 +98,14 @@ enum {
>>         IRQ_NOTHREAD            = (1 << 16),
>>         IRQ_PER_CPU_DEVID       = (1 << 17),
>>         IRQ_IS_POLLED           = (1 << 18),
>> +       IRQ_DISABLE_UNLAZY      = (1 << 19),
>>  };
>>
>>  #define IRQF_MODIFY_MASK       \
>>         (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
>>          IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
>>          IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
>> -        IRQ_IS_POLLED)
>> +        IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY)
>>
>>  #define IRQ_NO_BALANCING_MASK  (IRQ_PER_CPU | IRQ_NO_BALANCING)
>>
>> Index: tip/kernel/irq/chip.c
>> ===================================================================
>> --- tip.orig/kernel/irq/chip.c
>> +++ tip/kernel/irq/chip.c
>> @@ -241,6 +241,13 @@ void irq_enable(struct irq_desc *desc)
>>   * disabled. If an interrupt happens, then the interrupt flow
>>   * handler masks the line at the hardware level and marks it
>>   * pending.
>> + *
>> + * If the interrupt chip does not implement the irq_disable callback,
>> + * a driver can disable the lazy approach for a particular irq line by
>> + * calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can be
>> + * used for devices which cannot disable the interrupt at the device
>> + * level under certain circumstances and have to use
>> + * disable_irq[_nosync] instead.
>>   */
>>  void irq_disable(struct irq_desc *desc)
>>  {
>> @@ -248,6 +255,8 @@ void irq_disable(struct irq_desc *desc)
>>         if (desc->irq_data.chip->irq_disable) {
>>                 desc->irq_data.chip->irq_disable(&desc->irq_data);
>>                 irq_state_set_masked(desc);
>> +       } else if (irq_settings_disable_unlazy(desc)) {
>> +               mask_irq(desc);
>>         }
>>  }
>>
>> Index: tip/kernel/irq/settings.h
>> ===================================================================
>> --- tip.orig/kernel/irq/settings.h
>> +++ tip/kernel/irq/settings.h
>> @@ -15,6 +15,7 @@ enum {
>>         _IRQ_NESTED_THREAD      = IRQ_NESTED_THREAD,
>>         _IRQ_PER_CPU_DEVID      = IRQ_PER_CPU_DEVID,
>>         _IRQ_IS_POLLED          = IRQ_IS_POLLED,
>> +       _IRQ_DISABLE_UNLAZY     = IRQ_DISABLE_UNLAZY,
>>         _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
>>  };
>>
>> @@ -28,6 +29,7 @@ enum {
>>  #define IRQ_NESTED_THREAD      GOT_YOU_MORON
>>  #define IRQ_PER_CPU_DEVID      GOT_YOU_MORON
>>  #define IRQ_IS_POLLED          GOT_YOU_MORON
>> +#define IRQ_DISABLE_UNLAZY     GOT_YOU_MORON
>>  #undef IRQF_MODIFY_MASK
>>  #define IRQF_MODIFY_MASK       GOT_YOU_MORON
>>
>> @@ -154,3 +156,8 @@ static inline bool irq_settings_is_polle
>>  {
>>         return desc->status_use_accessors & _IRQ_IS_POLLED;
>>  }
>> +
>> +static inline bool irq_settings_disable_unlazy(struct irq_desc *desc)
>> +{
>> +       return desc->status_use_accessors & _IRQ_DISABLE_UNLAZY;
>> +}
>
> Regards,
> Duc Dang.

Duc Dang.



More information about the linux-arm-kernel mailing list