2022-07-15 07:23:03

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 00/15] 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;
int pci_segment;
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)and pci segment are extracted. And from MADT, we have the node id of each EIOINTC.

entry.node = node id of pci segment
entry.pci_segment = pci segment (only for msi irqdomain)

By matching node id of entry and EIOINTC to set parent.

entry.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;

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

return entrys[i].parent; (i is the index of msi irqdomain)

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

V12 -> V13
1 Based on 5.19-rc2
2 Remove arch specified gsi code
3 Split some 'common' code into the various drivers where they belong.
4 Allow acpi_gsi_to_irq() to have an arch-specific fallback

V13 -> V14
1 Add LoongArch-specified APICs definition
2 Use the way in CPUINTC driver to call pch-pic and pch-msi entry
3 Fix compiling and regression issue for OF path

V14 -> V15
1 Expose fwnode_handle of CPUINTC domain instead of using get_xxx_irq() for CPUINTC driver
2 Fix EIOINTC driver: delete parent_data referencing and fix set_affinity bug
3 Use acpi_disabled for DT and ACPI runtime code path
4 Fix return type of arch-specific acpi_gsi_to_irq fallback
5 Fix compile bug tested by kernel test robot

Huacai Chen (9):
ACPICA: MADT: Add LoongArch APICs support
irqchip: Add Loongson PCH LPC controller support
irqchip: remove COMPILE_TEST for pch-pic and pch-msi
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 LoongArch CPU interrupt controller support

Jianmin Lv (4):
genirq/generic_chip: export irq_unmap_generic_chip
LoongArch: Use ACPI_GENERIC_GSI for gsi handling
LoongArch: prepare to support multiple pch-pic and pch-msi irqdomain
irqchip / ACPI: Introduce ACPI_IRQ_MODEL_LPIC for LoongArch

Marc Zyngier (2):
APCI: irq: Add support for multiple GSI domains
ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific fallback

arch/loongarch/Kconfig | 1 +
arch/loongarch/include/asm/irq.h | 46 ++--
arch/loongarch/kernel/acpi.c | 65 -----
arch/loongarch/kernel/irq.c | 57 +++-
arch/loongarch/kernel/time.c | 14 +-
arch/mips/include/asm/mach-loongson64/irq.h | 2 +-
drivers/acpi/bus.c | 3 +
drivers/acpi/irq.c | 58 ++--
drivers/irqchip/Kconfig | 32 ++-
drivers/irqchip/Makefile | 3 +
drivers/irqchip/irq-gic-v3.c | 18 +-
drivers/irqchip/irq-gic.c | 18 +-
drivers/irqchip/irq-loongarch-cpu.c | 157 +++++++++++
drivers/irqchip/irq-loongson-eiointc.c | 395 ++++++++++++++++++++++++++++
drivers/irqchip/irq-loongson-htvec.c | 145 +++++++---
drivers/irqchip/irq-loongson-liointc.c | 226 ++++++++++------
drivers/irqchip/irq-loongson-pch-lpc.c | 208 +++++++++++++++
drivers/irqchip/irq-loongson-pch-msi.c | 131 ++++++---
drivers/irqchip/irq-loongson-pch-pic.c | 178 ++++++++++---
include/acpi/actbl2.h | 127 ++++++++-
include/linux/acpi.h | 4 +-
include/linux/cpuhotplug.h | 1 +
include/linux/irq.h | 1 +
kernel/irq/generic-chip.c | 2 +-
24 files changed, 1576 insertions(+), 316 deletions(-)
create mode 100644 drivers/irqchip/irq-loongarch-cpu.c
create mode 100644 drivers/irqchip/irq-loongson-eiointc.c
create mode 100644 drivers/irqchip/irq-loongson-pch-lpc.c

--
1.8.3.1


2022-07-15 07:24:14

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 13/15] irqchip: Add Loongson Extended I/O interrupt controller support

From: Huacai Chen <[email protected]>

EIOINTC stands for "Extended I/O Interrupts" that described in Section
11.2 of "Loongson 3A5000 Processor Reference Manual". For more
information please refer Documentation/loongarch/irq-chip-model.rst.

Loongson-3A5000 has 4 cores per NUMA node, and each NUMA node has an
EIOINTC; while Loongson-3C5000 has 16 cores per NUMA node, and each NUMA
node has 4 EIOINTCs. In other words, 16 cores of one NUMA node in
Loongson-3C5000 are organized in 4 groups, each group connects to an
EIOINTC. We call the "group" here as an EIOINTC node, so each EIOINTC
node always includes 4 cores (both in Loongson-3A5000 and Loongson-
3C5000).

Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
arch/loongarch/include/asm/irq.h | 11 +-
drivers/irqchip/Kconfig | 10 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-loongson-eiointc.c | 395 +++++++++++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
5 files changed, 408 insertions(+), 10 deletions(-)
create mode 100644 drivers/irqchip/irq-loongson-eiointc.c

diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index a07315a..a826ac4 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -87,15 +87,6 @@ struct acpi_vector_group {
extern int find_pch_pic(u32 gsi);
extern int eiointc_get_node(int id);

-static inline void eiointc_enable(void)
-{
- uint64_t misc;
-
- misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
- misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
- iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
-}
-
struct acpi_madt_lio_pic;
struct acpi_madt_eio_pic;
struct acpi_madt_ht_pic;
@@ -107,7 +98,7 @@ static inline void eiointc_enable(void)

int liointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lio_pic *acpi_liointc);
-struct irq_domain *eiointc_acpi_init(struct irq_domain *parent,
+int eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc);

