2023-10-25 20:24:34

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 00/21] RISC-V: ACPI: Add external interrupt controller support

This series adds support for the below ECR approved by ASWG.
1) MADT - https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view?usp=sharing

The series primarily enables irqchip drivers for RISC-V ACPI based
platforms.

In addition, PCI ACPI related functions are migrated from arm64 to
common file so that we don't need to duplicate them for RISC-V.

On RISC-V platforms, apart from root irqchips which provide local
interrupts and IPI, all other interrupt controllers are probed late
during boot. Hence, the drivers for the devices connected to these
interrupt controllers which are probed late, should also support
deferred probe. While ACPI platform devices/drivers seem to support
deferred probe since they use acpi_irq_get(), the PNP devices and the
PCI INTx expect GSIs are registered early. So, patches are required
to enable few essential drivers to support deferred probe. To minimize
the impact, a new CONFIG option is introduced which can be enabled only
by the architecture like RISC-V which supports deferred irqchip probe.

This series is based on Anup's AIA v11 series. Since Anup's AIA v11 is
not merged yet and first time introducing deferred probe, this series is
still kept as RFC. Looking forward for the feedback!

Changes since RFC v1:
1) Abandoned swnode approach as per Marc's feedback.
2) To cope up with AIA series changes which changed irqchip driver
probe from core_initcall() to platform_driver, added patches
to support deferred probing.
3) Rebased on top of Anup's AIA v11 and added tags.

To test the series,

1) Qemu should be built using the riscv_acpi_b2_v4 branch at
https://github.com/vlsunil/qemu.git

2) EDK2 should be built using the instructions at:
https://github.com/tianocore/edk2/blob/master/OvmfPkg/RiscVVirt/README.md

3) Build Linux using this series on top of Anup's AIA v11 series.

Run Qemu:
qemu-system-riscv64 \
-M virt,pflash0=pflash0,pflash1=pflash1,aia=aplic-imsic \
-m 2G -smp 8 \
-serial mon:stdio \
-device virtio-gpu-pci -full-screen \
-device qemu-xhci \
-device usb-kbd \
-blockdev node-name=pflash0,driver=file,read-only=on,filename=RISCV_VIRT_CODE.fd \
-blockdev node-name=pflash1,driver=file,filename=RISCV_VIRT_VARS.fd \
-netdev user,id=net0 -device virtio-net-pci,netdev=net0 \
-kernel arch/riscv/boot/Image \
-initrd rootfs.cpio \
-append "root=/dev/ram ro console=ttyS0 rootwait earlycon=uart8250,mmio,0x10000000"

To boot with APLIC only, use aia=aplic.
To boot with PLIC, remove aia= option.

This series is also available in acpi_b2_v2_riscv_aia_v11 branch at
https://github.com/vlsunil/linux.git

Based-on: [email protected]
(https://lore.kernel.org/lkml/[email protected]/)

Sunil V L (21):
arm64: PCI: Migrate ACPI related functions to pci-acpi.c
RISC-V: ACPI: Implement PCI related functionality
ACPI: Kconfig: Introduce new option to support deferred GSI probe
ACPI: irq: Add support for deferred probe in acpi_register_gsi()
pnp.h: Return -EPROBE_DEFER for disabled IRQ resource in pnp_irq()
RISC-V: Kconfig: Select deferred GSI probe for ACPI systems
serial: 8250_pnp: Add support for deferred probe
ACPI: pci_irq: Avoid warning for deferred probe in
acpi_pci_irq_enable()
ACPI: scan.c: Add weak arch specific function to reorder the IRQCHIP
probe
ACPI: RISC-V: Implement arch function to reorder irqchip probe entries
PCI: MSI: Add helper function to set system wide MSI support
PCI: pci-acpi.c: Return correct value from pcibios_alloc_irq()
irqchip: riscv-intc: Add ACPI support for AIA
irqchip: riscv-imsic: Add ACPI support
irqchip: riscv-aplic: Add ACPI support
irqchip: irq-sifive-plic: Add ACPI support
ACPI: bus: Add RINTC IRQ model for RISC-V
irqchip: riscv-intc: Set ACPI irqmodel
ACPI: bus: Add acpi_riscv_init function
ACPI: RISC-V: Create APLIC platform device
ACPI: RISC-V: Create PLIC platform device

arch/arm64/kernel/pci.c | 191 ---------------------
arch/riscv/Kconfig | 3 +
arch/riscv/include/asm/irq.h | 31 ++++
arch/riscv/kernel/acpi.c | 31 ++--
drivers/acpi/Kconfig | 3 +
drivers/acpi/bus.c | 4 +
drivers/acpi/irq.c | 12 +-
drivers/acpi/pci_irq.c | 7 +-
drivers/acpi/riscv/Makefile | 2 +-
drivers/acpi/riscv/init.c | 15 ++
drivers/acpi/riscv/init.h | 6 +
drivers/acpi/riscv/irq.c | 120 +++++++++++++
drivers/acpi/scan.c | 3 +
drivers/irqchip/irq-riscv-aplic-direct.c | 22 ++-
drivers/irqchip/irq-riscv-aplic-main.c | 105 ++++++++---
drivers/irqchip/irq-riscv-aplic-main.h | 1 +
drivers/irqchip/irq-riscv-aplic-msi.c | 10 +-
drivers/irqchip/irq-riscv-imsic-early.c | 52 +++++-
drivers/irqchip/irq-riscv-imsic-platform.c | 51 ++++--
drivers/irqchip/irq-riscv-imsic-state.c | 128 +++++++-------
drivers/irqchip/irq-riscv-imsic-state.h | 2 +-
drivers/irqchip/irq-riscv-intc.c | 114 +++++++++++-
drivers/irqchip/irq-sifive-plic.c | 113 ++++++++++--
drivers/pci/msi/msi.c | 5 +
drivers/pci/pci-acpi.c | 182 ++++++++++++++++++++
drivers/pci/pci.h | 2 +
drivers/tty/serial/8250/8250_pnp.c | 18 +-
include/linux/acpi.h | 9 +
include/linux/irqchip/riscv-imsic.h | 10 ++
include/linux/pnp.h | 10 +-
30 files changed, 906 insertions(+), 356 deletions(-)
create mode 100644 drivers/acpi/riscv/init.c
create mode 100644 drivers/acpi/riscv/init.h
create mode 100644 drivers/acpi/riscv/irq.c

--
2.39.2


2023-10-25 20:24:38

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 02/21] RISC-V: ACPI: Implement PCI related functionality

Replace the dummy implementation for PCI related functions with actual
implementation. This needs ECAM and MCFG CONFIG options to be enabled
for RISC-V.

Signed-off-by: Sunil V L <[email protected]>
---
arch/riscv/Kconfig | 2 ++
arch/riscv/kernel/acpi.c | 31 ++++++++++++++-----------------
drivers/pci/pci-acpi.c | 2 +-
3 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c3c3f3562082..8c105a151e12 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -13,6 +13,7 @@ config 32BIT
config RISCV
def_bool y
select ACPI_GENERIC_GSI if ACPI
+ select ACPI_MCFG if (ACPI && PCI)
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ARCH_DMA_DEFAULT_COHERENT
select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION
@@ -152,6 +153,7 @@ config RISCV
select OF_EARLY_FLATTREE
select OF_IRQ
select PCI_DOMAINS_GENERIC if PCI
+ select PCI_ECAM if (ACPI && PCI)
select PCI_MSI if PCI
select RISCV_ALTERNATIVE if !XIP_KERNEL
select RISCV_APLIC
diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
index e619edc8b0cc..41aa77c8484b 100644
--- a/arch/riscv/kernel/acpi.c
+++ b/arch/riscv/kernel/acpi.c
@@ -306,29 +306,26 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
#ifdef CONFIG_PCI

/*
- * These interfaces are defined just to enable building ACPI core.
- * TODO: Update it with actual implementation when external interrupt
- * controller support is added in RISC-V ACPI.
+ * raw_pci_read/write - Platform-specific PCI config space access.
*/
-int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
- int reg, int len, u32 *val)
+int raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
{
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
+ struct pci_bus *b = pci_find_bus(domain, bus);

-int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
- int reg, int len, u32 val)
-{
- return PCIBIOS_DEVICE_NOT_FOUND;
+ if (!b)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ return b->ops->read(b, devfn, reg, len, val);
}

-int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+int raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
{
- return -1;
-}
+ struct pci_bus *b = pci_find_bus(domain, bus);

-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
-{
- return NULL;
+ if (!b)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ return b->ops->write(b, devfn, reg, len, val);
}
+
#endif /* CONFIG_PCI */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 58497b25d2ab..c8c3369fd69f 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1520,7 +1520,7 @@ static int __init acpi_pci_init(void)
}
arch_initcall(acpi_pci_init);

-#if defined(CONFIG_ARM64)
+#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)

/*
* Try to assign the IRQ number when probing a new device
--
2.39.2

2023-10-25 20:24:52

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 03/21] ACPI: Kconfig: Introduce new option to support deferred GSI probe

On some architectures like RISC-V, the interrupt controllers for Global
System Interrupts (GSI) are not probed early during boot. So, the
device drivers which need to register their GSI, need to be deferred
until the actual interrupt controller driver is probed. To reduce the
impact of such change, add a new CONFIG option which can be set only by
the architecture which needs deferred GSI probing.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/Kconfig | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index cee82b473dc5..4399e793f1d2 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -51,6 +51,9 @@ config ARCH_MIGHT_HAVE_ACPI_PDC
config ACPI_GENERIC_GSI
bool

+config ARCH_ACPI_DEFERRED_GSI
+ bool
+
config ACPI_SYSTEM_POWER_STATES_SUPPORT
bool

--
2.39.2

2023-10-25 20:25:08

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 01/21] arm64: PCI: Migrate ACPI related functions to pci-acpi.c

The functions defined in arm64 for ACPI support are required
for RISC-V also. To avoid duplication, move these functions
to common location.

Signed-off-by: Sunil V L <[email protected]>
Acked-by: Bjorn Helgaas <[email protected]>
---
arch/arm64/kernel/pci.c | 191 ----------------------------------------
drivers/pci/pci-acpi.c | 182 ++++++++++++++++++++++++++++++++++++++
2 files changed, 182 insertions(+), 191 deletions(-)

diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index f872c57e9909..fd9a7bed83ce 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -6,28 +6,7 @@
* Copyright (C) 2014 ARM Ltd.
*/

-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/pci.h>
-#include <linux/pci-acpi.h>
-#include <linux/pci-ecam.h>
-#include <linux/slab.h>
-
-#ifdef CONFIG_ACPI
-/*
- * Try to assign the IRQ number when probing a new device
- */
-int pcibios_alloc_irq(struct pci_dev *dev)
-{
- if (!acpi_disabled)
- acpi_pci_irq_enable(dev);
-
- return 0;
-}
-#endif

