When allocating a user iommufd_hw_pagetable, the user space is allowed to associate a fault object with the hw_pagetable by specifying the fault object ID in the page table allocation data and setting the IOMMU_HWPT_FAULT_ID_VALID flag bit. On a successful return of hwpt allocation, the user can retrieve and respond to page faults by reading and writing the file interface of the fault object. Once a fault object has been associated with a hwpt, the hwpt is iopf-capable, indicated by hwpt->fault is non NULL. Attaching, detaching, or replacing an iopf-capable hwpt to an RID or PASID will differ from those that are not iopf-capable.
Unified · Split
| @@ -414,3 +414,20 @@ out_abort: · 413 unmodified lines | |||
| 414 | 414 | ||
| 415 | return rc; | 415 | return rc; |
| 416 | } | 416 | } |
| 417 | |||
| 418 | int iommufd_fault_iopf_handler(struct iopf_group *group) | ||
| 419 | { | ||
| 420 | struct iommufd_hw_pagetable *hwpt; | ||
| 421 | struct iommufd_fault *fault; | ||
| 422 | |||
| 423 | hwpt = group->attach_handle->domain->fault_data; | ||
| 424 | fault = hwpt->fault; | ||
| 425 | |||
| 426 | mutex_lock(&fault->mutex); | ||
| 427 | list_add_tail(&group->node, &fault->deliver); | ||
| 428 | mutex_unlock(&fault->mutex); | ||
| 429 | |||
| 430 | wake_up_interruptible(&fault->wait_queue); | ||
| 431 | |||
| 432 | return 0; | ||
| 433 | } | ||
| @@ -8,6 +8,15 @@ · 7 unmodified lines | |||
| 8 | #include "../iommu-priv.h" | 8 | #include "../iommu-priv.h" |
| 9 | #include "iommufd_private.h" | 9 | #include "iommufd_private.h" |
| 10 | 10 | ||
| 11 | static void __iommufd_hwpt_destroy(struct iommufd_hw_pagetable *hwpt) | ||
| 12 | { | ||
| 13 | if (hwpt->domain) | ||
| 14 | iommu_domain_free(hwpt->domain); | ||
| 15 | |||
| 16 | if (hwpt->fault) | ||
| 17 | refcount_dec(&hwpt->fault->obj.users); | ||
| 18 | } | ||
| 19 | |||
| 11 | void iommufd_hwpt_paging_destroy(struct iommufd_object *obj) | 20 | void iommufd_hwpt_paging_destroy(struct iommufd_object *obj) |
| 12 | { | 21 | { |
| 13 | struct iommufd_hwpt_paging *hwpt_paging = | 22 | struct iommufd_hwpt_paging *hwpt_paging = |
| @@ -22,9 +31,7 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj) · 8 unmodified lines | |||
| 22 | hwpt_paging->common.domain); | 31 | hwpt_paging->common.domain); |
| 23 | } | 32 | } |
| 24 | 33 | ||
| 25 | if (hwpt_paging->common.domain) | 34 | __iommufd_hwpt_destroy(&hwpt_paging->common); |
| 26 | iommu_domain_free(hwpt_paging->common.domain); | ||
| 27 | |||
| 28 | refcount_dec(&hwpt_paging->ioas->obj.users); | 35 | refcount_dec(&hwpt_paging->ioas->obj.users); |
| 29 | } | 36 | } |
| 30 | 37 | ||
| @@ -49,9 +56,7 @@ void iommufd_hwpt_nested_destroy(struct iommufd_object *obj) · 18 unmodified lines | |||
| 49 | struct iommufd_hwpt_nested *hwpt_nested = | 56 | struct iommufd_hwpt_nested *hwpt_nested = |
| 50 | container_of(obj, struct iommufd_hwpt_nested, common.obj); | 57 | container_of(obj, struct iommufd_hwpt_nested, common.obj); |
| 51 | 58 | ||
| 52 | if (hwpt_nested->common.domain) | 59 | __iommufd_hwpt_destroy(&hwpt_nested->common); |
| 53 | iommu_domain_free(hwpt_nested->common.domain); | ||
| 54 | |||
| 55 | refcount_dec(&hwpt_nested->parent->common.obj.users); | 60 | refcount_dec(&hwpt_nested->parent->common.obj.users); |
| 56 | } | 61 | } |
| 57 | 62 | ||
| @@ -213,7 +218,8 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, · 155 unmodified lines | |||
| 213 | struct iommufd_hw_pagetable *hwpt; | 218 | struct iommufd_hw_pagetable *hwpt; |
| 214 | int rc; | 219 | int rc; |
| 215 | 220 | ||
| 216 | if (flags || !user_data->len || !ops->domain_alloc_user) | 221 | if ((flags & ~IOMMU_HWPT_FAULT_ID_VALID) || |
| 222 | !user_data->len || !ops->domain_alloc_user) | ||
| 217 | return ERR_PTR(-EOPNOTSUPP); | 223 | return ERR_PTR(-EOPNOTSUPP); |
| 218 | if (parent->auto_domain || !parent->nest_parent) | 224 | if (parent->auto_domain || !parent->nest_parent) |
| 219 | return ERR_PTR(-EINVAL); | 225 | return ERR_PTR(-EINVAL); |
| @@ -227,7 +233,8 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, · 7 unmodified lines | |||
| 227 | refcount_inc(&parent->common.obj.users); | 233 | refcount_inc(&parent->common.obj.users); |
| 228 | hwpt_nested->parent = parent; | 234 | hwpt_nested->parent = parent; |
| 229 | 235 | ||
| 230 | hwpt->domain = ops->domain_alloc_user(idev->dev, flags, | 236 | hwpt->domain = ops->domain_alloc_user(idev->dev, |
| 237 | flags & ~IOMMU_HWPT_FAULT_ID_VALID, | ||
| 231 | parent->common.domain, user_data); | 238 | parent->common.domain, user_data); |
| 232 | if (IS_ERR(hwpt->domain)) { | 239 | if (IS_ERR(hwpt->domain)) { |
| 233 | rc = PTR_ERR(hwpt->domain); | 240 | rc = PTR_ERR(hwpt->domain); |
| @@ -308,6 +315,21 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd) · 74 unmodified lines | |||
| 308 | goto out_put_pt; | 315 | goto out_put_pt; |
| 309 | } | 316 | } |
| 310 | 317 | ||
| 318 | if (cmd->flags & IOMMU_HWPT_FAULT_ID_VALID) { | ||
| 319 | struct iommufd_fault *fault; | ||
| 320 | |||
| 321 | fault = iommufd_get_fault(ucmd, cmd->fault_id); | ||
| 322 | if (IS_ERR(fault)) { | ||
| 323 | rc = PTR_ERR(fault); | ||
| 324 | goto out_hwpt; | ||
| 325 | } | ||
| 326 | hwpt->fault = fault; | ||
| 327 | hwpt->domain->iopf_handler = iommufd_fault_iopf_handler; | ||
| 328 | hwpt->domain->fault_data = hwpt; | ||
| 329 | refcount_inc(&fault->obj.users); | ||
| 330 | iommufd_put_object(ucmd->ictx, &fault->obj); | ||
| 331 | } | ||
| 332 | |||
| 311 | cmd->out_hwpt_id = hwpt->obj.id; | 333 | cmd->out_hwpt_id = hwpt->obj.id; |
| 312 | rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); | 334 | rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); |
| 313 | if (rc) | 335 | if (rc) |
| @@ -458,8 +458,17 @@ struct iommufd_attach_handle { · 457 unmodified lines | |||
| 458 | /* Convert an iommu attach handle to iommufd handle. */ | 458 | /* Convert an iommu attach handle to iommufd handle. */ |
| 459 | #define to_iommufd_handle(hdl) container_of(hdl, struct iommufd_attach_handle, handle) | 459 | #define to_iommufd_handle(hdl) container_of(hdl, struct iommufd_attach_handle, handle) |
| 460 | 460 | ||
| 461 | static inline struct iommufd_fault * | ||
| 462 | iommufd_get_fault(struct iommufd_ucmd *ucmd, u32 id) | ||
| 463 | { | ||
| 464 | return container_of(iommufd_get_object(ucmd->ictx, id, | ||
| 465 | IOMMUFD_OBJ_FAULT), | ||
| 466 | struct iommufd_fault, obj); | ||
| 467 | } | ||
| 468 | |||
| 461 | int iommufd_fault_alloc(struct iommufd_ucmd *ucmd); | 469 | int iommufd_fault_alloc(struct iommufd_ucmd *ucmd); |
| 462 | void iommufd_fault_destroy(struct iommufd_object *obj); | 470 | void iommufd_fault_destroy(struct iommufd_object *obj); |
| 471 | int iommufd_fault_iopf_handler(struct iopf_group *group); | ||
| 463 | 472 | ||
| 464 | int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt, | 473 | int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt, |
| 465 | struct iommufd_device *idev); | 474 | struct iommufd_device *idev); |
| @@ -357,10 +357,13 @@ struct iommu_vfio_ioas { · 356 unmodified lines | |||
| 357 | * the parent HWPT in a nesting configuration. | 357 | * the parent HWPT in a nesting configuration. |
| 358 | * @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is | 358 | * @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is |
| 359 | * enforced on device attachment | 359 | * enforced on device attachment |
| 360 | * @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is | ||
| 361 | * valid. | ||
| 360 | */ | 362 | */ |
| 361 | enum iommufd_hwpt_alloc_flags { | 363 | enum iommufd_hwpt_alloc_flags { |
| 362 | IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0, | 364 | IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0, |
| 363 | IOMMU_HWPT_ALLOC_DIRTY_TRACKING = 1 << 1, | 365 | IOMMU_HWPT_ALLOC_DIRTY_TRACKING = 1 << 1, |
| 366 | IOMMU_HWPT_FAULT_ID_VALID = 1 << 2, | ||
| 364 | }; | 367 | }; |
| 365 | 368 | ||
| 366 | /** | 369 | /** |
| @@ -412,6 +415,9 @@ enum iommu_hwpt_data_type { · 45 unmodified lines | |||
| 412 | * @data_type: One of enum iommu_hwpt_data_type | 415 | * @data_type: One of enum iommu_hwpt_data_type |
| 413 | * @data_len: Length of the type specific data | 416 | * @data_len: Length of the type specific data |
| 414 | * @data_uptr: User pointer to the type specific data | 417 | * @data_uptr: User pointer to the type specific data |
| 418 | * @fault_id: The ID of IOMMUFD_FAULT object. Valid only if flags field of | ||
| 419 | * IOMMU_HWPT_FAULT_ID_VALID is set. | ||
| 420 | * @__reserved2: Padding to 64-bit alignment. Must be 0. | ||
| 415 | * | 421 | * |
| 416 | * Explicitly allocate a hardware page table object. This is the same object | 422 | * Explicitly allocate a hardware page table object. This is the same object |
| 417 | * type that is returned by iommufd_device_attach() and represents the | 423 | * type that is returned by iommufd_device_attach() and represents the |
| @@ -442,6 +448,8 @@ struct iommu_hwpt_alloc { · 24 unmodified lines | |||
| 442 | __u32 data_type; | 448 | __u32 data_type; |
| 443 | __u32 data_len; | 449 | __u32 data_len; |
| 444 | __aligned_u64 data_uptr; | 450 | __aligned_u64 data_uptr; |
| 451 | __u32 fault_id; | ||
| 452 | __u32 __reserved2; | ||
| 445 | }; | 453 | }; |
| 446 | #define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) | 454 | #define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) |
| 447 | 455 | ||