Re: [PATCH] s390/cio: introduce driver_override on the css bus
From: Cornelia Huck
Date: Fri Jun 21 2019 - 05:56:19 EST
On Thu, 13 Jun 2019 13:08:15 +0200
Cornelia Huck <cohuck@xxxxxxxxxx> wrote:
> Sometimes, we want to control which of the matching drivers
> binds to a subchannel device (e.g. for subchannels we want to
> handle via vfio-ccw).
>
> For pci devices, a mechanism to do so has been introduced in
> 782a985d7af2 ("PCI: Introduce new device binding path using
> pci_dev.driver_override"). It makes sense to introduce the
> driver_override attribute for subchannel devices as well, so
> that we can easily extend the 'driverctl' tool (which makes
> use of the driver_override attribute for pci).
>
> Note that unlike pci we still require a driver override to
> match the subchannel type; matching more than one subchannel
> type is probably not useful anyway.
>
> Signed-off-by: Cornelia Huck <cohuck@xxxxxxxxxx>
> ---
>
> Lightly tested; did not yet attempt to adapt driverctl to actually
> make use of it.
Friendly ping.
In the meanwhile, I figured out that you do not need to adapt driverctl
at all, but just need to pass it '-b css' to work on the css bus; this
seems to work just fine with this patch applied.
>
> For some background, refer to the thread around
> https://lore.kernel.org/kvm/20190612091439.3a33f17b.cohuck@xxxxxxxxxx/
>
> ---
> Documentation/ABI/testing/sysfs-bus-css | 23 +++++++++++
> drivers/s390/cio/cio.h | 1 +
> drivers/s390/cio/css.c | 53 +++++++++++++++++++++++++
> 3 files changed, 77 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-css b/Documentation/ABI/testing/sysfs-bus-css
> index 2979c40c10e9..966f8504bd7b 100644
> --- a/Documentation/ABI/testing/sysfs-bus-css
> +++ b/Documentation/ABI/testing/sysfs-bus-css
> @@ -33,3 +33,26 @@ Description: Contains the PIM/PAM/POM values, as reported by the
> in sync with the values current in the channel subsystem).
> Note: This is an I/O-subchannel specific attribute.
> Users: s390-tools, HAL
> +
> +What: /sys/bus/css/devices/.../driver_override
> +Date: June 2019
> +Contact: Cornelia Huck <cohuck@xxxxxxxxxx>
> + linux-s390@xxxxxxxxxxxxxxx
> +Description: This file allows the driver for a device to be specified. When
> + specified, only a driver with a name matching the value written
> + to driver_override will have an opportunity to bind to the
> + device. The override is specified by writing a string to the
> + driver_override file (echo vfio-ccw > driver_override) and
> + may be cleared with an empty string (echo > driver_override).
> + This returns the device to standard matching rules binding.
> + Writing to driver_override does not automatically unbind the
> + device from its current driver or make any attempt to
> + automatically load the specified driver. If no driver with a
> + matching name is currently loaded in the kernel, the device
> + will not bind to any driver. This also allows devices to
> + opt-out of driver binding using a driver_override name such as
> + "none". Only a single driver may be specified in the override,
> + there is no support for parsing delimiters.
> + Note that unlike the mechanism of the same name for pci, this
> + file does not allow to override basic matching rules. I.e.,
> + the driver must still match the subchannel type of the device.
> diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
> index 06a91743335a..8c4af88f1ac3 100644
> --- a/drivers/s390/cio/cio.h
> +++ b/drivers/s390/cio/cio.h
> @@ -113,6 +113,7 @@ struct subchannel {
> enum sch_todo todo;
> struct work_struct todo_work;
> struct schib_config config;
> + char *driver_override; /* Driver name to force a match */
> } __attribute__ ((aligned(8)));
>
> DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
> diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
> index aea502922646..f3436a17e3b5 100644
> --- a/drivers/s390/cio/css.c
> +++ b/drivers/s390/cio/css.c
> @@ -165,6 +165,7 @@ static void css_subchannel_release(struct device *dev)
>
> sch->config.intparm = 0;
> cio_commit_config(sch);
> + kfree(sch->driver_override);
> kfree(sch->lock);
> kfree(sch);
> }
> @@ -315,9 +316,57 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
>
> static DEVICE_ATTR_RO(modalias);
>
> +static ssize_t driver_override_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct subchannel *sch = to_subchannel(dev);
> + char *driver_override, *old, *cp;
> +
> + /* We need to keep extra room for a newline */
> + if (count >= (PAGE_SIZE - 1))
> + return -EINVAL;
> +
> + driver_override = kstrndup(buf, count, GFP_KERNEL);
> + if (!driver_override)
> + return -ENOMEM;
> +
> + cp = strchr(driver_override, '\n');
> + if (cp)
> + *cp = '\0';
> +
> + device_lock(dev);
> + old = sch->driver_override;
> + if (strlen(driver_override)) {
> + sch->driver_override = driver_override;
> + } else {
> + kfree(driver_override);
> + sch->driver_override = NULL;
> + }
> + device_unlock(dev);
> +
> + kfree(old);
> +
> + return count;
> +}
> +
> +static ssize_t driver_override_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct subchannel *sch = to_subchannel(dev);
> + ssize_t len;
> +
> + device_lock(dev);
> + len = snprintf(buf, PAGE_SIZE, "%s\n", sch->driver_override);
> + device_unlock(dev);
> + return len;
> +}
> +static DEVICE_ATTR_RW(driver_override);
> +
> static struct attribute *subch_attrs[] = {
> &dev_attr_type.attr,
> &dev_attr_modalias.attr,
> + &dev_attr_driver_override.attr,
> NULL,
> };
>
> @@ -1222,6 +1271,10 @@ static int css_bus_match(struct device *dev, struct device_driver *drv)
> struct css_driver *driver = to_cssdriver(drv);
> struct css_device_id *id;
>
> + /* When driver_override is set, only bind to the matching driver */
> + if (sch->driver_override && strcmp(sch->driver_override, drv->name))
> + return 0;
> +
> for (id = driver->subchannel_type; id->match_flags; id++) {
> if (sch->st == id->type)
> return 1;