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 | 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 | 8 | #include "../iommu-priv.h" |
| 9 | 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 | 20 | void iommufd_hwpt_paging_destroy(struct iommufd_object *obj) |
| 12 | 21 | { |
| 13 | 22 | struct iommufd_hwpt_paging *hwpt_paging = |
| @@ -22,9 +31,7 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj) · 8 unmodified lines | ||
| 22 | 31 | hwpt_paging->common.domain); |
| 23 | 32 | } |
| 24 | 33 | |
| 25 | − if (hwpt_paging->common.domain) | |
| 26 | − iommu_domain_free(hwpt_paging->common.domain); | |
| 27 | − | |
| 34 | + __iommufd_hwpt_destroy(&hwpt_paging->common); | |
| 28 | 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 | 56 | struct iommufd_hwpt_nested *hwpt_nested = |
| 50 | 57 | container_of(obj, struct iommufd_hwpt_nested, common.obj); |
| 51 | 58 | |
| 52 | − if (hwpt_nested->common.domain) | |
| 53 | − iommu_domain_free(hwpt_nested->common.domain); | |
| 54 | − | |
| 59 | + __iommufd_hwpt_destroy(&hwpt_nested->common); | |
| 55 | 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 | 218 | struct iommufd_hw_pagetable *hwpt; |
| 214 | 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 | 223 | return ERR_PTR(-EOPNOTSUPP); |
| 218 | 224 | if (parent->auto_domain || !parent->nest_parent) |
| 219 | 225 | return ERR_PTR(-EINVAL); |
| @@ -227,7 +233,8 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, · 7 unmodified lines | ||
| 227 | 233 | refcount_inc(&parent->common.obj.users); |
| 228 | 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 | 238 | parent->common.domain, user_data); |
| 232 | 239 | if (IS_ERR(hwpt->domain)) { |
| 233 | 240 | rc = PTR_ERR(hwpt->domain); |
| @@ -308,6 +315,21 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd) · 74 unmodified lines | ||
| 308 | 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 | 333 | cmd->out_hwpt_id = hwpt->obj.id; |
| 312 | 334 | rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); |
| 313 | 335 | if (rc) |
| @@ -458,8 +458,17 @@ struct iommufd_attach_handle { · 457 unmodified lines | ||
| 458 | 458 | /* Convert an iommu attach handle to iommufd handle. */ |
| 459 | 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 | 469 | int iommufd_fault_alloc(struct iommufd_ucmd *ucmd); |
| 462 | 470 | void iommufd_fault_destroy(struct iommufd_object *obj); |
| 471 | +int iommufd_fault_iopf_handler(struct iopf_group *group); | |
| 463 | 472 | |
| 464 | 473 | int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt, |
| 465 | 474 | struct iommufd_device *idev); |
| @@ -357,10 +357,13 @@ struct iommu_vfio_ioas { · 356 unmodified lines | ||
| 357 | 357 | * the parent HWPT in a nesting configuration. |
| 358 | 358 | * @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is |
| 359 | 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 | 363 | enum iommufd_hwpt_alloc_flags { |
| 362 | 364 | IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0, |
| 363 | 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 | 415 | * @data_type: One of enum iommu_hwpt_data_type |
| 413 | 416 | * @data_len: Length of the type specific data |
| 414 | 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 | 422 | * Explicitly allocate a hardware page table object. This is the same object |
| 417 | 423 | * type that is returned by iommufd_device_attach() and represents the |
| @@ -442,6 +448,8 @@ struct iommu_hwpt_alloc { · 24 unmodified lines | ||
| 442 | 448 | __u32 data_type; |
| 443 | 449 | __u32 data_len; |
| 444 | 450 | __aligned_u64 data_uptr; |
| 451 | + __u32 fault_id; | |
| 452 | + __u32 __reserved2; | |
| 445 | 453 | }; |
| 446 | 454 | #define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) |
| 447 | 455 | |