mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'irq-drivers-2025-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq controller updates from Thomas Gleixner:
"Update for interrupt chip drivers:
- Convert the generic interrupt chip to lock guards to remove copy &
pasta boilerplate code and gotos.
- A new driver fot the interrupt controller in the EcoNet EN751221
MIPS SoC.
- Extend the SG2042-MSI driver to support the new SG2044 SoC
- Updates and cleanups for the (ancient) VT8500 driver
- Improve the scalability of the ARM GICV4.1 ITS driver by utilizing
node local copies a VM's interrupt translation table when possible.
This results in a 12% reduction of VM IPI latency in certain
workloads.
- The usual cleanups and improvements all over the place"
* tag 'irq-drivers-2025-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
irqchip/irq-pruss-intc: Simplify chained interrupt handler setup
irqchip/gic-v4.1: Use local 4_1 ITS to generate VSGI
irqchip/econet-en751221: Switch to of_fwnode_handle()
irqchip/irq-vt8500: Switch to irq_domain_create_*()
irqchip/econet-en751221: Switch to irq_domain_create_linear()
irqchip/irq-vt8500: Use fewer global variables and add error handling
irqchip/irq-vt8500: Use a dedicated chained handler function
irqchip/irq-vt8500: Don't require 8 interrupts from a chained controller
irqchip/irq-vt8500: Drop redundant copy of the device node pointer
irqchip/irq-vt8500: Split up ack/mask functions
irqchip/sg2042-msi: Fix wrong type cast in sg2044_msi_irq_ack()
irqchip/sg2042-msi: Add the Sophgo SG2044 MSI interrupt controller
irqchip/sg2042-msi: Introduce configurable chipinfo for SG2042
irqchip/sg2042-msi: Rename functions and data structures to be SG2042 agnostic
dt-bindings: interrupt-controller: Add Sophgo SG2044 MSI controller
genirq/generic-chip: Fix incorrect lock guard conversions
genirq/generic-chip: Remove unused lock wrappers
irqchip: Convert generic irqchip locking to guards
gpio: mvebu: Convert generic irqchip locking to guard()
ARM: orion/gpio:: Convert generic irqchip locking to guard()
...
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/econet,en751221-intc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: EcoNet EN751221 Interrupt Controller
|
||||
|
||||
maintainers:
|
||||
- Caleb James DeLisle <cjd@cjdns.fr>
|
||||
|
||||
description:
|
||||
The EcoNet EN751221 Interrupt Controller is a simple interrupt controller
|
||||
designed for the MIPS 34Kc MT SMP processor with 2 VPEs. Each interrupt can
|
||||
be routed to either VPE but not both, so to support per-CPU interrupts, a
|
||||
secondary IRQ number is allocated to control masking/unmasking on VPE#1. For
|
||||
lack of a better term we call these "shadow interrupts". The assignment of
|
||||
shadow interrupts is defined by the SoC integrator when wiring the interrupt
|
||||
lines, so they are configurable in the device tree.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: econet,en751221-intc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: Interrupt line connecting this controller to its parent.
|
||||
|
||||
econet,shadow-interrupts:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
description:
|
||||
An array of interrupt number pairs where each pair represents a shadow
|
||||
interrupt relationship. The first number in each pair is the primary IRQ,
|
||||
and the second is its shadow IRQ used for VPE#1 control. For example,
|
||||
<8 3> means IRQ 8 is shadowed by IRQ 3, so IRQ 3 cannot be mapped, but
|
||||
when VPE#1 requests IRQ 8, it will manipulate the IRQ 3 mask bit.
|
||||
minItems: 1
|
||||
maxItems: 20
|
||||
items:
|
||||
items:
|
||||
- description: primary per-CPU IRQ
|
||||
- description: shadow IRQ number
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
interrupt-controller@1fb40000 {
|
||||
compatible = "econet,en751221-intc";
|
||||
reg = <0x1fb40000 0x100>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <2>;
|
||||
|
||||
econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>;
|
||||
};
|
||||
...
|
||||
@@ -18,7 +18,9 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sophgo,sg2042-msi
|
||||
enum:
|
||||
- sophgo,sg2042-msi
|
||||
- sophgo,sg2044-msi
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
||||
@@ -496,11 +496,10 @@ static void orion_gpio_unmask_irq(struct irq_data *d)
|
||||
u32 reg_val;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
reg_val = irq_reg_readl(gc, ct->regs.mask);
|
||||
reg_val |= mask;
|
||||
irq_reg_writel(gc, reg_val, ct->regs.mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void orion_gpio_mask_irq(struct irq_data *d)
|
||||
@@ -510,11 +509,10 @@ static void orion_gpio_mask_irq(struct irq_data *d)
|
||||
u32 mask = d->mask;
|
||||
u32 reg_val;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
reg_val = irq_reg_readl(gc, ct->regs.mask);
|
||||
reg_val &= ~mask;
|
||||
irq_reg_writel(gc, reg_val, ct->regs.mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
void __init orion_gpio_init(int gpio_base, int ngpio,
|
||||
|
||||
@@ -408,9 +408,8 @@ static void mvebu_gpio_irq_ack(struct irq_data *d)
|
||||
struct mvebu_gpio_chip *mvchip = gc->private;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
mvebu_gpio_write_edge_cause(mvchip, ~mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
|
||||
@@ -420,10 +419,9 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
ct->mask_cache_priv &= ~mask;
|
||||
mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
|
||||
@@ -433,11 +431,10 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
mvebu_gpio_write_edge_cause(mvchip, ~mask);
|
||||
ct->mask_cache_priv |= mask;
|
||||
mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_level_irq_mask(struct irq_data *d)
|
||||
@@ -447,10 +444,9 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d)
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
ct->mask_cache_priv &= ~mask;
|
||||
mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
|
||||
@@ -460,10 +456,9 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
ct->mask_cache_priv |= mask;
|
||||
mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
@@ -166,6 +166,11 @@ config DW_APB_ICTL
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
config ECONET_EN751221_INTC
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
|
||||
config FARADAY_FTINTC010
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
|
||||
@@ -10,6 +10,7 @@ obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
|
||||
obj-$(CONFIG_ARCH_ACTIONS) += irq-owl-sirq.o
|
||||
obj-$(CONFIG_DAVINCI_CP_INTC) += irq-davinci-cp-intc.o
|
||||
obj-$(CONFIG_EXYNOS_IRQ_COMBINER) += exynos-combiner.o
|
||||
obj-$(CONFIG_ECONET_EN751221_INTC) += irq-econet-en751221.o
|
||||
obj-$(CONFIG_FARADAY_FTINTC010) += irq-ftintc010.o
|
||||
obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
|
||||
obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o
|
||||
|
||||
@@ -65,15 +65,13 @@ static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
|
||||
struct al_fic *fic = gc->private;
|
||||
enum al_fic_state new_state;
|
||||
int ret = 0;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
|
||||
if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) &&
|
||||
((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) {
|
||||
pr_debug("fic doesn't support flow type %d\n", flow_type);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ?
|
||||
@@ -91,16 +89,10 @@ static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
if (fic->state == AL_FIC_UNCONFIGURED) {
|
||||
al_fic_set_trigger(fic, gc, new_state);
|
||||
} else if (fic->state != new_state) {
|
||||
pr_debug("fic %s state already configured to %d\n",
|
||||
fic->name, fic->state);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
pr_debug("fic %s state already configured to %d\n", fic->name, fic->state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err:
|
||||
irq_gc_unlock(gc);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void al_fic_irq_handler(struct irq_desc *desc)
|
||||
|
||||
@@ -78,9 +78,8 @@ static int aic_retrigger(struct irq_data *d)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
/* Enable interrupt on AIC5 */
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
irq_reg_writel(gc, d->mask, AT91_AIC_ISCR);
|
||||
irq_gc_unlock(gc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -106,30 +105,27 @@ static void aic_suspend(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IDCR);
|
||||
irq_reg_writel(gc, gc->wake_active, AT91_AIC_IECR);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void aic_resume(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
irq_reg_writel(gc, gc->wake_active, AT91_AIC_IDCR);
|
||||
irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IECR);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void aic_pm_shutdown(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR);
|
||||
irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
#else
|
||||
#define aic_suspend NULL
|
||||
@@ -175,10 +171,8 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
|
||||
{
|
||||
struct irq_domain_chip_generic *dgc = d->gc;
|
||||
struct irq_chip_generic *gc;
|
||||
unsigned long flags;
|
||||
unsigned smr;
|
||||
int idx;
|
||||
int ret;
|
||||
int idx, ret;
|
||||
|
||||
if (!dgc)
|
||||
return -EINVAL;
|
||||
@@ -194,11 +188,10 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
|
||||
|
||||
gc = dgc->gc[idx];
|
||||
|
||||
irq_gc_lock_irqsave(gc, flags);
|
||||
guard(raw_spinlock_irq)(&gc->lock);
|
||||
smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
|
||||
aic_common_set_priority(intspec[2], &smr);
|
||||
irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -92,11 +92,10 @@ static void aic5_mask(struct irq_data *d)
|
||||
* Disable interrupt on AIC5. We always take the lock of the
|
||||
* first irq chip as all chips share the same registers.
|
||||
*/
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
|
||||
irq_reg_writel(gc, 1, AT91_AIC5_IDCR);
|
||||
gc->mask_cache &= ~d->mask;
|
||||
irq_gc_unlock(bgc);
|
||||
}
|
||||
|
||||
static void aic5_unmask(struct irq_data *d)
|
||||
@@ -109,11 +108,10 @@ static void aic5_unmask(struct irq_data *d)
|
||||
* Enable interrupt on AIC5. We always take the lock of the
|
||||
* first irq chip as all chips share the same registers.
|
||||
*/
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
|
||||
irq_reg_writel(gc, 1, AT91_AIC5_IECR);
|
||||
gc->mask_cache |= d->mask;
|
||||
irq_gc_unlock(bgc);
|
||||
}
|
||||
|
||||
static int aic5_retrigger(struct irq_data *d)
|
||||
@@ -122,11 +120,9 @@ static int aic5_retrigger(struct irq_data *d)
|
||||
struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0);
|
||||
|
||||
/* Enable interrupt on AIC5 */
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR);
|
||||
irq_reg_writel(bgc, 1, AT91_AIC5_ISCR);
|
||||
irq_gc_unlock(bgc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -137,14 +133,12 @@ static int aic5_set_type(struct irq_data *d, unsigned type)
|
||||
unsigned int smr;
|
||||
int ret;
|
||||
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR);
|
||||
smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
|
||||
ret = aic_common_set_type(d, type, &smr);
|
||||
if (!ret)
|
||||
irq_reg_writel(bgc, smr, AT91_AIC5_SMR);
|
||||
irq_gc_unlock(bgc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -166,7 +160,7 @@ static void aic5_suspend(struct irq_data *d)
|
||||
smr_cache[i] = irq_reg_readl(bgc, AT91_AIC5_SMR);
|
||||
}
|
||||
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
for (i = 0; i < dgc->irqs_per_chip; i++) {
|
||||
mask = 1 << i;
|
||||
if ((mask & gc->mask_cache) == (mask & gc->wake_active))
|
||||
@@ -178,7 +172,6 @@ static void aic5_suspend(struct irq_data *d)
|
||||
else
|
||||
irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
|
||||
}
|
||||
irq_gc_unlock(bgc);
|
||||
}
|
||||
|
||||
static void aic5_resume(struct irq_data *d)
|
||||
@@ -190,7 +183,7 @@ static void aic5_resume(struct irq_data *d)
|
||||
int i;
|
||||
u32 mask;
|
||||
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
|
||||
if (smr_cache) {
|
||||
irq_reg_writel(bgc, 0xffffffff, AT91_AIC5_SPU);
|
||||
@@ -214,7 +207,6 @@ static void aic5_resume(struct irq_data *d)
|
||||
else
|
||||
irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
|
||||
}
|
||||
irq_gc_unlock(bgc);
|
||||
}
|
||||
|
||||
static void aic5_pm_shutdown(struct irq_data *d)
|
||||
@@ -225,13 +217,12 @@ static void aic5_pm_shutdown(struct irq_data *d)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
int i;
|
||||
|
||||
irq_gc_lock(bgc);
|
||||
guard(raw_spinlock)(&bgc->lock);
|
||||
for (i = 0; i < dgc->irqs_per_chip; i++) {
|
||||
irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
|
||||
irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
|
||||
irq_reg_writel(bgc, 1, AT91_AIC5_ICCR);
|
||||
}
|
||||
irq_gc_unlock(bgc);
|
||||
}
|
||||
#else
|
||||
#define aic5_suspend NULL
|
||||
@@ -277,7 +268,6 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
|
||||
unsigned int *out_type)
|
||||
{
|
||||
struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0);
|
||||
unsigned long flags;
|
||||
unsigned smr;
|
||||
int ret;
|
||||
|
||||
@@ -289,13 +279,11 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq_gc_lock_irqsave(bgc, flags);
|
||||
guard(raw_spinlock_irq)(&bgc->lock);
|
||||
irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR);
|
||||
smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
|
||||
aic_common_set_priority(intspec[2], &smr);
|
||||
irq_reg_writel(bgc, smr, AT91_AIC5_SMR);
|
||||
irq_gc_unlock_irqrestore(bgc, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,16 +63,15 @@ static void bcm7120_l2_intc_irq_handle(struct irq_desc *desc)
|
||||
|
||||
for (idx = 0; idx < b->n_words; idx++) {
|
||||
int base = idx * IRQS_PER_WORD;
|
||||
struct irq_chip_generic *gc =
|
||||
irq_get_domain_generic_chip(b->domain, base);
|
||||
struct irq_chip_generic *gc;
|
||||
unsigned long pending;
|
||||
int hwirq;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
pending = irq_reg_readl(gc, b->stat_offset[idx]) &
|
||||
gc->mask_cache &
|
||||
data->irq_map_mask[idx];
|
||||
irq_gc_unlock(gc);
|
||||
gc = irq_get_domain_generic_chip(b->domain, base);
|
||||
scoped_guard (raw_spinlock, &gc->lock) {
|
||||
pending = irq_reg_readl(gc, b->stat_offset[idx]) & gc->mask_cache &
|
||||
data->irq_map_mask[idx];
|
||||
}
|
||||
|
||||
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
|
||||
generic_handle_domain_irq(b->domain, base + hwirq);
|
||||
@@ -86,11 +85,9 @@ static void bcm7120_l2_intc_suspend(struct irq_chip_generic *gc)
|
||||
struct bcm7120_l2_intc_data *b = gc->private;
|
||||
struct irq_chip_type *ct = gc->chip_types;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
if (b->can_wake)
|
||||
irq_reg_writel(gc, gc->mask_cache | gc->wake_active,
|
||||
ct->regs.mask);
|
||||
irq_gc_unlock(gc);
|
||||
irq_reg_writel(gc, gc->mask_cache | gc->wake_active, ct->regs.mask);
|
||||
}
|
||||
|
||||
static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc)
|
||||
@@ -98,9 +95,8 @@ static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc)
|
||||
struct irq_chip_type *ct = gc->chip_types;
|
||||
|
||||
/* Restore the saved mask */
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
irq_reg_writel(gc, gc->mask_cache, ct->regs.mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static int bcm7120_l2_intc_init_one(struct device_node *dn,
|
||||
|
||||
@@ -97,9 +97,8 @@ static void __brcmstb_l2_intc_suspend(struct irq_data *d, bool save)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
struct brcmstb_l2_intc_data *b = gc->private;
|
||||
unsigned long flags;
|
||||
|
||||
irq_gc_lock_irqsave(gc, flags);
|
||||
guard(raw_spinlock_irqsave)(&gc->lock);
|
||||
/* Save the current mask */
|
||||
if (save)
|
||||
b->saved_mask = irq_reg_readl(gc, ct->regs.mask);
|
||||
@@ -109,7 +108,6 @@ static void __brcmstb_l2_intc_suspend(struct irq_data *d, bool save)
|
||||
irq_reg_writel(gc, ~gc->wake_active, ct->regs.disable);
|
||||
irq_reg_writel(gc, gc->wake_active, ct->regs.enable);
|
||||
}
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
}
|
||||
|
||||
static void brcmstb_l2_intc_shutdown(struct irq_data *d)
|
||||
@@ -127,9 +125,8 @@ static void brcmstb_l2_intc_resume(struct irq_data *d)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
struct brcmstb_l2_intc_data *b = gc->private;
|
||||
unsigned long flags;
|
||||
|
||||
irq_gc_lock_irqsave(gc, flags);
|
||||
guard(raw_spinlock_irqsave)(&gc->lock);
|
||||
if (ct->chip.irq_ack) {
|
||||
/* Clear unmasked non-wakeup interrupts */
|
||||
irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active,
|
||||
@@ -139,7 +136,6 @@ static void brcmstb_l2_intc_resume(struct irq_data *d)
|
||||
/* Restore the saved mask */
|
||||
irq_reg_writel(gc, b->saved_mask, ct->regs.disable);
|
||||
irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable);
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
}
|
||||
|
||||
static int __init brcmstb_l2_intc_of_init(struct device_node *np,
|
||||
|
||||
@@ -50,11 +50,10 @@ static void irq_ck_mask_set_bit(struct irq_data *d)
|
||||
unsigned long ifr = ct->regs.mask - 8;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
*ct->mask_cache |= mask;
|
||||
irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
|
||||
irq_reg_writel(gc, irq_reg_readl(gc, ifr) & ~mask, ifr);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void __init ck_set_gc(struct device_node *node, void __iomem *reg_base,
|
||||
|
||||
@@ -101,10 +101,9 @@ static void dw_apb_ictl_resume(struct irq_data *d)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct irq_chip_type *ct = irq_data_get_chip_type(d);
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
writel_relaxed(~0, gc->reg_base + ct->regs.enable);
|
||||
writel_relaxed(*ct->mask_cache, gc->reg_base + ct->regs.mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
#else
|
||||
#define dw_apb_ictl_resume NULL
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* EN751221 Interrupt Controller Driver.
|
||||
*
|
||||
* The EcoNet EN751221 Interrupt Controller is a simple interrupt controller
|
||||
* designed for the MIPS 34Kc MT SMP processor with 2 VPEs. Each interrupt can
|
||||
* be routed to either VPE but not both, so to support per-CPU interrupts, a
|
||||
* secondary IRQ number is allocated to control masking/unmasking on VPE#1. In
|
||||
* this driver, these are called "shadow interrupts". The assignment of shadow
|
||||
* interrupts is defined by the SoC integrator when wiring the interrupt lines,
|
||||
* so they are configurable in the device tree.
|
||||
*
|
||||
* If an interrupt (say 30) needs per-CPU capability, the SoC integrator
|
||||
* allocates another IRQ number (say 29) to be its shadow. The device tree
|
||||
* reflects this by adding the pair <30 29> to the "econet,shadow-interrupts"
|
||||
* property.
|
||||
*
|
||||
* When VPE#1 requests IRQ 30, the driver manipulates the mask bit for IRQ 29,
|
||||
* telling the hardware to mask VPE#1's view of IRQ 30.
|
||||
*
|
||||
* Copyright (C) 2025 Caleb James DeLisle <cjd@cjdns.fr>
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
|
||||
#define IRQ_COUNT 40
|
||||
|
||||
#define NOT_PERCPU 0xff
|
||||
#define IS_SHADOW 0xfe
|
||||
|
||||
#define REG_MASK0 0x04
|
||||
#define REG_MASK1 0x50
|
||||
#define REG_PENDING0 0x08
|
||||
#define REG_PENDING1 0x54
|
||||
|
||||
/**
|
||||
* @membase: Base address of the interrupt controller registers
|
||||
* @interrupt_shadows: Array of all interrupts, for each value,
|
||||
* - NOT_PERCPU: This interrupt is not per-cpu, so it has no shadow
|
||||
* - IS_SHADOW: This interrupt is a shadow of another per-cpu interrupt
|
||||
* - else: This is a per-cpu interrupt whose shadow is the value
|
||||
*/
|
||||
static struct {
|
||||
void __iomem *membase;
|
||||
u8 interrupt_shadows[IRQ_COUNT];
|
||||
} econet_intc __ro_after_init;
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(irq_lock);
|
||||
|
||||
/* IRQs must be disabled */
|
||||
static void econet_wreg(u32 reg, u32 val, u32 mask)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
guard(raw_spinlock)(&irq_lock);
|
||||
|
||||
v = ioread32(econet_intc.membase + reg);
|
||||
v &= ~mask;
|
||||
v |= val & mask;
|
||||
iowrite32(v, econet_intc.membase + reg);
|
||||
}
|
||||
|
||||
/* IRQs must be disabled */
|
||||
static void econet_chmask(u32 hwirq, bool unmask)
|
||||
{
|
||||
u32 reg, mask;
|
||||
u8 shadow;
|
||||
|
||||
/*
|
||||
* If the IRQ is a shadow, it should never be manipulated directly.
|
||||
* It should only be masked/unmasked as a result of the "real" per-cpu
|
||||
* irq being manipulated by a thread running on VPE#1.
|
||||
* If it is per-cpu (has a shadow), and we're on VPE#1, the shadow is what we mask.
|
||||
* This is single processor only, so smp_processor_id() never exceeds 1.
|
||||
*/
|
||||
shadow = econet_intc.interrupt_shadows[hwirq];
|
||||
if (WARN_ON_ONCE(shadow == IS_SHADOW))
|
||||
return;
|
||||
else if (shadow != NOT_PERCPU && smp_processor_id() == 1)
|
||||
hwirq = shadow;
|
||||
|
||||
if (hwirq >= 32) {
|
||||
reg = REG_MASK1;
|
||||
mask = BIT(hwirq - 32);
|
||||
} else {
|
||||
reg = REG_MASK0;
|
||||
mask = BIT(hwirq);
|
||||
}
|
||||
|
||||
econet_wreg(reg, unmask ? mask : 0, mask);
|
||||
}
|
||||
|
||||
/* IRQs must be disabled */
|
||||
static void econet_intc_mask(struct irq_data *d)
|
||||
{
|
||||
econet_chmask(d->hwirq, false);
|
||||
}
|
||||
|
||||
/* IRQs must be disabled */
|
||||
static void econet_intc_unmask(struct irq_data *d)
|
||||
{
|
||||
econet_chmask(d->hwirq, true);
|
||||
}
|
||||
|
||||
static void econet_mask_all(void)
|
||||
{
|
||||
/* IRQs are generally disabled during init, but guarding here makes it non-obligatory. */
|
||||
guard(irqsave)();
|
||||
econet_wreg(REG_MASK0, 0, ~0);
|
||||
econet_wreg(REG_MASK1, 0, ~0);
|
||||
}
|
||||
|
||||
static void econet_intc_handle_pending(struct irq_domain *d, u32 pending, u32 offset)
|
||||
{
|
||||
int hwirq;
|
||||
|
||||
while (pending) {
|
||||
hwirq = fls(pending) - 1;
|
||||
generic_handle_domain_irq(d, hwirq + offset);
|
||||
pending &= ~BIT(hwirq);
|
||||
}
|
||||
}
|
||||
|
||||
static void econet_intc_from_parent(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct irq_domain *domain;
|
||||
u32 pending0, pending1;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
pending0 = ioread32(econet_intc.membase + REG_PENDING0);
|
||||
pending1 = ioread32(econet_intc.membase + REG_PENDING1);
|
||||
|
||||
if (unlikely(!(pending0 | pending1))) {
|
||||
spurious_interrupt();
|
||||
} else {
|
||||
domain = irq_desc_get_handler_data(desc);
|
||||
econet_intc_handle_pending(domain, pending0, 0);
|
||||
econet_intc_handle_pending(domain, pending1, 32);
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static const struct irq_chip econet_irq_chip;
|
||||
|
||||
static int econet_intc_map(struct irq_domain *d, u32 irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (hwirq >= IRQ_COUNT) {
|
||||
pr_err("%s: hwirq %lu out of range\n", __func__, hwirq);
|
||||
return -EINVAL;
|
||||
} else if (econet_intc.interrupt_shadows[hwirq] == IS_SHADOW) {
|
||||
pr_err("%s: can't map hwirq %lu, it is a shadow interrupt\n", __func__, hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (econet_intc.interrupt_shadows[hwirq] == NOT_PERCPU) {
|
||||
irq_set_chip_and_handler(irq, &econet_irq_chip, handle_level_irq);
|
||||
} else {
|
||||
irq_set_chip_and_handler(irq, &econet_irq_chip, handle_percpu_devid_irq);
|
||||
ret = irq_set_percpu_devid(irq);
|
||||
if (ret)
|
||||
pr_warn("%s: Failed irq_set_percpu_devid for %u: %d\n", d->name, irq, ret);
|
||||
}
|
||||
|
||||
irq_set_chip_data(irq, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_chip econet_irq_chip = {
|
||||
.name = "en751221-intc",
|
||||
.irq_unmask = econet_intc_unmask,
|
||||
.irq_mask = econet_intc_mask,
|
||||
.irq_mask_ack = econet_intc_mask,
|
||||
};
|
||||
|
||||
static const struct irq_domain_ops econet_domain_ops = {
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
.map = econet_intc_map
|
||||
};
|
||||
|
||||
static int __init get_shadow_interrupts(struct device_node *node)
|
||||
{
|
||||
const char *field = "econet,shadow-interrupts";
|
||||
int num_shadows;
|
||||
|
||||
num_shadows = of_property_count_u32_elems(node, field);
|
||||
|
||||
memset(econet_intc.interrupt_shadows, NOT_PERCPU,
|
||||
sizeof(econet_intc.interrupt_shadows));
|
||||
|
||||
if (num_shadows <= 0) {
|
||||
return 0;
|
||||
} else if (num_shadows % 2) {
|
||||
pr_err("%pOF: %s count is odd, ignoring\n", node, field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 *shadows __free(kfree) = kmalloc_array(num_shadows, sizeof(u32), GFP_KERNEL);
|
||||
if (!shadows)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32_array(node, field, shadows, num_shadows)) {
|
||||
pr_err("%pOF: Failed to read %s\n", node, field);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_shadows; i += 2) {
|
||||
u32 shadow = shadows[i + 1];
|
||||
u32 target = shadows[i];
|
||||
|
||||
if (shadow > IRQ_COUNT) {
|
||||
pr_err("%pOF: %s[%d] shadow(%d) out of range\n",
|
||||
node, field, i + 1, shadow);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target >= IRQ_COUNT) {
|
||||
pr_err("%pOF: %s[%d] target(%d) out of range\n", node, field, i, target);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (econet_intc.interrupt_shadows[target] != NOT_PERCPU) {
|
||||
pr_err("%pOF: %s[%d] target(%d) already has a shadow\n",
|
||||
node, field, i, target);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (econet_intc.interrupt_shadows[shadow] != NOT_PERCPU) {
|
||||
pr_err("%pOF: %s[%d] shadow(%d) already has a target\n",
|
||||
node, field, i + 1, shadow);
|
||||
continue;
|
||||
}
|
||||
|
||||
econet_intc.interrupt_shadows[target] = shadow;
|
||||
econet_intc.interrupt_shadows[shadow] = IS_SHADOW;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init econet_intc_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
struct resource res;
|
||||
int ret, irq;
|
||||
|
||||
ret = get_shadow_interrupts(node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
if (!irq) {
|
||||
pr_err("%pOF: DT: Failed to get IRQ from 'interrupts'\n", node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(node, 0, &res)) {
|
||||
pr_err("%pOF: DT: Failed to get 'reg'\n", node);
|
||||
ret = -EINVAL;
|
||||
goto err_dispose_mapping;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res.start, resource_size(&res), res.name)) {
|
||||
pr_err("%pOF: Failed to request memory\n", node);
|
||||
ret = -EBUSY;
|
||||
goto err_dispose_mapping;
|
||||
}
|
||||
|
||||
econet_intc.membase = ioremap(res.start, resource_size(&res));
|
||||
if (!econet_intc.membase) {
|
||||
pr_err("%pOF: Failed to remap membase\n", node);
|
||||
ret = -ENOMEM;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
econet_mask_all();
|
||||
|
||||
domain = irq_domain_create_linear(of_fwnode_handle(node), IRQ_COUNT,
|
||||
&econet_domain_ops, NULL);
|
||||
if (!domain) {
|
||||
pr_err("%pOF: Failed to add irqdomain\n", node);
|
||||
ret = -ENOMEM;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(irq, econet_intc_from_parent, domain);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iounmap(econet_intc.membase);
|
||||
err_release:
|
||||
release_mem_region(res.start, resource_size(&res));
|
||||
err_dispose_mapping:
|
||||
irq_dispose_mapping(irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(econet_en751221_intc, "econet,en751221-intc", econet_intc_of_init);
|
||||
@@ -125,6 +125,8 @@ struct its_node {
|
||||
int vlpi_redist_offset;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct its_node *, local_4_1_its);
|
||||
|
||||
#define is_v4(its) (!!((its)->typer & GITS_TYPER_VLPIS))
|
||||
#define is_v4_1(its) (!!((its)->typer & GITS_TYPER_VMAPP))
|
||||
#define device_ids(its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)
|
||||
@@ -2778,6 +2780,7 @@ static u64 inherit_vpe_l1_table_from_its(void)
|
||||
}
|
||||
val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, GITS_BASER_NR_PAGES(baser) - 1);
|
||||
|
||||
*this_cpu_ptr(&local_4_1_its) = its;
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -2815,6 +2818,7 @@ static u64 inherit_vpe_l1_table_from_rd(cpumask_t **mask)
|
||||
gic_data_rdist()->vpe_l1_base = gic_data_rdist_cpu(cpu)->vpe_l1_base;
|
||||
*mask = gic_data_rdist_cpu(cpu)->vpe_table_mask;
|
||||
|
||||
*this_cpu_ptr(&local_4_1_its) = *per_cpu_ptr(&local_4_1_its, cpu);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -4180,7 +4184,7 @@ static struct irq_chip its_vpe_irq_chip = {
|
||||
|
||||
static struct its_node *find_4_1_its(void)
|
||||
{
|
||||
static struct its_node *its = NULL;
|
||||
struct its_node *its = *this_cpu_ptr(&local_4_1_its);
|
||||
|
||||
if (!its) {
|
||||
list_for_each_entry(its, &its_nodes, entry) {
|
||||
|
||||
@@ -52,11 +52,10 @@ static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d)
|
||||
struct regmap *map = gc->private;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
regmap_write(map, ct->regs.ack, mask);
|
||||
regmap_write(map, ct->regs.enable, mask);
|
||||
*ct->mask_cache |= mask;
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
|
||||
@@ -66,10 +65,9 @@ static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
|
||||
struct regmap *map = gc->private;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
regmap_write(map, ct->regs.disable, mask);
|
||||
*ct->mask_cache &= ~mask;
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
|
||||
@@ -79,10 +77,9 @@ static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
|
||||
struct regmap *map = gc->private;
|
||||
u32 mask = d->mask;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
regmap_write(map, ct->regs.ack, mask);
|
||||
regmap_write(map, ct->regs.disable, mask);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static int __init ingenic_tcu_irq_init(struct device_node *np,
|
||||
|
||||
@@ -71,14 +71,12 @@ static unsigned int lan966x_oic_irq_startup(struct irq_data *data)
|
||||
struct lan966x_oic_chip_regs *chip_regs = gc->private;
|
||||
u32 map;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
|
||||
/* Map the source interrupt to the destination */
|
||||
map = irq_reg_readl(gc, chip_regs->reg_off_map);
|
||||
map |= data->mask;
|
||||
irq_reg_writel(gc, map, chip_regs->reg_off_map);
|
||||
|
||||
irq_gc_unlock(gc);
|
||||
scoped_guard (raw_spinlock, &gc->lock) {
|
||||
/* Map the source interrupt to the destination */
|
||||
map = irq_reg_readl(gc, chip_regs->reg_off_map);
|
||||
map |= data->mask;
|
||||
irq_reg_writel(gc, map, chip_regs->reg_off_map);
|
||||
}
|
||||
|
||||
ct->chip.irq_ack(data);
|
||||
ct->chip.irq_unmask(data);
|
||||
@@ -95,14 +93,12 @@ static void lan966x_oic_irq_shutdown(struct irq_data *data)
|
||||
|
||||
ct->chip.irq_mask(data);
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
|
||||
/* Unmap the interrupt */
|
||||
map = irq_reg_readl(gc, chip_regs->reg_off_map);
|
||||
map &= ~data->mask;
|
||||
irq_reg_writel(gc, map, chip_regs->reg_off_map);
|
||||
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static int lan966x_oic_irq_set_type(struct irq_data *data,
|
||||
|
||||
@@ -116,9 +116,8 @@ static int liointc_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
|
||||
u32 mask = data->mask;
|
||||
unsigned long flags;
|
||||
|
||||
irq_gc_lock_irqsave(gc, flags);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
switch (type) {
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
|
||||
@@ -137,10 +136,8 @@ static int liointc_set_type(struct irq_data *data, unsigned int type)
|
||||
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
|
||||
break;
|
||||
default:
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
|
||||
irqd_set_trigger_type(data, type);
|
||||
return 0;
|
||||
@@ -157,10 +154,9 @@ static void liointc_suspend(struct irq_chip_generic *gc)
|
||||
static void liointc_resume(struct irq_chip_generic *gc)
|
||||
{
|
||||
struct liointc_priv *priv = gc->private;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
irq_gc_lock_irqsave(gc, flags);
|
||||
guard(raw_spinlock_irqsave)(&gc->lock);
|
||||
/* Disable all at first */
|
||||
writel(0xffffffff, gc->reg_base + LIOINTC_REG_INTC_DISABLE);
|
||||
/* Restore map cache */
|
||||
@@ -170,7 +166,6 @@ static void liointc_resume(struct irq_chip_generic *gc)
|
||||
writel(priv->int_edge, gc->reg_base + LIOINTC_REG_INTC_EDGE);
|
||||
/* Restore mask cache */
|
||||
writel(gc->mask_cache, gc->reg_base + LIOINTC_REG_INTC_ENABLE);
|
||||
irq_gc_unlock_irqrestore(gc, flags);
|
||||
}
|
||||
|
||||
static int parent_irq[LIOINTC_NUM_PARENT];
|
||||
|
||||
@@ -83,7 +83,7 @@ static void ocelot_irq_unmask(struct irq_data *data)
|
||||
unsigned int mask = data->mask;
|
||||
u32 val;
|
||||
|
||||
irq_gc_lock(gc);
|
||||
guard(raw_spinlock)(&gc->lock);
|
||||
/*
|
||||
* Clear sticky bits for edge mode interrupts.
|
||||
* Serval has only one trigger register replication, but the adjacent
|
||||
@@ -97,7 +97,6 @@ static void ocelot_irq_unmask(struct irq_data *data)
|
||||
|
||||
*ct->mask_cache &= ~mask;
|
||||
irq_reg_writel(gc, mask, p->reg_off_ena_set);
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
|
||||
static void ocelot_irq_handler(struct irq_desc *desc)
|
||||
|
||||
@@ -581,8 +581,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
|
||||
host_data->intc = intc;
|
||||
host_data->host_irq = i;
|
||||
|
||||
irq_set_handler_data(irq, host_data);
|
||||
irq_set_chained_handler(irq, pruss_intc_irq_handler);
|
||||
irq_set_chained_handler_and_data(irq, pruss_intc_irq_handler, host_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user