int htvec_acpi_init(struct irq_domain *parent,
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 8844e6b..8f077d3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -555,6 +555,16 @@ config LOONGSON_LIOINTC
help
Support for the Loongson Local I/O Interrupt Controller.

+config LOONGSON_EIOINTC
+ bool "Loongson Extend I/O Interrupt Controller"
+ depends on LOONGARCH
+ depends on MACH_LOONGSON64
+ default MACH_LOONGSON64
+ select IRQ_DOMAIN_HIERARCHY
+ select GENERIC_IRQ_CHIP
+ help
+ Support for the Loongson3 Extend I/O Interrupt Vector Controller.
+
config LOONGSON_HTPIC
bool "Loongson3 HyperTransport PIC Controller"
depends on MACH_LOONGSON64 && MIPS
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 242b8b3..0cfd4f0 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -104,6 +104,7 @@ 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_LOONGSON_LIOINTC) += irq-loongson-liointc.o
+obj-$(CONFIG_LOONGSON_EIOINTC) += irq-loongson-eiointc.o
obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o
obj-$(CONFIG_LOONGSON_PCH_PIC) += irq-loongson-pch-pic.o
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
new file mode 100644
index 0000000..80d8ca6
--- /dev/null
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Loongson Extend I/O Interrupt Controller support
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#define pr_fmt(fmt) "eiointc: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#define EIOINTC_REG_NODEMAP 0x14a0
+#define EIOINTC_REG_IPMAP 0x14c0
+#define EIOINTC_REG_ENABLE 0x1600
+#define EIOINTC_REG_BOUNCE 0x1680
+#define EIOINTC_REG_ISR 0x1800
+#define EIOINTC_REG_ROUTE 0x1c00
+
+#define VEC_REG_COUNT 4
+#define VEC_COUNT_PER_REG 64
+#define VEC_COUNT (VEC_REG_COUNT * VEC_COUNT_PER_REG)
+#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
+#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
+#define EIOINTC_ALL_ENABLE 0xffffffff
+
+#define MAX_EIO_NODES (NR_CPUS / CORES_PER_EIO_NODE)
+
+static int nr_pics;
+
+struct eiointc_priv {
+ u32 node;
+ nodemask_t node_map;
+ cpumask_t cpuspan_map;
+ struct fwnode_handle *domain_handle;
+ struct irq_domain *eiointc_domain;
+};
+
+static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
+
+static void eiointc_enable(void)
+{
+ uint64_t misc;
+
+ misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
+ misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+ iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
+}
+
+static int cpu_to_eio_node(int cpu)
+{
+ return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
+}
+
+static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode, nodemask_t *node_map)
+{
+ int i, node, cpu_node, route_node;
+ unsigned char coremap;
+ uint32_t pos_off, data, data_byte, data_mask;
+
+ pos_off = pos & ~3;
+ data_byte = pos & 3;
+ data_mask = ~BIT_MASK(data_byte) & 0xf;
+
+ /* Calculate node and coremap of target irq */
+ cpu_node = cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
+ coremap = BIT(cpu_logical_map(cpu) % CORES_PER_EIO_NODE);
+
+ for_each_online_cpu(i) {
+ node = cpu_to_eio_node(i);
+ if (!node_isset(node, *node_map))
+ continue;
+
+ /* EIO node 0 is in charge of inter-node interrupt dispatch */
+ route_node = (node == mnode) ? cpu_node : node;
+ data = ((coremap | (route_node << 4)) << (data_byte * 8));
+ csr_any_send(EIOINTC_REG_ROUTE + pos_off, data, data_mask, node * CORES_PER_EIO_NODE);
+ }
+}
+
+static DEFINE_RAW_SPINLOCK(affinity_lock);
+
+static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force)
+{
+ unsigned int cpu;
+ unsigned long flags;
+ uint32_t vector, regaddr;
+ struct cpumask intersect_affinity;
+ struct eiointc_priv *priv = d->domain->host_data;
+
+ raw_spin_lock_irqsave(&affinity_lock, flags);
+
+ cpumask_and(&intersect_affinity, affinity, cpu_online_mask);
+ cpumask_and(&intersect_affinity, &intersect_affinity, &priv->cpuspan_map);
+
+ if (cpumask_empty(&intersect_affinity)) {
+ raw_spin_unlock_irqrestore(&affinity_lock, flags);
+ return -EINVAL;
+ }
+ cpu = cpumask_first(&intersect_affinity);
+
+ vector = d->hwirq;
+ regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
+
+ /* Mask target vector */
+ csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)), 0x0, 0);
+ /* Set route for target vector */
+ eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
+ /* Unmask target vector */
+ csr_any_send(regaddr, EIOINTC_ALL_ENABLE, 0x0, 0);
+
+ irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
+ raw_spin_unlock_irqrestore(&affinity_lock, flags);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static int eiointc_index(int node)
+{
+ int i;
+
+ for (i = 0; i < nr_pics; i++) {
+ if (node_isset(node, eiointc_priv[i]->node_map))
+ return i;
+ }
+
+ return -1;
+}
+
+static int eiointc_router_init(unsigned int cpu)
+{
+ int i, bit;
+ uint32_t data;
+ uint32_t node = cpu_to_eio_node(cpu);
+ uint32_t index = eiointc_index(node);
+
+ if (index < 0) {
+ pr_err("Error: invalid nodemap!\n");
+ return -1;
+ }
+
+ if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
+ eiointc_enable();
+
+ for (i = 0; i < VEC_COUNT / 32; i++) {
+ data = (((1 << (i * 2 + 1)) << 16) | (1 << (i * 2)));
+ iocsr_write32(data, EIOINTC_REG_NODEMAP + i * 4);
+ }
+
+ for (i = 0; i < VEC_COUNT / 32 / 4; i++) {
+ bit = BIT(1 + index); /* Route to IP[1 + index] */
+ data = bit | (bit << 8) | (bit << 16) | (bit << 24);
+ iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
+ }
+
+ for (i = 0; i < VEC_COUNT / 4; i++) {
+ /* Route to Node-0 Core-0 */
+ if (index == 0)
+ bit = BIT(cpu_logical_map(0));
+ else
+ bit = (eiointc_priv[index]->node << 4) | 1;
+
+ data = bit | (bit << 8) | (bit << 16) | (bit << 24);
+ iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4);
+ }
+
+ for (i = 0; i < VEC_COUNT / 32; i++) {
+ data = 0xffffffff;
+ iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4);
+ iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4);
+ }
+ }
+
+ return 0;
+}
+
+static void eiointc_irq_dispatch(struct irq_desc *desc)
+{
+ int i;
+ u64 pending;
+ bool handled = false;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct eiointc_priv *priv = irq_desc_get_handler_data(desc);
+
+ chained_irq_enter(chip, desc);
+
+ for (i = 0; i < VEC_REG_COUNT; i++) {
+ pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
+ iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3));
+ while (pending) {
+ int bit = __ffs(pending);
+ int irq = bit + VEC_COUNT_PER_REG * i;
+
+ generic_handle_domain_irq(priv->eiointc_domain, irq);
+ pending &= ~BIT(bit);
+ handled = true;
+ }
+ }
+
+ if (!handled)
+ spurious_interrupt();
+
+ chained_irq_exit(chip, desc);
+}
+
+static void eiointc_ack_irq(struct irq_data *d)
+{
+}
+
+static void eiointc_mask_irq(struct irq_data *d)
+{
+}
+
+static void eiointc_unmask_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip eiointc_irq_chip = {
+ .name = "EIOINTC",
+ .irq_ack = eiointc_ack_irq,
+ .irq_mask = eiointc_mask_irq,
+ .irq_unmask = eiointc_unmask_irq,
+ .irq_set_affinity = eiointc_set_irq_affinity,
+};
+
+static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ int ret;
+ unsigned int i, type;
+ unsigned long hwirq = 0;
+ struct eiointc *priv = domain->host_data;
+
+ ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, hwirq + i, &eiointc_irq_chip,
+ priv, handle_edge_irq, NULL, NULL);
+ }
+
+ return 0;
+}
+
+static void eiointc_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+
+ irq_set_handler(virq + i, NULL);
+ irq_domain_reset_irq_data(d);
+ }
+}
+
+static const struct irq_domain_ops eiointc_domain_ops = {
+ .translate = irq_domain_translate_onecell,
+ .alloc = eiointc_domain_alloc,
+ .free = eiointc_domain_free,
+};
+
+static void acpi_set_vec_parent(int node, struct irq_domain *parent, struct acpi_vector_group *vec_group)
+{
+ 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 == vec_group[i].node) {
+ vec_group[i].parent = parent;
+ return;
+ }
+ }
+}
+
+struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group *vec_group)
+{
+ int i;
+
+ for (i = 0; i < MAX_IO_PICS; i++) {
+ if (node == vec_group[i].node)
+ return vec_group[i].parent;
+ }
+ return NULL;
+}
+
+static int __init
+pch_pic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
+ unsigned int node = (pchpic_entry->address >> 44) & 0xf;
+ struct irq_domain *parent = acpi_get_vec_parent(node, pch_group);
+
+ if (parent)
+ return pch_pic_acpi_init(parent, pchpic_entry);
+
+ return -EINVAL;
+}
+
+static int __init
+pch_msi_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
+ struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group);
+
+ if (parent)
+ return pch_msi_acpi_init(parent, pchmsi_entry);
+
+ return -EINVAL;
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
+ pch_pic_parse_madt, 0);
+ acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
+ pch_msi_parse_madt, 1);
+ return 0;
+}
+
+int __init eiointc_acpi_init(struct irq_domain *parent,
+ struct acpi_madt_eio_pic *acpi_eiointc)
+{
+ int i, parent_irq;
+ unsigned long node_map;
+ struct eiointc_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_eiointc);
+ if (!priv->domain_handle) {
+ pr_err("Unable to allocate domain handle\n");
+ goto out_free_priv;
+ }
+
+ priv->node = acpi_eiointc->node;
+ node_map = acpi_eiointc->node_map ? : -1ULL;
+
+ for_each_possible_cpu(i) {
+ if (node_map & (1ULL << cpu_to_eio_node(i))) {
+ node_set(cpu_to_eio_node(i), priv->node_map);
+ cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, cpumask_of(i));
+ }
+ }
+
+ /* Setup IRQ domain */
+ priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle, VEC_COUNT,
+ &eiointc_domain_ops, priv);
+ if (!priv->eiointc_domain) {
+ pr_err("loongson-eiointc: cannot add IRQ domain\n");
+ goto out_free_handle;
+ }
+
+ eiointc_priv[nr_pics++] = priv;
+
+ eiointc_router_init(0);
+
+ parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
+ irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
+
+ cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
+ "irqchip/loongarch/intc:starting",
+ eiointc_router_init, NULL);
+
+ acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group);
+ acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group);
+ acpi_cascade_irqdomain_init();
+
+ return 0;
+
+out_free_handle:
+ irq_domain_free_fwnode(priv->domain_handle);
+ priv->domain_handle = NULL;
+out_free_priv:
+ kfree(priv);
+
+ return -ENOMEM;
+}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 19f0dbf..de662f3 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -151,6 +151,7 @@ enum cpuhp_state {
CPUHP_AP_IRQ_BCM2836_STARTING,
CPUHP_AP_IRQ_MIPS_GIC_STARTING,
CPUHP_AP_IRQ_RISCV_STARTING,
+ CPUHP_AP_IRQ_LOONGARCH_STARTING,
CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
CPUHP_AP_ARM_MVEBU_COHERENCY,
CPUHP_AP_MICROCODE_LOADER,
--
1.8.3.1

2022-07-15 07:26:22

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 09/15] irqchip/loongson-pch-msi: Add ACPI init support

From: Huacai Chen <[email protected]>

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.

Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
arch/loongarch/include/asm/irq.h | 4 +-
arch/loongarch/kernel/irq.c | 1 -
drivers/irqchip/irq-loongson-pch-msi.c | 131 ++++++++++++++++++++++-----------
3 files changed, 91 insertions(+), 45 deletions(-)

diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index 74fef60..6022406 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -106,11 +106,12 @@ struct irq_domain *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 irq_domain *pch_msi_acpi_init(struct irq_domain *parent,
+int pch_msi_acpi_init(struct irq_domain *parent,
struct acpi_madt_msi_pic *acpi_pchmsi);
int pch_pic_acpi_init(struct irq_domain *parent,
struct acpi_madt_bio_pic *acpi_pchpic);
int find_pch_pic(u32 gsi);
+struct fwnode_handle *get_pch_msi_handle(int pci_segment);

extern struct acpi_madt_lio_pic *acpi_liointc;
extern struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS];
@@ -123,7 +124,6 @@ int pch_pic_acpi_init(struct irq_domain *parent,
extern struct irq_domain *cpu_domain;
extern struct irq_domain *liointc_domain;
extern struct fwnode_handle *pch_lpc_handle;
-extern struct irq_domain *pch_msi_domain[MAX_IO_PICS];
extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];

extern irqreturn_t loongson3_ipi_interrupt(int irq, void *dev);
diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c
index 866b2ee..ce21281 100644
--- a/arch/loongarch/kernel/irq.c
+++ b/arch/loongarch/kernel/irq.c
@@ -27,7 +27,6 @@

struct irq_domain *cpu_domain;
struct irq_domain *liointc_domain;
-struct irq_domain *pch_msi_domain[MAX_IO_PICS];

