diff --git a/include/linux/irq.h b/include/linux/irq.h index a36d35c25996..7c80b10cec59 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -751,6 +751,9 @@ void irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, void *data); +void __irq_modify_status(unsigned int irq, unsigned long clr, + unsigned long set, unsigned long mask); + void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set); static inline void irq_set_status_flags(unsigned int irq, unsigned long set) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 9e385bd90552..37fbb3076174 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1122,7 +1122,8 @@ irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, } EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name); -void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) +void __irq_modify_status(unsigned int irq, unsigned long clr, + unsigned long set, unsigned long mask) { unsigned long flags, trigger, tmp; struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); @@ -1136,7 +1137,9 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) */ WARN_ON_ONCE(!desc->depth && (set & _IRQ_NOAUTOEN)); - irq_settings_clr_and_set(desc, clr, set); + /* Warn when trying to clear or set a bit disallowed by the mask */ + WARN_ON((clr | set) & ~mask); + __irq_settings_clr_and_set(desc, clr, set, mask); trigger = irqd_get_trigger_type(&desc->irq_data); @@ -1159,6 +1162,11 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) irq_put_desc_unlock(desc, flags); } + +void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) +{ + __irq_modify_status(irq, clr, set, _IRQF_MODIFY_MASK); +} EXPORT_SYMBOL_GPL(irq_modify_status); /** diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index 403378b9947b..51acdf43eadc 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -36,11 +36,17 @@ enum { #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON +static inline void +__irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set, u32 mask) +{ + desc->status_use_accessors &= ~(clr & mask); + desc->status_use_accessors |= (set & mask); +} + static inline void irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set) { - desc->status_use_accessors &= ~(clr & _IRQF_MODIFY_MASK); - desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK); + __irq_settings_clr_and_set(desc, clr, set, _IRQF_MODIFY_MASK); } static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)