diff options
Diffstat (limited to 'drivers/acpi/arm64/iort.c')
-rw-r--r-- | drivers/acpi/arm64/iort.c | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a3215ee671c1..736783c67ea0 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -588,7 +588,8 @@ void acpi_configure_pmsi_domain(struct device *dev) dev_set_msi_domain(dev, msi_domain); } -static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) +static int __maybe_unused __get_pci_rid(struct pci_dev *pdev, u16 alias, + void *data) { u32 *rid = data; @@ -633,8 +634,7 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) { int err = 0; - if (!IS_ERR_OR_NULL(ops) && ops->add_device && dev->bus && - !dev->iommu_group) + if (ops->add_device && dev->bus && !dev->iommu_group) err = ops->add_device(dev); return err; @@ -648,36 +648,49 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) { return 0; } #endif -static const struct iommu_ops *iort_iommu_xlate(struct device *dev, - struct acpi_iort_node *node, - u32 streamid) +static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, + u32 streamid) { - const struct iommu_ops *ops = NULL; - int ret = -ENODEV; + const struct iommu_ops *ops; struct fwnode_handle *iort_fwnode; - if (node) { - iort_fwnode = iort_get_fwnode(node); - if (!iort_fwnode) - return NULL; + if (!node) + return -ENODEV; - ops = iommu_ops_from_fwnode(iort_fwnode); - /* - * If the ops look-up fails, this means that either - * the SMMU drivers have not been probed yet or that - * the SMMU drivers are not built in the kernel; - * Depending on whether the SMMU drivers are built-in - * in the kernel or not, defer the IOMMU configuration - * or just abort it. - */ - if (!ops) - return iort_iommu_driver_enabled(node->type) ? - ERR_PTR(-EPROBE_DEFER) : NULL; + iort_fwnode = iort_get_fwnode(node); + if (!iort_fwnode) + return -ENODEV; - ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops); - } + /* + * If the ops look-up fails, this means that either + * the SMMU drivers have not been probed yet or that + * the SMMU drivers are not built in the kernel; + * Depending on whether the SMMU drivers are built-in + * in the kernel or not, defer the IOMMU configuration + * or just abort it. + */ + ops = iommu_ops_from_fwnode(iort_fwnode); + if (!ops) + return iort_iommu_driver_enabled(node->type) ? + -EPROBE_DEFER : -ENODEV; - return ret ? NULL : ops; + return arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops); +} + +struct iort_pci_alias_info { + struct device *dev; + struct acpi_iort_node *node; +}; + +static int iort_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) +{ + struct iort_pci_alias_info *info = data; + struct acpi_iort_node *parent; + u32 streamid; + + parent = iort_node_map_id(info->node, alias, &streamid, + IORT_IOMMU_TYPE); + return iort_iommu_xlate(info->dev, parent, streamid); } /** @@ -713,9 +726,9 @@ void iort_set_dma_mask(struct device *dev) const struct iommu_ops *iort_iommu_configure(struct device *dev) { struct acpi_iort_node *node, *parent; - const struct iommu_ops *ops = NULL; + const struct iommu_ops *ops; u32 streamid = 0; - int err; + int err = -ENODEV; /* * If we already translated the fwspec there @@ -727,21 +740,16 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (dev_is_pci(dev)) { struct pci_bus *bus = to_pci_dev(dev)->bus; - u32 rid; - - pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid, - &rid); + struct iort_pci_alias_info info = { .dev = dev }; node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, iort_match_node_callback, &bus->dev); if (!node) return NULL; - parent = iort_node_map_id(node, rid, &streamid, - IORT_IOMMU_TYPE); - - ops = iort_iommu_xlate(dev, parent, streamid); - + info.node = node; + err = pci_for_each_dma_alias(to_pci_dev(dev), + iort_pci_iommu_init, &info); } else { int i = 0; @@ -750,31 +758,30 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (!node) return NULL; - parent = iort_node_map_platform_id(node, &streamid, - IORT_IOMMU_TYPE, i++); - - while (parent) { - ops = iort_iommu_xlate(dev, parent, streamid); - if (IS_ERR_OR_NULL(ops)) - return ops; - + do { parent = iort_node_map_platform_id(node, &streamid, IORT_IOMMU_TYPE, i++); - } + + if (parent) + err = iort_iommu_xlate(dev, parent, streamid); + } while (parent && !err); } /* * If we have reason to believe the IOMMU driver missed the initial * add_device callback for dev, replay it to get things in order. */ - err = iort_add_device_replay(ops, dev); - if (err) - ops = ERR_PTR(err); + if (!err) { + ops = iort_fwspec_iommu_ops(dev->iommu_fwspec); + err = iort_add_device_replay(ops, dev); + } /* Ignore all other errors apart from EPROBE_DEFER */ - if (IS_ERR(ops) && (PTR_ERR(ops) != -EPROBE_DEFER)) { - dev_dbg(dev, "Adding to IOMMU failed: %ld\n", PTR_ERR(ops)); + if (err == -EPROBE_DEFER) { + ops = ERR_PTR(err); + } else if (err) { + dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); ops = NULL; } @@ -908,6 +915,27 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE; } +#if defined(CONFIG_ACPI_NUMA) && defined(ACPI_IORT_SMMU_V3_PXM_VALID) +/* + * set numa proximity domain for smmuv3 device + */ +static void __init arm_smmu_v3_set_proximity(struct device *dev, + struct acpi_iort_node *node) +{ + struct acpi_iort_smmu_v3 *smmu; + + smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + if (smmu->flags & ACPI_IORT_SMMU_V3_PXM_VALID) { + set_dev_node(dev, acpi_map_pxm_to_node(smmu->pxm)); + pr_info("SMMU-v3[%llx] Mapped to Proximity domain %d\n", + smmu->base_address, + smmu->pxm); + } +} +#else +#define arm_smmu_v3_set_proximity NULL +#endif + static int __init arm_smmu_count_resources(struct acpi_iort_node *node) { struct acpi_iort_smmu *smmu; @@ -977,13 +1005,16 @@ struct iort_iommu_config { int (*iommu_count_resources)(struct acpi_iort_node *node); void (*iommu_init_resources)(struct resource *res, struct acpi_iort_node *node); + void (*iommu_set_proximity)(struct device *dev, + struct acpi_iort_node *node); }; static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = { .name = "arm-smmu-v3", .iommu_is_coherent = arm_smmu_v3_is_coherent, .iommu_count_resources = arm_smmu_v3_count_resources, - .iommu_init_resources = arm_smmu_v3_init_resources + .iommu_init_resources = arm_smmu_v3_init_resources, + .iommu_set_proximity = arm_smmu_v3_set_proximity, }; static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = { @@ -1028,6 +1059,9 @@ static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node) if (!pdev) return -ENOMEM; + if (ops->iommu_set_proximity) + ops->iommu_set_proximity(&pdev->dev, node); + count = ops->iommu_count_resources(node); r = kcalloc(count, sizeof(*r), GFP_KERNEL); |