2022-06-15 06:25:39

by 吕建民

[permalink] [raw]
Subject: [PATCH V12 00/10] irqchip: Add LoongArch-related irqchip drivers

LoongArch is a new RISC ISA, which is a bit like MIPS or RISC-V.
LoongArch includes a reduced 32-bit version (LA32R), a standard 32-bit
version (LA32S) and a 64-bit version (LA64). LoongArch use ACPI as its
boot protocol LoongArch-specific interrupt controllers (similar to APIC)
are already added in the ACPI Specification 6.5(which may be published in
early June this year and the board is reviewing the draft).

Currently, LoongArch based processors (e.g. Loongson-3A5000) can only
work together with LS7A chipsets. The irq chips in LoongArch computers
include CPUINTC (CPU Core Interrupt Controller), LIOINTC (Legacy I/O
Interrupt Controller), EIOINTC (Extended I/O Interrupt Controller),
HTVECINTC (Hyper-Transport Vector Interrupt Controller), PCH-PIC (Main
Interrupt Controller in LS7A chipset), PCH-LPC (LPC Interrupt Controller
in LS7A chipset) and PCH-MSI (MSI Interrupt Controller).

CPUINTC is a per-core controller (in CPU), LIOINTC/EIOINTC/HTVECINTC are
per-package controllers (in CPU), while PCH-PIC/PCH-LPC/PCH-MSI are all
controllers out of CPU (i.e., in chipsets). These controllers (in other
words, irqchips) are linked in a hierarchy, and there are two models of
hierarchy (legacy model and extended model).

Legacy IRQ model:

In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
gathered by HTVECINTC, and then go to LIOINTC, and then CPUINTC.

+---------------------------------------------+
| |
| +-----+ +---------+ +-------+ |
| | IPI | --> | CPUINTC | <-- | Timer | |
| +-----+ +---------+ +-------+ |
| ^ |
| | |
| +---------+ +-------+ |
| | LIOINTC | <-- | UARTs | |
| +---------+ +-------+ |
| ^ |
| | |
| +-----------+ |
| | HTVECINTC | |
| +-----------+ |
| ^ ^ |
| | | |
| +---------+ +---------+ |
| | PCH-PIC | | PCH-MSI | |
| +---------+ +---------+ |
| ^ ^ ^ |
| | | | |
| +---------+ +---------+ +---------+ |
| | PCH-LPC | | Devices | | Devices | |
| +---------+ +---------+ +---------+ |
| ^ |
| | |
| +---------+ |
| | Devices | |
| +---------+ |
| |
| |
+---------------------------------------------+

Extended IRQ model:

In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
gathered by EIOINTC, and then go to to CPUINTC directly.

+--------------------------------------------------------+
| |
| +-----+ +---------+ +-------+ |
| | IPI | --> | CPUINTC | <-- | Timer | |
| +-----+ +---------+ +-------+ |
| ^ ^ |
| | | |
| +---------+ +---------+ +-------+ |
| | EIOINTC | | LIOINTC | <-- | UARTs | |
| +---------+ +---------+ +-------+ |
| ^ ^ |
| | | |
| +---------+ +---------+ |
| | PCH-PIC | | PCH-MSI | |
| +---------+ +---------+ |
| ^ ^ ^ |
| | | | |
| +---------+ +---------+ +---------+ |
| | PCH-LPC | | Devices | | Devices | |
| +---------+ +---------+ +---------+ |
| ^ |
| | |
| +---------+ |
| | Devices | |
| +---------+ |
| |
| |
+--------------------------------------------------------+

The hierarchy model is constructed by parsing irq contronler structures
in MADT. Some controllers((e.g. LIOINTC, HTVECINTC, EIOINTC and PCH-LPC)
are hardcodingly connected to their parents, so their irqdomins are
separately routed to their parents in a fixed way. Some controllers
(e.g. PCH-PIC and PCH-MSI) could be routed to different parents for different
CPU. The firmware will config EIOINTC for the newer CPU and config HTVECINTC
for old CPU in MADT. By this way, PCH-PIC and PCH-MSI irqdomain can only be
routed one parent irqdomin: HTVECINTC or EIOINTC.


Example of irqchip topology in a system with two chipsets:

+------------------------------------------------------------+
| |
| +------------------+ |
| | CPUINTC | |
| +------------------+ |
| ^ ^ |
| | | |
| +----------+ +----------+ |
| | EIOINTC 0| | EIOINTC 1| |
| +----------+ +----------+ |
| ^ ^ ^ ^ |
| | | | | |
| +----------+ +----------+ +----------+ +----------+ |
| | PCH-PIC 0| | PCH-MSI 0| | PCH-PIC 1| | PCH-MSI 1| |
| +----------+ +----------+ +----------+ +----------+ |
| |
| |
+------------------------------------------------------------+

For systems with two chipsets, there are tow group(consists of EIOINTC, PCH-PIC and PCH-MSI) irqdomains,
and each group has same node id. So we defined a structure to mantain the relation of node and it's parent irqdomain.

struct acpi_vector_group {
int node;
struct irq_domain *parent;
};

The initialization and use of acpi_vector_group array are following:

1 Entry of struct acpi_vector_group array initialization:

By parsing MCFG, the node id(from bit44-47 of Base Address)of each pci segment is extracted. And from MADT, we have the node id of each EIOINTC.

entrys[pci segment].node = node id of pci segment
entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)

2 Get parent irqdomain for PCH-PIC:

From MADT, we have the node id of each PCH-PIC(from bit44-47 of Base Address).
if (node of entry i == node of PCH-PIC)
return entrys[i].parent;

entrys[pci segment].node = node id of pci segment
entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)

3 Get parent irqdomain for PCH-MSI of pci segment:

return entrys[pci segment].parent;

4 How to select a correct irqdomain to map irq for a device?
For devices using legacy irq behind PCH-PIC, GSI is used to select correct PCH-PIC irqdomain.
For devices using msi irq behind PCH-MSI, the pci segmen of the device is used to select correct PCH-MSI irqdomain.

V1 -> V2:
1, Remove queued patches;
2, Move common logic of DT/ACPI probing to common functions;
3, Split .suspend()/.resume() functions to separate patches.

V2 -> V3:
1, Fix a bug for loongson-pch-pic probe;
2, Some minor improvements for LPC controller.

V3 -> V4:
1, Rework the CPU interrupt controller driver;
2, Some minor improvements for other controllers.

V4 -> V5:
1, Add a description of LoonArch's IRQ model;
2, Support multiple EIOINTCs in one system;
3, Some minor improvements for other controllers.

V5 -> V6:
1, Attach a fwnode to CPUINTC irq domain;
2, Use raw spinlock instead of generic spinlock;
3, Improve the method of restoring EIOINTC state;
4, Update documentation, comments and commit messages.

V6 -> V7:
1, Fix build warnings reported by kernel test robot.

V7 -> V8:
1, Add arguments sanity checking for irqchip init functions;
2, Support Loongson-3C5000 (One NUMA Node includes 4 EIOINTC Node).

V8 -> V9:
1, Rebase on 5.17-rc5;
2, Update cover letter;
3, Some small improvements.

V9 -> V10:
1, Rebase on 5.17-rc6;
2, Fix build warnings reported by kernel test robot.

V10 -> V11:
1, Rebase on 5.18-rc4;
2, Fix irq affinity setting for EIOINTC;
3, Fix hwirq allocation failure for EIOINTC.

V11 -> RFC:
1, Refactored the way to build irqchip hierarchy topology.

RFC -> RFC V2:
1, Move all IO-interrupt related code to driver/irqchip from arch directory.
2. Add description for an example of two chipsets system.

RFC V2 -> RFC V3:
1, Add support for multiple GSI domains
2, Use ACPI_GENERIC_GSI for GSI handling
3, Drop suspend-resume stuff
4, Export fwnode handles instead of irq domain handles

RFC V3 -> V12:
1, Address patch attributions of the patch series

Huacai Chen (7):
irqchip: Add LoongArch CPU interrupt controller support
irqchip/loongson-pch-pic: Add ACPI init support
irqchip/loongson-pch-msi: Add ACPI init support
irqchip/loongson-htvec: Add ACPI init support
irqchip/loongson-liointc: Add ACPI init support
irqchip: Add Loongson Extended I/O interrupt controller support
irqchip: Add Loongson PCH LPC controller support

Jianmin Lv (2):
genirq/generic_chip: export irq_unmap_generic_chip
irqchip: create library file for LoongArch irqchip driver

Marc Zyngier (1):
APCI: irq: Add support for multiple GSI domains

drivers/acpi/bus.c | 3 +
drivers/acpi/irq.c | 40 ++--
drivers/irqchip/Kconfig | 28 +++
drivers/irqchip/Makefile | 3 +
drivers/irqchip/irq-gic-v3.c | 18 +-
drivers/irqchip/irq-gic.c | 18 +-
drivers/irqchip/irq-loongarch-cpu.c | 134 +++++++++++
drivers/irqchip/irq-loongarch-pic-common.c | 122 ++++++++++
drivers/irqchip/irq-loongarch-pic-common.h | 39 ++++
drivers/irqchip/irq-loongson-eiointc.c | 347 +++++++++++++++++++++++++++++
drivers/irqchip/irq-loongson-htvec.c | 119 +++++++---
drivers/irqchip/irq-loongson-liointc.c | 225 ++++++++++++-------
drivers/irqchip/irq-loongson-pch-lpc.c | 202 +++++++++++++++++
drivers/irqchip/irq-loongson-pch-msi.c | 138 ++++++++----
drivers/irqchip/irq-loongson-pch-pic.c | 171 +++++++++++---
include/linux/acpi.h | 3 +-
include/linux/cpuhotplug.h | 1 +
include/linux/irq.h | 1 +
kernel/irq/generic-chip.c | 2 +-
19 files changed, 1402 insertions(+), 212 deletions(-)
create mode 100644 drivers/irqchip/irq-loongarch-cpu.c
create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
create mode 100644 drivers/irqchip/irq-loongson-eiointc.c
create mode 100644 drivers/irqchip/irq-loongson-pch-lpc.c

--
1.8.3.1


2022-06-15 06:26:12

by 吕建民

[permalink] [raw]
Subject: [PATCH V12 04/10] irqchip: create library file for LoongArch irqchip driver

The library file contains following content:
- Implement acpi_get_gsi_domain_id callback.
- Implement initialization of vector group entries and APIs
for building hierachy irqdomains.

Signed-off-by: Jianmin Lv <[email protected]>
---
drivers/irqchip/Makefile | 2 +-
drivers/irqchip/irq-loongarch-pic-common.c | 122 +++++++++++++++++++++++++++++
drivers/irqchip/irq-loongarch-pic-common.h | 39 +++++++++
3 files changed, 162 insertions(+), 1 deletion(-)
create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 6894a13..2d0d871 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -103,7 +103,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
-obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
+obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o
obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c
new file mode 100644
index 0000000..2f75362
--- /dev/null
+++ b/drivers/irqchip/irq-loongarch-pic-common.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
+ */
+
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include "irq-loongarch-pic-common.h"
+
+static struct acpi_vector_group vector_group[MAX_IO_PICS];
+
+struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
+
+struct fwnode_handle *liointc_handle;
+struct fwnode_handle *pch_lpc_handle;
+struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
+struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
+
+static int find_pch_pic(u32 gsi)
+{
+ int i, start, end;
+
+ /* Find the PCH_PIC that manages this GSI. */
+ for (i = 0; i < MAX_IO_PICS; i++) {
+ struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
+
+ if (!irq_cfg)
+ return -1;
+
+ start = irq_cfg->gsi_base;
+ end = irq_cfg->gsi_base + irq_cfg->size;
+ if (gsi >= start && gsi < end)
+ return i;
+ }
+
+ pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
+ return -1;
+}
+
+struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
+{
+ int id;
+ struct fwnode_handle *domain_handle = NULL;
+
+ switch (gsi) {
+ case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
+ if (liointc_handle)
+ domain_handle = liointc_handle;
+ break;
+
+ case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
+ if (pch_lpc_handle)
+ domain_handle = pch_lpc_handle;
+ break;
+
+ case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
+ id = find_pch_pic(gsi);
+ if (id >= 0 && pch_pic_handle[id])
+ domain_handle = pch_pic_handle[id];
+
+ break;
+ }
+
+ return domain_handle;
+}
+
+static int pci_mcfg_parse(struct acpi_table_header *header)
+{
+ struct acpi_table_mcfg *mcfg;
+ struct acpi_mcfg_allocation *mptr;
+ int i, n;
+
+ if (header->length < sizeof(struct acpi_table_mcfg))
+ return -EINVAL;
+
+ n = (header->length - sizeof(struct acpi_table_mcfg)) /
+ sizeof(struct acpi_mcfg_allocation);
+ mcfg = (struct acpi_table_mcfg *)header;
+ mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
+
+ for (i = 0; i < n; i++, mptr++)
+ vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf;
+
+ return 0;
+}
+
+void __init init_vector_parent_group(void)
+{
+ acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
+}
+
+void acpi_set_vector_parent(int node, struct irq_domain *parent)
+{
+ int i;
+
+ if (cpu_has_flatmode)
+ node = cpu_to_node(node * CORES_PER_EIO_NODE);
+
+ for (i = 0; i < MAX_IO_PICS; i++) {
+ if (node == vector_group[i].node) {
+ vector_group[i].parent = parent;
+ return;
+ }
+ }
+}
+
+struct irq_domain *acpi_get_msi_parent(int index)
+{
+ return vector_group[index].parent;
+}
+
+struct irq_domain *acpi_get_pch_parent(int node)
+{
+ int i;
+
+ for (i = 0; i < MAX_IO_PICS; i++) {
+ if (node == vector_group[i].node)
+ return vector_group[i].parent;
+ }
+ return NULL;
+}
diff --git a/drivers/irqchip/irq-loongarch-pic-common.h b/drivers/irqchip/irq-loongarch-pic-common.h
new file mode 100644
index 0000000..3e068c3
--- /dev/null
+++ b/drivers/irqchip/irq-loongarch-pic-common.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
+ */
+
+#ifndef _IRQ_LOONGARCH_PIC_COMMON_H
+#define _IRQ_LOONGARCH_PIC_COMMON_H
+
+#include <linux/of.h>
+#include <linux/irqdomain.h>
+
+struct acpi_vector_group {
+ int node;
+ struct irq_domain *parent;
+};
+
+/* IRQ number definitions */
+#define LOONGSON_LPC_IRQ_BASE 0
+#define LOONGSON_CPU_IRQ_BASE 16
+#define LOONGSON_PCH_IRQ_BASE 64
+
+#define GSI_MIN_LPC_IRQ LOONGSON_LPC_IRQ_BASE
+#define GSI_MAX_LPC_IRQ (LOONGSON_LPC_IRQ_BASE + 16 - 1)
+#define GSI_MIN_CPU_IRQ LOONGSON_CPU_IRQ_BASE
+#define GSI_MAX_CPU_IRQ (LOONGSON_CPU_IRQ_BASE + 48 - 1)
+#define GSI_MIN_PCH_IRQ LOONGSON_PCH_IRQ_BASE
+#define GSI_MAX_PCH_IRQ (LOONGSON_PCH_IRQ_BASE + 256 - 1)
+
+int liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc);
+int eiointc_acpi_init(struct irq_domain *parent, struct acpi_madt_eio_pic *acpi_eiointc);
+int htvec_acpi_init(struct irq_domain *parent, struct acpi_madt_ht_pic *acpi_htvec);
+int pch_lpc_acpi_init(struct irq_domain *parent, struct acpi_madt_lpc_pic *acpi_pchlpc);
+struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi);
+void init_vector_parent_group(void);
+void acpi_set_vector_parent(int node, struct irq_domain *parent);
+struct irq_domain *acpi_get_msi_parent(int index);
+struct irq_domain *acpi_get_pch_parent(int node);
+
+#endif /* _IRQ_LOONGARCH_PIC_COMMON_H */
--
1.8.3.1

2022-06-15 06:26:33

by 吕建民

[permalink] [raw]
Subject: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

From: Marc Zyngier <[email protected]>

In an unfortunate departure from the ACPI spec, the LoongArch
architecture split its GSI space across multiple interrupt
controllers.

In order to be able to reuse sthe core code and prevent
architectures from reinventing an already square wheel, offer
the arch code the ability to register a dispatcher function
that will return the domain fwnode for a given GSI.

The ARM GIC drivers are updated to support this (with a single
domain, as intended).

Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Cc: Hanjun Guo <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
---
drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
drivers/irqchip/irq-gic.c | 18 ++++++++++++------
include/linux/acpi.h | 2 +-
4 files changed, 48 insertions(+), 30 deletions(-)

diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index c68e694..b7460ab 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -12,7 +12,7 @@

enum acpi_irq_model_id acpi_irq_model;

-static struct fwnode_handle *acpi_gsi_domain_id;
+static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);

