[PATCH v4 1/3] ACPI: RISC-V: Add support for RIMT

Anup Patel anup at brainfault.org
Tue Jul 15 21:19:25 PDT 2025


On Thu, Jul 10, 2025 at 2:28 PM Sunil V L <sunilvl at ventanamicro.com> wrote:
>
> RISC-V IO Mapping Table (RIMT) is a static ACPI table to communicate
> IOMMU information to the OS. The spec is available at [1].
>
> The changes at high level are,
>         a) Initialize data structures required for IOMMU/device
>            configuration using the data from RIMT. Provide APIs required
>            for device configuration.
>         b) Provide an API for IOMMU drivers to register the
>            fwnode with RIMT data structures. This API will create a
>            fwnode for PCIe IOMMU.
>
> [1] - https://github.com/riscv-non-isa/riscv-acpi-rimt
>
> Signed-off-by: Sunil V L <sunilvl at ventanamicro.com>
> ---
>  MAINTAINERS                 |   1 +
>  arch/riscv/Kconfig          |   1 +
>  drivers/acpi/Kconfig        |   4 +
>  drivers/acpi/riscv/Kconfig  |   7 +
>  drivers/acpi/riscv/Makefile |   1 +
>  drivers/acpi/riscv/init.c   |   2 +
>  drivers/acpi/riscv/init.h   |   1 +
>  drivers/acpi/riscv/rimt.c   | 520 ++++++++++++++++++++++++++++++++++++
>  include/linux/acpi_rimt.h   |  28 ++
>  9 files changed, 565 insertions(+)
>  create mode 100644 drivers/acpi/riscv/Kconfig
>  create mode 100644 drivers/acpi/riscv/rimt.c
>  create mode 100644 include/linux/acpi_rimt.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fad6cb025a19..21125f7c0d0a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -345,6 +345,7 @@ L:  linux-acpi at vger.kernel.org
>  L:     linux-riscv at lists.infradead.org
>  S:     Maintained
>  F:     drivers/acpi/riscv/
> +F:     include/linux/acpi_rimt.h
>
>  ACPI PCC(Platform Communication Channel) MAILBOX DRIVER
>  M:     Sudeep Holla <sudeep.holla at arm.com>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index d71ea0f4466f..67bbf3b7302d 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -16,6 +16,7 @@ config RISCV
>         select ACPI_MCFG if (ACPI && PCI)
>         select ACPI_PPTT if ACPI
>         select ACPI_REDUCED_HARDWARE_ONLY if ACPI
> +       select ACPI_RIMT if ACPI
>         select ACPI_SPCR_TABLE if ACPI
>         select ARCH_DMA_DEFAULT_COHERENT
>         select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 7bc40c2735ac..4381803c308c 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -546,6 +546,10 @@ if ARM64
>  source "drivers/acpi/arm64/Kconfig"
>  endif
>
> +if RISCV
> +source "drivers/acpi/riscv/Kconfig"
> +endif
> +
>  config ACPI_PPTT
>         bool
>
> diff --git a/drivers/acpi/riscv/Kconfig b/drivers/acpi/riscv/Kconfig
> new file mode 100644
> index 000000000000..046296a18d00
> --- /dev/null
> +++ b/drivers/acpi/riscv/Kconfig
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# ACPI Configuration for RISC-V
> +#
> +
> +config ACPI_RIMT
> +       bool
> diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
> index a96fdf1e2cb8..1284a076fa88 100644
> --- a/drivers/acpi/riscv/Makefile
> +++ b/drivers/acpi/riscv/Makefile
> @@ -2,3 +2,4 @@
>  obj-y                                  += rhct.o init.o irq.o
>  obj-$(CONFIG_ACPI_PROCESSOR_IDLE)      += cpuidle.o
>  obj-$(CONFIG_ACPI_CPPC_LIB)            += cppc.o
> +obj-$(CONFIG_ACPI_RIMT)                        += rimt.o
> diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
> index 673e4d5dd752..7c00f7995e86 100644
> --- a/drivers/acpi/riscv/init.c
> +++ b/drivers/acpi/riscv/init.c
> @@ -10,4 +10,6 @@
>  void __init acpi_arch_init(void)
>  {
>         riscv_acpi_init_gsi_mapping();
> +       if (IS_ENABLED(CONFIG_ACPI_RIMT))
> +               riscv_acpi_rimt_init();
>  }
> diff --git a/drivers/acpi/riscv/init.h b/drivers/acpi/riscv/init.h
> index 0b9a07e4031f..1680aa2aaf23 100644
> --- a/drivers/acpi/riscv/init.h
> +++ b/drivers/acpi/riscv/init.h
> @@ -2,3 +2,4 @@
>  #include <linux/init.h>
>
>  void __init riscv_acpi_init_gsi_mapping(void);
> +void __init riscv_acpi_rimt_init(void);
> diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c
> new file mode 100644
> index 000000000000..0cb486b19470
> --- /dev/null
> +++ b/drivers/acpi/riscv/rimt.c
> @@ -0,0 +1,520 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024-2025, Ventana Micro Systems Inc
> + *     Author: Sunil V L <sunilvl at ventanamicro.com>
> + *
> + */
> +
> +#define pr_fmt(fmt)    "ACPI: RIMT: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/acpi_rimt.h>
> +#include <linux/iommu.h>
> +#include <linux/list.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include "init.h"
> +
> +struct rimt_fwnode {
> +       struct list_head list;
> +       struct acpi_rimt_node *rimt_node;
> +       struct fwnode_handle *fwnode;
> +};
> +
> +static LIST_HEAD(rimt_fwnode_list);
> +static DEFINE_SPINLOCK(rimt_fwnode_lock);
> +
> +#define RIMT_TYPE_MASK(type)   (1 << (type))

