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 int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
static struct vfio_ap_queue *vfio_ap_find_queue(int apqn); static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
static const struct vfio_device_ops vfio_ap_matrix_dev_ops; 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 * 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)" #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; int ret = -EBUSY, elapsed = 0;
struct ap_queue_status status; 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)); memcpy(&status, &q->reset_status, sizeof(status));
while (true) { while (true) {
msleep(AP_RESET_INTERVAL); msleep(AP_RESET_INTERVAL);
@ -1635,7 +1637,7 @@ static int apq_reset_check(struct vfio_ap_queue *q)
status = ap_tapq(q->apqn, NULL); status = ap_tapq(q->apqn, NULL);
ret = apq_status_check(q->apqn, &status); ret = apq_status_check(q->apqn, &status);
if (ret == -EIO) if (ret == -EIO)
return ret; return;
if (ret == -EBUSY) { if (ret == -EBUSY) {
pr_notice_ratelimited(WAIT_MSG, elapsed, pr_notice_ratelimited(WAIT_MSG, elapsed,
AP_QID_CARD(q->apqn), AP_QID_CARD(q->apqn),
@ -1663,34 +1665,32 @@ static int apq_reset_check(struct vfio_ap_queue *q)
break; 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; struct ap_queue_status status;
int ret = 0;
if (!q) if (!q)
return 0; return;
status = ap_zapq(q->apqn, 0); status = ap_zapq(q->apqn, 0);
memcpy(&q->reset_status, &status, sizeof(status)); memcpy(&q->reset_status, &status, sizeof(status));
switch (status.response_code) { switch (status.response_code) {
case AP_RESPONSE_NORMAL: case AP_RESPONSE_NORMAL:
case AP_RESPONSE_RESET_IN_PROGRESS: case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY: 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; break;
case AP_RESPONSE_DECONFIGURED: case AP_RESPONSE_DECONFIGURED:
/* /*
* When an AP adapter is deconfigured, the associated * When an AP adapter is deconfigured, the associated
* queues are reset, so let's set the status response code to 0 * 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 * so the queue may be passed through (i.e., not filtered).
* return a value indicating the reset completed successfully.
*/ */
q->reset_status.response_code = 0; q->reset_status.response_code = 0;
ret = 0;
vfio_ap_free_aqic_resources(q); vfio_ap_free_aqic_resources(q);
break; break;
default: 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", "PQAP/ZAPQ for %02x.%04x failed with invalid rc=%u\n",
AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn), AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
status.response_code); status.response_code);
return -EIO;
} }
return ret;
} }
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable) 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; 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) { hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
ret = vfio_ap_mdev_reset_queue(q); flush_work(&q->reset_work);
/*
* Regardless whether a queue turns out to be busy, or if (q->reset_status.response_code)
* is not operational, we need to continue resetting ret = -EIO;
* the remaining queues.
*/
if (ret)
rc = ret;
} }
return rc; return ret;
} }
static int vfio_ap_mdev_open_device(struct vfio_device *vdev) 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->apqn = to_ap_queue(&apdev->device)->qid;
q->saved_isc = VFIO_AP_ISC_INVALID; q->saved_isc = VFIO_AP_ISC_INVALID;
memset(&q->reset_status, 0, sizeof(q->reset_status)); 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); matrix_mdev = get_update_locks_by_apqn(q->apqn);
if (matrix_mdev) { if (matrix_mdev) {
@ -2094,6 +2091,7 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
} }
vfio_ap_mdev_reset_queue(q); vfio_ap_mdev_reset_queue(q);
flush_work(&q->reset_work);
dev_set_drvdata(&apdev->device, NULL); dev_set_drvdata(&apdev->device, NULL);
kfree(q); kfree(q);
release_update_locks_for_mdev(matrix_mdev); 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 * @saved_isc: the guest ISC registered with the GIB interface
* @mdev_qnode: allows the vfio_ap_queue struct to be added to a hashtable * @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_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 vfio_ap_queue {
struct ap_matrix_mdev *matrix_mdev; struct ap_matrix_mdev *matrix_mdev;
@ -143,6 +144,7 @@ struct vfio_ap_queue {
unsigned char saved_isc; unsigned char saved_isc;
struct hlist_node mdev_qnode; struct hlist_node mdev_qnode;
struct ap_queue_status reset_status; struct ap_queue_status reset_status;
struct work_struct reset_work;
}; };
int vfio_ap_mdev_register(void); int vfio_ap_mdev_register(void);