]> git.baikalelectronics.ru Git - kernel.git/commitdiff
s390/ap/zcrypt: notify userspace with online, config and mode info
authorHarald Freudenberger <freude@linux.ibm.com>
Tue, 13 Apr 2021 16:11:09 +0000 (18:11 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Wed, 16 Jun 2021 21:46:18 +0000 (23:46 +0200)
This patch brings 3 reworked/new uevent changes:
* All AP uevents caused by an ap card or queue device now carry an
  additional uevent env value MODE=<accel|cca|ep11>. Here is an
  example:
    KERNEL[1267.301292] add  /devices/ap/card0a (ap)
    ACTION=add
    DEVPATH=/devices/ap/card0a
    SUBSYSTEM=ap
    DEVTYPE=ap_card
    DEV_TYPE=000D
    MODALIAS=ap:t0D
    MODE=ep11  <- this is new
    SEQNUM=1095
  This is true for bind, unbind, add, remove, and change uevents
  related to ap card or ap queue devices.
* On a change of the soft online attribute on a zcrypt queue or card
  device a new CHANGE uevent is sent with an env value ONLINE=<0|1>.
  Example uevent:
    KERNEL[613.067531] change /devices/ap/card09/09.0011 (ap)
    ACTION=change
    DEVPATH=/devices/ap/card09/09.0011
    SUBSYSTEM=ap
    ONLINE=0 <- this is new
    DEVTYPE=ap_queue
    DRIVER=cex4queue
    MODE=cca
    SEQNUM=1070
- On a change of the config state of an zcrypt card device a new
  CHANGE uevent is sent with an env value CONFIG=<0|1>.
  Example uevent:
    KERNEL[876.258680] change /devices/ap/card09 (ap)
    ACTION=change
    DEVPATH=/devices/ap/card09
    SUBSYSTEM=ap
    CONFIG=0 <- this is new
    DEVTYPE=ap_card
    DRIVER=cex4card
    DEV_TYPE=000D
    MODALIAS=ap:t0D
    MODE=cca
    SEQNUM=1073
  Setting a card config on/off causes the dependent queue devices to
  follow the config state change and thus uevents informing about the
  config state change for the queue devices are also emitted.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_card.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_card.c
drivers/s390/crypto/zcrypt_msgtype50.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/crypto/zcrypt_queue.c

index 0f088e335397f0d66f4a909cbdfa180da953e9b4..d2560186d7715ae55b547cd07771d57267e41ea1 100644 (file)
@@ -587,22 +587,47 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
  */
 static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       int rc;
+       int rc = 0;
        struct ap_device *ap_dev = to_ap_dev(dev);
 
        /* Uevents from ap bus core don't need extensions to the env */
        if (dev == ap_root_device)
                return 0;
 
-       /* Set up DEV_TYPE environment variable. */
-       rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
-       if (rc)
-               return rc;
+       if (is_card_dev(dev)) {
+               struct ap_card *ac = to_ap_card(&ap_dev->device);
 
-       /* Add MODALIAS= */
-       rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
-       if (rc)
-               return rc;
+               /* Set up DEV_TYPE environment variable. */
+               rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
+               if (rc)
+                       return rc;
+               /* Add MODALIAS= */
+               rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
+               if (rc)
+                       return rc;
+
+               /* Add MODE=<accel|cca|ep11> */
+               if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL))
+                       rc = add_uevent_var(env, "MODE=accel");
+               else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO))
+                       rc = add_uevent_var(env, "MODE=cca");
+               else if (ap_test_bit(&ac->functions, AP_FUNC_EP11))
+                       rc = add_uevent_var(env, "MODE=ep11");
+               if (rc)
+                       return rc;
+       } else {
+               struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+
+               /* Add MODE=<accel|cca|ep11> */
+               if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL))
+                       rc = add_uevent_var(env, "MODE=accel");
+               else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO))
+                       rc = add_uevent_var(env, "MODE=cca");
+               else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11))
+                       rc = add_uevent_var(env, "MODE=ep11");
+               if (rc)
+                       return rc;
+       }
 
        return 0;
 }
