s390/vfio-ap: use work struct to verify queue reset

Instead of waiting to verify that a queue is reset in the
vfio_ap_mdev_reset_queue function, let's use a wait queue to check the
the state of the reset. This way, when resetting all of the queues assigned
to a matrix mdev, we don't have to wait for each queue to be reset before
initiating a reset on the next queue to be reset.

Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com>
Suggested-by: Halil Pasic <pasic@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Tested-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Link: https://lore.kernel.org/r/20230815184333.6554-8-akrowiak@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
Tony Krowiak 2023-08-15 14:43:28 -04:00 committed by Heiko Carstens
parent 62aab082e9
commit 9261f04388
2 changed files with 25 additions and 25 deletions

View File

@ -35,7 +35,7 @@
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
static const struct vfio_device_ops vfio_ap_matrix_dev_ops;
static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
/**
* get_update_locks_for_kvm: Acquire the locks required to dynamically update a
@ -1623,11 +1623,13 @@ static int apq_status_check(int apqn, struct ap_queue_status *status)
#define WAIT_MSG "Waited %dms for reset of queue %02x.%04x (%u, %u, %u)"
static int apq_reset_check(struct vfio_ap_queue *q)
static void apq_reset_check(struct work_struct *reset_work)
{
int ret = -EBUSY, elapsed = 0;
struct ap_queue_status status;
struct vfio_ap_queue *q;
q = container_of(reset_work, struct vfio_ap_queue, reset_work);
memcpy(&status, &q->reset_status, sizeof(status));
while (true) {
msleep(AP_RESET_INTERVAL);
@ -1635,7 +1637,7 @@ static int apq_reset_check(struct vfio_ap_queue *q)
status = ap_tapq(q->apqn, NULL);
ret = apq_status_check(q->apqn, &status);
if (ret == -EIO)
return ret;
return;
if (ret == -EBUSY) {
pr_notice_ratelimited(WAIT_MSG, elapsed,
AP_QID_CARD(q->apqn),
@ -1663,34 +1665,32 @@ static int apq_reset_check(struct vfio_ap_queue *q)
break;
}
}
return ret;
}
static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
{
struct ap_queue_status status;
int ret = 0;
if (!q)
return 0;
return;
status = ap_zapq(q->apqn, 0);
memcpy(&q->reset_status, &status, sizeof(status));
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY:
/* Let's verify whether the ZAPQ completed successfully */
ret = apq_reset_check(q);
/*
* Let's verify whether the ZAPQ completed successfully on a work queue.
*/
queue_work(system_long_wq, &q->reset_work);
break;
case AP_RESPONSE_DECONFIGURED:
/*
* When an AP adapter is deconfigured, the associated
* queues are reset, so let's set the status response code to 0
* so the queue may be passed through (i.e., not filtered) and
* return a value indicating the reset completed successfully.
* so the queue may be passed through (i.e., not filtered).
*/
q->reset_status.response_code = 0;
ret = 0;
vfio_ap_free_aqic_resources(q);
break;
default:
@ -1698,29 +1698,25 @@ static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
"PQAP/ZAPQ for %02x.%04x failed with invalid rc=%u\n",
AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
status.response_code);
return -EIO;
}
return ret;
}
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable)
{
int ret, loop_cursor, rc = 0;
int ret = 0, loop_cursor;
struct vfio_ap_queue *q;
hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode)
vfio_ap_mdev_reset_queue(q);
hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
ret = vfio_ap_mdev_reset_queue(q);
/*
* Regardless whether a queue turns out to be busy, or
* is not operational, we need to continue resetting
* the remaining queues.
*/
if (ret)
rc = ret;
flush_work(&q->reset_work);
if (q->reset_status.response_code)
ret = -EIO;
}
return rc;
return ret;
}
static int vfio_ap_mdev_open_device(struct vfio_device *vdev)
@ -2045,6 +2041,7 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
q->apqn = to_ap_queue(&apdev->device)->qid;
q->saved_isc = VFIO_AP_ISC_INVALID;
memset(&q->reset_status, 0, sizeof(q->reset_status));
INIT_WORK(&q->reset_work, apq_reset_check);
matrix_mdev = get_update_locks_by_apqn(q->apqn);
if (matrix_mdev) {
@ -2094,6 +2091,7 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
}
vfio_ap_mdev_reset_queue(q);
flush_work(&q->reset_work);
dev_set_drvdata(&apdev->device, NULL);
kfree(q);
release_update_locks_for_mdev(matrix_mdev);

View File

@ -134,6 +134,7 @@ struct ap_matrix_mdev {
* @saved_isc: the guest ISC registered with the GIB interface
* @mdev_qnode: allows the vfio_ap_queue struct to be added to a hashtable
* @reset_status: the status from the last reset of the queue
* @reset_work: work to wait for queue reset to complete
*/
struct vfio_ap_queue {
struct ap_matrix_mdev *matrix_mdev;
@ -143,6 +144,7 @@ struct vfio_ap_queue {
unsigned char saved_isc;
struct hlist_node mdev_qnode;
struct ap_queue_status reset_status;
struct work_struct reset_work;
};
int vfio_ap_mdev_register(void);