summaryrefslogtreecommitdiff
path: root/gxp-domain-pool.c
blob: a0f9ead1b86f0b7d8ae0557908c2b87d0a3e062e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// SPDX-License-Identifier: GPL-2.0
/*
 * GXP IOMMU domain allocator.
 *
 * Copyright (C) 2022 Google LLC
 */

#include <linux/iommu.h>
#include <linux/slab.h>

#include <gcip/gcip-domain-pool.h>

#include "gxp-dma.h"
#include "gxp-domain-pool.h"

int gxp_domain_pool_init(struct gxp_dev *gxp, struct gcip_domain_pool *pool,
			 unsigned int size)
{
	int ret = gcip_domain_pool_init(gxp->dev, pool, size);
	__maybe_unused int i;

	if (ret)
		return ret;

#if IS_ENABLED(CONFIG_GXP_GEM5)
	for (i = 0; i < size; i++) {
		struct iommu_domain *domain = pool->array[i];

		/*
		 * Gem5 uses arm-smmu-v3 which requires domain finalization to do iommu map. Calling
		 * iommu_aux_attach_device to finalize the allocated domain and detach the device
		 * right after that.
		 */
		ret = iommu_aux_attach_device(domain, gxp->dev);
		if (ret) {
			dev_err(gxp->dev,
				"Failed to attach device to iommu domain %d of %u, ret=%d\n",
				i + 1, size, ret);
			gxp_domain_pool_destroy(pool);
			return ret;
		}

		iommu_aux_detach_device(domain, gxp->dev);
	}
#endif /* CONFIG_GXP_GEM5 */

	return 0;
}

struct gxp_iommu_domain *gxp_domain_pool_alloc(struct gcip_domain_pool *pool)
{
	struct iommu_domain *domain = gcip_domain_pool_alloc(pool);
	struct gxp_iommu_domain *gdomain;

	if (!domain)
		return NULL;

	gdomain = kmalloc(sizeof(*gdomain), GFP_KERNEL);
	if (!gdomain) {
		gcip_domain_pool_free(pool, domain);
		return NULL;
	}

	gdomain->domain = domain;

	return gdomain;
}

void gxp_domain_pool_free(struct gcip_domain_pool *pool,
			  struct gxp_iommu_domain *gdomain)
{
	gcip_domain_pool_free(pool, gdomain->domain);
	kfree(gdomain);
}

void gxp_domain_pool_destroy(struct gcip_domain_pool *pool)
{
	gcip_domain_pool_destroy(pool);
}