s390/zcrypt: introduce new internal AP queue se_bound attribute
authorHarald Freudenberger <freude@linux.ibm.com>
Tue, 12 Sep 2023 08:08:51 +0000 (10:08 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 16 Oct 2023 11:04:09 +0000 (13:04 +0200)
This patch introduces a new AP queue internal attribute
se_bound which reflects the bound state of an APQN within
a Secure Execution environment.

With introduction of Secure Execution guests now an
AP firmware queue needs to be bound to the guest before
usage. This patch introduces a new internal attribute
reflecting this bound state and some glue code to handle
this new field during lifetime of an AP queue device.

Together with that now the zcrypt scheduler considers
the state of the AP queues when a message is about to be
distributed among the existing queues. There is a new
function ap_queue_usable() which returns true only when
all conditions for using this AP queue device are fulfilled.
In details this means: the AP queue needs to be configured,
not checkstopped and within an SE environment it needs
to be bound. So the new function gives and indication
if the AP queue device is ready to serve requests or not.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/zcrypt_api.c

index 3e34912a605066fee5956c527118923c3d2c5def..359a35f894d5189bc8ec2142a532a9d0b72684c7 100644 (file)
@@ -207,6 +207,7 @@ struct ap_queue {
        bool chkstop;                   /* checkstop state */
        ap_qid_t qid;                   /* AP queue id. */
        bool interrupt;                 /* indicate if interrupts are enabled */
+       bool se_bound;                  /* SE bound state */
        unsigned int assoc_idx;         /* SE association index */
        int queue_count;                /* # messages currently on AP queue. */
        int pendingq_count;             /* # requests on pendingq list. */
@@ -271,6 +272,7 @@ enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event);
 int ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg);
 void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg);
 void ap_flush_queue(struct ap_queue *aq);
+bool ap_queue_usable(struct ap_queue *aq);
 
 void *ap_airq_ptr(void);
 int ap_sb_available(void);
index 2943b2529d3a03bedee7be4f1eaa34f8d9ccc0e3..993240370ecf7c478639849d12716bb388b5815f 100644 (file)
@@ -33,6 +33,11 @@ static inline bool ap_q_supports_assoc(struct ap_queue *aq)
        return ap_test_bit(&aq->card->functions, AP_FUNC_EP11);
 }
 
+static inline bool ap_q_needs_bind(struct ap_queue *aq)
+{
+       return ap_q_supports_bind(aq) && ap_sb_available();
+}
+
 /**
  * ap_queue_enable_irq(): Enable interrupt support on this AP queue.
  * @aq: The AP queue
@@ -304,6 +309,7 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq)
                aq->sm_state = AP_SM_STATE_RESET_WAIT;
                aq->interrupt = false;
                aq->rapq_fbit = 0;
+               aq->se_bound = false;
                return AP_SM_WAIT_LOW_TIMEOUT;
        default:
                aq->dev_state = AP_DEV_STATE_ERROR;
@@ -868,7 +874,12 @@ static ssize_t se_bind_store(struct device *dev,
                }
                status = ap_bapq(aq->qid);
                spin_unlock_bh(&aq->lock);
-               if (status.response_code) {
+               if (!status.response_code) {
+                       aq->se_bound = true;
+                       AP_DBF_INFO("%s bapq(0x%02x.%04x) success\n", __func__,
+                                   AP_QID_CARD(aq->qid),
+                                   AP_QID_QUEUE(aq->qid));
+               } else {
                        AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n",
                                    __func__, status.response_code,
                                    AP_QID_CARD(aq->qid),
@@ -1073,6 +1084,42 @@ int ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg)
 }
 EXPORT_SYMBOL(ap_queue_message);
 
+/**
+ * ap_queue_usable(): Check if queue is usable just now.
+ * @aq: The AP queue device to test for usability.
+ * This function is intended for the scheduler to query if it makes
+ * sense to enqueue a message into this AP queue device by calling
+ * ap_queue_message(). The perspective is very short-term as the
+ * state machine and device state(s) may change at any time.
+ */
+bool ap_queue_usable(struct ap_queue *aq)
+{
+       bool rc = true;
+
+       spin_lock_bh(&aq->lock);
+
+       /* check for not configured or checkstopped */
+       if (!aq->config || aq->chkstop) {
+               rc = false;
+               goto unlock_and_out;
+       }
+
+       /* device state needs to be ok */
+       if (aq->dev_state != AP_DEV_STATE_OPERATING) {
+               rc = false;
+               goto unlock_and_out;
+       }
+
+       /* SE guest's queues additionally need to be bound */
+       if (ap_q_needs_bind(aq) && !aq->se_bound)
+               rc = false;
+
+unlock_and_out:
+       spin_unlock_bh(&aq->lock);
+       return rc;
+}
+EXPORT_SYMBOL(ap_queue_usable);
+
 /**
  * ap_cancel_message(): Cancel a crypto request.
  * @aq: The AP device that has the message queued
index ce04caa7913fb0bd4bf36c9abe81426823764859..dcd6c7299fa9aa381361b2a8c5cc1faa38c2c382 100644 (file)
@@ -693,7 +693,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
                for_each_zcrypt_queue(zq, zc) {
                        /* check if device is usable and eligible */
                        if (!zq->online || !zq->ops->rsa_modexpo ||
-                           !zq->queue->config || zq->queue->chkstop)
+                           !ap_queue_usable(zq->queue))
                                continue;
                        /* check if device node has admission for this queue */
                        if (!zcrypt_check_queue(perms,
@@ -798,7 +798,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
                for_each_zcrypt_queue(zq, zc) {
                        /* check if device is usable and eligible */
                        if (!zq->online || !zq->ops->rsa_modexpo_crt ||
-                           !zq->queue->config || zq->queue->chkstop)
+                           !ap_queue_usable(zq->queue))
                                continue;
                        /* check if device node has admission for this queue */
                        if (!zcrypt_check_queue(perms,
@@ -916,7 +916,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
                for_each_zcrypt_queue(zq, zc) {
                        /* check for device usable and eligible */
                        if (!zq->online || !zq->ops->send_cprb ||
-                           !zq->queue->config || zq->queue->chkstop ||
+                           !ap_queue_usable(zq->queue) ||
                            (tdom != AUTOSEL_DOM &&
                             tdom != AP_QID_QUEUE(zq->queue->qid)))
                                continue;
@@ -1087,7 +1087,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
                for_each_zcrypt_queue(zq, zc) {
                        /* check if device is usable and eligible */
                        if (!zq->online || !zq->ops->send_ep11_cprb ||
-                           !zq->queue->config || zq->queue->chkstop ||
+                           !ap_queue_usable(zq->queue) ||
                            (targets &&
                             !is_desired_ep11_queue(zq->queue->qid,
                                                    target_num, targets)))
@@ -1186,7 +1186,7 @@ static long zcrypt_rng(char *buffer)
                for_each_zcrypt_queue(zq, zc) {
                        /* check if device is usable and eligible */
                        if (!zq->online || !zq->ops->rng ||
-                           !zq->queue->config || zq->queue->chkstop)
+                           !ap_queue_usable(zq->queue))
                                continue;
                        if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt))
                                continue;