18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2013-2017 ARM Limited, All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	"GICv3: " fmt
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/acpi.h>
108c2ecf20Sopenharmony_ci#include <linux/cpu.h>
118c2ecf20Sopenharmony_ci#include <linux/cpu_pm.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_address.h>
178c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
188c2ecf20Sopenharmony_ci#include <linux/percpu.h>
198c2ecf20Sopenharmony_ci#include <linux/refcount.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/irqchip.h>
238c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic-common.h>
248c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h>
258c2ecf20Sopenharmony_ci#include <linux/irqchip/irq-partition-percpu.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <asm/cputype.h>
288c2ecf20Sopenharmony_ci#include <asm/exception.h>
298c2ecf20Sopenharmony_ci#include <asm/smp_plat.h>
308c2ecf20Sopenharmony_ci#include <asm/virt.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "irq-gic-common.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define GICD_INT_NMI_PRI	(GICD_INT_DEF_PRI & ~0x80)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996	(1ULL << 0)
378c2ecf20Sopenharmony_ci#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539	(1ULL << 1)
388c2ecf20Sopenharmony_ci#define FLAGS_WORKAROUND_MTK_GICR_SAVE		(1ULL << 2)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define GIC_IRQ_TYPE_PARTITION	(GIC_IRQ_TYPE_LPI + 1)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct redist_region {
438c2ecf20Sopenharmony_ci	void __iomem		*redist_base;
448c2ecf20Sopenharmony_ci	phys_addr_t		phys_base;
458c2ecf20Sopenharmony_ci	bool			single_redist;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistruct gic_chip_data {
498c2ecf20Sopenharmony_ci	struct fwnode_handle	*fwnode;
508c2ecf20Sopenharmony_ci	void __iomem		*dist_base;
518c2ecf20Sopenharmony_ci	struct redist_region	*redist_regions;
528c2ecf20Sopenharmony_ci	struct rdists		rdists;
538c2ecf20Sopenharmony_ci	struct irq_domain	*domain;
548c2ecf20Sopenharmony_ci	u64			redist_stride;
558c2ecf20Sopenharmony_ci	u32			nr_redist_regions;
568c2ecf20Sopenharmony_ci	u64			flags;
578c2ecf20Sopenharmony_ci	bool			has_rss;
588c2ecf20Sopenharmony_ci	unsigned int		ppi_nr;
598c2ecf20Sopenharmony_ci	struct partition_desc	**ppi_descs;
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct gic_chip_data gic_data __read_mostly;
638c2ecf20Sopenharmony_cistatic DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define GIC_ID_NR	(1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer))
668c2ecf20Sopenharmony_ci#define GIC_LINE_NR	min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
678c2ecf20Sopenharmony_ci#define GIC_ESPI_NR	GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/*
708c2ecf20Sopenharmony_ci * The behaviours of RPR and PMR registers differ depending on the value of
718c2ecf20Sopenharmony_ci * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
728c2ecf20Sopenharmony_ci * distributor and redistributors depends on whether security is enabled in the
738c2ecf20Sopenharmony_ci * GIC.
748c2ecf20Sopenharmony_ci *
758c2ecf20Sopenharmony_ci * When security is enabled, non-secure priority values from the (re)distributor
768c2ecf20Sopenharmony_ci * are presented to the GIC CPUIF as follow:
778c2ecf20Sopenharmony_ci *     (GIC_(R)DIST_PRI[irq] >> 1) | 0x80;
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * If SCR_EL3.FIQ == 1, the values writen to/read from PMR and RPR at non-secure
808c2ecf20Sopenharmony_ci * EL1 are subject to a similar operation thus matching the priorities presented
818c2ecf20Sopenharmony_ci * from the (re)distributor when security is enabled. When SCR_EL3.FIQ == 0,
828c2ecf20Sopenharmony_ci * these values are unchanched by the GIC.
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * see GICv3/GICv4 Architecture Specification (IHI0069D):
858c2ecf20Sopenharmony_ci * - section 4.8.1 Non-secure accesses to register fields for Secure interrupt
868c2ecf20Sopenharmony_ci *   priorities.
878c2ecf20Sopenharmony_ci * - Figure 4-7 Secure read of the priority field for a Non-secure Group 1
888c2ecf20Sopenharmony_ci *   interrupt.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cistatic DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * Global static key controlling whether an update to PMR allowing more
948c2ecf20Sopenharmony_ci * interrupts requires to be propagated to the redistributor (DSB SY).
958c2ecf20Sopenharmony_ci * And this needs to be exported for modules to be able to enable
968c2ecf20Sopenharmony_ci * interrupts...
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(gic_pmr_sync);
998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gic_pmr_sync);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities);
1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gic_nonsecure_priorities);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * When the Non-secure world has access to group 0 interrupts (as a
1068c2ecf20Sopenharmony_ci * consequence of SCR_EL3.FIQ == 0), reading the ICC_RPR_EL1 register will
1078c2ecf20Sopenharmony_ci * return the Distributor's view of the interrupt priority.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * When GIC security is enabled (GICD_CTLR.DS == 0), the interrupt priority
1108c2ecf20Sopenharmony_ci * written by software is moved to the Non-secure range by the Distributor.
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci * If both are true (which is when gic_nonsecure_priorities gets enabled),
1138c2ecf20Sopenharmony_ci * we need to shift down the priority programmed by software to match it
1148c2ecf20Sopenharmony_ci * against the value returned by ICC_RPR_EL1.
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_ci#define GICD_INT_RPR_PRI(priority)					\
1178c2ecf20Sopenharmony_ci	({								\
1188c2ecf20Sopenharmony_ci		u32 __priority = (priority);				\
1198c2ecf20Sopenharmony_ci		if (static_branch_unlikely(&gic_nonsecure_priorities))	\
1208c2ecf20Sopenharmony_ci			__priority = 0x80 | (__priority >> 1);		\
1218c2ecf20Sopenharmony_ci									\
1228c2ecf20Sopenharmony_ci		__priority;						\
1238c2ecf20Sopenharmony_ci	})
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
1268c2ecf20Sopenharmony_cistatic refcount_t *ppi_nmi_refs;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic struct gic_kvm_info gic_v3_kvm_info;
1298c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(bool, has_rss);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci#define MPIDR_RS(mpidr)			(((mpidr) & 0xF0UL) >> 4)
1328c2ecf20Sopenharmony_ci#define gic_data_rdist()		(this_cpu_ptr(gic_data.rdists.rdist))
1338c2ecf20Sopenharmony_ci#define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
1348c2ecf20Sopenharmony_ci#define gic_data_rdist_sgi_base()	(gic_data_rdist_rd_base() + SZ_64K)
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* Our default, arbitrary priority value. Linux only uses one anyway. */
1378c2ecf20Sopenharmony_ci#define DEFAULT_PMR_VALUE	0xf0
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cienum gic_intid_range {
1408c2ecf20Sopenharmony_ci	SGI_RANGE,
1418c2ecf20Sopenharmony_ci	PPI_RANGE,
1428c2ecf20Sopenharmony_ci	SPI_RANGE,
1438c2ecf20Sopenharmony_ci	EPPI_RANGE,
1448c2ecf20Sopenharmony_ci	ESPI_RANGE,
1458c2ecf20Sopenharmony_ci	LPI_RANGE,
1468c2ecf20Sopenharmony_ci	__INVALID_RANGE__
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	switch (hwirq) {
1528c2ecf20Sopenharmony_ci	case 0 ... 15:
1538c2ecf20Sopenharmony_ci		return SGI_RANGE;
1548c2ecf20Sopenharmony_ci	case 16 ... 31:
1558c2ecf20Sopenharmony_ci		return PPI_RANGE;
1568c2ecf20Sopenharmony_ci	case 32 ... 1019:
1578c2ecf20Sopenharmony_ci		return SPI_RANGE;
1588c2ecf20Sopenharmony_ci	case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
1598c2ecf20Sopenharmony_ci		return EPPI_RANGE;
1608c2ecf20Sopenharmony_ci	case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
1618c2ecf20Sopenharmony_ci		return ESPI_RANGE;
1628c2ecf20Sopenharmony_ci	case 8192 ... GENMASK(23, 0):
1638c2ecf20Sopenharmony_ci		return LPI_RANGE;
1648c2ecf20Sopenharmony_ci	default:
1658c2ecf20Sopenharmony_ci		return __INVALID_RANGE__;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic enum gic_intid_range get_intid_range(struct irq_data *d)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	return __get_intid_range(d->hwirq);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline unsigned int gic_irq(struct irq_data *d)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	return d->hwirq;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic inline bool gic_irq_in_rdist(struct irq_data *d)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	switch (get_intid_range(d)) {
1828c2ecf20Sopenharmony_ci	case SGI_RANGE:
1838c2ecf20Sopenharmony_ci	case PPI_RANGE:
1848c2ecf20Sopenharmony_ci	case EPPI_RANGE:
1858c2ecf20Sopenharmony_ci		return true;
1868c2ecf20Sopenharmony_ci	default:
1878c2ecf20Sopenharmony_ci		return false;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic inline void __iomem *gic_dist_base(struct irq_data *d)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	switch (get_intid_range(d)) {
1948c2ecf20Sopenharmony_ci	case SGI_RANGE:
1958c2ecf20Sopenharmony_ci	case PPI_RANGE:
1968c2ecf20Sopenharmony_ci	case EPPI_RANGE:
1978c2ecf20Sopenharmony_ci		/* SGI+PPI -> SGI_base for this CPU */
1988c2ecf20Sopenharmony_ci		return gic_data_rdist_sgi_base();
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	case SPI_RANGE:
2018c2ecf20Sopenharmony_ci	case ESPI_RANGE:
2028c2ecf20Sopenharmony_ci		/* SPI -> dist_base */
2038c2ecf20Sopenharmony_ci		return gic_data.dist_base;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	default:
2068c2ecf20Sopenharmony_ci		return NULL;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic void gic_do_wait_for_rwp(void __iomem *base, u32 bit)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	u32 count = 1000000;	/* 1s! */
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	while (readl_relaxed(base + GICD_CTLR) & bit) {
2158c2ecf20Sopenharmony_ci		count--;
2168c2ecf20Sopenharmony_ci		if (!count) {
2178c2ecf20Sopenharmony_ci			pr_err_ratelimited("RWP timeout, gone fishing\n");
2188c2ecf20Sopenharmony_ci			return;
2198c2ecf20Sopenharmony_ci		}
2208c2ecf20Sopenharmony_ci		cpu_relax();
2218c2ecf20Sopenharmony_ci		udelay(1);
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/* Wait for completion of a distributor change */
2268c2ecf20Sopenharmony_cistatic void gic_dist_wait_for_rwp(void)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	gic_do_wait_for_rwp(gic_data.dist_base, GICD_CTLR_RWP);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* Wait for completion of a redistributor change */
2328c2ecf20Sopenharmony_cistatic void gic_redist_wait_for_rwp(void)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	gic_do_wait_for_rwp(gic_data_rdist_rd_base(), GICR_CTLR_RWP);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic u64 __maybe_unused gic_read_iar(void)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_23154))
2428c2ecf20Sopenharmony_ci		return gic_read_iar_cavium_thunderx();
2438c2ecf20Sopenharmony_ci	else
2448c2ecf20Sopenharmony_ci		return gic_read_iar_common();
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci#endif
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic void gic_enable_redist(bool enable)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	void __iomem *rbase;
2518c2ecf20Sopenharmony_ci	u32 count = 1000000;	/* 1s! */
2528c2ecf20Sopenharmony_ci	u32 val;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (gic_data.flags & FLAGS_WORKAROUND_GICR_WAKER_MSM8996)
2558c2ecf20Sopenharmony_ci		return;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	rbase = gic_data_rdist_rd_base();
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	val = readl_relaxed(rbase + GICR_WAKER);
2608c2ecf20Sopenharmony_ci	if (enable)
2618c2ecf20Sopenharmony_ci		/* Wake up this CPU redistributor */
2628c2ecf20Sopenharmony_ci		val &= ~GICR_WAKER_ProcessorSleep;
2638c2ecf20Sopenharmony_ci	else
2648c2ecf20Sopenharmony_ci		val |= GICR_WAKER_ProcessorSleep;
2658c2ecf20Sopenharmony_ci	writel_relaxed(val, rbase + GICR_WAKER);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (!enable) {		/* Check that GICR_WAKER is writeable */
2688c2ecf20Sopenharmony_ci		val = readl_relaxed(rbase + GICR_WAKER);
2698c2ecf20Sopenharmony_ci		if (!(val & GICR_WAKER_ProcessorSleep))
2708c2ecf20Sopenharmony_ci			return;	/* No PM support in this redistributor */
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	while (--count) {
2748c2ecf20Sopenharmony_ci		val = readl_relaxed(rbase + GICR_WAKER);
2758c2ecf20Sopenharmony_ci		if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep))
2768c2ecf20Sopenharmony_ci			break;
2778c2ecf20Sopenharmony_ci		cpu_relax();
2788c2ecf20Sopenharmony_ci		udelay(1);
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci	if (!count)
2818c2ecf20Sopenharmony_ci		pr_err_ratelimited("redistributor failed to %s...\n",
2828c2ecf20Sopenharmony_ci				   enable ? "wakeup" : "sleep");
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/*
2868c2ecf20Sopenharmony_ci * Routines to disable, enable, EOI and route interrupts
2878c2ecf20Sopenharmony_ci */
2888c2ecf20Sopenharmony_cistatic u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	switch (get_intid_range(d)) {
2918c2ecf20Sopenharmony_ci	case SGI_RANGE:
2928c2ecf20Sopenharmony_ci	case PPI_RANGE:
2938c2ecf20Sopenharmony_ci	case SPI_RANGE:
2948c2ecf20Sopenharmony_ci		*index = d->hwirq;
2958c2ecf20Sopenharmony_ci		return offset;
2968c2ecf20Sopenharmony_ci	case EPPI_RANGE:
2978c2ecf20Sopenharmony_ci		/*
2988c2ecf20Sopenharmony_ci		 * Contrary to the ESPI range, the EPPI range is contiguous
2998c2ecf20Sopenharmony_ci		 * to the PPI range in the registers, so let's adjust the
3008c2ecf20Sopenharmony_ci		 * displacement accordingly. Consistency is overrated.
3018c2ecf20Sopenharmony_ci		 */
3028c2ecf20Sopenharmony_ci		*index = d->hwirq - EPPI_BASE_INTID + 32;
3038c2ecf20Sopenharmony_ci		return offset;
3048c2ecf20Sopenharmony_ci	case ESPI_RANGE:
3058c2ecf20Sopenharmony_ci		*index = d->hwirq - ESPI_BASE_INTID;
3068c2ecf20Sopenharmony_ci		switch (offset) {
3078c2ecf20Sopenharmony_ci		case GICD_ISENABLER:
3088c2ecf20Sopenharmony_ci			return GICD_ISENABLERnE;
3098c2ecf20Sopenharmony_ci		case GICD_ICENABLER:
3108c2ecf20Sopenharmony_ci			return GICD_ICENABLERnE;
3118c2ecf20Sopenharmony_ci		case GICD_ISPENDR:
3128c2ecf20Sopenharmony_ci			return GICD_ISPENDRnE;
3138c2ecf20Sopenharmony_ci		case GICD_ICPENDR:
3148c2ecf20Sopenharmony_ci			return GICD_ICPENDRnE;
3158c2ecf20Sopenharmony_ci		case GICD_ISACTIVER:
3168c2ecf20Sopenharmony_ci			return GICD_ISACTIVERnE;
3178c2ecf20Sopenharmony_ci		case GICD_ICACTIVER:
3188c2ecf20Sopenharmony_ci			return GICD_ICACTIVERnE;
3198c2ecf20Sopenharmony_ci		case GICD_IPRIORITYR:
3208c2ecf20Sopenharmony_ci			return GICD_IPRIORITYRnE;
3218c2ecf20Sopenharmony_ci		case GICD_ICFGR:
3228c2ecf20Sopenharmony_ci			return GICD_ICFGRnE;
3238c2ecf20Sopenharmony_ci		case GICD_IROUTER:
3248c2ecf20Sopenharmony_ci			return GICD_IROUTERnE;
3258c2ecf20Sopenharmony_ci		default:
3268c2ecf20Sopenharmony_ci			break;
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci		break;
3298c2ecf20Sopenharmony_ci	default:
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	WARN_ON(1);
3348c2ecf20Sopenharmony_ci	*index = d->hwirq;
3358c2ecf20Sopenharmony_ci	return offset;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int gic_peek_irq(struct irq_data *d, u32 offset)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	void __iomem *base;
3418c2ecf20Sopenharmony_ci	u32 index, mask;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	offset = convert_offset_index(d, offset, &index);
3448c2ecf20Sopenharmony_ci	mask = 1 << (index % 32);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d))
3478c2ecf20Sopenharmony_ci		base = gic_data_rdist_sgi_base();
3488c2ecf20Sopenharmony_ci	else
3498c2ecf20Sopenharmony_ci		base = gic_data.dist_base;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void gic_poke_irq(struct irq_data *d, u32 offset)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	void (*rwp_wait)(void);
3578c2ecf20Sopenharmony_ci	void __iomem *base;
3588c2ecf20Sopenharmony_ci	u32 index, mask;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	offset = convert_offset_index(d, offset, &index);
3618c2ecf20Sopenharmony_ci	mask = 1 << (index % 32);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d)) {
3648c2ecf20Sopenharmony_ci		base = gic_data_rdist_sgi_base();
3658c2ecf20Sopenharmony_ci		rwp_wait = gic_redist_wait_for_rwp;
3668c2ecf20Sopenharmony_ci	} else {
3678c2ecf20Sopenharmony_ci		base = gic_data.dist_base;
3688c2ecf20Sopenharmony_ci		rwp_wait = gic_dist_wait_for_rwp;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	writel_relaxed(mask, base + offset + (index / 32) * 4);
3728c2ecf20Sopenharmony_ci	rwp_wait();
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic void gic_mask_irq(struct irq_data *d)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	gic_poke_irq(d, GICD_ICENABLER);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void gic_eoimode1_mask_irq(struct irq_data *d)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	gic_mask_irq(d);
3838c2ecf20Sopenharmony_ci	/*
3848c2ecf20Sopenharmony_ci	 * When masking a forwarded interrupt, make sure it is
3858c2ecf20Sopenharmony_ci	 * deactivated as well.
3868c2ecf20Sopenharmony_ci	 *
3878c2ecf20Sopenharmony_ci	 * This ensures that an interrupt that is getting
3888c2ecf20Sopenharmony_ci	 * disabled/masked will not get "stuck", because there is
3898c2ecf20Sopenharmony_ci	 * noone to deactivate it (guest is being terminated).
3908c2ecf20Sopenharmony_ci	 */
3918c2ecf20Sopenharmony_ci	if (irqd_is_forwarded_to_vcpu(d))
3928c2ecf20Sopenharmony_ci		gic_poke_irq(d, GICD_ICACTIVER);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic void gic_unmask_irq(struct irq_data *d)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	gic_poke_irq(d, GICD_ISENABLER);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic inline bool gic_supports_nmi(void)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
4038c2ecf20Sopenharmony_ci	       static_branch_likely(&supports_pseudo_nmis);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic int gic_irq_set_irqchip_state(struct irq_data *d,
4078c2ecf20Sopenharmony_ci				     enum irqchip_irq_state which, bool val)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	u32 reg;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (d->hwirq >= 8192) /* SGI/PPI/SPI only */
4128c2ecf20Sopenharmony_ci		return -EINVAL;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	switch (which) {
4158c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_PENDING:
4168c2ecf20Sopenharmony_ci		reg = val ? GICD_ISPENDR : GICD_ICPENDR;
4178c2ecf20Sopenharmony_ci		break;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_ACTIVE:
4208c2ecf20Sopenharmony_ci		reg = val ? GICD_ISACTIVER : GICD_ICACTIVER;
4218c2ecf20Sopenharmony_ci		break;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_MASKED:
4248c2ecf20Sopenharmony_ci		reg = val ? GICD_ICENABLER : GICD_ISENABLER;
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	default:
4288c2ecf20Sopenharmony_ci		return -EINVAL;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	gic_poke_irq(d, reg);
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int gic_irq_get_irqchip_state(struct irq_data *d,
4368c2ecf20Sopenharmony_ci				     enum irqchip_irq_state which, bool *val)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	if (d->hwirq >= 8192) /* PPI/SPI only */
4398c2ecf20Sopenharmony_ci		return -EINVAL;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	switch (which) {
4428c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_PENDING:
4438c2ecf20Sopenharmony_ci		*val = gic_peek_irq(d, GICD_ISPENDR);
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_ACTIVE:
4478c2ecf20Sopenharmony_ci		*val = gic_peek_irq(d, GICD_ISACTIVER);
4488c2ecf20Sopenharmony_ci		break;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	case IRQCHIP_STATE_MASKED:
4518c2ecf20Sopenharmony_ci		*val = !gic_peek_irq(d, GICD_ISENABLER);
4528c2ecf20Sopenharmony_ci		break;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	default:
4558c2ecf20Sopenharmony_ci		return -EINVAL;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return 0;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic void gic_irq_set_prio(struct irq_data *d, u8 prio)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	void __iomem *base = gic_dist_base(d);
4648c2ecf20Sopenharmony_ci	u32 offset, index;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	offset = convert_offset_index(d, GICD_IPRIORITYR, &index);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	writeb_relaxed(prio, base + offset + index);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic u32 gic_get_ppi_index(struct irq_data *d)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	switch (get_intid_range(d)) {
4748c2ecf20Sopenharmony_ci	case PPI_RANGE:
4758c2ecf20Sopenharmony_ci		return d->hwirq - 16;
4768c2ecf20Sopenharmony_ci	case EPPI_RANGE:
4778c2ecf20Sopenharmony_ci		return d->hwirq - EPPI_BASE_INTID + 16;
4788c2ecf20Sopenharmony_ci	default:
4798c2ecf20Sopenharmony_ci		unreachable();
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int gic_irq_nmi_setup(struct irq_data *d)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct irq_desc *desc = irq_to_desc(d->irq);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (!gic_supports_nmi())
4888c2ecf20Sopenharmony_ci		return -EINVAL;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (gic_peek_irq(d, GICD_ISENABLER)) {
4918c2ecf20Sopenharmony_ci		pr_err("Cannot set NMI property of enabled IRQ %u\n", d->irq);
4928c2ecf20Sopenharmony_ci		return -EINVAL;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/*
4968c2ecf20Sopenharmony_ci	 * A secondary irq_chip should be in charge of LPI request,
4978c2ecf20Sopenharmony_ci	 * it should not be possible to get there
4988c2ecf20Sopenharmony_ci	 */
4998c2ecf20Sopenharmony_ci	if (WARN_ON(gic_irq(d) >= 8192))
5008c2ecf20Sopenharmony_ci		return -EINVAL;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* desc lock should already be held */
5038c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d)) {
5048c2ecf20Sopenharmony_ci		u32 idx = gic_get_ppi_index(d);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		/* Setting up PPI as NMI, only switch handler for first NMI */
5078c2ecf20Sopenharmony_ci		if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) {
5088c2ecf20Sopenharmony_ci			refcount_set(&ppi_nmi_refs[idx], 1);
5098c2ecf20Sopenharmony_ci			desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
5108c2ecf20Sopenharmony_ci		}
5118c2ecf20Sopenharmony_ci	} else {
5128c2ecf20Sopenharmony_ci		desc->handle_irq = handle_fasteoi_nmi;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	gic_irq_set_prio(d, GICD_INT_NMI_PRI);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return 0;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic void gic_irq_nmi_teardown(struct irq_data *d)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct irq_desc *desc = irq_to_desc(d->irq);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (WARN_ON(!gic_supports_nmi()))
5258c2ecf20Sopenharmony_ci		return;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (gic_peek_irq(d, GICD_ISENABLER)) {
5288c2ecf20Sopenharmony_ci		pr_err("Cannot set NMI property of enabled IRQ %u\n", d->irq);
5298c2ecf20Sopenharmony_ci		return;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/*
5338c2ecf20Sopenharmony_ci	 * A secondary irq_chip should be in charge of LPI request,
5348c2ecf20Sopenharmony_ci	 * it should not be possible to get there
5358c2ecf20Sopenharmony_ci	 */
5368c2ecf20Sopenharmony_ci	if (WARN_ON(gic_irq(d) >= 8192))
5378c2ecf20Sopenharmony_ci		return;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	/* desc lock should already be held */
5408c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d)) {
5418c2ecf20Sopenharmony_ci		u32 idx = gic_get_ppi_index(d);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		/* Tearing down NMI, only switch handler for last NMI */
5448c2ecf20Sopenharmony_ci		if (refcount_dec_and_test(&ppi_nmi_refs[idx]))
5458c2ecf20Sopenharmony_ci			desc->handle_irq = handle_percpu_devid_irq;
5468c2ecf20Sopenharmony_ci	} else {
5478c2ecf20Sopenharmony_ci		desc->handle_irq = handle_fasteoi_irq;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	gic_irq_set_prio(d, GICD_INT_DEF_PRI);
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic void gic_eoi_irq(struct irq_data *d)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	gic_write_eoir(gic_irq(d));
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void gic_eoimode1_eoi_irq(struct irq_data *d)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	/*
5618c2ecf20Sopenharmony_ci	 * No need to deactivate an LPI, or an interrupt that
5628c2ecf20Sopenharmony_ci	 * is is getting forwarded to a vcpu.
5638c2ecf20Sopenharmony_ci	 */
5648c2ecf20Sopenharmony_ci	if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d))
5658c2ecf20Sopenharmony_ci		return;
5668c2ecf20Sopenharmony_ci	gic_write_dir(gic_irq(d));
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic int gic_set_type(struct irq_data *d, unsigned int type)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	enum gic_intid_range range;
5728c2ecf20Sopenharmony_ci	unsigned int irq = gic_irq(d);
5738c2ecf20Sopenharmony_ci	void (*rwp_wait)(void);
5748c2ecf20Sopenharmony_ci	void __iomem *base;
5758c2ecf20Sopenharmony_ci	u32 offset, index;
5768c2ecf20Sopenharmony_ci	int ret;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	range = get_intid_range(d);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/* Interrupt configuration for SGIs can't be changed */
5818c2ecf20Sopenharmony_ci	if (range == SGI_RANGE)
5828c2ecf20Sopenharmony_ci		return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* SPIs have restrictions on the supported types */
5858c2ecf20Sopenharmony_ci	if ((range == SPI_RANGE || range == ESPI_RANGE) &&
5868c2ecf20Sopenharmony_ci	    type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
5878c2ecf20Sopenharmony_ci		return -EINVAL;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d)) {
5908c2ecf20Sopenharmony_ci		base = gic_data_rdist_sgi_base();
5918c2ecf20Sopenharmony_ci		rwp_wait = gic_redist_wait_for_rwp;
5928c2ecf20Sopenharmony_ci	} else {
5938c2ecf20Sopenharmony_ci		base = gic_data.dist_base;
5948c2ecf20Sopenharmony_ci		rwp_wait = gic_dist_wait_for_rwp;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	offset = convert_offset_index(d, GICD_ICFGR, &index);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	ret = gic_configure_irq(index, type, base + offset, rwp_wait);
6008c2ecf20Sopenharmony_ci	if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
6018c2ecf20Sopenharmony_ci		/* Misconfigured PPIs are usually not fatal */
6028c2ecf20Sopenharmony_ci		pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq);
6038c2ecf20Sopenharmony_ci		ret = 0;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	return ret;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	if (get_intid_range(d) == SGI_RANGE)
6128c2ecf20Sopenharmony_ci		return -EINVAL;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (vcpu)
6158c2ecf20Sopenharmony_ci		irqd_set_forwarded_to_vcpu(d);
6168c2ecf20Sopenharmony_ci	else
6178c2ecf20Sopenharmony_ci		irqd_clr_forwarded_to_vcpu(d);
6188c2ecf20Sopenharmony_ci	return 0;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic u64 gic_mpidr_to_affinity(unsigned long mpidr)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	u64 aff;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	aff = ((u64)MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
6268c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
6278c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
6288c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	return aff;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic void gic_deactivate_unhandled(u32 irqnr)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key)) {
6368c2ecf20Sopenharmony_ci		if (irqnr < 8192)
6378c2ecf20Sopenharmony_ci			gic_write_dir(irqnr);
6388c2ecf20Sopenharmony_ci	} else {
6398c2ecf20Sopenharmony_ci		gic_write_eoir(irqnr);
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	bool irqs_enabled = interrupts_enabled(regs);
6468c2ecf20Sopenharmony_ci	int err;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (irqs_enabled)
6498c2ecf20Sopenharmony_ci		nmi_enter();
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
6528c2ecf20Sopenharmony_ci		gic_write_eoir(irqnr);
6538c2ecf20Sopenharmony_ci	/*
6548c2ecf20Sopenharmony_ci	 * Leave the PSR.I bit set to prevent other NMIs to be
6558c2ecf20Sopenharmony_ci	 * received while handling this one.
6568c2ecf20Sopenharmony_ci	 * PSR.I will be restored when we ERET to the
6578c2ecf20Sopenharmony_ci	 * interrupted context.
6588c2ecf20Sopenharmony_ci	 */
6598c2ecf20Sopenharmony_ci	err = handle_domain_nmi(gic_data.domain, irqnr, regs);
6608c2ecf20Sopenharmony_ci	if (err)
6618c2ecf20Sopenharmony_ci		gic_deactivate_unhandled(irqnr);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (irqs_enabled)
6648c2ecf20Sopenharmony_ci		nmi_exit();
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic u32 do_read_iar(struct pt_regs *regs)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	u32 iar;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	if (gic_supports_nmi() && unlikely(!interrupts_enabled(regs))) {
6728c2ecf20Sopenharmony_ci		u64 pmr;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci		/*
6758c2ecf20Sopenharmony_ci		 * We were in a context with IRQs disabled. However, the
6768c2ecf20Sopenharmony_ci		 * entry code has set PMR to a value that allows any
6778c2ecf20Sopenharmony_ci		 * interrupt to be acknowledged, and not just NMIs. This can
6788c2ecf20Sopenharmony_ci		 * lead to surprising effects if the NMI has been retired in
6798c2ecf20Sopenharmony_ci		 * the meantime, and that there is an IRQ pending. The IRQ
6808c2ecf20Sopenharmony_ci		 * would then be taken in NMI context, something that nobody
6818c2ecf20Sopenharmony_ci		 * wants to debug twice.
6828c2ecf20Sopenharmony_ci		 *
6838c2ecf20Sopenharmony_ci		 * Until we sort this, drop PMR again to a level that will
6848c2ecf20Sopenharmony_ci		 * actually only allow NMIs before reading IAR, and then
6858c2ecf20Sopenharmony_ci		 * restore it to what it was.
6868c2ecf20Sopenharmony_ci		 */
6878c2ecf20Sopenharmony_ci		pmr = gic_read_pmr();
6888c2ecf20Sopenharmony_ci		gic_pmr_mask_irqs();
6898c2ecf20Sopenharmony_ci		isb();
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		iar = gic_read_iar();
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		gic_write_pmr(pmr);
6948c2ecf20Sopenharmony_ci	} else {
6958c2ecf20Sopenharmony_ci		iar = gic_read_iar();
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return iar;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	u32 irqnr;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	irqnr = do_read_iar(regs);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Check for special IDs first */
7088c2ecf20Sopenharmony_ci	if ((irqnr >= 1020 && irqnr <= 1023))
7098c2ecf20Sopenharmony_ci		return;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (gic_supports_nmi() &&
7128c2ecf20Sopenharmony_ci	    unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI))) {
7138c2ecf20Sopenharmony_ci		gic_handle_nmi(irqnr, regs);
7148c2ecf20Sopenharmony_ci		return;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (gic_prio_masking_enabled()) {
7188c2ecf20Sopenharmony_ci		gic_pmr_mask_irqs();
7198c2ecf20Sopenharmony_ci		gic_arch_enable_irqs();
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
7238c2ecf20Sopenharmony_ci		gic_write_eoir(irqnr);
7248c2ecf20Sopenharmony_ci	else
7258c2ecf20Sopenharmony_ci		isb();
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (handle_domain_irq(gic_data.domain, irqnr, regs)) {
7288c2ecf20Sopenharmony_ci		WARN_ONCE(true, "Unexpected interrupt received!\n");
7298c2ecf20Sopenharmony_ci		gic_deactivate_unhandled(irqnr);
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic u32 gic_get_pribits(void)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	u32 pribits;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	pribits = gic_read_ctlr();
7388c2ecf20Sopenharmony_ci	pribits &= ICC_CTLR_EL1_PRI_BITS_MASK;
7398c2ecf20Sopenharmony_ci	pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT;
7408c2ecf20Sopenharmony_ci	pribits++;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return pribits;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic bool gic_has_group0(void)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	u32 val;
7488c2ecf20Sopenharmony_ci	u32 old_pmr;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	old_pmr = gic_read_pmr();
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	/*
7538c2ecf20Sopenharmony_ci	 * Let's find out if Group0 is under control of EL3 or not by
7548c2ecf20Sopenharmony_ci	 * setting the highest possible, non-zero priority in PMR.
7558c2ecf20Sopenharmony_ci	 *
7568c2ecf20Sopenharmony_ci	 * If SCR_EL3.FIQ is set, the priority gets shifted down in
7578c2ecf20Sopenharmony_ci	 * order for the CPU interface to set bit 7, and keep the
7588c2ecf20Sopenharmony_ci	 * actual priority in the non-secure range. In the process, it
7598c2ecf20Sopenharmony_ci	 * looses the least significant bit and the actual priority
7608c2ecf20Sopenharmony_ci	 * becomes 0x80. Reading it back returns 0, indicating that
7618c2ecf20Sopenharmony_ci	 * we're don't have access to Group0.
7628c2ecf20Sopenharmony_ci	 */
7638c2ecf20Sopenharmony_ci	gic_write_pmr(BIT(8 - gic_get_pribits()));
7648c2ecf20Sopenharmony_ci	val = gic_read_pmr();
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	gic_write_pmr(old_pmr);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	return val != 0;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic void __init gic_dist_init(void)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	unsigned int i;
7748c2ecf20Sopenharmony_ci	u64 affinity;
7758c2ecf20Sopenharmony_ci	void __iomem *base = gic_data.dist_base;
7768c2ecf20Sopenharmony_ci	u32 val;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* Disable the distributor */
7798c2ecf20Sopenharmony_ci	writel_relaxed(0, base + GICD_CTLR);
7808c2ecf20Sopenharmony_ci	gic_dist_wait_for_rwp();
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	/*
7838c2ecf20Sopenharmony_ci	 * Configure SPIs as non-secure Group-1. This will only matter
7848c2ecf20Sopenharmony_ci	 * if the GIC only has a single security state. This will not
7858c2ecf20Sopenharmony_ci	 * do the right thing if the kernel is running in secure mode,
7868c2ecf20Sopenharmony_ci	 * but that's not the intended use case anyway.
7878c2ecf20Sopenharmony_ci	 */
7888c2ecf20Sopenharmony_ci	for (i = 32; i < GIC_LINE_NR; i += 32)
7898c2ecf20Sopenharmony_ci		writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	/* Extended SPI range, not handled by the GICv2/GICv3 common code */
7928c2ecf20Sopenharmony_ci	for (i = 0; i < GIC_ESPI_NR; i += 32) {
7938c2ecf20Sopenharmony_ci		writel_relaxed(~0U, base + GICD_ICENABLERnE + i / 8);
7948c2ecf20Sopenharmony_ci		writel_relaxed(~0U, base + GICD_ICACTIVERnE + i / 8);
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	for (i = 0; i < GIC_ESPI_NR; i += 32)
7988c2ecf20Sopenharmony_ci		writel_relaxed(~0U, base + GICD_IGROUPRnE + i / 8);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	for (i = 0; i < GIC_ESPI_NR; i += 16)
8018c2ecf20Sopenharmony_ci		writel_relaxed(0, base + GICD_ICFGRnE + i / 4);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	for (i = 0; i < GIC_ESPI_NR; i += 4)
8048c2ecf20Sopenharmony_ci		writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	/* Now do the common stuff, and wait for the distributor to drain */
8078c2ecf20Sopenharmony_ci	gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1;
8108c2ecf20Sopenharmony_ci	if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) {
8118c2ecf20Sopenharmony_ci		pr_info("Enabling SGIs without active state\n");
8128c2ecf20Sopenharmony_ci		val |= GICD_CTLR_nASSGIreq;
8138c2ecf20Sopenharmony_ci	}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	/* Enable distributor with ARE, Group1 */
8168c2ecf20Sopenharmony_ci	writel_relaxed(val, base + GICD_CTLR);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/*
8198c2ecf20Sopenharmony_ci	 * Set all global interrupts to the boot CPU only. ARE must be
8208c2ecf20Sopenharmony_ci	 * enabled.
8218c2ecf20Sopenharmony_ci	 */
8228c2ecf20Sopenharmony_ci	affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
8238c2ecf20Sopenharmony_ci	for (i = 32; i < GIC_LINE_NR; i++)
8248c2ecf20Sopenharmony_ci		gic_write_irouter(affinity, base + GICD_IROUTER + i * 8);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	for (i = 0; i < GIC_ESPI_NR; i++)
8278c2ecf20Sopenharmony_ci		gic_write_irouter(affinity, base + GICD_IROUTERnE + i * 8);
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_cistatic int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *))
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	int ret = -ENODEV;
8338c2ecf20Sopenharmony_ci	int i;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	for (i = 0; i < gic_data.nr_redist_regions; i++) {
8368c2ecf20Sopenharmony_ci		void __iomem *ptr = gic_data.redist_regions[i].redist_base;
8378c2ecf20Sopenharmony_ci		u64 typer;
8388c2ecf20Sopenharmony_ci		u32 reg;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
8418c2ecf20Sopenharmony_ci		if (reg != GIC_PIDR2_ARCH_GICv3 &&
8428c2ecf20Sopenharmony_ci		    reg != GIC_PIDR2_ARCH_GICv4) { /* We're in trouble... */
8438c2ecf20Sopenharmony_ci			pr_warn("No redistributor present @%p\n", ptr);
8448c2ecf20Sopenharmony_ci			break;
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		do {
8488c2ecf20Sopenharmony_ci			typer = gic_read_typer(ptr + GICR_TYPER);
8498c2ecf20Sopenharmony_ci			ret = fn(gic_data.redist_regions + i, ptr);
8508c2ecf20Sopenharmony_ci			if (!ret)
8518c2ecf20Sopenharmony_ci				return 0;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci			if (gic_data.redist_regions[i].single_redist)
8548c2ecf20Sopenharmony_ci				break;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci			if (gic_data.redist_stride) {
8578c2ecf20Sopenharmony_ci				ptr += gic_data.redist_stride;
8588c2ecf20Sopenharmony_ci			} else {
8598c2ecf20Sopenharmony_ci				ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
8608c2ecf20Sopenharmony_ci				if (typer & GICR_TYPER_VLPIS)
8618c2ecf20Sopenharmony_ci					ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
8628c2ecf20Sopenharmony_ci			}
8638c2ecf20Sopenharmony_ci		} while (!(typer & GICR_TYPER_LAST));
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	return ret ? -ENODEV : 0;
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic int __gic_populate_rdist(struct redist_region *region, void __iomem *ptr)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	unsigned long mpidr = cpu_logical_map(smp_processor_id());
8728c2ecf20Sopenharmony_ci	u64 typer;
8738c2ecf20Sopenharmony_ci	u32 aff;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	/*
8768c2ecf20Sopenharmony_ci	 * Convert affinity to a 32bit value that can be matched to
8778c2ecf20Sopenharmony_ci	 * GICR_TYPER bits [63:32].
8788c2ecf20Sopenharmony_ci	 */
8798c2ecf20Sopenharmony_ci	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
8808c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
8818c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
8828c2ecf20Sopenharmony_ci	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	typer = gic_read_typer(ptr + GICR_TYPER);
8858c2ecf20Sopenharmony_ci	if ((typer >> 32) == aff) {
8868c2ecf20Sopenharmony_ci		u64 offset = ptr - region->redist_base;
8878c2ecf20Sopenharmony_ci		raw_spin_lock_init(&gic_data_rdist()->rd_lock);
8888c2ecf20Sopenharmony_ci		gic_data_rdist_rd_base() = ptr;
8898c2ecf20Sopenharmony_ci		gic_data_rdist()->phys_base = region->phys_base + offset;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci		pr_info("CPU%d: found redistributor %lx region %d:%pa\n",
8928c2ecf20Sopenharmony_ci			smp_processor_id(), mpidr,
8938c2ecf20Sopenharmony_ci			(int)(region - gic_data.redist_regions),
8948c2ecf20Sopenharmony_ci			&gic_data_rdist()->phys_base);
8958c2ecf20Sopenharmony_ci		return 0;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* Try next one */
8998c2ecf20Sopenharmony_ci	return 1;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic int gic_populate_rdist(void)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	if (gic_iterate_rdists(__gic_populate_rdist) == 0)
9058c2ecf20Sopenharmony_ci		return 0;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* We couldn't even deal with ourselves... */
9088c2ecf20Sopenharmony_ci	WARN(true, "CPU%d: mpidr %lx has no re-distributor!\n",
9098c2ecf20Sopenharmony_ci	     smp_processor_id(),
9108c2ecf20Sopenharmony_ci	     (unsigned long)cpu_logical_map(smp_processor_id()));
9118c2ecf20Sopenharmony_ci	return -ENODEV;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int __gic_update_rdist_properties(struct redist_region *region,
9158c2ecf20Sopenharmony_ci					 void __iomem *ptr)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	u64 typer = gic_read_typer(ptr + GICR_TYPER);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* Boot-time cleanip */
9208c2ecf20Sopenharmony_ci	if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) {
9218c2ecf20Sopenharmony_ci		u64 val;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		/* Deactivate any present vPE */
9248c2ecf20Sopenharmony_ci		val = gicr_read_vpendbaser(ptr + SZ_128K + GICR_VPENDBASER);
9258c2ecf20Sopenharmony_ci		if (val & GICR_VPENDBASER_Valid)
9268c2ecf20Sopenharmony_ci			gicr_write_vpendbaser(GICR_VPENDBASER_PendingLast,
9278c2ecf20Sopenharmony_ci					      ptr + SZ_128K + GICR_VPENDBASER);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci		/* Mark the VPE table as invalid */
9308c2ecf20Sopenharmony_ci		val = gicr_read_vpropbaser(ptr + SZ_128K + GICR_VPROPBASER);
9318c2ecf20Sopenharmony_ci		val &= ~GICR_VPROPBASER_4_1_VALID;
9328c2ecf20Sopenharmony_ci		gicr_write_vpropbaser(val, ptr + SZ_128K + GICR_VPROPBASER);
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	/* RVPEID implies some form of DirectLPI, no matter what the doc says... :-/ */
9388c2ecf20Sopenharmony_ci	gic_data.rdists.has_rvpeid &= !!(typer & GICR_TYPER_RVPEID);
9398c2ecf20Sopenharmony_ci	gic_data.rdists.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) |
9408c2ecf20Sopenharmony_ci					   gic_data.rdists.has_rvpeid);
9418c2ecf20Sopenharmony_ci	gic_data.rdists.has_vpend_valid_dirty &= !!(typer & GICR_TYPER_DIRTY);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* Detect non-sensical configurations */
9448c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(gic_data.rdists.has_rvpeid && !gic_data.rdists.has_vlpis)) {
9458c2ecf20Sopenharmony_ci		gic_data.rdists.has_direct_lpi = false;
9468c2ecf20Sopenharmony_ci		gic_data.rdists.has_vlpis = false;
9478c2ecf20Sopenharmony_ci		gic_data.rdists.has_rvpeid = false;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return 1;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic void gic_update_rdist_properties(void)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	gic_data.ppi_nr = UINT_MAX;
9588c2ecf20Sopenharmony_ci	gic_iterate_rdists(__gic_update_rdist_properties);
9598c2ecf20Sopenharmony_ci	if (WARN_ON(gic_data.ppi_nr == UINT_MAX))
9608c2ecf20Sopenharmony_ci		gic_data.ppi_nr = 0;
9618c2ecf20Sopenharmony_ci	pr_info("%d PPIs implemented\n", gic_data.ppi_nr);
9628c2ecf20Sopenharmony_ci	if (gic_data.rdists.has_vlpis)
9638c2ecf20Sopenharmony_ci		pr_info("GICv4 features: %s%s%s\n",
9648c2ecf20Sopenharmony_ci			gic_data.rdists.has_direct_lpi ? "DirectLPI " : "",
9658c2ecf20Sopenharmony_ci			gic_data.rdists.has_rvpeid ? "RVPEID " : "",
9668c2ecf20Sopenharmony_ci			gic_data.rdists.has_vpend_valid_dirty ? "Valid+Dirty " : "");
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci/* Check whether it's single security state view */
9708c2ecf20Sopenharmony_cistatic inline bool gic_dist_security_disabled(void)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cistatic void gic_cpu_sys_reg_init(void)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	int i, cpu = smp_processor_id();
9788c2ecf20Sopenharmony_ci	u64 mpidr = cpu_logical_map(cpu);
9798c2ecf20Sopenharmony_ci	u64 need_rss = MPIDR_RS(mpidr);
9808c2ecf20Sopenharmony_ci	bool group0;
9818c2ecf20Sopenharmony_ci	u32 pribits;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	/*
9848c2ecf20Sopenharmony_ci	 * Need to check that the SRE bit has actually been set. If
9858c2ecf20Sopenharmony_ci	 * not, it means that SRE is disabled at EL2. We're going to
9868c2ecf20Sopenharmony_ci	 * die painfully, and there is nothing we can do about it.
9878c2ecf20Sopenharmony_ci	 *
9888c2ecf20Sopenharmony_ci	 * Kindly inform the luser.
9898c2ecf20Sopenharmony_ci	 */
9908c2ecf20Sopenharmony_ci	if (!gic_enable_sre())
9918c2ecf20Sopenharmony_ci		pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	pribits = gic_get_pribits();
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	group0 = gic_has_group0();
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	/* Set priority mask register */
9988c2ecf20Sopenharmony_ci	if (!gic_prio_masking_enabled()) {
9998c2ecf20Sopenharmony_ci		write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
10008c2ecf20Sopenharmony_ci	} else if (gic_supports_nmi()) {
10018c2ecf20Sopenharmony_ci		/*
10028c2ecf20Sopenharmony_ci		 * Mismatch configuration with boot CPU, the system is likely
10038c2ecf20Sopenharmony_ci		 * to die as interrupt masking will not work properly on all
10048c2ecf20Sopenharmony_ci		 * CPUs
10058c2ecf20Sopenharmony_ci		 *
10068c2ecf20Sopenharmony_ci		 * The boot CPU calls this function before enabling NMI support,
10078c2ecf20Sopenharmony_ci		 * and as a result we'll never see this warning in the boot path
10088c2ecf20Sopenharmony_ci		 * for that CPU.
10098c2ecf20Sopenharmony_ci		 */
10108c2ecf20Sopenharmony_ci		if (static_branch_unlikely(&gic_nonsecure_priorities))
10118c2ecf20Sopenharmony_ci			WARN_ON(!group0 || gic_dist_security_disabled());
10128c2ecf20Sopenharmony_ci		else
10138c2ecf20Sopenharmony_ci			WARN_ON(group0 && !gic_dist_security_disabled());
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	/*
10178c2ecf20Sopenharmony_ci	 * Some firmwares hand over to the kernel with the BPR changed from
10188c2ecf20Sopenharmony_ci	 * its reset value (and with a value large enough to prevent
10198c2ecf20Sopenharmony_ci	 * any pre-emptive interrupts from working at all). Writing a zero
10208c2ecf20Sopenharmony_ci	 * to BPR restores is reset value.
10218c2ecf20Sopenharmony_ci	 */
10228c2ecf20Sopenharmony_ci	gic_write_bpr1(0);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key)) {
10258c2ecf20Sopenharmony_ci		/* EOI drops priority only (mode 1) */
10268c2ecf20Sopenharmony_ci		gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);
10278c2ecf20Sopenharmony_ci	} else {
10288c2ecf20Sopenharmony_ci		/* EOI deactivates interrupt too (mode 0) */
10298c2ecf20Sopenharmony_ci		gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	/* Always whack Group0 before Group1 */
10338c2ecf20Sopenharmony_ci	if (group0) {
10348c2ecf20Sopenharmony_ci		switch(pribits) {
10358c2ecf20Sopenharmony_ci		case 8:
10368c2ecf20Sopenharmony_ci		case 7:
10378c2ecf20Sopenharmony_ci			write_gicreg(0, ICC_AP0R3_EL1);
10388c2ecf20Sopenharmony_ci			write_gicreg(0, ICC_AP0R2_EL1);
10398c2ecf20Sopenharmony_ci			fallthrough;
10408c2ecf20Sopenharmony_ci		case 6:
10418c2ecf20Sopenharmony_ci			write_gicreg(0, ICC_AP0R1_EL1);
10428c2ecf20Sopenharmony_ci			fallthrough;
10438c2ecf20Sopenharmony_ci		case 5:
10448c2ecf20Sopenharmony_ci		case 4:
10458c2ecf20Sopenharmony_ci			write_gicreg(0, ICC_AP0R0_EL1);
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci		isb();
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	switch(pribits) {
10528c2ecf20Sopenharmony_ci	case 8:
10538c2ecf20Sopenharmony_ci	case 7:
10548c2ecf20Sopenharmony_ci		write_gicreg(0, ICC_AP1R3_EL1);
10558c2ecf20Sopenharmony_ci		write_gicreg(0, ICC_AP1R2_EL1);
10568c2ecf20Sopenharmony_ci		fallthrough;
10578c2ecf20Sopenharmony_ci	case 6:
10588c2ecf20Sopenharmony_ci		write_gicreg(0, ICC_AP1R1_EL1);
10598c2ecf20Sopenharmony_ci		fallthrough;
10608c2ecf20Sopenharmony_ci	case 5:
10618c2ecf20Sopenharmony_ci	case 4:
10628c2ecf20Sopenharmony_ci		write_gicreg(0, ICC_AP1R0_EL1);
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	isb();
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	/* ... and let's hit the road... */
10688c2ecf20Sopenharmony_ci	gic_write_grpen1(1);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	/* Keep the RSS capability status in per_cpu variable */
10718c2ecf20Sopenharmony_ci	per_cpu(has_rss, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	/* Check all the CPUs have capable of sending SGIs to other CPUs */
10748c2ecf20Sopenharmony_ci	for_each_online_cpu(i) {
10758c2ecf20Sopenharmony_ci		bool have_rss = per_cpu(has_rss, i) && per_cpu(has_rss, cpu);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		need_rss |= MPIDR_RS(cpu_logical_map(i));
10788c2ecf20Sopenharmony_ci		if (need_rss && (!have_rss))
10798c2ecf20Sopenharmony_ci			pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n",
10808c2ecf20Sopenharmony_ci				cpu, (unsigned long)mpidr,
10818c2ecf20Sopenharmony_ci				i, (unsigned long)cpu_logical_map(i));
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/**
10858c2ecf20Sopenharmony_ci	 * GIC spec says, when ICC_CTLR_EL1.RSS==1 and GICD_TYPER.RSS==0,
10868c2ecf20Sopenharmony_ci	 * writing ICC_ASGI1R_EL1 register with RS != 0 is a CONSTRAINED
10878c2ecf20Sopenharmony_ci	 * UNPREDICTABLE choice of :
10888c2ecf20Sopenharmony_ci	 *   - The write is ignored.
10898c2ecf20Sopenharmony_ci	 *   - The RS field is treated as 0.
10908c2ecf20Sopenharmony_ci	 */
10918c2ecf20Sopenharmony_ci	if (need_rss && (!gic_data.has_rss))
10928c2ecf20Sopenharmony_ci		pr_crit_once("RSS is required but GICD doesn't support it\n");
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic bool gicv3_nolpi;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_cistatic int __init gicv3_nolpi_cfg(char *buf)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	return strtobool(buf, &gicv3_nolpi);
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ciearly_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic int gic_dist_supports_lpis(void)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	return (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) &&
11068c2ecf20Sopenharmony_ci		!!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) &&
11078c2ecf20Sopenharmony_ci		!gicv3_nolpi);
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic void gic_cpu_init(void)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	void __iomem *rbase;
11138c2ecf20Sopenharmony_ci	int i;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	/* Register ourselves with the rest of the world */
11168c2ecf20Sopenharmony_ci	if (gic_populate_rdist())
11178c2ecf20Sopenharmony_ci		return;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	gic_enable_redist(true);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) &&
11228c2ecf20Sopenharmony_ci	     !(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange),
11238c2ecf20Sopenharmony_ci	     "Distributor has extended ranges, but CPU%d doesn't\n",
11248c2ecf20Sopenharmony_ci	     smp_processor_id());
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	rbase = gic_data_rdist_sgi_base();
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/* Configure SGIs/PPIs as non-secure Group-1 */
11298c2ecf20Sopenharmony_ci	for (i = 0; i < gic_data.ppi_nr + 16; i += 32)
11308c2ecf20Sopenharmony_ci		writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	/* initialise system registers */
11358c2ecf20Sopenharmony_ci	gic_cpu_sys_reg_init();
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci#define MPIDR_TO_SGI_RS(mpidr)	(MPIDR_RS(mpidr) << ICC_SGI1R_RS_SHIFT)
11418c2ecf20Sopenharmony_ci#define MPIDR_TO_SGI_CLUSTER_ID(mpidr)	((mpidr) & ~0xFUL)
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_cistatic int gic_starting_cpu(unsigned int cpu)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	gic_cpu_init();
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (gic_dist_supports_lpis())
11488c2ecf20Sopenharmony_ci		its_cpu_init();
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	return 0;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
11548c2ecf20Sopenharmony_ci				   unsigned long cluster_id)
11558c2ecf20Sopenharmony_ci{
11568c2ecf20Sopenharmony_ci	int next_cpu, cpu = *base_cpu;
11578c2ecf20Sopenharmony_ci	unsigned long mpidr = cpu_logical_map(cpu);
11588c2ecf20Sopenharmony_ci	u16 tlist = 0;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	while (cpu < nr_cpu_ids) {
11618c2ecf20Sopenharmony_ci		tlist |= 1 << (mpidr & 0xf);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		next_cpu = cpumask_next(cpu, mask);
11648c2ecf20Sopenharmony_ci		if (next_cpu >= nr_cpu_ids)
11658c2ecf20Sopenharmony_ci			goto out;
11668c2ecf20Sopenharmony_ci		cpu = next_cpu;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		mpidr = cpu_logical_map(cpu);
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci		if (cluster_id != MPIDR_TO_SGI_CLUSTER_ID(mpidr)) {
11718c2ecf20Sopenharmony_ci			cpu--;
11728c2ecf20Sopenharmony_ci			goto out;
11738c2ecf20Sopenharmony_ci		}
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ciout:
11768c2ecf20Sopenharmony_ci	*base_cpu = cpu;
11778c2ecf20Sopenharmony_ci	return tlist;
11788c2ecf20Sopenharmony_ci}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
11818c2ecf20Sopenharmony_ci	(MPIDR_AFFINITY_LEVEL(cluster_id, level) \
11828c2ecf20Sopenharmony_ci		<< ICC_SGI1R_AFFINITY_## level ##_SHIFT)
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	u64 val;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	val = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
11898c2ecf20Sopenharmony_ci	       MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
11908c2ecf20Sopenharmony_ci	       irq << ICC_SGI1R_SGI_ID_SHIFT		|
11918c2ecf20Sopenharmony_ci	       MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
11928c2ecf20Sopenharmony_ci	       MPIDR_TO_SGI_RS(cluster_id)		|
11938c2ecf20Sopenharmony_ci	       tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
11968c2ecf20Sopenharmony_ci	gic_write_sgi1r(val);
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	int cpu;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (WARN_ON(d->hwirq >= 16))
12048c2ecf20Sopenharmony_ci		return;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	/*
12078c2ecf20Sopenharmony_ci	 * Ensure that stores to Normal memory are visible to the
12088c2ecf20Sopenharmony_ci	 * other CPUs before issuing the IPI.
12098c2ecf20Sopenharmony_ci	 */
12108c2ecf20Sopenharmony_ci	wmb();
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	for_each_cpu(cpu, mask) {
12138c2ecf20Sopenharmony_ci		u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu));
12148c2ecf20Sopenharmony_ci		u16 tlist;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci		tlist = gic_compute_target_list(&cpu, mask, cluster_id);
12178c2ecf20Sopenharmony_ci		gic_send_sgi(cluster_id, tlist, d->hwirq);
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
12218c2ecf20Sopenharmony_ci	isb();
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_cistatic void __init gic_smp_init(void)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct irq_fwspec sgi_fwspec = {
12278c2ecf20Sopenharmony_ci		.fwnode		= gic_data.fwnode,
12288c2ecf20Sopenharmony_ci		.param_count	= 1,
12298c2ecf20Sopenharmony_ci	};
12308c2ecf20Sopenharmony_ci	int base_sgi;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
12338c2ecf20Sopenharmony_ci				  "irqchip/arm/gicv3:starting",
12348c2ecf20Sopenharmony_ci				  gic_starting_cpu, NULL);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	/* Register all 8 non-secure SGIs */
12378c2ecf20Sopenharmony_ci	base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8,
12388c2ecf20Sopenharmony_ci					   NUMA_NO_NODE, &sgi_fwspec,
12398c2ecf20Sopenharmony_ci					   false, NULL);
12408c2ecf20Sopenharmony_ci	if (WARN_ON(base_sgi <= 0))
12418c2ecf20Sopenharmony_ci		return;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	set_smp_ipi_range(base_sgi, 8);
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
12478c2ecf20Sopenharmony_ci			    bool force)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	unsigned int cpu;
12508c2ecf20Sopenharmony_ci	u32 offset, index;
12518c2ecf20Sopenharmony_ci	void __iomem *reg;
12528c2ecf20Sopenharmony_ci	int enabled;
12538c2ecf20Sopenharmony_ci	u64 val;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	if (force)
12568c2ecf20Sopenharmony_ci		cpu = cpumask_first(mask_val);
12578c2ecf20Sopenharmony_ci	else
12588c2ecf20Sopenharmony_ci		cpu = cpumask_any_and(mask_val, cpu_online_mask);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	if (cpu >= nr_cpu_ids)
12618c2ecf20Sopenharmony_ci		return -EINVAL;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	if (gic_irq_in_rdist(d))
12648c2ecf20Sopenharmony_ci		return -EINVAL;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* If interrupt was enabled, disable it first */
12678c2ecf20Sopenharmony_ci	enabled = gic_peek_irq(d, GICD_ISENABLER);
12688c2ecf20Sopenharmony_ci	if (enabled)
12698c2ecf20Sopenharmony_ci		gic_mask_irq(d);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	offset = convert_offset_index(d, GICD_IROUTER, &index);
12728c2ecf20Sopenharmony_ci	reg = gic_dist_base(d) + offset + (index * 8);
12738c2ecf20Sopenharmony_ci	val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	gic_write_irouter(val, reg);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	/*
12788c2ecf20Sopenharmony_ci	 * If the interrupt was enabled, enabled it again. Otherwise,
12798c2ecf20Sopenharmony_ci	 * just wait for the distributor to have digested our changes.
12808c2ecf20Sopenharmony_ci	 */
12818c2ecf20Sopenharmony_ci	if (enabled)
12828c2ecf20Sopenharmony_ci		gic_unmask_irq(d);
12838c2ecf20Sopenharmony_ci	else
12848c2ecf20Sopenharmony_ci		gic_dist_wait_for_rwp();
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	irq_data_update_effective_affinity(d, cpumask_of(cpu));
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	return IRQ_SET_MASK_OK_DONE;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci#else
12918c2ecf20Sopenharmony_ci#define gic_set_affinity	NULL
12928c2ecf20Sopenharmony_ci#define gic_ipi_send_mask	NULL
12938c2ecf20Sopenharmony_ci#define gic_smp_init()		do { } while(0)
12948c2ecf20Sopenharmony_ci#endif
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_cistatic int gic_retrigger(struct irq_data *data)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
12998c2ecf20Sopenharmony_ci}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_PM
13028c2ecf20Sopenharmony_cistatic int gic_cpu_pm_notifier(struct notifier_block *self,
13038c2ecf20Sopenharmony_ci			       unsigned long cmd, void *v)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	if (cmd == CPU_PM_EXIT) {
13068c2ecf20Sopenharmony_ci		if (gic_dist_security_disabled())
13078c2ecf20Sopenharmony_ci			gic_enable_redist(true);
13088c2ecf20Sopenharmony_ci		gic_cpu_sys_reg_init();
13098c2ecf20Sopenharmony_ci	} else if (cmd == CPU_PM_ENTER && gic_dist_security_disabled()) {
13108c2ecf20Sopenharmony_ci		gic_write_grpen1(0);
13118c2ecf20Sopenharmony_ci		gic_enable_redist(false);
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci	return NOTIFY_OK;
13148c2ecf20Sopenharmony_ci}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_cistatic struct notifier_block gic_cpu_pm_notifier_block = {
13178c2ecf20Sopenharmony_ci	.notifier_call = gic_cpu_pm_notifier,
13188c2ecf20Sopenharmony_ci};
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_cistatic void gic_cpu_pm_init(void)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci#else
13268c2ecf20Sopenharmony_cistatic inline void gic_cpu_pm_init(void) { }
13278c2ecf20Sopenharmony_ci#endif /* CONFIG_CPU_PM */
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_cistatic struct irq_chip gic_chip = {
13308c2ecf20Sopenharmony_ci	.name			= "GICv3",
13318c2ecf20Sopenharmony_ci	.irq_mask		= gic_mask_irq,
13328c2ecf20Sopenharmony_ci	.irq_unmask		= gic_unmask_irq,
13338c2ecf20Sopenharmony_ci	.irq_eoi		= gic_eoi_irq,
13348c2ecf20Sopenharmony_ci	.irq_set_type		= gic_set_type,
13358c2ecf20Sopenharmony_ci	.irq_set_affinity	= gic_set_affinity,
13368c2ecf20Sopenharmony_ci	.irq_retrigger          = gic_retrigger,
13378c2ecf20Sopenharmony_ci	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
13388c2ecf20Sopenharmony_ci	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
13398c2ecf20Sopenharmony_ci	.irq_nmi_setup		= gic_irq_nmi_setup,
13408c2ecf20Sopenharmony_ci	.irq_nmi_teardown	= gic_irq_nmi_teardown,
13418c2ecf20Sopenharmony_ci	.ipi_send_mask		= gic_ipi_send_mask,
13428c2ecf20Sopenharmony_ci	.flags			= IRQCHIP_SET_TYPE_MASKED |
13438c2ecf20Sopenharmony_ci				  IRQCHIP_SKIP_SET_WAKE |
13448c2ecf20Sopenharmony_ci				  IRQCHIP_MASK_ON_SUSPEND,
13458c2ecf20Sopenharmony_ci};
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic struct irq_chip gic_eoimode1_chip = {
13488c2ecf20Sopenharmony_ci	.name			= "GICv3",
13498c2ecf20Sopenharmony_ci	.irq_mask		= gic_eoimode1_mask_irq,
13508c2ecf20Sopenharmony_ci	.irq_unmask		= gic_unmask_irq,
13518c2ecf20Sopenharmony_ci	.irq_eoi		= gic_eoimode1_eoi_irq,
13528c2ecf20Sopenharmony_ci	.irq_set_type		= gic_set_type,
13538c2ecf20Sopenharmony_ci	.irq_set_affinity	= gic_set_affinity,
13548c2ecf20Sopenharmony_ci	.irq_retrigger          = gic_retrigger,
13558c2ecf20Sopenharmony_ci	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
13568c2ecf20Sopenharmony_ci	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
13578c2ecf20Sopenharmony_ci	.irq_set_vcpu_affinity	= gic_irq_set_vcpu_affinity,
13588c2ecf20Sopenharmony_ci	.irq_nmi_setup		= gic_irq_nmi_setup,
13598c2ecf20Sopenharmony_ci	.irq_nmi_teardown	= gic_irq_nmi_teardown,
13608c2ecf20Sopenharmony_ci	.ipi_send_mask		= gic_ipi_send_mask,
13618c2ecf20Sopenharmony_ci	.flags			= IRQCHIP_SET_TYPE_MASKED |
13628c2ecf20Sopenharmony_ci				  IRQCHIP_SKIP_SET_WAKE |
13638c2ecf20Sopenharmony_ci				  IRQCHIP_MASK_ON_SUSPEND,
13648c2ecf20Sopenharmony_ci};
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
13678c2ecf20Sopenharmony_ci			      irq_hw_number_t hw)
13688c2ecf20Sopenharmony_ci{
13698c2ecf20Sopenharmony_ci	struct irq_chip *chip = &gic_chip;
13708c2ecf20Sopenharmony_ci	struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
13738c2ecf20Sopenharmony_ci		chip = &gic_eoimode1_chip;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	switch (__get_intid_range(hw)) {
13768c2ecf20Sopenharmony_ci	case SGI_RANGE:
13778c2ecf20Sopenharmony_ci		irq_set_percpu_devid(irq);
13788c2ecf20Sopenharmony_ci		irq_domain_set_info(d, irq, hw, chip, d->host_data,
13798c2ecf20Sopenharmony_ci				    handle_percpu_devid_fasteoi_ipi,
13808c2ecf20Sopenharmony_ci				    NULL, NULL);
13818c2ecf20Sopenharmony_ci		break;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	case PPI_RANGE:
13848c2ecf20Sopenharmony_ci	case EPPI_RANGE:
13858c2ecf20Sopenharmony_ci		irq_set_percpu_devid(irq);
13868c2ecf20Sopenharmony_ci		irq_domain_set_info(d, irq, hw, chip, d->host_data,
13878c2ecf20Sopenharmony_ci				    handle_percpu_devid_irq, NULL, NULL);
13888c2ecf20Sopenharmony_ci		break;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	case SPI_RANGE:
13918c2ecf20Sopenharmony_ci	case ESPI_RANGE:
13928c2ecf20Sopenharmony_ci		irq_domain_set_info(d, irq, hw, chip, d->host_data,
13938c2ecf20Sopenharmony_ci				    handle_fasteoi_irq, NULL, NULL);
13948c2ecf20Sopenharmony_ci		irq_set_probe(irq);
13958c2ecf20Sopenharmony_ci		irqd_set_single_target(irqd);
13968c2ecf20Sopenharmony_ci		break;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	case LPI_RANGE:
13998c2ecf20Sopenharmony_ci		if (!gic_dist_supports_lpis())
14008c2ecf20Sopenharmony_ci			return -EPERM;
14018c2ecf20Sopenharmony_ci		irq_domain_set_info(d, irq, hw, chip, d->host_data,
14028c2ecf20Sopenharmony_ci				    handle_fasteoi_irq, NULL, NULL);
14038c2ecf20Sopenharmony_ci		break;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	default:
14068c2ecf20Sopenharmony_ci		return -EPERM;
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	/* Prevents SW retriggers which mess up the ACK/EOI ordering */
14108c2ecf20Sopenharmony_ci	irqd_set_handle_enforce_irqctx(irqd);
14118c2ecf20Sopenharmony_ci	return 0;
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cistatic int gic_irq_domain_translate(struct irq_domain *d,
14158c2ecf20Sopenharmony_ci				    struct irq_fwspec *fwspec,
14168c2ecf20Sopenharmony_ci				    unsigned long *hwirq,
14178c2ecf20Sopenharmony_ci				    unsigned int *type)
14188c2ecf20Sopenharmony_ci{
14198c2ecf20Sopenharmony_ci	if (fwspec->param_count == 1 && fwspec->param[0] < 16) {
14208c2ecf20Sopenharmony_ci		*hwirq = fwspec->param[0];
14218c2ecf20Sopenharmony_ci		*type = IRQ_TYPE_EDGE_RISING;
14228c2ecf20Sopenharmony_ci		return 0;
14238c2ecf20Sopenharmony_ci	}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	if (is_of_node(fwspec->fwnode)) {
14268c2ecf20Sopenharmony_ci		if (fwspec->param_count < 3)
14278c2ecf20Sopenharmony_ci			return -EINVAL;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		switch (fwspec->param[0]) {
14308c2ecf20Sopenharmony_ci		case 0:			/* SPI */
14318c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1] + 32;
14328c2ecf20Sopenharmony_ci			break;
14338c2ecf20Sopenharmony_ci		case 1:			/* PPI */
14348c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1] + 16;
14358c2ecf20Sopenharmony_ci			break;
14368c2ecf20Sopenharmony_ci		case 2:			/* ESPI */
14378c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1] + ESPI_BASE_INTID;
14388c2ecf20Sopenharmony_ci			break;
14398c2ecf20Sopenharmony_ci		case 3:			/* EPPI */
14408c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1] + EPPI_BASE_INTID;
14418c2ecf20Sopenharmony_ci			break;
14428c2ecf20Sopenharmony_ci		case GIC_IRQ_TYPE_LPI:	/* LPI */
14438c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1];
14448c2ecf20Sopenharmony_ci			break;
14458c2ecf20Sopenharmony_ci		case GIC_IRQ_TYPE_PARTITION:
14468c2ecf20Sopenharmony_ci			*hwirq = fwspec->param[1];
14478c2ecf20Sopenharmony_ci			if (fwspec->param[1] >= 16)
14488c2ecf20Sopenharmony_ci				*hwirq += EPPI_BASE_INTID - 16;
14498c2ecf20Sopenharmony_ci			else
14508c2ecf20Sopenharmony_ci				*hwirq += 16;
14518c2ecf20Sopenharmony_ci			break;
14528c2ecf20Sopenharmony_ci		default:
14538c2ecf20Sopenharmony_ci			return -EINVAL;
14548c2ecf20Sopenharmony_ci		}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci		/*
14598c2ecf20Sopenharmony_ci		 * Make it clear that broken DTs are... broken.
14608c2ecf20Sopenharmony_ci		 * Partitioned PPIs are an unfortunate exception.
14618c2ecf20Sopenharmony_ci		 */
14628c2ecf20Sopenharmony_ci		WARN_ON(*type == IRQ_TYPE_NONE &&
14638c2ecf20Sopenharmony_ci			fwspec->param[0] != GIC_IRQ_TYPE_PARTITION);
14648c2ecf20Sopenharmony_ci		return 0;
14658c2ecf20Sopenharmony_ci	}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	if (is_fwnode_irqchip(fwspec->fwnode)) {
14688c2ecf20Sopenharmony_ci		if(fwspec->param_count != 2)
14698c2ecf20Sopenharmony_ci			return -EINVAL;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci		if (fwspec->param[0] < 16) {
14728c2ecf20Sopenharmony_ci			pr_err(FW_BUG "Illegal GSI%d translation request\n",
14738c2ecf20Sopenharmony_ci			       fwspec->param[0]);
14748c2ecf20Sopenharmony_ci			return -EINVAL;
14758c2ecf20Sopenharmony_ci		}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci		*hwirq = fwspec->param[0];
14788c2ecf20Sopenharmony_ci		*type = fwspec->param[1];
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		WARN_ON(*type == IRQ_TYPE_NONE);
14818c2ecf20Sopenharmony_ci		return 0;
14828c2ecf20Sopenharmony_ci	}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return -EINVAL;
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_cistatic int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
14888c2ecf20Sopenharmony_ci				unsigned int nr_irqs, void *arg)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	int i, ret;
14918c2ecf20Sopenharmony_ci	irq_hw_number_t hwirq;
14928c2ecf20Sopenharmony_ci	unsigned int type = IRQ_TYPE_NONE;
14938c2ecf20Sopenharmony_ci	struct irq_fwspec *fwspec = arg;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);
14968c2ecf20Sopenharmony_ci	if (ret)
14978c2ecf20Sopenharmony_ci		return ret;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	for (i = 0; i < nr_irqs; i++) {
15008c2ecf20Sopenharmony_ci		ret = gic_irq_domain_map(domain, virq + i, hwirq + i);
15018c2ecf20Sopenharmony_ci		if (ret)
15028c2ecf20Sopenharmony_ci			return ret;
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	return 0;
15068c2ecf20Sopenharmony_ci}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_cistatic void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
15098c2ecf20Sopenharmony_ci				unsigned int nr_irqs)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	int i;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	for (i = 0; i < nr_irqs; i++) {
15148c2ecf20Sopenharmony_ci		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
15158c2ecf20Sopenharmony_ci		irq_set_handler(virq + i, NULL);
15168c2ecf20Sopenharmony_ci		irq_domain_reset_irq_data(d);
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_cistatic int gic_irq_domain_select(struct irq_domain *d,
15218c2ecf20Sopenharmony_ci				 struct irq_fwspec *fwspec,
15228c2ecf20Sopenharmony_ci				 enum irq_domain_bus_token bus_token)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	/* Not for us */
15258c2ecf20Sopenharmony_ci        if (fwspec->fwnode != d->fwnode)
15268c2ecf20Sopenharmony_ci		return 0;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/* If this is not DT, then we have a single domain */
15298c2ecf20Sopenharmony_ci	if (!is_of_node(fwspec->fwnode))
15308c2ecf20Sopenharmony_ci		return 1;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	/*
15338c2ecf20Sopenharmony_ci	 * If this is a PPI and we have a 4th (non-null) parameter,
15348c2ecf20Sopenharmony_ci	 * then we need to match the partition domain.
15358c2ecf20Sopenharmony_ci	 */
15368c2ecf20Sopenharmony_ci	if (fwspec->param_count >= 4 &&
15378c2ecf20Sopenharmony_ci	    fwspec->param[0] == 1 && fwspec->param[3] != 0 &&
15388c2ecf20Sopenharmony_ci	    gic_data.ppi_descs)
15398c2ecf20Sopenharmony_ci		return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return d == gic_data.domain;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic const struct irq_domain_ops gic_irq_domain_ops = {
15458c2ecf20Sopenharmony_ci	.translate = gic_irq_domain_translate,
15468c2ecf20Sopenharmony_ci	.alloc = gic_irq_domain_alloc,
15478c2ecf20Sopenharmony_ci	.free = gic_irq_domain_free,
15488c2ecf20Sopenharmony_ci	.select = gic_irq_domain_select,
15498c2ecf20Sopenharmony_ci};
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_cistatic int partition_domain_translate(struct irq_domain *d,
15528c2ecf20Sopenharmony_ci				      struct irq_fwspec *fwspec,
15538c2ecf20Sopenharmony_ci				      unsigned long *hwirq,
15548c2ecf20Sopenharmony_ci				      unsigned int *type)
15558c2ecf20Sopenharmony_ci{
15568c2ecf20Sopenharmony_ci	struct device_node *np;
15578c2ecf20Sopenharmony_ci	int ret;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	if (!gic_data.ppi_descs)
15608c2ecf20Sopenharmony_ci		return -ENOMEM;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	np = of_find_node_by_phandle(fwspec->param[3]);
15638c2ecf20Sopenharmony_ci	if (WARN_ON(!np))
15648c2ecf20Sopenharmony_ci		return -EINVAL;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	ret = partition_translate_id(gic_data.ppi_descs[fwspec->param[1]],
15678c2ecf20Sopenharmony_ci				     of_node_to_fwnode(np));
15688c2ecf20Sopenharmony_ci	if (ret < 0)
15698c2ecf20Sopenharmony_ci		return ret;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	*hwirq = ret;
15728c2ecf20Sopenharmony_ci	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	return 0;
15758c2ecf20Sopenharmony_ci}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_cistatic const struct irq_domain_ops partition_domain_ops = {
15788c2ecf20Sopenharmony_ci	.translate = partition_domain_translate,
15798c2ecf20Sopenharmony_ci	.select = gic_irq_domain_select,
15808c2ecf20Sopenharmony_ci};
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_cistatic bool gic_enable_quirk_msm8996(void *data)
15838c2ecf20Sopenharmony_ci{
15848c2ecf20Sopenharmony_ci	struct gic_chip_data *d = data;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	d->flags |= FLAGS_WORKAROUND_GICR_WAKER_MSM8996;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	return true;
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic bool gic_enable_quirk_mtk_gicr(void *data)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	struct gic_chip_data *d = data;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	d->flags |= FLAGS_WORKAROUND_MTK_GICR_SAVE;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	return true;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic bool gic_enable_quirk_cavium_38539(void *data)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct gic_chip_data *d = data;
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	d->flags |= FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	return true;
16078c2ecf20Sopenharmony_ci}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_cistatic bool gic_enable_quirk_hip06_07(void *data)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	struct gic_chip_data *d = data;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	/*
16148c2ecf20Sopenharmony_ci	 * HIP06 GICD_IIDR clashes with GIC-600 product number (despite
16158c2ecf20Sopenharmony_ci	 * not being an actual ARM implementation). The saving grace is
16168c2ecf20Sopenharmony_ci	 * that GIC-600 doesn't have ESPI, so nothing to do in that case.
16178c2ecf20Sopenharmony_ci	 * HIP07 doesn't even have a proper IIDR, and still pretends to
16188c2ecf20Sopenharmony_ci	 * have ESPI. In both cases, put them right.
16198c2ecf20Sopenharmony_ci	 */
16208c2ecf20Sopenharmony_ci	if (d->rdists.gicd_typer & GICD_TYPER_ESPI) {
16218c2ecf20Sopenharmony_ci		/* Zero both ESPI and the RES0 field next to it... */
16228c2ecf20Sopenharmony_ci		d->rdists.gicd_typer &= ~GENMASK(9, 8);
16238c2ecf20Sopenharmony_ci		return true;
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	return false;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic const struct gic_quirk gic_quirks[] = {
16308c2ecf20Sopenharmony_ci	{
16318c2ecf20Sopenharmony_ci		.desc	= "GICv3: Qualcomm MSM8996 broken firmware",
16328c2ecf20Sopenharmony_ci		.compatible = "qcom,msm8996-gic-v3",
16338c2ecf20Sopenharmony_ci		.init	= gic_enable_quirk_msm8996,
16348c2ecf20Sopenharmony_ci	},
16358c2ecf20Sopenharmony_ci	{
16368c2ecf20Sopenharmony_ci		.desc	= "GICv3: Mediatek Chromebook GICR save problem",
16378c2ecf20Sopenharmony_ci		.property = "mediatek,broken-save-restore-fw",
16388c2ecf20Sopenharmony_ci		.init	= gic_enable_quirk_mtk_gicr,
16398c2ecf20Sopenharmony_ci	},
16408c2ecf20Sopenharmony_ci	{
16418c2ecf20Sopenharmony_ci		.desc	= "GICv3: HIP06 erratum 161010803",
16428c2ecf20Sopenharmony_ci		.iidr	= 0x0204043b,
16438c2ecf20Sopenharmony_ci		.mask	= 0xffffffff,
16448c2ecf20Sopenharmony_ci		.init	= gic_enable_quirk_hip06_07,
16458c2ecf20Sopenharmony_ci	},
16468c2ecf20Sopenharmony_ci	{
16478c2ecf20Sopenharmony_ci		.desc	= "GICv3: HIP07 erratum 161010803",
16488c2ecf20Sopenharmony_ci		.iidr	= 0x00000000,
16498c2ecf20Sopenharmony_ci		.mask	= 0xffffffff,
16508c2ecf20Sopenharmony_ci		.init	= gic_enable_quirk_hip06_07,
16518c2ecf20Sopenharmony_ci	},
16528c2ecf20Sopenharmony_ci	{
16538c2ecf20Sopenharmony_ci		/*
16548c2ecf20Sopenharmony_ci		 * Reserved register accesses generate a Synchronous
16558c2ecf20Sopenharmony_ci		 * External Abort. This erratum applies to:
16568c2ecf20Sopenharmony_ci		 * - ThunderX: CN88xx
16578c2ecf20Sopenharmony_ci		 * - OCTEON TX: CN83xx, CN81xx
16588c2ecf20Sopenharmony_ci		 * - OCTEON TX2: CN93xx, CN96xx, CN98xx, CNF95xx*
16598c2ecf20Sopenharmony_ci		 */
16608c2ecf20Sopenharmony_ci		.desc	= "GICv3: Cavium erratum 38539",
16618c2ecf20Sopenharmony_ci		.iidr	= 0xa000034c,
16628c2ecf20Sopenharmony_ci		.mask	= 0xe8f00fff,
16638c2ecf20Sopenharmony_ci		.init	= gic_enable_quirk_cavium_38539,
16648c2ecf20Sopenharmony_ci	},
16658c2ecf20Sopenharmony_ci	{
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci};
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_cistatic void gic_enable_nmi_support(void)
16708c2ecf20Sopenharmony_ci{
16718c2ecf20Sopenharmony_ci	int i;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	if (!gic_prio_masking_enabled())
16748c2ecf20Sopenharmony_ci		return;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	if (gic_data.flags & FLAGS_WORKAROUND_MTK_GICR_SAVE) {
16778c2ecf20Sopenharmony_ci		pr_warn("Skipping NMI enable due to firmware issues\n");
16788c2ecf20Sopenharmony_ci		return;
16798c2ecf20Sopenharmony_ci	}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
16828c2ecf20Sopenharmony_ci	if (!ppi_nmi_refs)
16838c2ecf20Sopenharmony_ci		return;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	for (i = 0; i < gic_data.ppi_nr; i++)
16868c2ecf20Sopenharmony_ci		refcount_set(&ppi_nmi_refs[i], 0);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	/*
16898c2ecf20Sopenharmony_ci	 * Linux itself doesn't use 1:N distribution, so has no need to
16908c2ecf20Sopenharmony_ci	 * set PMHE. The only reason to have it set is if EL3 requires it
16918c2ecf20Sopenharmony_ci	 * (and we can't change it).
16928c2ecf20Sopenharmony_ci	 */
16938c2ecf20Sopenharmony_ci	if (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK)
16948c2ecf20Sopenharmony_ci		static_branch_enable(&gic_pmr_sync);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
16978c2ecf20Sopenharmony_ci		static_branch_unlikely(&gic_pmr_sync) ? "forced" : "relaxed");
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	/*
17008c2ecf20Sopenharmony_ci	 * How priority values are used by the GIC depends on two things:
17018c2ecf20Sopenharmony_ci	 * the security state of the GIC (controlled by the GICD_CTRL.DS bit)
17028c2ecf20Sopenharmony_ci	 * and if Group 0 interrupts can be delivered to Linux in the non-secure
17038c2ecf20Sopenharmony_ci	 * world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
17048c2ecf20Sopenharmony_ci	 * the ICC_PMR_EL1 register and the priority that software assigns to
17058c2ecf20Sopenharmony_ci	 * interrupts:
17068c2ecf20Sopenharmony_ci	 *
17078c2ecf20Sopenharmony_ci	 * GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
17088c2ecf20Sopenharmony_ci	 * -----------------------------------------------------------
17098c2ecf20Sopenharmony_ci	 *      1       |      -      |  unchanged  |    unchanged
17108c2ecf20Sopenharmony_ci	 * -----------------------------------------------------------
17118c2ecf20Sopenharmony_ci	 *      0       |      1      |  non-secure |    non-secure
17128c2ecf20Sopenharmony_ci	 * -----------------------------------------------------------
17138c2ecf20Sopenharmony_ci	 *      0       |      0      |  unchanged  |    non-secure
17148c2ecf20Sopenharmony_ci	 *
17158c2ecf20Sopenharmony_ci	 * where non-secure means that the value is right-shifted by one and the
17168c2ecf20Sopenharmony_ci	 * MSB bit set, to make it fit in the non-secure priority range.
17178c2ecf20Sopenharmony_ci	 *
17188c2ecf20Sopenharmony_ci	 * In the first two cases, where ICC_PMR_EL1 and the interrupt priority
17198c2ecf20Sopenharmony_ci	 * are both either modified or unchanged, we can use the same set of
17208c2ecf20Sopenharmony_ci	 * priorities.
17218c2ecf20Sopenharmony_ci	 *
17228c2ecf20Sopenharmony_ci	 * In the last case, where only the interrupt priorities are modified to
17238c2ecf20Sopenharmony_ci	 * be in the non-secure range, we use a different PMR value to mask IRQs
17248c2ecf20Sopenharmony_ci	 * and the rest of the values that we use remain unchanged.
17258c2ecf20Sopenharmony_ci	 */
17268c2ecf20Sopenharmony_ci	if (gic_has_group0() && !gic_dist_security_disabled())
17278c2ecf20Sopenharmony_ci		static_branch_enable(&gic_nonsecure_priorities);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	static_branch_enable(&supports_pseudo_nmis);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
17328c2ecf20Sopenharmony_ci		gic_eoimode1_chip.flags |= IRQCHIP_SUPPORTS_NMI;
17338c2ecf20Sopenharmony_ci	else
17348c2ecf20Sopenharmony_ci		gic_chip.flags |= IRQCHIP_SUPPORTS_NMI;
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_cistatic int __init gic_init_bases(void __iomem *dist_base,
17388c2ecf20Sopenharmony_ci				 struct redist_region *rdist_regs,
17398c2ecf20Sopenharmony_ci				 u32 nr_redist_regions,
17408c2ecf20Sopenharmony_ci				 u64 redist_stride,
17418c2ecf20Sopenharmony_ci				 struct fwnode_handle *handle)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	u32 typer;
17448c2ecf20Sopenharmony_ci	int err;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	if (!is_hyp_mode_available())
17478c2ecf20Sopenharmony_ci		static_branch_disable(&supports_deactivate_key);
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
17508c2ecf20Sopenharmony_ci		pr_info("GIC: Using split EOI/Deactivate mode\n");
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	gic_data.fwnode = handle;
17538c2ecf20Sopenharmony_ci	gic_data.dist_base = dist_base;
17548c2ecf20Sopenharmony_ci	gic_data.redist_regions = rdist_regs;
17558c2ecf20Sopenharmony_ci	gic_data.nr_redist_regions = nr_redist_regions;
17568c2ecf20Sopenharmony_ci	gic_data.redist_stride = redist_stride;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	/*
17598c2ecf20Sopenharmony_ci	 * Find out how many interrupts are supported.
17608c2ecf20Sopenharmony_ci	 */
17618c2ecf20Sopenharmony_ci	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
17628c2ecf20Sopenharmony_ci	gic_data.rdists.gicd_typer = typer;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
17658c2ecf20Sopenharmony_ci			  gic_quirks, &gic_data);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
17688c2ecf20Sopenharmony_ci	pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	/*
17718c2ecf20Sopenharmony_ci	 * ThunderX1 explodes on reading GICD_TYPER2, in violation of the
17728c2ecf20Sopenharmony_ci	 * architecture spec (which says that reserved registers are RES0).
17738c2ecf20Sopenharmony_ci	 */
17748c2ecf20Sopenharmony_ci	if (!(gic_data.flags & FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539))
17758c2ecf20Sopenharmony_ci		gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2);
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
17788c2ecf20Sopenharmony_ci						 &gic_data);
17798c2ecf20Sopenharmony_ci	gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
17808c2ecf20Sopenharmony_ci	gic_data.rdists.has_rvpeid = true;
17818c2ecf20Sopenharmony_ci	gic_data.rdists.has_vlpis = true;
17828c2ecf20Sopenharmony_ci	gic_data.rdists.has_direct_lpi = true;
17838c2ecf20Sopenharmony_ci	gic_data.rdists.has_vpend_valid_dirty = true;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
17868c2ecf20Sopenharmony_ci		err = -ENOMEM;
17878c2ecf20Sopenharmony_ci		goto out_free;
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
17938c2ecf20Sopenharmony_ci	pr_info("Distributor has %sRange Selector support\n",
17948c2ecf20Sopenharmony_ci		gic_data.has_rss ? "" : "no ");
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci	if (typer & GICD_TYPER_MBIS) {
17978c2ecf20Sopenharmony_ci		err = mbi_init(handle, gic_data.domain);
17988c2ecf20Sopenharmony_ci		if (err)
17998c2ecf20Sopenharmony_ci			pr_err("Failed to initialize MBIs\n");
18008c2ecf20Sopenharmony_ci	}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	set_handle_irq(gic_handle_irq);
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	gic_update_rdist_properties();
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	gic_dist_init();
18078c2ecf20Sopenharmony_ci	gic_cpu_init();
18088c2ecf20Sopenharmony_ci	gic_smp_init();
18098c2ecf20Sopenharmony_ci	gic_cpu_pm_init();
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	if (gic_dist_supports_lpis()) {
18128c2ecf20Sopenharmony_ci		its_init(handle, &gic_data.rdists, gic_data.domain);
18138c2ecf20Sopenharmony_ci		its_cpu_init();
18148c2ecf20Sopenharmony_ci	} else {
18158c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
18168c2ecf20Sopenharmony_ci			gicv2m_init(handle, gic_data.domain);
18178c2ecf20Sopenharmony_ci	}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	gic_enable_nmi_support();
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	return 0;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ciout_free:
18248c2ecf20Sopenharmony_ci	if (gic_data.domain)
18258c2ecf20Sopenharmony_ci		irq_domain_remove(gic_data.domain);
18268c2ecf20Sopenharmony_ci	free_percpu(gic_data.rdists.rdist);
18278c2ecf20Sopenharmony_ci	return err;
18288c2ecf20Sopenharmony_ci}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_cistatic int __init gic_validate_dist_version(void __iomem *dist_base)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
18358c2ecf20Sopenharmony_ci		return -ENODEV;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	return 0;
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci/* Create all possible partitions at boot time */
18418c2ecf20Sopenharmony_cistatic void __init gic_populate_ppi_partitions(struct device_node *gic_node)
18428c2ecf20Sopenharmony_ci{
18438c2ecf20Sopenharmony_ci	struct device_node *parts_node, *child_part;
18448c2ecf20Sopenharmony_ci	int part_idx = 0, i;
18458c2ecf20Sopenharmony_ci	int nr_parts;
18468c2ecf20Sopenharmony_ci	struct partition_affinity *parts;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	parts_node = of_get_child_by_name(gic_node, "ppi-partitions");
18498c2ecf20Sopenharmony_ci	if (!parts_node)
18508c2ecf20Sopenharmony_ci		return;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
18538c2ecf20Sopenharmony_ci	if (!gic_data.ppi_descs)
18548c2ecf20Sopenharmony_ci		goto out_put_node;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	nr_parts = of_get_child_count(parts_node);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	if (!nr_parts)
18598c2ecf20Sopenharmony_ci		goto out_put_node;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
18628c2ecf20Sopenharmony_ci	if (WARN_ON(!parts))
18638c2ecf20Sopenharmony_ci		goto out_put_node;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	for_each_child_of_node(parts_node, child_part) {
18668c2ecf20Sopenharmony_ci		struct partition_affinity *part;
18678c2ecf20Sopenharmony_ci		int n;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci		part = &parts[part_idx];
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci		part->partition_id = of_node_to_fwnode(child_part);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci		pr_info("GIC: PPI partition %pOFn[%d] { ",
18748c2ecf20Sopenharmony_ci			child_part, part_idx);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci		n = of_property_count_elems_of_size(child_part, "affinity",
18778c2ecf20Sopenharmony_ci						    sizeof(u32));
18788c2ecf20Sopenharmony_ci		WARN_ON(n <= 0);
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci		for (i = 0; i < n; i++) {
18818c2ecf20Sopenharmony_ci			int err, cpu;
18828c2ecf20Sopenharmony_ci			u32 cpu_phandle;
18838c2ecf20Sopenharmony_ci			struct device_node *cpu_node;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci			err = of_property_read_u32_index(child_part, "affinity",
18868c2ecf20Sopenharmony_ci							 i, &cpu_phandle);
18878c2ecf20Sopenharmony_ci			if (WARN_ON(err))
18888c2ecf20Sopenharmony_ci				continue;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci			cpu_node = of_find_node_by_phandle(cpu_phandle);
18918c2ecf20Sopenharmony_ci			if (WARN_ON(!cpu_node))
18928c2ecf20Sopenharmony_ci				continue;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci			cpu = of_cpu_node_to_id(cpu_node);
18958c2ecf20Sopenharmony_ci			if (WARN_ON(cpu < 0)) {
18968c2ecf20Sopenharmony_ci				of_node_put(cpu_node);
18978c2ecf20Sopenharmony_ci				continue;
18988c2ecf20Sopenharmony_ci			}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci			pr_cont("%pOF[%d] ", cpu_node, cpu);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci			cpumask_set_cpu(cpu, &part->mask);
19038c2ecf20Sopenharmony_ci			of_node_put(cpu_node);
19048c2ecf20Sopenharmony_ci		}
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci		pr_cont("}\n");
19078c2ecf20Sopenharmony_ci		part_idx++;
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	for (i = 0; i < gic_data.ppi_nr; i++) {
19118c2ecf20Sopenharmony_ci		unsigned int irq;
19128c2ecf20Sopenharmony_ci		struct partition_desc *desc;
19138c2ecf20Sopenharmony_ci		struct irq_fwspec ppi_fwspec = {
19148c2ecf20Sopenharmony_ci			.fwnode		= gic_data.fwnode,
19158c2ecf20Sopenharmony_ci			.param_count	= 3,
19168c2ecf20Sopenharmony_ci			.param		= {
19178c2ecf20Sopenharmony_ci				[0]	= GIC_IRQ_TYPE_PARTITION,
19188c2ecf20Sopenharmony_ci				[1]	= i,
19198c2ecf20Sopenharmony_ci				[2]	= IRQ_TYPE_NONE,
19208c2ecf20Sopenharmony_ci			},
19218c2ecf20Sopenharmony_ci		};
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci		irq = irq_create_fwspec_mapping(&ppi_fwspec);
19248c2ecf20Sopenharmony_ci		if (WARN_ON(!irq))
19258c2ecf20Sopenharmony_ci			continue;
19268c2ecf20Sopenharmony_ci		desc = partition_create_desc(gic_data.fwnode, parts, nr_parts,
19278c2ecf20Sopenharmony_ci					     irq, &partition_domain_ops);
19288c2ecf20Sopenharmony_ci		if (WARN_ON(!desc))
19298c2ecf20Sopenharmony_ci			continue;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci		gic_data.ppi_descs[i] = desc;
19328c2ecf20Sopenharmony_ci	}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ciout_put_node:
19358c2ecf20Sopenharmony_ci	of_node_put(parts_node);
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_cistatic void __init gic_of_setup_kvm_info(struct device_node *node)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	int ret;
19418c2ecf20Sopenharmony_ci	struct resource r;
19428c2ecf20Sopenharmony_ci	u32 gicv_idx;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	gic_v3_kvm_info.type = GIC_V3;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	gic_v3_kvm_info.maint_irq = irq_of_parse_and_map(node, 0);
19478c2ecf20Sopenharmony_ci	if (!gic_v3_kvm_info.maint_irq)
19488c2ecf20Sopenharmony_ci		return;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	if (of_property_read_u32(node, "#redistributor-regions",
19518c2ecf20Sopenharmony_ci				 &gicv_idx))
19528c2ecf20Sopenharmony_ci		gicv_idx = 1;
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	gicv_idx += 3;	/* Also skip GICD, GICC, GICH */
19558c2ecf20Sopenharmony_ci	ret = of_address_to_resource(node, gicv_idx, &r);
19568c2ecf20Sopenharmony_ci	if (!ret)
19578c2ecf20Sopenharmony_ci		gic_v3_kvm_info.vcpu = r;
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
19608c2ecf20Sopenharmony_ci	gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
19618c2ecf20Sopenharmony_ci	gic_set_kvm_info(&gic_v3_kvm_info);
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_cistatic int __init gic_of_init(struct device_node *node, struct device_node *parent)
19658c2ecf20Sopenharmony_ci{
19668c2ecf20Sopenharmony_ci	void __iomem *dist_base;
19678c2ecf20Sopenharmony_ci	struct redist_region *rdist_regs;
19688c2ecf20Sopenharmony_ci	u64 redist_stride;
19698c2ecf20Sopenharmony_ci	u32 nr_redist_regions;
19708c2ecf20Sopenharmony_ci	int err, i;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	dist_base = of_iomap(node, 0);
19738c2ecf20Sopenharmony_ci	if (!dist_base) {
19748c2ecf20Sopenharmony_ci		pr_err("%pOF: unable to map gic dist registers\n", node);
19758c2ecf20Sopenharmony_ci		return -ENXIO;
19768c2ecf20Sopenharmony_ci	}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	err = gic_validate_dist_version(dist_base);
19798c2ecf20Sopenharmony_ci	if (err) {
19808c2ecf20Sopenharmony_ci		pr_err("%pOF: no distributor detected, giving up\n", node);
19818c2ecf20Sopenharmony_ci		goto out_unmap_dist;
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
19858c2ecf20Sopenharmony_ci		nr_redist_regions = 1;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	rdist_regs = kcalloc(nr_redist_regions, sizeof(*rdist_regs),
19888c2ecf20Sopenharmony_ci			     GFP_KERNEL);
19898c2ecf20Sopenharmony_ci	if (!rdist_regs) {
19908c2ecf20Sopenharmony_ci		err = -ENOMEM;
19918c2ecf20Sopenharmony_ci		goto out_unmap_dist;
19928c2ecf20Sopenharmony_ci	}
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	for (i = 0; i < nr_redist_regions; i++) {
19958c2ecf20Sopenharmony_ci		struct resource res;
19968c2ecf20Sopenharmony_ci		int ret;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci		ret = of_address_to_resource(node, 1 + i, &res);
19998c2ecf20Sopenharmony_ci		rdist_regs[i].redist_base = of_iomap(node, 1 + i);
20008c2ecf20Sopenharmony_ci		if (ret || !rdist_regs[i].redist_base) {
20018c2ecf20Sopenharmony_ci			pr_err("%pOF: couldn't map region %d\n", node, i);
20028c2ecf20Sopenharmony_ci			err = -ENODEV;
20038c2ecf20Sopenharmony_ci			goto out_unmap_rdist;
20048c2ecf20Sopenharmony_ci		}
20058c2ecf20Sopenharmony_ci		rdist_regs[i].phys_base = res.start;
20068c2ecf20Sopenharmony_ci	}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
20098c2ecf20Sopenharmony_ci		redist_stride = 0;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	gic_enable_of_quirks(node, gic_quirks, &gic_data);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
20148c2ecf20Sopenharmony_ci			     redist_stride, &node->fwnode);
20158c2ecf20Sopenharmony_ci	if (err)
20168c2ecf20Sopenharmony_ci		goto out_unmap_rdist;
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	gic_populate_ppi_partitions(node);
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
20218c2ecf20Sopenharmony_ci		gic_of_setup_kvm_info(node);
20228c2ecf20Sopenharmony_ci	return 0;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ciout_unmap_rdist:
20258c2ecf20Sopenharmony_ci	for (i = 0; i < nr_redist_regions; i++)
20268c2ecf20Sopenharmony_ci		if (rdist_regs[i].redist_base)
20278c2ecf20Sopenharmony_ci			iounmap(rdist_regs[i].redist_base);
20288c2ecf20Sopenharmony_ci	kfree(rdist_regs);
20298c2ecf20Sopenharmony_ciout_unmap_dist:
20308c2ecf20Sopenharmony_ci	iounmap(dist_base);
20318c2ecf20Sopenharmony_ci	return err;
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ciIRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
20378c2ecf20Sopenharmony_cistatic struct
20388c2ecf20Sopenharmony_ci{
20398c2ecf20Sopenharmony_ci	void __iomem *dist_base;
20408c2ecf20Sopenharmony_ci	struct redist_region *redist_regs;
20418c2ecf20Sopenharmony_ci	u32 nr_redist_regions;
20428c2ecf20Sopenharmony_ci	bool single_redist;
20438c2ecf20Sopenharmony_ci	int enabled_rdists;
20448c2ecf20Sopenharmony_ci	u32 maint_irq;
20458c2ecf20Sopenharmony_ci	int maint_irq_mode;
20468c2ecf20Sopenharmony_ci	phys_addr_t vcpu_base;
20478c2ecf20Sopenharmony_ci} acpi_data __initdata;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_cistatic void __init
20508c2ecf20Sopenharmony_cigic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	static int count = 0;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	acpi_data.redist_regs[count].phys_base = phys_base;
20558c2ecf20Sopenharmony_ci	acpi_data.redist_regs[count].redist_base = redist_base;
20568c2ecf20Sopenharmony_ci	acpi_data.redist_regs[count].single_redist = acpi_data.single_redist;
20578c2ecf20Sopenharmony_ci	count++;
20588c2ecf20Sopenharmony_ci}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_cistatic int __init
20618c2ecf20Sopenharmony_cigic_acpi_parse_madt_redist(union acpi_subtable_headers *header,
20628c2ecf20Sopenharmony_ci			   const unsigned long end)
20638c2ecf20Sopenharmony_ci{
20648c2ecf20Sopenharmony_ci	struct acpi_madt_generic_redistributor *redist =
20658c2ecf20Sopenharmony_ci			(struct acpi_madt_generic_redistributor *)header;
20668c2ecf20Sopenharmony_ci	void __iomem *redist_base;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	redist_base = ioremap(redist->base_address, redist->length);
20698c2ecf20Sopenharmony_ci	if (!redist_base) {
20708c2ecf20Sopenharmony_ci		pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
20718c2ecf20Sopenharmony_ci		return -ENOMEM;
20728c2ecf20Sopenharmony_ci	}
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	gic_acpi_register_redist(redist->base_address, redist_base);
20758c2ecf20Sopenharmony_ci	return 0;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_cistatic int __init
20798c2ecf20Sopenharmony_cigic_acpi_parse_madt_gicc(union acpi_subtable_headers *header,
20808c2ecf20Sopenharmony_ci			 const unsigned long end)
20818c2ecf20Sopenharmony_ci{
20828c2ecf20Sopenharmony_ci	struct acpi_madt_generic_interrupt *gicc =
20838c2ecf20Sopenharmony_ci				(struct acpi_madt_generic_interrupt *)header;
20848c2ecf20Sopenharmony_ci	u32 reg = readl_relaxed(acpi_data.dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
20858c2ecf20Sopenharmony_ci	u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
20868c2ecf20Sopenharmony_ci	void __iomem *redist_base;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	/* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
20898c2ecf20Sopenharmony_ci	if (!(gicc->flags & ACPI_MADT_ENABLED))
20908c2ecf20Sopenharmony_ci		return 0;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	redist_base = ioremap(gicc->gicr_base_address, size);
20938c2ecf20Sopenharmony_ci	if (!redist_base)
20948c2ecf20Sopenharmony_ci		return -ENOMEM;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
20978c2ecf20Sopenharmony_ci	return 0;
20988c2ecf20Sopenharmony_ci}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_cistatic int __init gic_acpi_collect_gicr_base(void)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	acpi_tbl_entry_handler redist_parser;
21038c2ecf20Sopenharmony_ci	enum acpi_madt_type type;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	if (acpi_data.single_redist) {
21068c2ecf20Sopenharmony_ci		type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
21078c2ecf20Sopenharmony_ci		redist_parser = gic_acpi_parse_madt_gicc;
21088c2ecf20Sopenharmony_ci	} else {
21098c2ecf20Sopenharmony_ci		type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
21108c2ecf20Sopenharmony_ci		redist_parser = gic_acpi_parse_madt_redist;
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	/* Collect redistributor base addresses in GICR entries */
21148c2ecf20Sopenharmony_ci	if (acpi_table_parse_madt(type, redist_parser, 0) > 0)
21158c2ecf20Sopenharmony_ci		return 0;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	pr_info("No valid GICR entries exist\n");
21188c2ecf20Sopenharmony_ci	return -ENODEV;
21198c2ecf20Sopenharmony_ci}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_cistatic int __init gic_acpi_match_gicr(union acpi_subtable_headers *header,
21228c2ecf20Sopenharmony_ci				  const unsigned long end)
21238c2ecf20Sopenharmony_ci{
21248c2ecf20Sopenharmony_ci	/* Subtable presence means that redist exists, that's it */
21258c2ecf20Sopenharmony_ci	return 0;
21268c2ecf20Sopenharmony_ci}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_cistatic int __init gic_acpi_match_gicc(union acpi_subtable_headers *header,
21298c2ecf20Sopenharmony_ci				      const unsigned long end)
21308c2ecf20Sopenharmony_ci{
21318c2ecf20Sopenharmony_ci	struct acpi_madt_generic_interrupt *gicc =
21328c2ecf20Sopenharmony_ci				(struct acpi_madt_generic_interrupt *)header;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	/*
21358c2ecf20Sopenharmony_ci	 * If GICC is enabled and has valid gicr base address, then it means
21368c2ecf20Sopenharmony_ci	 * GICR base is presented via GICC
21378c2ecf20Sopenharmony_ci	 */
21388c2ecf20Sopenharmony_ci	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) {
21398c2ecf20Sopenharmony_ci		acpi_data.enabled_rdists++;
21408c2ecf20Sopenharmony_ci		return 0;
21418c2ecf20Sopenharmony_ci	}
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	/*
21448c2ecf20Sopenharmony_ci	 * It's perfectly valid firmware can pass disabled GICC entry, driver
21458c2ecf20Sopenharmony_ci	 * should not treat as errors, skip the entry instead of probe fail.
21468c2ecf20Sopenharmony_ci	 */
21478c2ecf20Sopenharmony_ci	if (!(gicc->flags & ACPI_MADT_ENABLED))
21488c2ecf20Sopenharmony_ci		return 0;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	return -ENODEV;
21518c2ecf20Sopenharmony_ci}
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_cistatic int __init gic_acpi_count_gicr_regions(void)
21548c2ecf20Sopenharmony_ci{
21558c2ecf20Sopenharmony_ci	int count;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	/*
21588c2ecf20Sopenharmony_ci	 * Count how many redistributor regions we have. It is not allowed
21598c2ecf20Sopenharmony_ci	 * to mix redistributor description, GICR and GICC subtables have to be
21608c2ecf20Sopenharmony_ci	 * mutually exclusive.
21618c2ecf20Sopenharmony_ci	 */
21628c2ecf20Sopenharmony_ci	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
21638c2ecf20Sopenharmony_ci				      gic_acpi_match_gicr, 0);
21648c2ecf20Sopenharmony_ci	if (count > 0) {
21658c2ecf20Sopenharmony_ci		acpi_data.single_redist = false;
21668c2ecf20Sopenharmony_ci		return count;
21678c2ecf20Sopenharmony_ci	}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
21708c2ecf20Sopenharmony_ci				      gic_acpi_match_gicc, 0);
21718c2ecf20Sopenharmony_ci	if (count > 0) {
21728c2ecf20Sopenharmony_ci		acpi_data.single_redist = true;
21738c2ecf20Sopenharmony_ci		count = acpi_data.enabled_rdists;
21748c2ecf20Sopenharmony_ci	}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	return count;
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_cistatic bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
21808c2ecf20Sopenharmony_ci					   struct acpi_probe_entry *ape)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	struct acpi_madt_generic_distributor *dist;
21838c2ecf20Sopenharmony_ci	int count;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	dist = (struct acpi_madt_generic_distributor *)header;
21868c2ecf20Sopenharmony_ci	if (dist->version != ape->driver_data)
21878c2ecf20Sopenharmony_ci		return false;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	/* We need to do that exercise anyway, the sooner the better */
21908c2ecf20Sopenharmony_ci	count = gic_acpi_count_gicr_regions();
21918c2ecf20Sopenharmony_ci	if (count <= 0)
21928c2ecf20Sopenharmony_ci		return false;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	acpi_data.nr_redist_regions = count;
21958c2ecf20Sopenharmony_ci	return true;
21968c2ecf20Sopenharmony_ci}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_cistatic int __init gic_acpi_parse_virt_madt_gicc(union acpi_subtable_headers *header,
21998c2ecf20Sopenharmony_ci						const unsigned long end)
22008c2ecf20Sopenharmony_ci{
22018c2ecf20Sopenharmony_ci	struct acpi_madt_generic_interrupt *gicc =
22028c2ecf20Sopenharmony_ci		(struct acpi_madt_generic_interrupt *)header;
22038c2ecf20Sopenharmony_ci	int maint_irq_mode;
22048c2ecf20Sopenharmony_ci	static int first_madt = true;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	/* Skip unusable CPUs */
22078c2ecf20Sopenharmony_ci	if (!(gicc->flags & ACPI_MADT_ENABLED))
22088c2ecf20Sopenharmony_ci		return 0;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	maint_irq_mode = (gicc->flags & ACPI_MADT_VGIC_IRQ_MODE) ?
22118c2ecf20Sopenharmony_ci		ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (first_madt) {
22148c2ecf20Sopenharmony_ci		first_madt = false;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci		acpi_data.maint_irq = gicc->vgic_interrupt;
22178c2ecf20Sopenharmony_ci		acpi_data.maint_irq_mode = maint_irq_mode;
22188c2ecf20Sopenharmony_ci		acpi_data.vcpu_base = gicc->gicv_base_address;
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci		return 0;
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/*
22248c2ecf20Sopenharmony_ci	 * The maintenance interrupt and GICV should be the same for every CPU
22258c2ecf20Sopenharmony_ci	 */
22268c2ecf20Sopenharmony_ci	if ((acpi_data.maint_irq != gicc->vgic_interrupt) ||
22278c2ecf20Sopenharmony_ci	    (acpi_data.maint_irq_mode != maint_irq_mode) ||
22288c2ecf20Sopenharmony_ci	    (acpi_data.vcpu_base != gicc->gicv_base_address))
22298c2ecf20Sopenharmony_ci		return -EINVAL;
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	return 0;
22328c2ecf20Sopenharmony_ci}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_cistatic bool __init gic_acpi_collect_virt_info(void)
22358c2ecf20Sopenharmony_ci{
22368c2ecf20Sopenharmony_ci	int count;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
22398c2ecf20Sopenharmony_ci				      gic_acpi_parse_virt_madt_gicc, 0);
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	return (count > 0);
22428c2ecf20Sopenharmony_ci}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci#define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
22458c2ecf20Sopenharmony_ci#define ACPI_GICV2_VCTRL_MEM_SIZE	(SZ_4K)
22468c2ecf20Sopenharmony_ci#define ACPI_GICV2_VCPU_MEM_SIZE	(SZ_8K)
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_cistatic void __init gic_acpi_setup_kvm_info(void)
22498c2ecf20Sopenharmony_ci{
22508c2ecf20Sopenharmony_ci	int irq;
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	if (!gic_acpi_collect_virt_info()) {
22538c2ecf20Sopenharmony_ci		pr_warn("Unable to get hardware information used for virtualization\n");
22548c2ecf20Sopenharmony_ci		return;
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	gic_v3_kvm_info.type = GIC_V3;
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	irq = acpi_register_gsi(NULL, acpi_data.maint_irq,
22608c2ecf20Sopenharmony_ci				acpi_data.maint_irq_mode,
22618c2ecf20Sopenharmony_ci				ACPI_ACTIVE_HIGH);
22628c2ecf20Sopenharmony_ci	if (irq <= 0)
22638c2ecf20Sopenharmony_ci		return;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	gic_v3_kvm_info.maint_irq = irq;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	if (acpi_data.vcpu_base) {
22688c2ecf20Sopenharmony_ci		struct resource *vcpu = &gic_v3_kvm_info.vcpu;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci		vcpu->flags = IORESOURCE_MEM;
22718c2ecf20Sopenharmony_ci		vcpu->start = acpi_data.vcpu_base;
22728c2ecf20Sopenharmony_ci		vcpu->end = vcpu->start + ACPI_GICV2_VCPU_MEM_SIZE - 1;
22738c2ecf20Sopenharmony_ci	}
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci	gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
22768c2ecf20Sopenharmony_ci	gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
22778c2ecf20Sopenharmony_ci	gic_set_kvm_info(&gic_v3_kvm_info);
22788c2ecf20Sopenharmony_ci}
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_cistatic int __init
22818c2ecf20Sopenharmony_cigic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
22828c2ecf20Sopenharmony_ci{
22838c2ecf20Sopenharmony_ci	struct acpi_madt_generic_distributor *dist;
22848c2ecf20Sopenharmony_ci	struct fwnode_handle *domain_handle;
22858c2ecf20Sopenharmony_ci	size_t size;
22868c2ecf20Sopenharmony_ci	int i, err;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	/* Get distributor base address */
22898c2ecf20Sopenharmony_ci	dist = (struct acpi_madt_generic_distributor *)header;
22908c2ecf20Sopenharmony_ci	acpi_data.dist_base = ioremap(dist->base_address,
22918c2ecf20Sopenharmony_ci				      ACPI_GICV3_DIST_MEM_SIZE);
22928c2ecf20Sopenharmony_ci	if (!acpi_data.dist_base) {
22938c2ecf20Sopenharmony_ci		pr_err("Unable to map GICD registers\n");
22948c2ecf20Sopenharmony_ci		return -ENOMEM;
22958c2ecf20Sopenharmony_ci	}
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	err = gic_validate_dist_version(acpi_data.dist_base);
22988c2ecf20Sopenharmony_ci	if (err) {
22998c2ecf20Sopenharmony_ci		pr_err("No distributor detected at @%p, giving up\n",
23008c2ecf20Sopenharmony_ci		       acpi_data.dist_base);
23018c2ecf20Sopenharmony_ci		goto out_dist_unmap;
23028c2ecf20Sopenharmony_ci	}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	size = sizeof(*acpi_data.redist_regs) * acpi_data.nr_redist_regions;
23058c2ecf20Sopenharmony_ci	acpi_data.redist_regs = kzalloc(size, GFP_KERNEL);
23068c2ecf20Sopenharmony_ci	if (!acpi_data.redist_regs) {
23078c2ecf20Sopenharmony_ci		err = -ENOMEM;
23088c2ecf20Sopenharmony_ci		goto out_dist_unmap;
23098c2ecf20Sopenharmony_ci	}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	err = gic_acpi_collect_gicr_base();
23128c2ecf20Sopenharmony_ci	if (err)
23138c2ecf20Sopenharmony_ci		goto out_redist_unmap;
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
23168c2ecf20Sopenharmony_ci	if (!domain_handle) {
23178c2ecf20Sopenharmony_ci		err = -ENOMEM;
23188c2ecf20Sopenharmony_ci		goto out_redist_unmap;
23198c2ecf20Sopenharmony_ci	}
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
23228c2ecf20Sopenharmony_ci			     acpi_data.nr_redist_regions, 0, domain_handle);
23238c2ecf20Sopenharmony_ci	if (err)
23248c2ecf20Sopenharmony_ci		goto out_fwhandle_free;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	if (static_branch_likely(&supports_deactivate_key))
23298c2ecf20Sopenharmony_ci		gic_acpi_setup_kvm_info();
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	return 0;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ciout_fwhandle_free:
23348c2ecf20Sopenharmony_ci	irq_domain_free_fwnode(domain_handle);
23358c2ecf20Sopenharmony_ciout_redist_unmap:
23368c2ecf20Sopenharmony_ci	for (i = 0; i < acpi_data.nr_redist_regions; i++)
23378c2ecf20Sopenharmony_ci		if (acpi_data.redist_regs[i].redist_base)
23388c2ecf20Sopenharmony_ci			iounmap(acpi_data.redist_regs[i].redist_base);
23398c2ecf20Sopenharmony_ci	kfree(acpi_data.redist_regs);
23408c2ecf20Sopenharmony_ciout_dist_unmap:
23418c2ecf20Sopenharmony_ci	iounmap(acpi_data.dist_base);
23428c2ecf20Sopenharmony_ci	return err;
23438c2ecf20Sopenharmony_ci}
23448c2ecf20Sopenharmony_ciIRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
23458c2ecf20Sopenharmony_ci		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
23468c2ecf20Sopenharmony_ci		     gic_acpi_init);
23478c2ecf20Sopenharmony_ciIRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
23488c2ecf20Sopenharmony_ci		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
23498c2ecf20Sopenharmony_ci		     gic_acpi_init);
23508c2ecf20Sopenharmony_ciIRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
23518c2ecf20Sopenharmony_ci		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
23528c2ecf20Sopenharmony_ci		     gic_acpi_init);
23538c2ecf20Sopenharmony_ci#endif
2354