From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A799633D501; Thu, 18 Dec 2025 10:15:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052909; cv=none; b=EXhHnO21m7wRcL8mG/cH+YkyM21KMWVeTwCVRMqzbe8LhNmx2IdP1DK6hleKLa9zIxLvGWu3HPNdazRWTuxV9vkyk2hofsEkJ07617KM4XX2x5fJfSkb06CafZTeWDnyau47yc3cc5y4bLe4YDd/0uvEP2sVpuO2DuOSylH0fq4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052909; c=relaxed/simple; bh=vnKEmMAe21QcHMZuNYI4JA27L1lMdTDSUIpCnogDK/I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AhqcOmdi3bgVtvkDUd4AtCzEUgKwnlpvPXU5/YHxH2A9qYIsRJex1MSYNiaLr1PCa1NAlNR0Ll00ylhkD/QahjDHi75ei24GXxOiAyuQE97Gtq8E/KtZHfQfbJYqpO+62uk7tzkFIJQHMRvrI/urHN1E6iTYADOEtzBaaOhaHyk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k5x6jANk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k5x6jANk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F0317C113D0; Thu, 18 Dec 2025 10:15:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052909; bh=vnKEmMAe21QcHMZuNYI4JA27L1lMdTDSUIpCnogDK/I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=k5x6jANk0HZCdFNmQ8ONf84TXV/hnSyODKlwPkYcldqK35T835k0zhX+1J4vW7h3x YuB87dKAHfjZqQktHnSNr4I87e8QoyWT5BOJ269qYwQLCmSCWMU2w1Q6fhpovy0gLP 4eWRN+g777w/a0xuPlSuAun1xmByvIKvT/LLFIqgow5KUjz5yV1YRNf2DWvopeDGr0 P1epYRKg9q7Q1XG+lQpKfb0Yxo5vd3IJuudlbkUYwRI5n+asIIoPcWcBhAUkOjCAVe 9mfSNHPmKQKiuQvf7L3sP4dyf0ZEBcc/0nxFTgJ3I5yVKNinhOY83mAZay6hnUkWZq y4rqden517tFg== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:27 +0100 Subject: [PATCH v2 1/7] ACPICA: Add GICv5 MADT structures Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-1-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi , Jose Marinho X-Mailer: b4 0.14.3 From: Jose Marinho The GICv5 adds the following MADT structures: - IRS - ITS Config Frame - ITS Translate Frame The ACPI spec ECR is at https://github.com/tianocore/edk2/issues/11148 Link: https://github.com/acpica/acpica/commit/69cca52d Signed-off-by: Jose Marinho Signed-off-by: Bob Moore Signed-off-by: Lorenzo Pieralisi --- include/acpi/actbl2.h | 49 +++++++++++++++++++++++++++++++++++++++++++++--= -- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index f726bce3eb84..fdabc6c64a9c 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1167,7 +1167,10 @@ enum acpi_madt_type { ACPI_MADT_TYPE_IMSIC =3D 25, ACPI_MADT_TYPE_APLIC =3D 26, ACPI_MADT_TYPE_PLIC =3D 27, - ACPI_MADT_TYPE_RESERVED =3D 28, /* 28 to 0x7F are reserved */ + ACPI_MADT_TYPE_GICV5_IRS =3D 28, + ACPI_MADT_TYPE_GICV5_ITS =3D 29, + ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE =3D 30, + ACPI_MADT_TYPE_RESERVED =3D 31, /* 31 to 0x7F are reserved */ ACPI_MADT_TYPE_OEM_RESERVED =3D 0x80 /* 0x80 to 0xFF are reserved for OEM= use */ }; =20 @@ -1289,7 +1292,7 @@ struct acpi_madt_local_x2apic_nmi { u8 reserved[3]; /* reserved - must be zero */ }; =20 -/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 + ACPI 6.5= changes) */ +/* 11: Generic interrupt - GICC (ACPI 5.0 + ACPI 6.0 + ACPI 6.3 + ACPI 6.5= + ACPI 6.7 changes) */ =20 struct acpi_madt_generic_interrupt { struct acpi_subtable_header header; @@ -1310,6 +1313,8 @@ struct acpi_madt_generic_interrupt { u8 reserved2[1]; u16 spe_interrupt; /* ACPI 6.3 */ u16 trbe_interrupt; /* ACPI 6.5 */ + u16 iaffid; /* ACPI 6.7 */ + u32 irs_id; }; =20 /* Masks for Flags field above */ @@ -1332,7 +1337,7 @@ struct acpi_madt_generic_distributor { u8 reserved2[3]; /* reserved - must be zero */ }; =20 -/* Values for Version field above */ +/* Values for Version field above and Version field in acpi_madt_gicv5_irs= */ =20 enum acpi_madt_gic_version { ACPI_MADT_GIC_VERSION_NONE =3D 0, @@ -1340,7 +1345,8 @@ enum acpi_madt_gic_version { ACPI_MADT_GIC_VERSION_V2 =3D 2, ACPI_MADT_GIC_VERSION_V3 =3D 3, ACPI_MADT_GIC_VERSION_V4 =3D 4, - ACPI_MADT_GIC_VERSION_RESERVED =3D 5 /* 5 and greater are reserved */ + ACPI_MADT_GIC_VERSION_V5 =3D 5, + ACPI_MADT_GIC_VERSION_RESERVED =3D 6 /* 6 and greater are reserved */ }; =20 /* 13: Generic MSI Frame (ACPI 5.1) */ @@ -1611,6 +1617,41 @@ struct acpi_madt_plic { u32 gsi_base; }; =20 +/* 28: Arm GICv5 IRS (ACPI 6.7) */ +struct acpi_madt_gicv5_irs { + struct acpi_subtable_header header; + u8 version; + u8 reserved; + u32 irs_id; + u32 flags; + u32 reserved2; + u64 config_base_address; + u64 setlpi_base_address; +}; + +#define ACPI_MADT_IRS_NON_COHERENT (1) + +/* 29: Arm GICv5 ITS Config Frame (ACPI 6.7) */ +struct acpi_madt_gicv5_translator { + struct acpi_subtable_header header; + u8 flags; + u8 reserved; /* reserved - must be zero */ + u32 translator_id; + u64 base_address; +}; + +#define ACPI_MADT_GICV5_ITS_NON_COHERENT (1) + +/* 30: Arm GICv5 ITS Translate Frame (ACPI 6.7) */ +struct acpi_madt_gicv5_translate_frame { + struct acpi_subtable_header header; + u16 reserved; /* reserved - must be zero */ + u32 linked_translator_id; + u32 translate_frame_id; + u32 reserved2; + u64 base_address; +}; + /* 80: OEM data */ =20 struct acpi_madt_oem_data { --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A94E233D519; Thu, 18 Dec 2025 10:15:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052914; cv=none; b=NvcUP2es6VqXCZfR8GW5rRvaTpeSpvhdJqyCI2S0luE7cBjZh48f6Mua/+AYXZ+QH3idCRTQWWXTZVrgHBRrABsC+ebn1Q/NhSxukDmxJt2uIBSljPkFVWLdumm00ikZ0Fb8s1gzU87QHtVNnbWAeUR3Mbv8YzLL5dFXHnUw3YA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052914; c=relaxed/simple; bh=O2IYaXBjmzGVATucF4s0OnNh/D79299lGX0XG+UCCJI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=h4BcXac3ZzhrP6Dlz5t6TKE4twRBnqrf6KMmCipnnZ5sJ0vKALm0Tkf2HCQYZlzyEzBlOiwMkWLM5OgL6GLt1Cf7kpVuJ8eBIaGkXT2nlJLFOuGn6/01CGhKJUFyoM4WFCmfLxNGNAywjEmcmCzqwCaUIGNNbevuvfhAf4StO/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Fvxw4WEQ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Fvxw4WEQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B8EC7C4CEFB; Thu, 18 Dec 2025 10:15:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052914; bh=O2IYaXBjmzGVATucF4s0OnNh/D79299lGX0XG+UCCJI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Fvxw4WEQaz44c9aV3tXuTMKcjMx3lwFdnz9x1vkVlLwafeGqA3hugyiaQRJxmz4W8 5GaGMLdA4+c7xEr6NX3I+MH4FH9/BxY1o5GTo+Q9ZkU4kK/+PH1nNDJ1ed4QEWfXkA 2aDbWC5tkknMLaFV9H1p1R1jvHaCtdWTRgS5hI6rw9Oz5supUkm9MHtlGgfxqFnOX/ l4JIQUxwJlrn2yg2iN76Kx6iqI4IyOWAMwrViTe6Ar6cvvfl3PPZ0F14ZALlCM9v8h VIbqtKfWh/W0hwVuMuYYQmKONdcgj2BqklrBg9IW0hULUsbYmePPtHp+jblJRNmjC8 F/FDdN139IUDg== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:28 +0100 Subject: [PATCH v2 2/7] ACPICA: Add Arm IORT IWB node definitions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-2-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi , Jose Marinho X-Mailer: b4 0.14.3 From: Jose Marinho The IORT IUWB node is defined in IORT issue E.g See https://developer.arm.com/documentation/den0049/eg Link: https://github.com/acpica/acpica/commit/a90dc2f5 Signed-off-by: Jose Marinho Signed-off-by: Bob Moore Signed-off-by: Lorenzo Pieralisi --- include/acpi/actbl2.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index fdabc6c64a9c..ba1a36d23e32 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -680,6 +680,7 @@ enum acpi_iort_node_type { ACPI_IORT_NODE_SMMU_V3 =3D 0x04, ACPI_IORT_NODE_PMCG =3D 0x05, ACPI_IORT_NODE_RMR =3D 0x06, + ACPI_IORT_NODE_IWB =3D 0x07, }; =20 struct acpi_iort_id_mapping { @@ -858,6 +859,12 @@ struct acpi_iort_rmr_desc { u32 reserved; }; =20 +struct acpi_iort_iwb { + u64 base_address; + u16 iwb_index; /* Unique IWB identifier matching with the IWB GSI namesp= ace. */ + char device_name[]; /* Path of the IWB namespace object */ +}; + /*************************************************************************= ****** * * IVRS - I/O Virtualization Reporting Structure --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3589281532; Thu, 18 Dec 2025 10:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052919; cv=none; b=rqxz/8XgkbJod338Kx3wajcN1eAzn4BhTkrnXnmIC53L9AocA/Gm1hoaMpNy1Uw5zMdKTBPE3lG3SDwiu+OgxTDYCEZB1DuHd8qrSWi8r1CvfHHMcO1um8UgqB3HX7S7H0ib6/umcOqg29j1zXkv7dtu0D4aJfjA4cInDY6yYK8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052919; c=relaxed/simple; bh=GJVTj8/Q1eWiuVLph/OBwj1vemW+Wer8nWvMvF151hI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Zsu6liE6d0nYMkxwvl4LEqQcHbGqIDVcGAwkFxHxhef+dm2QV+0TjGHfttPOFe9ehP84fNlcGl6LbMxZCQDgoHkQ2pIb5k1sXE0wYOwT0+03RMyxvpqUY+KTKz2zMmHtUtwL7suLgCrugl6mC1AkWSpN2v46TK9w9+lk7rJ69dE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ly05k+hP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ly05k+hP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C4A90C19421; Thu, 18 Dec 2025 10:15:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052919; bh=GJVTj8/Q1eWiuVLph/OBwj1vemW+Wer8nWvMvF151hI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Ly05k+hPNV70P3Z2zM20gHk5ANgv7lmpSZwDa/uy8qefGciy0CREV8pAC4QASs6sv mpWpXbGIv1cHs9Rsw09ZBNTI3Y7BfNsNLO8ghah62A/8VGPZ+YroTK8D/whGjabOBF 1jz0A2ZRc41mUwI6186K0vbtUEw/p/QA48gqMvLuyun3gokYNoxanjcbFnx4de+iFa oDVLJzfW1c5OJuY5JoxrE+3UUPCDO/lG5Z1IH25tR5SJrAD+Rw7AVCZstWpFf4QgkU VRZrjl0vwySDfJX5JtCz1X3b3htUHbuF/pw0OAG1ZTWrZTxx/vGT/6u2R2tZhsDzMC Fq8zXP+rjLESA== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:29 +0100 Subject: [PATCH v2 3/7] irqdomain: Add parent field to struct irqchip_fwid Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-3-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi X-Mailer: b4 0.14.3 The GICv5 driver IRQ domain hierarchy requires adding a parent field to struct irqchip_fwid so that core code can reference a fwnode_handle parent for a given fwnode. Add a parent field to struct irqchip_fwid and update the related kernel API functions to initialize and handle it. Signed-off-by: Lorenzo Pieralisi Cc: Thomas Gleixner Cc: Marc Zyngier --- include/linux/irqdomain.h | 30 ++++++++++++++++++++++++++---- kernel/irq/irqdomain.c | 14 +++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 62f81bbeb490..b9df84b447a1 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -257,7 +257,8 @@ static inline void irq_domain_set_pm_device(struct irq_= domain *d, struct device =20 #ifdef CONFIG_IRQ_DOMAIN struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, - const char *name, phys_addr_t *pa); + const char *name, phys_addr_t *pa, + struct fwnode_handle *parent); =20 enum { IRQCHIP_FWNODE_REAL, @@ -267,18 +268,39 @@ enum { =20 static inline struct fwnode_handle *irq_domain_alloc_named_fwnode(const ch= ar *name) { - return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL); + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL, NUL= L); +} + +static inline +struct fwnode_handle *irq_domain_alloc_named_fwnode_parent(const char *nam= e, + struct fwnode_handle *parent) +{ + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL, par= ent); } =20 static inline struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const= char *name, int id) { return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name, - NULL); + NULL, NULL); +} + +static inline +struct fwnode_handle *irq_domain_alloc_named_id_fwnode_parent(const char *= name, int id, + struct fwnode_handle *parent) +{ + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name, + NULL, parent); } =20 static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *p= a) { - return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa); + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa, NULL); +} + +static inline struct fwnode_handle *irq_domain_alloc_fwnode_parent(phys_ad= dr_t *pa, + struct fwnode_handle *parent) +{ + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa, parent= ); } =20 void irq_domain_free_fwnode(struct fwnode_handle *fwnode); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 2652c4cfd877..baf77cd167c4 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -33,6 +33,7 @@ static void irq_domain_free_one_irq(struct irq_domain *do= main, unsigned int virq =20 struct irqchip_fwid { struct fwnode_handle fwnode; + struct fwnode_handle *parent; unsigned int type; char *name; phys_addr_t *pa; @@ -53,8 +54,16 @@ static const char *irqchip_fwnode_get_name(const struct = fwnode_handle *fwnode) return fwid->name; } =20 +static struct fwnode_handle *irqchip_fwnode_get_parent(const struct fwnode= _handle *fwnode) +{ + struct irqchip_fwid *fwid =3D container_of(fwnode, struct irqchip_fwid, f= wnode); + + return fwid->parent; +} + const struct fwnode_operations irqchip_fwnode_ops =3D { .get_name =3D irqchip_fwnode_get_name, + .get_parent =3D irqchip_fwnode_get_parent, }; EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); =20 @@ -65,6 +74,7 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); * @id: Optional user provided id if name !=3D NULL * @name: Optional user provided domain name * @pa: Optional user-provided physical address + * @parent: Optional parent fwnode_handle * * Allocate a struct irqchip_fwid, and return a pointer to the embedded * fwnode_handle (or NULL on failure). @@ -76,7 +86,8 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); */ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, const char *name, - phys_addr_t *pa) + phys_addr_t *pa, + struct fwnode_handle *parent) { struct irqchip_fwid *fwid; char *n; @@ -104,6 +115,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigne= d int type, int id, fwid->type =3D type; fwid->name =3D n; fwid->pa =3D pa; + fwid->parent =3D parent; fwnode_init(&fwid->fwnode, &irqchip_fwnode_ops); return &fwid->fwnode; } --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C295281532; Thu, 18 Dec 2025 10:15:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052924; cv=none; b=VYjKKL1IQqoA4wwdd8SDXHOq7vs7eLJoWEPiGSY9B2ZcyA4EwVtLike6suLOtrUJWJVMwLMFvy54zmIHYtjNu6J2Pdb6Nr9pK+WsTj2bhhXnXBVJbed8FvveQ53bvboODrX7Ne8IQJ7MVz3jBsSgtX7ahe1eT10snCxayhRrVzA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052924; c=relaxed/simple; bh=Bi06CETWErknBAzyqJH7s43TP+l23Kbig0ziz2gkwNU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bIFMbMJU9Mm0WIiWbDG/TAU/qV/4CGNhLyQzxGFYmnMSRS6nL56QiWMtTenLTeHmcSENTpdOlmzbZX/9cm1Hy/ChJTK14VANxWCSvHEPcTu0SJPOEScy2Qvc1YuiCPAWyGZyvMwx7a4MbrUQ7oOEoZS3UrRWLxLXunNVEx1Y/DQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QB+UdsyI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QB+UdsyI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D8277C116C6; Thu, 18 Dec 2025 10:15:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052924; bh=Bi06CETWErknBAzyqJH7s43TP+l23Kbig0ziz2gkwNU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=QB+UdsyIWZOBLCFUBrvizDmKa5ET0ysK+9tr1s0TINduJaM24v9JNd30p05Ih1cIR 93AjPtXllVB4MfHolIfqz4asfZXcClFuPr6+HujwlDuxPX4MrWPiGmAyCSSoybzbuZ iaCo94FEMxrgCCpQfCI0Uxe8ltzb2yTjNfZer4OqdEuZcJqlVCObW34FO/YpJtbQO/ wKOZs9afgWx+Rmi7q2HfRfnBwct+whVGPVLHhe2RkY3hbbrgGrszH3pkK8P9W7grvh n3DilzA+G72OmvCuBihXhVDNB3rMOoDXrWlyoqgaDStzIT3Nms+jflJTSjdw8+IXa0 +TGNwszGlPDzg== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:30 +0100 Subject: [PATCH v2 4/7] PCI/MSI: Make the pci_msi_map_rid_ctlr_node() interface firmware agnostic Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-4-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi X-Mailer: b4 0.14.3 To support booting with OF and ACPI seamlessly, GIC ITS parent code requires the PCI/MSI irqdomain layer to implement a function to retrieve an MSI controller fwnode and map an RID in a firmware agnostic way (ie pci_msi_map_rid_ctlr_node()). Convert pci_msi_map_rid_ctlr_node() to an OF agnostic interface (fwnode_handle based) and update the GIC ITS MSI parent code to reflect the pci_msi_map_rid_ctlr_node() change. Signed-off-by: Lorenzo Pieralisi Cc: Thomas Gleixner Cc: Bjorn Helgaas Cc: Marc Zyngier Acked-by: Bjorn Helgaas Reviewed-by: Jonathan Cameron --- drivers/irqchip/irq-gic-its-msi-parent.c | 8 ++++---- drivers/pci/msi/irqdomain.c | 22 +++++++++++++++++----- include/linux/msi.h | 3 ++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/irqchip/irq-gic-its-msi-parent.c b/drivers/irqchip/irq= -gic-its-msi-parent.c index 12f45228c867..4d1ad1ee005d 100644 --- a/drivers/irqchip/irq-gic-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-its-msi-parent.c @@ -104,7 +104,7 @@ static int its_pci_msi_prepare(struct irq_domain *domai= n, struct device *dev, static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device= *dev, int nvec, msi_alloc_info_t *info) { - struct device_node *msi_node =3D NULL; + struct fwnode_handle *msi_node =3D NULL; struct msi_domain_info *msi_info; struct pci_dev *pdev; phys_addr_t pa; @@ -116,15 +116,15 @@ static int its_v5_pci_msi_prepare(struct irq_domain *= domain, struct device *dev, =20 pdev =3D to_pci_dev(dev); =20 - rid =3D pci_msi_map_rid_ctlr_node(pdev, &msi_node); + rid =3D pci_msi_map_rid_ctlr_node(domain->parent, pdev, &msi_node); if (!msi_node) return -ENODEV; =20 - ret =3D its_translate_frame_address(msi_node, &pa); + ret =3D its_translate_frame_address(to_of_node(msi_node), &pa); if (ret) return -ENODEV; =20 - of_node_put(msi_node); + fwnode_handle_put(msi_node); =20 /* ITS specific DeviceID */ info->scratchpad[0].ul =3D rid; diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index a329060287b5..3136341e802c 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -376,23 +376,35 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *dom= ain, struct pci_dev *pdev) } =20 /** - * pci_msi_map_rid_ctlr_node - Get the MSI controller node and MSI request= er id (RID) + * pci_msi_map_rid_ctlr_node - Get the MSI controller fwnode_handle and MS= I requester id (RID) + * @domain: The interrupt domain * @pdev: The PCI device - * @node: Pointer to store the MSI controller device node + * @node: Pointer to store the MSI controller fwnode_handle * - * Use the firmware data to find the MSI controller node for @pdev. + * Use the firmware data to find the MSI controller fwnode_handle for @pde= v. * If found map the RID and initialize @node with it. @node value must * be set to NULL on entry. * * Returns: The RID. */ -u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **n= ode) +u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain, struct pci_dev *p= dev, + struct fwnode_handle **node) { + struct device_node *of_node; u32 rid =3D pci_dev_id(pdev); =20 pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid); =20 - return of_msi_xlate(&pdev->dev, node, rid); + of_node =3D irq_domain_get_of_node(domain); + if (of_node) { + struct device_node *msi_ctlr_node =3D NULL; + + rid =3D of_msi_xlate(&pdev->dev, &msi_ctlr_node, rid); + if (msi_ctlr_node) + *node =3D of_fwnode_handle(msi_ctlr_node); + } + + return rid; } =20 /** diff --git a/include/linux/msi.h b/include/linux/msi.h index 8003e3218c46..8ddb05d5c96a 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -702,7 +702,8 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct= msi_msg *msg); void pci_msi_mask_irq(struct irq_data *data); void pci_msi_unmask_irq(struct irq_data *data); u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *= pdev); -u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **n= ode); +u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain, struct pci_dev *p= dev, + struct fwnode_handle **node); struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev); void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *ar= g, struct msi_desc *desc); --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F2D5E33E371; Thu, 18 Dec 2025 10:15:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052930; cv=none; b=CYTWExtJ7P9C5pnkIp2z+l/jmsXLOmiuVgmy4HdBTJausXMDiTCiDIbgN712Z4qMS/aV4DGEaaM2v1Zd8gmBmNvQKD20XGYoTEqI1u8Imlzj3yyqUNdnY03JTJxkXKvq8DHkp81L8B8Pp/WgX43IGK0//7snhipDLS7ofgJcS74= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052930; c=relaxed/simple; bh=11REyH6T/zi9pofxE8viB/8eRKLpOXtocQ0cKQzSEV4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UfUBkqtZB5sHpTTIs6m7RwfS3KOu0F4UVdVDNRKJ/RkN0A/V/0V7Lcx+DXUbRM4SVKAExICB+aKYXSftZMJrZobWgS9SW34YnCKLRR0q/Dbfp0QG1bYPxLsB6cMmlwKi32cB4R4bHGRCxjNUdUFBLaAQ08iJ3ve2LXP8RMfJKaY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=usY576Hj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="usY576Hj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AC401C116D0; Thu, 18 Dec 2025 10:15:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052929; bh=11REyH6T/zi9pofxE8viB/8eRKLpOXtocQ0cKQzSEV4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=usY576HjQPHAk75AVH55Aa9sTD+W+zb5gKRe+tRH8z7P6gW6NyeHxG+hz9YNsoPwq J0NLswXurq35zu14nXlijle0JqpSWHYgsrpu1ak7mWGmhnuOQiYSJwixTYLXIMcDoL TAd3834zRrcOi7w/GgEtGPMpYYF8NnPlv6wqN73VhDgEKk47yk3pYRzGrzxKUpYER4 N/tnERwnIvquT43G7osqPOneCvaswbgpMhHXA07O6UFVS9+jfHaCEp4Ge3aHffbys3 CZJeX5gfKqGQqxeTs2HLezpZfYLeNEDCM5OGFSeYc5qy3O+XtPg8HHyMjYf6O8aYjh yrsM0riC5CRWg== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:31 +0100 Subject: [PATCH v2 5/7] irqchip/gic-v5: Add ACPI IRS probing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-5-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi X-Mailer: b4 0.14.3 On ARM64 ACPI systems GICv5 IRSes are described in MADT sub-entries. Add the required plumbing to parse MADT IRS firmware table entries and probe the IRS components in ACPI. Refactor the OF based probe so that common code paths can be reused for ACPI as well in the process. Augment the irqdomain_ops.translate() for PPI and SPI IRQs in order to provide support for their ACPI based firmware translation. Implement an irqchip ACPI based callback to initialize the global GSI domain upon an MADT IRS detection. The IRQCHIP_ACPI_DECLARE() entry in the top level GICv5 driver is only used to trigger the IRS probing (ie the global GSI domain is initialized once on the first call on multi-IRS systems); IRS probing takes place by calling acpi_table_parse_madt() in the IRS sub-driver, that probes all IRSes in sequence. Add a new ACPI interrupt model so that it can be detected at runtime and distinguished from previous GIC architecture models. Signed-off-by: Lorenzo Pieralisi Cc: Thomas Gleixner Cc: "Rafael J. Wysocki" Cc: Marc Zyngier --- drivers/acpi/bus.c | 3 + drivers/irqchip/irq-gic-v5-irs.c | 239 +++++++++++++++++++++++++++++----= ---- drivers/irqchip/irq-gic-v5.c | 134 ++++++++++++++++++--- include/linux/acpi.h | 1 + include/linux/irqchip/arm-gic-v5.h | 1 + 5 files changed, 308 insertions(+), 70 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a984ccd4a2a0..e4f4059c4f1d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1197,6 +1197,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_GIC: message =3D "GIC"; break; + case ACPI_IRQ_MODEL_GIC_V5: + message =3D "GICv5"; + break; case ACPI_IRQ_MODEL_PLATFORM: message =3D "platform specific model"; break; diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-= irs.c index ce2732d649a3..07c3df5692af 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -5,6 +5,7 @@ =20 #define pr_fmt(fmt) "GICv5 IRS: " fmt =20 +#include #include #include #include @@ -545,15 +546,15 @@ int gicv5_irs_register_cpu(int cpuid) =20 static void __init gicv5_irs_init_bases(struct gicv5_irs_chip_data *irs_da= ta, void __iomem *irs_base, - struct fwnode_handle *handle) + struct fwnode_handle *handle, + bool noncoherent) { - struct device_node *np =3D to_of_node(handle); u32 cr0, cr1; =20 irs_data->fwnode =3D handle; irs_data->irs_base =3D irs_base; =20 - if (of_property_read_bool(np, "dma-noncoherent")) { + if (noncoherent) { /* * A non-coherent IRS implies that some cache levels cannot be * used coherently by the cores and GIC. Our only option is to mark @@ -678,49 +679,13 @@ static void irs_setup_pri_bits(u32 idr1) } } =20 -static int __init gicv5_irs_init(struct device_node *node) +static int __init gicv5_irs_init(struct gicv5_irs_chip_data *irs_data) { - struct gicv5_irs_chip_data *irs_data; - void __iomem *irs_base; - u32 idr, spi_count; - u8 iaffid_bits; - int ret; + u32 spi_count, idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR2); =20 - irs_data =3D kzalloc(sizeof(*irs_data), GFP_KERNEL); - if (!irs_data) - return -ENOMEM; - - raw_spin_lock_init(&irs_data->spi_config_lock); - - ret =3D of_property_match_string(node, "reg-names", "ns-config"); - if (ret < 0) { - pr_err("%pOF: ns-config reg-name not present\n", node); - goto out_err; - } - - irs_base =3D of_io_request_and_map(node, ret, of_node_full_name(node)); - if (IS_ERR(irs_base)) { - pr_err("%pOF: unable to map GICv5 IRS registers\n", node); - ret =3D PTR_ERR(irs_base); - goto out_err; - } - - gicv5_irs_init_bases(irs_data, irs_base, &node->fwnode); - - idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR1); - iaffid_bits =3D FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1; - - ret =3D gicv5_irs_of_init_affinity(node, irs_data, iaffid_bits); - if (ret) { - pr_err("Failed to parse CPU IAFFIDs from the device tree!\n"); - goto out_iomem; - } - - idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR2); if (WARN(!FIELD_GET(GICV5_IRS_IDR2_LPI, idr), "LPI support not available - no IPIs, can't proceed\n")) { - ret =3D -ENODEV; - goto out_iomem; + return -ENODEV; } =20 idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR7); @@ -729,14 +694,6 @@ static int __init gicv5_irs_init(struct device_node *n= ode) idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR6); irs_data->spi_range =3D FIELD_GET(GICV5_IRS_IDR6_SPI_IRS_RANGE, idr); =20 - if (irs_data->spi_range) { - pr_info("%s detected SPI range [%u-%u]\n", - of_node_full_name(node), - irs_data->spi_min, - irs_data->spi_min + - irs_data->spi_range - 1); - } - /* * Do the global setting only on the first IRS. * Global properties (iaffid_bits, global spi count) are guaranteed to @@ -760,6 +717,60 @@ static int __init gicv5_irs_init(struct device_node *n= ode) list_add_tail(&irs_data->entry, &irs_nodes); =20 return 0; +} + +static int __init gicv5_irs_of_init(struct device_node *node) +{ + struct gicv5_irs_chip_data *irs_data; + void __iomem *irs_base; + u8 iaffid_bits; + u32 idr; + int ret; + + irs_data =3D kzalloc(sizeof(*irs_data), GFP_KERNEL); + if (!irs_data) + return -ENOMEM; + + raw_spin_lock_init(&irs_data->spi_config_lock); + + ret =3D of_property_match_string(node, "reg-names", "ns-config"); + if (ret < 0) { + pr_err("%pOF: ns-config reg-name not present\n", node); + goto out_err; + } + + irs_base =3D of_io_request_and_map(node, ret, of_node_full_name(node)); + if (IS_ERR(irs_base)) { + pr_err("%pOF: unable to map GICv5 IRS registers\n", node); + ret =3D PTR_ERR(irs_base); + goto out_err; + } + + gicv5_irs_init_bases(irs_data, irs_base, &node->fwnode, + of_property_read_bool(node, "dma-noncoherent")); + + idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR1); + iaffid_bits =3D FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1; + + ret =3D gicv5_irs_of_init_affinity(node, irs_data, iaffid_bits); + if (ret) { + pr_err("Failed to parse CPU IAFFIDs from the device tree!\n"); + goto out_iomem; + } + + ret =3D gicv5_irs_init(irs_data); + if (ret) + goto out_iomem; + + if (irs_data->spi_range) { + pr_info("%s detected SPI range [%u-%u]\n", + of_node_full_name(node), + irs_data->spi_min, + irs_data->spi_min + + irs_data->spi_range - 1); + } + + return ret; =20 out_iomem: iounmap(irs_base); @@ -818,10 +829,136 @@ int __init gicv5_irs_of_probe(struct device_node *pa= rent) if (!of_device_is_compatible(np, "arm,gic-v5-irs")) continue; =20 - ret =3D gicv5_irs_init(np); + ret =3D gicv5_irs_of_init(np); if (ret) pr_err("Failed to init IRS %s\n", np->full_name); } =20 return list_empty(&irs_nodes) ? -ENODEV : 0; } + +#ifdef CONFIG_ACPI + +#define ACPI_GICV5_IRS_MEM_SIZE (SZ_64K) +static struct gicv5_irs_chip_data *current_irs_data __initdata; +static int current_irsid __initdata =3D -1; +static u8 current_iaffid_bits __initdata; + +static int __init gic_acpi_parse_iaffid(union acpi_subtable_headers *heade= r, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc =3D (struct acpi_madt_generic_in= terrupt *)header; + int cpu; + + if (!(gicc->flags & (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE))) + return 0; + + if (gicc->irs_id =3D=3D current_irsid) { + cpu =3D get_logical_index(gicc->arm_mpidr); + + if (gicc->iaffid & ~GENMASK(current_iaffid_bits - 1, 0)) { + pr_warn("CPU %d iaffid 0x%x exceeds IRS iaffid bits\n", cpu, gicc->iaff= id); + return 0; + } + + // Bind the IAFFID and the CPU + per_cpu(cpu_iaffid, cpu).iaffid =3D gicc->iaffid; + per_cpu(cpu_iaffid, cpu).valid =3D true; + pr_debug("Processed IAFFID %u for CPU%d", per_cpu(cpu_iaffid, cpu).iaffi= d, cpu); + + // We also know that the CPU is connected to this IRS + per_cpu(per_cpu_irs_data, cpu) =3D current_irs_data; + } + + return 0; +} + +static int __init gicv5_irs_acpi_init_affinity(u32 irsid, struct gicv5_irs= _chip_data *irs_data) +{ + u32 idr; + + current_irsid =3D irsid; + current_irs_data =3D irs_data; + + idr =3D irs_readl_relaxed(irs_data, GICV5_IRS_IDR1); + current_iaffid_bits =3D FIELD_GET(GICV5_IRS_IDR1_IAFFID_BITS, idr) + 1; + + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, gic_acpi_parse_ia= ffid, 0); + + return 0; +} + +static struct resource * __init gic_request_region(resource_size_t base, r= esource_size_t size, + const char *name) +{ + struct resource *r =3D request_mem_region(base, size, name); + + if (!r) + pr_warn_once(FW_BUG "%s region %pa has overlapping address\n", name, &ba= se); + + return r; +} + +static int __init gic_acpi_parse_madt_irs(union acpi_subtable_headers *hea= der, + const unsigned long end) +{ + struct acpi_madt_gicv5_irs *irs =3D (struct acpi_madt_gicv5_irs *)header; + struct gicv5_irs_chip_data *irs_data; + void __iomem *irs_base; + struct resource *r; + int ret; + + // Per-IRS data structure + irs_data =3D kzalloc(sizeof(*irs_data), GFP_KERNEL); + if (!irs_data) + return -ENOMEM; + + // This spinlock is used for SPI config changes + raw_spin_lock_init(&irs_data->spi_config_lock); + + irs_base =3D ioremap(irs->config_base_address, ACPI_GICV5_IRS_MEM_SIZE); + if (!irs_base) { + pr_err("Unable to map GIC IRS registers\n"); + ret =3D -ENOMEM; + goto out_free; + } + + r =3D gic_request_region(irs->config_base_address, ACPI_GICV5_IRS_MEM_SIZ= E, "GICv5 IRS"); + if (!r) { + ret =3D -EBUSY; + goto out_map; + } + + gicv5_irs_init_bases(irs_data, irs_base, NULL, irs->flags & ACPI_MADT_IRS= _NON_COHERENT); + + gicv5_irs_acpi_init_affinity(irs->irs_id, irs_data); + + ret =3D gicv5_irs_init(irs_data); + if (ret) + goto out_release; + + if (irs_data->spi_range) { + pr_info("%s @%llx detected SPI range [%u-%u]\n", "IRS", irs->config_base= _address, + irs_data->spi_min, + irs_data->spi_min + + irs_data->spi_range - 1); + } + + return 0; + +out_release: + release_mem_region(r->start, resource_size(r)); +out_map: + iounmap(irs_base); +out_free: + kfree(irs_data); + return ret; +} + +int __init gicv5_irs_acpi_probe(void) +{ + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_IRS, gic_acpi_parse_madt_irs, = 0); + + return list_empty(&irs_nodes) ? -ENODEV : 0; +} +#endif diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 41ef286c4d78..23fd551c4347 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -579,16 +579,36 @@ static __always_inline int gicv5_irq_domain_translate= (struct irq_domain *d, unsigned int *type, const u8 hwirq_type) { - if (!is_of_node(fwspec->fwnode)) - return -EINVAL; + unsigned int hwirq_trigger; + u8 fwspec_irq_type; =20 - if (fwspec->param_count < 3) - return -EINVAL; + if (is_of_node(fwspec->fwnode)) { =20 - if (fwspec->param[0] !=3D hwirq_type) - return -EINVAL; + if (fwspec->param_count < 3) + return -EINVAL; =20 - *hwirq =3D fwspec->param[1]; + fwspec_irq_type =3D fwspec->param[0]; + + if (fwspec->param[0] !=3D hwirq_type) + return -EINVAL; + + *hwirq =3D fwspec->param[1]; + hwirq_trigger =3D fwspec->param[2]; + } + + if (is_fwnode_irqchip(fwspec->fwnode)) { + + if (fwspec->param_count !=3D 2) + return -EINVAL; + + fwspec_irq_type =3D FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]); + + if (fwspec_irq_type !=3D hwirq_type) + return -EINVAL; + + *hwirq =3D FIELD_GET(GICV5_HWIRQ_ID, fwspec->param[0]); + hwirq_trigger =3D fwspec->param[1]; + } =20 switch (hwirq_type) { case GICV5_HWIRQ_TYPE_PPI: @@ -600,7 +620,7 @@ static __always_inline int gicv5_irq_domain_translate(s= truct irq_domain *d, IRQ_TYPE_EDGE_RISING; break; case GICV5_HWIRQ_TYPE_SPI: - *type =3D fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + *type =3D hwirq_trigger & IRQ_TYPE_SENSE_MASK; break; default: BUILD_BUG_ON(1); @@ -660,10 +680,18 @@ static void gicv5_irq_domain_free(struct irq_domain *= domain, unsigned int virq, static int gicv5_irq_ppi_domain_select(struct irq_domain *d, struct irq_fw= spec *fwspec, enum irq_domain_bus_token bus_token) { + u32 hwirq_type; + if (fwspec->fwnode !=3D d->fwnode) return 0; =20 - if (fwspec->param[0] !=3D GICV5_HWIRQ_TYPE_PPI) + if (is_of_node(fwspec->fwnode)) + hwirq_type =3D fwspec->param[0]; + + if (is_fwnode_irqchip(fwspec->fwnode)) + hwirq_type =3D FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]); + + if (hwirq_type !=3D GICV5_HWIRQ_TYPE_PPI) return 0; =20 return (d =3D=3D gicv5_global_data.ppi_domain); @@ -718,10 +746,18 @@ static int gicv5_irq_spi_domain_alloc(struct irq_doma= in *domain, unsigned int vi static int gicv5_irq_spi_domain_select(struct irq_domain *d, struct irq_fw= spec *fwspec, enum irq_domain_bus_token bus_token) { + u32 hwirq_type; + if (fwspec->fwnode !=3D d->fwnode) return 0; =20 - if (fwspec->param[0] !=3D GICV5_HWIRQ_TYPE_SPI) + if (is_of_node(fwspec->fwnode)) + hwirq_type =3D fwspec->param[0]; + + if (is_fwnode_irqchip(fwspec->fwnode)) + hwirq_type =3D FIELD_GET(GICV5_HWIRQ_TYPE, fwspec->param[0]); + + if (hwirq_type !=3D GICV5_HWIRQ_TYPE_SPI) return 0; =20 return (d =3D=3D gicv5_global_data.spi_domain); @@ -1082,16 +1118,12 @@ static inline void __init gic_of_setup_kvm_info(str= uct device_node *node) } #endif // CONFIG_KVM =20 -static int __init gicv5_of_init(struct device_node *node, struct device_no= de *parent) +static int __init gicv5_init_common(struct fwnode_handle *parent_domain) { - int ret =3D gicv5_irs_of_probe(node); + int ret =3D gicv5_init_domains(parent_domain); if (ret) return ret; =20 - ret =3D gicv5_init_domains(of_fwnode_handle(node)); - if (ret) - goto out_irs; - gicv5_set_cpuif_pribits(); gicv5_set_cpuif_idbits(); =20 @@ -1113,18 +1145,82 @@ static int __init gicv5_of_init(struct device_node = *node, struct device_node *pa gicv5_smp_init(); =20 gicv5_irs_its_probe(); - - gic_of_setup_kvm_info(node); - return 0; =20 out_int: gicv5_cpu_disable_interrupts(); out_dom: gicv5_free_domains(); + return ret; +} + +static int __init gicv5_of_init(struct device_node *node, struct device_no= de *parent) +{ + int ret =3D gicv5_irs_of_probe(node); + if (ret) + return ret; + + ret =3D gicv5_init_common(of_fwnode_handle(node)); + if (ret) + goto out_irs; + + gic_of_setup_kvm_info(node); + + return 0; out_irs: gicv5_irs_remove(); =20 return ret; } IRQCHIP_DECLARE(gic_v5, "arm,gic-v5", gicv5_of_init); + +#ifdef CONFIG_ACPI +static bool __init acpi_validate_gic_table(struct acpi_subtable_header *he= ader, + struct acpi_probe_entry *ape) +{ + struct acpi_madt_gicv5_irs *irs =3D (struct acpi_madt_gicv5_irs *)header; + + return (irs->version =3D=3D ape->driver_data); +} + +static struct fwnode_handle *gsi_domain_handle; + +static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi) +{ + return gsi_domain_handle; +} + +static int __init gic_acpi_init(union acpi_subtable_headers *header, const= unsigned long end) +{ + struct acpi_madt_gicv5_irs *irs =3D (struct acpi_madt_gicv5_irs *)header; + int ret; + + if (gsi_domain_handle) + return 0; + + gsi_domain_handle =3D irq_domain_alloc_fwnode(&irs->config_base_address); + if (!gsi_domain_handle) + return -ENOMEM; + + ret =3D gicv5_irs_acpi_probe(); + if (ret) + goto out_fwnode; + + ret =3D gicv5_init_common(gsi_domain_handle); + if (ret) + goto out_irs; + + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id); + + return 0; + +out_irs: + gicv5_irs_remove(); +out_fwnode: + irq_domain_free_fwnode(gsi_domain_handle); + return ret; +} +IRQCHIP_ACPI_DECLARE(gic_v5, ACPI_MADT_TYPE_GICV5_IRS, + acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V5, + gic_acpi_init); +#endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index fbf0c3a65f59..3a412dcebc29 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -107,6 +107,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_IOSAPIC, ACPI_IRQ_MODEL_PLATFORM, ACPI_IRQ_MODEL_GIC, + ACPI_IRQ_MODEL_GIC_V5, ACPI_IRQ_MODEL_LPIC, ACPI_IRQ_MODEL_RINTC, ACPI_IRQ_MODEL_COUNT diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm= -gic-v5.h index 68ddcdb1cec5..ff5b1a4931d7 100644 --- a/include/linux/irqchip/arm-gic-v5.h +++ b/include/linux/irqchip/arm-gic-v5.h @@ -344,6 +344,7 @@ void __init gicv5_init_lpi_domain(void); void __init gicv5_free_lpi_domain(void); =20 int gicv5_irs_of_probe(struct device_node *parent); +int gicv5_irs_acpi_probe(void); void gicv5_irs_remove(void); int gicv5_irs_enable(void); void gicv5_irs_its_probe(void); --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8973433EB0D; Thu, 18 Dec 2025 10:15:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052934; cv=none; b=CEnY4QR+SCMDXJMWhw+kCmGgDOh6oXaouON/oITWESwFNOdzm6UQ4b7QRpSSYWpBFQHnIgKpJOCX9jBSL90Spryx5YQBgXlOdcYz7N2loveWkp0AN7YOgbu4fmjK0ha4UFfa5IpDdU9ba14Rne/YzO0q3TnP88P+TMp5GbMrERY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052934; c=relaxed/simple; bh=qddCaPpoKzIS+gMhDfBW/nIlBvoNN/1wgvBirpUnYgs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XMYDXu6/l3aeZRgjbqNvY9Tc8jNGoU+AH1+aD6ra0jxQrx7HPpr5m8OSLaPSv9YSbMbOJ9ZZ5gxGK8tlzJ2vTYJ5XW8SkJW3JsBjbME+IO0J+ttBZvMilZZwQHpBtJ6zqgNvET5a54tc3cHxlXV/wSK/zHJo78JfeKnNRtvEB2o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Csmto2VZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Csmto2VZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 25835C116C6; Thu, 18 Dec 2025 10:15:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052934; bh=qddCaPpoKzIS+gMhDfBW/nIlBvoNN/1wgvBirpUnYgs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Csmto2VZGOBapFbUWNZZqQ9VyHhcxrh9870K5MNaYGpevTKfJA0uII1EUGUiF/153 hbSfNJNpIHWDuNNp9FFeUSYxaViBPikXofqrIFbJh0ff9k95te/zw5uUcw50eOmb8I z0uA1noZDUofKPZNueqkwWBucN0SOmHaCSM8o0V0yV5snROn0gkPZZtHPIkq1q9mnN afOdFHc8ImsYtTof5TPrDKLH2TdLHl1LFaV3lebDUKsJAG27JB8KlVOtdcLr2SnmND oV8Q2TXxxef0396CHbEG5aPOyxkFAXvbybOXumcJvTgpcX2p7bWJE3cl5ulGRtthkj YMDPolycK8fgA== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:32 +0100 Subject: [PATCH v2 6/7] irqchip/gic-v5: Add ACPI ITS probing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-6-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi X-Mailer: b4 0.14.3 On ACPI ARM64 systems the GICv5 ITS configuration and translate frames are described in the MADT table. Refactor the current GICv5 ITS driver code to share common functions between ACPI and OF and implement ACPI probing in the GICv5 ITS driver. Add iort_msi_xlate() to map a device ID and retrieve an MSI controller fwnode node for ACPI systems and update pci_msi_map_rid_ctlr_node() to use it in its ACPI code path. Add the required functions to IORT code for deviceID retrieval and IRQ domain registration and look-up so that the GICv5 ITS driver in an ACPI based system can be successfully probed. Signed-off-by: Lorenzo Pieralisi Cc: Thomas Gleixner Cc: Hanjun Guo Cc: Sudeep Holla Cc: Marc Zyngier Reviewed-by: Jonathan Cameron --- drivers/acpi/arm64/iort.c | 95 +++++++++++++++++----- drivers/irqchip/irq-gic-its-msi-parent.c | 39 ++++----- drivers/irqchip/irq-gic-v5-irs.c | 7 +- drivers/irqchip/irq-gic-v5-its.c | 132 +++++++++++++++++++++++++++= +++- drivers/pci/msi/irqdomain.c | 2 + include/linux/acpi_iort.h | 10 ++- include/linux/irqchip/arm-gic-v5.h | 1 + 7 files changed, 241 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 65f0f56ad753..17dbe66da804 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -595,45 +595,45 @@ u32 iort_msi_map_id(struct device *dev, u32 input_id) } =20 /** - * iort_pmsi_get_dev_id() - Get the device id for a device + * iort_msi_xlate() - Map a MSI input ID for a device * @dev: The device for which the mapping is to be done. - * @dev_id: The device ID found. + * @input_id: The device input ID. + * @fwnode: Pointer to store the fwnode. * - * Returns: 0 for successful find a dev id, -ENODEV on error + * Returns: mapped MSI ID on success, input ID otherwise + * On success, the fwnode pointer is initialized to the MSI + * controller fwnode handle. */ -int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) +u32 iort_msi_xlate(struct device *dev, u32 input_id, struct fwnode_handle = **fwnode) { - int i, index; + struct acpi_iort_its_group *its; struct acpi_iort_node *node; + u32 dev_id; =20 node =3D iort_find_dev_node(dev); if (!node) - return -ENODEV; + return input_id; =20 - index =3D iort_get_id_mapping_index(node); - /* if there is a valid index, go get the dev_id directly */ - if (index >=3D 0) { - if (iort_node_get_id(node, dev_id, index)) - return 0; - } else { - for (i =3D 0; i < node->mapping_count; i++) { - if (iort_node_map_platform_id(node, dev_id, - IORT_MSI_TYPE, i)) - return 0; - } - } + node =3D iort_node_map_id(node, input_id, &dev_id, IORT_MSI_TYPE); + if (!node) + return input_id; =20 - return -ENODEV; + /* Move to ITS specific data */ + its =3D (struct acpi_iort_its_group *)node->node_data; + + *fwnode =3D iort_find_domain_token(its->identifiers[0]); + + return dev_id; } =20 -static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base) +int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base) { struct iort_its_msi_chip *its_msi_chip; int ret =3D -ENODEV; =20 spin_lock(&iort_msi_chip_lock); list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) { - if (its_msi_chip->translation_id =3D=3D its_id) { + if (its_msi_chip->fw_node =3D=3D node) { *base =3D its_msi_chip->base_addr; ret =3D 0; break; @@ -644,6 +644,59 @@ static int __maybe_unused iort_find_its_base(u32 its_i= d, phys_addr_t *base) return ret; } =20 +static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base) +{ + struct fwnode_handle *fwnode =3D iort_find_domain_token(its_id); + + if (!fwnode) + return -ENODEV; + + return iort_its_translate_pa(fwnode, base); +} + +/** + * iort_pmsi_get_msi_info() - Get the device id and translate frame PA for= a device + * @dev: The device for which the mapping is to be done. + * @dev_id: The device ID found. + * @pa: optional pointer to store translate frame address. + * + * Returns: 0 for successful devid and pa retrieval, -ENODEV on error + */ +int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *p= a) +{ + struct acpi_iort_node *node, *parent =3D NULL; + struct acpi_iort_its_group *its; + int i, index; + + node =3D iort_find_dev_node(dev); + if (!node) + return -ENODEV; + + index =3D iort_get_id_mapping_index(node); + /* if there is a valid index, go get the dev_id directly */ + if (index >=3D 0) { + parent =3D iort_node_get_id(node, dev_id, index); + } else { + for (i =3D 0; i < node->mapping_count; i++) { + parent =3D iort_node_map_platform_id(node, dev_id, + IORT_MSI_TYPE, i); + if (parent) + break; + } + } + + if (parent && pa) { + int ret; + + its =3D (struct acpi_iort_its_group *)node->node_data; + ret =3D iort_find_its_base(its->identifiers[0], pa); + if (ret) + return ret; + } + + return parent ? 0 : -ENODEV; +} + /** * iort_dev_find_its_id() - Find the ITS identifier for a device * @dev: The device. diff --git a/drivers/irqchip/irq-gic-its-msi-parent.c b/drivers/irqchip/irq= -gic-its-msi-parent.c index 4d1ad1ee005d..a832cdb2e697 100644 --- a/drivers/irqchip/irq-gic-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-its-msi-parent.c @@ -19,18 +19,24 @@ MSI_FLAG_PCI_MSIX | \ MSI_FLAG_MULTI_PCI_MSI) =20 -static int its_translate_frame_address(struct device_node *msi_node, phys_= addr_t *pa) +static int its_translate_frame_address(struct fwnode_handle *msi_node, phy= s_addr_t *pa) { struct resource res; int ret; =20 - ret =3D of_property_match_string(msi_node, "reg-names", "ns-translate"); - if (ret < 0) - return ret; + if (is_of_node(msi_node)) { + struct device_node *msi_np =3D to_of_node(msi_node); =20 - ret =3D of_address_to_resource(msi_node, ret, &res); - if (ret) - return ret; + ret =3D of_property_match_string(msi_np, "reg-names", "ns-translate"); + if (ret < 0) + return ret; + + ret =3D of_address_to_resource(msi_np, ret, &res); + if (ret) + return ret; + } else { + ret =3D iort_its_translate_pa(msi_node, &res.start); + } =20 *pa =3D res.start; return 0; @@ -120,7 +126,7 @@ static int its_v5_pci_msi_prepare(struct irq_domain *do= main, struct device *dev, if (!msi_node) return -ENODEV; =20 - ret =3D its_translate_frame_address(to_of_node(msi_node), &pa); + ret =3D its_translate_frame_address(msi_node, &pa); if (ret) return -ENODEV; =20 @@ -161,7 +167,7 @@ static int of_pmsi_get_msi_info(struct irq_domain *doma= in, struct device *dev, u ret =3D -EINVAL; =20 if (!ret && pa) - ret =3D its_translate_frame_address(it.node, pa); + ret =3D its_translate_frame_address(of_fwnode_handle(it.node), pa); =20 if (!ret) *dev_id =3D args; @@ -176,11 +182,6 @@ static int of_pmsi_get_msi_info(struct irq_domain *dom= ain, struct device *dev, u return of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &msi_c= trl, dev_id); } =20 -int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) -{ - return -1; -} - static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, int nvec, msi_alloc_info_t *info) { @@ -191,7 +192,7 @@ static int its_pmsi_prepare(struct irq_domain *domain, = struct device *dev, if (dev->of_node) ret =3D of_pmsi_get_msi_info(domain->parent, dev, &dev_id, NULL); else - ret =3D iort_pmsi_get_dev_id(dev, &dev_id); + ret =3D iort_pmsi_get_msi_info(dev, &dev_id, NULL); if (ret) return ret; =20 @@ -214,10 +215,10 @@ static int its_v5_pmsi_prepare(struct irq_domain *dom= ain, struct device *dev, u32 dev_id; int ret; =20 - if (!dev->of_node) - return -ENODEV; - - ret =3D of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); + if (dev->of_node) + ret =3D of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); + else + ret =3D iort_pmsi_get_msi_info(dev, &dev_id, &pa); if (ret) return ret; =20 diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-= irs.c index 07c3df5692af..a3a0b270b5be 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -816,8 +816,11 @@ void __init gicv5_irs_its_probe(void) { struct gicv5_irs_chip_data *irs_data; =20 - list_for_each_entry(irs_data, &irs_nodes, entry) - gicv5_its_of_probe(to_of_node(irs_data->fwnode)); + if (acpi_disabled) + list_for_each_entry(irs_data, &irs_nodes, entry) + gicv5_its_of_probe(to_of_node(irs_data->fwnode)); + else + gicv5_its_acpi_probe(); } =20 int __init gicv5_irs_of_probe(struct device_node *parent) diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-= its.c index 554485f0be1f..751ccd88549a 100644 --- a/drivers/irqchip/irq-gic-v5-its.c +++ b/drivers/irqchip/irq-gic-v5-its.c @@ -5,6 +5,8 @@ =20 #define pr_fmt(fmt) "GICv5 ITS: " fmt =20 +#include +#include #include #include #include @@ -1115,7 +1117,7 @@ static int gicv5_its_init_domain(struct gicv5_its_chi= p_data *its, struct irq_dom } =20 static int __init gicv5_its_init_bases(void __iomem *its_base, struct fwno= de_handle *handle, - struct irq_domain *parent_domain) + struct irq_domain *parent_domain, bool noncoherent) { struct device_node *np =3D to_of_node(handle); struct gicv5_its_chip_data *its_node; @@ -1208,7 +1210,8 @@ static int __init gicv5_its_init(struct device_node *= node) } =20 ret =3D gicv5_its_init_bases(its_base, of_fwnode_handle(node), - gicv5_global_data.lpi_domain); + gicv5_global_data.lpi_domain, + of_property_read_bool(node, "dma-noncoherent")); if (ret) goto out_unmap; =20 @@ -1231,3 +1234,128 @@ void __init gicv5_its_of_probe(struct device_node *= parent) pr_err("Failed to init ITS %s\n", np->full_name); } } + +#ifdef CONFIG_ACPI + +#define ACPI_GICV5_ITS_MEM_SIZE (SZ_64K) + +static struct acpi_madt_gicv5_translator *current_its_entry __initdata; +static struct fwnode_handle *current_its_fwnode __initdata; + +static int __init gic_acpi_parse_madt_its_translate(union acpi_subtable_he= aders *header, + const unsigned long end) +{ + struct acpi_madt_gicv5_translate_frame *its_frame; + struct fwnode_handle *msi_dom_handle; + struct resource res =3D {}; + int err; + + its_frame =3D (struct acpi_madt_gicv5_translate_frame *)header; + if (its_frame->linked_translator_id !=3D current_its_entry->translator_id) + return 0; + + res.start =3D its_frame->base_address; + res.end =3D its_frame->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1; + res.flags =3D IORESOURCE_MEM; + + msi_dom_handle =3D irq_domain_alloc_fwnode_parent(&res.start, current_its= _fwnode); + if (!msi_dom_handle) { + pr_err("ITS@%pa: Unable to allocate GICv5 ITS translate domain token\n", + &res.start); + return -ENOMEM; + } + + err =3D iort_register_domain_token(its_frame->translate_frame_id, res.sta= rt, + msi_dom_handle); + if (err) { + pr_err("ITS@%pa: Unable to register GICv5 ITS domain token (ITS TRANSLAT= E FRAME ID %d) to IORT\n", + &res.start, its_frame->translate_frame_id); + irq_domain_free_fwnode(msi_dom_handle); + return err; + } + + return 0; +} + +static int __init gic_acpi_free_madt_its_translate(union acpi_subtable_hea= ders *header, + const unsigned long end) +{ + struct acpi_madt_gicv5_translate_frame *its_frame; + struct fwnode_handle *msi_dom_handle; + + its_frame =3D (struct acpi_madt_gicv5_translate_frame *)header; + if (its_frame->linked_translator_id !=3D current_its_entry->translator_id) + return 0; + + msi_dom_handle =3D iort_find_domain_token(its_frame->translate_frame_id); + if (!msi_dom_handle) + return 0; + + iort_deregister_domain_token(its_frame->translate_frame_id); + irq_domain_free_fwnode(msi_dom_handle); + + return 0; +} + +static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *hea= der, + const unsigned long end) +{ + struct acpi_madt_gicv5_translator *its_entry; + struct fwnode_handle *dom_handle; + struct resource res =3D {}; + void __iomem *its_base; + int err; + + its_entry =3D (struct acpi_madt_gicv5_translator *)header; + res.start =3D its_entry->base_address; + res.end =3D its_entry->base_address + ACPI_GICV5_ITS_MEM_SIZE - 1; + res.flags =3D IORESOURCE_MEM; + + if (!request_mem_region(res.start, resource_size(&res), "GICv5 ITS")) + return -EBUSY; + + dom_handle =3D irq_domain_alloc_fwnode(&res.start); + if (!dom_handle) { + pr_err("ITS@%pa: Unable to allocate GICv5 ITS domain token\n", + &res.start); + err =3D -ENOMEM; + goto out_rel_res; + } + + current_its_entry =3D its_entry; + current_its_fwnode =3D dom_handle; + + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE, + gic_acpi_parse_madt_its_translate, 0); + + its_base =3D ioremap(res.start, ACPI_GICV5_ITS_MEM_SIZE); + if (!its_base) { + err =3D -ENOMEM; + goto out_unregister; + } + + err =3D gicv5_its_init_bases(its_base, dom_handle, gicv5_global_data.lpi_= domain, + its_entry->flags & ACPI_MADT_GICV5_ITS_NON_COHERENT); + if (err) + goto out_unmap; + + return 0; + +out_unmap: + iounmap(its_base); +out_unregister: + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE, + gic_acpi_free_madt_its_translate, 0); + irq_domain_free_fwnode(dom_handle); +out_rel_res: + release_mem_region(res.start, resource_size(&res)); + return err; +} + +void __init gicv5_its_acpi_probe(void) +{ + acpi_table_parse_madt(ACPI_MADT_TYPE_GICV5_ITS, gic_acpi_parse_madt_its, = 0); +} +#else +void __init gicv5_its_acpi_probe(void) { } +#endif diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index 3136341e802c..25fcc2114803 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -402,6 +402,8 @@ u32 pci_msi_map_rid_ctlr_node(struct irq_domain *domain= , struct pci_dev *pdev, rid =3D of_msi_xlate(&pdev->dev, &msi_ctlr_node, rid); if (msi_ctlr_node) *node =3D of_fwnode_handle(msi_ctlr_node); + } else { + rid =3D iort_msi_xlate(&pdev->dev, rid, node); } =20 return rid; diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index d4ed5622cf2b..2d22268677a9 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -27,12 +27,14 @@ int iort_register_domain_token(int trans_id, phys_addr_= t base, struct fwnode_handle *fw_node); void iort_deregister_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id); -int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); =20 #ifdef CONFIG_ACPI_IORT u32 iort_msi_map_id(struct device *dev, u32 id); +u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode_handle **node= ); +int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base); struct irq_domain *iort_get_device_domain(struct device *dev, u32 id, enum irq_domain_bus_token bus_token); +int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *p= a); void acpi_configure_pmsi_domain(struct device *dev); void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_head *head); @@ -46,9 +48,15 @@ phys_addr_t acpi_iort_dma_get_max_cpu_address(void); #else static inline u32 iort_msi_map_id(struct device *dev, u32 id) { return id; } +static inline u32 iort_msi_xlate(struct device *dev, u32 id, struct fwnode= _handle **node) +{ return id; } +static inline int iort_its_translate_pa(struct fwnode_handle *node, phys_a= ddr_t *base) +{ return -ENODEV; } static inline struct irq_domain *iort_get_device_domain( struct device *dev, u32 id, enum irq_domain_bus_token bus_token) { return NULL; } +static inline int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, = phys_addr_t *pa) +{ return -ENODEV; } static inline void acpi_configure_pmsi_domain(struct device *dev) { } static inline void iort_get_rmr_sids(struct fwnode_handle *iommu_fwnode, struct list_hea= d *head) { } diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm= -gic-v5.h index ff5b1a4931d7..334b6986435c 100644 --- a/include/linux/irqchip/arm-gic-v5.h +++ b/include/linux/irqchip/arm-gic-v5.h @@ -392,4 +392,5 @@ int gicv5_alloc_lpi(void); void gicv5_free_lpi(u32 lpi); =20 void __init gicv5_its_of_probe(struct device_node *parent); +void __init gicv5_its_acpi_probe(void); #endif --=20 2.50.1 From nobody Sat Feb 7 18:21:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 205C033F37B; Thu, 18 Dec 2025 10:15:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052939; cv=none; b=qB+YO1P4kcwBvmht4Uj6+L5ANj/ykpxKvAUj9tpnFV6kmb705TVJf3EEXWKy/sfTkW4w4hMZuLg9sm7OYa14wpPVfxEOUFd21LPe3QHkmEbOW4JzMN2ixewQewbj3o+ckjBCRDFC7OUF1AV3mURR3HKEp16FY36ZTd4t38LNvOA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766052939; c=relaxed/simple; bh=nTj9AwGWa68OxCQB2ktt6UeErE1xFTjgXOQwZaEU084=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t1XKLFomQb4RzUN0SNS1iDjMz2VhmG1Vdu207OawflNTm+5wRodLE0+uGUoaapEP4OaHgyHoxKJqekk3pDcBIaTnuOJGD2BjwVv/cB6sjf34pPSBzOjXpxrf2M819dzRMoCSgho55UyuvgNRQ5qHBMUcgdnUVEnrjRXCnQEKqrM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iVGVHrKa; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iVGVHrKa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EDA6CC116C6; Thu, 18 Dec 2025 10:15:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766052939; bh=nTj9AwGWa68OxCQB2ktt6UeErE1xFTjgXOQwZaEU084=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=iVGVHrKankckqVetezOf6ZpRVgN2+0U+Ps7lIpaDUegsDIKXYDF/QqPxOa40l9FJI xcw2vbI3gged1gJ7N95KwKPdw/r/cHgOnpKTXZTQf4PZlRNBnaTPHW8IjsFmU+5h/1 VxLzD/ynhiKwn1VwaHAiyhOwxGBuGzQfk4e2U8CxqmO50syPhk9EgF+sixO0sWL8AA NXAAsHk6w77vB4iUpAa7zFbvr2hNJ+Om4ymdVxoisca2EWJ5PSb//KA8mb6YXg6HjU BLlopX6cOV902Frm4RnAKpWeIuW2KFOXZNbwgbPQUsog0grGnYPmdfx73GWdkQxjQb zOEYxrRSVLbAQ== From: Lorenzo Pieralisi Date: Thu, 18 Dec 2025 11:14:33 +0100 Subject: [PATCH v2 7/7] irqchip/gic-v5: Add ACPI IWB probing Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251218-gicv5-host-acpi-v2-7-eec76cd1d40b@kernel.org> References: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> In-Reply-To: <20251218-gicv5-host-acpi-v2-0-eec76cd1d40b@kernel.org> To: "Rafael J. Wysocki" , Len Brown , Robert Moore , Thomas Gleixner , Hanjun Guo , Sudeep Holla , Marc Zyngier , Bjorn Helgaas Cc: linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, Lorenzo Pieralisi X-Mailer: b4 0.14.3 To probe an IWB in an ACPI based system it is required: - to implement the IORT functions handling the IWB IORT node and create functions to retrieve IWB firmware information - to augment the driver to match the DSDT ACPI "ARMH0003" device and retrieve the IWB wire and trigger mask from the GSI interrupt descriptor in the IWB msi_domain_ops.msi_translate() function Make the required driver changes to enable IWB probing in ACPI systems. The GICv5 GSI format requires special handling for IWB routed IRQs. Add IWB GSI detection to the top level driver gic_v5_get_gsi_domain_id() function so that the correct IRQ domain for a GSI can be detected by parsing the GSI and check whether it is an IWB-backed IRQ or not. Signed-off-by: Lorenzo Pieralisi Cc: Thomas Gleixner Cc: Hanjun Guo Cc: Sudeep Holla Cc: Marc Zyngier Reviewed-by: Jonathan Cameron --- drivers/acpi/arm64/iort.c | 95 ++++++++++++++++++++++++++++++++--= ---- drivers/irqchip/irq-gic-v5-iwb.c | 42 +++++++++++++---- drivers/irqchip/irq-gic-v5.c | 4 ++ include/linux/acpi_iort.h | 1 + include/linux/irqchip/arm-gic-v5.h | 6 +++ 5 files changed, 123 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 17dbe66da804..4b0b753db738 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -264,39 +264,47 @@ static acpi_status iort_match_node_callback(struct ac= pi_iort_node *node, struct device *dev =3D context; acpi_status status =3D AE_NOT_FOUND; =20 - if (node->type =3D=3D ACPI_IORT_NODE_NAMED_COMPONENT) { + if (node->type =3D=3D ACPI_IORT_NODE_NAMED_COMPONENT || + node->type =3D=3D ACPI_IORT_NODE_IWB) { struct acpi_buffer buf =3D { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_device *adev; struct acpi_iort_named_component *ncomp; - struct device *nc_dev =3D dev; + struct acpi_iort_iwb *iwb; + struct device *cdev =3D dev; + struct acpi_device *adev; + const char *device_name; =20 /* * Walk the device tree to find a device with an * ACPI companion; there is no point in scanning - * IORT for a device matching a named component if + * IORT for a device matching a named component or IWB if * the device does not have an ACPI companion to * start with. */ do { - adev =3D ACPI_COMPANION(nc_dev); + adev =3D ACPI_COMPANION(cdev); if (adev) break; =20 - nc_dev =3D nc_dev->parent; - } while (nc_dev); + cdev =3D cdev->parent; + } while (cdev); =20 if (!adev) goto out; =20 status =3D acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf); if (ACPI_FAILURE(status)) { - dev_warn(nc_dev, "Can't get device full path name\n"); + dev_warn(cdev, "Can't get device full path name\n"); goto out; } =20 - ncomp =3D (struct acpi_iort_named_component *)node->node_data; - status =3D !strcmp(ncomp->device_name, buf.pointer) ? - AE_OK : AE_NOT_FOUND; + if (node->type =3D=3D ACPI_IORT_NODE_NAMED_COMPONENT) { + ncomp =3D (struct acpi_iort_named_component *)node->node_data; + device_name =3D ncomp->device_name; + } else { + iwb =3D (struct acpi_iort_iwb *)node->node_data; + device_name =3D iwb->device_name; + } + status =3D !strcmp(device_name, buf.pointer) ? AE_OK : AE_NOT_FOUND; acpi_os_free(buf.pointer); } else if (node->type =3D=3D ACPI_IORT_NODE_PCI_ROOT_COMPLEX) { struct acpi_iort_root_complex *pci_rc; @@ -317,12 +325,28 @@ static acpi_status iort_match_node_callback(struct ac= pi_iort_node *node, return status; } =20 +static acpi_status iort_match_iwb_callback(struct acpi_iort_node *node, vo= id *context) +{ + acpi_status status =3D AE_NOT_FOUND; + u32 *id =3D context; + + if (node->type =3D=3D ACPI_IORT_NODE_IWB) { + struct acpi_iort_iwb *iwb; + + iwb =3D (struct acpi_iort_iwb *)node->node_data; + status =3D iwb->iwb_index =3D=3D *id ? AE_OK : AE_NOT_FOUND; + } + + return status; +} + static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_= in, u32 *rid_out, bool check_overlap) { /* Single mapping does not care for input id */ if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { if (type =3D=3D ACPI_IORT_NODE_NAMED_COMPONENT || + type =3D=3D ACPI_IORT_NODE_IWB || type =3D=3D ACPI_IORT_NODE_PCI_ROOT_COMPLEX) { *rid_out =3D map->output_base; return 0; @@ -392,6 +416,7 @@ static struct acpi_iort_node *iort_node_get_id(struct a= cpi_iort_node *node, =20 if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { if (node->type =3D=3D ACPI_IORT_NODE_NAMED_COMPONENT || + node->type =3D=3D ACPI_IORT_NODE_IWB || node->type =3D=3D ACPI_IORT_NODE_PCI_ROOT_COMPLEX || node->type =3D=3D ACPI_IORT_NODE_SMMU_V3 || node->type =3D=3D ACPI_IORT_NODE_PMCG) { @@ -562,9 +587,14 @@ static struct acpi_iort_node *iort_find_dev_node(struc= t device *dev) return node; /* * if not, then it should be a platform device defined in - * DSDT/SSDT (with Named Component node in IORT) + * DSDT/SSDT (with Named Component node in IORT) or an + * IWB device in the DSDT/SSDT. */ - return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + node =3D iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (node) + return node; + return iort_scan_node(ACPI_IORT_NODE_IWB, iort_match_node_callback, dev); } =20 @@ -756,6 +786,35 @@ struct irq_domain *iort_get_device_domain(struct devic= e *dev, u32 id, return irq_find_matching_fwnode(handle, bus_token); } =20 +struct fwnode_handle *iort_iwb_handle(u32 iwb_id) +{ + struct fwnode_handle *fwnode; + struct acpi_iort_node *node; + struct acpi_device *device; + struct acpi_iort_iwb *iwb; + acpi_status status; + acpi_handle handle; + + /* find its associated IWB node */ + node =3D iort_scan_node(ACPI_IORT_NODE_IWB, iort_match_iwb_callback, &iwb= _id); + if (!node) + return NULL; + + iwb =3D (struct acpi_iort_iwb *)node->node_data; + status =3D acpi_get_handle(NULL, iwb->device_name, &handle); + if (ACPI_FAILURE(status)) + return NULL; + + device =3D acpi_get_acpi_dev(handle); + if (!device) + return NULL; + + fwnode =3D acpi_fwnode_handle(device); + acpi_put_acpi_dev(device); + + return fwnode; +} + static void iort_set_device_domain(struct device *dev, struct acpi_iort_node *node) { @@ -816,8 +875,14 @@ static struct irq_domain *iort_get_platform_device_dom= ain(struct device *dev) /* find its associated iort node */ node =3D iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, iort_match_node_callback, dev); - if (!node) - return NULL; + if (!node) { + /* find its associated iort node */ + node =3D iort_scan_node(ACPI_IORT_NODE_IWB, + iort_match_node_callback, dev); + + if (!node) + return NULL; + } =20 /* then find its msi parent node */ for (i =3D 0; i < node->mapping_count; i++) { diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-= iwb.c index ad9fdc14d1c6..c7d5fd34d053 100644 --- a/drivers/irqchip/irq-gic-v5-iwb.c +++ b/drivers/irqchip/irq-gic-v5-iwb.c @@ -4,6 +4,7 @@ */ #define pr_fmt(fmt) "GICv5 IWB: " fmt =20 +#include #include #include #include @@ -136,18 +137,31 @@ static int gicv5_iwb_irq_domain_translate(struct irq_= domain *d, struct irq_fwspe irq_hw_number_t *hwirq, unsigned int *type) { - if (!is_of_node(fwspec->fwnode)) - return -EINVAL; + if (is_of_node(fwspec->fwnode)) { =20 - if (fwspec->param_count < 2) - return -EINVAL; + if (fwspec->param_count < 2) + return -EINVAL; =20 - /* - * param[0] is be the wire - * param[1] is the interrupt type - */ - *hwirq =3D fwspec->param[0]; - *type =3D fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + /* + * param[0] is be the wire + * param[1] is the interrupt type + */ + *hwirq =3D fwspec->param[0]; + *type =3D fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + } + + if (is_acpi_device_node(fwspec->fwnode)) { + + if (fwspec->param_count < 2) + return -EINVAL; + + /* + * Extract the wire from param[0] + * param[1] is the interrupt type + */ + *hwirq =3D FIELD_GET(GICV5_GSI_IWB_WIRE, fwspec->param[0]); + *type =3D fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + } =20 return 0; } @@ -265,10 +279,18 @@ static const struct of_device_id gicv5_iwb_of_match[]= =3D { }; MODULE_DEVICE_TABLE(of, gicv5_iwb_of_match); =20 +#ifdef CONFIG_ACPI +static const struct acpi_device_id iwb_acpi_match[] =3D { + { "ARMH0003", 0 }, + {} +}; +#endif + static struct platform_driver gicv5_iwb_platform_driver =3D { .driver =3D { .name =3D "GICv5 IWB", .of_match_table =3D gicv5_iwb_of_match, + .acpi_match_table =3D ACPI_PTR(iwb_acpi_match), .suppress_bind_attrs =3D true, }, .probe =3D gicv5_iwb_device_probe, diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 23fd551c4347..da867dd2e77d 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -5,6 +5,7 @@ =20 #define pr_fmt(fmt) "GICv5: " fmt =20 +#include #include #include #include @@ -1187,6 +1188,9 @@ static struct fwnode_handle *gsi_domain_handle; =20 static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi) { + if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) =3D=3D GICV5_GSI_IWB_TYPE) + return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi)); + return gsi_domain_handle; } =20 diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 2d22268677a9..17bb3374f4ca 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -27,6 +27,7 @@ int iort_register_domain_token(int trans_id, phys_addr_t = base, struct fwnode_handle *fw_node); void iort_deregister_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id); +struct fwnode_handle *iort_iwb_handle(u32 iwb_id); =20 #ifdef CONFIG_ACPI_IORT u32 iort_msi_map_id(struct device *dev, u32 id); diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm= -gic-v5.h index 334b6986435c..3da1ad80fc9d 100644 --- a/include/linux/irqchip/arm-gic-v5.h +++ b/include/linux/irqchip/arm-gic-v5.h @@ -265,6 +265,12 @@ =20 #define GICV5_IWB_WENABLE_STATUSR_IDLE BIT(0) =20 +#define GICV5_GSI_IC_TYPE GENMASK(31, 29) +#define GICV5_GSI_IWB_TYPE 0x7 + +#define GICV5_GSI_IWB_FRAME_ID GENMASK(28, 16) +#define GICV5_GSI_IWB_WIRE GENMASK(15, 0) + /* * Global Data structures and functions */ --=20 2.50.1