Message ID | 1417623503-30261-2-git-send-email-marc.zyngier@arm.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
On Wed, Dec 3, 2014 at 8:18 AM, Marc Zyngier <marc.zyngier@arm.com> wrote: > There is a number of cases where a kernel subsystem may want to > introspect the state of an interrupt at the irqchip level: > > - When a peripheral is shared between virtual machines, > its interrupt state becomes part of the guest's state, > and must be switched accordingly. KVM on arm/arm64 requires > this for its guest-visible timer > - Some GPIO controllers seem to require peeking into the > interrupt controller they are connected to to report > their internal state > > This seem to be a pattern that is common enough for the core code > to try and support this without too many horrible hacks. Introduce > a pair of accessors (irq_get_irqchip_state/irq_set_irqchip_state) > to retrieve the bits that can be of interest to another subsystem: > pending, active, and masked. > > - irq_get_irqchip_state returns the state of the interrupt according > to a parameter set to IRQCHIP_STATE_PENDING, IRQCHIP_STATE_ACTIVE, > IRQCHIP_STATE_MASKED or IRQCHIP_STATE_LINE_LEVEL. > - irq_set_irqchip_state similarly sets the state of the interrupt. > > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> With the addition of actually assigning err to something useful in the setter below: Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> Tested-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c [..] > +/** > + * irq_set_irqchip_state - set the state of a forwarded interrupt. > + * @irq: Interrupt line that is forwarded to a VM > + * @which: State to be restored (one of IRQCHIP_STATE_*) > + * @val: Value corresponding to @which > + * > + * This call sets the internal irqchip state of an interrupt, > + * depending on the value of @which. > + * > + * This function should be called with preemption disabled if the > + * interrupt controller has per-cpu registers. > + */ > +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, > + bool val) > +{ > + struct irq_desc *desc; > + struct irq_data *data; > + struct irq_chip *chip; > + unsigned long flags; > + int err = -EINVAL; > + > + desc = irq_get_desc_buslock(irq, &flags, 0); > + if (!desc) > + return err; > + > + data = irq_desc_get_irq_data(desc); > + > + do { > + chip = irq_data_get_irq_chip(data); > + if (chip->irq_set_irqchip_state) > + break; > +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY > + data = data->parent_data; > +#else > + data = NULL; > +#endif > + } while (data); > + > + if (data) > + chip->irq_set_irqchip_state(data, which, val); err = > + > + irq_put_desc_busunlock(desc, flags); > + return err; > +} Regards, Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/12/14 22:42, Bjorn Andersson wrote: > On Wed, Dec 3, 2014 at 8:18 AM, Marc Zyngier <marc.zyngier@arm.com> wrote: >> There is a number of cases where a kernel subsystem may want to >> introspect the state of an interrupt at the irqchip level: >> >> - When a peripheral is shared between virtual machines, >> its interrupt state becomes part of the guest's state, >> and must be switched accordingly. KVM on arm/arm64 requires >> this for its guest-visible timer >> - Some GPIO controllers seem to require peeking into the >> interrupt controller they are connected to to report >> their internal state >> >> This seem to be a pattern that is common enough for the core code >> to try and support this without too many horrible hacks. Introduce >> a pair of accessors (irq_get_irqchip_state/irq_set_irqchip_state) >> to retrieve the bits that can be of interest to another subsystem: >> pending, active, and masked. >> >> - irq_get_irqchip_state returns the state of the interrupt according >> to a parameter set to IRQCHIP_STATE_PENDING, IRQCHIP_STATE_ACTIVE, >> IRQCHIP_STATE_MASKED or IRQCHIP_STATE_LINE_LEVEL. >> - irq_set_irqchip_state similarly sets the state of the interrupt. >> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> > > With the addition of actually assigning err to something useful in the > setter below: > > Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > Tested-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > >> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > > [..] > >> +/** >> + * irq_set_irqchip_state - set the state of a forwarded interrupt. >> + * @irq: Interrupt line that is forwarded to a VM >> + * @which: State to be restored (one of IRQCHIP_STATE_*) >> + * @val: Value corresponding to @which >> + * >> + * This call sets the internal irqchip state of an interrupt, >> + * depending on the value of @which. >> + * >> + * This function should be called with preemption disabled if the >> + * interrupt controller has per-cpu registers. >> + */ >> +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, >> + bool val) >> +{ >> + struct irq_desc *desc; >> + struct irq_data *data; >> + struct irq_chip *chip; >> + unsigned long flags; >> + int err = -EINVAL; >> + >> + desc = irq_get_desc_buslock(irq, &flags, 0); >> + if (!desc) >> + return err; >> + >> + data = irq_desc_get_irq_data(desc); >> + >> + do { >> + chip = irq_data_get_irq_chip(data); >> + if (chip->irq_set_irqchip_state) >> + break; >> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY >> + data = data->parent_data; >> +#else >> + data = NULL; >> +#endif >> + } while (data); >> + >> + if (data) >> + chip->irq_set_irqchip_state(data, which, val); > > err = Ah, that will teach me to write test code that actually checks the return value! :-) Thanks for the fix and the tags. M.
Marc, On Tue, Dec 09, 2014 at 09:37:26AM +0000, Marc Zyngier wrote: > On 08/12/14 22:42, Bjorn Andersson wrote: > > On Wed, Dec 3, 2014 at 8:18 AM, Marc Zyngier <marc.zyngier@arm.com> wrote: > >> There is a number of cases where a kernel subsystem may want to > >> introspect the state of an interrupt at the irqchip level: > >> > >> - When a peripheral is shared between virtual machines, > >> its interrupt state becomes part of the guest's state, > >> and must be switched accordingly. KVM on arm/arm64 requires > >> this for its guest-visible timer > >> - Some GPIO controllers seem to require peeking into the > >> interrupt controller they are connected to to report > >> their internal state > >> > >> This seem to be a pattern that is common enough for the core code > >> to try and support this without too many horrible hacks. Introduce > >> a pair of accessors (irq_get_irqchip_state/irq_set_irqchip_state) > >> to retrieve the bits that can be of interest to another subsystem: > >> pending, active, and masked. > >> > >> - irq_get_irqchip_state returns the state of the interrupt according > >> to a parameter set to IRQCHIP_STATE_PENDING, IRQCHIP_STATE_ACTIVE, > >> IRQCHIP_STATE_MASKED or IRQCHIP_STATE_LINE_LEVEL. > >> - irq_set_irqchip_state similarly sets the state of the interrupt. > >> > >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> > > > > With the addition of actually assigning err to something useful in the > > setter below: > > > > Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > > Tested-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > > > >> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > > > > [..] > > > >> +/** > >> + * irq_set_irqchip_state - set the state of a forwarded interrupt. > >> + * @irq: Interrupt line that is forwarded to a VM > >> + * @which: State to be restored (one of IRQCHIP_STATE_*) > >> + * @val: Value corresponding to @which > >> + * > >> + * This call sets the internal irqchip state of an interrupt, > >> + * depending on the value of @which. > >> + * > >> + * This function should be called with preemption disabled if the > >> + * interrupt controller has per-cpu registers. > >> + */ > >> +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, > >> + bool val) > >> +{ > >> + struct irq_desc *desc; > >> + struct irq_data *data; > >> + struct irq_chip *chip; > >> + unsigned long flags; > >> + int err = -EINVAL; > >> + > >> + desc = irq_get_desc_buslock(irq, &flags, 0); > >> + if (!desc) > >> + return err; > >> + > >> + data = irq_desc_get_irq_data(desc); > >> + > >> + do { > >> + chip = irq_data_get_irq_chip(data); > >> + if (chip->irq_set_irqchip_state) > >> + break; > >> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY > >> + data = data->parent_data; > >> +#else > >> + data = NULL; > >> +#endif > >> + } while (data); > >> + > >> + if (data) > >> + chip->irq_set_irqchip_state(data, which, val); > > > > err = > > Ah, that will teach me to write test code that actually checks the > return value! :-) > > Thanks for the fix and the tags. Did I miss the new version of this? thx, Jason. -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 07/01/15 16:05, Jason Cooper wrote: > Marc, > > On Tue, Dec 09, 2014 at 09:37:26AM +0000, Marc Zyngier wrote: >> On 08/12/14 22:42, Bjorn Andersson wrote: >>> On Wed, Dec 3, 2014 at 8:18 AM, Marc Zyngier <marc.zyngier@arm.com> wrote: >>>> There is a number of cases where a kernel subsystem may want to >>>> introspect the state of an interrupt at the irqchip level: >>>> >>>> - When a peripheral is shared between virtual machines, >>>> its interrupt state becomes part of the guest's state, >>>> and must be switched accordingly. KVM on arm/arm64 requires >>>> this for its guest-visible timer >>>> - Some GPIO controllers seem to require peeking into the >>>> interrupt controller they are connected to to report >>>> their internal state >>>> >>>> This seem to be a pattern that is common enough for the core code >>>> to try and support this without too many horrible hacks. Introduce >>>> a pair of accessors (irq_get_irqchip_state/irq_set_irqchip_state) >>>> to retrieve the bits that can be of interest to another subsystem: >>>> pending, active, and masked. >>>> >>>> - irq_get_irqchip_state returns the state of the interrupt according >>>> to a parameter set to IRQCHIP_STATE_PENDING, IRQCHIP_STATE_ACTIVE, >>>> IRQCHIP_STATE_MASKED or IRQCHIP_STATE_LINE_LEVEL. >>>> - irq_set_irqchip_state similarly sets the state of the interrupt. >>>> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> >>> >>> With the addition of actually assigning err to something useful in the >>> setter below: >>> >>> Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> >>> Tested-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> >>> >>>> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c >>> >>> [..] >>> >>>> +/** >>>> + * irq_set_irqchip_state - set the state of a forwarded interrupt. >>>> + * @irq: Interrupt line that is forwarded to a VM >>>> + * @which: State to be restored (one of IRQCHIP_STATE_*) >>>> + * @val: Value corresponding to @which >>>> + * >>>> + * This call sets the internal irqchip state of an interrupt, >>>> + * depending on the value of @which. >>>> + * >>>> + * This function should be called with preemption disabled if the >>>> + * interrupt controller has per-cpu registers. >>>> + */ >>>> +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, >>>> + bool val) >>>> +{ >>>> + struct irq_desc *desc; >>>> + struct irq_data *data; >>>> + struct irq_chip *chip; >>>> + unsigned long flags; >>>> + int err = -EINVAL; >>>> + >>>> + desc = irq_get_desc_buslock(irq, &flags, 0); >>>> + if (!desc) >>>> + return err; >>>> + >>>> + data = irq_desc_get_irq_data(desc); >>>> + >>>> + do { >>>> + chip = irq_data_get_irq_chip(data); >>>> + if (chip->irq_set_irqchip_state) >>>> + break; >>>> +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY >>>> + data = data->parent_data; >>>> +#else >>>> + data = NULL; >>>> +#endif >>>> + } while (data); >>>> + >>>> + if (data) >>>> + chip->irq_set_irqchip_state(data, which, val); >>> >>> err = >> >> Ah, that will teach me to write test code that actually checks the >> return value! :-) >> >> Thanks for the fix and the tags. > > Did I miss the new version of this? I'm rebasing all my stuff at the moment. Expect something later today (or tomorrow morning worse case). Thanks, M.
On Wed, Jan 07, 2015 at 04:09:54PM +0000, Marc Zyngier wrote: > On 07/01/15 16:05, Jason Cooper wrote: ... > > Did I miss the new version of this? > > I'm rebasing all my stuff at the moment. Expect something later today > (or tomorrow morning worse case). Ok, wasn't trying to rush. I had a few days of mail anomalies, so I was just double checking that it didn't go missing. thx, Jason. -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 69517a2..cbbe6a2 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -356,6 +356,20 @@ static inline int disable_irq_wake(unsigned int irq) return irq_set_irq_wake(irq, 0); } +/* + * irq_get_irqchip_state/irq_set_irqchip_state specific flags + */ +enum irqchip_irq_state { + IRQCHIP_STATE_PENDING, /* Is interrupt pending? */ + IRQCHIP_STATE_ACTIVE, /* Is interrupt in progress? */ + IRQCHIP_STATE_MASKED, /* Is interrupt masked? */ + IRQCHIP_STATE_LINE_LEVEL, /* Is IRQ line high? */ +}; + +extern int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + bool *state); +extern int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + bool state); #ifdef CONFIG_IRQ_FORCED_THREADING extern bool force_irqthreads; diff --git a/include/linux/irq.h b/include/linux/irq.h index 8badf34..1922539 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -29,6 +29,7 @@ struct seq_file; struct module; struct msi_msg; +enum irqchip_irq_state; /* * IRQ line status. @@ -323,6 +324,8 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) * irq_request_resources * @irq_compose_msi_msg: optional to compose message content for MSI * @irq_write_msi_msg: optional to write message content for MSI + * @irq_get_irqchip_state: return the internal state of an interrupt + * @irq_set_irqchip_state: set the internal state of a interrupt * @flags: chip specific flags */ struct irq_chip { @@ -362,6 +365,9 @@ struct irq_chip { void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg); void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg); + int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); + int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); + unsigned long flags; }; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8069237..06840ba 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1758,3 +1758,94 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler, return retval; } + +/** + * irq_get_irqchip_state - returns the irqchip state of a interrupt. + * @irq: Interrupt line that is forwarded to a VM + * @which: One of IRQCHIP_STATE_* the caller wants to know about + * @state: a pointer to a boolean where the state is to be storeed + * + * This call snapshots the internal irqchip state of an + * interrupt, returning into @state the bit corresponding to + * stage @which + * + * This function should be called with preemption disabled if the + * interrupt controller has per-cpu registers. + */ +int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + bool *state) +{ + struct irq_desc *desc; + struct irq_data *data; + struct irq_chip *chip; + unsigned long flags; + int err = -EINVAL; + + desc = irq_get_desc_buslock(irq, &flags, 0); + if (!desc) + return err; + + data = irq_desc_get_irq_data(desc); + + do { + chip = irq_data_get_irq_chip(data); + if (chip->irq_get_irqchip_state) + break; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + data = data->parent_data; +#else + data = NULL; +#endif + } while (data); + + if (data) + err = chip->irq_get_irqchip_state(data, which, state); + + irq_put_desc_busunlock(desc, flags); + return err; +} + +/** + * irq_set_irqchip_state - set the state of a forwarded interrupt. + * @irq: Interrupt line that is forwarded to a VM + * @which: State to be restored (one of IRQCHIP_STATE_*) + * @val: Value corresponding to @which + * + * This call sets the internal irqchip state of an interrupt, + * depending on the value of @which. + * + * This function should be called with preemption disabled if the + * interrupt controller has per-cpu registers. + */ +int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + bool val) +{ + struct irq_desc *desc; + struct irq_data *data; + struct irq_chip *chip; + unsigned long flags; + int err = -EINVAL; + + desc = irq_get_desc_buslock(irq, &flags, 0); + if (!desc) + return err; + + data = irq_desc_get_irq_data(desc); + + do { + chip = irq_data_get_irq_chip(data); + if (chip->irq_set_irqchip_state) + break; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + data = data->parent_data; +#else + data = NULL; +#endif + } while (data); + + if (data) + chip->irq_set_irqchip_state(data, which, val); + + irq_put_desc_busunlock(desc, flags); + return err; +}
There is a number of cases where a kernel subsystem may want to introspect the state of an interrupt at the irqchip level: - When a peripheral is shared between virtual machines, its interrupt state becomes part of the guest's state, and must be switched accordingly. KVM on arm/arm64 requires this for its guest-visible timer - Some GPIO controllers seem to require peeking into the interrupt controller they are connected to to report their internal state This seem to be a pattern that is common enough for the core code to try and support this without too many horrible hacks. Introduce a pair of accessors (irq_get_irqchip_state/irq_set_irqchip_state) to retrieve the bits that can be of interest to another subsystem: pending, active, and masked. - irq_get_irqchip_state returns the state of the interrupt according to a parameter set to IRQCHIP_STATE_PENDING, IRQCHIP_STATE_ACTIVE, IRQCHIP_STATE_MASKED or IRQCHIP_STATE_LINE_LEVEL. - irq_set_irqchip_state similarly sets the state of the interrupt. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- include/linux/interrupt.h | 14 ++++++++ include/linux/irq.h | 6 ++++ kernel/irq/manage.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+)