/*
* raw_pci_read/write - Platform-specific PCI config space access.
@@ -61,173 +40,3 @@ int pcibus_to_node(struct pci_bus *bus)
EXPORT_SYMBOL(pcibus_to_node);

#endif
-
-#ifdef CONFIG_ACPI
-
-struct acpi_pci_generic_root_info {
- struct acpi_pci_root_info common;
- struct pci_config_window *cfg; /* config space mapping */
-};
-
-int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
-{
- struct pci_config_window *cfg = bus->sysdata;
- struct acpi_device *adev = to_acpi_device(cfg->parent);
- struct acpi_pci_root *root = acpi_driver_data(adev);
-
- return root->segment;
-}
-
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- struct pci_config_window *cfg;
- struct acpi_device *adev;
- struct device *bus_dev;
-
- if (acpi_disabled)
- return 0;
-
- cfg = bridge->bus->sysdata;
-
- /*
- * On Hyper-V there is no corresponding ACPI device for a root bridge,
- * therefore ->parent is set as NULL by the driver. And set 'adev' as
- * NULL in this case because there is no proper ACPI device.
- */
- if (!cfg->parent)
- adev = NULL;
- else
- adev = to_acpi_device(cfg->parent);
-
- bus_dev = &bridge->bus->dev;
-
- ACPI_COMPANION_SET(&bridge->dev, adev);
- set_dev_node(bus_dev, acpi_get_node(acpi_device_handle(adev)));
-
- return 0;
-}
-
-static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
-{
- struct resource_entry *entry, *tmp;
- int status;
-
- status = acpi_pci_probe_root_resources(ci);
- resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
- if (!(entry->res->flags & IORESOURCE_WINDOW))
- resource_list_destroy_entry(entry);
- }
- return status;
-}
-
-/*
- * Lookup the bus range for the domain in MCFG, and set up config space
- * mapping.
- */
-static struct pci_config_window *
-pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
-{
- struct device *dev = &root->device->dev;
- struct resource *bus_res = &root->secondary;
- u16 seg = root->segment;
- const struct pci_ecam_ops *ecam_ops;
- struct resource cfgres;
- struct acpi_device *adev;
- struct pci_config_window *cfg;
- int ret;
-
- ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops);
- if (ret) {
- dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res);
- return NULL;
- }
-
- adev = acpi_resource_consumer(&cfgres);
- if (adev)
- dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres,
- dev_name(&adev->dev));
- else
- dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n",
- &cfgres);
-
- cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
- if (IS_ERR(cfg)) {
- dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res,
- PTR_ERR(cfg));
- return NULL;
- }
-
- return cfg;
-}
-
-/* release_info: free resources allocated by init_info */
-static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
-{
- struct acpi_pci_generic_root_info *ri;
-
- ri = container_of(ci, struct acpi_pci_generic_root_info, common);
- pci_ecam_free(ri->cfg);
- kfree(ci->ops);
- kfree(ri);
-}
-
-/* Interface called from ACPI code to setup PCI host controller */
-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
-{
- struct acpi_pci_generic_root_info *ri;
- struct pci_bus *bus, *child;
- struct acpi_pci_root_ops *root_ops;
- struct pci_host_bridge *host;
-
- ri = kzalloc(sizeof(*ri), GFP_KERNEL);
- if (!ri)
- return NULL;
-
- root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL);
- if (!root_ops) {
- kfree(ri);
- return NULL;
- }
-
- ri->cfg = pci_acpi_setup_ecam_mapping(root);
- if (!ri->cfg) {
- kfree(ri);
- kfree(root_ops);
- return NULL;
- }
-
- root_ops->release_info = pci_acpi_generic_release_info;
- root_ops->prepare_resources = pci_acpi_root_prepare_resources;
- root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops;
- bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
- if (!bus)
- return NULL;
-
- /* If we must preserve the resource configuration, claim now */
- host = pci_find_host_bridge(bus);
- if (host->preserve_config)
- pci_bus_claim_resources(bus);
-
- /*
- * Assign whatever was left unassigned. If we didn't claim above,
- * this will reassign everything.
- */
- pci_assign_unassigned_root_bus_resources(bus);
-
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
-
- return bus;
-}
-
-void pcibios_add_bus(struct pci_bus *bus)
-{
- acpi_pci_add_bus(bus);
-}
-
-void pcibios_remove_bus(struct pci_bus *bus)
-{
- acpi_pci_remove_bus(bus);
-}
-
-#endif
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a05350a4e49c..58497b25d2ab 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -15,6 +15,7 @@
#include <linux/pci_hotplug.h>
#include <linux/module.h>
#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/rwsem.h>
@@ -1518,3 +1519,184 @@ static int __init acpi_pci_init(void)
return 0;
}
arch_initcall(acpi_pci_init);
+
+#if defined(CONFIG_ARM64)
+
+/*
+ * Try to assign the IRQ number when probing a new device
+ */
+int pcibios_alloc_irq(struct pci_dev *dev)
+{
+ if (!acpi_disabled)
+ acpi_pci_irq_enable(dev);
+
+ return 0;
+}
+
+struct acpi_pci_generic_root_info {
+ struct acpi_pci_root_info common;
+ struct pci_config_window *cfg; /* config space mapping */
+};
+
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{
+ struct pci_config_window *cfg = bus->sysdata;
+ struct acpi_device *adev = to_acpi_device(cfg->parent);
+ struct acpi_pci_root *root = acpi_driver_data(adev);
+
+ return root->segment;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ struct pci_config_window *cfg;
+ struct acpi_device *adev;
+ struct device *bus_dev;
+
+ if (acpi_disabled)
+ return 0;
+
+ cfg = bridge->bus->sysdata;
+
+ /*
+ * On Hyper-V there is no corresponding ACPI device for a root bridge,
+ * therefore ->parent is set as NULL by the driver. And set 'adev' as
+ * NULL in this case because there is no proper ACPI device.
+ */
+ if (!cfg->parent)
+ adev = NULL;
+ else
+ adev = to_acpi_device(cfg->parent);
+
+ bus_dev = &bridge->bus->dev;
+
+ ACPI_COMPANION_SET(&bridge->dev, adev);
+ set_dev_node(bus_dev, acpi_get_node(acpi_device_handle(adev)));
+
+ return 0;
+}
+
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
+{
+ struct resource_entry *entry, *tmp;
+ int status;
+
+ status = acpi_pci_probe_root_resources(ci);
+ resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+ if (!(entry->res->flags & IORESOURCE_WINDOW))
+ resource_list_destroy_entry(entry);
+ }
+ return status;
+}
+
+/*
+ * Lookup the bus range for the domain in MCFG, and set up config space
+ * mapping.
+ */
+static struct pci_config_window *
+pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+{
+ struct device *dev = &root->device->dev;
+ struct resource *bus_res = &root->secondary;
+ u16 seg = root->segment;
+ const struct pci_ecam_ops *ecam_ops;
+ struct resource cfgres;
+ struct acpi_device *adev;
+ struct pci_config_window *cfg;
+ int ret;
+
+ ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops);
+ if (ret) {
+ dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res);
+ return NULL;
+ }
+
+ adev = acpi_resource_consumer(&cfgres);
+ if (adev)
+ dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres,
+ dev_name(&adev->dev));
+ else
+ dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n",
+ &cfgres);
+
+ cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
+ if (IS_ERR(cfg)) {
+ dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res,
+ PTR_ERR(cfg));
+ return NULL;
+ }
+
+ return cfg;
+}
+
+/* release_info: free resources allocated by init_info */
+static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
+{
+ struct acpi_pci_generic_root_info *ri;
+
+ ri = container_of(ci, struct acpi_pci_generic_root_info, common);
+ pci_ecam_free(ri->cfg);
+ kfree(ci->ops);
+ kfree(ri);
+}
+
+/* Interface called from ACPI code to setup PCI host controller */
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+ struct acpi_pci_generic_root_info *ri;
+ struct pci_bus *bus, *child;
+ struct acpi_pci_root_ops *root_ops;
+ struct pci_host_bridge *host;
+
+ ri = kzalloc(sizeof(*ri), GFP_KERNEL);
+ if (!ri)
+ return NULL;
+
+ root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL);
+ if (!root_ops) {
+ kfree(ri);
+ return NULL;
+ }
+
+ ri->cfg = pci_acpi_setup_ecam_mapping(root);
+ if (!ri->cfg) {
+ kfree(ri);
+ kfree(root_ops);
+ return NULL;
+ }
+
+ root_ops->release_info = pci_acpi_generic_release_info;
+ root_ops->prepare_resources = pci_acpi_root_prepare_resources;
+ root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops;
+ bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
+ if (!bus)
+ return NULL;
+
+ /* If we must preserve the resource configuration, claim now */
+ host = pci_find_host_bridge(bus);
+ if (host->preserve_config)
+ pci_bus_claim_resources(bus);
+
+ /*
+ * Assign whatever was left unassigned. If we didn't claim above,
+ * this will reassign everything.
+ */
+ pci_assign_unassigned_root_bus_resources(bus);
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+
+ return bus;
+}
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+ acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+ acpi_pci_remove_bus(bus);
+}
+
+#endif
--
2.39.2

2023-10-25 20:25:12

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 04/21] ACPI: irq: Add support for deferred probe in acpi_register_gsi()

The chip which provides the GSI support may not be initialized at the
time of acpi_register_gsi(). Return -EPROBE_DEFER to support deferred
probing similar to acpi_irq_get().

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/irq.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index 1687483ff319..c06cfc9725cb 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -51,19 +51,23 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
* @polarity: polarity of the GSI to be mapped
*
* Returns: a valid linux IRQ number on success
+ * -EPROBE_DEFER if irqdomain is not available.
* -EINVAL on failure
*/
int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
int polarity)
{
+ struct irq_domain *domain;
struct irq_fwspec fwspec;
unsigned int irq;

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

fwspec.param[0] = gsi;
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
--
2.39.2

2023-10-25 20:25:18

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 05/21] pnp.h: Return -EPROBE_DEFER for disabled IRQ resource in pnp_irq()

To support deferred PNP driver probe, pnp_irq() must return -EPROBE_DEFER
so that the device driver can do deferred probe if the interrupt controller
is not probed early.

Signed-off-by: Sunil V L <[email protected]>
---
include/linux/pnp.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index c2a7cfbca713..21cf833789fb 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -147,12 +147,18 @@ static inline resource_size_t pnp_mem_len(struct pnp_dev *dev,
}


-static inline resource_size_t pnp_irq(struct pnp_dev *dev, unsigned int bar)
+static inline int pnp_irq(struct pnp_dev *dev, unsigned int bar)
{
struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar);

- if (pnp_resource_valid(res))
+ if (pnp_resource_valid(res)) {
+#if IS_ENABLED(CONFIG_ARCH_ACPI_DEFERRED_GSI)
+ if (!pnp_resource_enabled(res))
+ return -EPROBE_DEFER;
+#endif
+
return res->start;
+ }
return -1;
}

--
2.39.2

2023-10-25 20:25:22

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

On RISC-V platforms, apart from root interrupt controllers (which
provide local interrupts and IPI), other interrupt controllers in the
hierarchy are probed late. Enable this select this CONFIG option for
RISC-V platforms so that device drivers which connect to deferred
interrupt controllers can take appropriate action.

Signed-off-by: Sunil V L <[email protected]>
---
arch/riscv/Kconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 8c105a151e12..b62441aefa6a 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -12,6 +12,7 @@ config 32BIT

config RISCV
def_bool y
+ select ARCH_ACPI_DEFERRED_GSI if ACPI
select ACPI_GENERIC_GSI if ACPI
select ACPI_MCFG if (ACPI && PCI)
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
--
2.39.2

2023-10-25 20:25:38

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 08/21] ACPI: pci_irq: Avoid warning for deferred probe in acpi_pci_irq_enable()

When the architecture like RISC-V supports deferred GSI interrupt
controller probe, acpi_register_gsi() can return -EPROBE_DEFER which is
a valid use case to delay the dependent driver probe. So, avoid printing
the warning for the deferred probe case.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/pci_irq.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index ff30ceca2203..f7d0822da08f 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -452,8 +452,11 @@ int acpi_pci_irq_enable(struct pci_dev *dev)

rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
if (rc < 0) {
- dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
- pin_name(pin));
+ if (rc != -EPROBE_DEFER) {
+ dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
+ pin_name(pin));
+ }
+
kfree(entry);
return rc;
}
--
2.39.2

2023-10-25 20:25:46

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 09/21] ACPI: scan.c: Add weak arch specific function to reorder the IRQCHIP probe

Unlike OF framework, the irqchip probe using IRQCHIP_ACPI_DECLARE has no
order defined. Depending on the driver Makefile is not a good idea. So,
usually it is worked around by mandating only root interrupt controller
probed using IRQCHIP_ACPI_DECLARE and other interrupt controllers are
probed via cascade mechanism.

However, this is also not a clean solution because if there are multiple
root controllers (ex: RINTC in RISC-V which is per CPU) which need to be
probed first, then the cascade will happen for every root controller.
So, introduce a architecture specific weak function to order the probing
of the interrupt controllers which can be implemented by different
architectures as per their interrupt controller hierarchy.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/scan.c | 3 +++
include/linux/acpi.h | 2 ++
2 files changed, 5 insertions(+)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 691d4b7686ee..87f4baebd497 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2685,6 +2685,8 @@ static int __init acpi_match_madt(union acpi_subtable_headers *header,
return 0;
}

+void __weak arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr) { }
+
int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
{
int count = 0;
@@ -2693,6 +2695,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
return 0;

mutex_lock(&acpi_probe_mutex);
+ arch_sort_irqchip_probe(ap_head, nr);
for (ape = ap_head; nr; ape++, nr--) {
if (ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id)) {
acpi_probe_count = 0;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index afd94c9b8b8a..4ad256a0039c 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1338,6 +1338,8 @@ struct acpi_probe_entry {
kernel_ulong_t driver_data;
};

+void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr);
+
#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, \
valid, data, fn) \
static const struct acpi_probe_entry __acpi_probe_##name \
--
2.39.2

2023-10-25 20:26:00

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 07/21] serial: 8250_pnp: Add support for deferred probe

With pnp_irq() able to return error code, enhance the serial pnp driver
to support deferred probing. Return -EPROBE_DEFER when pnp_irq() returns
the same so that the driver probe is deferred.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/tty/serial/8250/8250_pnp.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 1974bbadc975..dcb3daf7c816 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -8,6 +8,7 @@
*
* Ported to the Linux PnP Layer - (C) Adam Belay.
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pnp.h>
@@ -443,8 +444,21 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
}

memset(&uart, 0, sizeof(uart));
- if (pnp_irq_valid(dev, 0))
- uart.port.irq = pnp_irq(dev, 0);
+ if (pnp_irq_valid(dev, 0)) {
+ ret = pnp_irq(dev, 0);
+ if (ret == -EPROBE_DEFER) {
+ struct resource r;
+
+ ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), 0, &r);
+ if (!ret)
+ uart.port.irq = r.start;
+ else
+ return ret;
+ } else {
+ uart.port.irq = ret;
+ }
+ }
+
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
uart.port.iobase = pnp_port_start(dev, 2);
uart.port.iotype = UPIO_PORT;
--
2.39.2

2023-10-25 20:26:07

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 10/21] ACPI: RISC-V: Implement arch function to reorder irqchip probe entries

ACPI MADT entries for interrupt controllers don't have a way to describe
the hierarchy. However, the hierarchy is known to the architecture and
on RISC-V platforms, the MADT sub table types are ordered in the
incremental order from the root controller which is RINTC. So, add
architecture function for RISC-V to reorder the interrupt controller
probing as per the hierarchy as below.

RINTC->IMSIC->APLIC->PLIC

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/riscv/Makefile | 2 +-
drivers/acpi/riscv/irq.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
create mode 100644 drivers/acpi/riscv/irq.c

diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 8b3b126e0b94..f80b3da230e9 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += rhct.o
+obj-y += rhct.o irq.o
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
new file mode 100644
index 000000000000..36e0525b3235
--- /dev/null
+++ b/drivers/acpi/riscv/irq.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Ventana Micro Systems Inc
+ * Author: Sunil V L <[email protected]>
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/sort.h>
+
+static int irqchip_cmp_func(const void *in0, const void *in1)
+{
+ struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0;
+ struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1;
+
+ return (elem0->type > elem1->type) - (elem0->type < elem1->type);
+}
+
+/*
+ * RISC-V irqchips in MADT of ACPI spec are defined in the same order how
+ * they should be probed. Since IRQCHIP_ACPI_DECLARE doesn't define any
+ * order, this arch function will reorder the probe functions as per the
+ * required order for the architecture.
+ */
+void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)
+{
+ struct acpi_probe_entry *ape = ap_head;
+
+ if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id))
+ return;
+ sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);
+}
--
2.39.2

2023-10-25 20:26:12

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 11/21] PCI: MSI: Add helper function to set system wide MSI support

Like pci_no_msi() used to disable MSI support, add a function to enable
system wide MSI support.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/pci/msi/msi.c | 5 +++++
drivers/pci/pci.h | 2 ++
2 files changed, 7 insertions(+)

diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
index ef1d8857a51b..e76ccb8b5f0b 100644
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -913,3 +913,8 @@ void pci_no_msi(void)
{
pci_msi_enable = 0;
}
+
+void pci_set_msi(void)
+{
+ pci_msi_enable = 1;
+}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 39a8932dc340..2f876c29f75c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -167,8 +167,10 @@ extern unsigned int pci_pm_d3hot_delay;

#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
+void pci_set_msi(void);
#else
static inline void pci_no_msi(void) { }
+static inline void pci_set_msi(void) { }
#endif

void pci_realloc_get_opt(char *);
--
2.39.2

2023-10-25 20:26:27

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 12/21] PCI: pci-acpi.c: Return correct value from pcibios_alloc_irq()

Return the correct value from pcibios_alloc_irq().

Signed-off-by: Sunil V L <[email protected]>
---
drivers/pci/pci-acpi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c8c3369fd69f..80dc0b290544 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1528,7 +1528,7 @@ arch_initcall(acpi_pci_init);
int pcibios_alloc_irq(struct pci_dev *dev)
{
if (!acpi_disabled)
- acpi_pci_irq_enable(dev);
+ return acpi_pci_irq_enable(dev);

return 0;
}
--
2.39.2

2023-10-25 20:26:46

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

The RINTC subtype structure in MADT also has information about other
interrupt controllers like MMIO. So, save those information and provide
interfaces to retrieve them when required by corresponding drivers.

Signed-off-by: Sunil V L <[email protected]>
---
arch/riscv/include/asm/irq.h | 19 ++++++
drivers/irqchip/irq-riscv-intc.c | 102 ++++++++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
index 8e10a94430a2..ef102b6fa86e 100644
--- a/arch/riscv/include/asm/irq.h
+++ b/arch/riscv/include/asm/irq.h
@@ -12,8 +12,27 @@