/*
* 'what should we do if we get a hw irq event on an illegal vector'.
diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-loongson-pch-msi.c
index e3801c4..b3f1f8e 100644
--- a/drivers/irqchip/irq-loongson-pch-msi.c
+++ b/drivers/irqchip/irq-loongson-pch-msi.c
@@ -15,6 +15,8 @@
#include <linux/pci.h>
#include <linux/slab.h>

+static int nr_pics;
+
struct pch_msi_data {
struct mutex msi_map_lock;
phys_addr_t doorbell;
@@ -23,6 +25,8 @@ struct pch_msi_data {
unsigned long *msi_map;
};

+static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
+
static void pch_msi_mask_msi_irq(struct irq_data *d)
{
pci_msi_mask_irq(d);
@@ -154,12 +158,12 @@ static void pch_msi_middle_domain_free(struct irq_domain *domain,
};

static int pch_msi_init_domains(struct pch_msi_data *priv,
- struct device_node *node,
- struct irq_domain *parent)
+ struct irq_domain *parent,
+ struct fwnode_handle *domain_handle)
{
struct irq_domain *middle_domain, *msi_domain;

- middle_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+ middle_domain = irq_domain_create_linear(domain_handle,
priv->num_irqs,
&pch_msi_middle_domain_ops,
priv);
@@ -171,7 +175,7 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
middle_domain->parent = parent;
irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS);

- msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
+ msi_domain = pci_msi_create_irq_domain(domain_handle,
&pch_msi_domain_info,
middle_domain);
if (!msi_domain) {
@@ -183,19 +187,11 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
return 0;
}

-static int pch_msi_init(struct device_node *node,
- struct device_node *parent)
+static int pch_msi_init(phys_addr_t msg_address, int irq_base, int irq_count,
+ struct irq_domain *parent_domain, struct fwnode_handle *domain_handle)
{
- struct pch_msi_data *priv;
- struct irq_domain *parent_domain;
- struct resource res;
int ret;
-
- parent_domain = irq_find_host(parent);
- if (!parent_domain) {
- pr_err("Failed to find the parent domain\n");
- return -ENXIO;
- }
+ struct pch_msi_data *priv;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -203,48 +199,99 @@ static int pch_msi_init(struct device_node *node,

mutex_init(&priv->msi_map_lock);

- ret = of_address_to_resource(node, 0, &res);
- if (ret) {
- pr_err("Failed to allocate resource\n");
- goto err_priv;
- }
-
- priv->doorbell = res.start;
-
- if (of_property_read_u32(node, "loongson,msi-base-vec",
- &priv->irq_first)) {
- pr_err("Unable to parse MSI vec base\n");
- ret = -EINVAL;
- goto err_priv;
- }
-
- if (of_property_read_u32(node, "loongson,msi-num-vecs",
- &priv->num_irqs)) {
- pr_err("Unable to parse MSI vec number\n");
- ret = -EINVAL;
- goto err_priv;
- }
+ priv->doorbell = msg_address;
+ priv->irq_first = irq_base;
+ priv->num_irqs = irq_count;

priv->msi_map = bitmap_zalloc(priv->num_irqs, GFP_KERNEL);
- if (!priv->msi_map) {
- ret = -ENOMEM;
+ if (!priv->msi_map)
goto err_priv;
- }

pr_debug("Registering %d MSIs, starting at %d\n",
priv->num_irqs, priv->irq_first);

- ret = pch_msi_init_domains(priv, node, parent_domain);
+ ret = pch_msi_init_domains(priv, parent_domain, domain_handle);
if (ret)
goto err_map;

+ pch_msi_handle[nr_pics++] = domain_handle;
return 0;

err_map:
bitmap_free(priv->msi_map);
err_priv:
kfree(priv);
- return ret;
+
+ return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+static int pch_msi_of_init(struct device_node *node, struct device_node *parent)
+{
+ int err;
+ int irq_base, irq_count;
+ struct resource res;
+ struct irq_domain *parent_domain;
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("Failed to find the parent domain\n");
+ return -ENXIO;
+ }
+
+ if (of_address_to_resource(node, 0, &res)) {
+ pr_err("Failed to allocate resource\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(node, "loongson,msi-base-vec", &irq_base)) {
+ pr_err("Unable to parse MSI vec base\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(node, "loongson,msi-num-vecs", &irq_count)) {
+ pr_err("Unable to parse MSI vec number\n");
+ return -EINVAL;
+ }
+
+ err = pch_msi_init(res.start, irq_base, irq_count, parent_domain, of_node_to_fwnode(node));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init);
+#endif
+
+#ifdef CONFIG_ACPI
+struct fwnode_handle *get_pch_msi_handle(int pci_segment)
+{
+ int i;
+
+ for (i = 0; i < MAX_IO_PICS; i++) {
+ if (msi_group[i].pci_segment == pci_segment)
+ return pch_msi_handle[i];
+ }
+ return NULL;
}

-IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_init);
+int __init pch_msi_acpi_init(struct irq_domain *parent,
+ struct acpi_madt_msi_pic *acpi_pchmsi)
+{
+ int ret;
+ struct fwnode_handle *domain_handle;
+
+ if (!acpi_pchmsi)
+ return -EINVAL;
+
+ domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchmsi);
+
+ ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
+ acpi_pchmsi->count, parent, domain_handle);
+ if (ret < 0)
+ irq_domain_free_fwnode(domain_handle);
+
+ return ret;
+}
+#endif
--
1.8.3.1

2022-07-15 07:26:41

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 03/15] ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific fallback

From: Marc Zyngier <[email protected]>

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]>
Signed-off-by: Jianmin Lv <[email protected]>
Tested-by: Hanjun Guo <[email protected]>
Reviewed-by: Hanjun Guo <[email protected]>
---
drivers/acpi/irq.c | 18 ++++++++++++++++--
include/linux/acpi.h | 1 +
2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index f0de768..dabe45e 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 u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);

/**
* acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
@@ -32,9 +33,12 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
DOMAIN_BUS_ANY);
*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);
@@ -302,6 +306,16 @@ void __init acpi_set_irq_model(enum acpi_irq_model_id model,
}

/**
+ * acpi_set_gsi_to_irq_fallback - Register a GSI transfer
+ * callback to fallback to arch specified implementation.
+ * @fn: arch-specific fallback handler
+ */
+void __init acpi_set_gsi_to_irq_fallback(u32 (*fn)(u32))
+{
+ acpi_gsi_to_irq_fallback = fn;
+}
+
+/**
* acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default
* GSI domain as its parent.
* @flags: Irq domain flags associated with the domain
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 957e23f..e2b60d5 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -357,6 +357,7 @@ static inline bool acpi_sci_irq_valid(void)

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

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

2022-07-15 07:47:54

by 吕建民

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

From: Huacai Chen <[email protected]>

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.

Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
arch/loongarch/include/asm/irq.h | 2 +-
drivers/irqchip/irq-loongson-htvec.c | 145 +++++++++++++++++++++++++++--------
2 files changed, 112 insertions(+), 35 deletions(-)

diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index 6022406..8775dc6 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -102,7 +102,7 @@ struct irq_domain *liointc_acpi_init(struct irq_domain *parent,
struct irq_domain *eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc);

-struct irq_domain *htvec_acpi_init(struct irq_domain *parent,
+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);
diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index 60a335d..65f4938 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -20,7 +20,6 @@
/* 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)
@@ -32,6 +31,8 @@ struct htvec {
raw_spinlock_t htvec_lock;
};

+static struct htvec *htvec_priv;
+
static void htvec_irq_dispatch(struct irq_desc *desc)
{
int i;
@@ -155,64 +156,140 @@ 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);
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(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:
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
+static int __init
+pch_pic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
+
+ return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry);
+}
+
+static int __init
+pch_msi_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
+
+ return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
+ pch_pic_parse_madt, 0);
+ acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
+ pch_msi_parse_madt, 0);
+ return 0;
+}
+
+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)
+ acpi_cascade_irqdomain_init();
+ else
+ irq_domain_free_fwnode(domain_handle);
+
+ return ret;
+}
+
+#endif
--
1.8.3.1

2022-07-15 07:49:32

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 11/15] irqchip/loongson-liointc: Add ACPI init support

From: Huacai Chen <[email protected]>

LIOINTC stands for "Legacy I/O Interrupts" that described in Section
11.1 of "Loongson 3A5000 Processor Reference Manual". For more
information please refer Documentation/loongarch/irq-chip-model.rst.

Co-developed-by: Jianmin Lv <[email protected]>
Signed-off-by: Jianmin Lv <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
arch/loongarch/include/asm/irq.h | 4 +-
arch/loongarch/kernel/irq.c | 1 -
drivers/irqchip/irq-loongson-liointc.c | 225 ++++++++++++++++++++++-----------
3 files changed, 152 insertions(+), 78 deletions(-)

diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index 8775dc6..b4c7956 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -97,7 +97,7 @@ static inline void eiointc_enable(void)

struct irq_domain *loongarch_cpu_irq_init(void);

-struct irq_domain *liointc_acpi_init(struct irq_domain *parent,
+int liointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lio_pic *acpi_liointc);
struct irq_domain *eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc);
@@ -122,7 +122,7 @@ int pch_pic_acpi_init(struct irq_domain *parent,
extern struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];

extern struct irq_domain *cpu_domain;
-extern struct irq_domain *liointc_domain;
+extern struct fwnode_handle *liointc_handle;
extern struct fwnode_handle *pch_lpc_handle;
extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];

diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c
index ce21281..b04201c 100644
--- a/arch/loongarch/kernel/irq.c
+++ b/arch/loongarch/kernel/irq.c
@@ -26,7 +26,6 @@
EXPORT_PER_CPU_SYMBOL(irq_stat);

struct irq_domain *cpu_domain;
-struct irq_domain *liointc_domain;

/*
* 'what should we do if we get a hw irq event on an illegal vector'.
diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 8d05d8b..93eb01b 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -23,7 +23,7 @@
#endif

#define LIOINTC_CHIP_IRQ 32
-#define LIOINTC_NUM_PARENT 4
+#define LIOINTC_NUM_PARENT 4
#define LIOINTC_NUM_CORES 4

#define LIOINTC_INTC_CHIP_START 0x20
@@ -41,6 +41,7 @@

#if defined(CONFIG_MIPS)
#define liointc_core_id get_ebase_cpunum()
+#define GSI_MIN_CPU_IRQ 0
#else
#define liointc_core_id get_csr_cpuid()
#endif
@@ -58,6 +59,8 @@ struct liointc_priv {
bool has_lpc_irq_errata;
};

+struct fwnode_handle *liointc_handle;
+
static void liointc_chained_handle_irq(struct irq_desc *desc)
{
struct liointc_handler_data *handler = irq_desc_get_handler_data(desc);
@@ -153,97 +156,79 @@ static void liointc_resume(struct irq_chip_generic *gc)
irq_gc_unlock_irqrestore(gc, flags);
}

-static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
-static const char * const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};
+static int parent_irq[LIOINTC_NUM_PARENT];
+static u32 parent_int_map[LIOINTC_NUM_PARENT];
+static const char *const parent_names[] = {"int0", "int1", "int2", "int3"};
+static const char *const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};

-static void __iomem *liointc_get_reg_byname(struct device_node *node,
- const char *name)
+static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
{
- int index = of_property_match_string(node, "reg-names", name);
-
- if (index < 0)
- return NULL;
-
- return of_iomap(node, index);
+ if (WARN_ON(intsize < 1))
+ return -EINVAL;
+ *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;
+ *out_type = IRQ_TYPE_NONE;
+ return 0;
}

-static int __init liointc_of_init(struct device_node *node,
- struct device_node *parent)
+static const struct irq_domain_ops acpi_irq_gc_ops = {
+ .map = irq_map_generic_chip,
+ .unmap = irq_unmap_generic_chip,
+ .xlate = liointc_domain_xlate,
+};
+
+static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
+ struct fwnode_handle *domain_handle, struct device_node *node)
{
+ int i, err;
+ void __iomem *base;
+ struct irq_chip_type *ct;
struct irq_chip_generic *gc;
struct irq_domain *domain;
- struct irq_chip_type *ct;
struct liointc_priv *priv;
- void __iomem *base;
- u32 of_parent_int_map[LIOINTC_NUM_PARENT];
- int parent_irq[LIOINTC_NUM_PARENT];
- bool have_parent = FALSE;
- int sz, i, err = 0;

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

- if (of_device_is_compatible(node, "loongson,liointc-2.0")) {
- base = liointc_get_reg_byname(node, "main");
- if (!base) {
- err = -ENODEV;
- goto out_free_priv;
- }
+ base = ioremap(addr, size);
+ if (!base)
+ goto out_free_priv;

- for (i = 0; i < LIOINTC_NUM_CORES; i++)
- priv->core_isr[i] = liointc_get_reg_byname(node, core_reg_names[i]);
- if (!priv->core_isr[0]) {
- err = -ENODEV;
- goto out_iounmap_base;
- }
- } else {
- base = of_iomap(node, 0);
- if (!base) {
- err = -ENODEV;
- goto out_free_priv;
- }
+ for (i = 0; i < LIOINTC_NUM_CORES; i++)
+ priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS;

- for (i = 0; i < LIOINTC_NUM_CORES; i++)
- priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS;
- }
+ for (i = 0; i < LIOINTC_NUM_PARENT; i++)
+ priv->handler[i].parent_int_map = parent_int_map[i];

- for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
- parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
- if (parent_irq[i] > 0)
- have_parent = TRUE;
- }
- if (!have_parent) {
- err = -ENODEV;
- goto out_iounmap_isr;
- }
+ if (revision > 1) {
+ for (i = 0; i < LIOINTC_NUM_CORES; i++) {
+ int index = of_property_match_string(node,
+ "reg-names", core_reg_names[i]);

- sz = of_property_read_variable_u32_array(node,
- "loongson,parent_int_map",
- &of_parent_int_map[0],
- LIOINTC_NUM_PARENT,
- LIOINTC_NUM_PARENT);
- if (sz < 4) {
- pr_err("loongson-liointc: No parent_int_map\n");
- err = -ENODEV;
- goto out_iounmap_isr;
- }
+ if (index < 0)
+ return -EINVAL;

- for (i = 0; i < LIOINTC_NUM_PARENT; i++)
- priv->handler[i].parent_int_map = of_parent_int_map[i];
+ priv->core_isr[i] = of_iomap(node, index);
+ }
+ }

/* Setup IRQ domain */
- domain = irq_domain_add_linear(node, 32,
+ if (!acpi_disabled)
+ domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
+ &acpi_irq_gc_ops, priv);
+ else
+ domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
&irq_generic_chip_ops, priv);
if (!domain) {
pr_err("loongson-liointc: cannot add IRQ domain\n");
- err = -EINVAL;
- goto out_iounmap_isr;
+ goto out_iounmap;
}

- err = irq_alloc_domain_generic_chips(domain, 32, 1,
- node->full_name, handle_level_irq,
- IRQ_NOPROBE, 0, 0);
+ err = irq_alloc_domain_generic_chips(domain, LIOINTC_CHIP_IRQ, 1,
+ (node ? node->full_name : "LIOINTC"),
+ handle_level_irq, 0, IRQ_NOPROBE, 0);
if (err) {
pr_err("loongson-liointc: unable to register IRQ domain\n");
goto out_free_domain;
@@ -299,24 +284,114 @@ static int __init liointc_of_init(struct device_node *node,
liointc_chained_handle_irq, &priv->handler[i]);
}

+ liointc_handle = domain_handle;
return 0;

out_free_domain:
irq_domain_remove(domain);
-out_iounmap_isr:
- for (i = 0; i < LIOINTC_NUM_CORES; i++) {
- if (!priv->core_isr[i])
- continue;
- iounmap(priv->core_isr[i]);
- }
-out_iounmap_base:
+out_iounmap:
iounmap(base);
out_free_priv:
kfree(priv);

