]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390/ap: Support driver_override for AP queue devices
authorHarald Freudenberger <freude@linux.ibm.com>
Wed, 19 Nov 2025 15:27:36 +0000 (16:27 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Mon, 24 Nov 2025 10:43:05 +0000 (11:43 +0100)
Add a new sysfs attribute driver_override the AP queue's
directory. Writing in a string overrides the default driver
determination and the drivers are matched against this string
instead. This overrules the driver binding determined by the
apmask/aqmask bitmask fields.

According to the common understanding of how the driver_override
behavior shall work, there is no further checking done. Neither about
the string which is given as override driver nor if this device is
currently in use by an mdev device. Another patch may limit this
behavior to refuse a mixed usage of the driver_override and
apmask/aqmask feature.

As there exists some tooling for this kind of driver_override
(see package driverctl) the AP bus behavior for re-binding
should be compatible to this. The steps for a driver_override are:
 1) unbind the current driver from the device. For example
    echo "17.0005" > /sys/devices/ap/card17/17.0005/driver/unbind
 2) set the new driver for this device in the sysfs
    driver_override attribute. For example
    echo "vfio_ap" > /sys//devices/ap/card17/17.0005/driver_override
 3) trigger a bus reprobe of this device. For example
    echo "17.0005" > /sys/bus/ap/drivers_probe
With the driverctl package this is more comfortable and
the settings get persisted:
  driverctl -b ap set-override 17.0005 vfio_ap
and unset with
  driverctl -b ap unset-override 17.0005

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c

index cea7399456c657bc278ed09934483be4bb2c7df4..2dbfd8886038d38c2ddb4c9519709df9ad89a425 100644 (file)
@@ -853,20 +853,38 @@ static int __ap_revise_reserved(struct device *dev, void *dummy)
        int rc, card, queue, devres, drvres;
 
        if (is_queue_dev(dev)) {
-               card = AP_QID_CARD(to_ap_queue(dev)->qid);
-               queue = AP_QID_QUEUE(to_ap_queue(dev)->qid);
-               mutex_lock(&ap_perms_mutex);
-               devres = test_bit_inv(card, ap_perms.apm) &&
-                       test_bit_inv(queue, ap_perms.aqm);
-               mutex_unlock(&ap_perms_mutex);
-               drvres = to_ap_drv(dev->driver)->flags
-                       & AP_DRIVER_FLAG_DEFAULT;
-               if (!!devres != !!drvres) {
-                       pr_debug("reprobing queue=%02x.%04x\n", card, queue);
-                       rc = device_reprobe(dev);
-                       if (rc)
-                               AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
-                                           __func__, card, queue);
+               struct ap_driver *ap_drv = to_ap_drv(dev->driver);
+               struct ap_queue *aq = to_ap_queue(dev);
+               struct ap_device *ap_dev = &aq->ap_dev;
+
+               card = AP_QID_CARD(aq->qid);
+               queue = AP_QID_QUEUE(aq->qid);
+
+               if (ap_dev->driver_override) {
+                       if (strcmp(ap_dev->driver_override,
+                                  ap_drv->driver.name)) {
+                               pr_debug("reprobing queue=%02x.%04x\n", card, queue);
+                               rc = device_reprobe(dev);
+                               if (rc) {
+                                       AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
+                                                   __func__, card, queue);
+                               }
+                       }
+               } else {
+                       mutex_lock(&ap_perms_mutex);
+                       devres = test_bit_inv(card, ap_perms.apm) &&
+                               test_bit_inv(queue, ap_perms.aqm);
+                       mutex_unlock(&ap_perms_mutex);
+                       drvres = to_ap_drv(dev->driver)->flags
+                               & AP_DRIVER_FLAG_DEFAULT;
+                       if (!!devres != !!drvres) {
+                               pr_debug("reprobing queue=%02x.%04x\n", card, queue);
+                               rc = device_reprobe(dev);
+                               if (rc) {
+                                       AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
+                                                   __func__, card, queue);
+                               }
+                       }
                }
        }
 
@@ -891,15 +909,30 @@ static void ap_bus_revise_bindings(void)
  */
 int ap_owned_by_def_drv(int card, int queue)
 {
+       struct ap_queue *aq;
        int rc = 0;
 
        if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS)
                return -EINVAL;
 
+       aq = ap_get_qdev(AP_MKQID(card, queue));
+       if (aq) {
+               const struct device_driver *drv = aq->ap_dev.device.driver;
+               const struct ap_driver *ap_drv = to_ap_drv(drv);
+               bool override = !!aq->ap_dev.driver_override;
+
+               if (override && drv && ap_drv->flags & AP_DRIVER_FLAG_DEFAULT)
+                       rc = 1;
+               put_device(&aq->ap_dev.device);
+               if (override)
+                       goto out;
+       }
+
        if (test_bit_inv(card, ap_perms.apm) &&
            test_bit_inv(queue, ap_perms.aqm))
                rc = 1;
 