@@ -624,6 +649,28 @@ static void ap_send_bindings_complete_uevent(void)
        kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp);
 }
 
+void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg)
+{
+       char buf[16];
+       char *envp[] = { buf, NULL };
+
+       snprintf(buf, sizeof(buf), "CONFIG=%d", cfg ? 1 : 0);
+
+       kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
+}
+EXPORT_SYMBOL(ap_send_config_uevent);
+
+void ap_send_online_uevent(struct ap_device *ap_dev, int online)
+{
+       char buf[16];
+       char *envp[] = { buf, NULL };
+
+       snprintf(buf, sizeof(buf), "ONLINE=%d", online ? 1 : 0);
+
+       kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
+}
+EXPORT_SYMBOL(ap_send_online_uevent);
+
 /*
  * calc # of bound APQNs
  */
@@ -1546,6 +1593,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
                        spin_unlock_bh(&aq->lock);
                        AP_DBF_INFO("%s(%d,%d) queue device config off\n",
                                    __func__, ac->id, dom);
+                       ap_send_config_uevent(&aq->ap_dev, aq->config);
                        /* 'receive' pending messages with -EAGAIN */
                        ap_flush_queue(aq);
                        goto put_dev_and_continue;
@@ -1560,6 +1608,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
                        spin_unlock_bh(&aq->lock);
                        AP_DBF_INFO("%s(%d,%d) queue device config on\n",
                                    __func__, ac->id, dom);
+                       ap_send_config_uevent(&aq->ap_dev, aq->config);
                        goto put_dev_and_continue;
                }
                /* handle other error states */
@@ -1669,12 +1718,13 @@ static inline void ap_scan_adapter(int ap)
                                ac->config = false;
                                AP_DBF_INFO("%s(%d) card device config off\n",
                                            __func__, ap);
-
+                               ap_send_config_uevent(&ac->ap_dev, ac->config);
                        }
                        if (!decfg && !ac->config) {
                                ac->config = true;
                                AP_DBF_INFO("%s(%d) card device config on\n",
                                            __func__, ap);
+                               ap_send_config_uevent(&ac->ap_dev, ac->config);
                        }
                }
        }
index 472efd3a755c4b139f42de39ea61bd4190872a3f..230fec6510e25fde95052649d94a42dddae08581 100644 (file)
@@ -362,4 +362,7 @@ int ap_parse_mask_str(const char *str,
  */
 int ap_wait_init_apqn_bindings_complete(unsigned long timeout);
 
+void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg);
+void ap_send_online_uevent(struct ap_device *ap_dev, int online);
+
 #endif /* _AP_BUS_H_ */
index d98bdd28d23edd6417171e822c4c91a6282d3cc5..ca9afc5fcaf7f7ec2848d17c335a13df53f46e97 100644 (file)
@@ -167,6 +167,8 @@ static ssize_t config_store(struct device *dev,
 
        ac->config = cfg ? true : false;
 
+       ap_send_config_uevent(&ac->ap_dev, ac->config);
+
        return count;
 }
 
index 5103c4797572bb28f73f26e78672563acd8c034d..93e77e83ad147513d42411a3feee6bd660d504d7 100644 (file)
@@ -145,7 +145,7 @@ void zcrypt_queue_get(struct zcrypt_queue *);
 int zcrypt_queue_put(struct zcrypt_queue *);
 int zcrypt_queue_register(struct zcrypt_queue *);
 void zcrypt_queue_unregister(struct zcrypt_queue *);
-void zcrypt_queue_force_online(struct zcrypt_queue *, int);
+bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online);
 
 int zcrypt_rng_device_add(void);
 void zcrypt_rng_device_remove(void);
