1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
4  */
5 #include <linux/iommu.h>
6 
7 #include "iommufd_private.h"
8 
9 void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
10 {
11 	struct iommufd_hw_pagetable *hwpt =
12 		container_of(obj, struct iommufd_hw_pagetable, obj);
13 
14 	WARN_ON(!list_empty(&hwpt->devices));
15 
16 	iommu_domain_free(hwpt->domain);
17 	refcount_dec(&hwpt->ioas->obj.users);
18 	mutex_destroy(&hwpt->devices_lock);
19 }
20 
21 /**
22  * iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
23  * @ictx: iommufd context
24  * @ioas: IOAS to associate the domain with
25  * @dev: Device to get an iommu_domain for
26  *
27  * Allocate a new iommu_domain and return it as a hw_pagetable.
28  */
29 struct iommufd_hw_pagetable *
30 iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
31 			   struct device *dev)
32 {
33 	struct iommufd_hw_pagetable *hwpt;
34 	int rc;
35 
36 	hwpt = iommufd_object_alloc(ictx, hwpt, IOMMUFD_OBJ_HW_PAGETABLE);
37 	if (IS_ERR(hwpt))
38 		return hwpt;
39 
40 	hwpt->domain = iommu_domain_alloc(dev->bus);
41 	if (!hwpt->domain) {
42 		rc = -ENOMEM;
43 		goto out_abort;
44 	}
45 
46 	INIT_LIST_HEAD(&hwpt->devices);
47 	INIT_LIST_HEAD(&hwpt->hwpt_item);
48 	mutex_init(&hwpt->devices_lock);
49 	/* Pairs with iommufd_hw_pagetable_destroy() */
50 	refcount_inc(&ioas->obj.users);
51 	hwpt->ioas = ioas;
52 	return hwpt;
53 
54 out_abort:
55 	iommufd_object_abort(ictx, &hwpt->obj);
56 	return ERR_PTR(rc);
57 }
58