Skip to content

Commit

Permalink
irqchip/riscv-aplic: Add ACPI support
Browse files Browse the repository at this point in the history
Add ACPI support in APLIC drivers. Use the mapping created early during
boot to get the details about the APLIC.

Signed-off-by: Sunil V L <[email protected]>
Reviewed-by: Anup Patel <[email protected]>
Tested-by: Björn Töpel <[email protected]>
Acked-by: Thomas Gleixner <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Rafael J. Wysocki <[email protected]>
  • Loading branch information
vlsunil authored and rafaeljw committed Aug 27, 2024
1 parent fbe826b commit 5122e38
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 33 deletions.
22 changes: 14 additions & 8 deletions drivers/irqchip/irq-riscv-aplic-direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/

#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cpu.h>
Expand Down Expand Up @@ -189,17 +190,22 @@ 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)
u32 *parent_hwirq, unsigned long *parent_hartid,
struct aplic_priv *priv)
{
struct of_phandle_args parent;
unsigned long hartid;
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)) {
hartid = acpi_rintc_ext_parent_to_hartid(priv->acpi_aplic_id, index);
if (hartid == INVALID_HARTID)
return -ENODEV;

*parent_hartid = hartid;
*parent_hwirq = RV_IRQ_EXT;
return 0;
}

rc = of_irq_parse_one(to_of_node(dev->fwnode), index, &parent);
if (rc)
Expand Down Expand Up @@ -237,7 +243,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs)
/* Setup per-CPU IDC and target CPU mask */
current_cpu = get_cpu();
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;
Expand Down
71 changes: 47 additions & 24 deletions drivers/irqchip/irq-riscv-aplic-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/

#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/irqchip/riscv-aplic.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
Expand Down Expand Up @@ -125,39 +127,50 @@ static void aplic_init_hw_irqs(struct aplic_priv *priv)
writel(0, priv->regs + APLIC_DOMAINCFG);
}

#ifdef CONFIG_ACPI
static const struct acpi_device_id aplic_acpi_match[] = {
{ "RSCV0002", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, aplic_acpi_match);

#endif

int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs)
{
struct device_node *np = to_of_node(dev->fwnode);
struct of_phandle_args parent;
int rc;

/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!np)
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(np, "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(np, "msi-parent")) {
while (!of_irq_parse_one(np, priv->nr_idcs, &parent))
priv->nr_idcs++;
if (np) {
/* Find out number of interrupt sources */
rc = of_property_read_u32(np, "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(np, "msi-parent")) {
while (!of_irq_parse_one(np, priv->nr_idcs, &parent))
priv->nr_idcs++;
}
} else {
rc = riscv_acpi_get_gsi_info(dev->fwnode, &priv->gsi_base, &priv->acpi_aplic_id,
&priv->nr_irqs, &priv->nr_idcs);
if (rc) {
dev_err(dev, "failed to find GSI mapping\n");
return rc;
}
}

/* Setup initial state APLIC interrupts */
Expand All @@ -184,14 +197,23 @@ static int aplic_probe(struct platform_device *pdev)
* If msi-parent property is present then setup APLIC MSI
* mode otherwise setup APLIC direct mode.
*/
msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent");
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
rc = aplic_direct_setup(dev, regs);
if (rc)
dev_err(dev, "failed to setup APLIC in %s mode\n", msi_mode ? "MSI" : "direct");

#ifdef CONFIG_ACPI
if (!acpi_disabled)
acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
#endif

return rc;
}

Expand All @@ -204,6 +226,7 @@ static struct platform_driver aplic_driver = {
.driver = {
.name = "riscv-aplic",
.of_match_table = aplic_match,
.acpi_match_table = ACPI_PTR(aplic_acpi_match),
},
.probe = aplic_probe,
};
Expand Down
1 change: 1 addition & 0 deletions drivers/irqchip/irq-riscv-aplic-main.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct aplic_priv {
u32 gsi_base;
u32 nr_irqs;
u32 nr_idcs;
u32 acpi_aplic_id;
void __iomem *regs;
struct aplic_msicfg msicfg;
};
Expand Down
9 changes: 8 additions & 1 deletion drivers/irqchip/irq-riscv-aplic-msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ static const struct msi_domain_template aplic_msi_template = {
int aplic_msi_setup(struct device *dev, void __iomem *regs)
{
const struct imsic_global_config *imsic_global;
struct irq_domain *msi_domain;
struct aplic_priv *priv;
struct aplic_msicfg *mc;
phys_addr_t pa;
Expand Down Expand Up @@ -257,8 +258,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);
}
}

if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, &aplic_msi_template,
Expand Down

0 comments on commit 5122e38

Please sign in to comment.