index 09fe6bb8880bcb5f3d69918b61372d8b666baf23..40fd5d37d26afe4f0551882aaa538164d4134034 100644 (file)
@@ -64,7 +64,8 @@ static ssize_t online_store(struct device *dev,
        struct ap_card *ac = to_ap_card(dev);
        struct zcrypt_card *zc = ac->private;
        struct zcrypt_queue *zq;
-       int online, id;
+       int online, id, i = 0, maxzqs = 0;
+       struct zcrypt_queue **zq_uelist = NULL;
 
        if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
                return -EINVAL;
@@ -77,10 +78,35 @@ static ssize_t online_store(struct device *dev,
 
        ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online);
 
+       ap_send_online_uevent(&ac->ap_dev, online);
+
        spin_lock(&zcrypt_list_lock);
+       /*
+        * As we are in atomic context here, directly sending uevents
+        * does not work. So collect the zqueues in a dynamic array
+        * and process them after zcrypt_list_lock release. As we get/put
+        * the zqueue objects, we make sure they exist after lock release.
+        */
+       list_for_each_entry(zq, &zc->zqueues, list)
+               maxzqs++;
+       if (maxzqs > 0)
+               zq_uelist = kcalloc(maxzqs + 1, sizeof(zq), GFP_ATOMIC);
        list_for_each_entry(zq, &zc->zqueues, list)
-               zcrypt_queue_force_online(zq, online);
+               if (zcrypt_queue_force_online(zq, online))
+                       if (zq_uelist) {
+                               zcrypt_queue_get(zq);
+                               zq_uelist[i++] = zq;
+                       }
        spin_unlock(&zcrypt_list_lock);
+       if (zq_uelist) {
+               for (i = 0; zq_uelist[i]; i++) {
+                       zq = zq_uelist[i];
+                       ap_send_online_uevent(&zq->queue->ap_dev, online);
+                       zcrypt_queue_put(zq);
+               }
+               kfree(zq_uelist);
+       }
+
        return count;
 }
 
index bf14ee445f892ab8877df78f4788e50bda4f53b6..6d1800cb21df27da56d6b5e9065cbf494d7460f2 100644 (file)
@@ -375,6 +375,7 @@ static int convert_type80(struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               t80h->code);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
        if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
@@ -412,6 +413,7 @@ static int convert_response_cex2a(struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) rtype);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
 }
index 307f90657d1dd082a7ea3159ffe8dfc598dca00d..da6b2bf779a8994bb3795046d5b322c09585cc62 100644 (file)
@@ -675,6 +675,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) service_rc, (int) service_rs);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
        data = msg->text;
@@ -820,6 +821,7 @@ static int convert_response_ica(struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) msg->hdr.type);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
 }
@@ -854,6 +856,7 @@ static int convert_response_xcrb(bool userspace, struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) msg->hdr.type);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
 }
@@ -883,6 +886,7 @@ static int convert_response_ep11_xcrb(bool userspace, struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) msg->hdr.type);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
 }
@@ -913,6 +917,7 @@ static int convert_response_rng(struct zcrypt_queue *zq,
                               AP_QID_CARD(zq->queue->qid),
                               AP_QID_QUEUE(zq->queue->qid),
                               (int) msg->hdr.type);
+               ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
                return -EAGAIN;
        }
 }
index a89ccdaa512617f74b97805caebb6c7b1c686333..605904b86287db95fe7f8396ef535cb3d505e1a3 100644 (file)
@@ -70,6 +70,8 @@ static ssize_t online_store(struct device *dev,
                   AP_QID_QUEUE(zq->queue->qid),
                   online);
 
+       ap_send_online_uevent(&aq->ap_dev, online);
+
        if (!online)
                ap_flush_queue(zq->queue);
        return count;
@@ -98,11 +100,15 @@ static const struct attribute_group zcrypt_queue_attr_group = {
        .attrs = zcrypt_queue_attrs,
 };
 
-void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
+bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
 {
-       zq->online = online;
-       if (!online)
-               ap_flush_queue(zq->queue);
+       if (!!zq->online != !!online) {
+               zq->online = online;
+               if (!online)
+                       ap_flush_queue(zq->queue);
+               return true;
+       }
+       return false;
 }
 
 struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size)