Skip to content

Commit 0095bf8

Browse files
LuBaolujoergroedel
authored andcommitted
iommu: Improve iopf_queue_remove_device()
Convert iopf_queue_remove_device() to return void instead of an error code, as the return value is never used. This removal helper is designed to be never-failed, so there's no need for error handling. Ack all outstanding page requests from the device with the response code of IOMMU_PAGE_RESP_INVALID, indicating device should not attempt any retry. Add comments to this helper explaining the steps involved in removing a device from the iopf queue and disabling its PRI. The individual drivers are expected to be adjusted accordingly. Here we just define the expected behaviors of the individual iommu driver from the core's perspective. Suggested-by: Jason Gunthorpe <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Tested-by: Yan Zhao <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent a74c077 commit 0095bf8

File tree

3 files changed

+40
-29
lines changed

3 files changed

+40
-29
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4455,12 +4455,7 @@ static int intel_iommu_disable_iopf(struct device *dev)
44554455
*/
44564456
pci_disable_pri(to_pci_dev(dev));
44574457
info->pri_enabled = 0;
4458-
4459-
/*
4460-
* With PRI disabled and outstanding PRQs drained, removing device
4461-
* from iopf queue should never fail.
4462-
*/
4463-
WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev));
4458+
iopf_queue_remove_device(iommu->iopf_queue, dev);
44644459

44654460
return 0;
44664461
}

drivers/iommu/io-pgfault.c

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -448,50 +448,67 @@ EXPORT_SYMBOL_GPL(iopf_queue_add_device);
448448
* @queue: IOPF queue
449449
* @dev: device to remove
450450
*
451-
* Caller makes sure that no more faults are reported for this device.
451+
* Removing a device from an iopf_queue. It's recommended to follow these
452+
* steps when removing a device:
452453
*
453-
* Return: 0 on success and <0 on error.
454+
* - Disable new PRI reception: Turn off PRI generation in the IOMMU hardware
455+
* and flush any hardware page request queues. This should be done before
456+
* calling into this helper.
457+
* - Acknowledge all outstanding PRQs to the device: Respond to all outstanding
458+
* page requests with IOMMU_PAGE_RESP_INVALID, indicating the device should
459+
* not retry. This helper function handles this.
460+
* - Disable PRI on the device: After calling this helper, the caller could
461+
* then disable PRI on the device.
462+
*
463+
* Calling iopf_queue_remove_device() essentially disassociates the device.
464+
* The fault_param might still exist, but iommu_page_response() will do
465+
* nothing. The device fault parameter reference count has been properly
466+
* passed from iommu_report_device_fault() to the fault handling work, and
467+
* will eventually be released after iommu_page_response().
454468
*/
455-
int iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev)
469+
void iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev)
456470
{
457-
int ret = 0;
458471
struct iopf_fault *iopf, *next;
472+
struct iommu_page_response resp;
459473
struct dev_iommu *param = dev->iommu;
460474
struct iommu_fault_param *fault_param;
475+
const struct iommu_ops *ops = dev_iommu_ops(dev);
461476

462477
mutex_lock(&queue->lock);
463478
mutex_lock(&param->lock);
464479
fault_param = rcu_dereference_check(param->fault_param,
465480
lockdep_is_held(&param->lock));
466-
if (!fault_param) {
467-
ret = -ENODEV;
468-
goto unlock;
469-
}
470481

471-
if (fault_param->queue != queue) {
472-
ret = -EINVAL;
482+
if (WARN_ON(!fault_param || fault_param->queue != queue))
473483
goto unlock;
474-
}
475484

476-
if (!list_empty(&fault_param->faults)) {
477-
ret = -EBUSY;
478-
goto unlock;
479-
}
485+
mutex_lock(&fault_param->lock);
486+
list_for_each_entry_safe(iopf, next, &fault_param->partial, list)
487+
kfree(iopf);
480488

481-
list_del(&fault_param->queue_list);
489+
list_for_each_entry_safe(iopf, next, &fault_param->faults, list) {
490+
memset(&resp, 0, sizeof(struct iommu_page_response));
491+
resp.pasid = iopf->fault.prm.pasid;
492+
resp.grpid = iopf->fault.prm.grpid;
493+
resp.code = IOMMU_PAGE_RESP_INVALID;
482494

483-
/* Just in case some faults are still stuck */
484-
list_for_each_entry_safe(iopf, next, &fault_param->partial, list)
495+
if (iopf->fault.prm.flags & IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID)
496+
resp.flags = IOMMU_PAGE_RESP_PASID_VALID;
497+
498+
ops->page_response(dev, iopf, &resp);
499+
list_del(&iopf->list);
485500
kfree(iopf);
501+
}
502+
mutex_unlock(&fault_param->lock);
503+
504+
list_del(&fault_param->queue_list);
486505

487506
/* dec the ref owned by iopf_queue_add_device() */
488507
rcu_assign_pointer(param->fault_param, NULL);
489508
iopf_put_dev_fault_param(fault_param);
490509
unlock:
491510
mutex_unlock(&param->lock);
492511
mutex_unlock(&queue->lock);
493-
494-
return ret;
495512
}
496513
EXPORT_SYMBOL_GPL(iopf_queue_remove_device);
497514

include/linux/iommu.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,7 +1542,7 @@ iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm)
15421542

15431543
#ifdef CONFIG_IOMMU_IOPF
15441544
int iopf_queue_add_device(struct iopf_queue *queue, struct device *dev);
1545-
int iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev);
1545+
void iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev);
15461546
int iopf_queue_flush_dev(struct device *dev);
15471547
struct iopf_queue *iopf_queue_alloc(const char *name);
15481548
void iopf_queue_free(struct iopf_queue *queue);
@@ -1558,10 +1558,9 @@ iopf_queue_add_device(struct iopf_queue *queue, struct device *dev)
15581558
return -ENODEV;
15591559
}
15601560

1561-
static inline int
1561+
static inline void
15621562
iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev)
15631563
{
1564-
return -ENODEV;
15651564
}
15661565

15671566
static inline int iopf_queue_flush_dev(struct device *dev)

0 commit comments

Comments
 (0)