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 	if (!list_empty(&hwpt->hwpt_item)) {
17 		mutex_lock(&hwpt->ioas->mutex);
18 		list_del(&hwpt->hwpt_item);
19 		mutex_unlock(&hwpt->ioas->mutex);
20 
21 		iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
22 	}
23 
24 	if (hwpt->domain)
25 		iommu_domain_free(hwpt->domain);
26 
27 	refcount_dec(&hwpt->ioas->obj.users);
28 	mutex_destroy(&hwpt->devices_lock);
29 }
30 
31 /**
32  * iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
33  * @ictx: iommufd context
34  * @ioas: IOAS to associate the domain with
35  * @idev: Device to get an iommu_domain for
36  * @immediate_attach: True if idev should be attached to the hwpt
37  *
38  * Allocate a new iommu_domain and return it as a hw_pagetable. The HWPT
39  * will be linked to the given ioas and upon return the underlying iommu_domain
40  * is fully popoulated.
41  */
42 struct iommufd_hw_pagetable *
43 iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
44 			   struct iommufd_device *idev, bool immediate_attach)
45 {
46 	struct iommufd_hw_pagetable *hwpt;
47 	int rc;
48 
49 	lockdep_assert_held(&ioas->mutex);
50 
51 	hwpt = iommufd_object_alloc(ictx, hwpt, IOMMUFD_OBJ_HW_PAGETABLE);
52 	if (IS_ERR(hwpt))
53 		return hwpt;
54 
55 	INIT_LIST_HEAD(&hwpt->devices);
56 	INIT_LIST_HEAD(&hwpt->hwpt_item);
57 	mutex_init(&hwpt->devices_lock);
58 	/* Pairs with iommufd_hw_pagetable_destroy() */
59 	refcount_inc(&ioas->obj.users);
60 	hwpt->ioas = ioas;
61 
62 	hwpt->domain = iommu_domain_alloc(idev->dev->bus);
63 	if (!hwpt->domain) {
64 		rc = -ENOMEM;
65 		goto out_abort;
66 	}
67 
68 	mutex_lock(&hwpt->devices_lock);
69 
70 	/*
71 	 * immediate_attach exists only to accommodate iommu drivers that cannot
72 	 * directly allocate a domain. These drivers do not finish creating the
73 	 * domain until attach is completed. Thus we must have this call
74 	 * sequence. Once those drivers are fixed this should be removed.
75 	 */
76 	if (immediate_attach) {
77 		rc = iommufd_hw_pagetable_attach(hwpt, idev);
78 		if (rc)
79 			goto out_unlock;
80 	}
81 
82 	rc = iopt_table_add_domain(&hwpt->ioas->iopt, hwpt->domain);
83 	if (rc)
84 		goto out_detach;
85 	list_add_tail(&hwpt->hwpt_item, &hwpt->ioas->hwpt_list);
86 
87 	if (immediate_attach) {
88 		/* See iommufd_device_do_attach() */
89 		refcount_inc(&hwpt->obj.users);
90 		idev->hwpt = hwpt;
91 		list_add(&idev->devices_item, &hwpt->devices);
92 	}
93 
94 	mutex_unlock(&hwpt->devices_lock);
95 	return hwpt;
96 
97 out_detach:
98 	if (immediate_attach)
99 		iommufd_hw_pagetable_detach(hwpt, idev);
100 out_unlock:
101 	mutex_unlock(&hwpt->devices_lock);
102 out_abort:
103 	iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
104 	return ERR_PTR(rc);
105 }
106