- return err;
+ return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int __init liointc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ bool have_parent = FALSE;
+ int sz, i, index, revision, err = 0;
+ struct resource res;
+
+ if (!of_device_is_compatible(node, "loongson,liointc-2.0")) {
+ index = 0;
+ revision = 1;
+ } else {
+ index = of_property_match_string(node, "reg-names", "main");
+ revision = 2;
+ }
+
+ if (of_address_to_resource(node, index, &res))
+ return -EINVAL;
+
+ for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
+ parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
+ if (parent_irq[i] > 0)
+ have_parent = TRUE;
+ }
+ if (!have_parent)
+ return -ENODEV;
+
+ sz = of_property_read_variable_u32_array(node,
+ "loongson,parent_int_map",
+ &parent_int_map[0],
+ LIOINTC_NUM_PARENT,
+ LIOINTC_NUM_PARENT);
+ if (sz < 4) {
+ pr_err("loongson-liointc: No parent_int_map\n");
+ return -ENODEV;
+ }
+
+ err = liointc_init(res.start, resource_size(&res),
+ revision, of_node_to_fwnode(node), node);
+ if (err < 0)
+ return err;
+
+ return 0;
}

IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init);
IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+static int __init htintc_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_ht_pic *htintc_entry = (struct acpi_madt_ht_pic *)header;
+ struct irq_domain *parent = irq_find_matching_fwnode(liointc_handle, DOMAIN_BUS_ANY);
+
+ return htvec_acpi_init(parent, htintc_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_HT_PIC,
+ htintc_parse_madt, 0);
+ return 0;
+}
+
+int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)
+{
+ int ret;
+ struct fwnode_handle *domain_handle;
+
+ if (!acpi_liointc)
+ return -EINVAL;
+
+ parent_int_map[0] = acpi_liointc->cascade_map[0];
+ parent_int_map[1] = acpi_liointc->cascade_map[1];
+
+ parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]);
+ parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]);
+
+ domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_liointc);
+ if (!domain_handle) {
+ pr_err("Unable to allocate domain handle\n");
+ return -ENOMEM;
+ }
+ ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
+ 1, domain_handle, NULL);
+ if (ret == 0)
+ acpi_cascade_irqdomain_init();
+ else
+ irq_domain_free_fwnode(domain_handle);
+
+ return ret;
+}
+#endif
--
1.8.3.1

2022-07-15 07:49:41

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 05/15] LoongArch: Use ACPI_GENERIC_GSI for gsi handling

For LoongArch, generic gsi code(driver/acpi/irq.c) can be
reused after following patchs:

APCI: irq: Add support for multiple GSI domains
ACPI: irq: Allow acpi_gsi_to_irq() to have an arch-specific fallback

So, config ACPI_GENERIC_GSI for LoongArch with removing the gsi code
in arch directory.

Signed-off-by: Jianmin Lv <[email protected]>
---
arch/loongarch/Kconfig | 1 +
arch/loongarch/kernel/acpi.c | 65 --------------------------------------------
2 files changed, 1 insertion(+), 65 deletions(-)

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 1920d52..7f98fc0 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -112,6 +112,7 @@ config LOONGARCH
select TRACE_IRQFLAGS_SUPPORT
select USE_PERCPU_NUMA_NODE_ID
select ZONE_DMA32
+ select ACPI_GENERIC_GSI if ACPI

config 32BIT
bool
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index bb729ee..03aa145 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -25,7 +25,6 @@
int acpi_strict = 1; /* We have no workarounds on LoongArch */
int num_processors;
int disabled_cpus;
-enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;

u64 acpi_saved_sp;

@@ -33,70 +32,6 @@

#define PREFIX "ACPI: "

-int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
-{
- if (irqp != NULL)
- *irqp = acpi_register_gsi(NULL, gsi, -1, -1);
- return (*irqp >= 0) ? 0 : -EINVAL;
-}
-EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
-
-int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi)
-{
- if (gsi)
- *gsi = isa_irq;
- return 0;
-}
-
-/*
- * success: return IRQ number (>=0)
- * failure: return < 0
- */
-int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
-{
- struct irq_fwspec fwspec;
-
- switch (gsi) {
- case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
- fwspec.fwnode = liointc_domain->fwnode;
- fwspec.param[0] = gsi - GSI_MIN_CPU_IRQ;
- fwspec.param_count = 1;
-
- return irq_create_fwspec_mapping(&fwspec);
-
- case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
- if (!pch_lpc_domain)
- return -EINVAL;
-
- fwspec.fwnode = pch_lpc_domain->fwnode;
- fwspec.param[0] = gsi - GSI_MIN_LPC_IRQ;
- fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
- fwspec.param_count = 2;
-
- return irq_create_fwspec_mapping(&fwspec);
-
- case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
- if (!pch_pic_domain[0])
- return -EINVAL;
-
- fwspec.fwnode = pch_pic_domain[0]->fwnode;
- fwspec.param[0] = gsi - GSI_MIN_PCH_IRQ;
- fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
- fwspec.param_count = 2;
-
- return irq_create_fwspec_mapping(&fwspec);
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(acpi_register_gsi);
-
-void acpi_unregister_gsi(u32 gsi)
-{
-
-}
-EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
-
void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size)
{

--
1.8.3.1

2022-07-15 07:50:54

by 吕建民

[permalink] [raw]
Subject: [PATCH V15 15/15] irqchip / ACPI: Introduce ACPI_IRQ_MODEL_LPIC for LoongArch

For LoongArch, ACPI_IRQ_MODEL_LPIC is introduced, and then the
callback acpi_get_gsi_domain_id and acpi_gsi_to_irq_fallback are
implemented.

The acpi_get_gsi_domain_id callback returns related fwnode handle
of irqdomain for different GSI range.

The acpi_gsi_to_irq_fallback will create new mapping for gsi when
the mapping of it is not found.

Signed-off-by: Jianmin Lv <[email protected]>
---
drivers/acpi/bus.c | 3 +++
drivers/irqchip/irq-loongarch-cpu.c | 38 +++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 1 +
3 files changed, 42 insertions(+)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 86fa61a..63fbf00 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1145,6 +1145,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_PLATFORM:
message = "platform specific model";
break;
+ case ACPI_IRQ_MODEL_LPIC:
+ message = "LPIC";
+ break;
default:
pr_info("Unknown interrupt routing model\n");
return -ENODEV;
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 476f407..93a4b15 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -16,6 +16,42 @@
static struct irq_domain *irq_domain;
struct fwnode_handle *cpuintc_handle;

+static u32 lpic_gsi_to_irq(u32 gsi)
+{
+ /* Only pch irqdomain transferring is required for LoongArch. */
+ if (gsi >= GSI_MIN_PCH_IRQ && gsi <= GSI_MAX_PCH_IRQ)
+ return acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+
+ return 0;
+}
+
+static 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 void mask_loongarch_irq(struct irq_data *d)
{
clear_csr_ecfg(ECFGF(d->hwirq));
@@ -71,6 +107,8 @@ static int __init loongarch_cpu_irq_init(void)
panic("Failed to add irqdomain for LoongArch CPU");

set_handle_irq(&handle_cpu_irq);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
+ acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);

return 0;
}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index e2b60d5..76520f3 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -105,6 +105,7 @@ enum acpi_irq_model_id {
ACPI_IRQ_MODEL_IOSAPIC,
ACPI_IRQ_MODEL_PLATFORM,
ACPI_IRQ_MODEL_GIC,
+ ACPI_IRQ_MODEL_LPIC,
ACPI_IRQ_MODEL_COUNT
};

--
1.8.3.1

2022-07-16 18:49:30

by Marc Zyngier

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

On Fri, 15 Jul 2022 08:05:36 +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).

[...]

Compiling this series for loongarch with loongson3_defconfig on top of
5.19-rc3 results in the following:

loongarch64-linux-ld: drivers/irqchip/irq-loongson-eiointc.o: in function `.L60':
irq-loongson-eiointc.c:(.init.text+0x4c): undefined reference to `pch_msi_acpi_init'
loongarch64-linux-ld: drivers/irqchip/irq-loongson-htvec.o: in function `pch_msi_parse_madt':
irq-loongson-htvec.c:(.init.text+0x14): undefined reference to `pch_msi_acpi_init'
make: *** [Makefile:1164: vmlinux] Error 1

I *really* would have expected this series to be in a better shape
after over 15 rounds, but it looks like I'm expecting too much. I
haven't investigated the breakage, but this should (at the very least)
pass the defconfig test and optional drivers not being selected.

The corresponding MIPS configuration seems to build fine.

M.

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

2022-07-17 01:51:16