+out:
        return rc;
 }
 EXPORT_SYMBOL(ap_owned_by_def_drv);
@@ -922,12 +955,10 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm,
        int card, queue, rc = 0;
 
        for (card = 0; !rc && card < AP_DEVICES; card++)
-               if (test_bit_inv(card, apm) &&
-                   test_bit_inv(card, ap_perms.apm))
+               if (test_bit_inv(card, apm))
                        for (queue = 0; !rc && queue < AP_DOMAINS; queue++)
-                               if (test_bit_inv(queue, aqm) &&
-                                   test_bit_inv(queue, ap_perms.aqm))
-                                       rc = 1;
+                               if (test_bit_inv(queue, aqm))
+                                       rc = ap_owned_by_def_drv(card, queue);
 
        return rc;
 }
@@ -951,13 +982,19 @@ static int ap_device_probe(struct device *dev)
                 */
                card = AP_QID_CARD(to_ap_queue(dev)->qid);
                queue = AP_QID_QUEUE(to_ap_queue(dev)->qid);
-               mutex_lock(&ap_perms_mutex);
-               devres = test_bit_inv(card, ap_perms.apm) &&
-                       test_bit_inv(queue, ap_perms.aqm);
-               mutex_unlock(&ap_perms_mutex);
-               drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT;
-               if (!!devres != !!drvres)
-                       goto out;
+               if (ap_dev->driver_override) {
+                       if (strcmp(ap_dev->driver_override,
+                                  ap_drv->driver.name))
+                               goto out;
+               } else {
+                       mutex_lock(&ap_perms_mutex);
+                       devres = test_bit_inv(card, ap_perms.apm) &&
+                               test_bit_inv(queue, ap_perms.aqm);
+                       mutex_unlock(&ap_perms_mutex);
+                       drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT;
+                       if (!!devres != !!drvres)
+                               goto out;
+               }
        }
 
        /*
@@ -983,8 +1020,17 @@ static int ap_device_probe(struct device *dev)
        }
 
 out:
-       if (rc)
+       if (rc) {
                put_device(dev);
+       } else {
+               if (is_queue_dev(dev)) {
+                       pr_debug("queue=%02x.%04x new driver=%s\n",
+                                card, queue, ap_drv->driver.name);
+               } else {
+                       pr_debug("card=%02x new driver=%s\n",
+                                to_ap_card(dev)->id, ap_drv->driver.name);
+               }
+       }
        return rc;
 }
 
index 4b7ffa840563c47bc1d8549fed5842861887e1a9..9d54a6c5d50a91d67b4e94c4657e6a1901e9159d 100644 (file)
@@ -166,6 +166,7 @@ void ap_driver_unregister(struct ap_driver *);
 struct ap_device {
        struct device device;
        int device_type;                /* AP device type. */
+       const char *driver_override;
 };
 
 #define to_ap_dev(x) container_of((x), struct ap_device, device)
index 579e421d134c98d8fc43bd5d20a9bc9838846574..f05ff54f4c4b4eb0aac8af2e8946309b1ad8a6b2 100644 (file)
@@ -731,6 +731,41 @@ static ssize_t ap_functions_show(struct device *dev,
 
 static DEVICE_ATTR_RO(ap_functions);
 
+static ssize_t driver_override_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       struct ap_device *ap_dev = &aq->ap_dev;
+       int rc;
+
+       device_lock(dev);
+       if (ap_dev->driver_override)
+               rc = sysfs_emit(buf, "%s\n", ap_dev->driver_override);
+       else
+               rc = sysfs_emit(buf, "\n");
+       device_unlock(dev);
+
+       return rc;
+}
+
+static ssize_t driver_override_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       struct ap_device *ap_dev = &aq->ap_dev;
+       int rc;
+
+       rc = driver_set_override(dev, &ap_dev->driver_override, buf, count);
+       if (rc)
+               return rc;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(driver_override);
+
 #ifdef CONFIG_AP_DEBUG
 static ssize_t states_show(struct device *dev,
                           struct device_attribute *attr, char *buf)
@@ -843,6 +878,7 @@ static struct attribute *ap_queue_dev_attrs[] = {
        &dev_attr_config.attr,
        &dev_attr_chkstop.attr,
        &dev_attr_ap_functions.attr,
+       &dev_attr_driver_override.attr,
 #ifdef CONFIG_AP_DEBUG
        &dev_attr_states.attr,
        &dev_attr_last_err_rc.attr,