162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Handle device page faults 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 ARM Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/iommu.h> 962306a36Sopenharmony_ci#include <linux/list.h> 1062306a36Sopenharmony_ci#include <linux/sched/mm.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/workqueue.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "iommu-sva.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * struct iopf_queue - IO Page Fault queue 1862306a36Sopenharmony_ci * @wq: the fault workqueue 1962306a36Sopenharmony_ci * @devices: devices attached to this queue 2062306a36Sopenharmony_ci * @lock: protects the device list 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_cistruct iopf_queue { 2362306a36Sopenharmony_ci struct workqueue_struct *wq; 2462306a36Sopenharmony_ci struct list_head devices; 2562306a36Sopenharmony_ci struct mutex lock; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * struct iopf_device_param - IO Page Fault data attached to a device 3062306a36Sopenharmony_ci * @dev: the device that owns this param 3162306a36Sopenharmony_ci * @queue: IOPF queue 3262306a36Sopenharmony_ci * @queue_list: index into queue->devices 3362306a36Sopenharmony_ci * @partial: faults that are part of a Page Request Group for which the last 3462306a36Sopenharmony_ci * request hasn't been submitted yet. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistruct iopf_device_param { 3762306a36Sopenharmony_ci struct device *dev; 3862306a36Sopenharmony_ci struct iopf_queue *queue; 3962306a36Sopenharmony_ci struct list_head queue_list; 4062306a36Sopenharmony_ci struct list_head partial; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct iopf_fault { 4462306a36Sopenharmony_ci struct iommu_fault fault; 4562306a36Sopenharmony_ci struct list_head list; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct iopf_group { 4962306a36Sopenharmony_ci struct iopf_fault last_fault; 5062306a36Sopenharmony_ci struct list_head faults; 5162306a36Sopenharmony_ci struct work_struct work; 5262306a36Sopenharmony_ci struct device *dev; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int iopf_complete_group(struct device *dev, struct iopf_fault *iopf, 5662306a36Sopenharmony_ci enum iommu_page_response_code status) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct iommu_page_response resp = { 5962306a36Sopenharmony_ci .version = IOMMU_PAGE_RESP_VERSION_1, 6062306a36Sopenharmony_ci .pasid = iopf->fault.prm.pasid, 6162306a36Sopenharmony_ci .grpid = iopf->fault.prm.grpid, 6262306a36Sopenharmony_ci .code = status, 6362306a36Sopenharmony_ci }; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if ((iopf->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID) && 6662306a36Sopenharmony_ci (iopf->fault.prm.flags & IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID)) 6762306a36Sopenharmony_ci resp.flags = IOMMU_PAGE_RESP_PASID_VALID; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return iommu_page_response(dev, &resp); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void iopf_handler(struct work_struct *work) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct iopf_group *group; 7562306a36Sopenharmony_ci struct iommu_domain *domain; 7662306a36Sopenharmony_ci struct iopf_fault *iopf, *next; 7762306a36Sopenharmony_ci enum iommu_page_response_code status = IOMMU_PAGE_RESP_SUCCESS; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci group = container_of(work, struct iopf_group, work); 8062306a36Sopenharmony_ci domain = iommu_get_domain_for_dev_pasid(group->dev, 8162306a36Sopenharmony_ci group->last_fault.fault.prm.pasid, 0); 8262306a36Sopenharmony_ci if (!domain || !domain->iopf_handler) 8362306a36Sopenharmony_ci status = IOMMU_PAGE_RESP_INVALID; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci list_for_each_entry_safe(iopf, next, &group->faults, list) { 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * For the moment, errors are sticky: don't handle subsequent 8862306a36Sopenharmony_ci * faults in the group if there is an error. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci if (status == IOMMU_PAGE_RESP_SUCCESS) 9162306a36Sopenharmony_ci status = domain->iopf_handler(&iopf->fault, 9262306a36Sopenharmony_ci domain->fault_data); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (!(iopf->fault.prm.flags & 9562306a36Sopenharmony_ci IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) 9662306a36Sopenharmony_ci kfree(iopf); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci iopf_complete_group(group->dev, &group->last_fault, status); 10062306a36Sopenharmony_ci kfree(group); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/** 10462306a36Sopenharmony_ci * iommu_queue_iopf - IO Page Fault handler 10562306a36Sopenharmony_ci * @fault: fault event 10662306a36Sopenharmony_ci * @cookie: struct device, passed to iommu_register_device_fault_handler. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * Add a fault to the device workqueue, to be handled by mm. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * This module doesn't handle PCI PASID Stop Marker; IOMMU drivers must discard 11162306a36Sopenharmony_ci * them before reporting faults. A PASID Stop Marker (LRW = 0b100) doesn't 11262306a36Sopenharmony_ci * expect a response. It may be generated when disabling a PASID (issuing a 11362306a36Sopenharmony_ci * PASID stop request) by some PCI devices. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * The PASID stop request is issued by the device driver before unbind(). Once 11662306a36Sopenharmony_ci * it completes, no page request is generated for this PASID anymore and 11762306a36Sopenharmony_ci * outstanding ones have been pushed to the IOMMU (as per PCIe 4.0r1.0 - 6.20.1 11862306a36Sopenharmony_ci * and 10.4.1.2 - Managing PASID TLP Prefix Usage). Some PCI devices will wait 11962306a36Sopenharmony_ci * for all outstanding page requests to come back with a response before 12062306a36Sopenharmony_ci * completing the PASID stop request. Others do not wait for page responses, and 12162306a36Sopenharmony_ci * instead issue this Stop Marker that tells us when the PASID can be 12262306a36Sopenharmony_ci * reallocated. 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * It is safe to discard the Stop Marker because it is an optimization. 12562306a36Sopenharmony_ci * a. Page requests, which are posted requests, have been flushed to the IOMMU 12662306a36Sopenharmony_ci * when the stop request completes. 12762306a36Sopenharmony_ci * b. The IOMMU driver flushes all fault queues on unbind() before freeing the 12862306a36Sopenharmony_ci * PASID. 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * So even though the Stop Marker might be issued by the device *after* the stop 13162306a36Sopenharmony_ci * request completes, outstanding faults will have been dealt with by the time 13262306a36Sopenharmony_ci * the PASID is freed. 13362306a36Sopenharmony_ci * 13462306a36Sopenharmony_ci * Any valid page fault will be eventually routed to an iommu domain and the 13562306a36Sopenharmony_ci * page fault handler installed there will get called. The users of this 13662306a36Sopenharmony_ci * handling framework should guarantee that the iommu domain could only be 13762306a36Sopenharmony_ci * freed after the device has stopped generating page faults (or the iommu 13862306a36Sopenharmony_ci * hardware has been set to block the page faults) and the pending page faults 13962306a36Sopenharmony_ci * have been flushed. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Return: 0 on success and <0 on error. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ciint iommu_queue_iopf(struct iommu_fault *fault, void *cookie) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci int ret; 14662306a36Sopenharmony_ci struct iopf_group *group; 14762306a36Sopenharmony_ci struct iopf_fault *iopf, *next; 14862306a36Sopenharmony_ci struct iopf_device_param *iopf_param; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci struct device *dev = cookie; 15162306a36Sopenharmony_ci struct dev_iommu *param = dev->iommu; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci lockdep_assert_held(¶m->lock); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (fault->type != IOMMU_FAULT_PAGE_REQ) 15662306a36Sopenharmony_ci /* Not a recoverable page fault */ 15762306a36Sopenharmony_ci return -EOPNOTSUPP; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * As long as we're holding param->lock, the queue can't be unlinked 16162306a36Sopenharmony_ci * from the device and therefore cannot disappear. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci iopf_param = param->iopf_param; 16462306a36Sopenharmony_ci if (!iopf_param) 16562306a36Sopenharmony_ci return -ENODEV; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!(fault->prm.flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) { 16862306a36Sopenharmony_ci iopf = kzalloc(sizeof(*iopf), GFP_KERNEL); 16962306a36Sopenharmony_ci if (!iopf) 17062306a36Sopenharmony_ci return -ENOMEM; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci iopf->fault = *fault; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Non-last request of a group. Postpone until the last one */ 17562306a36Sopenharmony_ci list_add(&iopf->list, &iopf_param->partial); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci group = kzalloc(sizeof(*group), GFP_KERNEL); 18162306a36Sopenharmony_ci if (!group) { 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * The caller will send a response to the hardware. But we do 18462306a36Sopenharmony_ci * need to clean up before leaving, otherwise partial faults 18562306a36Sopenharmony_ci * will be stuck. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci ret = -ENOMEM; 18862306a36Sopenharmony_ci goto cleanup_partial; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci group->dev = dev; 19262306a36Sopenharmony_ci group->last_fault.fault = *fault; 19362306a36Sopenharmony_ci INIT_LIST_HEAD(&group->faults); 19462306a36Sopenharmony_ci list_add(&group->last_fault.list, &group->faults); 19562306a36Sopenharmony_ci INIT_WORK(&group->work, iopf_handler); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* See if we have partial faults for this group */ 19862306a36Sopenharmony_ci list_for_each_entry_safe(iopf, next, &iopf_param->partial, list) { 19962306a36Sopenharmony_ci if (iopf->fault.prm.grpid == fault->prm.grpid) 20062306a36Sopenharmony_ci /* Insert *before* the last fault */ 20162306a36Sopenharmony_ci list_move(&iopf->list, &group->faults); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci queue_work(iopf_param->queue->wq, &group->work); 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cicleanup_partial: 20862306a36Sopenharmony_ci list_for_each_entry_safe(iopf, next, &iopf_param->partial, list) { 20962306a36Sopenharmony_ci if (iopf->fault.prm.grpid == fault->prm.grpid) { 21062306a36Sopenharmony_ci list_del(&iopf->list); 21162306a36Sopenharmony_ci kfree(iopf); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci return ret; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iommu_queue_iopf); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/** 21962306a36Sopenharmony_ci * iopf_queue_flush_dev - Ensure that all queued faults have been processed 22062306a36Sopenharmony_ci * @dev: the endpoint whose faults need to be flushed. 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * The IOMMU driver calls this before releasing a PASID, to ensure that all 22362306a36Sopenharmony_ci * pending faults for this PASID have been handled, and won't hit the address 22462306a36Sopenharmony_ci * space of the next process that uses this PASID. The driver must make sure 22562306a36Sopenharmony_ci * that no new fault is added to the queue. In particular it must flush its 22662306a36Sopenharmony_ci * low-level queue before calling this function. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Return: 0 on success and <0 on error. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ciint iopf_queue_flush_dev(struct device *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int ret = 0; 23362306a36Sopenharmony_ci struct iopf_device_param *iopf_param; 23462306a36Sopenharmony_ci struct dev_iommu *param = dev->iommu; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!param) 23762306a36Sopenharmony_ci return -ENODEV; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci mutex_lock(¶m->lock); 24062306a36Sopenharmony_ci iopf_param = param->iopf_param; 24162306a36Sopenharmony_ci if (iopf_param) 24262306a36Sopenharmony_ci flush_workqueue(iopf_param->queue->wq); 24362306a36Sopenharmony_ci else 24462306a36Sopenharmony_ci ret = -ENODEV; 24562306a36Sopenharmony_ci mutex_unlock(¶m->lock); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return ret; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_flush_dev); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * iopf_queue_discard_partial - Remove all pending partial fault 25362306a36Sopenharmony_ci * @queue: the queue whose partial faults need to be discarded 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * When the hardware queue overflows, last page faults in a group may have been 25662306a36Sopenharmony_ci * lost and the IOMMU driver calls this to discard all partial faults. The 25762306a36Sopenharmony_ci * driver shouldn't be adding new faults to this queue concurrently. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Return: 0 on success and <0 on error. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ciint iopf_queue_discard_partial(struct iopf_queue *queue) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct iopf_fault *iopf, *next; 26462306a36Sopenharmony_ci struct iopf_device_param *iopf_param; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!queue) 26762306a36Sopenharmony_ci return -EINVAL; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mutex_lock(&queue->lock); 27062306a36Sopenharmony_ci list_for_each_entry(iopf_param, &queue->devices, queue_list) { 27162306a36Sopenharmony_ci list_for_each_entry_safe(iopf, next, &iopf_param->partial, 27262306a36Sopenharmony_ci list) { 27362306a36Sopenharmony_ci list_del(&iopf->list); 27462306a36Sopenharmony_ci kfree(iopf); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci mutex_unlock(&queue->lock); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_discard_partial); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * iopf_queue_add_device - Add producer to the fault queue 28462306a36Sopenharmony_ci * @queue: IOPF queue 28562306a36Sopenharmony_ci * @dev: device to add 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * Return: 0 on success and <0 on error. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ciint iopf_queue_add_device(struct iopf_queue *queue, struct device *dev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci int ret = -EBUSY; 29262306a36Sopenharmony_ci struct iopf_device_param *iopf_param; 29362306a36Sopenharmony_ci struct dev_iommu *param = dev->iommu; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!param) 29662306a36Sopenharmony_ci return -ENODEV; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci iopf_param = kzalloc(sizeof(*iopf_param), GFP_KERNEL); 29962306a36Sopenharmony_ci if (!iopf_param) 30062306a36Sopenharmony_ci return -ENOMEM; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci INIT_LIST_HEAD(&iopf_param->partial); 30362306a36Sopenharmony_ci iopf_param->queue = queue; 30462306a36Sopenharmony_ci iopf_param->dev = dev; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci mutex_lock(&queue->lock); 30762306a36Sopenharmony_ci mutex_lock(¶m->lock); 30862306a36Sopenharmony_ci if (!param->iopf_param) { 30962306a36Sopenharmony_ci list_add(&iopf_param->queue_list, &queue->devices); 31062306a36Sopenharmony_ci param->iopf_param = iopf_param; 31162306a36Sopenharmony_ci ret = 0; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci mutex_unlock(¶m->lock); 31462306a36Sopenharmony_ci mutex_unlock(&queue->lock); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (ret) 31762306a36Sopenharmony_ci kfree(iopf_param); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_add_device); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * iopf_queue_remove_device - Remove producer from fault queue 32562306a36Sopenharmony_ci * @queue: IOPF queue 32662306a36Sopenharmony_ci * @dev: device to remove 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Caller makes sure that no more faults are reported for this device. 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * Return: 0 on success and <0 on error. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ciint iopf_queue_remove_device(struct iopf_queue *queue, struct device *dev) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci int ret = -EINVAL; 33562306a36Sopenharmony_ci struct iopf_fault *iopf, *next; 33662306a36Sopenharmony_ci struct iopf_device_param *iopf_param; 33762306a36Sopenharmony_ci struct dev_iommu *param = dev->iommu; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!param || !queue) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci mutex_lock(&queue->lock); 34362306a36Sopenharmony_ci mutex_lock(¶m->lock); 34462306a36Sopenharmony_ci iopf_param = param->iopf_param; 34562306a36Sopenharmony_ci if (iopf_param && iopf_param->queue == queue) { 34662306a36Sopenharmony_ci list_del(&iopf_param->queue_list); 34762306a36Sopenharmony_ci param->iopf_param = NULL; 34862306a36Sopenharmony_ci ret = 0; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci mutex_unlock(¶m->lock); 35162306a36Sopenharmony_ci mutex_unlock(&queue->lock); 35262306a36Sopenharmony_ci if (ret) 35362306a36Sopenharmony_ci return ret; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Just in case some faults are still stuck */ 35662306a36Sopenharmony_ci list_for_each_entry_safe(iopf, next, &iopf_param->partial, list) 35762306a36Sopenharmony_ci kfree(iopf); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci kfree(iopf_param); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_remove_device); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/** 36662306a36Sopenharmony_ci * iopf_queue_alloc - Allocate and initialize a fault queue 36762306a36Sopenharmony_ci * @name: a unique string identifying the queue (for workqueue) 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Return: the queue on success and NULL on error. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_cistruct iopf_queue *iopf_queue_alloc(const char *name) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct iopf_queue *queue; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 37662306a36Sopenharmony_ci if (!queue) 37762306a36Sopenharmony_ci return NULL; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* 38062306a36Sopenharmony_ci * The WQ is unordered because the low-level handler enqueues faults by 38162306a36Sopenharmony_ci * group. PRI requests within a group have to be ordered, but once 38262306a36Sopenharmony_ci * that's dealt with, the high-level function can handle groups out of 38362306a36Sopenharmony_ci * order. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci queue->wq = alloc_workqueue("iopf_queue/%s", WQ_UNBOUND, 0, name); 38662306a36Sopenharmony_ci if (!queue->wq) { 38762306a36Sopenharmony_ci kfree(queue); 38862306a36Sopenharmony_ci return NULL; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->devices); 39262306a36Sopenharmony_ci mutex_init(&queue->lock); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return queue; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_alloc); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci/** 39962306a36Sopenharmony_ci * iopf_queue_free - Free IOPF queue 40062306a36Sopenharmony_ci * @queue: queue to free 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * Counterpart to iopf_queue_alloc(). The driver must not be queuing faults or 40362306a36Sopenharmony_ci * adding/removing devices on this queue anymore. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_civoid iopf_queue_free(struct iopf_queue *queue) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct iopf_device_param *iopf_param, *next; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!queue) 41062306a36Sopenharmony_ci return; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci list_for_each_entry_safe(iopf_param, next, &queue->devices, queue_list) 41362306a36Sopenharmony_ci iopf_queue_remove_device(queue, iopf_param->dev); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci destroy_workqueue(queue->wq); 41662306a36Sopenharmony_ci kfree(queue); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(iopf_queue_free); 419