Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f39c3f9b authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge tag 'arm64-iort-for-v4.14' of...

Merge tag 'arm64-iort-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux into for-next/core

Two patches for the 4.14 release merge window:

- IORT PCI aliases detection improvement to cater for systems with
  complex PCI topologies that current code mishandles (R.Murphy)
- IORT SMMUv3 proximity domain (ie NUMA) handling (respective ACPICA
  changes will be merged separately) (G. Kulkarni)

* tag 'arm64-iort-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux:
  ACPI/IORT: numa: Add numa node mapping for smmuv3 devices
  ACPI/IORT: Handle PCI aliases properly for IOMMUs
parents 05538967 5fe0ce3b
Loading
Loading
Loading
Loading
+87 −53
Original line number Diff line number Diff line
@@ -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,20 +648,19 @@ 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,
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) {
	if (!node)
		return -ENODEV;

	iort_fwnode = iort_get_fwnode(node);
	if (!iort_fwnode)
			return NULL;
		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
@@ -670,14 +669,28 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
	 * 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) ?
			       ERR_PTR(-EPROBE_DEFER) : NULL;
		       -EPROBE_DEFER : -ENODEV;

		ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
	return arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
}

	return ret ? NULL : 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.
	 */
	if (!err) {
		ops = dev->iommu_fwspec->ops;
		err = iort_add_device_replay(ops, dev);
	if (err)
		ops = ERR_PTR(err);
	}

	/* 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);