by 吕建民

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



On 2022/7/17 上午2:39, Marc Zyngier wrote:
> On Fri, 15 Jul 2022 08:05:36 +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).
>
> [...]
>
> Compiling this series for loongarch with loongson3_defconfig on top of
> 5.19-rc3 results in the following:
>
> loongarch64-linux-ld: drivers/irqchip/irq-loongson-eiointc.o: in function `.L60':
> irq-loongson-eiointc.c:(.init.text+0x4c): undefined reference to `pch_msi_acpi_init'
> loongarch64-linux-ld: drivers/irqchip/irq-loongson-htvec.o: in function `pch_msi_parse_madt':
> irq-loongson-htvec.c:(.init.text+0x14): undefined reference to `pch_msi_acpi_init'
> make: *** [Makefile:1164: vmlinux] Error 1
>
> I *really* would have expected this series to be in a better shape
> after over 15 rounds, but it looks like I'm expecting too much. I
> haven't investigated the breakage, but this should (at the very least)
> pass the defconfig test and optional drivers not being selected.
>
> The corresponding MIPS configuration seems to build fine.
>
> M.
>

Hi, Marc

Sorry for that first, pch_msi_acpi_init is defined in pch_msi driver
which is compiled depend on CONFIG_PCI, and I test the patches each time
with PCI patches and other(or else, kernel can not be boot), so I'm ok
for testing the patches. The PCI patches has been accepted by PCI
maintainers and will be merged in this merge window.

I don't know how to deal with this situation. Should I add *#ifdef
CONFIG_PCI* at position of calling pch_msi_acpi_init or some other way?

Thanks sincerely.

2022-07-17 10:15:03

by Marc Zyngier

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

On Sun, 17 Jul 2022 02:06:12 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/7/17 上午2:39, Marc Zyngier wrote:
> > On Fri, 15 Jul 2022 08:05:36 +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).
> >
> > [...]
> >
> > Compiling this series for loongarch with loongson3_defconfig on top of
> > 5.19-rc3 results in the following:
> >
> > loongarch64-linux-ld: drivers/irqchip/irq-loongson-eiointc.o: in function `.L60':
> > irq-loongson-eiointc.c:(.init.text+0x4c): undefined reference to `pch_msi_acpi_init'
> > loongarch64-linux-ld: drivers/irqchip/irq-loongson-htvec.o: in function `pch_msi_parse_madt':
> > irq-loongson-htvec.c:(.init.text+0x14): undefined reference to `pch_msi_acpi_init'
> > make: *** [Makefile:1164: vmlinux] Error 1
> >
> > I *really* would have expected this series to be in a better shape
> > after over 15 rounds, but it looks like I'm expecting too much. I
> > haven't investigated the breakage, but this should (at the very least)
> > pass the defconfig test and optional drivers not being selected.
> >
> > The corresponding MIPS configuration seems to build fine.
> >
> > M.
> >
>
> Hi, Marc
>
> Sorry for that first, pch_msi_acpi_init is defined in pch_msi driver
> which is compiled depend on CONFIG_PCI, and I test the patches each
> time with PCI patches and other(or else, kernel can not be boot), so
> I'm ok for testing the patches. The PCI patches has been accepted by
> PCI maintainers and will be merged in this merge window.

But each series *must* at the very least compile in isolation.

>
> I don't know how to deal with this situation. Should I add *#ifdef
> CONFIG_PCI* at position of calling pch_msi_acpi_init or some other
> way?

You could try something like this, which results in a kernel that
fully links with defconfig and no additional patch:

diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index ca468564fc85..4479d95867ec 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -99,8 +99,17 @@ 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);
+#if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI)
int pch_msi_acpi_init(struct irq_domain *parent,
- struct acpi_madt_msi_pic *acpi_pchmsi);
+ struct acpi_madt_msi_pic *acpi_pchmsi);
+#else
+static inline int pch_msi_acpi_init(struct irq_domain *parent,
+ struct acpi_madt_msi_pic *acpi_pchmsi)
+{
+ return 0;
+
+}
+#endif
int pch_pic_acpi_init(struct irq_domain *parent,
struct acpi_madt_bio_pic *acpi_pchpic);
int find_pch_pic(u32 gsi);

But the other issue is that you seem to call this function from two
different locations. This cannot be right, as there should be only one
probe order, and not multiple.

M.

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

2022-07-17 11:31:42

by 吕建民

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



On 2022/7/17 下午6:02, Marc Zyngier wrote:
> On Sun, 17 Jul 2022 02:06:12 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/7/17 上午2:39, Marc Zyngier wrote:
>>> On Fri, 15 Jul 2022 08:05:36 +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).
>>>
>>> [...]
>>>
>>> Compiling this series for loongarch with loongson3_defconfig on top of
>>> 5.19-rc3 results in the following:
>>>
>>> loongarch64-linux-ld: drivers/irqchip/irq-loongson-eiointc.o: in function `.L60':
>>> irq-loongson-eiointc.c:(.init.text+0x4c): undefined reference to `pch_msi_acpi_init'
>>> loongarch64-linux-ld: drivers/irqchip/irq-loongson-htvec.o: in function `pch_msi_parse_madt':
>>> irq-loongson-htvec.c:(.init.text+0x14): undefined reference to `pch_msi_acpi_init'
>>> make: *** [Makefile:1164: vmlinux] Error 1
>>>
>>> I *really* would have expected this series to be in a better shape
>>> after over 15 rounds, but it looks like I'm expecting too much. I
>>> haven't investigated the breakage, but this should (at the very least)
>>> pass the defconfig test and optional drivers not being selected.
>>>
>>> The corresponding MIPS configuration seems to build fine.
>>>
>>> M.
>>>
>>
>> Hi, Marc
>>
>> Sorry for that first, pch_msi_acpi_init is defined in pch_msi driver
>> which is compiled depend on CONFIG_PCI, and I test the patches each
>> time with PCI patches and other(or else, kernel can not be boot), so
>> I'm ok for testing the patches. The PCI patches has been accepted by
>> PCI maintainers and will be merged in this merge window.
>
> But each series *must* at the very least compile in isolation.
>
>>
>> I don't know how to deal with this situation. Should I add *#ifdef
>> CONFIG_PCI* at position of calling pch_msi_acpi_init or some other
>> way?
>
> You could try something like this, which results in a kernel that
> fully links with defconfig and no additional patch:
>
> diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
> index ca468564fc85..4479d95867ec 100644
> --- a/arch/loongarch/include/asm/irq.h
> +++ b/arch/loongarch/include/asm/irq.h
> @@ -99,8 +99,17 @@ 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);
> +#if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI)
> int pch_msi_acpi_init(struct irq_domain *parent,
> - struct acpi_madt_msi_pic *acpi_pchmsi);
> + struct acpi_madt_msi_pic *acpi_pchmsi);
> +#else
> +static inline int pch_msi_acpi_init(struct irq_domain *parent,
> + struct acpi_madt_msi_pic *acpi_pchmsi)
> +{
> + return 0;
> +
> +}
> +#endif
> int pch_pic_acpi_init(struct irq_domain *parent,
> struct acpi_madt_bio_pic *acpi_pchpic);
> int find_pch_pic(u32 gsi);
>

Ok, thanks, I'll add this into that patch.


> But the other issue is that you seem to call this function from two
> different locations. This cannot be right, as there should be only one
> probe order, and not multiple.
>

As we described two IRQ models(Legacy and Extended) in this cover
letter, the parent domain of MSI domain can be htvec domain(Legacy) or
eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
EIOPIC for eiointc) is allowed to pass into kernel, and then in the
irqchip driver, only one kind APIC of them can be parsed from MADT, so
we have to support two probe order for them.

> M.
>

2022-07-17 14:42:37

by Huacai Chen

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

Hi, Marc, Jianmin,

