1
0
Fork 0

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)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJZifGYAAoJEIKLOaai0TZ/QOMP/j7riN2CZrUZlJPMvoA40QEw
 HyVc5lPXxrs3cmsWSBbdCLGRwpY+Q5WdqzBGJ+OxhRqHHZGZPhjy//3O7+gMPmzv
 CswyN99IkeR2njLSTGh3Qv00RR4Fxa8a2ojjOVlsobre9PjMxbz190KhgHHmt1jJ
 RSPmxqAFo3PkoeChmyVqvPP9MNN1aP/yg+nujNTR+6rbppmHKyaqNum+8GjQVHwX
 SmmIUptvt4w4UTYk/PlyQUSFRSXWLbflsiXsyyfzPQs7jEmcVPbez4neAEh/pX4d
 8v7ybYiDzrKYSdhtz5HCIdpe9CxxSGwzos0dqiUnn/xdGQ3H5dj66SAHbZ7m5vxV
 096nkW2P/BOky+gc4bhq3bnQo0jLI03thb5sgB9st9j01M9RBoT7k4CA1Lc+YSAd
 NCu3W59WPIAhcnoRakOJsaHrWSYrFgQHqZJvqKKN5wRRbQR5XTilqgswKZgXB9ki
 CERz+W0tL1/n8FEOgA+Po7rgagwz8NMTSQdb6Gi29pkKyyjvOO8PewSQTOnwvXqc
 wDWfIC4rpJJIaivn/hpaSFIpJGb9jbXxiV3Zr8JcNGuLO4fuyZVwhFgB+9HEkqsj
 qSV1k+PqqdNhrEJvmDhEnVetWaw+4BYR7gqvtDGLedaJ149FgQcjHJ6Gmk8YWZza
 YFjfprBTrflxxAhV1dc1
 =alwx
 -----END PGP SIGNATURE-----

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
hifive-unleashed-5.1
Catalin Marinas 2017-08-09 15:39:09 +01:00
commit f39c3f9b10
1 changed files with 87 additions and 53 deletions

View File

@ -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;
}
@ -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);