[PATCH 26/30] iommu/arm-smmu-v3: Move to iommu_fw_alloc_per_device_ids()
Jason Gunthorpe
jgg at nvidia.com
Wed Nov 29 17:10:33 PST 2023
SMMUv3 supports a single iommu instance with multiple ids.
It has a combined ACPI (via the IORT table) and OF probe path, add
iommu_iort_get_single_iommu() to respresent this.
It already has a per-instance structure, extend it with the ids[]
array and use iommu_fwb_alloc_per_device_ids() to populate it.
Convert the rest of the funcs from calling dev_iommu_fwspec_get() to using
the per-device data and remove all use of fwspec.
Directly call iort_iommu_get_resv_regions() and pass in the internal id
array instead of getting it from the fwspec.
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/acpi/arm64/iort.c | 2 -
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 74 +++++++++------------
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 4 ++
include/linux/iommu-driver.h | 2 +-
4 files changed, 35 insertions(+), 47 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b2d50cc9ac180..acd2e48590f37a 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1297,8 +1297,6 @@ static void iort_named_component_init(struct device *dev,
props[0] = PROPERTY_ENTRY_U32("pasid-num-bits",
FIELD_GET(ACPI_IORT_NC_PASID_BITS,
nc->node_flags));
- if (nc->node_flags & ACPI_IORT_NC_STALL_SUPPORTED)
- props[1] = PROPERTY_ENTRY_BOOL("dma-can-stall");
if (device_create_managed_software_node(dev, props, NULL))
dev_warn(dev, "Could not add device properties\n");
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 1855d3892b15f8..1a43c677e2feaf 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -26,9 +26,9 @@
#include <linux/pci.h>
#include <linux/pci-ats.h>
#include <linux/platform_device.h>
+#include <linux/iommu-driver.h>
#include "arm-smmu-v3.h"
-#include "../../dma-iommu.h"
#include "../../iommu-sva.h"
static bool disable_bypass = true;
@@ -2255,12 +2255,11 @@ static bool arm_smmu_ats_supported(struct arm_smmu_master *master)
{
struct device *dev = master->dev;
struct arm_smmu_device *smmu = master->smmu;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
if (!(smmu->features & ARM_SMMU_FEAT_ATS))
return false;
- if (!(fwspec->flags & IOMMU_FWSPEC_PCI_RC_ATS))
+ if (!master->pci_rc_ats)
return false;
return dev_is_pci(dev) && pci_ats_supported(to_pci_dev(dev));
@@ -2382,14 +2381,10 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret = 0;
unsigned long flags;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_master *master;
- if (!fwspec)
- return -ENOENT;
-
master = dev_iommu_priv_get(dev);
smmu = master->smmu;
@@ -2529,15 +2524,6 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
static struct platform_driver arm_smmu_driver;
-static
-struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
-{
- struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver,
- fwnode);
- put_device(dev);
- return dev ? dev_get_drvdata(dev) : NULL;
-}
-
static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
{
unsigned long limit = smmu->strtab_cfg.num_l1_ents;
@@ -2568,17 +2554,16 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
int ret = 0;
struct arm_smmu_stream *new_stream, *cur_stream;
struct rb_node **new_node, *parent_node = NULL;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
- master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
+ master->streams = kcalloc(master->num_ids, sizeof(*master->streams),
GFP_KERNEL);
if (!master->streams)
return -ENOMEM;
- master->num_streams = fwspec->num_ids;
+ master->num_streams = master->num_ids;
mutex_lock(&smmu->streams_mutex);
- for (i = 0; i < fwspec->num_ids; i++) {
- u32 sid = fwspec->ids[i];
+ for (i = 0; i < master->num_ids; i++) {
+ u32 sid = master->ids[i];
new_stream = &master->streams[i];
new_stream->id = sid;
@@ -2627,13 +2612,12 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
{
int i;
struct arm_smmu_device *smmu = master->smmu;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
if (!smmu || !master->streams)
return;
mutex_lock(&smmu->streams_mutex);
- for (i = 0; i < fwspec->num_ids; i++)
+ for (i = 0; i < master->num_ids; i++)
rb_erase(&master->streams[i].node, &smmu->streams);
mutex_unlock(&smmu->streams_mutex);
@@ -2642,26 +2626,27 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
static struct iommu_ops arm_smmu_ops;
-static struct iommu_device *arm_smmu_probe_device(struct device *dev)
+static struct iommu_device *arm_smmu_probe_device(struct iommu_probe_info *pinf)
{
int ret;
+ struct device *dev = pinf->dev;
struct arm_smmu_device *smmu;
struct arm_smmu_master *master;
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct iort_params params;
- if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
- return ERR_PTR(-EBUSY);
+ smmu = iommu_iort_get_single_iommu(pinf, &arm_smmu_ops, ¶ms,
+ struct arm_smmu_device, iommu);
+ if (IS_ERR(smmu))
+ return ERR_CAST(smmu);
- smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
- if (!smmu)
- return ERR_PTR(-ENODEV);
-
- master = kzalloc(sizeof(*master), GFP_KERNEL);
- if (!master)
- return ERR_PTR(-ENOMEM);
+ master = iommu_fw_alloc_per_device_ids(pinf, master);
+ if (IS_ERR(master))
+ return ERR_CAST(master);
master->dev = dev;
master->smmu = smmu;
+ master->pci_rc_ats = params.pci_rc_ats;
+ master->acpi_fwnode = iommu_fw_acpi_fwnode(pinf);
INIT_LIST_HEAD(&master->bonds);
dev_iommu_priv_set(dev, master);
@@ -2670,7 +2655,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
goto err_free_master;
device_property_read_u32(dev, "pasid-num-bits", &master->ssid_bits);
- master->ssid_bits = min(smmu->ssid_bits, master->ssid_bits);
+ master->ssid_bits = min(smmu->ssid_bits,
+ max(params.pasid_num_bits, master->ssid_bits));
/*
* Note that PASID must be enabled before, and disabled after ATS:
@@ -2687,7 +2673,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
CTXDESC_LINEAR_CDMAX);
if ((smmu->features & ARM_SMMU_FEAT_STALLS &&
- device_property_read_bool(dev, "dma-can-stall")) ||
+ (device_property_read_bool(dev, "dma-can-stall") ||
+ params.dma_can_stall)) ||
smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
master->stall_enabled = true;
@@ -2744,14 +2731,10 @@ static int arm_smmu_enable_nesting(struct iommu_domain *domain)
return ret;
}
-static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
-{
- return iommu_fwspec_add_ids(dev, args->args, 1);
-}
-
static void arm_smmu_get_resv_regions(struct device *dev,
struct list_head *head)
{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
struct iommu_resv_region *region;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
@@ -2762,7 +2745,10 @@ static void arm_smmu_get_resv_regions(struct device *dev,
list_add_tail(®ion->list, head);
- iommu_dma_get_resv_regions(dev, head);
+ if (master->acpi_fwnode)
+ iort_iommu_get_resv_regions(dev, head, master->acpi_fwnode,
+ master->ids, master->num_ids);
+ of_iommu_get_resv_regions(dev, head);
}
static int arm_smmu_dev_enable_feature(struct device *dev,
@@ -2851,10 +2837,10 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
- .probe_device = arm_smmu_probe_device,
+ .probe_device_pinf = arm_smmu_probe_device,
.release_device = arm_smmu_release_device,
.device_group = arm_smmu_device_group,
- .of_xlate = arm_smmu_of_xlate,
+ .of_xlate = iommu_dummy_of_xlate,
.get_resv_regions = arm_smmu_get_resv_regions,
.remove_dev_pasid = arm_smmu_remove_dev_pasid,
.dev_enable_feat = arm_smmu_dev_enable_feature,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 961205ba86d25d..ac293265b21a13 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -692,6 +692,7 @@ struct arm_smmu_stream {
struct arm_smmu_master {
struct arm_smmu_device *smmu;
struct device *dev;
+ struct fwnode_handle *acpi_fwnode;
struct arm_smmu_domain *domain;
struct list_head domain_head;
struct arm_smmu_stream *streams;
@@ -702,8 +703,11 @@ struct arm_smmu_master {
bool stall_enabled;
bool sva_enabled;
bool iopf_enabled;
+ bool pci_rc_ats;
struct list_head bonds;
unsigned int ssid_bits;
+ unsigned int num_ids;
+ u32 ids[] __counted_by(num_ids);
};
/* SMMU private data for an IOMMU domain */
diff --git a/include/linux/iommu-driver.h b/include/linux/iommu-driver.h
index c4e133cdef2c78..8f7089d3bb7135 100644
--- a/include/linux/iommu-driver.h
+++ b/include/linux/iommu-driver.h
@@ -252,6 +252,6 @@ __iommu_iort_get_single_iommu(struct iommu_probe_info *pinf,
pinf, ops, params), \
__iommu_of_get_single_iommu( \
pinf, ops, -1)), \
- drv_struct, member) \
+ drv_struct, member); \
})
#endif
--
2.42.0
More information about the Linux-mediatek
mailing list