/**
* acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
@@ -26,10 +26,7 @@
*/
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
- struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
- DOMAIN_BUS_ANY);
-
- *irq = irq_find_mapping(d, gsi);
+ *irq = acpi_register_gsi(NULL, gsi, -1, -1);
/*
* *irq == 0 means no mapping, that should
* be reported as a failure
@@ -53,12 +50,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
{
struct irq_fwspec fwspec;

- if (WARN_ON(!acpi_gsi_domain_id)) {
+ fwspec.fwnode = acpi_get_gsi_domain_id(gsi);
+ if (WARN_ON(!fwspec.fwnode)) {
pr_warn("GSI: No registered irqchip, giving up\n");
return -EINVAL;
}

- fwspec.fwnode = acpi_gsi_domain_id;
fwspec.param[0] = gsi;
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
fwspec.param_count = 2;
@@ -73,13 +70,14 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
*/
void acpi_unregister_gsi(u32 gsi)
{
- struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
- DOMAIN_BUS_ANY);
+ struct irq_domain *d;
int irq;

if (WARN_ON(acpi_irq_model == ACPI_IRQ_MODEL_GIC && gsi < 16))
return;

+ d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
+ DOMAIN_BUS_ANY);
irq = irq_find_mapping(d, gsi);
irq_dispose_mapping(irq);
}
@@ -97,7 +95,8 @@ void acpi_unregister_gsi(u32 gsi)
* The referenced device fwhandle or NULL on failure
*/
static struct fwnode_handle *
-acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
+acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source,
+ u32 gsi)
{
struct fwnode_handle *result;
struct acpi_device *device;
@@ -105,7 +104,7 @@ void acpi_unregister_gsi(u32 gsi)
acpi_status status;

if (!source->string_length)
- return acpi_gsi_domain_id;
+ return acpi_get_gsi_domain_id(gsi);

status = acpi_get_handle(NULL, source->string_ptr, &handle);
if (WARN_ON(ACPI_FAILURE(status)))
@@ -194,7 +193,7 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
ctx->index -= irq->interrupt_count;
return AE_OK;
}
- fwnode = acpi_gsi_domain_id;
+ fwnode = acpi_get_gsi_domain_id(irq->interrupts[ctx->index]);
acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
irq->triggering, irq->polarity,
irq->shareable, ctx);
@@ -207,7 +206,8 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
ctx->index -= eirq->interrupt_count;
return AE_OK;
}
- fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source);
+ fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source,
+ eirq->interrupts[ctx->index]);
acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index],
eirq->triggering, eirq->polarity,
eirq->shareable, ctx);
@@ -291,10 +291,10 @@ int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
* GSI interrupts
*/
void __init acpi_set_irq_model(enum acpi_irq_model_id model,
- struct fwnode_handle *fwnode)
+ struct fwnode_handle *(*fn)(u32))
{
acpi_irq_model = model;
- acpi_gsi_domain_id = fwnode;
+ acpi_get_gsi_domain_id = fn;
}

/**
@@ -312,8 +312,14 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
const struct irq_domain_ops *ops,
void *host_data)
{
- struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
- DOMAIN_BUS_ANY);
+ struct irq_domain *d;
+
+ /* This only works for the GIC model... */
+ if (acpi_irq_model != ACPI_IRQ_MODEL_GIC)
+ return NULL;
+
+ d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(0),
+ DOMAIN_BUS_ANY);

if (!d)
return NULL;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 2be8dea..87b1f53 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -2357,11 +2357,17 @@ static void __init gic_acpi_setup_kvm_info(void)
vgic_set_kvm_info(&gic_v3_kvm_info);
}

+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v3_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_generic_distributor *dist;
- struct fwnode_handle *domain_handle;
size_t size;
int i, err;

@@ -2393,18 +2399,18 @@ static void __init gic_acpi_setup_kvm_info(void)
if (err)
goto out_redist_unmap;

- domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
- if (!domain_handle) {
+ gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
+ if (!gsi_domain_handle) {
err = -ENOMEM;
goto out_redist_unmap;
}

err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
- acpi_data.nr_redist_regions, 0, domain_handle);
+ acpi_data.nr_redist_regions, 0, gsi_domain_handle);
if (err)
goto out_fwhandle_free;

- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);

if (static_branch_likely(&supports_deactivate_key))
gic_acpi_setup_kvm_info();
@@ -2412,7 +2418,7 @@ static void __init gic_acpi_setup_kvm_info(void)
return 0;

out_fwhandle_free:
- irq_domain_free_fwnode(domain_handle);
+ irq_domain_free_fwnode(gsi_domain_handle);
out_redist_unmap:
for (i = 0; i < acpi_data.nr_redist_regions; i++)
if (acpi_data.redist_regs[i].redist_base)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 820404c..4c7bae0 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1682,11 +1682,17 @@ static void __init gic_acpi_setup_kvm_info(void)
vgic_set_kvm_info(&gic_v2_kvm_info);
}

+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v2_get_gsi_domain_id(u32 gsi)
+{
+ return gsi_domain_handle;
+}
+
static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_generic_distributor *dist;
- struct fwnode_handle *domain_handle;
struct gic_chip_data *gic = &gic_data[0];
int count, ret;

@@ -1724,22 +1730,22 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
/*
* Initialize GIC instance zero (no multi-GIC support).
*/
- domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
- if (!domain_handle) {
+ gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
+ if (!gsi_domain_handle) {
pr_err("Unable to allocate domain handle\n");
gic_teardown(gic);
return -ENOMEM;
}

- ret = __gic_init_bases(gic, domain_handle);
+ ret = __gic_init_bases(gic, gsi_domain_handle);
if (ret) {
pr_err("Failed to initialise GIC\n");
- irq_domain_free_fwnode(domain_handle);
+ irq_domain_free_fwnode(gsi_domain_handle);
gic_teardown(gic);
return ret;
}

- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);

if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(NULL, gic_data[0].domain);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4f82a5b..957e23f 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -356,7 +356,7 @@ static inline bool acpi_sci_irq_valid(void)
int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);

void acpi_set_irq_model(enum acpi_irq_model_id model,
- struct fwnode_handle *fwnode);
+ struct fwnode_handle *(*)(u32));

struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
unsigned int size,
--
1.8.3.1

2022-06-15 06:40:35

by 吕建民

[permalink] [raw]
Subject: [PATCH V12 05/10] irqchip/loongson-pch-pic: Add ACPI init support

From: Huacai Chen <[email protected]>

We are preparing to add new Loongson (based on LoongArch, not compatible
with old MIPS-based Loongson) support. LoongArch use ACPI other than DT
as its boot protocol, so add ACPI init support.

PCH-PIC/PCH-MSI stands for "Interrupt Controller" that described in
Section 5 of "Loongson 7A1000 Bridge User Manual". For more information
please refer Documentation/loongarch/irq-chip-model.rst.

Change-Id: I40e9b9e5298d7b3f6ae2ab2ba69f5bcfa50c1418
Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
drivers/irqchip/irq-loongson-pch-pic.c | 171 +++++++++++++++++++++++++++------
1 file changed, 141 insertions(+), 30 deletions(-)

diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
index a4eb8a2..1426b93 100644
--- a/drivers/irqchip/irq-loongson-pch-pic.c
+++ b/drivers/irqchip/irq-loongson-pch-pic.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include "irq-loongarch-pic-common.h"

/* Registers */
#define PCH_PIC_MASK 0x20
@@ -33,13 +34,20 @@
#define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
#define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)

+static int nr_pics;
+
struct pch_pic {
void __iomem *base;
struct irq_domain *pic_domain;
+ struct fwnode_handle *domain_handle;
u32 ht_vec_base;
raw_spinlock_t pic_lock;
+ u32 gsi_end;
+ u32 gsi_base;
};

+static struct pch_pic *pch_pic_priv[2];
+
static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
{
u32 reg;
@@ -139,6 +147,24 @@ static void pch_pic_ack_irq(struct irq_data *d)
.irq_set_type = pch_pic_set_type,
};

+static int pch_pic_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ struct pch_pic *priv = d->host_data;
+ struct device_node *of_node = to_of_node(fwspec->fwnode);
+
+ if (fwspec->param_count < 1)
+ return -EINVAL;
+ if (of_node)
+ *hwirq += priv->ht_vec_base;
+ else
+ *hwirq = fwspec->param[0] - priv->gsi_base;
+ *type = IRQ_TYPE_NONE;
+
+ return 0;
+}
static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
@@ -149,13 +175,13 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
struct irq_fwspec parent_fwspec;
struct pch_pic *priv = domain->host_data;

- err = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
+ err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
if (err)
return err;

parent_fwspec.fwnode = domain->parent->fwnode;
parent_fwspec.param_count = 1;
- parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
+ parent_fwspec.param[0] = hwirq;

err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
if (err)
@@ -170,7 +196,7 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
}

static const struct irq_domain_ops pch_pic_domain_ops = {
- .translate = irq_domain_translate_twocell,
+ .translate = pch_pic_domain_translate,
.alloc = pch_pic_alloc,
.free = irq_domain_free_irqs_parent,
};
@@ -180,7 +206,7 @@ static void pch_pic_reset(struct pch_pic *priv)
int i;

for (i = 0; i < PIC_COUNT; i++) {
- /* Write vectored ID */
+ /* Write vector ID */
writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
/* Hardcode route to HT0 Lo */
writeb(1, priv->base + PCH_INT_ROUTE(i));
@@ -198,50 +224,41 @@ static void pch_pic_reset(struct pch_pic *priv)
}
}

-static int pch_pic_of_init(struct device_node *node,
- struct device_node *parent)
+static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
+ struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
+ u32 gsi_base)
{
+ int vec_count;
struct pch_pic *priv;
- struct irq_domain *parent_domain;
- int err;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

raw_spin_lock_init(&priv->pic_lock);
- priv->base = of_iomap(node, 0);
- if (!priv->base) {
- err = -ENOMEM;
+ priv->base = ioremap(addr, size);
+ if (!priv->base)
goto free_priv;
- }

- parent_domain = irq_find_host(parent);
- if (!parent_domain) {
- pr_err("Failed to find the parent domain\n");
- err = -ENXIO;
- goto iounmap_base;
- }
+ priv->domain_handle = domain_handle;

- if (of_property_read_u32(node, "loongson,pic-base-vec",
- &priv->ht_vec_base)) {
- pr_err("Failed to determine pic-base-vec\n");
- err = -EINVAL;
- goto iounmap_base;
- }
+ priv->ht_vec_base = vec_base;
+ vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
+ priv->gsi_base = gsi_base;
+ priv->gsi_end = gsi_base + vec_count - 1;

priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
- PIC_COUNT,
- of_node_to_fwnode(node),
- &pch_pic_domain_ops,
- priv);
+ vec_count, priv->domain_handle,
+ &pch_pic_domain_ops, priv);
+
if (!priv->pic_domain) {
pr_err("Failed to create IRQ domain\n");
- err = -ENOMEM;
goto iounmap_base;
}

pch_pic_reset(priv);
+ pch_pic_handle[nr_pics] = domain_handle;
+ pch_pic_priv[nr_pics++] = priv;

return 0;

@@ -250,7 +267,101 @@ static int pch_pic_of_init(struct device_node *node,
free_priv:
kfree(priv);

- return err;
+ return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int pch_pic_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ int err, vec_base;
+ struct resource res;
+ struct irq_domain *parent_domain;
+
+ if (of_address_to_resource(node, 0, &res))
+ return -EINVAL;
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("Failed to find the parent domain\n");
+ return -ENXIO;
+ }
+
+ if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
+ pr_err("Failed to determine pic-base-vec\n");
+ return -EINVAL;
+ }
+
+ err = pch_pic_init(res.start, resource_size(&res), vec_base,
+ parent_domain, of_node_to_fwnode(node), 0);
+ if (err < 0)
+ return err;
+
+ return 0;
}

IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+static int __init
+lpcintc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_lpc_pic *lpcintc_entry = (struct acpi_madt_lpc_pic *)header;
+
+ return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, lpcintc_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
+ lpcintc_parse_madt, 0);
+ return 0;
+}
+int __init pch_pic_init_irqdomain(struct irq_domain *parent,
+ struct acpi_madt_bio_pic *acpi_pchpic)
+{
+ int ret, vec_base;
+ struct fwnode_handle *domain_handle;
+
+ if (!acpi_pchpic)
+ return -EINVAL;
+
+ vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
+
+ domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchpic);
+ if (!domain_handle) {
+ pr_err("Unable to allocate domain handle\n");
+ return -ENOMEM;
+ }
+
+ ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
+ vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
+ if (ret == 0 && acpi_pchpic->id == 0)
+ acpi_cascade_irqdomain_init();
+
+ return ret;
+}
+
+static int __init pchintc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_bio_pic *pch_pic_entry = (struct acpi_madt_bio_pic *)header;
+
+ acpi_pchpic[nr_pics] = pch_pic_entry;
+ return pch_pic_init_irqdomain(acpi_get_pch_parent((pch_pic_entry->address >> 44) & 0xf),
+ pch_pic_entry);
+}
+
+static int __init pch_pic_acpi_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
+ pchintc_parse_madt, 0);
+
+ return 0;
+}
+early_initcall(pch_pic_acpi_init);
+#endif
--
1.8.3.1

2022-06-15 06:43:15

by 吕建民

[permalink] [raw]
Subject: [PATCH V12 07/10] irqchip/loongson-htvec: Add ACPI init support

From: Huacai Chen <[email protected]>

We are preparing to add new Loongson (based on LoongArch, not compatible
with old MIPS-based Loongson) support. LoongArch use ACPI other than DT
as its boot protocol, so add ACPI init support.

HTVECINTC stands for "HyperTransport Interrupts" that described in
Section 14.3 of "Loongson 3A5000 Processor Reference Manual". For more
information please refer Documentation/loongarch/irq-chip-model.rst.

Change-Id: Id79050b46d31a9118a669972f3419585de8d8b11
Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
drivers/irqchip/irq-loongson-htvec.c | 119 +++++++++++++++++++++++++----------
1 file changed, 85 insertions(+), 34 deletions(-)

diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index 60a335d..72b3874 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -16,11 +16,11 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include "irq-loongarch-pic-common.h"

/* Registers */
#define HTVEC_EN_OFF 0x20
#define HTVEC_MAX_PARENT_IRQ 8
-
#define VEC_COUNT_PER_REG 32
#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
@@ -30,8 +30,11 @@ struct htvec {
void __iomem *base;
struct irq_domain *htvec_domain;
raw_spinlock_t htvec_lock;
+ struct fwnode_handle *domain_handle;
};

+static struct htvec *htvec_priv;
+
static void htvec_irq_dispatch(struct irq_desc *desc)
{
int i;
@@ -155,64 +158,112 @@ static void htvec_reset(struct htvec *priv)
}
}

-static int htvec_of_init(struct device_node *node,
- struct device_node *parent)
+static int htvec_init(phys_addr_t addr, unsigned long size,
+ int num_parents, int parent_irq[], struct fwnode_handle *domain_handle)
{
+ int i;
struct htvec *priv;
- int err, parent_irq[8], i;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

+ priv->num_parents = num_parents;
+ priv->base = ioremap(addr, size);
+ priv->domain_handle = domain_handle;
raw_spin_lock_init(&priv->htvec_lock);
- priv->base = of_iomap(node, 0);
- if (!priv->base) {
- err = -ENOMEM;
- goto free_priv;
- }
-
- /* Interrupt may come from any of the 8 interrupt lines */
- for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
- parent_irq[i] = irq_of_parse_and_map(node, i);
- if (parent_irq[i] <= 0)
- break;
-
- priv->num_parents++;
- }

- if (!priv->num_parents) {
- pr_err("Failed to get parent irqs\n");
- err = -ENODEV;
- goto iounmap_base;
- }
-
- priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+ /* Setup IRQ domain */
+ priv->htvec_domain = irq_domain_create_linear(priv->domain_handle,
(VEC_COUNT_PER_REG * priv->num_parents),
&htvec_domain_ops, priv);
if (!priv->htvec_domain) {
- pr_err("Failed to create IRQ domain\n");
- err = -ENOMEM;
- goto irq_dispose;
+ pr_err("loongson-htvec: cannot add IRQ domain\n");
+ goto iounmap_base;
}

htvec_reset(priv);

- for (i = 0; i < priv->num_parents; i++)
+ for (i = 0; i < priv->num_parents; i++) {
irq_set_chained_handler_and_data(parent_irq[i],
htvec_irq_dispatch, priv);
+ }
+
+ htvec_priv = priv;

return 0;

-irq_dispose:
- for (; i > 0; i--)
- irq_dispose_mapping(parent_irq[i - 1]);
iounmap_base:
iounmap(priv->base);
-free_priv:
+ priv->domain_handle = NULL;
kfree(priv);

- return err;
+ return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int htvec_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ int i, err;
+ int parent_irq[8];
+ int num_parents = 0;
+ struct resource res;
+
+ if (of_address_to_resource(node, 0, &res))
+ return -EINVAL;
+
+ /* Interrupt may come from any of the 8 interrupt lines */
+ for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
+ parent_irq[i] = irq_of_parse_and_map(node, i);
+ if (parent_irq[i] <= 0)
+ break;
+
+ num_parents++;
+ }
+
+ err = htvec_init(res.start, resource_size(&res),
+ num_parents, parent_irq, of_node_to_fwnode(node));
+ if (err < 0)
+ return err;
+
+ return 0;
}

IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+int __init htvec_acpi_init(struct irq_domain *parent,
+ struct acpi_madt_ht_pic *acpi_htvec)
+{
+ int i, ret;
+ int num_parents, parent_irq[8];
+ struct fwnode_handle *domain_handle;
+
+ if (!acpi_htvec)
+ return -EINVAL;
+
+ num_parents = HTVEC_MAX_PARENT_IRQ;
+
+ domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_htvec);
+ if (!domain_handle) {
+ pr_err("Unable to allocate domain handle\n");
+ return -ENOMEM;
+ }
+
+ /* Interrupt may come from any of the 8 interrupt lines */
+ for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++)
+ parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]);
+
+ ret = htvec_init(acpi_htvec->address, acpi_htvec->size,
+ num_parents, parent_irq, domain_handle);
+ if (ret == 0)
+ acpi_set_vector_parent(0, htvec_priv->htvec_domain);
+
+ return ret;
+}
+
+#endif
--
1.8.3.1

2022-06-15 07:57:04

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

On Wed, 15 Jun 2022 07:07:21 +0100,
Jianmin Lv <[email protected]> wrote:
>
> From: Marc Zyngier <[email protected]>
>
> In an unfortunate departure from the ACPI spec, the LoongArch
> architecture split its GSI space across multiple interrupt
> controllers.
>
> In order to be able to reuse sthe core code and prevent
> architectures from reinventing an already square wheel, offer
> the arch code the ability to register a dispatcher function
> that will return the domain fwnode for a given GSI.
>
> The ARM GIC drivers are updated to support this (with a single
> domain, as intended).
>
> Co-developed-by: Jianmin Lv <[email protected]>

I don't think this tag is appropriate here.

> Signed-off-by: Marc Zyngier <[email protected]>
> Cc: Hanjun Guo <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Signed-off-by: Jianmin Lv <[email protected]>
> ---
> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
> include/linux/acpi.h | 2 +-
> 4 files changed, 48 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> index c68e694..b7460ab 100644
> --- a/drivers/acpi/irq.c
> +++ b/drivers/acpi/irq.c
> @@ -12,7 +12,7 @@
>
> enum acpi_irq_model_id acpi_irq_model;
>
> -static struct fwnode_handle *acpi_gsi_domain_id;
> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>
> /**
> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> @@ -26,10 +26,7 @@
> */
> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> {
> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> - DOMAIN_BUS_ANY);
> -
> - *irq = irq_find_mapping(d, gsi);
> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);

What is this?

- This wasn't part of my initial patch, and randomly changing patches
without mentioning it isn't acceptable

- you *cannot* trigger a registration here, as this isn't what the API
advertises

- what makes you think that passing random values (NULL, -1... )to
acpi_register_gsi() is an acceptable thing to do?

The original patch had:

@@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
*/
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
- struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
- DOMAIN_BUS_ANY);
+ struct irq_domain *d;
+
+ d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
+ DOMAIN_BUS_ANY);
*irq = irq_find_mapping(d, gsi);
/*

and I don't think it needs anything else. If something breaks, let's
discuss it, but don't abuse the API nor the fact that I usually don't
review my own patches to sneak things in...

M.

--
Without deviation from the norm, progress is not possible.

2022-06-15 10:11:06

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/15 下午3:14, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 07:07:21 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>> From: Marc Zyngier <[email protected]>
>>
>> In an unfortunate departure from the ACPI spec, the LoongArch
>> architecture split its GSI space across multiple interrupt
>> controllers.
>>
>> In order to be able to reuse sthe core code and prevent
>> architectures from reinventing an already square wheel, offer
>> the arch code the ability to register a dispatcher function
>> that will return the domain fwnode for a given GSI.
>>
>> The ARM GIC drivers are updated to support this (with a single
>> domain, as intended).
>>
>> Co-developed-by: Jianmin Lv <[email protected]>
>
> I don't think this tag is appropriate here.
>
>> Signed-off-by: Marc Zyngier <[email protected]>
>> Cc: Hanjun Guo <[email protected]>
>> Cc: Lorenzo Pieralisi <[email protected]>
>> Signed-off-by: Jianmin Lv <[email protected]>
>> ---
>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
>> include/linux/acpi.h | 2 +-
>> 4 files changed, 48 insertions(+), 30 deletions(-)
>>
>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>> index c68e694..b7460ab 100644
>> --- a/drivers/acpi/irq.c
>> +++ b/drivers/acpi/irq.c
>> @@ -12,7 +12,7 @@
>>
>> enum acpi_irq_model_id acpi_irq_model;
>>
>> -static struct fwnode_handle *acpi_gsi_domain_id;
>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>
>> /**
>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>> @@ -26,10 +26,7 @@
>> */
>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>> {
>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>> - DOMAIN_BUS_ANY);
>> -
>> - *irq = irq_find_mapping(d, gsi);
>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>
> What is this?
>
> - This wasn't part of my initial patch, and randomly changing patches
> without mentioning it isn't acceptable
>
> - you *cannot* trigger a registration here, as this isn't what the API
> advertises
>
> - what makes you think that passing random values (NULL, -1... )to
> acpi_register_gsi() is an acceptable thing to do?
>
> The original patch had:
>
> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
> */
> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> {
> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> - DOMAIN_BUS_ANY);
> + struct irq_domain *d;
> +
> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
> + DOMAIN_BUS_ANY);
> *irq = irq_find_mapping(d, gsi);
> /*
>
> and I don't think it needs anything else. If something breaks, let's
> discuss it, but don't abuse the API nor the fact that I usually don't
> review my own patches to sneak things in...
>

Sorry, Marc, I don't know how to communicate with you for my change
here before submitting the patch, maybe I should mention it in the
patch commit or code.


When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
only handle existed mapping and will return -EINVAL if mapping not
found. When I test on my machine, a calling stack is as following:


acpi_bus_init
->acpi_enable_subsystem
->acpi_ev_install_xrupt_handlers
->acpi_ev_install_sci_handler
->acpi_os_install_interrupt_handler
->acpi_gsi_to_irq


the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it so
that new mapping for gsi is created if no mapping is found.


I looked into generic acpi_register_gsi, the existed mapping will be
checked first by calling irq_find_mapping, so I think calling
acpi_register_gsi in acpi_gsi_to_irq can address the problem.


But you're right, I'm wrong that I passed random value of -1 to
acpi_register_gsi. I don't find a right way to address the problem
without changing acpi_gsi_to_irq. I'll continue to work for the problem.

> M.
>

2022-06-15 10:30:23

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/15 下午3:14, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 07:07:21 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>> From: Marc Zyngier <[email protected]>
>>
>> In an unfortunate departure from the ACPI spec, the LoongArch
>> architecture split its GSI space across multiple interrupt
>> controllers.
>>
>> In order to be able to reuse sthe core code and prevent
>> architectures from reinventing an already square wheel, offer
>> the arch code the ability to register a dispatcher function
>> that will return the domain fwnode for a given GSI.
>>
>> The ARM GIC drivers are updated to support this (with a single
>> domain, as intended).
>>
>> Co-developed-by: Jianmin Lv <[email protected]>
>
> I don't think this tag is appropriate here.
>

Ok, I'll drop it.

>> Signed-off-by: Marc Zyngier <[email protected]>
>> Cc: Hanjun Guo <[email protected]>
>> Cc: Lorenzo Pieralisi <[email protected]>
>> Signed-off-by: Jianmin Lv <[email protected]>
>> ---
>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
>> include/linux/acpi.h | 2 +-
>> 4 files changed, 48 insertions(+), 30 deletions(-)
>>
>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>> index c68e694..b7460ab 100644
>> --- a/drivers/acpi/irq.c
>> +++ b/drivers/acpi/irq.c
>> @@ -12,7 +12,7 @@
>>
>> enum acpi_irq_model_id acpi_irq_model;
>>
>> -static struct fwnode_handle *acpi_gsi_domain_id;
>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>
>> /**
>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>> @@ -26,10 +26,7 @@
>> */
>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>> {
>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>> - DOMAIN_BUS_ANY);
>> -
>> - *irq = irq_find_mapping(d, gsi);
>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>
> What is this?
>
> - This wasn't part of my initial patch, and randomly changing patches
> without mentioning it isn't acceptable
>
> - you *cannot* trigger a registration here, as this isn't what the API
> advertises
>
> - what makes you think that passing random values (NULL, -1... )to
> acpi_register_gsi() is an acceptable thing to do?
>
> The original patch had:
>
> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
> */
> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> {
> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> - DOMAIN_BUS_ANY);
> + struct irq_domain *d;
> +
> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
> + DOMAIN_BUS_ANY);
> *irq = irq_find_mapping(d, gsi);
> /*
>
> and I don't think it needs anything else. If something breaks, let's
> discuss it, but don't abuse the API nor the fact that I usually don't
> review my own patches to sneak things in...
>
> M.
>

2022-06-18 10:50:27

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 00/10] irqchip: Add LoongArch-related irqchip drivers

On Wed, 15 Jun 2022 07:07:20 +0100,
Jianmin Lv <[email protected]> wrote:
>
> LoongArch is a new RISC ISA, which is a bit like MIPS or RISC-V.
> LoongArch includes a reduced 32-bit version (LA32R), a standard 32-bit
> version (LA32S) and a 64-bit version (LA64). LoongArch use ACPI as its
> boot protocol LoongArch-specific interrupt controllers (similar to APIC)
> are already added in the ACPI Specification 6.5(which may be published in
> early June this year and the board is reviewing the draft).
>
> Currently, LoongArch based processors (e.g. Loongson-3A5000) can only
> work together with LS7A chipsets. The irq chips in LoongArch computers
> include CPUINTC (CPU Core Interrupt Controller), LIOINTC (Legacy I/O
> Interrupt Controller), EIOINTC (Extended I/O Interrupt Controller),
> HTVECINTC (Hyper-Transport Vector Interrupt Controller), PCH-PIC (Main
> Interrupt Controller in LS7A chipset), PCH-LPC (LPC Interrupt Controller
> in LS7A chipset) and PCH-MSI (MSI Interrupt Controller).
>
> CPUINTC is a per-core controller (in CPU), LIOINTC/EIOINTC/HTVECINTC are
> per-package controllers (in CPU), while PCH-PIC/PCH-LPC/PCH-MSI are all
> controllers out of CPU (i.e., in chipsets). These controllers (in other
> words, irqchips) are linked in a hierarchy, and there are two models of
> hierarchy (legacy model and extended model).
>
> Legacy IRQ model:
>
> In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
> interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
> while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
> gathered by HTVECINTC, and then go to LIOINTC, and then CPUINTC.
>
> +---------------------------------------------+
> | |
> | +-----+ +---------+ +-------+ |
> | | IPI | --> | CPUINTC | <-- | Timer | |
> | +-----+ +---------+ +-------+ |
> | ^ |
> | | |
> | +---------+ +-------+ |
> | | LIOINTC | <-- | UARTs | |
> | +---------+ +-------+ |
> | ^ |
> | | |
> | +-----------+ |
> | | HTVECINTC | |
> | +-----------+ |
> | ^ ^ |
> | | | |
> | +---------+ +---------+ |
> | | PCH-PIC | | PCH-MSI | |
> | +---------+ +---------+ |
> | ^ ^ ^ |
> | | | | |
> | +---------+ +---------+ +---------+ |
> | | PCH-LPC | | Devices | | Devices | |
> | +---------+ +---------+ +---------+ |
> | ^ |
> | | |
> | +---------+ |
> | | Devices | |
> | +---------+ |
> | |
> | |
> +---------------------------------------------+
>
> Extended IRQ model:
>
> In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
> interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
> while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
> gathered by EIOINTC, and then go to to CPUINTC directly.
>
> +--------------------------------------------------------+
> | |
> | +-----+ +---------+ +-------+ |
> | | IPI | --> | CPUINTC | <-- | Timer | |
> | +-----+ +---------+ +-------+ |
> | ^ ^ |
> | | | |
> | +---------+ +---------+ +-------+ |
> | | EIOINTC | | LIOINTC | <-- | UARTs | |
> | +---------+ +---------+ +-------+ |
> | ^ ^ |
> | | | |
> | +---------+ +---------+ |
> | | PCH-PIC | | PCH-MSI | |
> | +---------+ +---------+ |
> | ^ ^ ^ |
> | | | | |
> | +---------+ +---------+ +---------+ |
> | | PCH-LPC | | Devices | | Devices | |
> | +---------+ +---------+ +---------+ |
> | ^ |
> | | |
> | +---------+ |
> | | Devices | |
> | +---------+ |
> | |
> | |
> +--------------------------------------------------------+
>
> The hierarchy model is constructed by parsing irq contronler structures
> in MADT. Some controllers((e.g. LIOINTC, HTVECINTC, EIOINTC and PCH-LPC)
> are hardcodingly connected to their parents, so their irqdomins are
> separately routed to their parents in a fixed way. Some controllers
> (e.g. PCH-PIC and PCH-MSI) could be routed to different parents for different
> CPU. The firmware will config EIOINTC for the newer CPU and config HTVECINTC
> for old CPU in MADT. By this way, PCH-PIC and PCH-MSI irqdomain can only be
> routed one parent irqdomin: HTVECINTC or EIOINTC.
>
>
> Example of irqchip topology in a system with two chipsets:
>
> +------------------------------------------------------------+
> | |
> | +------------------+ |
> | | CPUINTC | |
> | +------------------+ |
> | ^ ^ |
> | | | |
> | +----------+ +----------+ |
> | | EIOINTC 0| | EIOINTC 1| |
> | +----------+ +----------+ |
> | ^ ^ ^ ^ |
> | | | | | |
> | +----------+ +----------+ +----------+ +----------+ |
> | | PCH-PIC 0| | PCH-MSI 0| | PCH-PIC 1| | PCH-MSI 1| |
> | +----------+ +----------+ +----------+ +----------+ |
> | |
> | |
> +------------------------------------------------------------+
>
> For systems with two chipsets, there are tow group(consists of EIOINTC, PCH-PIC and PCH-MSI) irqdomains,
> and each group has same node id. So we defined a structure to mantain the relation of node and it's parent irqdomain.
>
> struct acpi_vector_group {
> int node;
> struct irq_domain *parent;
> };
>
> The initialization and use of acpi_vector_group array are following:
>
> 1 Entry of struct acpi_vector_group array initialization:
>
> By parsing MCFG, the node id(from bit44-47 of Base Address)of each pci segment is extracted. And from MADT, we have the node id of each EIOINTC.
>
> entrys[pci segment].node = node id of pci segment
> entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)
>
> 2 Get parent irqdomain for PCH-PIC:
>
> From MADT, we have the node id of each PCH-PIC(from bit44-47 of Base Address).
> if (node of entry i == node of PCH-PIC)
> return entrys[i].parent;
>
> entrys[pci segment].node = node id of pci segment
> entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)
>
> 3 Get parent irqdomain for PCH-MSI of pci segment:
>
> return entrys[pci segment].parent;
>
> 4 How to select a correct irqdomain to map irq for a device?
> For devices using legacy irq behind PCH-PIC, GSI is used to select correct PCH-PIC irqdomain.
> For devices using msi irq behind PCH-MSI, the pci segmen of the device is used to select correct PCH-MSI irqdomain.
>
> V1 -> V2:
> 1, Remove queued patches;
> 2, Move common logic of DT/ACPI probing to common functions;
> 3, Split .suspend()/.resume() functions to separate patches.
>
> V2 -> V3:
> 1, Fix a bug for loongson-pch-pic probe;
> 2, Some minor improvements for LPC controller.
>
> V3 -> V4:
> 1, Rework the CPU interrupt controller driver;
> 2, Some minor improvements for other controllers.
>
> V4 -> V5:
> 1, Add a description of LoonArch's IRQ model;
> 2, Support multiple EIOINTCs in one system;
> 3, Some minor improvements for other controllers.
>
> V5 -> V6:
> 1, Attach a fwnode to CPUINTC irq domain;
> 2, Use raw spinlock instead of generic spinlock;
> 3, Improve the method of restoring EIOINTC state;
> 4, Update documentation, comments and commit messages.
>
> V6 -> V7:
> 1, Fix build warnings reported by kernel test robot.
>
> V7 -> V8:
> 1, Add arguments sanity checking for irqchip init functions;
> 2, Support Loongson-3C5000 (One NUMA Node includes 4 EIOINTC Node).
>
> V8 -> V9:
> 1, Rebase on 5.17-rc5;
> 2, Update cover letter;
> 3, Some small improvements.
>
> V9 -> V10:
> 1, Rebase on 5.17-rc6;
> 2, Fix build warnings reported by kernel test robot.
>
> V10 -> V11:
> 1, Rebase on 5.18-rc4;
> 2, Fix irq affinity setting for EIOINTC;
> 3, Fix hwirq allocation failure for EIOINTC.
>
> V11 -> RFC:
> 1, Refactored the way to build irqchip hierarchy topology.
>
> RFC -> RFC V2:
> 1, Move all IO-interrupt related code to driver/irqchip from arch directory.
> 2. Add description for an example of two chipsets system.
>
> RFC V2 -> RFC V3:
> 1, Add support for multiple GSI domains
> 2, Use ACPI_GENERIC_GSI for GSI handling
> 3, Drop suspend-resume stuff
> 4, Export fwnode handles instead of irq domain handles
>
> RFC V3 -> V12:
> 1, Address patch attributions of the patch series
>
> Huacai Chen (7):
> irqchip: Add LoongArch CPU interrupt controller support
> irqchip/loongson-pch-pic: Add ACPI init support
> irqchip/loongson-pch-msi: Add ACPI init support
> irqchip/loongson-htvec: Add ACPI init support
> irqchip/loongson-liointc: Add ACPI init support
> irqchip: Add Loongson Extended I/O interrupt controller support
> irqchip: Add Loongson PCH LPC controller support
>
> Jianmin Lv (2):
> genirq/generic_chip: export irq_unmap_generic_chip
> irqchip: create library file for LoongArch irqchip driver
>
> Marc Zyngier (1):
> APCI: irq: Add support for multiple GSI domains
>
> drivers/acpi/bus.c | 3 +
> drivers/acpi/irq.c | 40 ++--
> drivers/irqchip/Kconfig | 28 +++
> drivers/irqchip/Makefile | 3 +
> drivers/irqchip/irq-gic-v3.c | 18 +-
> drivers/irqchip/irq-gic.c | 18 +-
> drivers/irqchip/irq-loongarch-cpu.c | 134 +++++++++++
> drivers/irqchip/irq-loongarch-pic-common.c | 122 ++++++++++
> drivers/irqchip/irq-loongarch-pic-common.h | 39 ++++
> drivers/irqchip/irq-loongson-eiointc.c | 347 +++++++++++++++++++++++++++++
> drivers/irqchip/irq-loongson-htvec.c | 119 +++++++---
> drivers/irqchip/irq-loongson-liointc.c | 225 ++++++++++++-------
> drivers/irqchip/irq-loongson-pch-lpc.c | 202 +++++++++++++++++
> drivers/irqchip/irq-loongson-pch-msi.c | 138 ++++++++----
> drivers/irqchip/irq-loongson-pch-pic.c | 171 +++++++++++---
> include/linux/acpi.h | 3 +-
> include/linux/cpuhotplug.h | 1 +
> include/linux/irq.h | 1 +
> kernel/irq/generic-chip.c | 2 +-
> 19 files changed, 1402 insertions(+), 212 deletions(-)
> create mode 100644 drivers/irqchip/irq-loongarch-cpu.c
> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
> create mode 100644 drivers/irqchip/irq-loongson-eiointc.c
> create mode 100644 drivers/irqchip/irq-loongson-pch-lpc.c

One thing I don't see here is the removal of the irq code that
currently lives in arch/loongarch/kernel/acpi.c. It really should be
removed as part of this series with the patch that enables the common
ACPI irq code for this architecture.

Thanks,

M.

--
Without deviation from the norm, progress is not possible.

2022-06-18 11:04:54

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

On Wed, 15 Jun 2022 10:28:47 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/6/15 下午3:14, Marc Zyngier wrote:
> > On Wed, 15 Jun 2022 07:07:21 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >> From: Marc Zyngier <[email protected]>
> >>
> >> In an unfortunate departure from the ACPI spec, the LoongArch
> >> architecture split its GSI space across multiple interrupt
> >> controllers.
> >>
> >> In order to be able to reuse sthe core code and prevent
> >> architectures from reinventing an already square wheel, offer
> >> the arch code the ability to register a dispatcher function
> >> that will return the domain fwnode for a given GSI.
> >>
> >> The ARM GIC drivers are updated to support this (with a single
> >> domain, as intended).
> >>
> >> Co-developed-by: Jianmin Lv <[email protected]>
> >
> > I don't think this tag is appropriate here.
> >
> >> Signed-off-by: Marc Zyngier <[email protected]>
> >> Cc: Hanjun Guo <[email protected]>
> >> Cc: Lorenzo Pieralisi <[email protected]>
> >> Signed-off-by: Jianmin Lv <[email protected]>
> >> ---
> >> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
> >> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
> >> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
> >> include/linux/acpi.h | 2 +-
> >> 4 files changed, 48 insertions(+), 30 deletions(-)
> >>
> >> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> >> index c68e694..b7460ab 100644
> >> --- a/drivers/acpi/irq.c
> >> +++ b/drivers/acpi/irq.c
> >> @@ -12,7 +12,7 @@
> >> enum acpi_irq_model_id acpi_irq_model;
> >> -static struct fwnode_handle *acpi_gsi_domain_id;
> >> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
> >> /**
> >> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> >> @@ -26,10 +26,7 @@
> >> */
> >> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> >> {
> >> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> >> - DOMAIN_BUS_ANY);
> >> -
> >> - *irq = irq_find_mapping(d, gsi);
> >> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
> >
> > What is this?
> >
> > - This wasn't part of my initial patch, and randomly changing patches
> > without mentioning it isn't acceptable
> >
> > - you *cannot* trigger a registration here, as this isn't what the API
> > advertises
> >
> > - what makes you think that passing random values (NULL, -1... )to
> > acpi_register_gsi() is an acceptable thing to do?
> >
> > The original patch had:
> >
> > @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
> > */
> > int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> > {
> > - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> > - DOMAIN_BUS_ANY);
> > + struct irq_domain *d;
> > +
> > + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
> > + DOMAIN_BUS_ANY);
> > *irq = irq_find_mapping(d, gsi);
> > /*
> >
> > and I don't think it needs anything else. If something breaks, let's
> > discuss it, but don't abuse the API nor the fact that I usually don't
> > review my own patches to sneak things in...
> >
>
> Sorry, Marc, I don't know how to communicate with you for my change
> here before submitting the patch, maybe I should mention it in the
> patch commit or code.

It should at least be discussed first, like you are doing it here.

> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
> only handle existed mapping and will return -EINVAL if mapping not
> found. When I test on my machine, a calling stack is as following:
>
>
> acpi_bus_init
> ->acpi_enable_subsystem
> ->acpi_ev_install_xrupt_handlers
> ->acpi_ev_install_sci_handler
> ->acpi_os_install_interrupt_handler
> ->acpi_gsi_to_irq
>
>
> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
> so that new mapping for gsi is created if no mapping is found.

So it looks like we have a discrepancy between the x86 and ARM on that
front.

Lorenzo, Hanjun, can you please have a look at this and shed some
light on what the expected behaviour is? It looks like we never
encountered an issue with this on arm64, which tends to indicate that
we don't usually use the above path.

> I looked into generic acpi_register_gsi, the existed mapping will be
> checked first by calling irq_find_mapping, so I think calling
> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>
> But you're right, I'm wrong that I passed random value of -1 to
> acpi_register_gsi. I don't find a right way to address the problem
> without changing acpi_gsi_to_irq. I'll continue to work for the
> problem.

At the very least, this should be indirected so that the existing
behaviour isn't affected, no matter how badly broken arm64 may or may
not be here. Please have a look at the patch below that should help
you with this.

Thanks,

M.

From 3e6b87ea49473d0eb384f42e76d584a1495a538c Mon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Sat, 18 Jun 2022 11:29:33 +0100
Subject: [PATCH] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific
fallback

It appears that the generic version of acpi_gsi_to_irq() doesn't
fallback to establishing a mapping if there is no pre-existing
one while the x86 version does.

While arm64 seems unaffected by it, LoongArch is relying on the x86
behaviour. In an effort to prevent new architectures from reinventing
the proverbial wheel, provide an optional callback that the arch code
can set to restore the x86 behaviour.

Hopefully we can eventually get rid of this in the future once
the expected behaviour has been clarified.

Reported-by: Jianmin Lv <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/acpi/irq.c | 8 ++++++--
include/linux/acpi.h | 1 +
2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index 6e1633ac1756..66c5f01995d0 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -13,6 +13,7 @@
enum acpi_irq_model_id acpi_irq_model;

static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
+static int (*acpi_gsi_to_irq_fallback)(u32 gsi);

/**
* acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
@@ -33,9 +34,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)

*irq = irq_find_mapping(d, gsi);
/*
- * *irq == 0 means no mapping, that should
- * be reported as a failure
+ * *irq == 0 means no mapping, that should be reported as a
+ * failure, unless there is an arch-specific fallback handler.
*/
+ if (!*irq && acpi_gsi_to_irq_fallback)
+ *irq = acpi_gsi_to_irq_fallback(gsi);
+
return (*irq > 0) ? 0 : -EINVAL;
}
EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 957e23f727ea..71d3719e3ec4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -357,6 +357,7 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);