#include <asm-generic/irq.h>

+#ifdef CONFIG_ACPI
+
+/*
+ * The ext_intc_id format is as follows:
+ * Bits [31:24] APLIC/PLIC ID
+ * Bits [15:0] APLIC IDC ID / PLIC S-Mode Context ID for this hart
+ */
+#define APLIC_PLIC_ID(x) ((x) >> 24)
+#define IDC_CONTEXT_ID(x) ((x) & 0x0000ffff)
+
+int __init acpi_get_intc_index_hartid(u32 index, unsigned long *hartid);
+int acpi_get_ext_intc_parent_hartid(u8 id, u32 idx, unsigned long *hartid);
+void acpi_get_plic_nr_contexts(u8 id, int *nr_contexts);
+int acpi_get_plic_context(u8 id, u32 idx, int *context_id);
+int __init acpi_get_imsic_mmio_info(u32 index, struct resource *res);
+
+#endif
+
void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void));

struct fwnode_handle *riscv_get_intc_hwnode(void);
+int acpi_imsic_probe(struct fwnode_handle *parent);

#endif /* _ASM_RISCV_IRQ_H */
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index bab536bbaf2c..f3aaecde12dd 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/smp.h>
#include <asm/hwcap.h>
+#include "../pci/pci.h"

static struct irq_domain *intc_domain;

@@ -195,13 +196,100 @@ IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init);

#ifdef CONFIG_ACPI

+struct rintc_data {
+ u32 ext_intc_id;
+ unsigned long hart_id;
+ u64 imsic_addr;
+ u32 imsic_size;
+};
+
+static u32 nr_rintc;
+static struct rintc_data *rintc_acpi_data[NR_CPUS];
+
+int acpi_get_intc_index_hartid(u32 index, unsigned long *hartid)
+{
+ if (index >= nr_rintc)
+ return -1;
+
+ *hartid = rintc_acpi_data[index]->hart_id;
+ return 0;
+}
+
+int acpi_get_ext_intc_parent_hartid(u8 id, u32 idx, unsigned long *hartid)
+{
+ int i, j = 0;
+
+ for (i = 0; i < nr_rintc; i++) {
+ if (APLIC_PLIC_ID(rintc_acpi_data[i]->ext_intc_id) == id) {
+ if (idx == j) {
+ *hartid = rintc_acpi_data[i]->hart_id;
+ return 0;
+ }
+ j++;
+ }
+ }
+
+ return -1;
+}
+
+void acpi_get_plic_nr_contexts(u8 id, int *nr_contexts)
+{
+ int i, j = 0;
+
+ for (i = 0; i < nr_rintc; i++) {
+ if (APLIC_PLIC_ID(rintc_acpi_data[i]->ext_intc_id) == id)
+ j++;
+ }
+
+ *nr_contexts = j;
+}
+
+int acpi_get_plic_context(u8 id, u32 idx, int *context_id)
+{
+ int i, j = 0;
+
+ for (i = 0; i < nr_rintc; i++) {
+ if (APLIC_PLIC_ID(rintc_acpi_data[i]->ext_intc_id) == id) {
+ if (idx == j) {
+ *context_id = IDC_CONTEXT_ID(rintc_acpi_data[i]->ext_intc_id);
+ return 0;
+ }
+
+ j++;
+ }
+ }
+
+ return -1;
+}
+
+int acpi_get_imsic_mmio_info(u32 index, struct resource *res)
+{
+ if (index >= nr_rintc)
+ return -1;
+
+ res->start = rintc_acpi_data[index]->imsic_addr;
+ res->end = res->start + rintc_acpi_data[index]->imsic_size - 1;
+ res->flags = IORESOURCE_MEM;
+ return 0;
+}
+
static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
struct fwnode_handle *fn;
struct acpi_madt_rintc *rintc;
+ int rc;

rintc = (struct acpi_madt_rintc *)header;
+ rintc_acpi_data[nr_rintc] = kzalloc(sizeof(*rintc_acpi_data[0]), GFP_KERNEL);
+ if (!rintc_acpi_data[nr_rintc])
+ return -ENOMEM;
+
+ rintc_acpi_data[nr_rintc]->ext_intc_id = rintc->ext_intc_id;
+ rintc_acpi_data[nr_rintc]->hart_id = rintc->hart_id;
+ rintc_acpi_data[nr_rintc]->imsic_addr = rintc->imsic_addr;
+ rintc_acpi_data[nr_rintc]->imsic_size = rintc->imsic_size;
+ nr_rintc++;

/*
* The ACPI MADT will have one INTC for each CPU (or HART)
@@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
return -ENOMEM;
}

- return riscv_intc_init_common(fn);
+ rc = riscv_intc_init_common(fn);
+ if (rc) {
+ irq_domain_free_fwnode(fn);
+ return rc;
+ }
+
+ /*
+ * MSI controller (IMSIC) in RISC-V is optional. So, unless
+ * IMSIC is discovered, set system wide MSI support as
+ * unsupported. Once IMSIC is probed, MSI support will be set.
+ */
+ pci_no_msi();
+ return 0;
}

IRQCHIP_ACPI_DECLARE(riscv_intc, ACPI_MADT_TYPE_RINTC, NULL,
--
2.39.2

2023-10-25 20:27:03

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 15/21] irqchip: riscv-aplic: Add ACPI support

Add ACPI support in APLIC drivers. In ACPI, IO devices use Global System
Interrupts (GSI) which is a flat space split across multiple APLICs. So,
the driver also need to provide the mapping from GSI to correct APLIC.

Signed-off-by: Sunil V L <[email protected]>
---
arch/riscv/include/asm/irq.h | 6 ++
drivers/irqchip/irq-riscv-aplic-direct.c | 22 +++--
drivers/irqchip/irq-riscv-aplic-main.c | 105 +++++++++++++++++------
drivers/irqchip/irq-riscv-aplic-main.h | 1 +
drivers/irqchip/irq-riscv-aplic-msi.c | 10 ++-
5 files changed, 109 insertions(+), 35 deletions(-)

diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
index ef102b6fa86e..00eb8b0333c2 100644
--- a/arch/riscv/include/asm/irq.h
+++ b/arch/riscv/include/asm/irq.h
@@ -22,6 +22,12 @@
#define APLIC_PLIC_ID(x) ((x) >> 24)
#define IDC_CONTEXT_ID(x) ((x) & 0x0000ffff)

+#ifdef CONFIG_RISCV_APLIC
+struct fwnode_handle *aplic_get_gsi_domain_id(u32 gsi);
+#else
+static inline struct fwnode_handle *aplic_get_gsi_domain_id(u32 gsi) { return NULL; }
+#endif
+
int __init acpi_get_intc_index_hartid(u32 index, unsigned long *hartid);
int acpi_get_ext_intc_parent_hartid(u8 id, u32 idx, unsigned long *hartid);
void acpi_get_plic_nr_contexts(u8 id, int *nr_contexts);
diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c
index 9ed2666bfb5e..3902e6d32856 100644
--- a/drivers/irqchip/irq-riscv-aplic-direct.c
+++ b/drivers/irqchip/irq-riscv-aplic-direct.c
@@ -4,6 +4,7 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/

+#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
@@ -14,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/printk.h>
#include <linux/smp.h>
+#include <asm/acpi.h>

#include "irq-riscv-aplic-main.h"

@@ -203,17 +205,20 @@ static int aplic_direct_starting_cpu(unsigned int cpu)

static int aplic_direct_parse_parent_hwirq(struct device *dev,
u32 index, u32 *parent_hwirq,
- unsigned long *parent_hartid)
+ unsigned long *parent_hartid,
+ struct aplic_priv *priv)
{
struct of_phandle_args parent;
int rc;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
- if (!is_of_node(dev->fwnode))
- return -EINVAL;
+ if (!is_of_node(dev->fwnode)) {
+ rc = acpi_get_ext_intc_parent_hartid(priv->id, index, parent_hartid);
+ if (rc)
+ return rc;
+
+ *parent_hwirq = RV_IRQ_EXT;
+ return 0;
+ }

rc = of_irq_parse_one(to_of_node(dev->fwnode), index, &parent);
if (rc)
@@ -251,7 +256,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs)

/* Setup per-CPU IDC and target CPU mask */
for (i = 0; i < priv->nr_idcs; i++) {
- rc = aplic_direct_parse_parent_hwirq(dev, i, &hwirq, &hartid);
+ rc = aplic_direct_parse_parent_hwirq(dev, i, &hwirq, &hartid, priv);
if (rc) {
dev_warn(dev, "parent irq for IDC%d not found\n", i);
continue;
@@ -335,6 +340,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs)
return -ENOMEM;
}

+ dev_set_drvdata(dev, priv);
/* Advertise the interrupt controller */
dev_info(dev, "%d interrupts directly connected to %d CPUs\n",
priv->nr_irqs, priv->nr_idcs);
diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c
index d1b342b66551..f0ba1411c95e 100644
--- a/drivers/irqchip/irq-riscv-aplic-main.c
+++ b/drivers/irqchip/irq-riscv-aplic-main.c
@@ -4,12 +4,15 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/

+#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/printk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/irqchip/riscv-aplic.h>
+#include <linux/irqchip/riscv-imsic.h>
+#include <asm/acpi.h>

#include "irq-riscv-aplic-main.h"

@@ -137,38 +140,44 @@ int aplic_setup_priv(struct aplic_priv *priv, struct device *dev,
void __iomem *regs)
{
struct of_phandle_args parent;
+ struct acpi_madt_aplic *aplic;
int rc;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
- if (!is_of_node(dev->fwnode))
- return -EINVAL;
-
/* Save device pointer and register base */
priv->dev = dev;
priv->regs = regs;

- /* Find out number of interrupt sources */
- rc = of_property_read_u32(to_of_node(dev->fwnode),
- "riscv,num-sources",
- &priv->nr_irqs);
- if (rc) {
- dev_err(dev, "failed to get number of interrupt sources\n");
- return rc;
- }
-
- /*
- * Find out number of IDCs based on parent interrupts
- *
- * If "msi-parent" property is present then we ignore the
- * APLIC IDCs which forces the APLIC driver to use MSI mode.
- */
- if (!of_property_present(to_of_node(dev->fwnode), "msi-parent")) {
- while (!of_irq_parse_one(to_of_node(dev->fwnode),
- priv->nr_idcs, &parent))
- priv->nr_idcs++;
+ if (is_of_node(dev->fwnode)) {
+ /* Find out number of interrupt sources */
+ rc = of_property_read_u32(to_of_node(dev->fwnode),
+ "riscv,num-sources",
+ &priv->nr_irqs);
+ if (rc) {
+ dev_err(dev, "failed to get number of interrupt sources\n");
+ return rc;
+ }
+
+ /*
+ * Find out number of IDCs based on parent interrupts
+ *
+ * If "msi-parent" property is present then we ignore the
+ * APLIC IDCs which forces the APLIC driver to use MSI mode.
+ */
+ if (!of_property_present(to_of_node(dev->fwnode), "msi-parent")) {
+ while (!of_irq_parse_one(to_of_node(dev->fwnode),
+ priv->nr_idcs, &parent))
+ priv->nr_idcs++;
+ }
+ } else {
+ aplic = *(struct acpi_madt_aplic **)dev_get_platdata(dev);
+ if (!aplic) {
+ dev_err(dev, "APLIC platform data is NULL!\n");
+ return -1;
+ }
+ priv->gsi_base = aplic->gsi_base;
+ priv->nr_irqs = aplic->num_sources;
+ priv->nr_idcs = aplic->num_idcs;
+ priv->id = aplic->id;
}

/* Setup initial state APLIC interrupts */
@@ -177,9 +186,36 @@ int aplic_setup_priv(struct aplic_priv *priv, struct device *dev,
return 0;
}

+#ifdef CONFIG_ACPI
+
+LIST_HEAD(aplic_list);
+struct aplic_priv_list {
+ struct aplic_priv *priv;
+ struct list_head list;
+};
+
+struct fwnode_handle *aplic_get_gsi_domain_id(u32 gsi)
+{
+ struct aplic_priv_list *aplic_element;
+ struct list_head *i, *tmp;
+
+ /* Find the APLIC that manages this GSI. */
+ list_for_each_safe(i, tmp, &aplic_list) {
+ aplic_element = list_entry(i, struct aplic_priv_list, list);
+ if (gsi >= aplic_element->priv->gsi_base &&
+ gsi < (aplic_element->priv->gsi_base + aplic_element->priv->nr_irqs))
+ return aplic_element->priv->dev->fwnode;
+ }
+
+ return NULL;
+}
+
+#endif
+
static int aplic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct aplic_priv *priv;
bool msi_mode = false;
struct resource *res;
void __iomem *regs;
@@ -204,6 +240,9 @@ static int aplic_probe(struct platform_device *pdev)
if (is_of_node(dev->fwnode))
msi_mode = of_property_present(to_of_node(dev->fwnode),
"msi-parent");
+ else
+ msi_mode = imsic_acpi_get_fwnode(NULL) ? 1 : 0;
+
if (msi_mode)
rc = aplic_msi_setup(dev, regs);
else
@@ -214,6 +253,20 @@ static int aplic_probe(struct platform_device *pdev)
return rc;
}

+#ifdef CONFIG_ACPI
+ struct aplic_priv_list *aplic_element;
+
+ priv = dev_get_drvdata(dev);
+ if (priv) {
+ aplic_element = devm_kzalloc(dev, sizeof(*aplic_element), GFP_KERNEL);
+ if (!aplic_element)
+ return -ENOMEM;
+
+ aplic_element->priv = priv;
+ list_add_tail(&aplic_element->list, &aplic_list);
+ }
+#endif
+
return 0;
}

diff --git a/drivers/irqchip/irq-riscv-aplic-main.h b/drivers/irqchip/irq-riscv-aplic-main.h
index 78267ec58098..dc022e89bc97 100644
--- a/drivers/irqchip/irq-riscv-aplic-main.h
+++ b/drivers/irqchip/irq-riscv-aplic-main.h
@@ -28,6 +28,7 @@ struct aplic_priv {
u32 gsi_base;
u32 nr_irqs;
u32 nr_idcs;
+ u32 id;
void __iomem *regs;
struct aplic_msicfg msicfg;
};
diff --git a/drivers/irqchip/irq-riscv-aplic-msi.c b/drivers/irqchip/irq-riscv-aplic-msi.c
index 086d00e0429e..433ab2f270d9 100644
--- a/drivers/irqchip/irq-riscv-aplic-msi.c
+++ b/drivers/irqchip/irq-riscv-aplic-msi.c
@@ -178,6 +178,7 @@ static void aplic_msi_write_msg(struct msi_desc *desc, struct msi_msg *msg)
int aplic_msi_setup(struct device *dev, void __iomem *regs)
{
const struct imsic_global_config *imsic_global;
+ struct irq_domain *msi_domain;
struct irq_domain *irqdomain;
struct aplic_priv *priv;
struct aplic_msicfg *mc;
@@ -261,8 +262,14 @@ int aplic_msi_setup(struct device *dev, void __iomem *regs)
* IMSIC and the IMSIC MSI domains are created later through
* the platform driver probing so we set it explicitly here.
*/
- if (is_of_node(dev->fwnode))
+ if (is_of_node(dev->fwnode)) {
of_msi_configure(dev, to_of_node(dev->fwnode));
+ } else {
+ msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev),
+ DOMAIN_BUS_PLATFORM_MSI);
+ if (msi_domain)
+ dev_set_msi_domain(dev, msi_domain);
+ }
}

