diff options
Diffstat (limited to 'drivers/acpi/arm64')
-rw-r--r-- | drivers/acpi/arm64/iort.c | 111 |
1 files changed, 59 insertions, 52 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a3215ee671c1..919f8d84b0ef 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 = dev->iommu_fwspec->ops; + 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; } |