On Sun, Jul 17, 2022 at 7:29 PM Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/7/17 下午6:02, Marc Zyngier wrote:
> > On Sun, 17 Jul 2022 02:06:12 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >>
> >>
> >> On 2022/7/17 上午2:39, Marc Zyngier wrote:
> >>> On Fri, 15 Jul 2022 08:05:36 +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).
> >>>
> >>> [...]
> >>>
> >>> Compiling this series for loongarch with loongson3_defconfig on top of
> >>> 5.19-rc3 results in the following:
> >>>
> >>> loongarch64-linux-ld: drivers/irqchip/irq-loongson-eiointc.o: in function `.L60':
> >>> irq-loongson-eiointc.c:(.init.text+0x4c): undefined reference to `pch_msi_acpi_init'
> >>> loongarch64-linux-ld: drivers/irqchip/irq-loongson-htvec.o: in function `pch_msi_parse_madt':
> >>> irq-loongson-htvec.c:(.init.text+0x14): undefined reference to `pch_msi_acpi_init'
> >>> make: *** [Makefile:1164: vmlinux] Error 1
> >>>
> >>> I *really* would have expected this series to be in a better shape
> >>> after over 15 rounds, but it looks like I'm expecting too much. I
> >>> haven't investigated the breakage, but this should (at the very least)
> >>> pass the defconfig test and optional drivers not being selected.
> >>>
> >>> The corresponding MIPS configuration seems to build fine.
> >>>
> >>> M.
> >>>
> >>
> >> Hi, Marc
> >>
> >> Sorry for that first, pch_msi_acpi_init is defined in pch_msi driver
> >> which is compiled depend on CONFIG_PCI, and I test the patches each
> >> time with PCI patches and other(or else, kernel can not be boot), so
> >> I'm ok for testing the patches. The PCI patches has been accepted by
> >> PCI maintainers and will be merged in this merge window.
> >
> > But each series *must* at the very least compile in isolation.
> >
> >>
> >> I don't know how to deal with this situation. Should I add *#ifdef
> >> CONFIG_PCI* at position of calling pch_msi_acpi_init or some other
> >> way?
> >
> > You could try something like this, which results in a kernel that
> > fully links with defconfig and no additional patch:
> >
> > diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
> > index ca468564fc85..4479d95867ec 100644
> > --- a/arch/loongarch/include/asm/irq.h
> > +++ b/arch/loongarch/include/asm/irq.h
> > @@ -99,8 +99,17 @@ 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);
> > +#if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI)
> > int pch_msi_acpi_init(struct irq_domain *parent,
> > - struct acpi_madt_msi_pic *acpi_pchmsi);
> > + struct acpi_madt_msi_pic *acpi_pchmsi);
> > +#else
> > +static inline int pch_msi_acpi_init(struct irq_domain *parent,
> > + struct acpi_madt_msi_pic *acpi_pchmsi)
> > +{
> > + return 0;
> > +
> > +}
> > +#endif
> > int pch_pic_acpi_init(struct irq_domain *parent,
> > struct acpi_madt_bio_pic *acpi_pchpic);
> > int find_pch_pic(u32 gsi);
> >
>
> Ok, thanks, I'll add this into that patch.
>
>
> > But the other issue is that you seem to call this function from two
> > different locations. This cannot be right, as there should be only one
> > probe order, and not multiple.
> >
>
> As we described two IRQ models(Legacy and Extended) in this cover
> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
> irqchip driver, only one kind APIC of them can be parsed from MADT, so
> we have to support two probe order for them.

I have an idea but I don't know whether it is acceptable: Marc gives
an Acked-by for the whole series, then this irqchip series goes
through the loongarch tree together with the PCI patches, then we
don't need other hacks except the ACPI definitions.

Huacai
>
> > M.
> >
>
>

2022-07-17 14:45:12

by Marc Zyngier

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

On Sun, 17 Jul 2022 15:08:14 +0100,
Huacai Chen <[email protected]> wrote:
>
> Hi, Marc, Jianmin,
>
> I have an idea but I don't know whether it is acceptable: Marc gives
> an Acked-by for the whole series, then this irqchip series goes
> through the loongarch tree together with the PCI patches, then we
> don't need other hacks except the ACPI definitions.

Not sure how this solves the original problem. PCI should never be
mandatory (it is actually super useful to be able to build a very
small kernel without too many drivers), and there shouldn't be
configurations where the kernel doesn't build.

It is also my own responsibility to merge these things, and I'd rather
not delegate this, specially as it touches a bunch of other
subsystems.

Thanks,

M.

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

2022-07-17 15:02:42

by Marc Zyngier

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

On Sun, 17 Jul 2022 12:29:05 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/7/17 下午6:02, Marc Zyngier wrote:
> > But the other issue is that you seem to call this function from two
> > different locations. This cannot be right, as there should be only one
> > probe order, and not multiple.
> >
>
> As we described two IRQ models(Legacy and Extended) in this cover
> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
> irqchip driver, only one kind APIC of them can be parsed from MADT, so
> we have to support two probe order for them.

Do you really have the two variants in the wild? Or is this just
because this is a possibility?

M.

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

2022-07-18 01:16:19

by 吕建民

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



On 2022/7/17 下午10:49, Marc Zyngier wrote:
> On Sun, 17 Jul 2022 12:29:05 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/7/17 下午6:02, Marc Zyngier wrote:
>>> But the other issue is that you seem to call this function from two
>>> different locations. This cannot be right, as there should be only one
>>> probe order, and not multiple.
>>>
>>
>> As we described two IRQ models(Legacy and Extended) in this cover
>> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
>> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
>> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
>> irqchip driver, only one kind APIC of them can be parsed from MADT, so
>> we have to support two probe order for them.
>
> Do you really have the two variants in the wild? Or is this just
> because this is a possibility?
>

Currently, there are not CPUs(used for PC and server) based on LoongArch
shipped with only HTPIC, but with both HTPIC and EIOPIC, we just want to
provide two choices for designers(but obviously, EIOPIC may be enough
currently). Do you think we don't have to do like this, yes? If so,
maybe we don't have to support ACPI-way entry for htvec currently, and
do the work in future if required.

> M.
>

2022-07-18 02:51:08

by Huacai Chen

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

Hi, Marc,

On Sun, Jul 17, 2022 at 10:43 PM Marc Zyngier <[email protected]> wrote:
>
> On Sun, 17 Jul 2022 15:08:14 +0100,
> Huacai Chen <[email protected]> wrote:
> >
> > Hi, Marc, Jianmin,
> >
> > I have an idea but I don't know whether it is acceptable: Marc gives
> > an Acked-by for the whole series, then this irqchip series goes
> > through the loongarch tree together with the PCI patches, then we
> > don't need other hacks except the ACPI definitions.
>
> Not sure how this solves the original problem. PCI should never be
> mandatory (it is actually super useful to be able to build a very
> small kernel without too many drivers), and there shouldn't be
> configurations where the kernel doesn't build.
Now, the pci-loongson controller code (A) is in the PCI tree, the pci
enablement code (B) is in the LoongArch tree, and the irqchip code (C)
is in the irqchip tree. If the order for upstream is (A) --> (B) -->
(C), there will be no build error. My above idea is to make sure the
order of (B) and (C) is controlled in the same tree. PCI/MSI is a
mandatory requirement for LoongArch, so I want to avoid some
unnecessary #ifdefs.

>
> It is also my own responsibility to merge these things, and I'd rather
> not delegate this, specially as it touches a bunch of other
> subsystems.
I know, this is reasonable. Then if we can control the order of
(A)(B)(C) in three trees, the build error can be avoided in the
linux-next tree.

Huacai

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

2022-07-18 06:46:04

by Marc Zyngier

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

On Mon, 18 Jul 2022 02:07:21 +0100,
Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/7/17 下午10:49, Marc Zyngier wrote:
> > On Sun, 17 Jul 2022 12:29:05 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >>
> >>
> >> On 2022/7/17 下午6:02, Marc Zyngier wrote:
> >>> But the other issue is that you seem to call this function from two
> >>> different locations. This cannot be right, as there should be only one
> >>> probe order, and not multiple.
> >>>
> >>
> >> As we described two IRQ models(Legacy and Extended) in this cover
> >> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
> >> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
> >> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
> >> irqchip driver, only one kind APIC of them can be parsed from MADT, so
> >> we have to support two probe order for them.
> >
> > Do you really have the two variants in the wild? Or is this just
> > because this is a possibility?
> >
>
> Currently, there are not CPUs(used for PC and server) based on
> LoongArch shipped with only HTPIC, but with both HTPIC and EIOPIC, we
> just want to provide two choices for designers(but obviously, EIOPIC
> may be enough currently). Do you think we don't have to do like this,
> yes? If so, maybe we don't have to support ACPI-way entry for htvec
> currently, and do the work in future if required.

If the existing HW is only following the 'Extended' model, then I'd
suggest you only support this for now. It has two effects:

- it simplifies the current code, making it more maintainable and
easier to reason about

- it sends the message to integrators that 'Extended' is the correct
model, and that it is what they should support

Now, we don't have much time left to get this series into -next (I
will be closing the tree to new features this week, and only queue
fixes).

So whatever you need to do, please do it quickly so that we can have
at least some of this in 5.20.

Thanks,

M.

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

2022-07-18 07:05:52

by Marc Zyngier

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