void acpi_set_irq_model(enum acpi_irq_model_id model,
struct fwnode_handle *(*)(u32));
+void acpi_set_gsi_to_irq_fallback(int (*)(u32));

struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
unsigned int size,
--
2.34.1


--
Without deviation from the norm, progress is not possible.

2022-06-18 17:43:22

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 04/10] irqchip: create library file for LoongArch irqchip driver

On Wed, 15 Jun 2022 07:07:24 +0100,
Jianmin Lv <[email protected]> wrote:
>
> The library file contains following content:
> - Implement acpi_get_gsi_domain_id callback.
> - Implement initialization of vector group entries and APIs
> for building hierachy irqdomains.
>
> Signed-off-by: Jianmin Lv <[email protected]>
> ---
> drivers/irqchip/Makefile | 2 +-
> drivers/irqchip/irq-loongarch-pic-common.c | 122 +++++++++++++++++++++++++++++
> drivers/irqchip/irq-loongarch-pic-common.h | 39 +++++++++
> 3 files changed, 162 insertions(+), 1 deletion(-)
> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
>
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 6894a13..2d0d871 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -103,7 +103,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
> obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
> -obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
> +obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o
> obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
> obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
> obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
> diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c
> new file mode 100644
> index 0000000..2f75362
> --- /dev/null
> +++ b/drivers/irqchip/irq-loongarch-pic-common.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
> + */
> +
> +#include <linux/irq.h>
> +#include <linux/pci.h>
> +#include <linux/acpi.h>
> +#include "irq-loongarch-pic-common.h"
> +
> +static struct acpi_vector_group vector_group[MAX_IO_PICS];
> +
> +struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
> +
> +struct fwnode_handle *liointc_handle;
> +struct fwnode_handle *pch_lpc_handle;
> +struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
> +struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];

Why aren't these in individual drivers, and then have accessors to
retrieve them?

> +
> +static int find_pch_pic(u32 gsi)
> +{
> + int i, start, end;
> +
> + /* Find the PCH_PIC that manages this GSI. */
> + for (i = 0; i < MAX_IO_PICS; i++) {
> + struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
> +
> + if (!irq_cfg)
> + return -1;
> +
> + start = irq_cfg->gsi_base;
> + end = irq_cfg->gsi_base + irq_cfg->size;
> + if (gsi >= start && gsi < end)
> + return i;
> + }
> +
> + pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
> + return -1;
> +}

Same thing. This really should be in the PCH driver, and be called by
lpic_get_gsi_domain().

> +
> +struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
> +{
> + int id;
> + struct fwnode_handle *domain_handle = NULL;
> +
> + switch (gsi) {
> + case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
> + if (liointc_handle)
> + domain_handle = liointc_handle;
> + break;
> +
> + case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
> + if (pch_lpc_handle)
> + domain_handle = pch_lpc_handle;
> + break;
> +
> + case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
> + id = find_pch_pic(gsi);
> + if (id >= 0 && pch_pic_handle[id])
> + domain_handle = pch_pic_handle[id];
> +
> + break;
> + }
> +
> + return domain_handle;
> +}
> +
> +static int pci_mcfg_parse(struct acpi_table_header *header)
> +{
> + struct acpi_table_mcfg *mcfg;
> + struct acpi_mcfg_allocation *mptr;
> + int i, n;
> +
> + if (header->length < sizeof(struct acpi_table_mcfg))
> + return -EINVAL;
> +
> + n = (header->length - sizeof(struct acpi_table_mcfg)) /
> + sizeof(struct acpi_mcfg_allocation);
> + mcfg = (struct acpi_table_mcfg *)header;
> + mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
> +
> + for (i = 0; i < n; i++, mptr++)
> + vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf;
> +
> + return 0;
> +}
> +
> +void __init init_vector_parent_group(void)
> +{
> + acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
> +}

I really don't think the PCI code should be anywhere near
this. Frankly, this file looks like a dumping ground for totally
unrelated stuff.

> +
> +void acpi_set_vector_parent(int node, struct irq_domain *parent)
> +{
> + int i;
> +
> + if (cpu_has_flatmode)
> + node = cpu_to_node(node * CORES_PER_EIO_NODE);
> +
> + for (i = 0; i < MAX_IO_PICS; i++) {
> + if (node == vector_group[i].node) {
> + vector_group[i].parent = parent;
> + return;
> + }
> + }
> +}
> +
> +struct irq_domain *acpi_get_msi_parent(int index)
> +{
> + return vector_group[index].parent;
> +}
> +
> +struct irq_domain *acpi_get_pch_parent(int node)
> +{
> + int i;
> +
> + for (i = 0; i < MAX_IO_PICS; i++) {
> + if (node == vector_group[i].node)
> + return vector_group[i].parent;
> + }
> + return NULL;
> +}

Same thing. There is nothing "common" here. All this should be split
in the various drivers, where they belong.

M.

--
Without deviation from the norm, progress is not possible.

2022-06-20 02:38:12

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 00/10] irqchip: Add LoongArch-related irqchip drivers