/* Create irq domain instance for the APLIC MSI-mode */
@@ -276,6 +283,7 @@ int aplic_msi_setup(struct device *dev, void __iomem *regs)
return -ENOMEM;
}

+ dev_set_drvdata(dev, priv);
/* Advertise the interrupt controller */
pa = priv->msicfg.base_ppn << APLIC_xMSICFGADDR_PPN_SHIFT;
dev_info(dev, "%d interrupts forwared to MSI base %pa\n",
--
2.39.2

2023-10-25 20:27:20

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 17/21] ACPI: bus: Add RINTC IRQ model for RISC-V

Add the IRQ model for RISC-V INTC so that acpi_set_irq_model can use this
for RISC-V.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/bus.c | 3 +++
include/linux/acpi.h | 1 +
2 files changed, 4 insertions(+)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a4aa53b7e2bb..9eace6c7042e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1158,6 +1158,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_LPIC:
message = "LPIC";
break;
+ case ACPI_IRQ_MODEL_RINTC:
+ message = "RINTC";
+ break;
default:
pr_info("Unknown interrupt routing model\n");
return -ENODEV;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4ad256a0039c..19c3dda9c2ed 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -95,6 +95,7 @@ enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PLATFORM,
ACPI_IRQ_MODEL_GIC,
ACPI_IRQ_MODEL_LPIC,
+ ACPI_IRQ_MODEL_RINTC,
ACPI_IRQ_MODEL_COUNT
};

--
2.39.2

2023-10-25 20:27:21

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 14/21] irqchip: riscv-imsic: Add ACPI support

RISC-V IMSIC interrupt controller provides IPI and MSI support.
Currently, DT based drivers setup the IPI feature early during boot but
defer setting up the MSI functionality. However, in ACPI systems, PCI
scan happens early during boot and PCI subsystem expects MSI controller
is already setup. Hence, in case of ACPI, both IPI and MSI features are
initialized early itself.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/irqchip/irq-riscv-imsic-early.c | 52 ++++++++-
drivers/irqchip/irq-riscv-imsic-platform.c | 51 +++++---
drivers/irqchip/irq-riscv-imsic-state.c | 128 ++++++++++-----------
drivers/irqchip/irq-riscv-imsic-state.h | 2 +-
include/linux/irqchip/riscv-imsic.h | 10 ++
5 files changed, 160 insertions(+), 83 deletions(-)

diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c
index 23f689ff5807..8ce864a7e4dd 100644
--- a/drivers/irqchip/irq-riscv-imsic-early.c
+++ b/drivers/irqchip/irq-riscv-imsic-early.c
@@ -5,16 +5,20 @@
*/

#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/riscv-imsic.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/smp.h>

+#include "../pci/pci.h"
#include "irq-riscv-imsic-state.h"

static int imsic_parent_irq;
@@ -216,7 +220,7 @@ static int __init imsic_early_dt_init(struct device_node *node,
struct fwnode_handle *fwnode = &node->fwnode;

/* Setup IMSIC state */
- rc = imsic_setup_state(fwnode);
+ rc = imsic_setup_state(fwnode, NULL);
if (rc) {
pr_err("%pfwP: failed to setup state (error %d)\n",
fwnode, rc);
@@ -233,3 +237,49 @@ static int __init imsic_early_dt_init(struct device_node *node,
return 0;
}
IRQCHIP_DECLARE(riscv_imsic, "riscv,imsics", imsic_early_dt_init);
+
+#ifdef CONFIG_ACPI
+
+static struct fwnode_handle *imsic_acpi_fwnode;
+
+struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev)
+{
+ return imsic_acpi_fwnode;
+}
+
+static int __init imsic_early_acpi_init(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_imsic *imsic = (struct acpi_madt_imsic *)header;
+ int rc;
+
+ imsic_acpi_fwnode = irq_domain_alloc_named_fwnode("imsic");
+ if (!imsic_acpi_fwnode) {
+ pr_err("unable to allocate IMSIC FW node\n");
+ return -ENOMEM;
+ }
+
+ /* Setup IMSIC state */
+ rc = imsic_setup_state(imsic_acpi_fwnode, (void *)imsic);
+ if (rc) {
+ pr_err("%pfwP: failed to setup state (error %d)\n", imsic_acpi_fwnode, rc);
+ return rc;
+ }
+
+ /* Do early setup of IMSIC state and IPIs */
+ rc = imsic_early_probe(imsic_acpi_fwnode);
+ if (rc)
+ return rc;
+
+ rc = imsic_platform_acpi_probe(imsic_acpi_fwnode);
+ if (!rc) {
+ pci_msi_register_fwnode_provider(&imsic_acpi_get_fwnode);
+ pci_set_msi();
+ }
+
+ return rc;
+}
+
+IRQCHIP_ACPI_DECLARE(riscv_imsic, ACPI_MADT_TYPE_IMSIC, NULL,
+ 1, imsic_early_acpi_init);
+#endif
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
index cdb659401199..f905340d24e6 100644
--- a/drivers/irqchip/irq-riscv-imsic-platform.c
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -5,6 +5,7 @@
*/

#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
@@ -308,43 +309,47 @@ static int imsic_irq_domains_init(struct fwnode_handle *fwnode)
return 0;
}

-static int imsic_platform_probe(struct platform_device *pdev)
+static int imsic_platform_probe_common(struct fwnode_handle *fwnode)
{
- struct device *dev = &pdev->dev;
struct imsic_global_config *global;
int rc;

if (!imsic) {
- dev_err(dev, "early driver not probed\n");
+ pr_err("%pfwP: early driver not probed\n", fwnode);
return -ENODEV;
}

if (imsic->base_domain) {
- dev_err(dev, "irq domain already created\n");
+ pr_err("%pfwP: irq domain already created\n", fwnode);
return -ENODEV;
}

global = &imsic->global;

/* Initialize IRQ and MSI domains */
- rc = imsic_irq_domains_init(dev->fwnode);
+ rc = imsic_irq_domains_init(fwnode);
if (rc) {
- dev_err(dev, "failed to initialize IRQ and MSI domains\n");
+ pr_err("%pfwP: failed to initialize IRQ and MSI domains\n", fwnode);
return rc;
}

- dev_info(dev, " hart-index-bits: %d, guest-index-bits: %d\n",
- global->hart_index_bits, global->guest_index_bits);
- dev_info(dev, " group-index-bits: %d, group-index-shift: %d\n",
- global->group_index_bits, global->group_index_shift);
- dev_info(dev, " per-CPU IDs %d at base PPN %pa\n",
- global->nr_ids, &global->base_addr);
- dev_info(dev, " total %d interrupts available\n",
- imsic->nr_hwirqs);
+ pr_info("%pfwP: hart-index-bits: %d, guest-index-bits: %d\n", fwnode,
+ global->hart_index_bits, global->guest_index_bits);
+ pr_info("%pfwP: group-index-bits: %d, group-index-shift: %d\n", fwnode,
+ global->group_index_bits, global->group_index_shift);
+ pr_info("%pfwP: per-CPU IDs %d at base PPN %pa\n", fwnode,
+ global->nr_ids, &global->base_addr);
+ pr_info("%pfwP: total %d interrupts available\n", fwnode,
+ imsic->nr_hwirqs);

return 0;
}

+static int imsic_platform_dt_probe(struct platform_device *pdev)
+{
+ return imsic_platform_probe_common(pdev->dev.fwnode);
+}
+
static const struct of_device_id imsic_platform_match[] = {
{ .compatible = "riscv,imsics" },
{}
@@ -355,6 +360,22 @@ static struct platform_driver imsic_platform_driver = {
.name = "riscv-imsic",
.of_match_table = imsic_platform_match,
},
- .probe = imsic_platform_probe,
+ .probe = imsic_platform_dt_probe,
};
builtin_platform_driver(imsic_platform_driver);
+
+#ifdef CONFIG_ACPI
+
+/*
+ * On ACPI based systems, PCI enumeration happens early during boot in
+ * acpi_scan_init(). PCI enumeration expects MSI domain setup before
+ * it calls pci_set_msi_domain(). Hence, unlike in DT where
+ * imsic-platform drive probe happens late during boot, ACPI based
+ * systems need to setup the MSI domain early.
+ */
+int imsic_platform_acpi_probe(struct fwnode_handle *fwnode)
+{
+ return imsic_platform_probe_common(fwnode);
+}
+
+#endif
diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index 54465e47851c..b842c499df0a 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -5,6 +5,7 @@
*/

#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/bitmap.h>
#include <linux/interrupt.h>
@@ -593,12 +594,8 @@ static int __init imsic_get_parent_hartid(struct fwnode_handle *fwnode,
int rc;
struct of_phandle_args parent;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
if (!is_of_node(fwnode))
- return -EINVAL;
+ return acpi_get_intc_index_hartid(index, hartid);

rc = of_irq_parse_one(to_of_node(fwnode), index, &parent);
if (rc)
@@ -617,12 +614,8 @@ static int __init imsic_get_parent_hartid(struct fwnode_handle *fwnode,
static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode,
u32 index, struct resource *res)
{
- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
if (!is_of_node(fwnode))
- return -EINVAL;
+ return acpi_get_imsic_mmio_info(index, res);

return of_address_to_resource(to_of_node(fwnode), index, res);
}
@@ -630,20 +623,15 @@ static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode,
static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs,
- u32 *nr_mmios)
+ u32 *nr_mmios,
+ void *opaque)
{
+ struct acpi_madt_imsic *imsic = (struct acpi_madt_imsic *)opaque;
unsigned long hartid;
struct resource res;
int rc;
u32 i;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
- if (!is_of_node(fwnode))
- return -EINVAL;
-
*nr_parent_irqs = 0;
*nr_mmios = 0;

@@ -656,58 +644,66 @@ static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
return -EINVAL;
}

- /* Find number of guest index bits in MSI address */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,guest-index-bits",
- &global->guest_index_bits);
- if (rc)
- global->guest_index_bits = 0;
+ if (is_of_node(fwnode)) {
+ /* Find number of guest index bits in MSI address */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,guest-index-bits",
+ &global->guest_index_bits);
+ if (rc)
+ global->guest_index_bits = 0;

- /* Find number of HART index bits */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,hart-index-bits",
- &global->hart_index_bits);
- if (rc) {
- /* Assume default value */
- global->hart_index_bits = __fls(*nr_parent_irqs);
- if (BIT(global->hart_index_bits) < *nr_parent_irqs)
- global->hart_index_bits++;
- }
+ /* Find number of HART index bits */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,hart-index-bits",
+ &global->hart_index_bits);
+ if (rc) {
+ /* Assume default value */
+ global->hart_index_bits = __fls(*nr_parent_irqs);
+ if (BIT(global->hart_index_bits) < *nr_parent_irqs)
+ global->hart_index_bits++;
+ }

- /* Find number of group index bits */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,group-index-bits",
- &global->group_index_bits);
- if (rc)
- global->group_index_bits = 0;
+ /* Find number of group index bits */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,group-index-bits",
+ &global->group_index_bits);
+ if (rc)
+ global->group_index_bits = 0;

- /*
- * Find first bit position of group index.
- * If not specified assumed the default APLIC-IMSIC configuration.
- */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,group-index-shift",
- &global->group_index_shift);
- if (rc)
- global->group_index_shift = IMSIC_MMIO_PAGE_SHIFT * 2;
+ /*
+ * Find first bit position of group index.
+ * If not specified assumed the default APLIC-IMSIC configuration.
+ */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,group-index-shift",
+ &global->group_index_shift);
+ if (rc)
+ global->group_index_shift = IMSIC_MMIO_PAGE_SHIFT * 2;
+
+ /* Find number of interrupt identities */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,num-ids",
+ &global->nr_ids);
+ if (rc) {
+ pr_err("%pfwP: number of interrupt identities not found\n", fwnode);
+ return rc;
+ }

- /* Find number of interrupt identities */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,num-ids",
- &global->nr_ids);
- if (rc) {
- pr_err("%pfwP: number of interrupt identities not found\n",
- fwnode);
- return rc;
+ /* Find number of guest interrupt identities */
+ rc = of_property_read_u32(to_of_node(fwnode),
+ "riscv,num-guest-ids",
+ &global->nr_guest_ids);
+ if (rc)
+ global->nr_guest_ids = global->nr_ids;
+ } else {
+ global->guest_index_bits = imsic->guest_index_bits;
+ global->hart_index_bits = imsic->hart_index_bits;
+ global->group_index_bits = imsic->group_index_bits;
+ global->group_index_shift = imsic->group_index_shift;
+ global->nr_ids = imsic->num_ids;
+ global->nr_guest_ids = imsic->num_guest_ids;
}

- /* Find number of guest interrupt identities */
- rc = of_property_read_u32(to_of_node(fwnode),
- "riscv,num-guest-ids",
- &global->nr_guest_ids);
- if (rc)
- global->nr_guest_ids = global->nr_ids;
-
/* Sanity check guest index bits */
i = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT;
if (i < global->guest_index_bits) {
@@ -775,7 +771,7 @@ static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
return 0;
}

-int __init imsic_setup_state(struct fwnode_handle *fwnode)
+int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
{
int rc, cpu;
phys_addr_t base_addr;
@@ -817,7 +813,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode)
}

/* Parse IMSIC fwnode */
- rc = imsic_parse_fwnode(fwnode, global, &nr_parent_irqs, &nr_mmios);
+ rc = imsic_parse_fwnode(fwnode, global, &nr_parent_irqs, &nr_mmios, opaque);
if (rc)
goto out_free_local;

diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index 8d209e77432e..ee1f52891e89 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -105,6 +105,6 @@ void imsic_vector_debug_show_summary(struct seq_file *m, int ind);
int imsic_hwirqs_alloc(unsigned int order);
void imsic_hwirqs_free(unsigned int base_hwirq, unsigned int order);

-int imsic_setup_state(struct fwnode_handle *fwnode);
+int imsic_setup_state(struct fwnode_handle *fwnode, void *opaque);

