[PATCH v7 4/9] ACPI/IORT: Add a helper to retrieve RMR memory regions

Shameer Kolothum
2021-08-05T08:09:17Z

Add a helper function (iort_iommu_get_rmrs()) that retrieves RMR
memory descriptors associated with a given IOMMU. This will be used
by IOMMU drivers to setup necessary mappings.

Invoke it from the generic helper iommu_dma_get_rmrs().

Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
drivers/acpi/arm64/iort.c | 38 ++++++++++++++++++++++++++++++++++++++
drivers/iommu/dma-iommu.c | 4 ++++
include/linux/acpi_iort.h | 7 +++++++
3 files changed, 49 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index d76ba46ebe67..3c32d62e63b6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -809,6 +809,42 @@ static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
return NULL;
}

+/**
+ * iort_iommu_get_rmrs() - Helper to retrieve RMR info associated with IOMMU
+ * @iommu_fwnode: fwnode for the IOMMU
+ * @head: RMR list head to be populated
+ *
+ * Returns: 0 on success, <0 failure. Please note, we will keep the already
+ * allocated RMR reserve regions in case of a kmemdup()
+ * failure.
+ */
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+ struct list_head *head)
+{
+ struct iommu_resv_region *e;
+ struct acpi_iort_node *iommu;
+ int rmrs = 0;
+
+ iommu = iort_get_iort_node(iommu_fwnode);
+ if (!iommu || list_empty(&iort_rmr_list))
+ return -ENODEV;
+
+ list_for_each_entry(e, &iort_rmr_list, list) {
+ struct iommu_resv_region *region;
+
+ if (e->fw_data.rmr.smmu != iommu)
+ continue;
+
+ region = kmemdup(e, sizeof(*region), GFP_KERNEL);
+ if (region) {
+ list_add_tail(&region->list, head);
+ rmrs++;
+ }
+ }
+
+ return (rmrs == 0) ? -ENODEV : 0;
+}
+
/**
* iort_iommu_msi_get_resv_regions - Reserved region driver helper
* @dev: Device from iommu_get_resv_regions()
@@ -1041,6 +1077,8 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
{ return 0; }
int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
{ return -ENODEV; }
+int iort_iommu_get_rmrs(struct fwnode_handle *fwnode, struct list_head *head)
+{ return -ENODEV; }
#endif

static int nc_dma_get_range(struct device *dev, u64 *size)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 2fa2445e9070..1b6e27475279 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -185,6 +185,9 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
int iommu_dma_get_rmrs(struct fwnode_handle *iommu_fwnode,
struct list_head *list)
{
+ if (!is_of_node(iommu_fwnode))
+ return iort_iommu_get_rmrs(iommu_fwnode, list);
+
return -EINVAL;
}
EXPORT_SYMBOL(iommu_dma_get_rmrs);
@@ -200,6 +203,7 @@ EXPORT_SYMBOL(iommu_dma_get_rmrs);
void iommu_dma_put_rmrs(struct fwnode_handle *iommu_fwnode,
struct list_head *list)
{
+ generic_iommu_put_resv_regions(iommu_fwnode->dev, list);
}
EXPORT_SYMBOL(iommu_dma_put_rmrs);

diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index f1f0842a2cb2..d8c030c103f5 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -38,6 +38,8 @@ int iort_dma_get_ranges(struct device *dev, u64 *size);
int iort_iommu_configure_id(struct device *dev, const u32 *id_in);
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
phys_addr_t acpi_iort_dma_get_max_cpu_address(void);
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+ struct list_head *list);
#else
static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_id(struct device *dev, u32 id)
@@ -57,6 +59,11 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)

static inline phys_addr_t acpi_iort_dma_get_max_cpu_address(void)
{ return PHYS_ADDR_MAX; }
+
+static inline
+int iort_iommu_get_rmrs(struct fwnode_handle *iommu_fwnode,
+ struct list_head *list)
+{ return -ENODEV; }
#endif

#endif /* __ACPI_IORT_H__ */
--
2.17.1