On 2022/6/18 下午6:39, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 07:07:20 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>> LoongArch is a new RISC ISA, which is a bit like MIPS or RISC-V.
>> LoongArch includes a reduced 32-bit version (LA32R), a standard 32-bit
>> version (LA32S) and a 64-bit version (LA64). LoongArch use ACPI as its
>> boot protocol LoongArch-specific interrupt controllers (similar to APIC)
>> are already added in the ACPI Specification 6.5(which may be published in
>> early June this year and the board is reviewing the draft).
>>
>> Currently, LoongArch based processors (e.g. Loongson-3A5000) can only
>> work together with LS7A chipsets. The irq chips in LoongArch computers
>> include CPUINTC (CPU Core Interrupt Controller), LIOINTC (Legacy I/O
>> Interrupt Controller), EIOINTC (Extended I/O Interrupt Controller),
>> HTVECINTC (Hyper-Transport Vector Interrupt Controller), PCH-PIC (Main
>> Interrupt Controller in LS7A chipset), PCH-LPC (LPC Interrupt Controller
>> in LS7A chipset) and PCH-MSI (MSI Interrupt Controller).
>>
>> CPUINTC is a per-core controller (in CPU), LIOINTC/EIOINTC/HTVECINTC are
>> per-package controllers (in CPU), while PCH-PIC/PCH-LPC/PCH-MSI are all
>> controllers out of CPU (i.e., in chipsets). These controllers (in other
>> words, irqchips) are linked in a hierarchy, and there are two models of
>> hierarchy (legacy model and extended model).
>>
>> Legacy IRQ model:
>>
>> In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
>> interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
>> while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
>> gathered by HTVECINTC, and then go to LIOINTC, and then CPUINTC.
>>
>> +---------------------------------------------+
>> | |
>> | +-----+ +---------+ +-------+ |
>> | | IPI | --> | CPUINTC | <-- | Timer | |
>> | +-----+ +---------+ +-------+ |
>> | ^ |
>> | | |
>> | +---------+ +-------+ |
>> | | LIOINTC | <-- | UARTs | |
>> | +---------+ +-------+ |
>> | ^ |
>> | | |
>> | +-----------+ |
>> | | HTVECINTC | |
>> | +-----------+ |
>> | ^ ^ |
>> | | | |
>> | +---------+ +---------+ |
>> | | PCH-PIC | | PCH-MSI | |
>> | +---------+ +---------+ |
>> | ^ ^ ^ |
>> | | | | |
>> | +---------+ +---------+ +---------+ |
>> | | PCH-LPC | | Devices | | Devices | |
>> | +---------+ +---------+ +---------+ |
>> | ^ |
>> | | |
>> | +---------+ |
>> | | Devices | |
>> | +---------+ |
>> | |
>> | |
>> +---------------------------------------------+
>>
>> Extended IRQ model:
>>
>> In this model, the IPI (Inter-Processor Interrupt) and CPU Local Timer
>> interrupt go to CPUINTC directly, CPU UARTS interrupts go to LIOINTC,
>> while all other devices interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and
>> gathered by EIOINTC, and then go to to CPUINTC directly.
>>
>> +--------------------------------------------------------+
>> | |
>> | +-----+ +---------+ +-------+ |
>> | | IPI | --> | CPUINTC | <-- | Timer | |
>> | +-----+ +---------+ +-------+ |
>> | ^ ^ |
>> | | | |
>> | +---------+ +---------+ +-------+ |
>> | | EIOINTC | | LIOINTC | <-- | UARTs | |
>> | +---------+ +---------+ +-------+ |
>> | ^ ^ |
>> | | | |
>> | +---------+ +---------+ |
>> | | PCH-PIC | | PCH-MSI | |
>> | +---------+ +---------+ |
>> | ^ ^ ^ |
>> | | | | |
>> | +---------+ +---------+ +---------+ |
>> | | PCH-LPC | | Devices | | Devices | |
>> | +---------+ +---------+ +---------+ |
>> | ^ |
>> | | |
>> | +---------+ |
>> | | Devices | |
>> | +---------+ |
>> | |
>> | |
>> +--------------------------------------------------------+
>>
>> The hierarchy model is constructed by parsing irq contronler structures
>> in MADT. Some controllers((e.g. LIOINTC, HTVECINTC, EIOINTC and PCH-LPC)
>> are hardcodingly connected to their parents, so their irqdomins are
>> separately routed to their parents in a fixed way. Some controllers
>> (e.g. PCH-PIC and PCH-MSI) could be routed to different parents for different
>> CPU. The firmware will config EIOINTC for the newer CPU and config HTVECINTC
>> for old CPU in MADT. By this way, PCH-PIC and PCH-MSI irqdomain can only be
>> routed one parent irqdomin: HTVECINTC or EIOINTC.
>>
>>
>> Example of irqchip topology in a system with two chipsets:
>>
>> +------------------------------------------------------------+
>> | |
>> | +------------------+ |
>> | | CPUINTC | |
>> | +------------------+ |
>> | ^ ^ |
>> | | | |
>> | +----------+ +----------+ |
>> | | EIOINTC 0| | EIOINTC 1| |
>> | +----------+ +----------+ |
>> | ^ ^ ^ ^ |
>> | | | | | |
>> | +----------+ +----------+ +----------+ +----------+ |
>> | | PCH-PIC 0| | PCH-MSI 0| | PCH-PIC 1| | PCH-MSI 1| |
>> | +----------+ +----------+ +----------+ +----------+ |
>> | |
>> | |
>> +------------------------------------------------------------+
>>
>> For systems with two chipsets, there are tow group(consists of EIOINTC, PCH-PIC and PCH-MSI) irqdomains,
>> and each group has same node id. So we defined a structure to mantain the relation of node and it's parent irqdomain.
>>
>> struct acpi_vector_group {
>> int node;
>> struct irq_domain *parent;
>> };
>>
>> The initialization and use of acpi_vector_group array are following:
>>
>> 1 Entry of struct acpi_vector_group array initialization:
>>
>> By parsing MCFG, the node id(from bit44-47 of Base Address)of each pci segment is extracted. And from MADT, we have the node id of each EIOINTC.
>>
>> entrys[pci segment].node = node id of pci segment
>> entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)
>>
>> 2 Get parent irqdomain for PCH-PIC:
>>
>> From MADT, we have the node id of each PCH-PIC(from bit44-47 of Base Address).
>> if (node of entry i == node of PCH-PIC)
>> return entrys[i].parent;
>>
>> entrys[pci segment].node = node id of pci segment
>> entrys[pci segment].parent = EIOINTC irqdomain(node id of EIOINTC == node id of pci segment)
>>
>> 3 Get parent irqdomain for PCH-MSI of pci segment:
>>
>> return entrys[pci segment].parent;
>>
>> 4 How to select a correct irqdomain to map irq for a device?
>> For devices using legacy irq behind PCH-PIC, GSI is used to select correct PCH-PIC irqdomain.
>> For devices using msi irq behind PCH-MSI, the pci segmen of the device is used to select correct PCH-MSI irqdomain.
>>
>> V1 -> V2:
>> 1, Remove queued patches;
>> 2, Move common logic of DT/ACPI probing to common functions;
>> 3, Split .suspend()/.resume() functions to separate patches.
>>
>> V2 -> V3:
>> 1, Fix a bug for loongson-pch-pic probe;
>> 2, Some minor improvements for LPC controller.
>>
>> V3 -> V4:
>> 1, Rework the CPU interrupt controller driver;
>> 2, Some minor improvements for other controllers.
>>
>> V4 -> V5:
>> 1, Add a description of LoonArch's IRQ model;
>> 2, Support multiple EIOINTCs in one system;
>> 3, Some minor improvements for other controllers.
>>
>> V5 -> V6:
>> 1, Attach a fwnode to CPUINTC irq domain;
>> 2, Use raw spinlock instead of generic spinlock;
>> 3, Improve the method of restoring EIOINTC state;
>> 4, Update documentation, comments and commit messages.
>>
>> V6 -> V7:
>> 1, Fix build warnings reported by kernel test robot.
>>
>> V7 -> V8:
>> 1, Add arguments sanity checking for irqchip init functions;
>> 2, Support Loongson-3C5000 (One NUMA Node includes 4 EIOINTC Node).
>>
>> V8 -> V9:
>> 1, Rebase on 5.17-rc5;
>> 2, Update cover letter;
>> 3, Some small improvements.
>>
>> V9 -> V10:
>> 1, Rebase on 5.17-rc6;
>> 2, Fix build warnings reported by kernel test robot.
>>
>> V10 -> V11:
>> 1, Rebase on 5.18-rc4;
>> 2, Fix irq affinity setting for EIOINTC;
>> 3, Fix hwirq allocation failure for EIOINTC.
>>
>> V11 -> RFC:
>> 1, Refactored the way to build irqchip hierarchy topology.
>>
>> RFC -> RFC V2:
>> 1, Move all IO-interrupt related code to driver/irqchip from arch directory.
>> 2. Add description for an example of two chipsets system.
>>
>> RFC V2 -> RFC V3:
>> 1, Add support for multiple GSI domains
>> 2, Use ACPI_GENERIC_GSI for GSI handling
>> 3, Drop suspend-resume stuff
>> 4, Export fwnode handles instead of irq domain handles
>>
>> RFC V3 -> V12:
>> 1, Address patch attributions of the patch series
>>
>> Huacai Chen (7):
>> irqchip: Add LoongArch CPU interrupt controller support
>> irqchip/loongson-pch-pic: Add ACPI init support
>> irqchip/loongson-pch-msi: Add ACPI init support
>> irqchip/loongson-htvec: Add ACPI init support
>> irqchip/loongson-liointc: Add ACPI init support
>> irqchip: Add Loongson Extended I/O interrupt controller support
>> irqchip: Add Loongson PCH LPC controller support
>>
>> Jianmin Lv (2):
>> genirq/generic_chip: export irq_unmap_generic_chip
>> irqchip: create library file for LoongArch irqchip driver
>>
>> Marc Zyngier (1):
>> APCI: irq: Add support for multiple GSI domains
>>
>> drivers/acpi/bus.c | 3 +
>> drivers/acpi/irq.c | 40 ++--
>> drivers/irqchip/Kconfig | 28 +++
>> drivers/irqchip/Makefile | 3 +
>> drivers/irqchip/irq-gic-v3.c | 18 +-
>> drivers/irqchip/irq-gic.c | 18 +-
>> drivers/irqchip/irq-loongarch-cpu.c | 134 +++++++++++
>> drivers/irqchip/irq-loongarch-pic-common.c | 122 ++++++++++
>> drivers/irqchip/irq-loongarch-pic-common.h | 39 ++++
>> drivers/irqchip/irq-loongson-eiointc.c | 347 +++++++++++++++++++++++++++++
>> drivers/irqchip/irq-loongson-htvec.c | 119 +++++++---
>> drivers/irqchip/irq-loongson-liointc.c | 225 ++++++++++++-------
>> drivers/irqchip/irq-loongson-pch-lpc.c | 202 +++++++++++++++++
>> drivers/irqchip/irq-loongson-pch-msi.c | 138 ++++++++----
>> drivers/irqchip/irq-loongson-pch-pic.c | 171 +++++++++++---
>> include/linux/acpi.h | 3 +-
>> include/linux/cpuhotplug.h | 1 +
>> include/linux/irq.h | 1 +
>> kernel/irq/generic-chip.c | 2 +-
>> 19 files changed, 1402 insertions(+), 212 deletions(-)
>> create mode 100644 drivers/irqchip/irq-loongarch-cpu.c
>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
>> create mode 100644 drivers/irqchip/irq-loongson-eiointc.c
>> create mode 100644 drivers/irqchip/irq-loongson-pch-lpc.c
>
> One thing I don't see here is the removal of the irq code that
> currently lives in arch/loongarch/kernel/acpi.c. It really should be
> removed as part of this series with the patch that enables the common
> ACPI irq code for this architecture.
>

Ok, I'll add the change of removing arch irq code and enabling common
irq code to the patch series.

> Thanks,
>
> M.
>

2022-06-20 03:32:11

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/18 下午6:36, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 10:28:47 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/6/15 下午3:14, Marc Zyngier wrote:
>>> On Wed, 15 Jun 2022 07:07:21 +0100,
>>> Jianmin Lv <[email protected]> wrote:
>>>>
>>>> From: Marc Zyngier <[email protected]>
>>>>
>>>> In an unfortunate departure from the ACPI spec, the LoongArch
>>>> architecture split its GSI space across multiple interrupt
>>>> controllers.
>>>>
>>>> In order to be able to reuse sthe core code and prevent
>>>> architectures from reinventing an already square wheel, offer
>>>> the arch code the ability to register a dispatcher function
>>>> that will return the domain fwnode for a given GSI.
>>>>
>>>> The ARM GIC drivers are updated to support this (with a single
>>>> domain, as intended).
>>>>
>>>> Co-developed-by: Jianmin Lv <[email protected]>
>>>
>>> I don't think this tag is appropriate here.
>>>
>>>> Signed-off-by: Marc Zyngier <[email protected]>
>>>> Cc: Hanjun Guo <[email protected]>
>>>> Cc: Lorenzo Pieralisi <[email protected]>
>>>> Signed-off-by: Jianmin Lv <[email protected]>
>>>> ---
>>>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
>>>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
>>>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
>>>> include/linux/acpi.h | 2 +-
>>>> 4 files changed, 48 insertions(+), 30 deletions(-)
>>>>
>>>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>>>> index c68e694..b7460ab 100644
>>>> --- a/drivers/acpi/irq.c
>>>> +++ b/drivers/acpi/irq.c
>>>> @@ -12,7 +12,7 @@
>>>> enum acpi_irq_model_id acpi_irq_model;
>>>> -static struct fwnode_handle *acpi_gsi_domain_id;
>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>> /**
>>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>>>> @@ -26,10 +26,7 @@
>>>> */
>>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>> {
>>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>> - DOMAIN_BUS_ANY);
>>>> -
>>>> - *irq = irq_find_mapping(d, gsi);
>>>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>
>>> What is this?
>>>
>>> - This wasn't part of my initial patch, and randomly changing patches
>>> without mentioning it isn't acceptable
>>>
>>> - you *cannot* trigger a registration here, as this isn't what the API
>>> advertises
>>>
>>> - what makes you think that passing random values (NULL, -1... )to
>>> acpi_register_gsi() is an acceptable thing to do?
>>>
>>> The original patch had:
>>>
>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>> */
>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>> {
>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>> - DOMAIN_BUS_ANY);
>>> + struct irq_domain *d;
>>> +
>>> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>> + DOMAIN_BUS_ANY);
>>> *irq = irq_find_mapping(d, gsi);
>>> /*
>>>
>>> and I don't think it needs anything else. If something breaks, let's
>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>> review my own patches to sneak things in...
>>>
>>
>> Sorry, Marc, I don't know how to communicate with you for my change
>> here before submitting the patch, maybe I should mention it in the
>> patch commit or code.
>
> It should at least be discussed first, like you are doing it here.
>

Ok, thanks for your correcting.


>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>> only handle existed mapping and will return -EINVAL if mapping not
>> found. When I test on my machine, a calling stack is as following:
>>
>>
>> acpi_bus_init
>> ->acpi_enable_subsystem
>> ->acpi_ev_install_xrupt_handlers
>> ->acpi_ev_install_sci_handler
>> ->acpi_os_install_interrupt_handler
>> ->acpi_gsi_to_irq
>>
>>
>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>> so that new mapping for gsi is created if no mapping is found.
>
> So it looks like we have a discrepancy between the x86 and ARM on that
> front.
>

Yes, I think so.

> Lorenzo, Hanjun, can you please have a look at this and shed some
> light on what the expected behaviour is? It looks like we never
> encountered an issue with this on arm64, which tends to indicate that
> we don't usually use the above path.
>
>> I looked into generic acpi_register_gsi, the existed mapping will be
>> checked first by calling irq_find_mapping, so I think calling
>> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>>
>> But you're right, I'm wrong that I passed random value of -1 to
>> acpi_register_gsi. I don't find a right way to address the problem
>> without changing acpi_gsi_to_irq. I'll continue to work for the
>> problem.
>
> At the very least, this should be indirected so that the existing
> behaviour isn't affected, no matter how badly broken arm64 may or may
> not be here. Please have a look at the patch below that should help
> you with this.
>

Ok, Marc, thanks very much for your way to address the problem, I'll try
it on my machine. And I'll put the patch in my patch series without
change( :) ) if that works well.

> Thanks,
>
> M.
>
> From 3e6b87ea49473d0eb384f42e76d584a1495a538c Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <[email protected]>
> Date: Sat, 18 Jun 2022 11:29:33 +0100
> Subject: [PATCH] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific
> fallback
>
> It appears that the generic version of acpi_gsi_to_irq() doesn't
> fallback to establishing a mapping if there is no pre-existing
> one while the x86 version does.
>
> While arm64 seems unaffected by it, LoongArch is relying on the x86
> behaviour. In an effort to prevent new architectures from reinventing
> the proverbial wheel, provide an optional callback that the arch code
> can set to restore the x86 behaviour.
>
> Hopefully we can eventually get rid of this in the future once
> the expected behaviour has been clarified.
>
> Reported-by: Jianmin Lv <[email protected]>
> Signed-off-by: Marc Zyngier <[email protected]>
> ---
> drivers/acpi/irq.c | 8 ++++++--
> include/linux/acpi.h | 1 +
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> index 6e1633ac1756..66c5f01995d0 100644
> --- a/drivers/acpi/irq.c
> +++ b/drivers/acpi/irq.c
> @@ -13,6 +13,7 @@
> enum acpi_irq_model_id acpi_irq_model;
>
> static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
> +static int (*acpi_gsi_to_irq_fallback)(u32 gsi);
>
> /**
> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> @@ -33,9 +34,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>
> *irq = irq_find_mapping(d, gsi);
> /*
> - * *irq == 0 means no mapping, that should
> - * be reported as a failure
> + * *irq == 0 means no mapping, that should be reported as a
> + * failure, unless there is an arch-specific fallback handler.
> */
> + if (!*irq && acpi_gsi_to_irq_fallback)
> + *irq = acpi_gsi_to_irq_fallback(gsi);
> +
> return (*irq > 0) ? 0 : -EINVAL;
> }
> EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 957e23f727ea..71d3719e3ec4 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -357,6 +357,7 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
>
> void acpi_set_irq_model(enum acpi_irq_model_id model,
> struct fwnode_handle *(*)(u32));
> +void acpi_set_gsi_to_irq_fallback(int (*)(u32));
>
> struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
> unsigned int size,
>

2022-06-20 03:43:45

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 04/10] irqchip: create library file for LoongArch irqchip driver



On 2022/6/19 上午1:22, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 07:07:24 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>> The library file contains following content:
>> - Implement acpi_get_gsi_domain_id callback.
>> - Implement initialization of vector group entries and APIs
>> for building hierachy irqdomains.
>>
>> Signed-off-by: Jianmin Lv <[email protected]>
>> ---
>> drivers/irqchip/Makefile | 2 +-
>> drivers/irqchip/irq-loongarch-pic-common.c | 122 +++++++++++++++++++++++++++++
>> drivers/irqchip/irq-loongarch-pic-common.h | 39 +++++++++
>> 3 files changed, 162 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
>>
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 6894a13..2d0d871 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -103,7 +103,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
>> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
>> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
>> obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
>> -obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
>> +obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o
>> obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
>> obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
>> obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
>> diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c
>> new file mode 100644
>> index 0000000..2f75362
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-loongarch-pic-common.c
>> @@ -0,0 +1,122 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
>> + */
>> +
>> +#include <linux/irq.h>
>> +#include <linux/pci.h>
>> +#include <linux/acpi.h>
>> +#include "irq-loongarch-pic-common.h"
>> +
>> +static struct acpi_vector_group vector_group[MAX_IO_PICS];
>> +
>> +struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
>> +
>> +struct fwnode_handle *liointc_handle;
>> +struct fwnode_handle *pch_lpc_handle;
>> +struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
>> +struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>
> Why aren't these in individual drivers, and then have accessors to
> retrieve them?
>

Ok, I'll try to put them in individual drivers.