#endif
diff --git a/include/linux/irqchip/riscv-imsic.h b/include/linux/irqchip/riscv-imsic.h
index cbb7bcd0e4dd..c112e5559d88 100644
--- a/include/linux/irqchip/riscv-imsic.h
+++ b/include/linux/irqchip/riscv-imsic.h
@@ -84,4 +84,14 @@ static inline const struct imsic_global_config *imsic_get_global_config(void)

#endif

+#ifdef CONFIG_ACPI
+int imsic_platform_acpi_probe(struct fwnode_handle *fwnode);
+struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev);
+#else
+static inline struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
#endif
--
2.39.2

2023-10-25 20:27:24

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 16/21] irqchip: irq-sifive-plic: Add ACPI support

Add ACPI support in PLIC driver. In ACPI, IO devices use Global System
Interrupts (GSI) which is a flat space split across multiple PLICs. So,
the driver also need to provide the mapping from GSI to correct PLIC.

Signed-off-by: Sunil V L <[email protected]>
Co-developed-by: Haibo Xu <[email protected]>
Signed-off-by: Haibo Xu <[email protected]>
---
arch/riscv/include/asm/irq.h | 6 ++
drivers/irqchip/irq-sifive-plic.c | 113 +++++++++++++++++++++++++-----
2 files changed, 101 insertions(+), 18 deletions(-)

diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
index 00eb8b0333c2..eff442766c87 100644
--- a/arch/riscv/include/asm/irq.h
+++ b/arch/riscv/include/asm/irq.h
@@ -28,6 +28,12 @@ struct fwnode_handle *aplic_get_gsi_domain_id(u32 gsi);
static inline struct fwnode_handle *aplic_get_gsi_domain_id(u32 gsi) { return NULL; }
#endif

+#ifdef CONFIG_SIFIVE_PLIC
+struct fwnode_handle *plic_get_gsi_domain_id(u32 gsi);
+#else
+static inline struct fwnode_handle *plic_get_gsi_domain_id(u32 gsi) { return NULL; }
+#endif
+
int __init acpi_get_intc_index_hartid(u32 index, unsigned long *hartid);
int acpi_get_ext_intc_parent_hartid(u8 id, u32 idx, unsigned long *hartid);
void acpi_get_plic_nr_contexts(u8 id, int *nr_contexts);
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index c8f8a8cdcce1..9c61084a74eb 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -3,6 +3,7 @@
* Copyright (C) 2017 SiFive
* Copyright (C) 2018 Christoph Hellwig
*/
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -70,6 +71,8 @@ struct plic_priv {
unsigned long plic_quirks;
unsigned int nr_irqs;
unsigned long *prio_save;
+ u32 gsi_base;
+ int id;
};

struct plic_handler {
@@ -316,6 +319,10 @@ static int plic_irq_domain_translate(struct irq_domain *d,
{
struct plic_priv *priv = d->host_data;

+ /* For DT, gsi_base is always zero. */
+ if (fwspec->param[0] >= priv->gsi_base)
+ fwspec->param[0] = fwspec->param[0] - priv->gsi_base;
+
if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
return irq_domain_translate_twocell(d, fwspec, hwirq, type);

@@ -417,17 +424,31 @@ static const struct of_device_id plic_match[] = {
};

static int plic_parse_nr_irqs_and_contexts(struct platform_device *pdev,
- u32 *nr_irqs, u32 *nr_contexts)
+ u32 *nr_irqs, u32 *nr_contexts,
+ u32 *gsi_base, u32 *id)
{
struct device *dev = &pdev->dev;
+ struct acpi_madt_plic *plic;
int rc;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
- if (!is_of_node(dev->fwnode))
- return -EINVAL;
+ if (!is_of_node(dev->fwnode)) {
+ plic = *(struct acpi_madt_plic **)dev_get_platdata(dev);
+ if (!plic) {
+ dev_err(dev, "PLIC platform data is NULL!\n");
+ return -EINVAL;
+ }
+
+ *nr_irqs = plic->num_irqs;
+ acpi_get_plic_nr_contexts(plic->id, nr_contexts);
+ if (WARN_ON(!*nr_contexts)) {
+ dev_err(dev, "no PLIC context available\n");
+ return -EINVAL;
+ }
+
+ *gsi_base = plic->gsi_base;
+ *id = plic->id;
+ return 0;
+ }

rc = of_property_read_u32(to_of_node(dev->fwnode),
"riscv,ndev", nr_irqs);
@@ -442,23 +463,28 @@ static int plic_parse_nr_irqs_and_contexts(struct platform_device *pdev,
return -EINVAL;
}

+ *gsi_base = 0;
+ *id = 0;
+
return 0;
}

static int plic_parse_context_parent_hwirq(struct platform_device *pdev,
- u32 context, u32 *parent_hwirq,
+ u32 context, u32 id, u32 *parent_hwirq,
unsigned long *parent_hartid)
{
struct device *dev = &pdev->dev;
struct of_phandle_args parent;
int rc;

- /*
- * Currently, only OF fwnode is supported so extend this
- * function for ACPI support.
- */
- if (!is_of_node(dev->fwnode))
- return -EINVAL;
+ if (!is_of_node(dev->fwnode)) {
+ rc = acpi_get_ext_intc_parent_hartid(id, context, parent_hartid);
+ if (rc)
+ return rc;
+
+ *parent_hwirq = RV_IRQ_EXT;
+ return 0;
+ }

rc = of_irq_parse_one(to_of_node(dev->fwnode), context, &parent);
if (rc)
@@ -472,6 +498,32 @@ static int plic_parse_context_parent_hwirq(struct platform_device *pdev,
return 0;
}

+#ifdef CONFIG_ACPI
+
+LIST_HEAD(plic_list);
+struct plic_priv_list {
+ struct plic_priv *priv;
+ struct list_head list;
+};
+
+struct fwnode_handle *plic_get_gsi_domain_id(u32 gsi)
+{
+ struct plic_priv_list *plic_element;
+ struct list_head *i, *tmp;
+
+ /* Find the PLIC that manages this GSI. */
+ list_for_each_safe(i, tmp, &plic_list) {
+ plic_element = list_entry(i, struct plic_priv_list, list);
+ if (gsi >= plic_element->priv->gsi_base &&
+ gsi <= (plic_element->priv->gsi_base + plic_element->priv->nr_irqs))
+ return plic_element->priv->dev->fwnode;
+ }
+
+ return NULL;
+}
+
+#endif
+
static int plic_probe(struct platform_device *pdev)
{
int rc, nr_contexts, nr_handlers = 0, i, cpu;
@@ -483,7 +535,9 @@ static int plic_probe(struct platform_device *pdev)
struct plic_priv *priv;
irq_hw_number_t hwirq;
struct resource *res;
+ int id, context_id;
bool cpuhp_setup;
+ u32 gsi_base;

if (is_of_node(dev->fwnode)) {
const struct of_device_id *id;
@@ -510,19 +564,21 @@ static int plic_probe(struct platform_device *pdev)
return -EIO;
}

- rc = plic_parse_nr_irqs_and_contexts(pdev, &nr_irqs, &nr_contexts);
+ rc = plic_parse_nr_irqs_and_contexts(pdev, &nr_irqs, &nr_contexts, &gsi_base, &id);
if (rc) {
dev_err(dev, "failed to parse irqs and contexts\n");
return rc;
}
priv->nr_irqs = nr_irqs;
+ priv->gsi_base = gsi_base;
+ priv->id = id;

priv->prio_save = devm_bitmap_zalloc(dev, nr_irqs, GFP_KERNEL);
if (!priv->prio_save)
return -ENOMEM;

for (i = 0; i < nr_contexts; i++) {
- rc = plic_parse_context_parent_hwirq(pdev, i,
+ rc = plic_parse_context_parent_hwirq(pdev, i, priv->id,
&parent_hwirq, &hartid);
if (rc) {
dev_warn(dev, "hwirq for context%d not found\n", i);
@@ -574,13 +630,23 @@ static int plic_probe(struct platform_device *pdev)
goto done;
}

+ if (is_of_node(dev->fwnode)) {
+ context_id = i;
+ } else {
+ rc = acpi_get_plic_context(priv->id, i, &context_id);
+ if (rc) {
+ dev_warn(dev, "invalid context id for context%d\n", i);
+ continue;
+ }
+ }
+
cpumask_set_cpu(cpu, &priv->lmask);
handler->present = true;
handler->hart_base = priv->regs + CONTEXT_BASE +
- i * CONTEXT_SIZE;
+ context_id * CONTEXT_SIZE;
raw_spin_lock_init(&handler->enable_lock);
handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
- i * CONTEXT_ENABLE_SIZE;
+ context_id * CONTEXT_ENABLE_SIZE;
handler->priv = priv;

handler->enable_save = devm_kcalloc(dev,
@@ -624,6 +690,17 @@ static int plic_probe(struct platform_device *pdev)
register_syscore_ops(&plic_irq_syscore_ops);
}

+#ifdef CONFIG_ACPI
+ struct plic_priv_list *plic_element;
+
+ plic_element = devm_kzalloc(dev, sizeof(*plic_element), GFP_KERNEL);
+ if (!plic_element)
+ return -ENOMEM;
+
+ plic_element->priv = priv;
+ list_add_tail(&plic_element->list, &plic_list);
+#endif
+
dev_info(dev, "mapped %d interrupts with %d handlers for"
" %d contexts.\n", nr_irqs, nr_handlers, nr_contexts);
return 0;
--
2.39.2

2023-10-25 20:27:39

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 18/21] irqchip: riscv-intc: Set ACPI irqmodel

INTC being the root interrupt controller, set the ACPI irqmodel with
callback function to get the GSI domain id.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/irqchip/irq-riscv-intc.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index f3aaecde12dd..627723d72b01 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -273,6 +273,17 @@ int acpi_get_imsic_mmio_info(u32 index, struct resource *res)
return 0;
}

+static struct fwnode_handle *riscv_get_gsi_domain_id(u32 gsi)
+{
+ struct fwnode_handle *gsi_fwnode = NULL;
+
+ gsi_fwnode = aplic_get_gsi_domain_id(gsi);
+ if (!gsi_fwnode)
+ gsi_fwnode = plic_get_gsi_domain_id(gsi);
+
+ return gsi_fwnode;
+}
+
static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
@@ -318,6 +329,7 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
* unsupported. Once IMSIC is probed, MSI support will be set.
*/
pci_no_msi();
+ acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_get_gsi_domain_id);
return 0;
}

--
2.39.2

2023-10-25 20:27:52

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 19/21] ACPI: bus: Add acpi_riscv_init function

Add a new function for RISC-V to do any architecture specific
initialization. This function will be used to create platform devices
like APLIC, PLIC, RISC-V IOMMU etc. This is similar to acpi_arm_init().

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/bus.c | 1 +
drivers/acpi/riscv/Makefile | 2 +-
drivers/acpi/riscv/init.c | 12 ++++++++++++
include/linux/acpi.h | 6 ++++++
4 files changed, 20 insertions(+), 1 deletion(-)
create mode 100644 drivers/acpi/riscv/init.c

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9eace6c7042e..f7ac0caf04cf 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1417,6 +1417,7 @@ static int __init acpi_init(void)
acpi_hest_init();
acpi_ghes_init();
acpi_arm_init();
+ acpi_riscv_init();
acpi_scan_init();
acpi_ec_init();
acpi_debugfs_init();
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index f80b3da230e9..c4d679b1359e 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += rhct.o irq.o
+obj-y += rhct.o irq.o init.o
diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
new file mode 100644
index 000000000000..b5807bbdb171
--- /dev/null
+++ b/drivers/acpi/riscv/init.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Ventana Micro Systems Inc
+ * Author: Sunil V L <[email protected]>
+ *
+ */
+
+#include <linux/acpi.h>
+
+void __init acpi_riscv_init(void)
+{
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 19c3dda9c2ed..c408070ac52e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1527,6 +1527,12 @@ void acpi_arm_init(void);
static inline void acpi_arm_init(void) { }
#endif

+#ifdef CONFIG_RISCV
+void acpi_riscv_init(void);
+#else
+static inline void acpi_riscv_init(void) { }
+#endif
+
#ifdef CONFIG_ACPI_PCC
void acpi_init_pcc(void);
#else
--
2.39.2

2023-10-25 20:28:05

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 21/21] ACPI: RISC-V: Create PLIC platform device

Since PLIC needs to be a platform device, probe the MADT and create
platform devices for each PLIC in the system.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/riscv/init.c | 1 +
drivers/acpi/riscv/init.h | 1 +
drivers/acpi/riscv/irq.c | 14 ++++++++++++++
3 files changed, 16 insertions(+)

diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
index e7eff7ab1474..c6fd4097e8ae 100644
--- a/drivers/acpi/riscv/init.c
+++ b/drivers/acpi/riscv/init.c
@@ -11,4 +11,5 @@
void __init acpi_riscv_init(void)
{
riscv_acpi_aplic_platform_init();
+ riscv_acpi_plic_platform_init();
}
diff --git a/drivers/acpi/riscv/init.h b/drivers/acpi/riscv/init.h
index 17bcf0baaadb..b4b305d83b3a 100644
--- a/drivers/acpi/riscv/init.h
+++ b/drivers/acpi/riscv/init.h
@@ -3,3 +3,4 @@

void __init riscv_acpi_imsic_platform_init(void);
void __init riscv_acpi_aplic_platform_init(void);
+void __init riscv_acpi_plic_platform_init(void);
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index fbccecdcbf8b..90b0738e2b9f 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -104,3 +104,17 @@ void __init riscv_acpi_aplic_platform_init(void)
{
acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0);
}
+
+static int __init plic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_plic *plic = (struct acpi_madt_plic *)header;
+
+ return irqchip_add_platform_device("riscv-plic", plic->id, plic->base_addr,
+ plic->size, header);
+}
+
+void __init riscv_acpi_plic_platform_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_PLIC, plic_parse_madt, 0);
+}
--
2.39.2

2023-10-25 20:28:06

by Sunil V L

[permalink] [raw]
Subject: [RFC PATCH v2 20/21] ACPI: RISC-V: Create APLIC platform device

Since APLIC needs to be a platform device, probe the MADT and create
platform devices for each APLIC in the system.

Signed-off-by: Sunil V L <[email protected]>
---
drivers/acpi/riscv/init.c | 2 ++
drivers/acpi/riscv/init.h | 5 +++
drivers/acpi/riscv/irq.c | 74 +++++++++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+)
create mode 100644 drivers/acpi/riscv/init.h

diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
index b5807bbdb171..e7eff7ab1474 100644
--- a/drivers/acpi/riscv/init.c
+++ b/drivers/acpi/riscv/init.c
@@ -6,7 +6,9 @@
*/

#include <linux/acpi.h>
+#include "init.h"

void __init acpi_riscv_init(void)
{
+ riscv_acpi_aplic_platform_init();
}
diff --git a/drivers/acpi/riscv/init.h b/drivers/acpi/riscv/init.h
new file mode 100644
index 000000000000..17bcf0baaadb
--- /dev/null
+++ b/drivers/acpi/riscv/init.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/init.h>
+
+void __init riscv_acpi_imsic_platform_init(void);
+void __init riscv_acpi_aplic_platform_init(void);
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 36e0525b3235..fbccecdcbf8b 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -6,6 +6,8 @@
*/

#include <linux/acpi.h>
+#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
#include <linux/sort.h>

static int irqchip_cmp_func(const void *in0, const void *in1)
@@ -30,3 +32,75 @@ void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)
return;
sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);
}
+
+static int __init irqchip_add_platform_device(char *irqchip_name, u32 irqchip_id,
+ resource_size_t iomem_res_start,
+ resource_size_t iomem_res_size,
+ union acpi_subtable_headers *header)
+{
+ struct platform_device *pdev;
+ struct fwnode_handle *fn;
+ struct resource *res;
+ int ret;
+
+ fn = irq_domain_alloc_named_id_fwnode(irqchip_name, irqchip_id);
+ if (!fn)
+ return -ENOMEM;
+
+ pdev = platform_device_alloc(irqchip_name, irqchip_id);
+ if (!pdev) {
+ irq_domain_free_fwnode(fn);
+ return -ENOMEM;
+ }
+
+ res = kcalloc(1, sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ irq_domain_free_fwnode(fn);
+ platform_device_put(pdev);
+ return -ENOMEM;
+ }
+
+ res->start = iomem_res_start;
+ res->end = res->start + iomem_res_size - 1;
+ res->flags = IORESOURCE_MEM;
+ ret = platform_device_add_resources(pdev, res, 1);
+ /*
+ * Resources are duplicated in platform_device_add_resources,
+ * free their allocated memory
+ */
+ kfree(res);
+
+ /*
+ * Add copy of aplic pointer so that platform driver get aplic details.
+ */
+ ret = platform_device_add_data(pdev, &header, sizeof(header));
+ if (ret) {
+ irq_domain_free_fwnode(fn);
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ pdev->dev.fwnode = fn;
+ ret = platform_device_add(pdev);
+ if (ret) {
+ irq_domain_free_fwnode(fn);
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __init aplic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header;
+
+ return irqchip_add_platform_device("riscv-aplic", aplic->id, aplic->base_addr,
+ aplic->size, header);
+}
+
+void __init riscv_acpi_aplic_platform_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0);
+}
--
2.39.2

2023-10-26 16:32:00

by Catalin Marinas

[permalink] [raw]
Subject: Re: [RFC PATCH v2 01/21] arm64: PCI: Migrate ACPI related functions to pci-acpi.c

On Thu, Oct 26, 2023 at 01:53:24AM +0530, Sunil V L wrote:
> The functions defined in arm64 for ACPI support are required
> for RISC-V also. To avoid duplication, move these functions
> to common location.
>
> Signed-off-by: Sunil V L <[email protected]>
> Acked-by: Bjorn Helgaas <[email protected]>

Acked-by: Catalin Marinas <[email protected]>

2023-10-26 16:52:37

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

On Thu, Oct 26, 2023 at 01:53:36AM +0530, Sunil V L wrote:
> The RINTC subtype structure in MADT also has information about other
> interrupt controllers like MMIO. So, save those information and provide
> interfaces to retrieve them when required by corresponding drivers.

> @@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,

> + * MSI controller (IMSIC) in RISC-V is optional. So, unless
> + * IMSIC is discovered, set system wide MSI support as
> + * unsupported. Once IMSIC is probed, MSI support will be set.
> + */
> + pci_no_msi();

It doesn't seem like we should have to tell the PCI core about
functionality we *don't* have.

I would think IMSIC would be detected before enumerating PCI devices
that might use it, and if we *haven't* found an IMSIC by the time we
get to pci_register_host_bridge(), would/should we set
PCI_BUS_FLAGS_NO_MSI there?

I see Thomas is cc'd; he'd have better insight.

Bjorn

2023-10-26 17:05:03

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

On Thu, Oct 26, 2023 at 01:53:29AM +0530, Sunil V L wrote:
> On RISC-V platforms, apart from root interrupt controllers (which
> provide local interrupts and IPI), other interrupt controllers in the
> hierarchy are probed late. Enable this select this CONFIG option for
> RISC-V platforms so that device drivers which connect to deferred
> interrupt controllers can take appropriate action.

Quite a bit of this series seems related to the question of interrupt
controllers being probed "late".

I don't see anything specific about *how* late this might be, but from
the use of -EPROBE_DEFER in individual drivers (8250_pnp explicitly,
and acpi_register_gsi() and pnp_irq() and acpi_pci_irq_enable(), which
are called from driver .probe() paths) it seems like interrupt
controllers might be detected even after devices that use them.

That seems like a fairly invasive change to the driver probe flow.
If we really need to do that, I think it might merit a little more
background as justification since we haven't had to do it for any
other arch yet.

Bjorn

> Signed-off-by: Sunil V L <[email protected]>
> ---
> arch/riscv/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 8c105a151e12..b62441aefa6a 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -12,6 +12,7 @@ config 32BIT
>
> config RISCV
> def_bool y
> + select ARCH_ACPI_DEFERRED_GSI if ACPI
> select ACPI_GENERIC_GSI if ACPI
> select ACPI_MCFG if (ACPI && PCI)
> select ACPI_REDUCED_HARDWARE_ONLY if ACPI
> --
> 2.39.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

2023-10-27 11:29:44

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

Hi Bjorn,

On Thu, Oct 26, 2023 at 11:51:50AM -0500, Bjorn Helgaas wrote:
> On Thu, Oct 26, 2023 at 01:53:36AM +0530, Sunil V L wrote:
> > The RINTC subtype structure in MADT also has information about other
> > interrupt controllers like MMIO. So, save those information and provide
> > interfaces to retrieve them when required by corresponding drivers.
>
> > @@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
>
> > + * MSI controller (IMSIC) in RISC-V is optional. So, unless
> > + * IMSIC is discovered, set system wide MSI support as
> > + * unsupported. Once IMSIC is probed, MSI support will be set.
> > + */
> > + pci_no_msi();
>
> It doesn't seem like we should have to tell the PCI core about
> functionality we *don't* have.
>
> I would think IMSIC would be detected before enumerating PCI devices
> that might use it, and if we *haven't* found an IMSIC by the time we
> get to pci_register_host_bridge(), would/should we set
> PCI_BUS_FLAGS_NO_MSI there?
>
The check in pci_register_host_bridge() is like below.

if (bridge->msi_domain && !dev_get_msi_domain(&bus->dev) &&
!pci_host_of_has_msi_map(parent))
bus->bus_flags |= PCI_BUS_FLAGS_NO_MSI;

When there is no IMSIC, bridge->msi_domain is 0 and hence
PCI_BUS_FLAGS_NO_MSI will never be set. Do you recommend to set
PCI_BUS_FLAGS_NO_MSI if bridge->msi_domain is 0? Let me know if I am
missing something.

Thanks,
Sunil

2023-10-27 11:55:24

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

On Fri, Oct 27, 2023 at 04:59:31PM +0530, Sunil V L wrote:
> Hi Bjorn,
>
> On Thu, Oct 26, 2023 at 11:51:50AM -0500, Bjorn Helgaas wrote:
> > On Thu, Oct 26, 2023 at 01:53:36AM +0530, Sunil V L wrote:
> > > The RINTC subtype structure in MADT also has information about other
> > > interrupt controllers like MMIO. So, save those information and provide
> > > interfaces to retrieve them when required by corresponding drivers.
> >
> > > @@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
> >
> > > + * MSI controller (IMSIC) in RISC-V is optional. So, unless
> > > + * IMSIC is discovered, set system wide MSI support as
> > > + * unsupported. Once IMSIC is probed, MSI support will be set.
> > > + */
> > > + pci_no_msi();
> >
> > It doesn't seem like we should have to tell the PCI core about
> > functionality we *don't* have.
> >
> > I would think IMSIC would be detected before enumerating PCI devices
> > that might use it, and if we *haven't* found an IMSIC by the time we
> > get to pci_register_host_bridge(), would/should we set
> > PCI_BUS_FLAGS_NO_MSI there?
> >
> The check in pci_register_host_bridge() is like below.
>
> if (bridge->msi_domain && !dev_get_msi_domain(&bus->dev) &&
> !pci_host_of_has_msi_map(parent))
> bus->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
>
> When there is no IMSIC, bridge->msi_domain is 0 and hence
> PCI_BUS_FLAGS_NO_MSI will never be set. Do you recommend to set
> PCI_BUS_FLAGS_NO_MSI if bridge->msi_domain is 0? Let me know if I am
> missing something.
>
What seems to work is, setting bridge->msi_domain = true in
pci_create_root_bus() similar to how pci_host_common_probe() sets for OF
framework. Would that be better solution?

Thanks,
Sunil

2023-10-27 12:56:52

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

On Thu, Oct 26, 2023 at 12:04:08PM -0500, Bjorn Helgaas wrote:
> On Thu, Oct 26, 2023 at 01:53:29AM +0530, Sunil V L wrote:
> > On RISC-V platforms, apart from root interrupt controllers (which
> > provide local interrupts and IPI), other interrupt controllers in the
> > hierarchy are probed late. Enable this select this CONFIG option for
> > RISC-V platforms so that device drivers which connect to deferred
> > interrupt controllers can take appropriate action.
>
> Quite a bit of this series seems related to the question of interrupt
> controllers being probed "late".
>
> I don't see anything specific about *how* late this might be, but from
> the use of -EPROBE_DEFER in individual drivers (8250_pnp explicitly,
> and acpi_register_gsi() and pnp_irq() and acpi_pci_irq_enable(), which
> are called from driver .probe() paths) it seems like interrupt
> controllers might be detected even after devices that use them.
>
> That seems like a fairly invasive change to the driver probe flow.
> If we really need to do that, I think it might merit a little more
> background as justification since we haven't had to do it for any
> other arch yet.
>

Hi Bjorn,

In RISC-V, the APLIC can be a converter from wired (GSI) to MSI interrupts.
Hence, especially in this mode, it has to be a platform device to use
device MSI domain. Also, according to Marc Zyngier there is no reason to
probe interrupt controllers early apart from root controller. So, the
device drivers which use wired interrupts need to be probed after APLIC.

The PNP devices and PCI INTx GSI links use either
acpi_dev_resource_interrupt() (PNP) or acpi_register_gsi() directly
(PCI). The approach taken here is to follow the example of
acpi_irq_get() which is enhanced to return EPROBE_DEFER and several
platform device drivers which use platform_get_irq() seem to be handling
this already.

Using ResourceSource dependency (mbigen uses) in the namespace as part of
Extended Interrupt Descriptor will not ensure the order since PNP/INTx
GSI devices don't work with that.

Is there any other better way to create dependency between IO devices
and the interrupt controllers when interrupt controller itself is a
platform device? While using core_initcall() for interrupt controllers
seem to work which forces the interrupt controller to be probed first,
Marc is not in favor of that approach since it is fragile.

Thanks a lot for your help with review and feedback!

Sunil

2023-10-27 17:46:16

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

On Thu, Oct 26 2023 at 11:51, Bjorn Helgaas wrote:
> On Thu, Oct 26, 2023 at 01:53:36AM +0530, Sunil V L wrote:
>> The RINTC subtype structure in MADT also has information about other
>> interrupt controllers like MMIO. So, save those information and provide
>> interfaces to retrieve them when required by corresponding drivers.
>
>> @@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
>
>> + * MSI controller (IMSIC) in RISC-V is optional. So, unless
>> + * IMSIC is discovered, set system wide MSI support as
>> + * unsupported. Once IMSIC is probed, MSI support will be set.
>> + */
>> + pci_no_msi();
>
> It doesn't seem like we should have to tell the PCI core about
> functionality we *don't* have.
>
> I would think IMSIC would be detected before enumerating PCI devices
> that might use it, and if we *haven't* found an IMSIC by the time we
> get to pci_register_host_bridge(), would/should we set
> PCI_BUS_FLAGS_NO_MSI there?
>
> I see Thomas is cc'd; he'd have better insight.

I was not really involved with this bus and MSI domain logic. Marc
should know. CC'ed.

Thanks,

tglx


2023-10-30 14:29:06

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC PATCH v2 11/21] PCI: MSI: Add helper function to set system wide MSI support

On Thu, Oct 26 2023 at 01:53, Sunil V. L. wrote:
> Like pci_no_msi() used to disable MSI support, add a function to enable
> system wide MSI support.

Why?

int pci_msi_enable = 1;

So this function makes it more one or what am I missing here?

Thanks,

tglx

2023-10-30 17:54:48

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 11/21] PCI: MSI: Add helper function to set system wide MSI support

On Mon, Oct 30, 2023 at 03:28:53PM +0100, Thomas Gleixner wrote:
> On Thu, Oct 26 2023 at 01:53, Sunil V. L. wrote:
> > Like pci_no_msi() used to disable MSI support, add a function to enable
> > system wide MSI support.
>
> Why?
>
> int pci_msi_enable = 1;
>
> So this function makes it more one or what am I missing here?
>
Hi Thomas,

Just noting related discussion :
https://www.spinics.net/lists/linux-serial/msg57616.html

The MSI controller on RISC-V (IMSIC) is optional for the platform. So,
when by default pci_msi_enable = 1 and the MSI controller is not
discovered, we get stack trace like below.

[ 0.608941] [<ffffffff804d0400>] pci_msi_setup_msi_irqs+0x18/0x34
[ 0.608991] [<ffffffff804cfe04>] msix_capability_init+0x228/0x406
[ 0.609001] [<ffffffff804cfbc6>] __pci_enable_msix_range+0x1b4/0x1ca
[ 0.609011] [<ffffffff804ce8c2>]
pci_alloc_irq_vectors_affinity+0x6e/0xee
[ 0.609020] [<ffffffff8055015c>] vp_find_vqs_msix+0xfa/0x350
[ 0.609031] [<ffffffff8054ff54>] vp_find_vqs+0x36/0x144
[ 0.609040] [<ffffffff8054f7b8>] vp_modern_find_vqs+0x14/0x48
[ 0.609049] [<ffffffff8064d3fc>] init_vqs+0x362/0x4ee
[ 0.609058] [<ffffffff8064c8be>] virtnet_probe+0x672/0xa70
[ 0.609067] [<ffffffff80549d38>] virtio_dev_probe+0x194/0x200
[ 0.609075] [<ffffffff805afb52>] really_probe+0x106/0x28a
[ 0.609083] [<ffffffff805aefda>] __driver_probe_device+0x62/0xdc
[ 0.609091] [<ffffffff805af920>] driver_probe_device+0x38/0x164
[ 0.609098] [<ffffffff805af146>] __driver_attach+0xd0/0x17c
[ 0.609106] [<ffffffff805ac6e2>] bus_for_each_dev+0xd0/0x11c
[ 0.609116] [<ffffffff805af06e>] driver_attach+0x1a/0x22
[ 0.609123] [<ffffffff805ace06>] bus_add_driver+0x136/0x208
[ 0.609132] [<ffffffff805b044e>] driver_register+0x48/0xda
[ 0.609140] [<ffffffff80549594>] register_virtio_driver+0x20/0x2a
[ 0.609157] [<ffffffff80a3060e>] virtio_net_driver_init+0x76/0xa6
[ 0.609168] [<ffffffff800020ec>] do_one_initcall+0xc0/0x21e
[ 0.609176] [<ffffffff80a00f68>] do_initcall_level+0x7c/0x8e
[ 0.609186] [<ffffffff80a00eb6>] do_initcalls+0x52/0x88
[ 0.609195] [<ffffffff80a00e5c>] do_basic_setup+0x1c/0x24
[ 0.609204] [<ffffffff80a00e00>] kernel_init_freeable+0xe2/0x122
[ 0.609213] [<ffffffff8090beb4>] kernel_init+0x1a/0x18e
[ 0.609223] [<ffffffff8000383e>] ret_from_fork+0xa/0x1c

