mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
Merge branch 'iommu/fwspec-ops-removal' into iommu/next
* iommu/fwspec-ops-removal: iommu: Remove iommu_fwspec ops OF: Simplify of_iommu_configure() ACPI: Retire acpi_iommu_fwspec_ops() iommu: Resolve fwspec ops automatically iommu/mediatek-v1: Clean up redundant fwspec checks [will: Fixed conflict in drivers/iommu/tegra-smmu.c between fwspec ops removal and fwspec driver fix as per Robin and Jon]
This commit is contained in:
commit
342d3c1cbf
@ -1221,10 +1221,10 @@ static bool iort_pci_rc_supports_ats(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;
|
||||
struct fwnode_handle *iort_fwnode;
|
||||
|
||||
if (!node)
|
||||
/* If there's no SMMU driver at all, give up now */
|
||||
if (!node || !iort_iommu_driver_enabled(node->type))
|
||||
return -ENODEV;
|
||||
|
||||
iort_fwnode = iort_get_fwnode(node);
|
||||
@ -1232,19 +1232,10 @@ static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* 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 the SMMU drivers are enabled but not loaded/probed
|
||||
* yet, this will defer.
|
||||
*/
|
||||
ops = iommu_ops_from_fwnode(iort_fwnode);
|
||||
if (!ops)
|
||||
return iort_iommu_driver_enabled(node->type) ?
|
||||
-EPROBE_DEFER : -ENODEV;
|
||||
|
||||
return acpi_iommu_fwspec_init(dev, streamid, iort_fwnode, ops);
|
||||
return acpi_iommu_fwspec_init(dev, streamid, iort_fwnode);
|
||||
}
|
||||
|
||||
struct iort_pci_alias_info {
|
||||
|
@ -1577,38 +1577,25 @@ int acpi_dma_get_range(struct device *dev, const struct bus_dma_region **map)
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
int acpi_iommu_fwspec_init(struct device *dev, u32 id,
|
||||
struct fwnode_handle *fwnode,
|
||||
const struct iommu_ops *ops)
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iommu_fwspec_init(dev, fwnode, ops);
|
||||
ret = iommu_fwspec_init(dev, fwnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return iommu_fwspec_add_ids(dev, &id, 1);
|
||||
}
|
||||
|
||||
static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev)
|
||||
{
|
||||
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||||
|
||||
return fwspec ? fwspec->ops : NULL;
|
||||
}
|
||||
|
||||
static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
|
||||
{
|
||||
int err;
|
||||
const struct iommu_ops *ops;
|
||||
|
||||
/* Serialise to make dev->iommu stable under our potential fwspec */
|
||||
mutex_lock(&iommu_probe_device_lock);
|
||||
/*
|
||||
* If we already translated the fwspec there is nothing left to do,
|
||||
* return the iommu_ops.
|
||||
*/
|
||||
ops = acpi_iommu_fwspec_ops(dev);
|
||||
if (ops) {
|
||||
/* If we already translated the fwspec there is nothing left to do */
|
||||
if (dev_iommu_fwspec_get(dev)) {
|
||||
mutex_unlock(&iommu_probe_device_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -1625,22 +1612,13 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
|
||||
if (!err && dev->bus)
|
||||
err = iommu_probe_device(dev);
|
||||
|
||||
if (err == -EPROBE_DEFER)
|
||||
return err;
|
||||
if (err) {
|
||||
dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
if (!acpi_iommu_fwspec_ops(dev))
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IOMMU_API */
|
||||
|
||||
int acpi_iommu_fwspec_init(struct device *dev, u32 id,
|
||||
struct fwnode_handle *fwnode,
|
||||
const struct iommu_ops *ops)
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1674,6 +1652,8 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
|
||||
ret = acpi_iommu_configure_id(dev, input_id);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (ret)
|
||||
dev_dbg(dev, "Adding to IOMMU failed: %d\n", ret);
|
||||
|
||||
arch_setup_dma_ops(dev, attr == DEV_DMA_COHERENT);
|
||||
|
||||
|
@ -307,21 +307,14 @@ void __init acpi_viot_init(void)
|
||||
static int viot_dev_iommu_init(struct device *dev, struct viot_iommu *viommu,
|
||||
u32 epid)
|
||||
{
|
||||
const struct iommu_ops *ops;
|
||||
|
||||
if (!viommu)
|
||||
if (!viommu || !IS_ENABLED(CONFIG_VIRTIO_IOMMU))
|
||||
return -ENODEV;
|
||||
|
||||
/* We're not translating ourself */
|
||||
if (device_match_fwnode(dev, viommu->fwnode))
|
||||
return -EINVAL;
|
||||
|
||||
ops = iommu_ops_from_fwnode(viommu->fwnode);
|
||||
if (!ops)
|
||||
return IS_ENABLED(CONFIG_VIRTIO_IOMMU) ?
|
||||
-EPROBE_DEFER : -ENODEV;
|
||||
|
||||
return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode, ops);
|
||||
return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode);
|
||||
}
|
||||
|
||||
static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
|
||||
|
@ -178,8 +178,7 @@ static int arm_smmu_register_legacy_master(struct device *dev,
|
||||
it.cur_count = 1;
|
||||
}
|
||||
|
||||
err = iommu_fwspec_init(dev, &smmu_dev->of_node->fwnode,
|
||||
&arm_smmu_ops);
|
||||
err = iommu_fwspec_init(dev, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -17,6 +17,13 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
|
||||
return dev->iommu->iommu_dev->ops;
|
||||
}
|
||||
|
||||
const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode);
|
||||
|
||||
static inline const struct iommu_ops *iommu_fwspec_ops(struct iommu_fwspec *fwspec)
|
||||
{
|
||||
return iommu_ops_from_fwnode(fwspec ? fwspec->iommu_fwnode : NULL);
|
||||
}
|
||||
|
||||
int iommu_group_replace_domain(struct iommu_group *group,
|
||||
struct iommu_domain *new_domain);
|
||||
|
||||
|
@ -510,7 +510,6 @@ DEFINE_MUTEX(iommu_probe_device_lock);
|
||||
static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
|
||||
{
|
||||
const struct iommu_ops *ops;
|
||||
struct iommu_fwspec *fwspec;
|
||||
struct iommu_group *group;
|
||||
struct group_device *gdev;
|
||||
int ret;
|
||||
@ -523,12 +522,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
|
||||
* be present, and that any of their registered instances has suitable
|
||||
* ops for probing, and thus cheekily co-opt the same mechanism.
|
||||
*/
|
||||
fwspec = dev_iommu_fwspec_get(dev);
|
||||
if (fwspec && fwspec->ops)
|
||||
ops = fwspec->ops;
|
||||
else
|
||||
ops = iommu_ops_from_fwnode(NULL);
|
||||
|
||||
ops = iommu_fwspec_ops(dev_iommu_fwspec_get(dev));
|
||||
if (!ops)
|
||||
return -ENODEV;
|
||||
/*
|
||||
@ -2822,13 +2816,16 @@ const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode
|
||||
return ops;
|
||||
}
|
||||
|
||||
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
|
||||
const struct iommu_ops *ops)
|
||||
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode)
|
||||
{
|
||||
const struct iommu_ops *ops = iommu_ops_from_fwnode(iommu_fwnode);
|
||||
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||||
|
||||
if (!ops)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (fwspec)
|
||||
return ops == fwspec->ops ? 0 : -EINVAL;
|
||||
return ops == iommu_fwspec_ops(fwspec) ? 0 : -EINVAL;
|
||||
|
||||
if (!dev_iommu_get(dev))
|
||||
return -ENOMEM;
|
||||
@ -2838,9 +2835,8 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
|
||||
if (!fwspec)
|
||||
return -ENOMEM;
|
||||
|
||||
of_node_get(to_of_node(iommu_fwnode));
|
||||
fwnode_handle_get(iommu_fwnode);
|
||||
fwspec->iommu_fwnode = iommu_fwnode;
|
||||
fwspec->ops = ops;
|
||||
dev_iommu_fwspec_set(dev, fwspec);
|
||||
return 0;
|
||||
}
|
||||
|
@ -401,7 +401,6 @@ static const struct iommu_ops mtk_iommu_v1_ops;
|
||||
static int mtk_iommu_v1_create_mapping(struct device *dev,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||||
struct mtk_iommu_v1_data *data;
|
||||
struct platform_device *m4updev;
|
||||
struct dma_iommu_mapping *mtk_mapping;
|
||||
@ -413,14 +412,9 @@ static int mtk_iommu_v1_create_mapping(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!fwspec) {
|
||||
ret = iommu_fwspec_init(dev, &args->np->fwnode, &mtk_iommu_v1_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
fwspec = dev_iommu_fwspec_get(dev);
|
||||
} else if (dev_iommu_fwspec_get(dev)->ops != &mtk_iommu_v1_ops) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = iommu_fwspec_init(dev, of_fwnode_handle(args->np));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev_iommu_priv_get(dev)) {
|
||||
/* Get the m4u device */
|
||||
|
@ -17,30 +17,25 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fsl/mc.h>
|
||||
|
||||
#include "iommu-priv.h"
|
||||
|
||||
static int of_iommu_xlate(struct device *dev,
|
||||
struct of_phandle_args *iommu_spec)
|
||||
{
|
||||
const struct iommu_ops *ops;
|
||||
struct fwnode_handle *fwnode = &iommu_spec->np->fwnode;
|
||||
int ret;
|
||||
|
||||
ops = iommu_ops_from_fwnode(fwnode);
|
||||
if ((ops && !ops->of_xlate) ||
|
||||
!of_device_is_available(iommu_spec->np))
|
||||
if (!of_device_is_available(iommu_spec->np))
|
||||
return -ENODEV;
|
||||
|
||||
ret = iommu_fwspec_init(dev, fwnode, ops);
|
||||
ret = iommu_fwspec_init(dev, of_fwnode_handle(iommu_spec->np));
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return driver_deferred_probe_check_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* The otherwise-empty fwspec handily serves to indicate the specific
|
||||
* IOMMU device we're waiting for, which will be useful if we ever get
|
||||
* a proper probe-ordering dependency mechanism in future.
|
||||
*/
|
||||
if (!ops)
|
||||
return driver_deferred_probe_check_state(dev);
|
||||
|
||||
if (!try_module_get(ops->owner))
|
||||
ops = iommu_ops_from_fwnode(&iommu_spec->np->fwnode);
|
||||
if (!ops->of_xlate || !try_module_get(ops->owner))
|
||||
return -ENODEV;
|
||||
|
||||
ret = ops->of_xlate(dev, iommu_spec);
|
||||
@ -115,7 +110,6 @@ static int of_iommu_configure_device(struct device_node *master_np,
|
||||
int of_iommu_configure(struct device *dev, struct device_node *master_np,
|
||||
const u32 *id)
|
||||
{
|
||||
struct iommu_fwspec *fwspec;
|
||||
int err;
|
||||
|
||||
if (!master_np)
|
||||
@ -123,14 +117,9 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
|
||||
|
||||
/* Serialise to make dev->iommu stable under our potential fwspec */
|
||||
mutex_lock(&iommu_probe_device_lock);
|
||||
fwspec = dev_iommu_fwspec_get(dev);
|
||||
if (fwspec) {
|
||||
if (fwspec->ops) {
|
||||
mutex_unlock(&iommu_probe_device_lock);
|
||||
return 0;
|
||||
}
|
||||
/* In the deferred case, start again from scratch */
|
||||
iommu_fwspec_free(dev);
|
||||
if (dev_iommu_fwspec_get(dev)) {
|
||||
mutex_unlock(&iommu_probe_device_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -150,20 +139,17 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
|
||||
} else {
|
||||
err = of_iommu_configure_device(master_np, dev, id);
|
||||
}
|
||||
|
||||
if (err)
|
||||
iommu_fwspec_free(dev);
|
||||
mutex_unlock(&iommu_probe_device_lock);
|
||||
|
||||
if (err == -ENODEV || err == -EPROBE_DEFER)
|
||||
return err;
|
||||
if (err)
|
||||
goto err_log;
|
||||
if (!err && dev->bus)
|
||||
err = iommu_probe_device(dev);
|
||||
|
||||
err = iommu_probe_device(dev);
|
||||
if (err)
|
||||
goto err_log;
|
||||
return 0;
|
||||
if (err && err != -EPROBE_DEFER)
|
||||
dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
|
||||
|
||||
err_log:
|
||||
dev_dbg(dev, "Adding to IOMMU failed: %pe\n", ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -837,7 +837,7 @@ static int tegra_smmu_configure(struct tegra_smmu *smmu, struct device *dev,
|
||||
const struct iommu_ops *ops = smmu->iommu.ops;
|
||||
int err;
|
||||
|
||||
err = iommu_fwspec_init(dev, &smmu->dev->of_node->fwnode, ops);
|
||||
err = iommu_fwspec_init(dev, dev_fwnode(smmu->dev));
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to initialize fwspec: %d\n", err);
|
||||
return err;
|
||||
|
@ -96,8 +96,7 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
|
||||
const struct bus_dma_region *map = NULL;
|
||||
struct device_node *bus_np;
|
||||
u64 mask, end = 0;
|
||||
bool coherent;
|
||||
int iommu_ret;
|
||||
bool coherent, set_map = false;
|
||||
int ret;
|
||||
|
||||
if (np == dev->of_node)
|
||||
@ -118,6 +117,7 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
|
||||
} else {
|
||||
/* Determine the overall bounds of all DMA regions */
|
||||
end = dma_range_map_max(map);
|
||||
set_map = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -144,7 +144,7 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
|
||||
dev->coherent_dma_mask &= mask;
|
||||
*dev->dma_mask &= mask;
|
||||
/* ...but only set bus limit and range map if we found valid dma-ranges earlier */
|
||||
if (!ret) {
|
||||
if (set_map) {
|
||||
dev->bus_dma_limit = end;
|
||||
dev->dma_range_map = map;
|
||||
}
|
||||
@ -153,29 +153,21 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
|
||||
dev_dbg(dev, "device is%sdma coherent\n",
|
||||
coherent ? " " : " not ");
|
||||
|
||||
iommu_ret = of_iommu_configure(dev, np, id);
|
||||
if (iommu_ret == -EPROBE_DEFER) {
|
||||
ret = of_iommu_configure(dev, np, id);
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
/* Don't touch range map if it wasn't set from a valid dma-ranges */
|
||||
if (!ret)
|
||||
if (set_map)
|
||||
dev->dma_range_map = NULL;
|
||||
kfree(map);
|
||||
return -EPROBE_DEFER;
|
||||
} else if (iommu_ret == -ENODEV) {
|
||||
dev_dbg(dev, "device is not behind an iommu\n");
|
||||
} else if (iommu_ret) {
|
||||
dev_err(dev, "iommu configuration for device failed with %pe\n",
|
||||
ERR_PTR(iommu_ret));
|
||||
|
||||
/*
|
||||
* Historically this routine doesn't fail driver probing
|
||||
* due to errors in of_iommu_configure()
|
||||
*/
|
||||
} else
|
||||
dev_dbg(dev, "device is behind an iommu\n");
|
||||
}
|
||||
/* Take all other IOMMU errors to mean we'll just carry on without it */
|
||||
dev_dbg(dev, "device is%sbehind an iommu\n",
|
||||
!ret ? " " : " not ");
|
||||
|
||||
arch_setup_dma_ops(dev, coherent);
|
||||
|
||||
if (iommu_ret)
|
||||
if (ret)
|
||||
of_dma_set_restricted_buffer(dev, np);
|
||||
|
||||
return 0;
|
||||
|
@ -736,8 +736,7 @@ struct iommu_ops;
|
||||
bool acpi_dma_supported(const struct acpi_device *adev);
|
||||
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
|
||||
int acpi_iommu_fwspec_init(struct device *dev, u32 id,
|
||||
struct fwnode_handle *fwnode,
|
||||
const struct iommu_ops *ops);
|
||||
struct fwnode_handle *fwnode);
|
||||
int acpi_dma_get_range(struct device *dev, const struct bus_dma_region **map);
|
||||
int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
|
||||
const u32 *input_id);
|
||||
|
@ -968,7 +968,6 @@ extern struct iommu_group *generic_single_device_group(struct device *dev);
|
||||
|
||||
/**
|
||||
* struct iommu_fwspec - per-device IOMMU instance data
|
||||
* @ops: ops for this device's IOMMU
|
||||
* @iommu_fwnode: firmware handle for this device's IOMMU
|
||||
* @flags: IOMMU_FWSPEC_* flags
|
||||
* @num_ids: number of associated device IDs
|
||||
@ -979,7 +978,6 @@ extern struct iommu_group *generic_single_device_group(struct device *dev);
|
||||
* consumers.
|
||||
*/
|
||||
struct iommu_fwspec {
|
||||
const struct iommu_ops *ops;
|
||||
struct fwnode_handle *iommu_fwnode;
|
||||
u32 flags;
|
||||
unsigned int num_ids;
|
||||
@ -1005,11 +1003,9 @@ struct iommu_mm_data {
|
||||
struct list_head sva_handles;
|
||||
};
|
||||
|
||||
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
|
||||
const struct iommu_ops *ops);
|
||||
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode);
|
||||
void iommu_fwspec_free(struct device *dev);
|
||||
int iommu_fwspec_add_ids(struct device *dev, const u32 *ids, int num_ids);
|
||||
const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode);
|
||||
|
||||
static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
|
||||
{
|
||||
@ -1315,8 +1311,7 @@ static inline void iommu_device_unlink(struct device *dev, struct device *link)
|
||||
}
|
||||
|
||||
static inline int iommu_fwspec_init(struct device *dev,
|
||||
struct fwnode_handle *iommu_fwnode,
|
||||
const struct iommu_ops *ops)
|
||||
struct fwnode_handle *iommu_fwnode)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1331,12 +1326,6 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline
|
||||
const struct iommu_ops *iommu_ops_from_fwnode(const struct fwnode_handle *fwnode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user