>> +
>> +static int find_pch_pic(u32 gsi)
>> +{
>> + int i, start, end;
>> +
>> + /* Find the PCH_PIC that manages this GSI. */
>> + for (i = 0; i < MAX_IO_PICS; i++) {
>> + struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
>> +
>> + if (!irq_cfg)
>> + return -1;
>> +
>> + start = irq_cfg->gsi_base;
>> + end = irq_cfg->gsi_base + irq_cfg->size;
>> + if (gsi >= start && gsi < end)
>> + return i;
>> + }
>> +
>> + pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
>> + return -1;
>> +}
>
> Same thing. This really should be in the PCH driver, and be called by
> lpic_get_gsi_domain().
>

Ok, I'll try to put them in PCH driver.


>> +
>> +struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
>> +{
>> + int id;
>> + struct fwnode_handle *domain_handle = NULL;
>> +
>> + switch (gsi) {
>> + case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
>> + if (liointc_handle)
>> + domain_handle = liointc_handle;
>> + break;
>> +
>> + case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
>> + if (pch_lpc_handle)
>> + domain_handle = pch_lpc_handle;
>> + break;
>> +
>> + case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
>> + id = find_pch_pic(gsi);
>> + if (id >= 0 && pch_pic_handle[id])
>> + domain_handle = pch_pic_handle[id];
>> +
>> + break;
>> + }
>> +
>> + return domain_handle;
>> +}
>> +
>> +static int pci_mcfg_parse(struct acpi_table_header *header)
>> +{
>> + struct acpi_table_mcfg *mcfg;
>> + struct acpi_mcfg_allocation *mptr;
>> + int i, n;
>> +
>> + if (header->length < sizeof(struct acpi_table_mcfg))
>> + return -EINVAL;
>> +
>> + n = (header->length - sizeof(struct acpi_table_mcfg)) /
>> + sizeof(struct acpi_mcfg_allocation);
>> + mcfg = (struct acpi_table_mcfg *)header;
>> + mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
>> +
>> + for (i = 0; i < n; i++, mptr++)
>> + vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf;
>> +
>> + return 0;
>> +}
>> +
>> +void __init init_vector_parent_group(void)
>> +{
>> + acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
>> +}
>
> I really don't think the PCI code should be anywhere near
> this. Frankly, this file looks like a dumping ground for totally
> unrelated stuff.
>


For ARM, the msi domain of a pci device is matched by comparing PCI
segment of it and PCI segment of msi domain's parent domain(its domain).
The PCI segment number here is as in MCFG and as returned by _SEG in the
namespace.

For LoongArch, a similar way is used, but we don't use
IORT-like table, rather, we directly used PCI segment and Base
address(node information is in bit44-47 of the address) in MCFG for it,
so we need to get them by early parsing MCFG before creating MSI and PCH
irqdomain(MSI and PCH irqdomain have the same node as their parent
irqdomain).

If the related code is not suitable to be here, Maybe I should put them
in arch/loongarch/kernel/irq.c and call init_vector_parent_group before
irqchip_init().


>> +
>> +void acpi_set_vector_parent(int node, struct irq_domain *parent)
>> +{
>> + int i;
>> +
>> + if (cpu_has_flatmode)
>> + node = cpu_to_node(node * CORES_PER_EIO_NODE);
>> +
>> + for (i = 0; i < MAX_IO_PICS; i++) {
>> + if (node == vector_group[i].node) {
>> + vector_group[i].parent = parent;
>> + return;
>> + }
>> + }
>> +}
>> +
>> +struct irq_domain *acpi_get_msi_parent(int index)
>> +{
>> + return vector_group[index].parent;
>> +}
>> +
>> +struct irq_domain *acpi_get_pch_parent(int node)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < MAX_IO_PICS; i++) {
>> + if (node == vector_group[i].node)
>> + return vector_group[i].parent;
>> + }
>> + return NULL;
>> +}
>
> Same thing. There is nothing "common" here. All this should be split
> in the various drivers, where they belong.
>

Ok, I'll try to put them in individual drivers. So the "common" file
here will be not needed any more.


> M.
>

2022-06-25 09:41:14

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/18 下午6:36, Marc Zyngier wrote:
> On Wed, 15 Jun 2022 10:28:47 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/6/15 下午3:14, Marc Zyngier wrote:
>>> On Wed, 15 Jun 2022 07:07:21 +0100,
>>> Jianmin Lv <[email protected]> wrote:
>>>>
>>>> From: Marc Zyngier <[email protected]>
>>>>
>>>> In an unfortunate departure from the ACPI spec, the LoongArch
>>>> architecture split its GSI space across multiple interrupt
>>>> controllers.
>>>>
>>>> In order to be able to reuse sthe core code and prevent
>>>> architectures from reinventing an already square wheel, offer
>>>> the arch code the ability to register a dispatcher function
>>>> that will return the domain fwnode for a given GSI.
>>>>
>>>> The ARM GIC drivers are updated to support this (with a single
>>>> domain, as intended).
>>>>
>>>> Co-developed-by: Jianmin Lv <[email protected]>
>>>
>>> I don't think this tag is appropriate here.
>>>
>>>> Signed-off-by: Marc Zyngier <[email protected]>
>>>> Cc: Hanjun Guo <[email protected]>
>>>> Cc: Lorenzo Pieralisi <[email protected]>
>>>> Signed-off-by: Jianmin Lv <[email protected]>
>>>> ---
>>>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
>>>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
>>>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
>>>> include/linux/acpi.h | 2 +-
>>>> 4 files changed, 48 insertions(+), 30 deletions(-)
>>>>
>>>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>>>> index c68e694..b7460ab 100644
>>>> --- a/drivers/acpi/irq.c
>>>> +++ b/drivers/acpi/irq.c
>>>> @@ -12,7 +12,7 @@
>>>> enum acpi_irq_model_id acpi_irq_model;
>>>> -static struct fwnode_handle *acpi_gsi_domain_id;
>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>> /**
>>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>>>> @@ -26,10 +26,7 @@
>>>> */
>>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>> {
>>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>> - DOMAIN_BUS_ANY);
>>>> -
>>>> - *irq = irq_find_mapping(d, gsi);
>>>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>
>>> What is this?
>>>
>>> - This wasn't part of my initial patch, and randomly changing patches
>>> without mentioning it isn't acceptable
>>>
>>> - you *cannot* trigger a registration here, as this isn't what the API
>>> advertises
>>>
>>> - what makes you think that passing random values (NULL, -1... )to
>>> acpi_register_gsi() is an acceptable thing to do?
>>>
>>> The original patch had:
>>>
>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>> */
>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>> {
>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>> - DOMAIN_BUS_ANY);
>>> + struct irq_domain *d;
>>> +
>>> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>> + DOMAIN_BUS_ANY);
>>> *irq = irq_find_mapping(d, gsi);
>>> /*
>>>
>>> and I don't think it needs anything else. If something breaks, let's
>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>> review my own patches to sneak things in...
>>>
>>
>> Sorry, Marc, I don't know how to communicate with you for my change
>> here before submitting the patch, maybe I should mention it in the
>> patch commit or code.
>
> It should at least be discussed first, like you are doing it here.
>
>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>> only handle existed mapping and will return -EINVAL if mapping not
>> found. When I test on my machine, a calling stack is as following:
>>
>>
>> acpi_bus_init
>> ->acpi_enable_subsystem
>> ->acpi_ev_install_xrupt_handlers
>> ->acpi_ev_install_sci_handler
>> ->acpi_os_install_interrupt_handler
>> ->acpi_gsi_to_irq
>>
>>
>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>> so that new mapping for gsi is created if no mapping is found.
>
> So it looks like we have a discrepancy between the x86 and ARM on that
> front.
>
> Lorenzo, Hanjun, can you please have a look at this and shed some
> light on what the expected behaviour is? It looks like we never
> encountered an issue with this on arm64, which tends to indicate that
> we don't usually use the above path.
>
>> I looked into generic acpi_register_gsi, the existed mapping will be
>> checked first by calling irq_find_mapping, so I think calling
>> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>>
>> But you're right, I'm wrong that I passed random value of -1 to
>> acpi_register_gsi. I don't find a right way to address the problem
>> without changing acpi_gsi_to_irq. I'll continue to work for the
>> problem.
>
> At the very least, this should be indirected so that the existing
> behaviour isn't affected, no matter how badly broken arm64 may or may
> not be here. Please have a look at the patch below that should help
> you with this.
>
> Thanks,
>
> M.
>
> From 3e6b87ea49473d0eb384f42e76d584a1495a538c Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <[email protected]>
> Date: Sat, 18 Jun 2022 11:29:33 +0100
> Subject: [PATCH] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific
> fallback
>
> It appears that the generic version of acpi_gsi_to_irq() doesn't
> fallback to establishing a mapping if there is no pre-existing
> one while the x86 version does.
>
> While arm64 seems unaffected by it, LoongArch is relying on the x86
> behaviour. In an effort to prevent new architectures from reinventing
> the proverbial wheel, provide an optional callback that the arch code
> can set to restore the x86 behaviour.
>
> Hopefully we can eventually get rid of this in the future once
> the expected behaviour has been clarified.
>
> Reported-by: Jianmin Lv <[email protected]>
> Signed-off-by: Marc Zyngier <[email protected]>
> ---
> drivers/acpi/irq.c | 8 ++++++--
> include/linux/acpi.h | 1 +
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> index 6e1633ac1756..66c5f01995d0 100644
> --- a/drivers/acpi/irq.c
> +++ b/drivers/acpi/irq.c
> @@ -13,6 +13,7 @@
> enum acpi_irq_model_id acpi_irq_model;
>
> static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
> +static int (*acpi_gsi_to_irq_fallback)(u32 gsi);
>
> /**
> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> @@ -33,9 +34,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>
> *irq = irq_find_mapping(d, gsi);
> /*
> - * *irq == 0 means no mapping, that should
> - * be reported as a failure
> + * *irq == 0 means no mapping, that should be reported as a
> + * failure, unless there is an arch-specific fallback handler.
> */
> + if (!*irq && acpi_gsi_to_irq_fallback)
> + *irq = acpi_gsi_to_irq_fallback(gsi);
> +
> return (*irq > 0) ? 0 : -EINVAL;
> }
> EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 957e23f727ea..71d3719e3ec4 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -357,6 +357,7 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
>
> void acpi_set_irq_model(enum acpi_irq_model_id model,
> struct fwnode_handle *(*)(u32));
> +void acpi_set_gsi_to_irq_fallback(int (*)(u32));
>

Hi, Marc

I want to make sure that if acpi_set_gsi_to_irq_fallback should be
implemented in driver/acpi/irq.c as acpi_set_irq_model, e.g.:

void __init acpi_set_gsi_to_irq_fallback(int (*fn)(u32))
{
acpi_gsi_to_irq_fallback = fn;
}

And then, arch related code can call acpi_set_gsi_to_irq_fallback
to register a callback.

> struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
> unsigned int size,
>

2022-06-27 07:58:22

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 04/10] irqchip: create library file for LoongArch irqchip driver

On Mon, 20 Jun 2022 04:12:10 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/6/19 上午1:22, Marc Zyngier wrote:
> > On Wed, 15 Jun 2022 07:07:24 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >> The library file contains following content:
> >> - Implement acpi_get_gsi_domain_id callback.
> >> - Implement initialization of vector group entries and APIs
> >> for building hierachy irqdomains.
> >>
> >> Signed-off-by: Jianmin Lv <[email protected]>
> >> ---
> >> drivers/irqchip/Makefile | 2 +-
> >> drivers/irqchip/irq-loongarch-pic-common.c | 122 +++++++++++++++++++++++++++++
> >> drivers/irqchip/irq-loongarch-pic-common.h | 39 +++++++++
> >> 3 files changed, 162 insertions(+), 1 deletion(-)
> >> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
> >> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
> >>
> >> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> >> index 6894a13..2d0d871 100644
> >> --- a/drivers/irqchip/Makefile
> >> +++ b/drivers/irqchip/Makefile
> >> @@ -103,7 +103,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
> >> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
> >> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
> >> obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
> >> -obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
> >> +obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o
> >> obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
> >> obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
> >> obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
> >> diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c
> >> new file mode 100644
> >> index 0000000..2f75362
> >> --- /dev/null
> >> +++ b/drivers/irqchip/irq-loongarch-pic-common.c
> >> @@ -0,0 +1,122 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
> >> + */
> >> +
> >> +#include <linux/irq.h>
> >> +#include <linux/pci.h>
> >> +#include <linux/acpi.h>
> >> +#include "irq-loongarch-pic-common.h"
> >> +
> >> +static struct acpi_vector_group vector_group[MAX_IO_PICS];
> >> +
> >> +struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
> >> +
> >> +struct fwnode_handle *liointc_handle;
> >> +struct fwnode_handle *pch_lpc_handle;
> >> +struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
> >> +struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
> >
> > Why aren't these in individual drivers, and then have accessors to
> > retrieve them?
> >
>
> Ok, I'll try to put them in individual drivers.
>
>
> >> +
> >> +static int find_pch_pic(u32 gsi)
> >> +{
> >> + int i, start, end;
> >> +
> >> + /* Find the PCH_PIC that manages this GSI. */
> >> + for (i = 0; i < MAX_IO_PICS; i++) {
> >> + struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
> >> +
> >> + if (!irq_cfg)
> >> + return -1;
> >> +
> >> + start = irq_cfg->gsi_base;
> >> + end = irq_cfg->gsi_base + irq_cfg->size;
> >> + if (gsi >= start && gsi < end)
> >> + return i;
> >> + }
> >> +
> >> + pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
> >> + return -1;
> >> +}
> >
> > Same thing. This really should be in the PCH driver, and be called by
> > lpic_get_gsi_domain().
> >
>
> Ok, I'll try to put them in PCH driver.
>
>
> >> +
> >> +struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
> >> +{
> >> + int id;
> >> + struct fwnode_handle *domain_handle = NULL;
> >> +
> >> + switch (gsi) {
> >> + case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
> >> + if (liointc_handle)
> >> + domain_handle = liointc_handle;
> >> + break;
> >> +
> >> + case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
> >> + if (pch_lpc_handle)
> >> + domain_handle = pch_lpc_handle;
> >> + break;
> >> +
> >> + case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
> >> + id = find_pch_pic(gsi);
> >> + if (id >= 0 && pch_pic_handle[id])
> >> + domain_handle = pch_pic_handle[id];
> >> +
> >> + break;
> >> + }
> >> +
> >> + return domain_handle;
> >> +}
> >> +
> >> +static int pci_mcfg_parse(struct acpi_table_header *header)
> >> +{
> >> + struct acpi_table_mcfg *mcfg;
> >> + struct acpi_mcfg_allocation *mptr;
> >> + int i, n;
> >> +
> >> + if (header->length < sizeof(struct acpi_table_mcfg))
> >> + return -EINVAL;
> >> +
> >> + n = (header->length - sizeof(struct acpi_table_mcfg)) /
> >> + sizeof(struct acpi_mcfg_allocation);
> >> + mcfg = (struct acpi_table_mcfg *)header;
> >> + mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
> >> +
> >> + for (i = 0; i < n; i++, mptr++)
> >> + vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +void __init init_vector_parent_group(void)
> >> +{
> >> + acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
> >> +}
> >
> > I really don't think the PCI code should be anywhere near
> > this. Frankly, this file looks like a dumping ground for totally
> > unrelated stuff.
> >
>
>
> For ARM, the msi domain of a pci device is matched by comparing PCI
> segment of it and PCI segment of msi domain's parent domain(its
> domain).
> The PCI segment number here is as in MCFG and as returned by _SEG in
> the namespace.
>
> For LoongArch, a similar way is used, but we don't use
> IORT-like table, rather, we directly used PCI segment and Base
> address(node information is in bit44-47 of the address) in MCFG for
> it, so we need to get them by early parsing MCFG before creating MSI
> and PCH irqdomain(MSI and PCH irqdomain have the same node as their
> parent
> irqdomain).
>
> If the related code is not suitable to be here, Maybe I should put
> them in arch/loongarch/kernel/irq.c and call init_vector_parent_group
> before irqchip_init().

That'd probably be better. This really is arch-specific stuff, and not
interrupt-controller related.

M.

--
Without deviation from the norm, progress is not possible.

