aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorTony Krowiak <akrowiak@linux.ibm.com>2023-08-15 14:43:26 -0400
committerHeiko Carstens <hca@linux.ibm.com>2023-08-18 15:09:28 +0200
commitdd174833e44e7717f88f0925b1f78e9ba1d2626e (patch)
treebbd967e9783ba8611dcd20c886fd23271c5e87ca /drivers/s390
parentc51f8c6bb5c8a4878310d55e3a0b91747954b43d (diff)
downloadlinux-dd174833e44e7717f88f0925b1f78e9ba1d2626e.tar.gz
s390/vfio-ap: remove upper limit on wait for queue reset to complete
The architecture does not define an upper limit on how long a queue reset (RAPQ/ZAPQ) can take to complete. In order to ensure both the security requirements and prevent resource leakage and corruption in the hypervisor, it is necessary to remove the upper limit (200ms) the vfio_ap driver currently waits for a reset to complete. This, of course, may result in a hang which is a less than desirable user experience, but until a firmware solution is provided, this is a necessary evil. Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com> Acked-by: Halil Pasic <pasic@linux.ibm.com> Tested-by: Viktor Mihajlovski <mihajlov@linux.ibm.com> Link: https://lore.kernel.org/r/20230815184333.6554-6-akrowiak@linux.ibm.com Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index a489536c508aa..2517868aad563 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -30,7 +30,6 @@
#define AP_QUEUE_UNASSIGNED "unassigned"
#define AP_QUEUE_IN_USE "in use"
-#define MAX_RESET_CHECK_WAIT 200 /* Sleep max 200ms for reset check */
#define AP_RESET_INTERVAL 20 /* Reset sleep interval (20ms) */
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
@@ -1622,58 +1621,66 @@ 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)
{
- int ret;
- int iters = MAX_RESET_CHECK_WAIT / AP_RESET_INTERVAL;
+ int ret = -EBUSY, elapsed = 0;
struct ap_queue_status status;
- for (; iters > 0; iters--) {
+ while (true) {
msleep(AP_RESET_INTERVAL);
+ elapsed += AP_RESET_INTERVAL;
status = ap_tapq(q->apqn, NULL);
ret = apq_status_check(q->apqn, &status);
- if (ret != -EBUSY)
+ if (ret == -EIO)
return ret;
+ if (ret == -EBUSY) {
+ pr_notice_ratelimited(WAIT_MSG, elapsed,
+ AP_QID_CARD(q->apqn),
+ AP_QID_QUEUE(q->apqn),
+ status.response_code,
+ status.queue_empty,
+ status.irq_enabled);
+ } else {
+ if (q->reset_rc == AP_RESPONSE_RESET_IN_PROGRESS ||
+ q->reset_rc == AP_RESPONSE_BUSY) {
+ status = ap_zapq(q->apqn, 0);
+ q->reset_rc = status.response_code;
+ continue;
+ }
+ /*
+ * 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).
+ */
+ if (q->reset_rc == AP_RESPONSE_DECONFIGURED)
+ q->reset_rc = 0;
+ if (q->saved_isc != VFIO_AP_ISC_INVALID)
+ vfio_ap_free_aqic_resources(q);
+ break;
+ }
}
- WARN_ONCE(iters <= 0,
- "timeout verifying reset of queue %02x.%04x (%u, %u, %u)",
- AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
- status.queue_empty, status.irq_enabled, status.response_code);
return ret;
}
static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
{
struct ap_queue_status status;
- int ret;
+ int ret = 0;
if (!q)
return 0;
-retry_zapq:
status = ap_zapq(q->apqn, 0);
q->reset_rc = status.response_code;
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
- ret = 0;
- if (!status.irq_enabled)
- vfio_ap_free_aqic_resources(q);
- if (!status.queue_empty || status.irq_enabled) {
- ret = apq_reset_check(q);
- if (status.irq_enabled && ret == 0)
- vfio_ap_free_aqic_resources(q);
- }
- break;
case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY:
- /*
- * There is a reset issued by another process in progress. Let's wait
- * for that to complete. Since we have no idea whether it was a RAPQ or
- * ZAPQ, then if it completes successfully, let's issue the ZAPQ.
- */
+ /* Let's verify whether the ZAPQ completed successfully */
ret = apq_reset_check(q);
- if (ret)
- break;
- goto retry_zapq;
+ break;
case AP_RESPONSE_DECONFIGURED:
/*
* When an AP adapter is deconfigured, the associated
@@ -1682,7 +1689,6 @@ retry_zapq:
* return a value indicating the reset completed successfully.
*/
q->reset_rc = 0;
- ret = 0;
vfio_ap_free_aqic_resources(q);
break;
default: