Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e279926 authored by Patrick Daly's avatar Patrick Daly
Browse files

arm64: dma-mapping: Allow drivers to use the upstream iova allocator



Add support for DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR. This allocator
supports dma_map_sg() with unaligned buffers.

Change-Id: I3b5fbe86cdbcb12137980b4ea63f4c665fa3e384
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 1748f086
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -1975,6 +1975,45 @@ static void bypass_iommu_release_mapping(struct kref *kref)
	kfree(mapping);
}

static int upstream_iommu_init_mapping(struct device *dev,
					struct dma_iommu_mapping *mapping)
{
	struct iommu_domain *domain = mapping->domain;
	struct iommu_group *group = dev->iommu_group;
	dma_addr_t base = mapping->base;
	u64 size = mapping->bits << PAGE_SHIFT;

	if (iommu_get_dma_cookie(domain))
		return -EINVAL;

	/* Need to attach to get geometry */
	if (iommu_attach_group(domain, group))
		goto out_put_cookie;

	if (iommu_dma_init_domain(domain, base, size, dev))
		goto out_detach_group;

	mapping->ops = &iommu_dma_ops;
	iommu_detach_group(domain, group);
	return 0;

out_detach_group:
	iommu_detach_group(domain, group);
out_put_cookie:
	iommu_put_dma_cookie(domain);
	return -EINVAL;
}

static void upstream_iommu_release_mapping(struct kref *kref)
{
	struct dma_iommu_mapping *mapping =
		container_of(kref, struct dma_iommu_mapping, kref);

	iommu_put_dma_cookie(mapping->domain);
	iommu_domain_free(mapping->domain);
	kfree(mapping);
}

/*
 * arm_iommu_release_mapping
 * @mapping: allocted via arm_iommu_create_mapping()
@@ -1984,7 +2023,7 @@ static void bypass_iommu_release_mapping(struct kref *kref)
 */
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
	int s1_bypass = 0, is_fast = 0;
	int s1_bypass = 0, is_fast = 0, is_upstream = 0;
	void (*release)(struct kref *kref);

	if (!mapping)
@@ -1999,11 +2038,16 @@ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
					&s1_bypass);
	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
	iommu_domain_get_attr(mapping->domain,
				DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
				&is_upstream);

	if (s1_bypass)
		release = bypass_iommu_release_mapping;
	else if (is_fast)
		release = fast_smmu_release_mapping;
	else if (is_upstream)
		release = upstream_iommu_release_mapping;
	else
		release = bitmap_iommu_release_mapping;

@@ -2015,7 +2059,7 @@ static int arm_iommu_init_mapping(struct device *dev,
			    struct dma_iommu_mapping *mapping)
{
	int err = -EINVAL;
	int s1_bypass = 0, is_fast = 0;
	int s1_bypass = 0, is_fast = 0, is_upstream = 0;
	struct iommu_group *group;
	dma_addr_t iova_end;

@@ -2045,12 +2089,17 @@ static int arm_iommu_init_mapping(struct device *dev,
	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
					&s1_bypass);
	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
	iommu_domain_get_attr(mapping->domain,
				DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
				&is_upstream);

	if (s1_bypass) {
		mapping->ops = &swiotlb_dma_ops;
		err = 0;
	} else if (is_fast) {
		err = fast_smmu_init_mapping(dev, mapping);
	} else if (is_upstream) {
		err = upstream_iommu_init_mapping(dev, mapping);
	} else {
		err = bitmap_iommu_init_mapping(dev, mapping);
	}
+11 −0
Original line number Diff line number Diff line
@@ -2766,6 +2766,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
					& (1 << DOMAIN_ATTR_FAST));
		ret = 0;
		break;
	case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
		*((int *)data) = !!(smmu_domain->attributes
			& (1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR));
		ret = 0;
		break;
	case DOMAIN_ATTR_USE_UPSTREAM_HINT:
		*((int *)data) = !!(smmu_domain->attributes &
				   (1 << DOMAIN_ATTR_USE_UPSTREAM_HINT));
@@ -2918,6 +2923,12 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
		}
		smmu_domain->secure_vmid = *((int *)data);
		break;
	case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
		if (*((int *)data))
			smmu_domain->attributes |=
				1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR;
		ret = 0;
		break;
	case DOMAIN_ATTR_FAST:
		if (*((int *)data))
			smmu_domain->attributes |= 1 << DOMAIN_ATTR_FAST;
+1 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ enum iommu_attr {
	DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
	DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
	DOMAIN_ATTR_CB_STALL_DISABLE,
	DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
	DOMAIN_ATTR_MAX,
};