History

iommufd: Add IOMMU_HWPT_SET_DIRTY_TRACKING

Every IOMMU driver should be able to implement the needed iommu domain ops to control dirty tracking. Connect a hw_pagetable to the IOMMU core dirty tracking ops, specifically the ability to enable/disable dirty tracking on an IOMMU domain (hw_pagetable id). To that end add an io_pagetable kernel API to toggle dirty tracking: * iopt_set_dirty_tracking(iopt, [domain], state) The intended caller of this is via the hw_pagetable object that is created. Internally it will ensure the leftover dirty state is cleared /right before/ dirty tracking starts. This is also useful for iommu drivers which may decide that dirty tracking is always-enabled at boot without wanting to toggle dynamically via corresponding iommu domain op.

Joao Martins committed 3 years ago

Commit e2a4b291 parent 5f9bdbf5 files · +121 −0Browse files

Unified · Split

5 files
  1. drivers/iommu/iommufd/hw_pagetable.c +24 −0
  2. drivers/iommu/iommufd/io_pagetable.c +54 −0
  3. drivers/iommu/iommufd/iommufd_private.h +12 −0
  4. drivers/iommu/iommufd/main.c +3 −0
  5. include/uapi/linux/iommufd.h +28 −0
drivers/iommu/iommufd/hw_pagetable.c+24−0
@@ -196,3 +196,27 @@ out_put_idev: · 195 unmodified lines
196 iommufd_put_object(&idev->obj);196 iommufd_put_object(&idev->obj);
197 return rc;197 return rc;
198}198}
199
200int iommufd_hwpt_set_dirty_tracking(struct iommufd_ucmd *ucmd)
201{
202 struct iommu_hwpt_set_dirty_tracking *cmd = ucmd->cmd;
203 struct iommufd_hw_pagetable *hwpt;
204 struct iommufd_ioas *ioas;
205 int rc = -EOPNOTSUPP;
206 bool enable;
207
208 if (cmd->flags & ~IOMMU_HWPT_DIRTY_TRACKING_ENABLE)
209 return rc;
210
211 hwpt = iommufd_get_hwpt(ucmd, cmd->hwpt_id);
212 if (IS_ERR(hwpt))
213 return PTR_ERR(hwpt);
214
215 ioas = hwpt->ioas;
216 enable = cmd->flags & IOMMU_HWPT_DIRTY_TRACKING_ENABLE;
217
218 rc = iopt_set_dirty_tracking(&ioas->iopt, hwpt->domain, enable);
219
220 iommufd_put_object(&hwpt->obj);
221 return rc;
222}
drivers/iommu/iommufd/io_pagetable.c+54−0
@@ -412,6 +412,60 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt, · 411 unmodified lines
412 return 0;412 return 0;
413}413}
414 414
415static int iopt_clear_dirty_data(struct io_pagetable *iopt,
416 struct iommu_domain *domain)
417{
418 const struct iommu_dirty_ops *ops = domain->dirty_ops;
419 struct iommu_iotlb_gather gather;
420 struct iommu_dirty_bitmap dirty;
421 struct iopt_area *area;
422 int ret = 0;
423
424 lockdep_assert_held_read(&iopt->iova_rwsem);
425
426 iommu_dirty_bitmap_init(&dirty, NULL, &gather);
427
428 for (area = iopt_area_iter_first(iopt, 0, ULONG_MAX); area;
429 area = iopt_area_iter_next(area, 0, ULONG_MAX)) {
430 if (!area->pages)
431 continue;
432
433 ret = ops->read_and_clear_dirty(domain, iopt_area_iova(area),
434 iopt_area_length(area), 0,
435 &dirty);
436 if (ret)
437 break;
438 }
439
440 iommu_iotlb_sync(domain, &gather);
441 return ret;
442}
443
444int iopt_set_dirty_tracking(struct io_pagetable *iopt,
445 struct iommu_domain *domain, bool enable)
446{
447 const struct iommu_dirty_ops *ops = domain->dirty_ops;
448 int ret = 0;
449
450 if (!ops)
451 return -EOPNOTSUPP;
452
453 down_read(&iopt->iova_rwsem);
454
455 /* Clear dirty bits from PTEs to ensure a clean snapshot */
456 if (enable) {
457 ret = iopt_clear_dirty_data(iopt, domain);
458 if (ret)
459 goto out_unlock;
460 }
461
462 ret = ops->set_dirty_tracking(domain, enable);
463
464out_unlock:
465 up_read(&iopt->iova_rwsem);
466 return ret;
467}
468
415int iopt_get_pages(struct io_pagetable *iopt, unsigned long iova,469int iopt_get_pages(struct io_pagetable *iopt, unsigned long iova,
416 unsigned long length, struct list_head *pages_list)470 unsigned long length, struct list_head *pages_list)
417{471{
drivers/iommu/iommufd/iommufd_private.h+12−0
@@ -8,6 +8,7 @@ · 7 unmodified lines
8#include <linux/xarray.h>8#include <linux/xarray.h>
9#include <linux/refcount.h>9#include <linux/refcount.h>
10#include <linux/uaccess.h>10#include <linux/uaccess.h>
11#include <uapi/linux/iommufd.h>
11 12
12struct iommu_domain;13struct iommu_domain;
13struct iommu_group;14struct iommu_group;
@@ -70,6 +71,9 @@ int iopt_unmap_iova(struct io_pagetable *iopt, unsigned long iova, · 56 unmodified lines
70 unsigned long length, unsigned long *unmapped);71 unsigned long length, unsigned long *unmapped);
71int iopt_unmap_all(struct io_pagetable *iopt, unsigned long *unmapped);72int iopt_unmap_all(struct io_pagetable *iopt, unsigned long *unmapped);
72 73
74int iopt_set_dirty_tracking(struct io_pagetable *iopt,
75 struct iommu_domain *domain, bool enable);
76
73void iommufd_access_notify_unmap(struct io_pagetable *iopt, unsigned long iova,77void iommufd_access_notify_unmap(struct io_pagetable *iopt, unsigned long iova,
74 unsigned long length);78 unsigned long length);
75int iopt_table_add_domain(struct io_pagetable *iopt,79int iopt_table_add_domain(struct io_pagetable *iopt,
@@ -240,6 +244,14 @@ struct iommufd_hw_pagetable { · 164 unmodified lines
240 struct list_head hwpt_item;244 struct list_head hwpt_item;
241};245};
242 246
247static inline struct iommufd_hw_pagetable *
248iommufd_get_hwpt(struct iommufd_ucmd *ucmd, u32 id)
249{
250 return container_of(iommufd_get_object(ucmd->ictx, id,
251 IOMMUFD_OBJ_HW_PAGETABLE),
252 struct iommufd_hw_pagetable, obj);
253}
254int iommufd_hwpt_set_dirty_tracking(struct iommufd_ucmd *ucmd);
243struct iommufd_hw_pagetable *255struct iommufd_hw_pagetable *
244iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,256iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
245 struct iommufd_device *idev, u32 flags,257 struct iommufd_device *idev, u32 flags,
drivers/iommu/iommufd/main.c+3−0
@@ -307,6 +307,7 @@ union ucmd_buffer { · 306 unmodified lines
307 struct iommu_destroy destroy;307 struct iommu_destroy destroy;
308 struct iommu_hw_info info;308 struct iommu_hw_info info;
309 struct iommu_hwpt_alloc hwpt;309 struct iommu_hwpt_alloc hwpt;
310 struct iommu_hwpt_set_dirty_tracking set_dirty_tracking;
310 struct iommu_ioas_alloc alloc;311 struct iommu_ioas_alloc alloc;
311 struct iommu_ioas_allow_iovas allow_iovas;312 struct iommu_ioas_allow_iovas allow_iovas;
312 struct iommu_ioas_copy ioas_copy;313 struct iommu_ioas_copy ioas_copy;
@@ -342,6 +343,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { · 29 unmodified lines
342 __reserved),343 __reserved),
343 IOCTL_OP(IOMMU_HWPT_ALLOC, iommufd_hwpt_alloc, struct iommu_hwpt_alloc,344 IOCTL_OP(IOMMU_HWPT_ALLOC, iommufd_hwpt_alloc, struct iommu_hwpt_alloc,
344 __reserved),345 __reserved),
346 IOCTL_OP(IOMMU_HWPT_SET_DIRTY_TRACKING, iommufd_hwpt_set_dirty_tracking,
347 struct iommu_hwpt_set_dirty_tracking, __reserved),
345 IOCTL_OP(IOMMU_IOAS_ALLOC, iommufd_ioas_alloc_ioctl,348 IOCTL_OP(IOMMU_IOAS_ALLOC, iommufd_ioas_alloc_ioctl,
346 struct iommu_ioas_alloc, out_ioas_id),349 struct iommu_ioas_alloc, out_ioas_id),
347 IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas,350 IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas,
include/uapi/linux/iommufd.h+28−0
@@ -47,6 +47,7 @@ enum { · 46 unmodified lines
47 IOMMUFD_CMD_VFIO_IOAS,47 IOMMUFD_CMD_VFIO_IOAS,
48 IOMMUFD_CMD_HWPT_ALLOC,48 IOMMUFD_CMD_HWPT_ALLOC,
49 IOMMUFD_CMD_GET_HW_INFO,49 IOMMUFD_CMD_GET_HW_INFO,
50 IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING,
50};51};
51 52
52/**53/**
@@ -453,4 +454,31 @@ struct iommu_hw_info { · 400 unmodified lines
453 __u32 __reserved;454 __u32 __reserved;
454};455};
455#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO)456#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO)
457
458/*
459 * enum iommufd_hwpt_set_dirty_tracking_flags - Flags for steering dirty
460 * tracking
461 * @IOMMU_HWPT_DIRTY_TRACKING_ENABLE: Enable dirty tracking
462 */
463enum iommufd_hwpt_set_dirty_tracking_flags {
464 IOMMU_HWPT_DIRTY_TRACKING_ENABLE = 1,
465};
466
467/**
468 * struct iommu_hwpt_set_dirty_tracking - ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING)
469 * @size: sizeof(struct iommu_hwpt_set_dirty_tracking)
470 * @flags: Combination of enum iommufd_hwpt_set_dirty_tracking_flags
471 * @hwpt_id: HW pagetable ID that represents the IOMMU domain
472 * @__reserved: Must be 0
473 *
474 * Toggle dirty tracking on an HW pagetable.
475 */
476struct iommu_hwpt_set_dirty_tracking {
477 __u32 size;
478 __u32 flags;
479 __u32 hwpt_id;
480 __u32 __reserved;
481};
482#define IOMMU_HWPT_SET_DIRTY_TRACKING _IO(IOMMUFD_TYPE, \
483 IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING)
456#endif484#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t