So, what I did was, by default call pci_no_msi() to disable MSI and then
call pci_set_msi() to enable when MSI controller is probed.

But I think Bjorn's suggestion to depend on PCI_BUS_FLAGS_NO_MSI may be
better idea. In that case, we need to set bridge->msi_domain to true in
pci_create_root_bus(). Let me know what do you prefer or if I am
completely missing something here.

Thanks,
Sunil

2023-10-30 19:29:38

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC PATCH v2 11/21] PCI: MSI: Add helper function to set system wide MSI support

On Mon, Oct 30 2023 at 23:24, Sunil V. L. wrote:
> On Mon, Oct 30, 2023 at 03:28:53PM +0100, Thomas Gleixner wrote:
> Just noting related discussion :
> https://www.spinics.net/lists/linux-serial/msg57616.html
>
> The MSI controller on RISC-V (IMSIC) is optional for the platform. So,
> when by default pci_msi_enable = 1 and the MSI controller is not
> discovered, we get stack trace like below.

<SNIP>

> So, what I did was, by default call pci_no_msi() to disable MSI and then
> call pci_set_msi() to enable when MSI controller is probed.

Your taste sensors should have gone out of range ...

> But I think Bjorn's suggestion to depend on PCI_BUS_FLAGS_NO_MSI may be
> better idea. In that case, we need to set bridge->msi_domain to true in
> pci_create_root_bus(). Let me know what do you prefer or if I am
> completely missing something here.

That's definitely more sensible, but as I said in the other thread, Marc
is the one who did the PCI core/bridge setup magic and he is definitely
in a better position to answer that bridge->msi_domain question.

Thanks,

tglx

2023-10-31 02:01:19

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 11/21] PCI: MSI: Add helper function to set system wide MSI support

On Mon, Oct 30, 2023 at 08:29:13PM +0100, Thomas Gleixner wrote:
> On Mon, Oct 30 2023 at 23:24, Sunil V. L. wrote:
> > On Mon, Oct 30, 2023 at 03:28:53PM +0100, Thomas Gleixner wrote:
> > Just noting related discussion :
> > https://www.spinics.net/lists/linux-serial/msg57616.html
> >
> > The MSI controller on RISC-V (IMSIC) is optional for the platform. So,
> > when by default pci_msi_enable = 1 and the MSI controller is not
> > discovered, we get stack trace like below.
>
> <SNIP>
>
> > So, what I did was, by default call pci_no_msi() to disable MSI and then
> > call pci_set_msi() to enable when MSI controller is probed.
>
> Your taste sensors should have gone out of range ...
>
> > But I think Bjorn's suggestion to depend on PCI_BUS_FLAGS_NO_MSI may be
> > better idea. In that case, we need to set bridge->msi_domain to true in
> > pci_create_root_bus(). Let me know what do you prefer or if I am
> > completely missing something here.
>
> That's definitely more sensible, but as I said in the other thread, Marc
> is the one who did the PCI core/bridge setup magic and he is definitely
> in a better position to answer that bridge->msi_domain question.
>
Thanks!. It looks like Marc introduced bridge->msi_domain in [1] for
exactly the same problem we have with RISC-V + ACPI. Let me remove this
hack and do similar to pci_host_common_probe() in next revision unless I
get objections to that approach.

Sorry, somehow my script didn't copy Marc in the series. Will make sure
I copy him explicitly in next revision.

[1] - https://lore.kernel.org/all/[email protected]/

Thanks!
Sunil

2023-11-06 11:36:36

by Marc Zyngier

[permalink] [raw]
Subject: Re: [RFC PATCH v2 13/21] irqchip: riscv-intc: Add ACPI support for AIA

On Fri, 27 Oct 2023 18:45:38 +0100,
Thomas Gleixner <[email protected]> wrote:
>
> On Thu, Oct 26 2023 at 11:51, Bjorn Helgaas wrote:
> > On Thu, Oct 26, 2023 at 01:53:36AM +0530, Sunil V L wrote:
> >> The RINTC subtype structure in MADT also has information about other
> >> interrupt controllers like MMIO. So, save those information and provide
> >> interfaces to retrieve them when required by corresponding drivers.
> >
> >> @@ -218,7 +306,19 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
> >
> >> + * MSI controller (IMSIC) in RISC-V is optional. So, unless
> >> + * IMSIC is discovered, set system wide MSI support as
> >> + * unsupported. Once IMSIC is probed, MSI support will be set.
> >> + */
> >> + pci_no_msi();
> >
> > It doesn't seem like we should have to tell the PCI core about
> > functionality we *don't* have.
> >
> > I would think IMSIC would be detected before enumerating PCI devices
> > that might use it, and if we *haven't* found an IMSIC by the time we
> > get to pci_register_host_bridge(), would/should we set
> > PCI_BUS_FLAGS_NO_MSI there?
> >
> > I see Thomas is cc'd; he'd have better insight.
>
> I was not really involved with this bus and MSI domain logic. Marc
> should know. CC'ed.

The canonical way of doing this is by the platform expressing that
there is no linkage between the PCIe RC and the MSI controller. If
there is no MSI domain associated with the RC, then by extension the
endpoints don't get one either.

There are additional quirks linked to the msi_domain host bridge
property, allowing the host bridge driver to indicate that it isn't in
charge of MSIs, but that a third party may provide it (in which case a
MSI irq domain will be associated with it).

In any case, slapping a pci_no_msi() call in an irqchip driver is
gross and most probably a sign that this is going in the wrong
direction, specially as this is platform-wide.

The only cases I'd expect this function to be called are:

- Platform or firmware explicitly disallowing MSIs
- pci=nomsi on the command line

none of which are the business of an irqchip driver.

HTH,

M.

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

2023-11-06 22:16:31

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

On Fri, Oct 27, 2023 at 06:25:03PM +0530, Sunil V L wrote:
> On Thu, Oct 26, 2023 at 12:04:08PM -0500, Bjorn Helgaas wrote:
> > On Thu, Oct 26, 2023 at 01:53:29AM +0530, Sunil V L wrote:
> > > On RISC-V platforms, apart from root interrupt controllers (which
> > > provide local interrupts and IPI), other interrupt controllers in the
> > > hierarchy are probed late. Enable this select this CONFIG option for
> > > RISC-V platforms so that device drivers which connect to deferred
> > > interrupt controllers can take appropriate action.
> >
> > Quite a bit of this series seems related to the question of interrupt
> > controllers being probed "late".
> >
> > I don't see anything specific about *how* late this might be, but from
> > the use of -EPROBE_DEFER in individual drivers (8250_pnp explicitly,
> > and acpi_register_gsi() and pnp_irq() and acpi_pci_irq_enable(), which
> > are called from driver .probe() paths) it seems like interrupt
> > controllers might be detected even after devices that use them.
> >
> > That seems like a fairly invasive change to the driver probe flow.
> > If we really need to do that, I think it might merit a little more
> > background as justification since we haven't had to do it for any
> > other arch yet.
>
> In RISC-V, the APLIC can be a converter from wired (GSI) to MSI interrupts.
> Hence, especially in this mode, it has to be a platform device to use
> device MSI domain. Also, according to Marc Zyngier there is no reason to
> probe interrupt controllers early apart from root controller. So, the
> device drivers which use wired interrupts need to be probed after APLIC.
>
> The PNP devices and PCI INTx GSI links use either
> acpi_dev_resource_interrupt() (PNP) or acpi_register_gsi() directly
> (PCI). The approach taken here is to follow the example of
> acpi_irq_get() which is enhanced to return EPROBE_DEFER and several
> platform device drivers which use platform_get_irq() seem to be handling
> this already.

This series (patch 04/21 "ACPI: irq: Add support for deferred probe in
acpi_register_gsi()" [1]) makes acpi_register_gsi() return
-EPROBE_DEFER, which percolates up through pci_enable_device().

Maybe that's ok, but this affects *all* PCI drivers, and it's a new
case that did not occur before. Many drivers emit warning or error
messages for any pci_enable_device() failure, which you probably don't
want in this case, since -EPROBE_DEFER is not really a "failure";
IIUC, it just means "probe again later."

> Using ResourceSource dependency (mbigen uses) in the namespace as part of
> Extended Interrupt Descriptor will not ensure the order since PNP/INTx
> GSI devices don't work with that.

Are these PNP/INTx GSI devices described in ACPI? In the namespace?
Or in a static table?

> Is there any other better way to create dependency between IO devices
> and the interrupt controllers when interrupt controller itself is a
> platform device? While using core_initcall() for interrupt controllers
> seem to work which forces the interrupt controller to be probed first,
> Marc is not in favor of that approach since it is fragile.

I guess PCI interrupts from the PCI host bridges (PNP0A03 devices)
feed into the APLIC? And APLIC is described via MADT? Based on this
series, it looks like this:

acpi_init
+ acpi_riscv_init
+ riscv_acpi_aplic_platform_init
+ acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0)
acpi_scan_init
acpi_pci_root_init
acpi_pci_link_init
acpi_bus_scan # add PCI host bridges, etc

If that's the sequence, it looks like aplic_parse_madt() should be
called before the PCI host bridges are added.

Or maybe this isn't how the APLICs are enumerated?

Bjorn

[1] https://lore.kernel.org/r/[email protected]

2023-11-22 12:23:20

by Björn Töpel

[permalink] [raw]
Subject: Re: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

Hi Sunil!

I'm trying to decipher this thread, so apologies in advance for the
stupid questions! :-P

Sunil V L <[email protected]> writes:

> Hi Bjorn,
>
> On Mon, Nov 06, 2023 at 04:16:06PM -0600, Bjorn Helgaas wrote:
>> On Fri, Oct 27, 2023 at 06:25:03PM +0530, Sunil V L wrote:
>> > On Thu, Oct 26, 2023 at 12:04:08PM -0500, Bjorn Helgaas wrote:
>> > > On Thu, Oct 26, 2023 at 01:53:29AM +0530, Sunil V L wrote:
>> > > > On RISC-V platforms, apart from root interrupt controllers (which
>> > > > provide local interrupts and IPI), other interrupt controllers in the
>> > > > hierarchy are probed late. Enable this select this CONFIG option for
>> > > > RISC-V platforms so that device drivers which connect to deferred
>> > > > interrupt controllers can take appropriate action.
>> > >
>> > > Quite a bit of this series seems related to the question of interrupt
>> > > controllers being probed "late".
>> > >
>> > > I don't see anything specific about *how* late this might be, but from
>> > > the use of -EPROBE_DEFER in individual drivers (8250_pnp explicitly,
>> > > and acpi_register_gsi() and pnp_irq() and acpi_pci_irq_enable(), which
>> > > are called from driver .probe() paths) it seems like interrupt
>> > > controllers might be detected even after devices that use them.
>> > >
>> > > That seems like a fairly invasive change to the driver probe flow.
>> > > If we really need to do that, I think it might merit a little more
>> > > background as justification since we haven't had to do it for any
>> > > other arch yet.
>> >
>> > In RISC-V, the APLIC can be a converter from wired (GSI) to MSI interrupts.
>> > Hence, especially in this mode, it has to be a platform device to use
>> > device MSI domain. Also, according to Marc Zyngier there is no reason to
>> > probe interrupt controllers early apart from root controller. So, the
>> > device drivers which use wired interrupts need to be probed after APLIC.
>> >
>> > The PNP devices and PCI INTx GSI links use either
>> > acpi_dev_resource_interrupt() (PNP) or acpi_register_gsi() directly
>> > (PCI). The approach taken here is to follow the example of
>> > acpi_irq_get() which is enhanced to return EPROBE_DEFER and several
>> > platform device drivers which use platform_get_irq() seem to be handling
>> > this already.
>>
>> This series (patch 04/21 "ACPI: irq: Add support for deferred probe in
>> acpi_register_gsi()" [1]) makes acpi_register_gsi() return
>> -EPROBE_DEFER, which percolates up through pci_enable_device().
>>
>> Maybe that's ok, but this affects *all* PCI drivers, and it's a new
>> case that did not occur before. Many drivers emit warning or error
>> messages for any pci_enable_device() failure, which you probably don't
>> want in this case, since -EPROBE_DEFER is not really a "failure";
>> IIUC, it just means "probe again later."
>>
> Yeah, I think all the drivers which need to be supported on RISC-V
> ACPI based systems will have to support deferred probe with this scheme.
>
>> > Using ResourceSource dependency (mbigen uses) in the namespace as part of
>> > Extended Interrupt Descriptor will not ensure the order since PNP/INTx
>> > GSI devices don't work with that.
>>
>> Are these PNP/INTx GSI devices described in ACPI? In the namespace?
>> Or in a static table?
>>
> Yes, these are standard devices in the namespace. For ex: PNP0501(16550)
> or PNP0C0F (PCI interrupt link devices) are in the namespace.
>
>> > Is there any other better way to create dependency between IO devices
>> > and the interrupt controllers when interrupt controller itself is a
>> > platform device? While using core_initcall() for interrupt controllers
>> > seem to work which forces the interrupt controller to be probed first,
>> > Marc is not in favor of that approach since it is fragile.
>>
>> I guess PCI interrupts from the PCI host bridges (PNP0A03 devices)
>> feed into the APLIC? And APLIC is described via MADT? Based on this
>> series, it looks like this:
>>
>> acpi_init
>> + acpi_riscv_init
>> + riscv_acpi_aplic_platform_init
>> + acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0)
>> acpi_scan_init
>> acpi_pci_root_init
>> acpi_pci_link_init
>> acpi_bus_scan # add PCI host bridges, etc
>>
>> If that's the sequence, it looks like aplic_parse_madt() should be
>> called before the PCI host bridges are added.
>>
>> Or maybe this isn't how the APLICs are enumerated?
>>
> That's partly correct. APLIC platform devices are created prior to PCI
> host bridges added. But the actual APLIC driver which creates the
> irqdomain will be probed as a regular platform driver for the APLIC
> device. The platform driver probe will happen using DD framework and
> devices don't have any dependency on APLIC which can cause device probe
> prior to APLIC driver probe.
>
> DT supports fw_devlink framework which makes it easier for IRQ devices
> to use regular platform drivers and produces-consumers are probed in the
> order without requiring drivers to do deferred probe. But I don't see
> that supported for ACPI framework. Also, the way PNP devices get added
> there is an assumption that interrupt controller is already setup fully.

