From nobody Mon Feb 9 03:13:40 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 3975C1E49F; Tue, 28 Oct 2025 10:19:15 +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=1761646757; cv=none; b=tmBC+XAf8gzhEBkx4tz+Y1LE7fCBYDcyp4CkH+tffsbd6sJb9SpG6qnJnkVSeAbbt7Zpgi3HBggPJxQ4c/2ooys8oSn8tQdUJ2t8zLoau6kRmjiwHVBsh6VE4MHFMtrOWbdzbwv2zZroPG99jsIy5Y4NftKyZcRBNVuF+b5Di+Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646757; c=relaxed/simple; bh=p0f8Rraz0GV8UR1BJMRxEm3oPPAlcgLESwykdG885Gw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=K/FFEc0IC4jWtNfmLfVyhhTb0cTgCZNoiY/aMDG8PgpcqETx+8XolmuVndv24PIII3IPGrPbYPV4nBaEezp1OC+wNjryOjVQoajuWF3caGQyb4Ae3R0kuQm4z9derBGNHiKC8PePCLka5j73qoBDGn/ee1V7ZG2Kq6IhumHYQ2o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GQucdflx; 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="GQucdflx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6A326C4CEE7; Tue, 28 Oct 2025 10:19:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646755; bh=p0f8Rraz0GV8UR1BJMRxEm3oPPAlcgLESwykdG885Gw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=GQucdflxoAT6wN5gUDaAL3dd/tLnvPZUHy/uGZXsPU2FJmAdHVwS6Ll7ETXQLUkVW iBBvOth0poTp3vDrGRsr19znYXRsIjJ8VvkJrNyX19kx/kPlpB6nq8irrukHFKMJTA maOkAI1gxO41cR1iBmf117RMxrQbPCPq/aqvCVkPDjn34KW41DiJpb1/QfM32RcLom m9wyxi4XtaC2kh9chbTujIKmahtMoRCnSMNQcivqiA/yGm/5faO5ZVkl4pxJ7y2oDb kD3EWS3yf9nnq0pD/xCz4G/VH3Fl3IZicVNr/xNRFlBltyzGwdBSfsXoU1q1HPUfoF 289BHJvUWeNIg== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:18:59 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-1-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 ACPICA commit 3996a7eec0ded24b22fa2098fb63f4805a3e809c 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/3996a7ee Signed-off-by: Jose Marinho 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 Mon Feb 9 03:13:40 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 3E96D1D31B9; Tue, 28 Oct 2025 10:19:20 +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=1761646761; cv=none; b=ayBO9Xf6kUpurbEg/ti8LO7gzHCZ3dsdVKL6a20wtXvUVaOoUdGJ870uVW/fHcH0VncXX9CDXZAvDSw8i09/AIDk68wQFn7ndEPJQcqqwH9lw5WxIWDUtTP+D9YISuKsv4jfXiFiyoG3QiGks1utGlcW8BYyU6jisXxAnFD3JXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646761; c=relaxed/simple; bh=KkOSLYci++vNRNEQTXDYGgJqFXUhVXvlHo6io3wLa/k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qIMRY3I62vxW58TrfwiVUX0EQdmS074PL9W4SMKqCYFdZueTk+rA3hcXysqhf609XBbWIjMYW2YK40pnMhWp467HRXVPp/JeiD+SuLkNq+dW9VOMWU6jlRkTEJTh+7+k1ivi+st7V+vnG5b7897xBworFutNUGAgkog0/s+1Is0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cPuh0EB0; 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="cPuh0EB0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 73ED4C4CEF7; Tue, 28 Oct 2025 10:19:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646760; bh=KkOSLYci++vNRNEQTXDYGgJqFXUhVXvlHo6io3wLa/k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=cPuh0EB0azQbYctGin8hqnUkPiYwN2MTm0rtBoagUm5KGBcfPOxcUIRMkkiPWhlbg 9nXKlDYoqPaGGRTLqqNsUiJ7EV4vHI/7s1ImXFl3lDsy/nJ/VQtjxgtLdmMdPPjbzC /IO6krhU/I6Qh91mifyLsmQxD00sHLn0t3iJZn7yU42/4d8T+ed6pM89Gfaf00CNpx x4Wr4gV1N3YR+euOSAdoxcOZ7+qf+6unzfRiHWVLYoUM0eIHbaC1DIgoEccjxTRRD2 AmoUtju3D2HfCFAbTnFSKM9+XRKKsa1MSBqb8WK/4LpHZC8NC2p7nFMjpjHolOny9H TjjoTaXS5vC/w== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:00 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-2-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 ACPICA commit d68693b24e5235a7da4d57e690d3c13380c14c16 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/d68693b2 Signed-off-by: Jose Marinho 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 Mon Feb 9 03:13:40 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 D2503302177; Tue, 28 Oct 2025 10:19:25 +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=1761646765; cv=none; b=q8r98VAoP78HroQj7zmUPp0CrioQMZK7S7PU6JxgfhHL+DrAXg7K74g7fl0KBiVSPLj2JdMU/pG6p9mZqVnd/mXfqA28c4rdgI/RGmLBfUAblSifUX9Yn83EP4N1c8KVtcFDb8zqFhJJYaNIRYrkJ2AxYjoOzx5FwzUocQ1Qj0s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646765; c=relaxed/simple; bh=mcD+09JpIvqsqebTYtxhjCLGrP7RjNZxDg9R66+62F0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BVJGHyMo9olXdxjVgRncilXoAIz55y892s31Xqufnh4QlOx7ccvfyqSoMI6hIHXS/XnNt2GkxOzpst6z/RS1Kq6/BBSm0fJJJt4JpJjylhxOb/z6lA3msF0rYo5iyRwk9GK7OLJEQbe5+1oIsGkQZhlAIF1SO3mJ2CYNbh7Hxa8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kla7tCnv; 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="kla7tCnv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5BB06C116C6; Tue, 28 Oct 2025 10:19:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646765; bh=mcD+09JpIvqsqebTYtxhjCLGrP7RjNZxDg9R66+62F0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=kla7tCnv0JF9dJLj5VYpCy7ya63VZlpgFQ9vzNir/y5fmztD5BP+IbFu5JIx1hW+U dfP8v3x2mb0sUZys0r9JADSCWgLJbS+PD3H66cKDCGX+kgcgjuFVBK8uslWWowy7Jw j1cIwQC6qRv8+VoEBLCDzaExBcBkFmYnVKL3VsZO3yR7DW60GTz76GmbGS8MVxQpfh pcXEqwqlkYM4Gr7diLckHcobZvtFZ7FevYdDswOvNIu2d4IXr3k5tOybI9oylKhDJ7 F2nRrmtn1xtfLjaTfNsnILZtRGSLwLS2PhNynjgjIvCSX293ULBzJljuOzN+HLoHSS HitGoNQI54QQg== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:01 +0100 Subject: [PATCH not for merging 3/7] irqdomain: Add parent field to 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: <20251028-gicv5-host-acpi-v1-3-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 4a86e6b915dd..289a390ccbe6 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -236,7 +236,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, @@ -246,18 +247,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 dc473faadcc8..a6e159785cc2 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 Mon Feb 9 03:13:40 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 0EE352C3770; Tue, 28 Oct 2025 10:19:30 +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=1761646771; cv=none; b=CrOiREDGCen7yYf+YC6mt+qYzvyyrMtLSm5y3NtzSTHLJzOfxjHlTbuB7LDtKnkaHH/FmJluPVUahSnzQZO43oigk7ct7xEP9MX4ejtMV/RcMrIjoo/r4gydD0kVe3jUaN4FeVVY3n7Ew5JiuAlJoJauzvkvnhCUUPX16QdmTqg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646771; c=relaxed/simple; bh=rD3Szlqc7Z0x3k0SP/scHjSXL5BaHqvTEadpp6jc/pU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Qf09tkOUjQZ2KL4xfGa69Us/WzB7JH2S5r9WmxJy4zhJCS+ztVEjyJWm1Vuu8IFvTA9AeVBqYC0WvX/KXJJrcc7hIr5otx/7H1FbFZznrPpcAdIibdOzoAcU90Do15i0u4QwcqHKwIy/KvCR6ypACuogbj35VyTu4lLoet98OQc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Xn24dFg5; 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="Xn24dFg5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1C70BC116B1; Tue, 28 Oct 2025 10:19:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646770; bh=rD3Szlqc7Z0x3k0SP/scHjSXL5BaHqvTEadpp6jc/pU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Xn24dFg5oBUGL/jI1D0BK6jlkG/Lqkt3g4h92UIzYCervftU3CSzfm+GCkE3iF65g dCn5C3Uq4e52R+5j64h8QkpOU6R2+ZSmbzNwBMidibn9ww8RPAh/Dnh05S1nAgTlJD iGCA0bK5nhsfNdwhews0PVvyYrJgg+o4lTlJfG/QwGYu9NZNOxGEmE12VFVtDpQvSW 1zPXKl16InDuVofp4mzb4i5GtUjcCWv0XnQJYSpYOtWz+IDdgaxZ3xDCE/UHTEZIN5 EscM72yqQdV1qWLO1dSkrbyipmC78Gl4QzbIkmaaxmGOOPq2I95M3qxVy7AROo+LH6 1srdGbPCgBLoQ== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:02 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-4-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 --- 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 eb1473f1448a..87b0e33870da 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 ce741ed9dc3f..d10b72aff1ee 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -466,23 +466,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 d415dd15a0a9..7513db929cbc 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -705,7 +705,8 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwn= ode_handle *fwnode, struct msi_domain_info *info, struct irq_domain *parent); 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 Mon Feb 9 03:13:40 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 4FDC5304BC9; Tue, 28 Oct 2025 10:19:35 +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=1761646776; cv=none; b=ZBoLe76jKaXQ6D8xpg1VMOF7ux/syk1WSdAafcnrxHS/mN1hCwADJre2q/LRHVAzr744A7lEQZkeRF10MRqQxcEMgoDrG2P2kmF8gQ3Rj/Kz//2IcXgf69mSgwsU9nFumaW5xdXgTwVWR3C8mINsIvcefMM5pOwJSJsT8tBq9G4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646776; c=relaxed/simple; bh=z8yy7XPRc2lhhR5v6Wo+qIfn06ry075Dh1q9MHuSbqo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sJ7+yEK09kgeRjKuI1qDnJVCE2Rs2UEMdRjWWsvXMyRJTi19IXOKlqM4hgat7bxgiPYnYSJitX+VqysxzoMZ7F3z2FKPbc51vpmY3JMkCdQcbYtMW/maoH/2HPIcEwqoPYTXl1anr7sVTDhr2vKx0Ee5wwB3HQHMH+0wI1ieCmU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=t2m72fhR; 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="t2m72fhR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 161AAC4CEF7; Tue, 28 Oct 2025 10:19:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646775; bh=z8yy7XPRc2lhhR5v6Wo+qIfn06ry075Dh1q9MHuSbqo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=t2m72fhR+DcUrcrAo3SMtGCVaR0Jd4YrZ5zdXeeKcmbW4VUNqNi9gMNB9cBGaq3rP ej4+aibkXERZvbctj7noDGbF1FKgdDdkypT1yWs3Y0OiTs9R2XBFQ9oRC3Zf7aRuC3 eBhFZF3fCbtklfnakrkKcQwpaReaJV/meQd5Da4x9GJm34UOLzu/IkcDIge6+xlEin VeRMPhydXZ6kU+aq0IjHFC2oATxpfd5T4ZLfzXjko0eAeA0jhac0mKPaxgfimOO2fY UIDbioWT0auCvYWZFsZY3z9R7FaaYJMRgUJr+qIbwN+td6xIuP6C6/nvpqVKVA/Opw MuVMK53mAWBgw== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:03 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-5-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 | 240 +++++++++++++++++++++++++++++----= ---- drivers/irqchip/irq-gic-v5.c | 134 ++++++++++++++++++--- include/linux/acpi.h | 1 + include/linux/irqchip/arm-gic-v5.h | 1 + 5 files changed, 309 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..a28c88480f82 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,137 @@ 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); + + /* Get distributor base address */ + 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 5ff5d99f6ead..58b75084c976 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -106,6 +106,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 Mon Feb 9 03:13:40 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 EEAAC3054E8; Tue, 28 Oct 2025 10:19:40 +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=1761646781; cv=none; b=KLPeIW1+sJiNGxwaTV+U4Ol36F813yIsN3s+fqR2bYLOoZwM9DxQBlKJQJAi/ZdmRsGtXzV8T55oIxQc0RBlTxtVKCqkOA6jpa+B7oCgfqpTIwPrfx5OOWhdMflijXMhXNQck9LnwLun4pvp4X2RphqWSHRfRjFZEBKxwCzQu5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646781; c=relaxed/simple; bh=VZs/7JkOM8RctA6XNfyoB1M+17AdU2S3QKfbDy5c3AU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uxgzgzPufN6QqW2auFhrxRxXXfZiMxbZII4/Eh8alhprWo38bP6Vjgn+O1mJYd0Up3OEzilvDAM0S3iJpf5e3SUbriefqz66mSLFPEB3BU6MDwXY6T1KmmmvzV4INquRIP8zvoQIN+5i9vmvZ4XNADHcrz2IGRSz73AD4yrR+2g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RbbqS54v; 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="RbbqS54v" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67A80C116B1; Tue, 28 Oct 2025 10:19:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646780; bh=VZs/7JkOM8RctA6XNfyoB1M+17AdU2S3QKfbDy5c3AU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RbbqS54vpJQXY7vEkgJcnyfNBWErqxJqgDcd9FNzplBrrml2sJ2P10qcJH+AIe5UL FnMPjCmhdeGdAAkSY8a2MwxSHYcWgxKTJHodIAlyqm3znyOf77rTBN5qd/NgDQonVc T0Tk2RJnLHBrZp6T7XPBwT10eXOQSrYfIWzLfrg6IlCcoh8uL0XHm4d8lrSyWcoJ5x ZtCPeGON3EGeElS2NZiSYXO+u7iQ7bdt8tTRx3xNgNOkxkuFTYaAGsZhJfYroW/HYs KKvs7lZUO7KmRxYuIWt4SGPpHFRUYrax5l74hCsUQxl2aV7y8qwKpycvfcZxxLo7MD HlP4gM9d4nZXA== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:04 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-6-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 --- drivers/acpi/arm64/iort.c | 95 +++++++++++++++++----- drivers/irqchip/irq-gic-its-msi-parent.c | 41 +++++----- 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, 242 insertions(+), 46 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 65f0f56ad753..7354760cad5d 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 -ENXIO; =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 -ENXIO; =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 87b0e33870da..3bc4cf8f64e4 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 @@ -200,7 +206,7 @@ static int of_v5_pmsi_get_msi_info(struct irq_domain *d= omain, struct device *dev return -EINVAL; *dev_id =3D args.args[0]; =20 - ret =3D its_translate_frame_address(args.np, pa); + ret =3D its_translate_frame_address(of_fwnode_handle(args.np), pa); if (ret) return -ENODEV; break; @@ -213,7 +219,7 @@ static int of_v5_pmsi_get_msi_info(struct irq_domain *d= omain, struct device *dev =20 ret =3D of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np,= dev_id); if (np) { - ret =3D its_translate_frame_address(np, pa); + ret =3D its_translate_frame_address(of_fwnode_handle(np), pa); of_node_put(np); } } @@ -221,11 +227,6 @@ static int of_v5_pmsi_get_msi_info(struct irq_domain *= domain, struct device *dev return ret; } =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) { @@ -236,7 +237,7 @@ static int its_pmsi_prepare(struct irq_domain *domain, = struct device *dev, if (dev->of_node) ret =3D of_pmsi_get_dev_id(domain->parent, dev, &dev_id); 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 @@ -259,10 +260,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_v5_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); + if (dev->of_node) + ret =3D of_v5_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 a28c88480f82..01af03c3c8ee 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 d10b72aff1ee..539aed2e0630 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -492,6 +492,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 Mon Feb 9 03:13:40 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 12937307ACA; Tue, 28 Oct 2025 10:19:45 +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=1761646786; cv=none; b=WzobO5LSvI6aJG3DKgOK/uIp/4VXICEjDrMgPKp69I5a4iWkLddrJ8PEIO+BNo03oOAaPGg98o7CbS1JNIWjxsm78OlAepk/zbaQu8K4k0G9mRQBQOHCha5iBR+a2j/w1ZawW9X4xMITn2Xi7c5ydf5LeHVupfw5q3bpQL6sTlQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761646786; c=relaxed/simple; bh=minlv4Mdvyv58h6PsDl8RTUVTBPlA8ZCb/VHYefz728=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Gcc5wOhfeBkBNriP4NhisvOukVDv/wfx5pO7uTGj62xufyA4F2D2KNlF/zFz9MPeFMnK2vm1U/yUxEdGDTDV8ypk5Y9DTmamGXuKI4DXwliA7xbXWBOr2CSifp7GAYDkabOEd9Iz/WFzJq0AI4z5p5D3AqfI2akCdPOsQuIOQ1g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rE6jA4kB; 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="rE6jA4kB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 390BCC4CEE7; Tue, 28 Oct 2025 10:19:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761646785; bh=minlv4Mdvyv58h6PsDl8RTUVTBPlA8ZCb/VHYefz728=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=rE6jA4kBM/6yhoGJSJ5ecD8L3pv7MXwX0H6hSlr0/gP1I8sJQpdnQfzsFedwcwNWA GUbOchBgOVDZtiJvLfkEKXNjYmJ9xYPA1c8qkL4WPbfQKKxJHVz72x5dNgSQT3CyUE /Uc4ZOZDeOTiplsYI5fsrsPiXEgBdVGybh4Vw6mcVSp7OyOJ9TX1CWK4abXQwV81BE 4Ue6d9caBSS4hqka6ZCoe+zo05RV0+BmgnDq2Y2u7ON0agkCGOh2eD0w70ktt0APHG I4bGK9QtJq1vQZ+Rdt8o7IR3MLxrlxNZU6JJg/E+W00XTT4CAjj5mnAMYbVAOHIc1l UGncB2jrLmtww== From: Lorenzo Pieralisi Date: Tue, 28 Oct 2025 11:19:05 +0100 Subject: [PATCH not for merging 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: <20251028-gicv5-host-acpi-v1-7-01a862feb5ca@kernel.org> References: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@kernel.org> In-Reply-To: <20251028-gicv5-host-acpi-v1-0-01a862feb5ca@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 --- 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 7354760cad5d..76ec31d385cd 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..f6f3d30cbc99 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; + + /* + * param[0] is the wire + * 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