Commit 9cc5b7fb authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-5.4' of...

Merge tag 'irqchip-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

Pull irqchip updates for Linux 5.4 from Marc Zyngier:

 - Large GICv3 updates to support new PPI and SPI ranges
 - Conver all alloc_fwnode() users to use PAs instead of VAs
 - Add support for Marvell's MMP3 irqchip
 - Add support for Amlogic Meson SM1
 - Various cleanups and fixes
parents 101f85b5 c9c96e30
...@@ -115,6 +115,8 @@ stable kernels. ...@@ -115,6 +115,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip0{6,7} | #161010701 | N/A | | Hisilicon | Hip0{6,7} | #161010701 | N/A |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip0{6,7} | #161010803 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 | | Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A | | Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A |
......
...@@ -16,6 +16,7 @@ Required properties: ...@@ -16,6 +16,7 @@ Required properties:
"amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912) "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912)
"amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X) "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X)
"amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2) "amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2)
"amlogic,meson-sm1-gpio-intc" for SM1 SoCs (S905D3, S905X3, S905Y3)
- reg : Specifies base physical address and size of the registers. - reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller. - interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Specifies the number of cells needed to encode an - #interrupt-cells : Specifies the number of cells needed to encode an
......
...@@ -44,11 +44,13 @@ properties: ...@@ -44,11 +44,13 @@ properties:
be at least 4. be at least 4.
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
interrupts. Other values are reserved for future use. interrupts, 2 for interrupts in the Extended SPI range, 3 for the
Extended PPI range. Other values are reserved for future use.
The 2nd cell contains the interrupt number for the interrupt type. The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15]. range [0-15]. Extented SPI interrupts are in the range [0-1023].
Extended PPI interrupts are in the range [0-127].
The 3rd cell is the flags, encoded as follows: The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags. bits[3:0] trigger type and level flags.
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) #define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000)
#define ICU_REG(x) (ICU_VIRT_BASE + (x)) #define ICU_REG(x) (ICU_VIRT_BASE + (x))
#define ICU2_VIRT_BASE (AXI_VIRT_BASE + 0x84000)
#define ICU2_REG(x) (ICU2_VIRT_BASE + (x))
#define ICU_INT_CONF(n) ICU_REG((n) << 2) #define ICU_INT_CONF(n) ICU_REG((n) << 2)
#define ICU_INT_CONF_MASK (0xf) #define ICU_INT_CONF_MASK (0xf)
......
...@@ -400,7 +400,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) ...@@ -400,7 +400,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
g->fwnode = of_node_to_fwnode(np); g->fwnode = of_node_to_fwnode(np);
} else { } else {
parent = ixp4xx_get_irq_domain(); parent = ixp4xx_get_irq_domain();
g->fwnode = irq_domain_alloc_fwnode(g->base); g->fwnode = irq_domain_alloc_fwnode(&res->start);
if (!g->fwnode) { if (!g->fwnode) {
dev_err(dev, "no domain base\n"); dev_err(dev, "no domain base\n");
return -ENODEV; return -ENODEV;
......
...@@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, ...@@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data) void *data)
{ {
for (; quirks->desc; quirks++) { for (; quirks->desc; quirks++) {
if (quirks->compatible)
continue;
if (quirks->iidr != (quirks->mask & iidr)) if (quirks->iidr != (quirks->mask & iidr))
continue; continue;
if (quirks->init(data)) if (quirks->init(data))
...@@ -63,7 +65,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -63,7 +65,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* for "irq", depending on "type". * for "irq", depending on "type".
*/ */
raw_spin_lock_irqsave(&irq_controller_lock, flags); raw_spin_lock_irqsave(&irq_controller_lock, flags);
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); val = oldval = readl_relaxed(base + confoff);
if (type & IRQ_TYPE_LEVEL_MASK) if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask; val &= ~confmask;
else if (type & IRQ_TYPE_EDGE_BOTH) else if (type & IRQ_TYPE_EDGE_BOTH)
...@@ -83,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -83,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* does not allow us to set the configuration or we are in a * does not allow us to set the configuration or we are in a
* non-secure mode, and hence it may not be catastrophic. * non-secure mode, and hence it may not be catastrophic.
*/ */
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); writel_relaxed(val, base + confoff);
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) { if (readl_relaxed(base + confoff) != val)
if (WARN_ON(irq >= 32))
ret = -EINVAL; ret = -EINVAL;
else
pr_warn("GIC: PPI%d is secure or misconfigured\n",
irq - 16);
}
raw_spin_unlock_irqrestore(&irq_controller_lock, flags); raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
if (sync_access) if (sync_access)
...@@ -132,26 +130,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs, ...@@ -132,26 +130,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
sync_access(); sync_access();
} }
void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
{ {
int i; int i;
/* /*
* Deal with the banked PPI and SGI interrupts - disable all * Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled. * private interrupts. Make sure everything is deactivated.
* Make sure everything is deactivated.
*/ */
writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR); for (i = 0; i < nr; i += 32) {
writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); writel_relaxed(GICD_INT_EN_CLR_X32,
writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); base + GIC_DIST_ACTIVE_CLEAR + i / 8);
writel_relaxed(GICD_INT_EN_CLR_X32,
base + GIC_DIST_ENABLE_CLEAR + i / 8);
}
/* /*
* Set priority on PPI and SGI interrupts * Set priority on PPI and SGI interrupts
*/ */
for (i = 0; i < 32; i += 4) for (i = 0; i < nr; i += 4)
writel_relaxed(GICD_INT_DEF_PRI_X4, writel_relaxed(GICD_INT_DEF_PRI_X4,
base + GIC_DIST_PRI + i * 4 / 4); base + GIC_DIST_PRI + i * 4 / 4);
/* Ensure all SGI interrupts are now enabled */
writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
if (sync_access) if (sync_access)
sync_access(); sync_access();
} }
...@@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void)); void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs, void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void)); void (*sync_access)(void));
void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void));
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data); void *data);
void gic_enable_of_quirks(const struct device_node *np, void gic_enable_of_quirks(const struct device_node *np,
......
...@@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, ...@@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
spi_start, nr_spis); spi_start, nr_spis);
} }
fwnode = irq_domain_alloc_fwnode((void *)m->base_address); fwnode = irq_domain_alloc_fwnode(&res.start);
if (!fwnode) { if (!fwnode) {
pr_err("Unable to allocate GICv2m domain token\n"); pr_err("Unable to allocate GICv2m domain token\n");
return -EINVAL; return -EINVAL;
......
...@@ -2464,6 +2464,7 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number ...@@ -2464,6 +2464,7 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number
{ {
int idx; int idx;
/* Find a free LPI region in lpi_map and allocate them. */
idx = bitmap_find_free_region(dev->event_map.lpi_map, idx = bitmap_find_free_region(dev->event_map.lpi_map,
dev->event_map.nr_lpis, dev->event_map.nr_lpis,
get_count_order(nvecs)); get_count_order(nvecs));
...@@ -2471,7 +2472,6 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number ...@@ -2471,7 +2472,6 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number
return -ENOSPC; return -ENOSPC;
*hwirq = dev->event_map.lpi_base + idx; *hwirq = dev->event_map.lpi_base + idx;
set_bit(idx, dev->event_map.lpi_map);
return 0; return 0;
} }
...@@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, ...@@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct its_node *its = its_dev->its; struct its_node *its = its_dev->its;
int i; int i;
bitmap_release_region(its_dev->event_map.lpi_map,
its_get_event_id(irq_domain_get_irq_data(domain, virq)),
get_count_order(nr_irqs));
for (i = 0; i < nr_irqs; i++) { for (i = 0; i < nr_irqs; i++) {
struct irq_data *data = irq_domain_get_irq_data(domain, struct irq_data *data = irq_domain_get_irq_data(domain,
virq + i); virq + i);
u32 event = its_get_event_id(data);
/* Mark interrupt index as unused */
clear_bit(event, its_dev->event_map.lpi_map);
/* Nuke the entry in the domain */ /* Nuke the entry in the domain */
irq_domain_reset_irq_data(data); irq_domain_reset_irq_data(data);
} }
...@@ -3921,7 +3920,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, ...@@ -3921,7 +3920,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1; res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
res.flags = IORESOURCE_MEM; res.flags = IORESOURCE_MEM;
dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address); dom_handle = irq_domain_alloc_fwnode(&res.start);
if (!dom_handle) { if (!dom_handle) {
pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n", pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
&res.start); &res.start);
......
...@@ -51,13 +51,17 @@ struct gic_chip_data { ...@@ -51,13 +51,17 @@ struct gic_chip_data {
u32 nr_redist_regions; u32 nr_redist_regions;
u64 flags; u64 flags;
bool has_rss; bool has_rss;
unsigned int irq_nr; unsigned int ppi_nr;
struct partition_desc *ppi_descs[16]; struct partition_desc **ppi_descs;
}; };
static struct gic_chip_data gic_data __read_mostly; static struct gic_chip_data gic_data __read_mostly;
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer))
#define GIC_LINE_NR max(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
#define GIC_ESPI_NR GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
/* /*
* The behaviours of RPR and PMR registers differ depending on the value of * The behaviours of RPR and PMR registers differ depending on the value of
* SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
...@@ -84,7 +88,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); ...@@ -84,7 +88,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */ /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
static refcount_t ppi_nmi_refs[16]; static refcount_t *ppi_nmi_refs;
static struct gic_kvm_info gic_v3_kvm_info; static struct gic_kvm_info gic_v3_kvm_info;
static DEFINE_PER_CPU(bool, has_rss); static DEFINE_PER_CPU(bool, has_rss);
...@@ -97,6 +101,38 @@ static DEFINE_PER_CPU(bool, has_rss); ...@@ -97,6 +101,38 @@ static DEFINE_PER_CPU(bool, has_rss);
/* Our default, arbitrary priority value. Linux only uses one anyway. */ /* Our default, arbitrary priority value. Linux only uses one anyway. */
#define DEFAULT_PMR_VALUE 0xf0 #define DEFAULT_PMR_VALUE 0xf0
enum gic_intid_range {
PPI_RANGE,
SPI_RANGE,
EPPI_RANGE,
ESPI_RANGE,
LPI_RANGE,
__INVALID_RANGE__
};
static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
{
switch (hwirq) {
case 16 ... 31:
return PPI_RANGE;
case 32 ... 1019:
return SPI_RANGE;
case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
return EPPI_RANGE;
case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
return ESPI_RANGE;
case 8192 ... GENMASK(23, 0):
return LPI_RANGE;
default:
return __INVALID_RANGE__;
}
}
static enum gic_intid_range get_intid_range(struct irq_data *d)
{
return __get_intid_range(d->hwirq);
}
static inline unsigned int gic_irq(struct irq_data *d) static inline unsigned int gic_irq(struct irq_data *d)
{ {
return d->hwirq; return d->hwirq;
...@@ -104,18 +140,26 @@ static inline unsigned int gic_irq(struct irq_data *d) ...@@ -104,18 +140,26 @@ static inline unsigned int gic_irq(struct irq_data *d)
static inline int gic_irq_in_rdist(struct irq_data *d) static inline int gic_irq_in_rdist(struct irq_data *d)
{ {
return gic_irq(d) < 32; enum gic_intid_range range = get_intid_range(d);
return range == PPI_RANGE || range == EPPI_RANGE;
} }
static inline void __iomem *gic_dist_base(struct irq_data *d) static inline void __iomem *gic_dist_base(struct irq_data *d)
{ {
if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */ switch (get_intid_range(d)) {
case PPI_RANGE:
case EPPI_RANGE:
/* SGI+PPI -> SGI_base for this CPU */
return gic_data_rdist_sgi_base(); return gic_data_rdist_sgi_base();
if (d->hwirq <= 1023) /* SPI -> dist_base */ case SPI_RANGE:
case ESPI_RANGE:
/* SPI -> dist_base */
return gic_data.dist_base; return gic_data.dist_base;
default:
return NULL; return NULL;
}
} }
static void gic_do_wait_for_rwp(void __iomem *base) static void gic_do_wait_for_rwp(void __iomem *base)
...@@ -196,24 +240,79 @@ static void gic_enable_redist(bool enable) ...@@ -196,24 +240,79 @@ static void gic_enable_redist(bool enable)
/* /*
* Routines to disable, enable, EOI and route interrupts * Routines to disable, enable, EOI and route interrupts
*/ */
static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
{
switch (get_intid_range(d)) {
case PPI_RANGE:
case SPI_RANGE:
*index = d->hwirq;
return offset;
case EPPI_RANGE:
/*
* Contrary to the ESPI range, the EPPI range is contiguous
* to the PPI range in the registers, so let's adjust the
* displacement accordingly. Consistency is overrated.
*/
*index = d->hwirq - EPPI_BASE_INTID + 32;
return offset;
case ESPI_RANGE:
*index = d->hwirq - ESPI_BASE_INTID;
switch (offset) {
case GICD_ISENABLER:
return GICD_ISENABLERnE;
case GICD_ICENABLER:
return GICD_ICENABLERnE;
case GICD_ISPENDR:
return GICD_ISPENDRnE;
case GICD_ICPENDR:
return GICD_ICPENDRnE;
case GICD_ISACTIVER:
return GICD_ISACTIVERnE;
case GICD_ICACTIVER:
return GICD_ICACTIVERnE;
case GICD_IPRIORITYR:
return GICD_IPRIORITYRnE;
case GICD_ICFGR:
return GICD_ICFGRnE;
case GICD_IROUTER:
return GICD_IROUTERnE;
default:
break;
}
break;
default:
break;
}
WARN_ON(1);
*index = d->hwirq;
return offset;
}
static int gic_peek_irq(struct irq_data *d, u32 offset) static int gic_peek_irq(struct irq_data *d, u32 offset)
{ {
u32 mask = 1 << (gic_irq(d) % 32);
void __iomem *base; void __iomem *base;
u32 index, mask;
offset = convert_offset_index(d, offset, &index);
mask = 1 << (index % 32);
if (gic_irq_in_rdist(d)) if (gic_irq_in_rdist(d))
base = gic_data_rdist_sgi_base(); base = gic_data_rdist_sgi_base();
else else
base = gic_data.dist_base; base = gic_data.dist_base;
return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask);
} }
static void gic_poke_irq(struct irq_data *d, u32 offset) static void gic_poke_irq(struct irq_data *d, u32 offset)
{ {
u32 mask = 1 << (gic_irq(d) % 32);
void (*rwp_wait)(void); void (*rwp_wait)(void);
void __iomem *base; void __iomem *base;
u32 index, mask;
offset = convert_offset_index(d, offset, &index);
mask = 1 << (index % 32);
if (gic_irq_in_rdist(d)) { if (gic_irq_in_rdist(d)) {
base = gic_data_rdist_sgi_base(); base = gic_data_rdist_sgi_base();
...@@ -223,7 +322,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset) ...@@ -223,7 +322,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset)
rwp_wait = gic_dist_wait_for_rwp; rwp_wait = gic_dist_wait_for_rwp;
} }
writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4); writel_relaxed(mask, base + offset + (index / 32) * 4);
rwp_wait(); rwp_wait();
} }
...@@ -263,7 +362,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, ...@@ -263,7 +362,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
{ {
u32 reg; u32 reg;
if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ if (d->hwirq >= 8192) /* PPI/SPI only */
return -EINVAL; return -EINVAL;
switch (which) { switch (which) {
...@@ -290,7 +389,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, ...@@ -290,7 +389,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
static int gic_irq_get_irqchip_state(struct irq_data *d, static int gic_irq_get_irqchip_state(struct irq_data *d,
enum irqchip_irq_state which, bool *val) enum irqchip_irq_state which, bool *val)
{ {
if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ if (d->hwirq >= 8192) /* PPI/SPI only */
return -EINVAL; return -EINVAL;
switch (which) { switch (which) {
...@@ -316,8 +415,23 @@ static int gic_irq_get_irqchip_state(struct irq_data *d, ...@@ -316,8 +415,23 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
static void gic_irq_set_prio(struct irq_data *d, u8 prio) static void gic_irq_set_prio(struct irq_data *d, u8 prio)
{ {
void __iomem *base = gic_dist_base(d); void __iomem *base = gic_dist_base(d);
u32 offset, index;
offset = convert_offset_index(d, GICD_IPRIORITYR, &index);
writeb_relaxed(prio, base + GICD_IPRIORITYR + gic_irq(d)); writeb_relaxed(prio, base + offset + index);
}
static u32 gic_get_ppi_index(struct irq_data *d)
{
switch (get_intid_range(d)) {
case PPI_RANGE:
return d->hwirq - 16;
case EPPI_RANGE:
return d->hwirq - EPPI_BASE_INTID + 16;
default:
unreachable();
}
} }
static int gic_irq_nmi_setup(struct irq_data *d) static int gic_irq_nmi_setup(struct irq_data *d)
...@@ -340,10 +454,12 @@ static int gic_irq_nmi_setup(struct irq_data *d) ...@@ -340,10 +454,12 @@ static int gic_irq_nmi_setup(struct irq_data *d)
return -EINVAL; return -EINVAL;
/* desc lock should already be held */ /* desc lock should already be held */
if (gic_irq(d) < 32) { if (gic_irq_in_rdist(d)) {
u32 idx = gic_get_ppi_index(d);
/* Setting up PPI as NMI, only switch handler for first NMI */ /* Setting up PPI as NMI, only switch handler for first NMI */
if (!refcount_inc_not_zero(&ppi_nmi_refs[gic_irq(d) - 16])) { if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) {
refcount_set(&ppi_nmi_refs[gic_irq(d) - 16], 1); refcount_set(&ppi_nmi_refs[idx], 1);
desc->handle_irq = handle_percpu_devid_fasteoi_nmi; desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
} }
} else { } else {
...@@ -375,9 +491,11 @@ static void gic_irq_nmi_teardown(struct irq_data *d) ...@@ -375,9 +491,11 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
return; return;
/* desc lock should already be held */ /* desc lock should already be held */
if (gic_irq(d) < 32) { if (gic_irq_in_rdist(d)) {
u32 idx = gic_get_ppi_index(d);
/* Tearing down NMI, only switch handler for last NMI */ /* Tearing down NMI, only switch handler for last NMI */
if (refcount_dec_and_test(&ppi_nmi_refs[gic_irq(d) - 16])) if (refcount_dec_and_test(&ppi_nmi_refs[idx]))
desc->handle_irq = handle_percpu_devid_irq; desc->handle_irq = handle_percpu_devid_irq;
} else { } else {
desc->handle_irq = handle_fasteoi_irq; desc->handle_irq = handle_fasteoi_irq;
...@@ -404,17 +522,22 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d) ...@@ -404,17 +522,22 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d)
static int gic_set_type(struct irq_data *d, unsigned int type) static int gic_set_type(struct irq_data *d, unsigned int type)
{ {
enum gic_intid_range range;
unsigned int irq = gic_irq(d); unsigned int irq = gic_irq(d);
void (*rwp_wait)(void); void (*rwp_wait)(void);
void __iomem *base; void __iomem *base;
u32 offset, index;
int ret;
/* Interrupt configuration for SGIs can't be changed */ /* Interrupt configuration for SGIs can't be changed */
if (irq < 16) if (irq < 16)
return -EINVAL; return -EINVAL;
range = get_intid_range(d);
/* SPIs have restrictions on the supported types */ /* SPIs have restrictions on the supported types */
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && if ((range == SPI_RANGE || range == ESPI_RANGE) &&
type != IRQ_TYPE_EDGE_RISING) type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
return -EINVAL; return -EINVAL;
if (gic_irq_in_rdist(d)) { if (gic_irq_in_rdist(d)) {
...@@ -425,7 +548,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -425,7 +548,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
rwp_wait = gic_dist_wait_for_rwp; rwp_wait = gic_dist_wait_for_rwp;
} }
return gic_configure_irq(irq, type, base, rwp_wait); offset = convert_offset_index(d, GICD_ICFGR, &index);
ret = gic_configure_irq(index, type, base + offset, rwp_wait);
if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq);
ret = 0;
}
return ret;
} }
static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
...@@ -500,7 +632,12 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs ...@@ -500,7 +632,12 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
gic_arch_enable_irqs(); gic_arch_enable_irqs();
} }
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { /* Check for special IDs first */
if ((irqnr >= 1020 && irqnr <= 1023))
return;
/* Treat anything but SGIs in a uniform way */
if (likely(irqnr > 15)) {
int err; int err;
if (static_branch_likely(&supports_deactivate_key)) if (static_branch_likely(&supports_deactivate_key))
...@@ -588,10 +725,26 @@ static void __init gic_dist_init(void) ...@@ -588,10 +725,26 @@ static void __init gic_dist_init(void)
* do the right thing if the kernel is running in secure mode, * do the right thing if the kernel is running in secure mode,
* but that's not the intended use case anyway. * but that's not the intended use case anyway.
*/ */
for (i = 32; i < gic_data.irq_nr; i += 32) for (i = 32; i < GIC_LINE_NR; i += 32)
writel_relaxed(~0, base + GICD_IGROUPR + i / 8); writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp); /* Extended SPI range, not handled by the GICv2/GICv3 common code */
for (i = 0; i < GIC_ESPI_NR; i += 32) {
writel_relaxed(~0U, base + GICD_ICENABLERnE + i / 8);
writel_relaxed(~0U, base + GICD_ICACTIVERnE + i / 8);
}
for (i = 0; i < GIC_ESPI_NR; i += 32)
writel_relaxed(~0U, base + GICD_IGROUPRnE + i / 8);
for (i = 0; i < GIC_ESPI_NR; i += 16)
writel_relaxed(0, base + GICD_ICFGRnE + i / 4);
for (i = 0; i < GIC_ESPI_NR; i += 4)
writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i);
/* Now do the common stuff, and wait for the distributor to drain */
gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp);
/* Enable distributor with ARE, Group1 */ /* Enable distributor with ARE, Group1 */
writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
...@@ -602,8 +755,11 @@ static void __init gic_dist_init(void) ...@@ -602,8 +755,11 @@ static void __init gic_dist_init(void)
* enabled. * enabled.
*/ */
affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
for (i = 32; i < gic_data.irq_nr; i++) for (i = 32; i < GIC_LINE_NR; i++)
gic_write_irouter(affinity, base + GICD_IROUTER + i * 8); gic_write_irouter(affinity, base + GICD_IROUTER + i * 8);
for (i = 0; i < GIC_ESPI_NR; i++)
gic_write_irouter(affinity, base + GICD_IROUTERnE + i * 8);
} }
static int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *)) static int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *))
...@@ -689,19 +845,24 @@ static int gic_populate_rdist(void) ...@@ -689,19 +845,24 @@ static int gic_populate_rdist(void)
return -ENODEV; return -ENODEV;
} }
static int __gic_update_vlpi_properties(struct redist_region *region, static int __gic_update_rdist_properties(struct redist_region *region,
void __iomem *ptr) void __iomem *ptr)
{ {
u64 typer = gic_read_typer(ptr + GICR_TYPER); u64 typer = gic_read_typer(ptr + GICR_TYPER);
gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS);
gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr);
return 1; return 1;
} }
static void gic_update_vlpi_properties(void) static void gic_update_rdist_properties(void)
{ {
gic_iterate_rdists(__gic_update_vlpi_properties); gic_data.ppi_nr = UINT_MAX;
gic_iterate_rdists(__gic_update_rdist_properties);
if (WARN_ON(gic_data.ppi_nr == UINT_MAX))
gic_data.ppi_nr = 0;
pr_info("%d PPIs implemented\n", gic_data.ppi_nr);
pr_info("%sVLPI support, %sdirect LPI support\n", pr_info("%sVLPI support, %sdirect LPI support\n",
!gic_data.rdists.has_vlpis ? "no " : "", !gic_data.rdists.has_vlpis ? "no " : "",
!gic_data.rdists.has_direct_lpi ? "no " : ""); !gic_data.rdists.has_direct_lpi ? "no " : "");
...@@ -845,6 +1006,7 @@ static int gic_dist_supports_lpis(void) ...@@ -845,6 +1006,7 @@ static int gic_dist_supports_lpis(void)
static void gic_cpu_init(void) static void gic_cpu_init(void)
{ {
void __iomem *rbase; void __iomem *rbase;
int i;
/* Register ourselves with the rest of the world */ /* Register ourselves with the rest of the world */
if (gic_populate_rdist()) if (gic_populate_rdist())
...@@ -852,12 +1014,18 @@ static void gic_cpu_init(void) ...@@ -852,12 +1014,18 @@ static void gic_cpu_init(void)
gic_enable_redist(true); gic_enable_redist(true);
WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) &&
!(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange),
"Distributor has extended ranges, but CPU%d doesn't\n",
smp_processor_id());
rbase = gic_data_rdist_sgi_base(); rbase = gic_data_rdist_sgi_base();
/* Configure SGIs/PPIs as non-secure Group-1 */ /* Configure SGIs/PPIs as non-secure Group-1 */
writel_relaxed(~0, rbase + GICR_IGROUPR0); for (i = 0; i < gic_data.ppi_nr + 16; i += 32)
writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
gic_cpu_config(rbase, gic_redist_wait_for_rwp); gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp);
/* initialise system registers */ /* initialise system registers */
gic_cpu_sys_reg_init(); gic_cpu_sys_reg_init();
...@@ -961,6 +1129,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ...@@ -961,6 +1129,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force) bool force)
{ {
unsigned int cpu; unsigned int cpu;
u32 offset, index;
void __iomem *reg; void __iomem *reg;
int enabled; int enabled;
u64 val; u64 val;
...@@ -981,7 +1150,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ...@@ -981,7 +1150,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
if (enabled) if (enabled)
gic_mask_irq(d); gic_mask_irq(d);
reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8); offset = convert_offset_index(d, GICD_IROUTER, &index);
reg = gic_dist_base(d) + offset + (index * 8);
val = gic_mpidr_to_affinity(cpu_logical_map(cpu)); val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
gic_write_irouter(val, reg); gic_write_irouter(val, reg);
...@@ -1065,8 +1235,6 @@ static struct irq_chip gic_eoimode1_chip = { ...@@ -1065,8 +1235,6 @@ static struct irq_chip gic_eoimode1_chip = {
IRQCHIP_MASK_ON_SUSPEND, IRQCHIP_MASK_ON_SUSPEND,
}; };
#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer))
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hw)
{ {
...@@ -1075,36 +1243,32 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, ...@@ -1075,36 +1243,32 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
if (static_branch_likely(&supports_deactivate_key)) if (static_branch_likely(&supports_deactivate_key))
chip = &gic_eoimode1_chip; chip = &gic_eoimode1_chip;
/* SGIs are private to the core kernel */ switch (__get_intid_range(hw)) {
if (hw < 16) case PPI_RANGE:
return -EPERM; case EPPI_RANGE:
/* Nothing here */
if (hw >= gic_data.irq_nr && hw < 8192)
return -EPERM;
/* Off limits */
if (hw >= GIC_ID_NR)
return -EPERM;
/* PPIs */
if (hw < 32) {
irq_set_percpu_devid(irq); irq_set_percpu_devid(irq);
irq_domain_set_info(d, irq, hw, chip, d->host_data, irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL); handle_percpu_devid_irq, NULL, NULL);
irq_set_status_flags(irq, IRQ_NOAUTOEN); irq_set_status_flags(irq, IRQ_NOAUTOEN);
} break;
/* SPIs */
if (hw >= 32 && hw < gic_data.irq_nr) { case SPI_RANGE:
case ESPI_RANGE:
irq_domain_set_info(d, irq, hw, chip, d->host_data, irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL); handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq); irq_set_probe(irq);
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq))); irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
} break;
/* LPIs */
if (hw >= 8192 && hw < GIC_ID_NR) { case LPI_RANGE:
if (!gic_dist_supports_lpis()) if (!gic_dist_supports_lpis())
return -EPERM; return -EPERM;
irq_domain_set_info(d, irq, hw, chip, d->host_data, irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_fasteoi_irq, NULL, NULL); handle_fasteoi_irq, NULL, NULL);
break;
default:
return -EPERM;
} }
return 0; return 0;
...@@ -1126,12 +1290,24 @@ static int gic_irq_domain_translate(struct irq_domain *d, ...@@ -1126,12 +1290,24 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq = fwspec->param[1] + 32; *hwirq = fwspec->param[1] + 32;
break; break;
case 1: /* PPI */ case 1: /* PPI */
case GIC_IRQ_TYPE_PARTITION:
*hwirq = fwspec->param[1] + 16; *hwirq = fwspec->param[1] + 16;
break; break;
case 2: /* ESPI */
*hwirq = fwspec->param[1] + ESPI_BASE_INTID;
break;
case 3: /* EPPI */
*hwirq = fwspec->param[1] + EPPI_BASE_INTID;
break;
case GIC_IRQ_TYPE_LPI: /* LPI */ case GIC_IRQ_TYPE_LPI: /* LPI */
*hwirq = fwspec->param[1]; *hwirq = fwspec->param[1];
break; break;
case GIC_IRQ_TYPE_PARTITION:
*hwirq = fwspec->param[1];
if (fwspec->param[1] >= 16)
*hwirq += EPPI_BASE_INTID - 16;
else
*hwirq += 16;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -1211,7 +1387,8 @@ static int gic_irq_domain_select(struct irq_domain *d, ...@@ -1211,7 +1387,8 @@ static int gic_irq_domain_select(struct irq_domain *d,
* then we need to match the partition domain. * then we need to match the partition domain.
*/ */
if (fwspec->param_count >= 4 && if (fwspec->param_count >= 4 &&
fwspec->param[0] == 1 && fwspec->param[3] != 0) fwspec->param[0] == 1 && fwspec->param[3] != 0 &&
gic_data.ppi_descs)
return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]); return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
return d == gic_data.domain; return d == gic_data.domain;
...@@ -1232,6 +1409,9 @@ static int partition_domain_translate(struct irq_domain *d, ...@@ -1232,6 +1409,9 @@ static int partition_domain_translate(struct irq_domain *d,
struct device_node *np; struct device_node *np;
int ret; int ret;
if (!gic_data.ppi_descs)
return -ENOMEM;
np = of_find_node_by_phandle(fwspec->param[3]); np = of_find_node_by_phandle(fwspec->param[3]);
if (WARN_ON(!np)) if (WARN_ON(!np))
return -EINVAL; return -EINVAL;
...@@ -1261,11 +1441,65 @@ static bool gic_enable_quirk_msm8996(void *data) ...@@ -1261,11 +1441,65 @@ static bool gic_enable_quirk_msm8996(void *data)
return true; return true;
} }
static bool gic_enable_quirk_hip06_07(void *data)
{
struct gic_chip_data *d = data;
/*
* HIP06 GICD_IIDR clashes with GIC-600 product number (despite
* not being an actual ARM implementation). The saving grace is
* that GIC-600 doesn't have ESPI, so nothing to do in that case.
* HIP07 doesn't even have a proper IIDR, and still pretends to
* have ESPI. In both cases, put them right.
*/
if (d->rdists.gicd_typer & GICD_TYPER_ESPI) {
/* Zero both ESPI and the RES0 field next to it... */
d->rdists.gicd_typer &= ~GENMASK(9, 8);
return true;
}
return false;
}
static const struct gic_quirk gic_quirks[] = {
{
.desc = "GICv3: Qualcomm MSM8996 broken firmware",
.compatible = "qcom,msm8996-gic-v3",
.init = gic_enable_quirk_msm8996,
},
{
.desc = "GICv3: HIP06 erratum 161010803",
.iidr = 0x0204043b,
.mask = 0xffffffff,
.init = gic_enable_quirk_hip06_07,
},
{
.desc = "GICv3: HIP07 erratum 161010803",
.iidr = 0x00000000,
.mask = 0xffffffff,
.init = gic_enable_quirk_hip06_07,
},
{
}
};
static void gic_enable_nmi_support(void) static void gic_enable_nmi_support(void)
{ {
int i; int i;
for (i = 0; i < 16; i++) if (!gic_prio_masking_enabled())
return;
if (gic_has_group0() && !gic_dist_security_disabled()) {
pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
return;
}
ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
if (!ppi_nmi_refs)
return;
for (i = 0; i < gic_data.ppi_nr; i++)
refcount_set(&ppi_nmi_refs[i], 0); refcount_set(&ppi_nmi_refs[i], 0);
static_branch_enable(&supports_pseudo_nmis); static_branch_enable(&supports_pseudo_nmis);
...@@ -1283,7 +1517,6 @@ static int __init gic_init_bases(void __iomem *dist_base, ...@@ -1283,7 +1517,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
struct fwnode_handle *handle) struct fwnode_handle *handle)
{ {
u32 typer; u32 typer;
int gic_irqs;
int err; int err;
if (!is_hyp_mode_available()) if (!is_hyp_mode_available())
...@@ -1300,15 +1533,15 @@ static int __init gic_init_bases(void __iomem *dist_base, ...@@ -1300,15 +1533,15 @@ static int __init gic_init_bases(void __iomem *dist_base,
/* /*
* Find out how many interrupts are supported. * Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
*/ */
typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
gic_data.rdists.gicd_typer = typer; gic_data.rdists.gicd_typer = typer;
gic_irqs = GICD_TYPER_IRQS(typer);
if (gic_irqs > 1020)
gic_irqs = 1020;
gic_data.irq_nr = gic_irqs;
gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
gic_quirks, &gic_data);
pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
&gic_data); &gic_data);
irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
...@@ -1333,7 +1566,7 @@ static int __init gic_init_bases(void __iomem *dist_base, ...@@ -1333,7 +1566,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq); set_handle_irq(gic_handle_irq);
gic_update_vlpi_properties(); gic_update_rdist_properties();
gic_smp_init(); gic_smp_init();
gic_dist_init(); gic_dist_init();
...@@ -1348,12 +1581,7 @@ static int __init gic_init_bases(void __iomem *dist_base, ...@@ -1348,12 +1581,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
gicv2m_init(handle, gic_data.domain); gicv2m_init(handle, gic_data.domain);
} }
if (gic_prio_masking_enabled()) {
if (!gic_has_group0() || gic_dist_security_disabled())
gic_enable_nmi_support(); gic_enable_nmi_support();
else
pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
}
return 0; return 0;
...@@ -1386,6 +1614,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) ...@@ -1386,6 +1614,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
if (!parts_node) if (!parts_node)
return; return;
gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
if (!gic_data.ppi_descs)
return;
nr_parts = of_get_child_count(parts_node); nr_parts = of_get_child_count(parts_node);
if (!nr_parts) if (!nr_parts)
...@@ -1437,7 +1669,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) ...@@ -1437,7 +1669,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
part_idx++; part_idx++;
} }
for (i = 0; i < 16; i++) { for (i = 0; i < gic_data.ppi_nr; i++) {
unsigned int irq; unsigned int irq;
struct partition_desc *desc; struct partition_desc *desc;
struct irq_fwspec ppi_fwspec = { struct irq_fwspec ppi_fwspec = {
...@@ -1490,16 +1722,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) ...@@ -1490,16 +1722,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
gic_set_kvm_info(&gic_v3_kvm_info); gic_set_kvm_info(&gic_v3_kvm_info);
} }
static const struct gic_quirk gic_quirks[] = {
{
.desc = "GICv3: Qualcomm MSM8996 broken firmware",
.compatible = "qcom,msm8996-gic-v3",
.init = gic_enable_quirk_msm8996,
},
{
}
};
static int __init gic_of_init(struct device_node *node, struct device_node *parent) static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{ {
void __iomem *dist_base; void __iomem *dist_base;
...@@ -1845,7 +2067,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) ...@@ -1845,7 +2067,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
if (err) if (err)
goto out_redist_unmap; goto out_redist_unmap;
domain_handle = irq_domain_alloc_fwnode(acpi_data.dist_base); domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
if (!domain_handle) { if (!domain_handle) {
err = -ENOMEM; err = -ENOMEM;
goto out_redist_unmap; goto out_redist_unmap;
......
...@@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{ {
void __iomem *base = gic_dist_base(d); void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d); unsigned int gicirq = gic_irq(d);
int ret;
/* Interrupt configuration for SGIs can't be changed */ /* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16) if (gicirq < 16)
...@@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
type != IRQ_TYPE_EDGE_RISING) type != IRQ_TYPE_EDGE_RISING)
return -EINVAL; return -EINVAL;
return gic_configure_irq(gicirq, type, base, NULL); ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL);
if (ret && gicirq < 32) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16);
ret = 0;
}
return ret;
} }
static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
...@@ -535,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic) ...@@ -535,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic)
gic_cpu_map[i] &= ~cpu_mask; gic_cpu_map[i] &= ~cpu_mask;
} }
gic_cpu_config(dist_base, NULL); gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
gic_cpu_if_up(gic); gic_cpu_if_up(gic);
...@@ -1627,7 +1635,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, ...@@ -1627,7 +1635,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
/* /*
* Initialize GIC instance zero (no multi-GIC support). * Initialize GIC instance zero (no multi-GIC support).
*/ */
domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base); domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
if (!domain_handle) { if (!domain_handle) {
pr_err("Unable to allocate domain handle\n"); pr_err("Unable to allocate domain handle\n");
gic_teardown(gic); gic_teardown(gic);
......
...@@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_lock(&irq_controller_lock); raw_spin_lock(&irq_controller_lock);
ret = gic_configure_irq(irq, type, base, NULL); ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL);
if (ret && irq < 32) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
ret = 0;
}
raw_spin_unlock(&irq_controller_lock); raw_spin_unlock(&irq_controller_lock);
...@@ -268,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) ...@@ -268,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
if (i != cpu) if (i != cpu)
hip04_cpu_map[i] &= ~cpu_mask; hip04_cpu_map[i] &= ~cpu_mask;
gic_cpu_config(dist_base, NULL); gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
writel_relaxed(1, base + GIC_CPU_CTRL); writel_relaxed(1, base + GIC_CPU_CTRL);
......
...@@ -362,10 +362,8 @@ static int pdc_intc_probe(struct platform_device *pdev) ...@@ -362,10 +362,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
} }
for (i = 0; i < priv->nr_perips; ++i) { for (i = 0; i < priv->nr_perips; ++i) {
irq = platform_get_irq(pdev, 1 + i); irq = platform_get_irq(pdev, 1 + i);
if (irq < 0) { if (irq < 0)
dev_err(&pdev->dev, "cannot find perip IRQ #%u\n", i);
return irq; return irq;
}
priv->perip_irqs[i] = irq; priv->perip_irqs[i] = irq;
} }
/* check if too many were provided */ /* check if too many were provided */
...@@ -376,10 +374,8 @@ static int pdc_intc_probe(struct platform_device *pdev) ...@@ -376,10 +374,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
/* Get syswake IRQ number */ /* Get syswake IRQ number */
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_err(&pdev->dev, "cannot find syswake IRQ\n");
return irq; return irq;
}
priv->syswake_irq = irq; priv->syswake_irq = irq;
/* Set up an IRQ domain */ /* Set up an IRQ domain */
......
...@@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase, ...@@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase,
pr_crit("IXP4XX: could not ioremap interrupt controller\n"); pr_crit("IXP4XX: could not ioremap interrupt controller\n");
return; return;
} }
fwnode = irq_domain_alloc_fwnode(base); fwnode = irq_domain_alloc_fwnode(&irqbase);
if (!fwnode) { if (!fwnode) {
pr_crit("IXP4XX: no domain handle\n"); pr_crit("IXP4XX: no domain handle\n");
return; return;
......
...@@ -164,10 +164,8 @@ static int keystone_irq_probe(struct platform_device *pdev) ...@@ -164,10 +164,8 @@ static int keystone_irq_probe(struct platform_device *pdev)
} }
kirq->irq = platform_get_irq(pdev, 0); kirq->irq = platform_get_irq(pdev, 0);
if (kirq->irq < 0) { if (kirq->irq < 0)
dev_err(dev, "no irq resource %d\n", kirq->irq);
return kirq->irq; return kirq->irq;
}
kirq->dev = dev; kirq->dev = dev;
kirq->mask = ~0x0; kirq->mask = ~0x0;
......
...@@ -24,14 +24,25 @@ ...@@ -24,14 +24,25 @@
#define REG_PIN_47_SEL 0x08 #define REG_PIN_47_SEL 0x08
#define REG_FILTER_SEL 0x0c #define REG_FILTER_SEL 0x0c
#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x))) /*
* Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by
* bits 24 to 31. Tests on the actual HW show that these bits are
* stuck at 0. Bits 8 to 15 are responsive and have the expected
* effect.
*/
#define REG_EDGE_POL_EDGE(x) BIT(x) #define REG_EDGE_POL_EDGE(x) BIT(x)
#define REG_EDGE_POL_LOW(x) BIT(16 + (x)) #define REG_EDGE_POL_LOW(x) BIT(16 + (x))
#define REG_BOTH_EDGE(x) BIT(8 + (x))
#define REG_EDGE_POL_MASK(x) ( \
REG_EDGE_POL_EDGE(x) | \
REG_EDGE_POL_LOW(x) | \
REG_BOTH_EDGE(x))
#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8) #define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
#define REG_FILTER_SEL_SHIFT(x) ((x) * 4) #define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
struct meson_gpio_irq_params { struct meson_gpio_irq_params {
unsigned int nr_hwirq; unsigned int nr_hwirq;
bool support_edge_both;
}; };
static const struct meson_gpio_irq_params meson8_params = { static const struct meson_gpio_irq_params meson8_params = {
...@@ -54,6 +65,11 @@ static const struct meson_gpio_irq_params axg_params = { ...@@ -54,6 +65,11 @@ static const struct meson_gpio_irq_params axg_params = {
.nr_hwirq = 100, .nr_hwirq = 100,
}; };
static const struct meson_gpio_irq_params sm1_params = {
.nr_hwirq = 100,
.support_edge_both = true,
};
static const struct of_device_id meson_irq_gpio_matches[] = { static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
...@@ -61,11 +77,12 @@ static const struct of_device_id meson_irq_gpio_matches[] = { ...@@ -61,11 +77,12 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
{ .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
{ .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params }, { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
{ .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
{ } { }
}; };
struct meson_gpio_irq_controller { struct meson_gpio_irq_controller {
unsigned int nr_hwirq; const struct meson_gpio_irq_params *params;
void __iomem *base; void __iomem *base;
u32 channel_irqs[NUM_CHANNEL]; u32 channel_irqs[NUM_CHANNEL];
DECLARE_BITMAP(channel_map, NUM_CHANNEL); DECLARE_BITMAP(channel_map, NUM_CHANNEL);
...@@ -168,14 +185,22 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl, ...@@ -168,14 +185,22 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl,
*/ */
type &= IRQ_TYPE_SENSE_MASK; type &= IRQ_TYPE_SENSE_MASK;
if (type == IRQ_TYPE_EDGE_BOTH) /*
* New controller support EDGE_BOTH trigger. This setting takes
* precedence over the other edge/polarity settings
*/
if (type == IRQ_TYPE_EDGE_BOTH) {
if (!ctl->params->support_edge_both)
return -EINVAL; return -EINVAL;
val |= REG_BOTH_EDGE(idx);
} else {
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_EDGE(idx); val |= REG_EDGE_POL_EDGE(idx);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_LOW(idx); val |= REG_EDGE_POL_LOW(idx);
}
spin_lock(&ctl->lock); spin_lock(&ctl->lock);
...@@ -199,7 +224,7 @@ static unsigned int meson_gpio_irq_type_output(unsigned int type) ...@@ -199,7 +224,7 @@ static unsigned int meson_gpio_irq_type_output(unsigned int type)
*/ */
if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
type |= IRQ_TYPE_LEVEL_HIGH; type |= IRQ_TYPE_LEVEL_HIGH;
else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) else
type |= IRQ_TYPE_EDGE_RISING; type |= IRQ_TYPE_EDGE_RISING;
return type; return type;
...@@ -328,15 +353,13 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node, ...@@ -328,15 +353,13 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node,
struct meson_gpio_irq_controller *ctl) struct meson_gpio_irq_controller *ctl)
{ {
const struct of_device_id *match; const struct of_device_id *match;
const struct meson_gpio_irq_params *params;
int ret; int ret;
match = of_match_node(meson_irq_gpio_matches, node); match = of_match_node(meson_irq_gpio_matches, node);
if (!match) if (!match)
return -ENODEV; return -ENODEV;
params = match->data; ctl->params = match->data;
ctl->nr_hwirq = params->nr_hwirq;
ret = of_property_read_variable_u32_array(node, ret = of_property_read_variable_u32_array(node,
"amlogic,channel-interrupts", "amlogic,channel-interrupts",
...@@ -385,7 +408,8 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, ...@@ -385,7 +408,8 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
if (ret) if (ret)
goto free_channel_irqs; goto free_channel_irqs;
domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq, domain = irq_domain_create_hierarchy(parent_domain, 0,
ctl->params->nr_hwirq,
of_node_to_fwnode(node), of_node_to_fwnode(node),
&meson_gpio_irq_domain_ops, &meson_gpio_irq_domain_ops,
ctl); ctl);
...@@ -396,7 +420,7 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, ...@@ -396,7 +420,7 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
} }
pr_info("%d to %d gpio interrupt mux initialized\n", pr_info("%d to %d gpio interrupt mux initialized\n",
ctl->nr_hwirq, NUM_CHANNEL); ctl->params->nr_hwirq, NUM_CHANNEL);
return 0; return 0;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -43,6 +44,7 @@ struct icu_chip_data { ...@@ -43,6 +44,7 @@ struct icu_chip_data {
unsigned int conf_enable; unsigned int conf_enable;
unsigned int conf_disable; unsigned int conf_disable;
unsigned int conf_mask; unsigned int conf_mask;
unsigned int conf2_mask;
unsigned int clr_mfp_irq_base; unsigned int clr_mfp_irq_base;
unsigned int clr_mfp_hwirq; unsigned int clr_mfp_hwirq;
struct irq_domain *domain; struct irq_domain *domain;
...@@ -52,9 +54,11 @@ struct mmp_intc_conf { ...@@ -52,9 +54,11 @@ struct mmp_intc_conf {
unsigned int conf_enable; unsigned int conf_enable;
unsigned int conf_disable; unsigned int conf_disable;
unsigned int conf_mask; unsigned int conf_mask;
unsigned int conf2_mask;
}; };
static void __iomem *mmp_icu_base; static void __iomem *mmp_icu_base;
static void __iomem *mmp_icu2_base;
static struct icu_chip_data icu_data[MAX_ICU_NR]; static struct icu_chip_data icu_data[MAX_ICU_NR];
static int max_icu_nr; static int max_icu_nr;
...@@ -97,6 +101,16 @@ static void icu_mask_irq(struct irq_data *d) ...@@ -97,6 +101,16 @@ static void icu_mask_irq(struct irq_data *d)
r &= ~data->conf_mask; r &= ~data->conf_mask;
r |= data->conf_disable; r |= data->conf_disable;
writel_relaxed(r, mmp_icu_base + (hwirq << 2)); writel_relaxed(r, mmp_icu_base + (hwirq << 2));
if (data->conf2_mask) {
/*
* ICU1 (above) only controls PJ4 MP1; if using SMP,
* we need to also mask the MP2 and MM cores via ICU2.
*/
r = readl_relaxed(mmp_icu2_base + (hwirq << 2));
r &= ~data->conf2_mask;
writel_relaxed(r, mmp_icu2_base + (hwirq << 2));
}
} else { } else {
r = readl_relaxed(data->reg_mask) | (1 << hwirq); r = readl_relaxed(data->reg_mask) | (1 << hwirq);
writel_relaxed(r, data->reg_mask); writel_relaxed(r, data->reg_mask);
...@@ -132,11 +146,14 @@ struct irq_chip icu_irq_chip = { ...@@ -132,11 +146,14 @@ struct irq_chip icu_irq_chip = {
static void icu_mux_irq_demux(struct irq_desc *desc) static void icu_mux_irq_demux(struct irq_desc *desc)
{ {
unsigned int irq = irq_desc_get_irq(desc); unsigned int irq = irq_desc_get_irq(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_domain *domain; struct irq_domain *domain;
struct icu_chip_data *data; struct icu_chip_data *data;
int i; int i;
unsigned long mask, status, n; unsigned long mask, status, n;
chained_irq_enter(chip, desc);
for (i = 1; i < max_icu_nr; i++) { for (i = 1; i < max_icu_nr; i++) {
if (irq == icu_data[i].cascade_irq) { if (irq == icu_data[i].cascade_irq) {
domain = icu_data[i].domain; domain = icu_data[i].domain;
...@@ -146,7 +163,7 @@ static void icu_mux_irq_demux(struct irq_desc *desc) ...@@ -146,7 +163,7 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
} }
if (i >= max_icu_nr) { if (i >= max_icu_nr) {
pr_err("Spurious irq %d in MMP INTC\n", irq); pr_err("Spurious irq %d in MMP INTC\n", irq);
return; goto out;
} }
mask = readl_relaxed(data->reg_mask); mask = readl_relaxed(data->reg_mask);
...@@ -158,6 +175,9 @@ static void icu_mux_irq_demux(struct irq_desc *desc) ...@@ -158,6 +175,9 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
generic_handle_irq(icu_data[i].virq_base + n); generic_handle_irq(icu_data[i].virq_base + n);
} }
} }
out:
chained_irq_exit(chip, desc);
} }
static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
...@@ -194,6 +214,14 @@ static const struct mmp_intc_conf mmp2_conf = { ...@@ -194,6 +214,14 @@ static const struct mmp_intc_conf mmp2_conf = {
MMP2_ICU_INT_ROUTE_PJ4_FIQ, MMP2_ICU_INT_ROUTE_PJ4_FIQ,
}; };
static struct mmp_intc_conf mmp3_conf = {
.conf_enable = 0x20,
.conf_disable = 0x0,
.conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
MMP2_ICU_INT_ROUTE_PJ4_FIQ,
.conf2_mask = 0xf0,
};
static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
{ {
int hwirq; int hwirq;
...@@ -395,7 +423,6 @@ static int __init mmp_of_init(struct device_node *node, ...@@ -395,7 +423,6 @@ static int __init mmp_of_init(struct device_node *node,
icu_data[0].conf_enable = mmp_conf.conf_enable; icu_data[0].conf_enable = mmp_conf.conf_enable;
icu_data[0].conf_disable = mmp_conf.conf_disable; icu_data[0].conf_disable = mmp_conf.conf_disable;
icu_data[0].conf_mask = mmp_conf.conf_mask; icu_data[0].conf_mask = mmp_conf.conf_mask;
irq_set_default_host(icu_data[0].domain);
set_handle_irq(mmp_handle_irq); set_handle_irq(mmp_handle_irq);
max_icu_nr = 1; max_icu_nr = 1;
return 0; return 0;
...@@ -414,19 +441,50 @@ static int __init mmp2_of_init(struct device_node *node, ...@@ -414,19 +441,50 @@ static int __init mmp2_of_init(struct device_node *node,
icu_data[0].conf_enable = mmp2_conf.conf_enable; icu_data[0].conf_enable = mmp2_conf.conf_enable;
icu_data[0].conf_disable = mmp2_conf.conf_disable; icu_data[0].conf_disable = mmp2_conf.conf_disable;
icu_data[0].conf_mask = mmp2_conf.conf_mask; icu_data[0].conf_mask = mmp2_conf.conf_mask;
irq_set_default_host(icu_data[0].domain);
set_handle_irq(mmp2_handle_irq); set_handle_irq(mmp2_handle_irq);
max_icu_nr = 1; max_icu_nr = 1;
return 0; return 0;
} }
IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init); IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
static int __init mmp3_of_init(struct device_node *node,
struct device_node *parent)
{
int ret;
mmp_icu2_base = of_iomap(node, 1);
if (!mmp_icu2_base) {
pr_err("Failed to get interrupt controller register #2\n");
return -ENODEV;
}
ret = mmp_init_bases(node);
if (ret < 0) {
iounmap(mmp_icu2_base);
return ret;
}
icu_data[0].conf_enable = mmp3_conf.conf_enable;
icu_data[0].conf_disable = mmp3_conf.conf_disable;
icu_data[0].conf_mask = mmp3_conf.conf_mask;
icu_data[0].conf2_mask = mmp3_conf.conf2_mask;
if (!parent) {
/* This is the main interrupt controller. */
set_handle_irq(mmp2_handle_irq);
}
max_icu_nr = 1;
return 0;
}
IRQCHIP_DECLARE(mmp3_intc, "marvell,mmp3-intc", mmp3_of_init);
static int __init mmp2_mux_of_init(struct device_node *node, static int __init mmp2_mux_of_init(struct device_node *node,
struct device_node *parent) struct device_node *parent)
{ {
struct resource res;
int i, ret, irq, j = 0; int i, ret, irq, j = 0;
u32 nr_irqs, mfp_irq; u32 nr_irqs, mfp_irq;
u32 reg[4];
if (!parent) if (!parent)
return -ENODEV; return -ENODEV;
...@@ -438,18 +496,22 @@ static int __init mmp2_mux_of_init(struct device_node *node, ...@@ -438,18 +496,22 @@ static int __init mmp2_mux_of_init(struct device_node *node,
pr_err("Not found mrvl,intc-nr-irqs property\n"); pr_err("Not found mrvl,intc-nr-irqs property\n");
return -EINVAL; return -EINVAL;
} }
ret = of_address_to_resource(node, 0, &res);
if (ret < 0) { /*
pr_err("Not found reg property\n"); * For historical reasons, the "regs" property of the
return -EINVAL; * mrvl,mmp2-mux-intc is not a regular "regs" property containing
} * addresses on the parent bus, but offsets from the intc's base.
icu_data[i].reg_status = mmp_icu_base + res.start; * That is why we can't use of_address_to_resource() here.
ret = of_address_to_resource(node, 1, &res); */
ret = of_property_read_variable_u32_array(node, "reg", reg,
ARRAY_SIZE(reg),
ARRAY_SIZE(reg));
if (ret < 0) { if (ret < 0) {
pr_err("Not found reg property\n"); pr_err("Not found reg property\n");
return -EINVAL; return -EINVAL;
} }
icu_data[i].reg_mask = mmp_icu_base + res.start; icu_data[i].reg_status = mmp_icu_base + reg[0];
icu_data[i].reg_mask = mmp_icu_base + reg[2];
icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
if (!icu_data[i].cascade_irq) if (!icu_data[i].cascade_irq)
return -EINVAL; return -EINVAL;
......
...@@ -166,7 +166,6 @@ static int uniphier_aidet_probe(struct platform_device *pdev) ...@@ -166,7 +166,6 @@ static int uniphier_aidet_probe(struct platform_device *pdev)
struct device_node *parent_np; struct device_node *parent_np;
struct irq_domain *parent_domain; struct irq_domain *parent_domain;
struct uniphier_aidet_priv *priv; struct uniphier_aidet_priv *priv;
struct resource *res;
parent_np = of_irq_find_parent(dev->of_node); parent_np = of_irq_find_parent(dev->of_node);
if (!parent_np) if (!parent_np)
...@@ -181,8 +180,7 @@ static int uniphier_aidet_probe(struct platform_device *pdev) ...@@ -181,8 +180,7 @@ static int uniphier_aidet_probe(struct platform_device *pdev)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
priv->reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->reg_base)) if (IS_ERR(priv->reg_base))
return PTR_ERR(priv->reg_base); return PTR_ERR(priv->reg_base);
......
...@@ -248,10 +248,8 @@ static int __init combiner_probe(struct platform_device *pdev) ...@@ -248,10 +248,8 @@ static int __init combiner_probe(struct platform_device *pdev)
return err; return err;
combiner->parent_irq = platform_get_irq(pdev, 0); combiner->parent_irq = platform_get_irq(pdev, 0);
if (combiner->parent_irq <= 0) { if (combiner->parent_irq <= 0)
dev_err(&pdev->dev, "Error getting IRQ resource\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
}
combiner->domain = irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs, combiner->domain = irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs,
&domain_ops, combiner); &domain_ops, combiner);
......
...@@ -2521,6 +2521,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -2521,6 +2521,7 @@ static int hv_pci_probe(struct hv_device *hdev,
const struct hv_vmbus_device_id *dev_id) const struct hv_vmbus_device_id *dev_id)
{ {
struct hv_pcibus_device *hbus; struct hv_pcibus_device *hbus;
char *name;
int ret; int ret;
/* /*
...@@ -2589,7 +2590,14 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -2589,7 +2590,14 @@ static int hv_pci_probe(struct hv_device *hdev,
goto free_config; goto free_config;
} }
hbus->sysdata.fwnode = irq_domain_alloc_fwnode(hbus); name = kasprintf(GFP_KERNEL, "%pUL", &hdev->dev_instance);
if (!name) {
ret = -ENOMEM;
goto unmap;
}
hbus->sysdata.fwnode = irq_domain_alloc_named_fwnode(name);
kfree(name);
if (!hbus->sysdata.fwnode) { if (!hbus->sysdata.fwnode) {
ret = -ENOMEM; ret = -ENOMEM;
goto unmap; goto unmap;
......
...@@ -30,10 +30,22 @@ ...@@ -30,10 +30,22 @@
#define GICD_ICFGR 0x0C00 #define GICD_ICFGR 0x0C00
#define GICD_IGRPMODR 0x0D00 #define GICD_IGRPMODR 0x0D00
#define GICD_NSACR 0x0E00 #define GICD_NSACR 0x0E00
#define GICD_IGROUPRnE 0x1000
#define GICD_ISENABLERnE 0x1200
#define GICD_ICENABLERnE 0x1400
#define GICD_ISPENDRnE 0x1600
#define GICD_ICPENDRnE 0x1800
#define GICD_ISACTIVERnE 0x1A00
#define GICD_ICACTIVERnE 0x1C00
#define GICD_IPRIORITYRnE 0x2000
#define GICD_ICFGRnE 0x3000
#define GICD_IROUTER 0x6000 #define GICD_IROUTER 0x6000
#define GICD_IROUTERnE 0x8000
#define GICD_IDREGS 0xFFD0 #define GICD_IDREGS 0xFFD0
#define GICD_PIDR2 0xFFE8 #define GICD_PIDR2 0xFFE8
#define ESPI_BASE_INTID 4096
/* /*
* Those registers are actually from GICv2, but the spec demands that they * Those registers are actually from GICv2, but the spec demands that they
* are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3). * are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3).
...@@ -69,10 +81,13 @@ ...@@ -69,10 +81,13 @@
#define GICD_TYPER_RSS (1U << 26) #define GICD_TYPER_RSS (1U << 26)
#define GICD_TYPER_LPIS (1U << 17) #define GICD_TYPER_LPIS (1U << 17)
#define GICD_TYPER_MBIS (1U << 16) #define GICD_TYPER_MBIS (1U << 16)
#define GICD_TYPER_ESPI (1U << 8)
#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) #define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1)
#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1) #define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1)
#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) #define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32)
#define GICD_TYPER_ESPIS(typer) \
(((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0)
#define GICD_IROUTER_SPI_MODE_ONE (0U << 31) #define GICD_IROUTER_SPI_MODE_ONE (0U << 31)
#define GICD_IROUTER_SPI_MODE_ANY (1U << 31) #define GICD_IROUTER_SPI_MODE_ANY (1U << 31)
...@@ -109,6 +124,18 @@ ...@@ -109,6 +124,18 @@
#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) #define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
#define EPPI_BASE_INTID 1056
#define GICR_TYPER_NR_PPIS(r) \
({ \
unsigned int __ppinum = ((r) >> 27) & 0x1f; \
unsigned int __nr_ppis = 16; \
if (__ppinum == 1 || __ppinum == 2) \
__nr_ppis += __ppinum * 32; \
\
__nr_ppis; \
})
#define GICR_WAKER_ProcessorSleep (1U << 1) #define GICR_WAKER_ProcessorSleep (1U << 1)
#define GICR_WAKER_ChildrenAsleep (1U << 2) #define GICR_WAKER_ChildrenAsleep (1U << 2)
...@@ -469,6 +496,7 @@ ...@@ -469,6 +496,7 @@
#define ICC_CTLR_EL1_A3V_SHIFT 15 #define ICC_CTLR_EL1_A3V_SHIFT 15
#define ICC_CTLR_EL1_A3V_MASK (0x1 << ICC_CTLR_EL1_A3V_SHIFT) #define ICC_CTLR_EL1_A3V_MASK (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
#define ICC_CTLR_EL1_RSS (0x1 << 18) #define ICC_CTLR_EL1_RSS (0x1 << 18)
#define ICC_CTLR_EL1_ExtRange (0x1 << 19)
#define ICC_PMR_EL1_SHIFT 0 #define ICC_PMR_EL1_SHIFT 0
#define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT) #define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT)
#define ICC_BPR0_EL1_SHIFT 0 #define ICC_BPR0_EL1_SHIFT 0
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
* Author: Marc Zyngier <marc.zyngier@arm.com> * Author: Marc Zyngier <marc.zyngier@arm.com>
*/ */
#ifndef __LINUX_IRQCHIP_IRQ_PARTITION_PERCPU_H
#define __LINUX_IRQCHIP_IRQ_PARTITION_PERCPU_H
#include <linux/fwnode.h> #include <linux/fwnode.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -46,3 +49,5 @@ struct irq_domain *partition_get_domain(struct partition_desc *dsc) ...@@ -46,3 +49,5 @@ struct irq_domain *partition_get_domain(struct partition_desc *dsc)
return NULL; return NULL;
} }
#endif #endif
#endif /* __LINUX_IRQCHIP_IRQ_PARTITION_PERCPU_H */
...@@ -220,7 +220,7 @@ static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d) ...@@ -220,7 +220,7 @@ static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d)
#ifdef CONFIG_IRQ_DOMAIN #ifdef CONFIG_IRQ_DOMAIN
struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
const char *name, void *data); const char *name, phys_addr_t *pa);
enum { enum {
IRQCHIP_FWNODE_REAL, IRQCHIP_FWNODE_REAL,
...@@ -241,9 +241,9 @@ struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id) ...@@ -241,9 +241,9 @@ struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id)
NULL); NULL);
} }
static inline struct fwnode_handle *irq_domain_alloc_fwnode(void *data) static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa)
{ {
return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, data); return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa);
} }
void irq_domain_free_fwnode(struct fwnode_handle *fwnode); void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
......
...@@ -31,7 +31,7 @@ struct irqchip_fwid { ...@@ -31,7 +31,7 @@ struct irqchip_fwid {
struct fwnode_handle fwnode; struct fwnode_handle fwnode;
unsigned int type; unsigned int type;
char *name; char *name;
void *data; phys_addr_t *pa;
}; };
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
...@@ -62,7 +62,8 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); ...@@ -62,7 +62,8 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
* domain struct. * domain struct.
*/ */
struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
const char *name, void *data) const char *name,
phys_addr_t *pa)
{ {
struct irqchip_fwid *fwid; struct irqchip_fwid *fwid;
char *n; char *n;
...@@ -77,7 +78,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, ...@@ -77,7 +78,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
n = kasprintf(GFP_KERNEL, "%s-%d", name, id); n = kasprintf(GFP_KERNEL, "%s-%d", name, id);
break; break;
default: default:
n = kasprintf(GFP_KERNEL, "irqchip@%p", data); n = kasprintf(GFP_KERNEL, "irqchip@%pa", pa);
break; break;
} }
...@@ -89,7 +90,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, ...@@ -89,7 +90,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
fwid->type = type; fwid->type = type;
fwid->name = n; fwid->name = n;
fwid->data = data; fwid->pa = pa;
fwid->fwnode.ops = &irqchip_fwnode_ops; fwid->fwnode.ops = &irqchip_fwnode_ops;
return &fwid->fwnode; return &fwid->fwnode;
} }
...@@ -148,6 +149,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, ...@@ -148,6 +149,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
switch (fwid->type) { switch (fwid->type) {
case IRQCHIP_FWNODE_NAMED: case IRQCHIP_FWNODE_NAMED:
case IRQCHIP_FWNODE_NAMED_ID: case IRQCHIP_FWNODE_NAMED_ID:
domain->fwnode = fwnode;
domain->name = kstrdup(fwid->name, GFP_KERNEL); domain->name = kstrdup(fwid->name, GFP_KERNEL);
if (!domain->name) { if (!domain->name) {
kfree(domain); kfree(domain);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment