arm: dma-mapping: Use default iommu domain

When a device probes and arch_setup_dma_ops is called, check if the
device has an associated default iommu_domain. If it does, setup
a virtual address allocator of the type described by the
default domain's attributes.

Mark arm_iommu_create_mapping and arm_iommu_attach_device as
deprecated, since clients will no longer need to use them now that
the iommu framework will associate them with a default domain.

Change-Id: I0721c038c68f0f48b78d50f9a72418dbaed97172
Signed-off-by: Vijayanand Jitta <vjitta@codeaurora.org>
Signed-off-by: Qingqing Zhou <qqzhou@codeaurora.org>
This commit is contained in:
Qingqing Zhou 2019-08-09 11:13:22 +05:30 • committed by Gerrit - the friendly Code Review server
commit b1cce515d1

View file

@ -2056,6 +2056,7 @@ const struct dma_map_ops iommu_coherent_ops = {
};
/**
* DEPRECATED
* arm_iommu_create_mapping
* @bus: pointer to the bus holding the client device (for IOMMU calls)
* @base: start address of the valid IO address space
@ -2158,6 +2159,9 @@ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
return 0;
}
/**
* DEPRECATED
*/
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
if (mapping)
@ -2182,6 +2186,7 @@ static int __arm_iommu_attach_device(struct device *dev,
}
/**
* DEPRECATED
* arm_iommu_attach_device
* @dev: valid struct device pointer
* @mapping: io address space mapping structure (returned from
@ -2209,6 +2214,7 @@ int arm_iommu_attach_device(struct device *dev,
EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
/**
* DEPRECATED
* arm_iommu_detach_device
* @dev: valid struct device pointer
*
@ -2239,42 +2245,162 @@ static const struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
return coherent ? &iommu_coherent_ops : &iommu_ops;
}
static void arm_iommu_dma_release_mapping(struct kref *kref)
{
int i;
struct dma_iommu_mapping *mapping =
container_of(kref, struct dma_iommu_mapping, kref);
for (i = 0; i < mapping->nr_bitmaps; i++)
kfree(mapping->bitmaps[i]);
kfree(mapping->bitmaps);
kfree(mapping);
}
struct dma_iommu_mapping *
arm_iommu_dma_init_mapping(dma_addr_t base, u64 size)
{
unsigned int bits = size >> PAGE_SHIFT;
unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
struct dma_iommu_mapping *mapping;
int extensions = 1;
int err = -ENOMEM;
/* currently only 32-bit DMA address space is supported */
if (size > DMA_BIT_MASK(32) + 1)
return ERR_PTR(-ERANGE);
if (!bitmap_size)
return ERR_PTR(-EINVAL);
if (bitmap_size > PAGE_SIZE) {
extensions = bitmap_size / PAGE_SIZE;
bitmap_size = PAGE_SIZE;
}
mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
if (!mapping)
goto err;
mapping->bitmap_size = bitmap_size;
mapping->bitmaps = kcalloc(extensions, sizeof(unsigned long *),
GFP_KERNEL);
if (!mapping->bitmaps)
goto err2;
mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL);
if (!mapping->bitmaps[0])
goto err3;
mapping->nr_bitmaps = 1;
mapping->extensions = extensions;
mapping->base = base;
mapping->bits = BITS_PER_BYTE * bitmap_size;
spin_lock_init(&mapping->lock);
kref_init(&mapping->kref);
return mapping;
err3:
kfree(mapping->bitmaps);
err2:
kfree(mapping);
err:
return ERR_PTR(err);
}
/*
* Checks for "qcom,iommu-dma-addr-pool" property.
* If not present, leaves dma_addr and dma_size unmodified.
*/
static void arm_iommu_get_dma_window(struct device *dev, u64 *dma_addr,
u64 *dma_size)
{
struct device_node *np;
int naddr, nsize, len;
const __be32 *ranges;
if (!dev->of_node)
return;
np = of_parse_phandle(dev->of_node, "qcom,iommu-group", 0);
if (!np)
np = dev->of_node;
ranges = of_get_property(np, "qcom,iommu-dma-addr-pool", &len);
if (!ranges)
return;
len /= sizeof(u32);
naddr = of_n_addr_cells(np);
nsize = of_n_size_cells(np);
if (len < naddr + nsize) {
dev_err(dev, "Invalid length for qcom,iommu-dma-addr-pool, expected %d cells\n",
naddr + nsize);
return;
}
if (naddr == 0 || nsize == 0) {
dev_err(dev, "Invalid #address-cells %d or #size-cells %d\n",
naddr, nsize);
return;
}
*dma_addr = of_read_number(ranges, naddr);
*dma_size = of_read_number(ranges + naddr, nsize);
}
static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu)
{
struct iommu_group *group;
struct iommu_domain *domain;
struct dma_iommu_mapping *mapping;
if (!iommu)
return false;
mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
group = dev->iommu_group;
if (!group)
return false;
domain = iommu_get_domain_for_dev(dev);
if (!domain)
return false;
arm_iommu_get_dma_window(dev, &dma_base, &size);
/* Allow iommu-debug to call arch_setup_dma_ops to reconfigure itself */
if (domain->type != IOMMU_DOMAIN_DMA &&
!of_device_is_compatible(dev->of_node, "iommu-debug-test")) {
dev_err(dev, "Invalid iommu domain type!\n");
return false;
}
mapping = arm_iommu_dma_init_mapping(dma_base, size);
if (IS_ERR(mapping)) {
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
pr_warn("Failed to initialize %llu-byte IOMMU mapping for device %s\n",
size, dev_name(dev));
return false;
}
if (__arm_iommu_attach_device(dev, mapping)) {
pr_warn("Failed to attached device %s to IOMMU_mapping\n",
dev_name(dev));
arm_iommu_release_mapping(mapping);
return false;
}
mapping->domain = domain;
kref_get(&mapping->kref);
to_dma_iommu_mapping(dev) = mapping;
return true;
}
static void arm_teardown_iommu_dma_ops(struct device *dev)
{
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
struct dma_iommu_mapping *mapping;
mapping = to_dma_iommu_mapping(dev);
if (!mapping)
return;
arm_iommu_detach_device(dev);
arm_iommu_release_mapping(mapping);
kref_put(&mapping->kref, arm_iommu_dma_release_mapping);
to_dma_iommu_mapping(dev) = NULL;
}
#else
static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,