2022-06-27 08:06:18

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/27 下午3:32, Marc Zyngier wrote:
> On Sat, 25 Jun 2022 10:34:34 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/6/18 下午6:36, Marc Zyngier wrote:
>>> On Wed, 15 Jun 2022 10:28:47 +0100,
>>> Jianmin Lv <[email protected]> wrote:
>>>>
>>>>
>>>>
>>>> On 2022/6/15 下午3:14, Marc Zyngier wrote:
>>>>> On Wed, 15 Jun 2022 07:07:21 +0100,
>>>>> Jianmin Lv <[email protected]> wrote:
>>>>>>
>>>>>> From: Marc Zyngier <[email protected]>
>>>>>>
>>>>>> In an unfortunate departure from the ACPI spec, the LoongArch
>>>>>> architecture split its GSI space across multiple interrupt
>>>>>> controllers.
>>>>>>
>>>>>> In order to be able to reuse sthe core code and prevent
>>>>>> architectures from reinventing an already square wheel, offer
>>>>>> the arch code the ability to register a dispatcher function
>>>>>> that will return the domain fwnode for a given GSI.
>>>>>>
>>>>>> The ARM GIC drivers are updated to support this (with a single
>>>>>> domain, as intended).
>>>>>>
>>>>>> Co-developed-by: Jianmin Lv <[email protected]>
>>>>>
>>>>> I don't think this tag is appropriate here.
>>>>>
>>>>>> Signed-off-by: Marc Zyngier <[email protected]>
>>>>>> Cc: Hanjun Guo <[email protected]>
>>>>>> Cc: Lorenzo Pieralisi <[email protected]>
>>>>>> Signed-off-by: Jianmin Lv <[email protected]>
>>>>>> ---
>>>>>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
>>>>>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
>>>>>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
>>>>>> include/linux/acpi.h | 2 +-
>>>>>> 4 files changed, 48 insertions(+), 30 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>>>>>> index c68e694..b7460ab 100644
>>>>>> --- a/drivers/acpi/irq.c
>>>>>> +++ b/drivers/acpi/irq.c
>>>>>> @@ -12,7 +12,7 @@
>>>>>> enum acpi_irq_model_id acpi_irq_model;
>>>>>> -static struct fwnode_handle *acpi_gsi_domain_id;
>>>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>>>> /**
>>>>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>>>>>> @@ -26,10 +26,7 @@
>>>>>> */
>>>>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>>> {
>>>>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>>>> - DOMAIN_BUS_ANY);
>>>>>> -
>>>>>> - *irq = irq_find_mapping(d, gsi);
>>>>>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>>>
>>>>> What is this?
>>>>>
>>>>> - This wasn't part of my initial patch, and randomly changing patches
>>>>> without mentioning it isn't acceptable
>>>>>
>>>>> - you *cannot* trigger a registration here, as this isn't what the API
>>>>> advertises
>>>>>
>>>>> - what makes you think that passing random values (NULL, -1... )to
>>>>> acpi_register_gsi() is an acceptable thing to do?
>>>>>
>>>>> The original patch had:
>>>>>
>>>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>>>> */
>>>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>> {
>>>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>>> - DOMAIN_BUS_ANY);
>>>>> + struct irq_domain *d;
>>>>> +
>>>>> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>>>> + DOMAIN_BUS_ANY);
>>>>> *irq = irq_find_mapping(d, gsi);
>>>>> /*
>>>>>
>>>>> and I don't think it needs anything else. If something breaks, let's
>>>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>>>> review my own patches to sneak things in...
>>>>>
>>>>
>>>> Sorry, Marc, I don't know how to communicate with you for my change
>>>> here before submitting the patch, maybe I should mention it in the
>>>> patch commit or code.
>>>
>>> It should at least be discussed first, like you are doing it here.
>>>
>>>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>>>> only handle existed mapping and will return -EINVAL if mapping not
>>>> found. When I test on my machine, a calling stack is as following:
>>>>
>>>>
>>>> acpi_bus_init
>>>> ->acpi_enable_subsystem
>>>> ->acpi_ev_install_xrupt_handlers
>>>> ->acpi_ev_install_sci_handler
>>>> ->acpi_os_install_interrupt_handler
>>>> ->acpi_gsi_to_irq
>>>>
>>>>
>>>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>>>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>>>> so that new mapping for gsi is created if no mapping is found.
>>>
>>> So it looks like we have a discrepancy between the x86 and ARM on that
>>> front.
>>>
>>> Lorenzo, Hanjun, can you please have a look at this and shed some
>>> light on what the expected behaviour is? It looks like we never
>>> encountered an issue with this on arm64, which tends to indicate that
>>> we don't usually use the above path.
>>>
>>>> I looked into generic acpi_register_gsi, the existed mapping will be
>>>> checked first by calling irq_find_mapping, so I think calling
>>>> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>>>>
>>>> But you're right, I'm wrong that I passed random value of -1 to
>>>> acpi_register_gsi. I don't find a right way to address the problem
>>>> without changing acpi_gsi_to_irq. I'll continue to work for the
>>>> problem.
>>>
>>> At the very least, this should be indirected so that the existing
>>> behaviour isn't affected, no matter how badly broken arm64 may or may
>>> not be here. Please have a look at the patch below that should help
>>> you with this.
>>>
>>> Thanks,
>>>
>>> M.
>>>
>>> From 3e6b87ea49473d0eb384f42e76d584a1495a538c Mon Sep 17 00:00:00 2001
>>> From: Marc Zyngier <[email protected]>
>>> Date: Sat, 18 Jun 2022 11:29:33 +0100
>>> Subject: [PATCH] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific
>>> fallback
>>>
>>> It appears that the generic version of acpi_gsi_to_irq() doesn't
>>> fallback to establishing a mapping if there is no pre-existing
>>> one while the x86 version does.
>>>
>>> While arm64 seems unaffected by it, LoongArch is relying on the x86
>>> behaviour. In an effort to prevent new architectures from reinventing
>>> the proverbial wheel, provide an optional callback that the arch code
>>> can set to restore the x86 behaviour.
>>>
>>> Hopefully we can eventually get rid of this in the future once
>>> the expected behaviour has been clarified.
>>>
>>> Reported-by: Jianmin Lv <[email protected]>
>>> Signed-off-by: Marc Zyngier <[email protected]>
>>> ---
>>> drivers/acpi/irq.c | 8 ++++++--
>>> include/linux/acpi.h | 1 +
>>> 2 files changed, 7 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
>>> index 6e1633ac1756..66c5f01995d0 100644
>>> --- a/drivers/acpi/irq.c
>>> +++ b/drivers/acpi/irq.c
>>> @@ -13,6 +13,7 @@
>>> enum acpi_irq_model_id acpi_irq_model;
>>> static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>> +static int (*acpi_gsi_to_irq_fallback)(u32 gsi);
>>> /**
>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>>> @@ -33,9 +34,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>> *irq = irq_find_mapping(d, gsi);
>>> /*
>>> - * *irq == 0 means no mapping, that should
>>> - * be reported as a failure
>>> + * *irq == 0 means no mapping, that should be reported as a
>>> + * failure, unless there is an arch-specific fallback handler.
>>> */
>>> + if (!*irq && acpi_gsi_to_irq_fallback)
>>> + *irq = acpi_gsi_to_irq_fallback(gsi);
>>> +
>>> return (*irq > 0) ? 0 : -EINVAL;
>>> }
>>> EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
>>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>>> index 957e23f727ea..71d3719e3ec4 100644
>>> --- a/include/linux/acpi.h
>>> +++ b/include/linux/acpi.h
>>> @@ -357,6 +357,7 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
>>> void acpi_set_irq_model(enum acpi_irq_model_id model,
>>> struct fwnode_handle *(*)(u32));
>>> +void acpi_set_gsi_to_irq_fallback(int (*)(u32));
>>>
>>
>> Hi, Marc
>>
>> I want to make sure that if acpi_set_gsi_to_irq_fallback should be
>> implemented in driver/acpi/irq.c as acpi_set_irq_model, e.g.:
>>
>> void __init acpi_set_gsi_to_irq_fallback(int (*fn)(u32))
>> {
>> acpi_gsi_to_irq_fallback = fn;
>> }
>>
>> And then, arch related code can call acpi_set_gsi_to_irq_fallback
>> to register a callback.
>
> Yes. I had something like that, but forgot to add it to the patch,
> apparently.
>

Ok, I'll add that to the patch, please check the change in next version.

>  M.
>

2022-06-27 08:07:34

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 04/10] irqchip: create library file for LoongArch irqchip driver



On 2022/6/27 下午3:34, Marc Zyngier wrote:
> On Mon, 20 Jun 2022 04:12:10 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/6/19 上午1:22, Marc Zyngier wrote:
>>> On Wed, 15 Jun 2022 07:07:24 +0100,
>>> Jianmin Lv <[email protected]> wrote:
>>>>
>>>> The library file contains following content:
>>>> - Implement acpi_get_gsi_domain_id callback.
>>>> - Implement initialization of vector group entries and APIs
>>>> for building hierachy irqdomains.
>>>>
>>>> Signed-off-by: Jianmin Lv <[email protected]>
>>>> ---
>>>> drivers/irqchip/Makefile | 2 +-
>>>> drivers/irqchip/irq-loongarch-pic-common.c | 122 +++++++++++++++++++++++++++++
>>>> drivers/irqchip/irq-loongarch-pic-common.h | 39 +++++++++
>>>> 3 files changed, 162 insertions(+), 1 deletion(-)
>>>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c
>>>> create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
>>>>
>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>>> index 6894a13..2d0d871 100644
>>>> --- a/drivers/irqchip/Makefile
>>>> +++ b/drivers/irqchip/Makefile
>>>> @@ -103,7 +103,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
>>>> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
>>>> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
>>>> obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
>>>> -obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
>>>> +obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o
>>>> obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
>>>> obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
>>>> obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
>>>> diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c
>>>> new file mode 100644
>>>> index 0000000..2f75362
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-loongarch-pic-common.c
>>>> @@ -0,0 +1,122 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (C) 2022 Loongson Limited, All Rights Reserved.
>>>> + */
>>>> +
>>>> +#include <linux/irq.h>
>>>> +#include <linux/pci.h>
>>>> +#include <linux/acpi.h>
>>>> +#include "irq-loongarch-pic-common.h"
>>>> +
>>>> +static struct acpi_vector_group vector_group[MAX_IO_PICS];
>>>> +
>>>> +struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
>>>> +
>>>> +struct fwnode_handle *liointc_handle;
>>>> +struct fwnode_handle *pch_lpc_handle;
>>>> +struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
>>>> +struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>>>
>>> Why aren't these in individual drivers, and then have accessors to
>>> retrieve them?
>>>
>>
>> Ok, I'll try to put them in individual drivers.
>>
>>
>>>> +
>>>> +static int find_pch_pic(u32 gsi)
>>>> +{
>>>> + int i, start, end;
>>>> +
>>>> + /* Find the PCH_PIC that manages this GSI. */
>>>> + for (i = 0; i < MAX_IO_PICS; i++) {
>>>> + struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
>>>> +
>>>> + if (!irq_cfg)
>>>> + return -1;
>>>> +
>>>> + start = irq_cfg->gsi_base;
>>>> + end = irq_cfg->gsi_base + irq_cfg->size;
>>>> + if (gsi >= start && gsi < end)
>>>> + return i;
>>>> + }
>>>> +
>>>> + pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
>>>> + return -1;
>>>> +}
>>>
>>> Same thing. This really should be in the PCH driver, and be called by
>>> lpic_get_gsi_domain().
>>>
>>
>> Ok, I'll try to put them in PCH driver.
>>
>>
>>>> +
>>>> +struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
>>>> +{
>>>> + int id;
>>>> + struct fwnode_handle *domain_handle = NULL;
>>>> +
>>>> + switch (gsi) {
>>>> + case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
>>>> + if (liointc_handle)
>>>> + domain_handle = liointc_handle;
>>>> + break;
>>>> +
>>>> + case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
>>>> + if (pch_lpc_handle)
>>>> + domain_handle = pch_lpc_handle;
>>>> + break;
>>>> +
>>>> + case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
>>>> + id = find_pch_pic(gsi);
>>>> + if (id >= 0 && pch_pic_handle[id])
>>>> + domain_handle = pch_pic_handle[id];
>>>> +
>>>> + break;
>>>> + }
>>>> +
>>>> + return domain_handle;
>>>> +}
>>>> +
>>>> +static int pci_mcfg_parse(struct acpi_table_header *header)
>>>> +{
>>>> + struct acpi_table_mcfg *mcfg;
>>>> + struct acpi_mcfg_allocation *mptr;
>>>> + int i, n;
>>>> +
>>>> + if (header->length < sizeof(struct acpi_table_mcfg))
>>>> + return -EINVAL;
>>>> +
>>>> + n = (header->length - sizeof(struct acpi_table_mcfg)) /
>>>> + sizeof(struct acpi_mcfg_allocation);
>>>> + mcfg = (struct acpi_table_mcfg *)header;
>>>> + mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
>>>> +
>>>> + for (i = 0; i < n; i++, mptr++)
>>>> + vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf;
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +void __init init_vector_parent_group(void)
>>>> +{
>>>> + acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
>>>> +}
>>>
>>> I really don't think the PCI code should be anywhere near
>>> this. Frankly, this file looks like a dumping ground for totally
>>> unrelated stuff.
>>>
>>
>>
>> For ARM, the msi domain of a pci device is matched by comparing PCI
>> segment of it and PCI segment of msi domain's parent domain(its
>> domain).
>> The PCI segment number here is as in MCFG and as returned by _SEG in
>> the namespace.
>>
>> For LoongArch, a similar way is used, but we don't use
>> IORT-like table, rather, we directly used PCI segment and Base
>> address(node information is in bit44-47 of the address) in MCFG for
>> it, so we need to get them by early parsing MCFG before creating MSI
>> and PCH irqdomain(MSI and PCH irqdomain have the same node as their
>> parent
>> irqdomain).
>>
>> If the related code is not suitable to be here, Maybe I should put
>> them in arch/loongarch/kernel/irq.c and call init_vector_parent_group
>> before irqchip_init().
>
> That'd probably be better. This really is arch-specific stuff, and not
> interrupt-controller related.
>

Ok, I'll do that in next version.

> M.
>

2022-06-27 08:22:27

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

On Sat, 25 Jun 2022 10:34:34 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/6/18 下午6:36, Marc Zyngier wrote:
> > On Wed, 15 Jun 2022 10:28:47 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >>
> >>
> >> On 2022/6/15 下午3:14, Marc Zyngier wrote:
> >>> On Wed, 15 Jun 2022 07:07:21 +0100,
> >>> Jianmin Lv <[email protected]> wrote:
> >>>>
> >>>> From: Marc Zyngier <[email protected]>
> >>>>
> >>>> In an unfortunate departure from the ACPI spec, the LoongArch
> >>>> architecture split its GSI space across multiple interrupt
> >>>> controllers.
> >>>>
> >>>> In order to be able to reuse sthe core code and prevent
> >>>> architectures from reinventing an already square wheel, offer
> >>>> the arch code the ability to register a dispatcher function
> >>>> that will return the domain fwnode for a given GSI.
> >>>>
> >>>> The ARM GIC drivers are updated to support this (with a single
> >>>> domain, as intended).
> >>>>
> >>>> Co-developed-by: Jianmin Lv <[email protected]>
> >>>
> >>> I don't think this tag is appropriate here.
> >>>
> >>>> Signed-off-by: Marc Zyngier <[email protected]>
> >>>> Cc: Hanjun Guo <[email protected]>
> >>>> Cc: Lorenzo Pieralisi <[email protected]>
> >>>> Signed-off-by: Jianmin Lv <[email protected]>
> >>>> ---
> >>>> drivers/acpi/irq.c | 40 +++++++++++++++++++++++-----------------
> >>>> drivers/irqchip/irq-gic-v3.c | 18 ++++++++++++------
> >>>> drivers/irqchip/irq-gic.c | 18 ++++++++++++------
> >>>> include/linux/acpi.h | 2 +-
> >>>> 4 files changed, 48 insertions(+), 30 deletions(-)
> >>>>
> >>>> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> >>>> index c68e694..b7460ab 100644
> >>>> --- a/drivers/acpi/irq.c
> >>>> +++ b/drivers/acpi/irq.c
> >>>> @@ -12,7 +12,7 @@
> >>>> enum acpi_irq_model_id acpi_irq_model;
> >>>> -static struct fwnode_handle *acpi_gsi_domain_id;
> >>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
> >>>> /**
> >>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> >>>> @@ -26,10 +26,7 @@
> >>>> */
> >>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> >>>> {
> >>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> >>>> - DOMAIN_BUS_ANY);
> >>>> -
> >>>> - *irq = irq_find_mapping(d, gsi);
> >>>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
> >>>
> >>> What is this?
> >>>
> >>> - This wasn't part of my initial patch, and randomly changing patches
> >>> without mentioning it isn't acceptable
> >>>
> >>> - you *cannot* trigger a registration here, as this isn't what the API
> >>> advertises
> >>>
> >>> - what makes you think that passing random values (NULL, -1... )to
> >>> acpi_register_gsi() is an acceptable thing to do?
> >>>
> >>> The original patch had:
> >>>
> >>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
> >>> */
> >>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> >>> {
> >>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
> >>> - DOMAIN_BUS_ANY);
> >>> + struct irq_domain *d;
> >>> +
> >>> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
> >>> + DOMAIN_BUS_ANY);
> >>> *irq = irq_find_mapping(d, gsi);
> >>> /*
> >>>
> >>> and I don't think it needs anything else. If something breaks, let's
> >>> discuss it, but don't abuse the API nor the fact that I usually don't
> >>> review my own patches to sneak things in...
> >>>
> >>
> >> Sorry, Marc, I don't know how to communicate with you for my change
> >> here before submitting the patch, maybe I should mention it in the
> >> patch commit or code.
> >
> > It should at least be discussed first, like you are doing it here.
> >
> >> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
> >> only handle existed mapping and will return -EINVAL if mapping not
> >> found. When I test on my machine, a calling stack is as following:
> >>
> >>
> >> acpi_bus_init
> >> ->acpi_enable_subsystem
> >> ->acpi_ev_install_xrupt_handlers
> >> ->acpi_ev_install_sci_handler
> >> ->acpi_os_install_interrupt_handler
> >> ->acpi_gsi_to_irq
> >>
> >>
> >> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
> >> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
> >> so that new mapping for gsi is created if no mapping is found.
> >
> > So it looks like we have a discrepancy between the x86 and ARM on that
> > front.
> >
> > Lorenzo, Hanjun, can you please have a look at this and shed some
> > light on what the expected behaviour is? It looks like we never
> > encountered an issue with this on arm64, which tends to indicate that
> > we don't usually use the above path.
> >
> >> I looked into generic acpi_register_gsi, the existed mapping will be
> >> checked first by calling irq_find_mapping, so I think calling
> >> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
> >>
> >> But you're right, I'm wrong that I passed random value of -1 to
> >> acpi_register_gsi. I don't find a right way to address the problem
> >> without changing acpi_gsi_to_irq. I'll continue to work for the
> >> problem.
> >
> > At the very least, this should be indirected so that the existing
> > behaviour isn't affected, no matter how badly broken arm64 may or may
> > not be here. Please have a look at the patch below that should help
> > you with this.
> >
> > Thanks,
> >
> > M.
> >
> > From 3e6b87ea49473d0eb384f42e76d584a1495a538c Mon Sep 17 00:00:00 2001
> > From: Marc Zyngier <[email protected]>
> > Date: Sat, 18 Jun 2022 11:29:33 +0100
> > Subject: [PATCH] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific
> > fallback
> >
> > It appears that the generic version of acpi_gsi_to_irq() doesn't
> > fallback to establishing a mapping if there is no pre-existing
> > one while the x86 version does.
> >
> > While arm64 seems unaffected by it, LoongArch is relying on the x86
> > behaviour. In an effort to prevent new architectures from reinventing
> > the proverbial wheel, provide an optional callback that the arch code
> > can set to restore the x86 behaviour.
> >
> > Hopefully we can eventually get rid of this in the future once
> > the expected behaviour has been clarified.
> >
> > Reported-by: Jianmin Lv <[email protected]>
> > Signed-off-by: Marc Zyngier <[email protected]>
> > ---
> > drivers/acpi/irq.c | 8 ++++++--
> > include/linux/acpi.h | 1 +
> > 2 files changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> > index 6e1633ac1756..66c5f01995d0 100644
> > --- a/drivers/acpi/irq.c
> > +++ b/drivers/acpi/irq.c
> > @@ -13,6 +13,7 @@
> > enum acpi_irq_model_id acpi_irq_model;
> > static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
> > +static int (*acpi_gsi_to_irq_fallback)(u32 gsi);
> > /**
> > * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
> > @@ -33,9 +34,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
> > *irq = irq_find_mapping(d, gsi);
> > /*
> > - * *irq == 0 means no mapping, that should
> > - * be reported as a failure
> > + * *irq == 0 means no mapping, that should be reported as a
> > + * failure, unless there is an arch-specific fallback handler.
> > */
> > + if (!*irq && acpi_gsi_to_irq_fallback)
> > + *irq = acpi_gsi_to_irq_fallback(gsi);
> > +
> > return (*irq > 0) ? 0 : -EINVAL;
> > }
> > EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
> > diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> > index 957e23f727ea..71d3719e3ec4 100644
> > --- a/include/linux/acpi.h
> > +++ b/include/linux/acpi.h
> > @@ -357,6 +357,7 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
> > void acpi_set_irq_model(enum acpi_irq_model_id model,
> > struct fwnode_handle *(*)(u32));
> > +void acpi_set_gsi_to_irq_fallback(int (*)(u32));
> >
>
> Hi, Marc
>
> I want to make sure that if acpi_set_gsi_to_irq_fallback should be
> implemented in driver/acpi/irq.c as acpi_set_irq_model, e.g.:
>
> void __init acpi_set_gsi_to_irq_fallback(int (*fn)(u32))
> {
> acpi_gsi_to_irq_fallback = fn;
> }
>
> And then, arch related code can call acpi_set_gsi_to_irq_fallback
> to register a callback.

Yes. I had something like that, but forgot to add it to the patch,
apparently.

 M.

--
Without deviation from the norm, progress is not possible.

2022-06-28 08:19:54

by Hanjun Guo

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

On 2022/6/18 18:36, Marc Zyngier wrote:
[...]
>>>> --- a/drivers/acpi/irq.c
>>>> +++ b/drivers/acpi/irq.c
>>>> @@ -12,7 +12,7 @@
>>>> enum acpi_irq_model_id acpi_irq_model;
>>>> -static struct fwnode_handle *acpi_gsi_domain_id;
>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>> /**
>>>> * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
>>>> @@ -26,10 +26,7 @@
>>>> */
>>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>> {
>>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>> - DOMAIN_BUS_ANY);
>>>> -
>>>> - *irq = irq_find_mapping(d, gsi);
>>>> + *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>
>>> What is this?
>>>
>>> - This wasn't part of my initial patch, and randomly changing patches
>>> without mentioning it isn't acceptable
>>>
>>> - you *cannot* trigger a registration here, as this isn't what the API
>>> advertises
>>>
>>> - what makes you think that passing random values (NULL, -1... )to
>>> acpi_register_gsi() is an acceptable thing to do?
>>>
>>> The original patch had:
>>>
>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>> */
>>> int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>> {
>>> - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
>>> - DOMAIN_BUS_ANY);
>>> + struct irq_domain *d;
>>> +
>>> + d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>> + DOMAIN_BUS_ANY);
>>> *irq = irq_find_mapping(d, gsi);
>>> /*
>>>
>>> and I don't think it needs anything else. If something breaks, let's
>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>> review my own patches to sneak things in...
>>>
>>
>> Sorry, Marc, I don't know how to communicate with you for my change
>> here before submitting the patch, maybe I should mention it in the
>> patch commit or code.
>
> It should at least be discussed first, like you are doing it here.
>
>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>> only handle existed mapping and will return -EINVAL if mapping not
>> found. When I test on my machine, a calling stack is as following:
>>
>>
>> acpi_bus_init
>> ->acpi_enable_subsystem
>> ->acpi_ev_install_xrupt_handlers
>> ->acpi_ev_install_sci_handler
>> ->acpi_os_install_interrupt_handler
>> ->acpi_gsi_to_irq
>>
>>
>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>> so that new mapping for gsi is created if no mapping is found.
>
> So it looks like we have a discrepancy between the x86 and ARM on that
> front.
>
> Lorenzo, Hanjun, can you please have a look at this and shed some
> light on what the expected behaviour is? It looks like we never
> encountered an issue with this on arm64, which tends to indicate that
> we don't usually use the above path.

Sorry for the late reply, I just noticed this tomorrow.

As you said, we never encountered Jianmin's issue on ARM64 hardware,
for the call stack which Jianmin shows, acpi_ev_install_xrupt_handlers()
is only called for non-reduced ACPI hardware, but ARM64 is always
defined as reduced ACPI hardware in the ACPI spec, from the first
supported version of ACPI spec for ARM.

Jianmin, is the LoongArch using the redunced hardware mode in ACPI?
if it's using SCI interrupt, I think not, correct me if I'm wrong.

>
>> I looked into generic acpi_register_gsi, the existed mapping will be
>> checked first by calling irq_find_mapping, so I think calling
>> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>>
>> But you're right, I'm wrong that I passed random value of -1 to
>> acpi_register_gsi. I don't find a right way to address the problem
>> without changing acpi_gsi_to_irq. I'll continue to work for the
>> problem.
>
> At the very least, this should be indirected so that the existing
> behaviour isn't affected, no matter how badly broken arm64 may or may
> not be here. Please have a look at the patch below that should help
> you with this.

Looks good to me, I will review and test the v13 patch set.

Thanks
Hanjun

2022-06-28 09:14:58

by 吕建民

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains



On 2022/6/28 下午3:42, Hanjun Guo wrote:
> On 2022/6/18 18:36, Marc Zyngier wrote:
> [...]
>>>>> --- a/drivers/acpi/irq.c
>>>>> +++ b/drivers/acpi/irq.c
>>>>> @@ -12,7 +12,7 @@
>>>>>      enum acpi_irq_model_id acpi_irq_model;
>>>>>    -static struct fwnode_handle *acpi_gsi_domain_id;
>>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>>>      /**
>>>>>     * acpi_gsi_to_irq() - Retrieve the linux irq number for a given
>>>>> GSI
>>>>> @@ -26,10 +26,7 @@
>>>>>     */
>>>>>    int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>>    {
>>>>> -    struct irq_domain *d =
>>>>> irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>>> -                            DOMAIN_BUS_ANY);
>>>>> -
>>>>> -    *irq = irq_find_mapping(d, gsi);
>>>>> +    *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>>
>>>> What is this?
>>>>
>>>> - This wasn't part of my initial patch, and randomly changing patches
>>>>     without mentioning it isn't acceptable
>>>>
>>>> - you *cannot* trigger a registration here, as this isn't what the API
>>>>     advertises
>>>>
>>>> - what makes you think that passing random values (NULL, -1... )to
>>>>     acpi_register_gsi() is an acceptable thing to do?
>>>>
>>>> The original patch had:
>>>>
>>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>>>      */
>>>>     int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>     {
>>>> -    struct irq_domain *d =
>>>> irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>> -                            DOMAIN_BUS_ANY);
>>>> +    struct irq_domain *d;
>>>> +
>>>> +    d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>>> +                     DOMAIN_BUS_ANY);
>>>>           *irq = irq_find_mapping(d, gsi);
>>>>         /*
>>>>
>>>> and I don't think it needs anything else. If something breaks, let's
>>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>>> review my own patches to sneak things in...
>>>>
>>>
>>> Sorry, Marc, I don't know how to communicate with you for my change
>>> here before submitting the patch, maybe I should mention it in the
>>> patch commit or code.
>>
>> It should at least be discussed first, like you are doing it here.
>>
>>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>>> only handle existed mapping and will return -EINVAL if mapping not
>>> found. When I test on my machine, a calling stack is as following:
>>>
>>>
>>> acpi_bus_init
>>> ->acpi_enable_subsystem
>>>    ->acpi_ev_install_xrupt_handlers
>>>      ->acpi_ev_install_sci_handler
>>>        ->acpi_os_install_interrupt_handler
>>>          ->acpi_gsi_to_irq
>>>
>>>
>>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>>> so that new mapping for gsi is created if no mapping is found.
>>
>> So it looks like we have a discrepancy between the x86 and ARM on that
>> front.
>>
>> Lorenzo, Hanjun, can you please have a look at this and shed some
>> light on what the expected behaviour is? It looks like we never
>> encountered an issue with this on arm64, which tends to indicate that
>> we don't usually use the above path.
>
> Sorry for the late reply, I just noticed this tomorrow.
>
> As you said, we never encountered Jianmin's issue on ARM64 hardware,
> for the call stack which Jianmin shows, acpi_ev_install_xrupt_handlers()
> is only called for non-reduced ACPI hardware, but ARM64 is always
> defined as reduced ACPI hardware in the ACPI spec, from the first
> supported version of ACPI spec for ARM.
>
> Jianmin, is the LoongArch using the redunced hardware mode in ACPI?
> if it's using SCI interrupt, I think not, correct me if I'm wrong.
>

Thanks for your reply, Hanjun, LoongArch uses non-reduced ACPI hardware,
so SCI interrupt is used, which is different from ARM using reduced
hardware.

>>
>>> I looked into generic acpi_register_gsi, the existed mapping will be
>>> checked first by calling irq_find_mapping, so I think calling
>>> acpi_register_gsi in acpi_gsi_to_irq can address the problem.
>>>
>>> But you're right, I'm wrong that I passed random value of -1 to
>>> acpi_register_gsi. I don't find a right way to address the problem
>>> without changing acpi_gsi_to_irq. I'll continue to work for the
>>> problem.
>>
>> At the very least, this should be indirected so that the existing
>> behaviour isn't affected, no matter how badly broken arm64 may or may
>> not be here. Please have a look at the patch below that should help
>> you with this.
>
> Looks good to me, I will review and test the v13 patch set.
>
> Thanks
> Hanjun

2022-06-28 09:46:47

by Hanjun Guo

[permalink] [raw]
Subject: Re: [PATCH V12 01/10] APCI: irq: Add support for multiple GSI domains

On 2022/6/28 16:45, Jianmin Lv wrote:
>
>
> On 2022/6/28 下午3:42, Hanjun Guo wrote:
>> On 2022/6/18 18:36, Marc Zyngier wrote:
>> [...]
>>>>>> --- a/drivers/acpi/irq.c
>>>>>> +++ b/drivers/acpi/irq.c
>>>>>> @@ -12,7 +12,7 @@
>>>>>>      enum acpi_irq_model_id acpi_irq_model;
>>>>>>    -static struct fwnode_handle *acpi_gsi_domain_id;
>>>>>> +static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
>>>>>>      /**
>>>>>>     * acpi_gsi_to_irq() - Retrieve the linux irq number for a
>>>>>> given GSI
>>>>>> @@ -26,10 +26,7 @@
>>>>>>     */
>>>>>>    int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>>>    {
>>>>>> -    struct irq_domain *d =
>>>>>> irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>>>> -                            DOMAIN_BUS_ANY);
>>>>>> -
>>>>>> -    *irq = irq_find_mapping(d, gsi);
>>>>>> +    *irq = acpi_register_gsi(NULL, gsi, -1, -1);
>>>>>
>>>>> What is this?
>>>>>
>>>>> - This wasn't part of my initial patch, and randomly changing patches
>>>>>     without mentioning it isn't acceptable
>>>>>
>>>>> - you *cannot* trigger a registration here, as this isn't what the API
>>>>>     advertises
>>>>>
>>>>> - what makes you think that passing random values (NULL, -1... )to
>>>>>     acpi_register_gsi() is an acceptable thing to do?
>>>>>
>>>>> The original patch had:
>>>>>
>>>>> @@ -26,8 +26,10 @@ static struct fwnode_handle *acpi_gsi_domain_id;
>>>>>      */
>>>>>     int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
>>>>>     {
>>>>> -    struct irq_domain *d =
>>>>> irq_find_matching_fwnode(acpi_gsi_domain_id,
>>>>> -                            DOMAIN_BUS_ANY);
>>>>> +    struct irq_domain *d;
>>>>> +
>>>>> +    d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
>>>>> +                     DOMAIN_BUS_ANY);
>>>>>           *irq = irq_find_mapping(d, gsi);
>>>>>         /*
>>>>>
>>>>> and I don't think it needs anything else. If something breaks, let's
>>>>> discuss it, but don't abuse the API nor the fact that I usually don't
>>>>> review my own patches to sneak things in...
>>>>>
>>>>
>>>> Sorry, Marc, I don't know how to communicate with you for my change
>>>> here before submitting the patch, maybe I should mention it in the
>>>> patch commit or code.
>>>
>>> It should at least be discussed first, like you are doing it here.
>>>
>>>> When I use the patch, I found that acpi_gsi_to_irq in driver/acpi/irq.c
>>>> only handle existed mapping and will return -EINVAL if mapping not
>>>> found. When I test on my machine, a calling stack is as following:
>>>>
>>>>
>>>> acpi_bus_init
>>>> ->acpi_enable_subsystem
>>>>    ->acpi_ev_install_xrupt_handlers
>>>>      ->acpi_ev_install_sci_handler
>>>>        ->acpi_os_install_interrupt_handler
>>>>          ->acpi_gsi_to_irq
>>>>
>>>>
>>>> the acpi_gsi_to_irq returned -EINVAL because of no mapping found. I
>>>> looked into acpi_gsi_to_irq of x86, acpi_register_gsi is called in it
>>>> so that new mapping for gsi is created if no mapping is found.
>>>
>>> So it looks like we have a discrepancy between the x86 and ARM on that
>>> front.
>>>
>>> Lorenzo, Hanjun, can you please have a look at this and shed some
>>> light on what the expected behaviour is? It looks like we never
>>> encountered an issue with this on arm64, which tends to indicate that
>>> we don't usually use the above path.
>>
>> Sorry for the late reply, I just noticed this tomorrow.

What? Tomorrow? more coffee is needed... it's yesterday...

>>
>> As you said, we never encountered Jianmin's issue on ARM64 hardware,
>> for the call stack which Jianmin shows, acpi_ev_install_xrupt_handlers()
>> is only called for non-reduced ACPI hardware, but ARM64 is always
>> defined as reduced ACPI hardware in the ACPI spec, from the first
>> supported version of ACPI spec for ARM.
>>
>> Jianmin, is the LoongArch using the redunced hardware mode in ACPI?
>> if it's using SCI interrupt, I think not, correct me if I'm wrong.
>>
>
> Thanks for your reply, Hanjun, LoongArch uses non-reduced ACPI hardware,
> so SCI interrupt is used, which is different from ARM using reduced
> hardware.

OK, so for ARM64, it will not call acpi_gsi_to_irq() before the
irqdomain and mapping created.

Thanks
Hanjun