Merge tag 'irq-core-2022-03-21' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull interrupt updates from Thomas Gleixner:
"Core code:
- Provide generic_handle_irq_safe() which can be invoked from any
context (hard interrupt or threaded). This allows to remove ugly
workarounds in drivers all over the place.
- Use generic_handle_irq_safe() in the affected drivers.
- The usual cleanups and improvements.
Interrupt chip drivers:
- Support for new interrupt chips or not yet supported variants:
STM32MP14, Meson GPIO, Apple M1 PMU, Apple M1 AICv2, Qualcomm MPM
- Convert the Xilinx driver to generic interrupt domains
- Cleanup the irq_chip::name handling
- The usual cleanups and improvements all over the place"
* tag 'irq-core-2022-03-21' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (52 commits)
irqchip: Add Qualcomm MPM controller driver
dt-bindings: interrupt-controller: Add Qualcomm MPM support
irqchip/apple-aic: Add support for AICv2
irqchip/apple-aic: Support multiple dies
irqchip/apple-aic: Dynamically compute register offsets
irqchip/apple-aic: Switch to irq_domain_create_tree and sparse hwirqs
irqchip/apple-aic: Add Fast IPI support
dt-bindings: interrupt-controller: apple,aic2: New binding for AICv2
PCI: apple: Change MSI handling to handle 4-cell AIC fwspec form
irqchip/apple-aic: Fix cpumask allocation for FIQs
irqchip/meson-gpio: Add support for meson s4 SoCs
irqchip/meson-gpio: add select trigger type callback
irqchip/meson-gpio: support more than 8 channels gpio irq
dt-bindings: interrupt-controller: New binding for Meson-S4 SoCs
irqchip/xilinx: Switch to GENERIC_IRQ_MULTI_HANDLER
staging: greybus: gpio: Use generic_handle_irq_safe().
net: usb: lan78xx: Use generic_handle_irq_safe().
mfd: ezx-pcap: Use generic_handle_irq_safe().
misc: hi6421-spmi-pmic: Use generic_handle_irq_safe().
irqchip/sifive-plic: Disable S-mode IRQs if running in M-mode
...
This commit is contained in:
@@ -38,7 +38,7 @@ struct irqaction chained_action = {
|
||||
* @irq: irq number
|
||||
* @chip: pointer to irq chip description structure
|
||||
*/
|
||||
int irq_set_chip(unsigned int irq, struct irq_chip *chip)
|
||||
int irq_set_chip(unsigned int irq, const struct irq_chip *chip)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
|
||||
@@ -46,10 +46,7 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip)
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (!chip)
|
||||
chip = &no_irq_chip;
|
||||
|
||||
desc->irq_data.chip = chip;
|
||||
desc->irq_data.chip = (struct irq_chip *)(chip ?: &no_irq_chip);
|
||||
irq_put_desc_unlock(desc, flags);
|
||||
/*
|
||||
* For !CONFIG_SPARSE_IRQ make the irq show up in
|
||||
@@ -1073,7 +1070,7 @@ irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle,
|
||||
EXPORT_SYMBOL_GPL(irq_set_chained_handler_and_data);
|
||||
|
||||
void
|
||||
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
|
||||
irq_set_chip_and_handler_name(unsigned int irq, const struct irq_chip *chip,
|
||||
irq_flow_handler_t handle, const char *name)
|
||||
{
|
||||
irq_set_chip(irq, chip);
|
||||
@@ -1558,6 +1555,14 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device *irq_get_parent_device(struct irq_data *data)
|
||||
{
|
||||
if (data->domain)
|
||||
return data->domain->dev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_chip_pm_get - Enable power for an IRQ chip
|
||||
* @data: Pointer to interrupt specific data
|
||||
@@ -1567,12 +1572,13 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
*/
|
||||
int irq_chip_pm_get(struct irq_data *data)
|
||||
{
|
||||
struct device *dev = irq_get_parent_device(data);
|
||||
int retval;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) {
|
||||
retval = pm_runtime_get_sync(data->chip->parent_device);
|
||||
if (IS_ENABLED(CONFIG_PM) && dev) {
|
||||
retval = pm_runtime_get_sync(dev);
|
||||
if (retval < 0) {
|
||||
pm_runtime_put_noidle(data->chip->parent_device);
|
||||
pm_runtime_put_noidle(dev);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@@ -1590,10 +1596,11 @@ int irq_chip_pm_get(struct irq_data *data)
|
||||
*/
|
||||
int irq_chip_pm_put(struct irq_data *data)
|
||||
{
|
||||
struct device *dev = irq_get_parent_device(data);
|
||||
int retval = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device)
|
||||
retval = pm_runtime_put(data->chip->parent_device);
|
||||
if (IS_ENABLED(CONFIG_PM) && dev)
|
||||
retval = pm_runtime_put(dev);
|
||||
|
||||
return (retval < 0) ? retval : 0;
|
||||
}
|
||||
|
||||
@@ -69,8 +69,12 @@ irq_debug_show_chip(struct seq_file *m, struct irq_data *data, int ind)
|
||||
seq_printf(m, "chip: None\n");
|
||||
return;
|
||||
}
|
||||
seq_printf(m, "%*schip: %s\n", ind, "", chip->name);
|
||||
seq_printf(m, "%*sflags: 0x%lx\n", ind + 1, "", chip->flags);
|
||||
seq_printf(m, "%*schip: ", ind, "");
|
||||
if (chip->irq_print_chip)
|
||||
chip->irq_print_chip(data, m);
|
||||
else
|
||||
seq_printf(m, "%s", chip->name);
|
||||
seq_printf(m, "\n%*sflags: 0x%lx\n", ind + 1, "", chip->flags);
|
||||
irq_debug_show_bits(m, ind, chip->flags, irqchip_flags,
|
||||
ARRAY_SIZE(irqchip_flags));
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ int handle_irq_desc(struct irq_desc *desc)
|
||||
return -EINVAL;
|
||||
|
||||
data = irq_desc_get_irq_data(desc);
|
||||
if (WARN_ON_ONCE(!in_irq() && handle_enforce_irqctx(data)))
|
||||
if (WARN_ON_ONCE(!in_hardirq() && handle_enforce_irqctx(data)))
|
||||
return -EPERM;
|
||||
|
||||
generic_handle_irq_desc(desc);
|
||||
@@ -662,6 +662,29 @@ int generic_handle_irq(unsigned int irq)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_handle_irq);
|
||||
|
||||
/**
|
||||
* generic_handle_irq_safe - Invoke the handler for a particular irq from any
|
||||
* context.
|
||||
* @irq: The irq number to handle
|
||||
*
|
||||
* Returns: 0 on success, a negative value on error.
|
||||
*
|
||||
* This function can be called from any context (IRQ or process context). It
|
||||
* will report an error if not invoked from IRQ context and the irq has been
|
||||
* marked to enforce IRQ-context only.
|
||||
*/
|
||||
int generic_handle_irq_safe(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
local_irq_save(flags);
|
||||
ret = handle_irq_desc(irq_to_desc(irq));
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_handle_irq_safe);
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN
|
||||
/**
|
||||
* generic_handle_domain_irq - Invoke the handler for a HW irq belonging
|
||||
@@ -676,7 +699,7 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
|
||||
*/
|
||||
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
|
||||
{
|
||||
WARN_ON_ONCE(!in_irq());
|
||||
WARN_ON_ONCE(!in_hardirq());
|
||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
|
||||
|
||||
@@ -1319,7 +1319,8 @@ EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
|
||||
* @chip_data: The associated chip data
|
||||
*/
|
||||
int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq, struct irq_chip *chip,
|
||||
irq_hw_number_t hwirq,
|
||||
const struct irq_chip *chip,
|
||||
void *chip_data)
|
||||
{
|
||||
struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
|
||||
@@ -1328,7 +1329,7 @@ int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
|
||||
return -ENOENT;
|
||||
|
||||
irq_data->hwirq = hwirq;
|
||||
irq_data->chip = chip ? chip : &no_irq_chip;
|
||||
irq_data->chip = (struct irq_chip *)(chip ? chip : &no_irq_chip);
|
||||
irq_data->chip_data = chip_data;
|
||||
|
||||
return 0;
|
||||
@@ -1347,7 +1348,7 @@ EXPORT_SYMBOL_GPL(irq_domain_set_hwirq_and_chip);
|
||||
* @handler_name: The interrupt handler name
|
||||
*/
|
||||
void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq, struct irq_chip *chip,
|
||||
irq_hw_number_t hwirq, const struct irq_chip *chip,
|
||||
void *chip_data, irq_flow_handler_t handler,
|
||||
void *handler_data, const char *handler_name)
|
||||
{
|
||||
@@ -1853,7 +1854,7 @@ EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
|
||||
* @handler_name: The interrupt handler name
|
||||
*/
|
||||
void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq, struct irq_chip *chip,
|
||||
irq_hw_number_t hwirq, const struct irq_chip *chip,
|
||||
void *chip_data, irq_flow_handler_t handler,
|
||||
void *handler_data, const char *handler_name)
|
||||
{
|
||||
|
||||
@@ -222,7 +222,7 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
|
||||
u32 pending;
|
||||
int curcnt;
|
||||
|
||||
WARN_ON_ONCE(in_irq());
|
||||
WARN_ON_ONCE(in_hardirq());
|
||||
lockdep_assert_irqs_enabled();
|
||||
|
||||
local_irq_save(flags);
|
||||
@@ -305,7 +305,7 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON_ONCE(in_irq());
|
||||
WARN_ON_ONCE(in_hardirq());
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
/*
|
||||
@@ -352,14 +352,14 @@ static void __local_bh_enable(unsigned int cnt)
|
||||
*/
|
||||
void _local_bh_enable(void)
|
||||
{
|
||||
WARN_ON_ONCE(in_irq());
|
||||
WARN_ON_ONCE(in_hardirq());
|
||||
__local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
|
||||
}
|
||||
EXPORT_SYMBOL(_local_bh_enable);
|
||||
|
||||
void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
|
||||
{
|
||||
WARN_ON_ONCE(in_irq());
|
||||
WARN_ON_ONCE(in_hardirq());
|
||||
lockdep_assert_irqs_enabled();
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
local_irq_disable();
|
||||
@@ -618,7 +618,7 @@ static inline void tick_irq_exit(void)
|
||||
|
||||
/* Make sure that timer wheel updates are propagated */
|
||||
if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) {
|
||||
if (!in_irq())
|
||||
if (!in_hardirq())
|
||||
tick_nohz_irq_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user