Commit f39c3f9b authored by Catalin Marinas's avatar Catalin Marinas

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
...@@ -588,7 +588,8 @@ void acpi_configure_pmsi_domain(struct device *dev) ...@@ -588,7 +588,8 @@ void acpi_configure_pmsi_domain(struct device *dev)
dev_set_msi_domain(dev, msi_domain); 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; u32 *rid = data;
...@@ -633,8 +634,7 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) ...@@ -633,8 +634,7 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev)
{ {
int err = 0; int err = 0;
if (!IS_ERR_OR_NULL(ops) && ops->add_device && dev->bus && if (ops->add_device && dev->bus && !dev->iommu_group)
!dev->iommu_group)
err = ops->add_device(dev); err = ops->add_device(dev);
return err; return err;
...@@ -648,36 +648,49 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) ...@@ -648,36 +648,49 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev)
{ return 0; } { return 0; }
#endif #endif
static const struct iommu_ops *iort_iommu_xlate(struct device *dev, static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
struct acpi_iort_node *node, u32 streamid)
u32 streamid)
{ {
const struct iommu_ops *ops = NULL; const struct iommu_ops *ops;
int ret = -ENODEV;
struct fwnode_handle *iort_fwnode; struct fwnode_handle *iort_fwnode;
if (node) { if (!node)
iort_fwnode = iort_get_fwnode(node); return -ENODEV;
if (!iort_fwnode)
return NULL;
ops = iommu_ops_from_fwnode(iort_fwnode); iort_fwnode = iort_get_fwnode(node);
/* if (!iort_fwnode)
* If the ops look-up fails, this means that either return -ENODEV;
* 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;
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) ...@@ -713,9 +726,9 @@ void iort_set_dma_mask(struct device *dev)
const struct iommu_ops *iort_iommu_configure(struct device *dev) const struct iommu_ops *iort_iommu_configure(struct device *dev)
{ {
struct acpi_iort_node *node, *parent; struct acpi_iort_node *node, *parent;
const struct iommu_ops *ops = NULL; const struct iommu_ops *ops;
u32 streamid = 0; u32 streamid = 0;
int err; int err = -ENODEV;
/* /*
* If we already translated the fwspec there * If we already translated the fwspec there
...@@ -727,21 +740,16 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) ...@@ -727,21 +740,16 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
if (dev_is_pci(dev)) { if (dev_is_pci(dev)) {
struct pci_bus *bus = to_pci_dev(dev)->bus; struct pci_bus *bus = to_pci_dev(dev)->bus;
u32 rid; struct iort_pci_alias_info info = { .dev = dev };
pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
&rid);
node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
iort_match_node_callback, &bus->dev); iort_match_node_callback, &bus->dev);
if (!node) if (!node)
return NULL; return NULL;
parent = iort_node_map_id(node, rid, &streamid, info.node = node;
IORT_IOMMU_TYPE); err = pci_for_each_dma_alias(to_pci_dev(dev),
iort_pci_iommu_init, &info);
ops = iort_iommu_xlate(dev, parent, streamid);
} else { } else {
int i = 0; int i = 0;
...@@ -750,31 +758,30 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) ...@@ -750,31 +758,30 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
if (!node) if (!node)
return NULL; return NULL;
parent = iort_node_map_platform_id(node, &streamid, do {
IORT_IOMMU_TYPE, i++);
while (parent) {
ops = iort_iommu_xlate(dev, parent, streamid);
if (IS_ERR_OR_NULL(ops))
return ops;
parent = iort_node_map_platform_id(node, &streamid, parent = iort_node_map_platform_id(node, &streamid,
IORT_IOMMU_TYPE, IORT_IOMMU_TYPE,
i++); 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 * If we have reason to believe the IOMMU driver missed the initial
* add_device callback for dev, replay it to get things in order. * add_device callback for dev, replay it to get things in order.
*/ */
err = iort_add_device_replay(ops, dev); if (!err) {
if (err) ops = dev->iommu_fwspec->ops;
ops = ERR_PTR(err); err = iort_add_device_replay(ops, dev);
}
/* Ignore all other errors apart from EPROBE_DEFER */ /* Ignore all other errors apart from EPROBE_DEFER */
if (IS_ERR(ops) && (PTR_ERR(ops) != -EPROBE_DEFER)) { if (err == -EPROBE_DEFER) {
dev_dbg(dev, "Adding to IOMMU failed: %ld\n", PTR_ERR(ops)); ops = ERR_PTR(err);
} else if (err) {
dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
ops = NULL; ops = NULL;
} }
...@@ -908,6 +915,27 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) ...@@ -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; 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) static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
{ {
struct acpi_iort_smmu *smmu; struct acpi_iort_smmu *smmu;
...@@ -977,13 +1005,16 @@ struct iort_iommu_config { ...@@ -977,13 +1005,16 @@ struct iort_iommu_config {
int (*iommu_count_resources)(struct acpi_iort_node *node); int (*iommu_count_resources)(struct acpi_iort_node *node);
void (*iommu_init_resources)(struct resource *res, void (*iommu_init_resources)(struct resource *res,
struct acpi_iort_node *node); 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 = { static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.name = "arm-smmu-v3", .name = "arm-smmu-v3",
.iommu_is_coherent = arm_smmu_v3_is_coherent, .iommu_is_coherent = arm_smmu_v3_is_coherent,
.iommu_count_resources = arm_smmu_v3_count_resources, .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 = { 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) ...@@ -1028,6 +1059,9 @@ static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
if (!pdev) if (!pdev)
return -ENOMEM; return -ENOMEM;
if (ops->iommu_set_proximity)
ops->iommu_set_proximity(&pdev->dev, node);
count = ops->iommu_count_resources(node); count = ops->iommu_count_resources(node);
r = kcalloc(count, sizeof(*r), GFP_KERNEL); r = kcalloc(count, sizeof(*r), GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment