| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES |
| */ |
| #include <linux/iommu.h> |
| |
| #include "iommufd_private.h" |
| |
| void iommufd_hw_pagetable_destroy(struct iommufd_object *obj) |
| { |
| struct iommufd_hw_pagetable *hwpt = |
| container_of(obj, struct iommufd_hw_pagetable, obj); |
| |
| WARN_ON(!list_empty(&hwpt->devices)); |
| |
| iommu_domain_free(hwpt->domain); |
| refcount_dec(&hwpt->ioas->obj.users); |
| mutex_destroy(&hwpt->devices_lock); |
| } |
| |
| /** |
| * iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device |
| * @ictx: iommufd context |
| * @ioas: IOAS to associate the domain with |
| * @dev: Device to get an iommu_domain for |
| * |
| * Allocate a new iommu_domain and return it as a hw_pagetable. |
| */ |
| struct iommufd_hw_pagetable * |
| iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas, |
| struct device *dev) |
| { |
| struct iommufd_hw_pagetable *hwpt; |
| int rc; |
| |
| hwpt = iommufd_object_alloc(ictx, hwpt, IOMMUFD_OBJ_HW_PAGETABLE); |
| if (IS_ERR(hwpt)) |
| return hwpt; |
| |
| hwpt->domain = iommu_domain_alloc(dev->bus); |
| if (!hwpt->domain) { |
| rc = -ENOMEM; |
| goto out_abort; |
| } |
| |
| INIT_LIST_HEAD(&hwpt->devices); |
| INIT_LIST_HEAD(&hwpt->hwpt_item); |
| mutex_init(&hwpt->devices_lock); |
| /* Pairs with iommufd_hw_pagetable_destroy() */ |
| refcount_inc(&ioas->obj.users); |
| hwpt->ioas = ioas; |
| return hwpt; |
| |
| out_abort: |
| iommufd_object_abort(ictx, &hwpt->obj); |
| return ERR_PTR(rc); |
| } |