On Mon, 18 Jul 2022 03:38:09 +0100,
Huacai Chen <[email protected]> wrote:
>
> Hi, Marc,
>
> On Sun, Jul 17, 2022 at 10:43 PM Marc Zyngier <[email protected]> wrote:
> >
> > On Sun, 17 Jul 2022 15:08:14 +0100,
> > Huacai Chen <[email protected]> wrote:
> > >
> > > Hi, Marc, Jianmin,
> > >
> > > I have an idea but I don't know whether it is acceptable: Marc gives
> > > an Acked-by for the whole series, then this irqchip series goes
> > > through the loongarch tree together with the PCI patches, then we
> > > don't need other hacks except the ACPI definitions.
> >
> > Not sure how this solves the original problem. PCI should never be
> > mandatory (it is actually super useful to be able to build a very
> > small kernel without too many drivers), and there shouldn't be
> > configurations where the kernel doesn't build.
> Now, the pci-loongson controller code (A) is in the PCI tree, the pci
> enablement code (B) is in the LoongArch tree, and the irqchip code (C)
> is in the irqchip tree. If the order for upstream is (A) --> (B) -->
> (C), there will be no build error. My above idea is to make sure the
> order of (B) and (C) is controlled in the same tree. PCI/MSI is a
> mandatory requirement for LoongArch, so I want to avoid some
> unnecessary #ifdefs.
>
> >
> > It is also my own responsibility to merge these things, and I'd rather
> > not delegate this, specially as it touches a bunch of other
> > subsystems.
> I know, this is reasonable. Then if we can control the order of
> (A)(B)(C) in three trees, the build error can be avoided in the
> linux-next tree.

This would require stable branches between all three trees, as we
don't control the *order* of the merges. I'd have to carry (A) and (B)
as part of (C), which is really over the top.

Just queue a patch to remove the #ifdef once we're at -rc1 and that
things have settled down. This will be simpler for everyone, and will
allow everyone to have a clean tree without dragging tons of extra
patches.

M.

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

2022-07-18 08:50:21

by Huacai Chen

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

Hi, Marc,

On Mon, Jul 18, 2022 at 2:43 PM Marc Zyngier <[email protected]> wrote:
>
> On Mon, 18 Jul 2022 03:38:09 +0100,
> Huacai Chen <[email protected]> wrote:
> >
> > Hi, Marc,
> >
> > On Sun, Jul 17, 2022 at 10:43 PM Marc Zyngier <[email protected]> wrote:
> > >
> > > On Sun, 17 Jul 2022 15:08:14 +0100,
> > > Huacai Chen <[email protected]> wrote:
> > > >
> > > > Hi, Marc, Jianmin,
> > > >
> > > > I have an idea but I don't know whether it is acceptable: Marc gives
> > > > an Acked-by for the whole series, then this irqchip series goes
> > > > through the loongarch tree together with the PCI patches, then we
> > > > don't need other hacks except the ACPI definitions.
> > >
> > > Not sure how this solves the original problem. PCI should never be
> > > mandatory (it is actually super useful to be able to build a very
> > > small kernel without too many drivers), and there shouldn't be
> > > configurations where the kernel doesn't build.
> > Now, the pci-loongson controller code (A) is in the PCI tree, the pci
> > enablement code (B) is in the LoongArch tree, and the irqchip code (C)
> > is in the irqchip tree. If the order for upstream is (A) --> (B) -->
> > (C), there will be no build error. My above idea is to make sure the
> > order of (B) and (C) is controlled in the same tree. PCI/MSI is a
> > mandatory requirement for LoongArch, so I want to avoid some
> > unnecessary #ifdefs.
> >
> > >
> > > It is also my own responsibility to merge these things, and I'd rather
> > > not delegate this, specially as it touches a bunch of other
> > > subsystems.
> > I know, this is reasonable. Then if we can control the order of
> > (A)(B)(C) in three trees, the build error can be avoided in the
> > linux-next tree.
>
> This would require stable branches between all three trees, as we
> don't control the *order* of the merges. I'd have to carry (A) and (B)
> as part of (C), which is really over the top.
>
> Just queue a patch to remove the #ifdef once we're at -rc1 and that
> things have settled down. This will be simpler for everyone, and will
> allow everyone to have a clean tree without dragging tons of extra
> patches.
OK, I agree with your decision.

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

2022-07-18 08:52:52

by 吕建民

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



On 2022/7/18 下午2:39, Marc Zyngier wrote:
> On Mon, 18 Jul 2022 02:07:21 +0100,
> Jianmin Lv <[email protected]> wrote:
>>
>>
>>
>> On 2022/7/17 下午10:49, Marc Zyngier wrote:
>>> On Sun, 17 Jul 2022 12:29:05 +0100,
>>> Jianmin Lv <[email protected]> wrote:
>>>>
>>>>
>>>>
>>>> On 2022/7/17 下午6:02, Marc Zyngier wrote:
>>>>> But the other issue is that you seem to call this function from two
>>>>> different locations. This cannot be right, as there should be only one
>>>>> probe order, and not multiple.
>>>>>
>>>>
>>>> As we described two IRQ models(Legacy and Extended) in this cover
>>>> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
>>>> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
>>>> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
>>>> irqchip driver, only one kind APIC of them can be parsed from MADT, so
>>>> we have to support two probe order for them.
>>>
>>> Do you really have the two variants in the wild? Or is this just
>>> because this is a possibility?
>>>
>>
>> Currently, there are not CPUs(used for PC and server) based on
>> LoongArch shipped with only HTPIC, but with both HTPIC and EIOPIC, we
>> just want to provide two choices for designers(but obviously, EIOPIC
>> may be enough currently). Do you think we don't have to do like this,
>> yes? If so, maybe we don't have to support ACPI-way entry for htvec
>> currently, and do the work in future if required.
>
> If the existing HW is only following the 'Extended' model, then I'd
> suggest you only support this for now. It has two effects:
>
> - it simplifies the current code, making it more maintainable and
> easier to reason about
>
> - it sends the message to integrators that 'Extended' is the correct
> model, and that it is what they should support
>
> Now, we don't have much time left to get this series into -next (I
> will be closing the tree to new features this week, and only queue
> fixes).
>
> So whatever you need to do, please do it quickly so that we can have
> at least some of this in 5.20.
>
> Thanks,
>
> M.
>

Ok, Marc, thanks for your suggestion, got it, I'll remove 'Legacy' mode
support and send next version as soon as possible.

2022-07-18 09:09:17

by Huacai Chen

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

Hi, Jianmin and Marc,

On Mon, Jul 18, 2022 at 4:29 PM Jianmin Lv <[email protected]> wrote:
>
>
>
> On 2022/7/18 下午2:39, Marc Zyngier wrote:
> > On Mon, 18 Jul 2022 02:07:21 +0100,
> > Jianmin Lv <[email protected]> wrote:
> >>
> >>
> >>
> >> On 2022/7/17 下午10:49, Marc Zyngier wrote:
> >>> On Sun, 17 Jul 2022 12:29:05 +0100,
> >>> Jianmin Lv <[email protected]> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 2022/7/17 下午6:02, Marc Zyngier wrote:
> >>>>> But the other issue is that you seem to call this function from two
> >>>>> different locations. This cannot be right, as there should be only one
> >>>>> probe order, and not multiple.
> >>>>>
> >>>>
> >>>> As we described two IRQ models(Legacy and Extended) in this cover
> >>>> letter, the parent domain of MSI domain can be htvec domain(Legacy) or
> >>>> eiointc domain(Extended). In MADT, only one APIC(HTPIC for htvec or
> >>>> EIOPIC for eiointc) is allowed to pass into kernel, and then in the
> >>>> irqchip driver, only one kind APIC of them can be parsed from MADT, so
> >>>> we have to support two probe order for them.
> >>>
> >>> Do you really have the two variants in the wild? Or is this just
> >>> because this is a possibility?
> >>>
> >>
> >> Currently, there are not CPUs(used for PC and server) based on
> >> LoongArch shipped with only HTPIC, but with both HTPIC and EIOPIC, we
> >> just want to provide two choices for designers(but obviously, EIOPIC
> >> may be enough currently). Do you think we don't have to do like this,
> >> yes? If so, maybe we don't have to support ACPI-way entry for htvec
> >> currently, and do the work in future if required.
> >
> > If the existing HW is only following the 'Extended' model, then I'd
> > suggest you only support this for now. It has two effects:
> >
> > - it simplifies the current code, making it more maintainable and
> > easier to reason about
> >
> > - it sends the message to integrators that 'Extended' is the correct
> > model, and that it is what they should support
> >
> > Now, we don't have much time left to get this series into -next (I
> > will be closing the tree to new features this week, and only queue
> > fixes).
> >
> > So whatever you need to do, please do it quickly so that we can have
> > at least some of this in 5.20.
> >
> > Thanks,
> >
> > M.
> >
>
> Ok, Marc, thanks for your suggestion, got it, I'll remove 'Legacy' mode
> support and send next version as soon as possible.
I think keeping the "Legacy" mode is faster than removing it for now
to keep up with the merge window, since it is already here and doesn't
need to modify.

Huacai
>
>