]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
s390/zcrypt: reinit ap queue state machine during device probe
authorHarald Freudenberger <freude@linux.ibm.com>
Fri, 14 Dec 2018 16:32:06 +0000 (11:32 -0500)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Mon, 14 Jan 2019 09:28:55 +0000 (09:28 +0000)
BugLink: https://bugs.launchpad.net/bugs/1805414
Until the vfio-ap driver came into live there was a well known
agreement about the way how ap devices are initialized and their
states when the driver's probe function is called.

However, the vfio device driver when receiving an ap queue device does
additional resets thereby removing the registration for interrupts for
the ap device done by the ap bus core code. So when later the vfio
driver releases the device and one of the default zcrypt drivers takes
care of the device the interrupt registration needs to get
renewed. The current code does no renew and result is that requests
send into such a queue will never see a reply processed - the
application hangs.

This patch adds a function which resets the aq queue state machine for
the ap queue device and triggers the walk through the initial states
(which are reset and registration for interrupts). This function is
now called before the driver's probe function is invoked.

When the association between driver and device is released, the
driver's remove function is called. The current implementation calls a
ap queue function ap_queue_remove(). This invokation has been moved to
the ap bus function to make the probe / remove pair for ap bus and
drivers more symmetric.

Fixes: 7e0bdbe5c21c ("s390/zcrypt: AP bus support for alternate driver(s)")
Cc: stable@vger.kernel.org # 4.19+
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewd-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewd-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
(cherry picked from commit 104f708fd1241b22f808bdf066ab67dc5a051de5)
Signed-off-by: Joseph Salisbury <joseph.salisbury@canonical.com>
Acked-by: Khalid Elmously <khalid.elmously@canonical.com>
Acked-by: Kleber Souza <kleber.souza@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/zcrypt_cex2a.c
drivers/s390/crypto/zcrypt_cex4.c
drivers/s390/crypto/zcrypt_pcixcc.c

index 868b502d0744a56490d4ccadab95cf6bf1d10944..1bf1ef355da06287e77589b4f926cba253882670 100644 (file)
@@ -777,6 +777,8 @@ static int ap_device_probe(struct device *dev)
                drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT;
                if (!!devres != !!drvres)
                        return -ENODEV;
+               /* (re-)init queue's state machine */
+               ap_queue_reinit_state(to_ap_queue(dev));
        }
 
        /* Add queue/card to list of active queues/cards */
@@ -809,6 +811,8 @@ static int ap_device_remove(struct device *dev)
        struct ap_device *ap_dev = to_ap_dev(dev);
        struct ap_driver *ap_drv = ap_dev->drv;
 
+       if (is_queue_dev(dev))
+               ap_queue_remove(to_ap_queue(dev));
        if (ap_drv->remove)
                ap_drv->remove(ap_dev);
 
@@ -1446,10 +1450,6 @@ static void ap_scan_bus(struct work_struct *unused)
                        aq->ap_dev.device.parent = &ac->ap_dev.device;
                        dev_set_name(&aq->ap_dev.device,
                                     "%02x.%04x", id, dom);
-                       /* Start with a device reset */
-                       spin_lock_bh(&aq->lock);
-                       ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
-                       spin_unlock_bh(&aq->lock);
                        /* Register device */
                        rc = device_register(&aq->ap_dev.device);
                        if (rc) {
index 5246cd8c16a605f6748884b47bdc59d963c3b578..7e85d238767ba1d42938a24b67381221f7cc0593 100644 (file)
@@ -253,6 +253,7 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type);
 void ap_queue_remove(struct ap_queue *aq);
 void ap_queue_suspend(struct ap_device *ap_dev);
 void ap_queue_resume(struct ap_device *ap_dev);
+void ap_queue_reinit_state(struct ap_queue *aq);
 
 struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
                               int comp_device_type, unsigned int functions);
index 66f7334bcb03214307fb4f3fecebf91dbb3ba341..0aa4b3ccc948c10cbbd9ac904d6da353e341fd78 100644 (file)
@@ -718,5 +718,20 @@ void ap_queue_remove(struct ap_queue *aq)
 {
        ap_flush_queue(aq);
        del_timer_sync(&aq->timeout);
+
+       /* reset with zero, also clears irq registration */
+       spin_lock_bh(&aq->lock);
+       ap_zapq(aq->qid);
+       aq->state = AP_STATE_BORKED;
+       spin_unlock_bh(&aq->lock);
 }
 EXPORT_SYMBOL(ap_queue_remove);
+
+void ap_queue_reinit_state(struct ap_queue *aq)
+{
+       spin_lock_bh(&aq->lock);
+       aq->state = AP_STATE_RESET_START;
+       ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_queue_reinit_state);
index f4ae5fa30ec970e99a39387b2b0a7a4b13903889..ff17a00273f77d60f63bf3e20c67b3408d96915b 100644 (file)
@@ -198,7 +198,6 @@ static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev)
        struct ap_queue *aq = to_ap_queue(&ap_dev->device);
        struct zcrypt_queue *zq = aq->private;
 
-       ap_queue_remove(aq);
        if (zq)
                zcrypt_queue_unregister(zq);
 }
index 35d58dbbc4da3dcc5fa47f5d23a8dfcbe08ff9ae..2a42e5962317a1cf797720219ccac09aa2807638 100644 (file)
@@ -273,7 +273,6 @@ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
        struct ap_queue *aq = to_ap_queue(&ap_dev->device);
        struct zcrypt_queue *zq = aq->private;
 
-       ap_queue_remove(aq);
        if (zq)
                zcrypt_queue_unregister(zq);
 }
index 94d9f7224aea3acbb394c424a88ed2e6ba867c04..baa683c3f5d302f8be3fb7f6d7e6dfd9434f7eb1 100644 (file)
@@ -276,7 +276,6 @@ static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
        struct ap_queue *aq = to_ap_queue(&ap_dev->device);
        struct zcrypt_queue *zq = aq->private;
 
-       ap_queue_remove(aq);
        if (zq)
                zcrypt_queue_unregister(zq);
 }