Can we not use BIT() here ?

> +#define RIMT_IOMMU_TYPE                BIT(0)
> +
> +/* Root pointer to the mapped RIMT table */
> +static struct acpi_table_header *rimt_table;
> +
> +/**
> + * rimt_set_fwnode() - Create rimt_fwnode and use it to register
> + *                    iommu data in the rimt_fwnode_list
> + *
> + * @rimt_node: RIMT table node associated with the IOMMU
> + * @fwnode: fwnode associated with the RIMT node
> + *
> + * Returns: 0 on success
> + *          <0 on failure
> + */
> +static int rimt_set_fwnode(struct acpi_rimt_node *rimt_node,
> +                          struct fwnode_handle *fwnode)
> +{
> +       struct rimt_fwnode *np;
> +
> +       np = kzalloc(sizeof(*np), GFP_ATOMIC);
> +
> +       if (WARN_ON(!np))
> +               return -ENOMEM;
> +
> +       INIT_LIST_HEAD(&np->list);
> +       np->rimt_node = rimt_node;
> +       np->fwnode = fwnode;
> +
> +       spin_lock(&rimt_fwnode_lock);
> +       list_add_tail(&np->list, &rimt_fwnode_list);
> +       spin_unlock(&rimt_fwnode_lock);
> +
> +       return 0;
> +}
> +
> +/**
> + * rimt_get_fwnode() - Retrieve fwnode associated with an RIMT node
> + *
> + * @node: RIMT table node to be looked-up
> + *
> + * Returns: fwnode_handle pointer on success, NULL on failure
> + */
> +static struct fwnode_handle *rimt_get_fwnode(struct acpi_rimt_node *node)
> +{
> +       struct rimt_fwnode *curr;
> +       struct fwnode_handle *fwnode = NULL;

Inverted pyramid declaration of local variable here and everywhere else below.

> +
> +       spin_lock(&rimt_fwnode_lock);
> +       list_for_each_entry(curr, &rimt_fwnode_list, list) {
> +               if (curr->rimt_node == node) {
> +                       fwnode = curr->fwnode;
> +                       break;
> +               }
> +       }
> +       spin_unlock(&rimt_fwnode_lock);
> +
> +       return fwnode;
> +}
> +
> +static acpi_status rimt_match_node_callback(struct acpi_rimt_node *node,
> +                                           void *context)
> +{
> +       struct device *dev = context;
> +       acpi_status status = AE_NOT_FOUND;
> +
> +       if (node->type == ACPI_RIMT_NODE_TYPE_IOMMU) {
> +               struct acpi_rimt_iommu *iommu_node = (struct acpi_rimt_iommu *)&node->node_data;
> +
> +               if (dev_is_pci(dev)) {
> +                       struct pci_dev *pdev;
> +                       u16 bdf;
> +
> +                       pdev = to_pci_dev(dev);
> +                       bdf = PCI_DEVID(pdev->bus->number, pdev->devfn);
> +                       if ((pci_domain_nr(pdev->bus) == iommu_node->pcie_segment_number) &&
> +                           bdf == iommu_node->pcie_bdf) {
> +                               status = AE_OK;
> +                       } else {
> +                               status = AE_NOT_FOUND;
> +                       }
> +               } else {
> +                       struct platform_device *pdev = to_platform_device(dev);
> +                       struct resource *res;
> +
> +                       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +                       if (res && res->start == iommu_node->base_address)
> +                               status = AE_OK;
> +                       else
> +                               status = AE_NOT_FOUND;
> +               }
> +       } else if (node->type == ACPI_RIMT_NODE_TYPE_PCIE_ROOT_COMPLEX) {
> +               struct acpi_rimt_pcie_rc *pci_rc;
> +               struct pci_bus *bus;
> +
> +               bus = to_pci_bus(dev);
> +               pci_rc = (struct acpi_rimt_pcie_rc *)node->node_data;
> +
> +               /*
> +                * It is assumed that PCI segment numbers maps one-to-one
> +                * with root complexes. Each segment number can represent only
> +                * one root complex.
> +                */
> +               status = pci_rc->pcie_segment_number == pci_domain_nr(bus) ?
> +                                                       AE_OK : AE_NOT_FOUND;
> +       } else if (node->type == ACPI_RIMT_NODE_TYPE_PLAT_DEVICE) {
> +               struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
> +               struct acpi_device *adev;
> +               struct acpi_rimt_platform_device *ncomp;
> +               struct device *plat_dev = dev;
> +
> +               /*
> +                * Walk the device tree to find a device with an
> +                * ACPI companion; there is no point in scanning
> +                * RIMT for a device matching a platform device if
> +                * the device does not have an ACPI companion to
> +                * start with.
> +                */
> +               do {
> +                       adev = ACPI_COMPANION(plat_dev);
> +                       if (adev)
> +                               break;
> +
> +                       plat_dev = plat_dev->parent;
> +               } while (plat_dev);
> +
> +               if (!adev)
> +                       return status;
> +
> +               status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
> +               if (ACPI_FAILURE(status)) {
> +                       dev_warn(plat_dev, "Can't get device full path name\n");
> +                       return status;
> +               }
> +
> +               ncomp = (struct acpi_rimt_platform_device *)node->node_data;
> +               status = !strcmp(ncomp->device_name, buf.pointer) ?
> +                                                       AE_OK : AE_NOT_FOUND;
> +               acpi_os_free(buf.pointer);
> +       }
> +
> +       return status;
> +}
> +
> +static struct acpi_rimt_node *rimt_scan_node(enum acpi_rimt_node_type type,
> +                                            void *context)
> +{
> +       struct acpi_rimt_node *rimt_node, *rimt_end;
> +       struct acpi_table_rimt *rimt;
> +       int i;
> +
> +       if (!rimt_table)
> +               return NULL;
> +
> +       /* Get the first RIMT node */
> +       rimt = (struct acpi_table_rimt *)rimt_table;
> +       rimt_node = ACPI_ADD_PTR(struct acpi_rimt_node, rimt,
> +                                rimt->node_offset);
> +       rimt_end = ACPI_ADD_PTR(struct acpi_rimt_node, rimt_table,
> +                               rimt_table->length);
> +
> +       for (i = 0; i < rimt->num_nodes; i++) {
> +               if (WARN_TAINT(rimt_node >= rimt_end, TAINT_FIRMWARE_WORKAROUND,
> +                              "RIMT node pointer overflows, bad table!\n"))
> +                       return NULL;
> +
> +               if (rimt_node->type == type &&
> +                   ACPI_SUCCESS(rimt_match_node_callback(rimt_node, context)))
> +                       return rimt_node;
> +
> +               rimt_node = ACPI_ADD_PTR(struct acpi_rimt_node, rimt_node,
> +                                        rimt_node->length);
> +       }
> +
> +       return NULL;
> +}
> +
> +static bool rimt_pcie_rc_supports_ats(struct acpi_rimt_node *node)
> +{
> +       struct acpi_rimt_pcie_rc *pci_rc;
> +
> +       pci_rc = (struct acpi_rimt_pcie_rc *)node->node_data;
> +       return pci_rc->flags & ACPI_RIMT_PCIE_ATS_SUPPORTED;
> +}
> +
> +static int rimt_iommu_xlate(struct device *dev, struct acpi_rimt_node *node, u32 deviceid)
> +{
> +       struct fwnode_handle *rimt_fwnode;
> +
> +       if (!node)
> +               return -ENODEV;
> +
> +       rimt_fwnode = rimt_get_fwnode(node);
> +
> +       /*
> +        * The IOMMU drivers may not be probed yet.
> +        * Defer the IOMMU configuration
> +        */
> +       if (!rimt_fwnode)
> +               return -EPROBE_DEFER;
> +
> +       return acpi_iommu_fwspec_init(dev, deviceid, rimt_fwnode);
> +}
> +
> +struct rimt_pci_alias_info {
> +       struct device *dev;
> +       struct acpi_rimt_node *node;
> +       const struct iommu_ops *ops;
> +};
> +
> +static int rimt_id_map(struct acpi_rimt_id_mapping *map, u8 type, u32 rid_in, u32 *rid_out)
> +{
> +       if (rid_in < map->source_id_base ||
> +           (rid_in > map->source_id_base + map->num_ids))
> +               return -ENXIO;
> +
> +       *rid_out = map->dest_id_base + (rid_in - map->source_id_base);
> +       return 0;
> +}
> +
> +static struct acpi_rimt_node *rimt_node_get_id(struct acpi_rimt_node *node,
> +                                              u32 *id_out, int index)
> +{
> +       struct acpi_rimt_platform_device *plat_node;
> +       struct acpi_rimt_pcie_rc *pci_node;
> +       u32 id_mapping_offset, num_id_mapping;
> +       struct acpi_rimt_id_mapping *map;
> +       struct acpi_rimt_node *parent;
> +
> +       if (node->type == ACPI_RIMT_NODE_TYPE_PCIE_ROOT_COMPLEX) {
> +               pci_node = (struct acpi_rimt_pcie_rc *)&node->node_data;
> +               id_mapping_offset = pci_node->id_mapping_offset;
> +               num_id_mapping = pci_node->num_id_mappings;
> +       } else if (node->type == ACPI_RIMT_NODE_TYPE_PLAT_DEVICE) {
> +               plat_node = (struct acpi_rimt_platform_device *)&node->node_data;
> +               id_mapping_offset = plat_node->id_mapping_offset;
> +               num_id_mapping = plat_node->num_id_mappings;
> +       } else {
> +               return NULL;
> +       }
> +
> +       if (!id_mapping_offset || !num_id_mapping || index >= num_id_mapping)
> +               return NULL;
> +
> +       map = ACPI_ADD_PTR(struct acpi_rimt_id_mapping, node,
> +                          id_mapping_offset + index * sizeof(*map));
> +
> +       /* Firmware bug! */
> +       if (!map->dest_offset) {
> +               pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
> +                      node, node->type);
> +               return NULL;
> +       }
> +
> +       parent = ACPI_ADD_PTR(struct acpi_rimt_node, rimt_table, map->dest_offset);
> +
> +       if (node->type == ACPI_RIMT_NODE_TYPE_PLAT_DEVICE ||
> +           node->type == ACPI_RIMT_NODE_TYPE_PCIE_ROOT_COMPLEX) {
> +               *id_out = map->dest_offset;
> +               return parent;
> +       }
> +
> +       return NULL;
> +}
> +
> +static struct acpi_rimt_node *rimt_node_map_id(struct acpi_rimt_node *node,
> +                                              u32 id_in, u32 *id_out,
> +                                              u8 type_mask)
> +{
> +       struct acpi_rimt_pcie_rc *pci_node;
> +       struct acpi_rimt_platform_device *plat_node;
> +       u32 id = id_in;
> +       u32 id_mapping_offset, num_id_mapping;
> +
> +       /* Parse the ID mapping tree to find specified node type */
> +       while (node) {
> +               struct acpi_rimt_id_mapping *map;
> +               int i, rc = 0;
> +               u32 map_id = id;
> +
> +               if (RIMT_TYPE_MASK(node->type) & type_mask) {
> +                       if (id_out)
> +                               *id_out = id;
> +                       return node;
> +               }
> +
> +               if (node->type == ACPI_RIMT_NODE_TYPE_PCIE_ROOT_COMPLEX) {
> +                       pci_node = (struct acpi_rimt_pcie_rc *)&node->node_data;
> +                       id_mapping_offset = pci_node->id_mapping_offset;
> +                       num_id_mapping = pci_node->num_id_mappings;
> +               } else if (node->type == ACPI_RIMT_NODE_TYPE_PLAT_DEVICE) {
> +                       plat_node = (struct acpi_rimt_platform_device *)&node->node_data;
> +                       id_mapping_offset = plat_node->id_mapping_offset;
> +                       num_id_mapping = plat_node->num_id_mappings;
> +               } else {
> +                       goto fail_map;
> +               }
> +
> +               if (!id_mapping_offset || !num_id_mapping)
> +                       goto fail_map;
> +
> +               map = ACPI_ADD_PTR(struct acpi_rimt_id_mapping, node,
> +                                  id_mapping_offset);
> +
> +               /* Firmware bug! */
> +               if (!map->dest_offset) {
> +                       pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
> +                              node, node->type);
> +                       goto fail_map;
> +               }
> +
> +               /* Do the ID translation */
> +               for (i = 0; i < num_id_mapping; i++, map++) {
> +                       rc = rimt_id_map(map, node->type, map_id, &id);
> +                       if (!rc)
> +                               break;
> +               }
> +
> +               if (i == num_id_mapping)
> +                       goto fail_map;
> +
> +               node = ACPI_ADD_PTR(struct acpi_rimt_node, rimt_table,
> +                                   rc ? 0 : map->dest_offset);
> +       }
> +
> +fail_map:
> +       /* Map input ID to output ID unchanged on mapping failure */
> +       if (id_out)
> +               *id_out = id_in;
> +
> +       return NULL;
> +}
> +
> +static struct acpi_rimt_node *rimt_node_map_platform_id(struct acpi_rimt_node *node, u32 *id_out,
> +                                                       u8 type_mask, int index)
> +{
> +       struct acpi_rimt_node *parent;
> +       u32 id;
> +
> +       parent = rimt_node_get_id(node, &id, index);
> +       if (!parent)
> +               return NULL;
> +
> +       if (!(RIMT_TYPE_MASK(parent->type) & type_mask))
> +               parent = rimt_node_map_id(parent, id, id_out, type_mask);
> +       else
> +               if (id_out)
> +                       *id_out = id;
> +
> +       return parent;
> +}
> +
> +static int rimt_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
> +{
> +       struct rimt_pci_alias_info *info = data;
> +       struct acpi_rimt_node *parent;
> +       u32 deviceid;
> +
> +       parent = rimt_node_map_id(info->node, alias, &deviceid, RIMT_IOMMU_TYPE);
> +       return rimt_iommu_xlate(info->dev, parent, deviceid);
> +}
> +
> +/*
> + * RISC-V supports IOMMU as a PCI device or a platform device.
> + * When it is a platform device, there should be a namespace device as
> + * well along with RIMT. To create the link between RIMT information and
> + * the platform device, the IOMMU driver should register itself with the
> + * RIMT module. This is true for PCI based IOMMU as well.
> + */
> +int rimt_iommu_register(struct device *dev)
> +{
> +       struct fwnode_handle *rimt_fwnode;
> +       struct acpi_rimt_node *node;
> +
> +       node = rimt_scan_node(ACPI_RIMT_NODE_TYPE_IOMMU, dev);
> +       if (!node) {
> +               pr_err("Could not find IOMMU node in RIMT\n");
> +               return -ENODEV;
> +       }
> +
> +       if (dev_is_pci(dev)) {
> +               rimt_fwnode = acpi_alloc_fwnode_static();
> +               if (!rimt_fwnode)
> +                       return -ENOMEM;
> +
> +               rimt_fwnode->dev = dev;
> +               if (!dev->fwnode)
> +                       dev->fwnode = rimt_fwnode;
> +
> +               rimt_set_fwnode(node, rimt_fwnode);
> +       } else {
> +               rimt_set_fwnode(node, dev->fwnode);
> +       }
> +
> +       return 0;
> +}
> +
> +#ifdef CONFIG_IOMMU_API
> +
> +static int rimt_plat_iommu_map(struct device *dev, struct acpi_rimt_node *node)
> +{
> +       struct acpi_rimt_node *parent;
> +       int err = -ENODEV, i = 0;
> +       u32 deviceid = 0;
> +
> +       do {
> +               parent = rimt_node_map_platform_id(node, &deviceid,
> +                                                  RIMT_IOMMU_TYPE,
> +                                                  i++);
> +
> +               if (parent)
> +                       err = rimt_iommu_xlate(dev, parent, deviceid);
> +       } while (parent && !err);
> +
> +       return err;
> +}
> +
> +static int rimt_plat_iommu_map_id(struct device *dev,
> +                                 struct acpi_rimt_node *node,
> +                                 const u32 *in_id)
> +{
> +       struct acpi_rimt_node *parent;
> +       u32 deviceid;
> +
> +       parent = rimt_node_map_id(node, *in_id, &deviceid, RIMT_IOMMU_TYPE);
> +       if (parent)
> +               return rimt_iommu_xlate(dev, parent, deviceid);
> +
> +       return -ENODEV;
> +}
> +
> +/**
> + * rimt_iommu_configure_id - Set-up IOMMU configuration for a device.
> + *
> + * @dev: device to configure
> + * @id_in: optional input id const value pointer
> + *
> + * Returns: 0 on success, <0 on failure
> + */
> +int rimt_iommu_configure_id(struct device *dev, const u32 *id_in)
> +{
> +       struct acpi_rimt_node *node;
> +       int err = -ENODEV;
> +
> +       if (dev_is_pci(dev)) {
> +               struct iommu_fwspec *fwspec;
> +               struct pci_bus *bus = to_pci_dev(dev)->bus;
> +               struct rimt_pci_alias_info info = { .dev = dev };
> +
> +               node = rimt_scan_node(ACPI_RIMT_NODE_TYPE_PCIE_ROOT_COMPLEX, &bus->dev);
> +               if (!node)
> +                       return -ENODEV;
> +
> +               info.node = node;
> +               err = pci_for_each_dma_alias(to_pci_dev(dev),
> +                                            rimt_pci_iommu_init, &info);
> +
> +               fwspec = dev_iommu_fwspec_get(dev);
> +               if (fwspec && rimt_pcie_rc_supports_ats(node))
> +                       fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS;
> +       } else {
> +               node = rimt_scan_node(ACPI_RIMT_NODE_TYPE_PLAT_DEVICE, dev);
> +               if (!node)
> +                       return -ENODEV;
> +
> +               err = id_in ? rimt_plat_iommu_map_id(dev, node, id_in) :
> +                             rimt_plat_iommu_map(dev, node);
> +       }
> +
> +       return err;
> +}
> +
> +#endif
> +
> +void __init riscv_acpi_rimt_init(void)
> +{
> +       acpi_status status;
> +
> +       /* rimt_table will be used at runtime after the rimt init,
> +        * so we don't need to call acpi_put_table() to release
> +        * the RIMT table mapping.
> +        */
> +       status = acpi_get_table(ACPI_SIG_RIMT, 0, &rimt_table);
> +       if (ACPI_FAILURE(status)) {
> +               if (status != AE_NOT_FOUND) {
> +                       const char *msg = acpi_format_exception(status);
> +
> +                       pr_err("Failed to get table, %s\n", msg);
> +               }
> +
> +               return;
> +       }
> +}
> diff --git a/include/linux/acpi_rimt.h b/include/linux/acpi_rimt.h
> new file mode 100644
> index 000000000000..fad3adc4d899
> --- /dev/null
> +++ b/include/linux/acpi_rimt.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + *  Copyright (C) 2024-2025, Ventana Micro Systems Inc.
> + *     Author: Sunil V L <sunilvl at ventanamicro.com>
> + */
> +
> +#ifndef _ACPI_RIMT_H
> +#define _ACPI_RIMT_H
> +
> +#ifdef CONFIG_ACPI_RIMT
> +int rimt_iommu_register(struct device *dev);
> +#else
> +static inline int rimt_iommu_register(struct device *dev)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +#if defined(CONFIG_IOMMU_API) && defined(CONFIG_ACPI_RIMT)
> +int rimt_iommu_configure_id(struct device *dev, const u32 *id_in);
> +#else
> +static inline int rimt_iommu_configure_id(struct device *dev, const u32 *id_in)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +#endif /* _ACPI_RIMT_H */
> --
> 2.43.0
>
>

Otherwise, it looks good to me from RISC-V perspective.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
ANup



More information about the linux-riscv mailing list