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 IOMMUshifive-unleashed-5.1
commit
f39c3f9b10
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{ 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue