Skip to content

Commit 4debf77

Browse files
committed
Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd
Pull iommufd updates from Jason Gunthorpe: "On top of the vfio updates is built some new iommufd functionality: - IOMMU_HWPT_ALLOC allows userspace to directly create the low level IO Page table objects and affiliate them with IOAS objects that hold the translation mapping. This is the basic functionality for the normal IOMMU_DOMAIN_PAGING domains. - VFIO_DEVICE_ATTACH_IOMMUFD_PT can be used to replace the current translation. This is wired up to through all the layers down to the driver so the driver has the ability to implement a hitless replacement. This is necessary to fully support guest behaviors when emulating HW (eg guest atomic change of translation) - IOMMU_GET_HW_INFO returns information about the IOMMU driver HW that owns a VFIO device. This includes support for the Intel iommu, and patches have been posted for all the other server IOMMU. Along the way are a number of internal items: - New iommufd kernel APIs: iommufd_ctx_has_group(), iommufd_device_to_ictx(), iommufd_device_to_id(), iommufd_access_detach(), iommufd_ctx_from_fd(), iommufd_device_replace() - iommufd now internally tracks iommu_groups as it needs some per-group data - Reorganize how the internal hwpt allocation flows to have more robust locking - Improve the access interfaces to support detach and replace of an IOAS from an access - New selftests and a rework of how the selftests creates a mock iommu driver to be more like a real iommu driver" Link: https://lore.kernel.org/lkml/ZO%[email protected]/ * tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd: (34 commits) iommufd/selftest: Don't leak the platform device memory when unloading the module iommu/vt-d: Implement hw_info for iommu capability query iommufd/selftest: Add coverage for IOMMU_GET_HW_INFO ioctl iommufd: Add IOMMU_GET_HW_INFO iommu: Add new iommu op to get iommu hardware information iommu: Move dev_iommu_ops() to private header iommufd: Remove iommufd_ref_to_users() iommufd/selftest: Make the mock iommu driver into a real driver vfio: Support IO page table replacement iommufd/selftest: Add IOMMU_TEST_OP_ACCESS_REPLACE_IOAS coverage iommufd: Add iommufd_access_replace() API iommufd: Use iommufd_access_change_ioas in iommufd_access_destroy_object iommufd: Add iommufd_access_change_ioas(_id) helpers iommufd: Allow passing in iopt_access_list_id to iopt_remove_access() vfio: Do not allow !ops->dma_unmap in vfio_pin/unpin_pages() iommufd/selftest: Add a selftest for IOMMU_HWPT_ALLOC iommufd/selftest: Return the real idev id from selftest mock_domain iommufd: Add IOMMU_HWPT_ALLOC iommufd/selftest: Test iommufd_device_replace() iommufd: Make destroy_rwsem use a lock class per object type ...
2 parents ec0e2dc + eb501c2 commit 4debf77

File tree

19 files changed

+1486
-355
lines changed

19 files changed

+1486
-355
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/spinlock.h>
2323
#include <linux/syscore_ops.h>
2424
#include <linux/tboot.h>
25+
#include <uapi/linux/iommufd.h>
2526

2627
#include "iommu.h"
2728
#include "../dma-iommu.h"
@@ -4732,8 +4733,26 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
47324733
intel_pasid_tear_down_entry(iommu, dev, pasid, false);
47334734
}
47344735

4736+
static void *intel_iommu_hw_info(struct device *dev, u32 *length, u32 *type)
4737+
{
4738+
struct device_domain_info *info = dev_iommu_priv_get(dev);
4739+
struct intel_iommu *iommu = info->iommu;
4740+
struct iommu_hw_info_vtd *vtd;
4741+
4742+
vtd = kzalloc(sizeof(*vtd), GFP_KERNEL);
4743+
if (!vtd)
4744+
return ERR_PTR(-ENOMEM);
4745+
4746+
vtd->cap_reg = iommu->cap;
4747+
vtd->ecap_reg = iommu->ecap;
4748+
*length = sizeof(*vtd);
4749+
*type = IOMMU_HW_INFO_TYPE_INTEL_VTD;
4750+
return vtd;
4751+
}
4752+
47354753
const struct iommu_ops intel_iommu_ops = {
47364754
.capable = intel_iommu_capable,
4755+
.hw_info = intel_iommu_hw_info,
47374756
.domain_alloc = intel_iommu_domain_alloc,
47384757
.probe_device = intel_iommu_probe_device,
47394758
.probe_finalize = intel_iommu_probe_finalize,

drivers/iommu/iommu-priv.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
3+
*/
4+
#ifndef __LINUX_IOMMU_PRIV_H
5+
#define __LINUX_IOMMU_PRIV_H
6+
7+
#include <linux/iommu.h>
8+
9+
static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
10+
{
11+
/*
12+
* Assume that valid ops must be installed if iommu_probe_device()
13+
* has succeeded. The device ops are essentially for internal use
14+
* within the IOMMU subsystem itself, so we should be able to trust
15+
* ourselves not to misuse the helper.
16+
*/
17+
return dev->iommu->iommu_dev->ops;
18+
}
19+
20+
int iommu_group_replace_domain(struct iommu_group *group,
21+
struct iommu_domain *new_domain);
22+
23+
int iommu_device_register_bus(struct iommu_device *iommu,
24+
const struct iommu_ops *ops, struct bus_type *bus,
25+
struct notifier_block *nb);
26+
void iommu_device_unregister_bus(struct iommu_device *iommu,
27+
struct bus_type *bus,
28+
struct notifier_block *nb);
29+
30+
#endif /* __LINUX_IOMMU_PRIV_H */

drivers/iommu/iommu.c

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include <linux/msi.h>
3535

3636
#include "dma-iommu.h"
37+
#include "iommu-priv.h"
3738

3839
#include "iommu-sva.h"
40+
#include "iommu-priv.h"
3941

4042
static struct kset *iommu_group_kset;
4143
static DEFINE_IDA(iommu_group_ida);
@@ -287,6 +289,48 @@ void iommu_device_unregister(struct iommu_device *iommu)
287289
}
288290
EXPORT_SYMBOL_GPL(iommu_device_unregister);
289291

292+
#if IS_ENABLED(CONFIG_IOMMUFD_TEST)
293+
void iommu_device_unregister_bus(struct iommu_device *iommu,
294+
struct bus_type *bus,
295+
struct notifier_block *nb)
296+
{
297+
bus_unregister_notifier(bus, nb);
298+
iommu_device_unregister(iommu);
299+
}
300+
EXPORT_SYMBOL_GPL(iommu_device_unregister_bus);
301+
302+
/*
303+
* Register an iommu driver against a single bus. This is only used by iommufd
304+
* selftest to create a mock iommu driver. The caller must provide
305+
* some memory to hold a notifier_block.
306+
*/
307+
int iommu_device_register_bus(struct iommu_device *iommu,
308+
const struct iommu_ops *ops, struct bus_type *bus,
309+
struct notifier_block *nb)
310+
{
311+
int err;
312+
313+
iommu->ops = ops;
314+
nb->notifier_call = iommu_bus_notifier;
315+
err = bus_register_notifier(bus, nb);
316+
if (err)
317+
return err;
318+
319+
spin_lock(&iommu_device_lock);
320+
list_add_tail(&iommu->list, &iommu_device_list);
321+
spin_unlock(&iommu_device_lock);
322+
323+
bus->iommu_ops = ops;
324+
err = bus_iommu_probe(bus);
325+
if (err) {
326+
iommu_device_unregister_bus(iommu, bus, nb);
327+
return err;
328+
}
329+
return 0;
330+
}
331+
EXPORT_SYMBOL_GPL(iommu_device_register_bus);
332+
#endif
333+
290334
static struct dev_iommu *dev_iommu_get(struct device *dev)
291335
{
292336
struct dev_iommu *param = dev->iommu;
@@ -2114,6 +2158,32 @@ int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
21142158
}
21152159
EXPORT_SYMBOL_GPL(iommu_attach_group);
21162160

2161+
/**
2162+
* iommu_group_replace_domain - replace the domain that a group is attached to
2163+
* @new_domain: new IOMMU domain to replace with
2164+
* @group: IOMMU group that will be attached to the new domain
2165+
*
2166+
* This API allows the group to switch domains without being forced to go to
2167+
* the blocking domain in-between.
2168+
*
2169+
* If the currently attached domain is a core domain (e.g. a default_domain),
2170+
* it will act just like the iommu_attach_group().
2171+
*/
2172+
int iommu_group_replace_domain(struct iommu_group *group,
2173+
struct iommu_domain *new_domain)
2174+
{
2175+
int ret;
2176+
2177+
if (!new_domain)
2178+
return -EINVAL;
2179+
2180+
mutex_lock(&group->mutex);
2181+
ret = __iommu_group_set_domain(group, new_domain);
2182+
mutex_unlock(&group->mutex);
2183+
return ret;
2184+
}
2185+
EXPORT_SYMBOL_NS_GPL(iommu_group_replace_domain, IOMMUFD_INTERNAL);
2186+
21172187
static int __iommu_device_set_domain(struct iommu_group *group,
21182188
struct device *dev,
21192189
struct iommu_domain *new_domain,
@@ -2642,16 +2712,25 @@ int iommu_set_pgtable_quirks(struct iommu_domain *domain,
26422712
}
26432713
EXPORT_SYMBOL_GPL(iommu_set_pgtable_quirks);
26442714

2715+
/**
2716+
* iommu_get_resv_regions - get reserved regions
2717+
* @dev: device for which to get reserved regions
2718+
* @list: reserved region list for device
2719+
*
2720+
* This returns a list of reserved IOVA regions specific to this device.
2721+
* A domain user should not map IOVA in these ranges.
2722+
*/
26452723
void iommu_get_resv_regions(struct device *dev, struct list_head *list)
26462724
{
26472725
const struct iommu_ops *ops = dev_iommu_ops(dev);
26482726

26492727
if (ops->get_resv_regions)
26502728
ops->get_resv_regions(dev, list);
26512729
}
2730+
EXPORT_SYMBOL_GPL(iommu_get_resv_regions);
26522731

26532732
/**
2654-
* iommu_put_resv_regions - release resered regions
2733+
* iommu_put_resv_regions - release reserved regions
26552734
* @dev: device for which to free reserved regions
26562735
* @list: reserved region list for device
26572736
*

0 commit comments

Comments
 (0)