AFAIU, the -EPROBE_DEFER changes are needed for GSIs (and the way the
IMSIC/APLIC irqchip series is structured), right?

There's a couple of separate pieces in play here:
1. IMSIC-IPI (MADT init)
2. IMSIC-MSI (MADT init, imsic_platform_acpi_probe() patch 14)
3. APLIC-wired (platform)
4. APLIC-MSI-bridge (platform)

APLIC-MSI-bridge is pretty much a RISC-V mbigen.

Some devices do not have ResourceSource parsing implemented yet. The PNP
devices that cannot use ResourceSource (you mention PNP0501 (16550) and
PNP0C0F (PCI interrupt link devices), do we really need to care about
them for the RISC-V platforms using ACPI? If that would change, the
kernel drivers can be adjusted (d44fa3d46079 ("ACPI: Add support for
ResourceSource/IRQ domain mapping"))?

I guess my question is we need to care about GSIs w/o explicit
ResourceSource, so that APLIC-MSI-bridge can be used.

GED works nicely with ResourceSource, and covers a lot of the GSI
use-cases, no?

And if we do care, then *both* 3 and 4 would need at MADT scan
point/init, and not be a platform device (late init).

From my, probably naive perspective, it's a bit weird *not* to create
the irq domains at MADT scan time.

> With this new use case in RISC-V, here are the alternatives I am aware of.
>
> 1) Use core_initcall() in the APLIC drivers which makes APLIC driver to
> be probed prior to PNP or PCI INTx devices. But this was ruled out in
> the context of DT from Marc.
>
> 2) Like the approach tried in this series, add support for deferred
> probe in drivers. This will be invasive change requiring many drivers to
> change like you pointed.

Again is this only for GSIs? Patch 14 moves the IMSIC-MSI init to MADT
for PCIe devices (which is different from DT), so it's not for PCIe
devices. I wonder if it's a lot of churn for something that will not be
used for RISC-V ACPI systems...

A quick look at what Arm's GICv3 does, all irq domains are created at
MADT init.


Björn (no, not PCI-Bjorn ;-))

2023-11-30 07:27:02

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 06/21] RISC-V: Kconfig: Select deferred GSI probe for ACPI systems

Hi Björn!,

Apologies for the delay in response. Held up with something else.

On Wed, Nov 22, 2023 at 01:22:56PM +0100, Björn Töpel wrote:
> Hi Sunil!
>
> I'm trying to decipher this thread, so apologies in advance for the
> stupid questions! :-P
>
Appreciate your help to review the patch and suggesting solutions.
Thank you very much!.

> Sunil V L <[email protected]> writes:
>
> > Hi Bjorn,
> >
> > On Mon, Nov 06, 2023 at 04:16:06PM -0600, Bjorn Helgaas wrote:
> >> On Fri, Oct 27, 2023 at 06:25:03PM +0530, Sunil V L wrote:
> >> > On Thu, Oct 26, 2023 at 12:04:08PM -0500, Bjorn Helgaas wrote:
> >> > > On Thu, Oct 26, 2023 at 01:53:29AM +0530, Sunil V L wrote:
> >> > > > On RISC-V platforms, apart from root interrupt controllers (which
> >> > > > provide local interrupts and IPI), other interrupt controllers in the
> >> > > > hierarchy are probed late. Enable this select this CONFIG option for
> >> > > > RISC-V platforms so that device drivers which connect to deferred
> >> > > > interrupt controllers can take appropriate action.
> >> > >
> >> > > Quite a bit of this series seems related to the question of interrupt
> >> > > controllers being probed "late".
> >> > >
> >> > > I don't see anything specific about *how* late this might be, but from
> >> > > the use of -EPROBE_DEFER in individual drivers (8250_pnp explicitly,
> >> > > and acpi_register_gsi() and pnp_irq() and acpi_pci_irq_enable(), which
> >> > > are called from driver .probe() paths) it seems like interrupt
> >> > > controllers might be detected even after devices that use them.
> >> > >
> >> > > That seems like a fairly invasive change to the driver probe flow.
> >> > > If we really need to do that, I think it might merit a little more
> >> > > background as justification since we haven't had to do it for any
> >> > > other arch yet.
> >> >
> >> > In RISC-V, the APLIC can be a converter from wired (GSI) to MSI interrupts.
> >> > Hence, especially in this mode, it has to be a platform device to use
> >> > device MSI domain. Also, according to Marc Zyngier there is no reason to
> >> > probe interrupt controllers early apart from root controller. So, the
> >> > device drivers which use wired interrupts need to be probed after APLIC.
> >> >
> >> > The PNP devices and PCI INTx GSI links use either
> >> > acpi_dev_resource_interrupt() (PNP) or acpi_register_gsi() directly
> >> > (PCI). The approach taken here is to follow the example of
> >> > acpi_irq_get() which is enhanced to return EPROBE_DEFER and several
> >> > platform device drivers which use platform_get_irq() seem to be handling
> >> > this already.
> >>
> >> This series (patch 04/21 "ACPI: irq: Add support for deferred probe in
> >> acpi_register_gsi()" [1]) makes acpi_register_gsi() return
> >> -EPROBE_DEFER, which percolates up through pci_enable_device().
> >>
> >> Maybe that's ok, but this affects *all* PCI drivers, and it's a new
> >> case that did not occur before. Many drivers emit warning or error
> >> messages for any pci_enable_device() failure, which you probably don't
> >> want in this case, since -EPROBE_DEFER is not really a "failure";
> >> IIUC, it just means "probe again later."
> >>
> > Yeah, I think all the drivers which need to be supported on RISC-V
> > ACPI based systems will have to support deferred probe with this scheme.
> >
> >> > Using ResourceSource dependency (mbigen uses) in the namespace as part of
> >> > Extended Interrupt Descriptor will not ensure the order since PNP/INTx
> >> > GSI devices don't work with that.
> >>
> >> Are these PNP/INTx GSI devices described in ACPI? In the namespace?
> >> Or in a static table?
> >>
> > Yes, these are standard devices in the namespace. For ex: PNP0501(16550)
> > or PNP0C0F (PCI interrupt link devices) are in the namespace.
> >
> >> > Is there any other better way to create dependency between IO devices
> >> > and the interrupt controllers when interrupt controller itself is a
> >> > platform device? While using core_initcall() for interrupt controllers
> >> > seem to work which forces the interrupt controller to be probed first,
> >> > Marc is not in favor of that approach since it is fragile.
> >>
> >> I guess PCI interrupts from the PCI host bridges (PNP0A03 devices)
> >> feed into the APLIC? And APLIC is described via MADT? Based on this
> >> series, it looks like this:
> >>
> >> acpi_init
> >> + acpi_riscv_init
> >> + riscv_acpi_aplic_platform_init
> >> + acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0)
> >> acpi_scan_init
> >> acpi_pci_root_init
> >> acpi_pci_link_init
> >> acpi_bus_scan # add PCI host bridges, etc
> >>
> >> If that's the sequence, it looks like aplic_parse_madt() should be
> >> called before the PCI host bridges are added.
> >>
> >> Or maybe this isn't how the APLICs are enumerated?
> >>
> > That's partly correct. APLIC platform devices are created prior to PCI
> > host bridges added. But the actual APLIC driver which creates the
> > irqdomain will be probed as a regular platform driver for the APLIC
> > device. The platform driver probe will happen using DD framework and
> > devices don't have any dependency on APLIC which can cause device probe
> > prior to APLIC driver probe.
> >
> > DT supports fw_devlink framework which makes it easier for IRQ devices
> > to use regular platform drivers and produces-consumers are probed in the
> > order without requiring drivers to do deferred probe. But I don't see
> > that supported for ACPI framework. Also, the way PNP devices get added
> > there is an assumption that interrupt controller is already setup fully.
>
> AFAIU, the -EPROBE_DEFER changes are needed for GSIs (and the way the
> IMSIC/APLIC irqchip series is structured), right?
>
Yes, It is only for GSI's.

> There's a couple of separate pieces in play here:
> 1. IMSIC-IPI (MADT init)
> 2. IMSIC-MSI (MADT init, imsic_platform_acpi_probe() patch 14)
> 3. APLIC-wired (platform)
> 4. APLIC-MSI-bridge (platform)
>
> APLIC-MSI-bridge is pretty much a RISC-V mbigen.
>
> Some devices do not have ResourceSource parsing implemented yet. The PNP
> devices that cannot use ResourceSource (you mention PNP0501 (16550) and
> PNP0C0F (PCI interrupt link devices), do we really need to care about
> them for the RISC-V platforms using ACPI? If that would change, the
> kernel drivers can be adjusted (d44fa3d46079 ("ACPI: Add support for
> ResourceSource/IRQ domain mapping"))?
>
> I guess my question is we need to care about GSIs w/o explicit
> ResourceSource, so that APLIC-MSI-bridge can be used.
>
> GED works nicely with ResourceSource, and covers a lot of the GSI
> use-cases, no?
>
> And if we do care, then *both* 3 and 4 would need at MADT scan
> point/init, and not be a platform device (late init).
>
I am not sure it is a good idea not to support PCI link devices. Not
allowing them removes the flexibility in _PRT. Also, is there a standard
16550 UART apart from PNP0501? ACPI platform devices already support
deferred probe as per the series you mentioned. IMO, PNP also should
support it. So, I am not sure it is a good idea to prohibit all PnP
devices on RISC-V platforms. Other OS's might be able to handle them.

> From my, probably naive perspective, it's a bit weird *not* to create
> the irq domains at MADT scan time.
>
> > With this new use case in RISC-V, here are the alternatives I am aware of.
> >
> > 1) Use core_initcall() in the APLIC drivers which makes APLIC driver to
> > be probed prior to PNP or PCI INTx devices. But this was ruled out in
> > the context of DT from Marc.
> >
> > 2) Like the approach tried in this series, add support for deferred
> > probe in drivers. This will be invasive change requiring many drivers to
> > change like you pointed.
>
> Again is this only for GSIs? Patch 14 moves the IMSIC-MSI init to MADT
> for PCIe devices (which is different from DT), so it's not for PCIe
> devices. I wonder if it's a lot of churn for something that will not be
> used for RISC-V ACPI systems...
>
> A quick look at what Arm's GICv3 does, all irq domains are created at
> MADT init.
>
The issue is primarily with APLIC-MSI. Since it needs MSI device domain,
it has to be a platform device.

I am investigating fw-devlink like Marc suggested atleast for IRQ
dependencies. If that works, it would be the best solution.

Thanks,
Sunil

2024-02-01 18:01:16

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [RFC PATCH v2 05/21] pnp.h: Return -EPROBE_DEFER for disabled IRQ resource in pnp_irq()

On Wed, Oct 25, 2023 at 10:24 PM Sunil V L <[email protected]> wrote:
>
> To support deferred PNP driver probe, pnp_irq() must return -EPROBE_DEFER
> so that the device driver can do deferred probe if the interrupt controller
> is not probed early.
>
> Signed-off-by: Sunil V L <[email protected]>
> ---
> include/linux/pnp.h | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/pnp.h b/include/linux/pnp.h
> index c2a7cfbca713..21cf833789fb 100644
> --- a/include/linux/pnp.h
> +++ b/include/linux/pnp.h
> @@ -147,12 +147,18 @@ static inline resource_size_t pnp_mem_len(struct pnp_dev *dev,
> }
>
>
> -static inline resource_size_t pnp_irq(struct pnp_dev *dev, unsigned int bar)
> +static inline int pnp_irq(struct pnp_dev *dev, unsigned int bar)
> {
> struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar);
>
> - if (pnp_resource_valid(res))
> + if (pnp_resource_valid(res)) {
> +#if IS_ENABLED(CONFIG_ARCH_ACPI_DEFERRED_GSI)
> + if (!pnp_resource_enabled(res))
> + return -EPROBE_DEFER;
> +#endif

What would be wrong with

if (IS_ENABLED(CONFIG_ARCH_ACPI_DEFERRED_GSI) && !pnp_resource_enabled(res))
return -EPROBE_DEFER;

?

> +
> return res->start;
> + }
> return -1;
> }
>
> --
> 2.39.2
>

2024-02-02 08:49:42

by Sunil V L

[permalink] [raw]
Subject: Re: [RFC PATCH v2 05/21] pnp.h: Return -EPROBE_DEFER for disabled IRQ resource in pnp_irq()

On Thu, Feb 01, 2024 at 07:00:51PM +0100, Rafael J. Wysocki wrote:
> On Wed, Oct 25, 2023 at 10:24 PM Sunil V L <[email protected]> wrote:
> >
> > To support deferred PNP driver probe, pnp_irq() must return -EPROBE_DEFER
> > so that the device driver can do deferred probe if the interrupt controller
> > is not probed early.
> >
> > Signed-off-by: Sunil V L <[email protected]>
> > ---
> > include/linux/pnp.h | 10 ++++++++--
> > 1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/linux/pnp.h b/include/linux/pnp.h
> > index c2a7cfbca713..21cf833789fb 100644
> > --- a/include/linux/pnp.h
> > +++ b/include/linux/pnp.h
> > @@ -147,12 +147,18 @@ static inline resource_size_t pnp_mem_len(struct pnp_dev *dev,
> > }
> >
> >
> > -static inline resource_size_t pnp_irq(struct pnp_dev *dev, unsigned int bar)
> > +static inline int pnp_irq(struct pnp_dev *dev, unsigned int bar)
> > {
> > struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar);
> >
> > - if (pnp_resource_valid(res))
> > + if (pnp_resource_valid(res)) {
> > +#if IS_ENABLED(CONFIG_ARCH_ACPI_DEFERRED_GSI)
> > + if (!pnp_resource_enabled(res))
> > + return -EPROBE_DEFER;
> > +#endif
>
> What would be wrong with
>
> if (IS_ENABLED(CONFIG_ARCH_ACPI_DEFERRED_GSI) && !pnp_resource_enabled(res))
> return -EPROBE_DEFER;
>
> ?
Hi Rafael,

Actually, this is v2 version of the patch and there is recent v3. Please
take a look at [1] for the latest version.

However, your comment is still valid for v3. I will update as you
mentioned.

[1] - https://lore.kernel.org/linux-arm-kernel/[email protected]/

Thanks,
Sunil
>
> > +
> > return res->start;
> > + }
> > return -1;
> > }
> >
> > --
> > 2.39.2
> >