[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2B0E3F215D1AB84DA946C8BEE234CCC97B2FE617@ORSMSX101.amr.corp.intel.com>
Date: Wed, 13 Nov 2019 01:09:01 +0000
From: "Ertman, David M" <david.m.ertman@...el.com>
To: Greg KH <gregkh@...uxfoundation.org>,
"Kirsher, Jeffrey T" <jeffrey.t.kirsher@...el.com>
CC: "davem@...emloft.net" <davem@...emloft.net>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"linux-rdma@...r.kernel.org" <linux-rdma@...r.kernel.org>,
"nhorman@...hat.com" <nhorman@...hat.com>,
"sassmann@...hat.com" <sassmann@...hat.com>,
"parav@...lanox.com" <parav@...lanox.com>,
"jgg@...pe.ca" <jgg@...pe.ca>,
"Patil, Kiran" <kiran.patil@...el.com>
Subject: RE: [net-next 1/1] virtual-bus: Implementation of Virtual Bus
> -----Original Message-----
> From: Greg KH <gregkh@...uxfoundation.org>
> Sent: Tuesday, November 12, 2019 1:28 PM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@...el.com>
> Cc: davem@...emloft.net; Ertman, David M <david.m.ertman@...el.com>;
> netdev@...r.kernel.org; linux-rdma@...r.kernel.org;
> nhorman@...hat.com; sassmann@...hat.com; parav@...lanox.com;
> jgg@...pe.ca; Patil, Kiran <kiran.patil@...el.com>
> Subject: Re: [net-next 1/1] virtual-bus: Implementation of Virtual Bus
>
> On Mon, Nov 11, 2019 at 11:22:19AM -0800, Jeff Kirsher wrote:
> > From: Dave Ertman <david.m.ertman@...el.com>
> >
> > This is the initial implementation of the Virtual Bus, virtbus_device
> > and virtbus_driver. The virtual bus is a software based bus intended
> > to support lightweight devices and drivers and provide matching
> > between them and probing of the registered drivers.
> >
> > Files added:
> > drivers/bus/virtual_bus.c
> > include/linux/virtual_bus.h
> > Documentation/driver-api/virtual_bus.rst
> >
> > The primary purpose of the virual bus is to provide matching services
> > and to pass the data pointer contained in the virtbus_device to the
> > virtbus_driver during its probe call. This will allow two separate
> > kernel objects to match up and start communication.
> >
> > The bus will support probe/remove shutdown and suspend/resume
> > callbacks.
> >
> > Kconfig and Makefile alterations are included
> >
> > Signed-off-by: Dave Ertman <david.m.ertman@...el.com>
> > Signed-off-by: Kiran Patil <kiran.patil@...el.com>
> > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@...el.com>
>
> Interesting, and kind of what I was thinking of, but the implementation is odd
> and I don't really see how you can use it.
>
> Can you provide a second patch that actually uses this api?
>
> Code comments below for when you resend:
>
> > +Virtual Bus Structs
> > +~~~~~~~~~~~~~~~~~~~
> > +struct device virtual_bus = {
> > + .init_name = "virtbus",
> > + .release = virtual_bus_release,
> > +};
> > +
> > +struct bus_type virtual_bus_type = {
> > + .name = "virtbus",
> > + .match = virtbus_match,
> > + .probe = virtbus_probe,
> > + .remove = virtbus_remove,
> > + .shutdown = virtbus_shutdown,
> > + .suspend = virtbus_suspend,
> > + .resume = virtbus_resume,
> > +};
> > +
> > +struct virtbus_device {
> > + const char *name;
> > + int id;
> > + const struct virtbus_dev_id *dev_id;
> > + struct device dev;
> > + void *data;
> > +};
> > +
> > +struct virtbus_driver {
> > + int (*probe)(struct virtbus_device *);
> > + int (*remove)(struct virtbus_device *);
> > + void (*shutdown)(struct virtbus_device *);
> > + int (*suspend)(struct virtbus_device *, pm_message_t state);
> > + int (*resume)(struct virtbus_device *);
> > + struct device_driver driver;
> > +};
>
>
> All of the above should come straight from the .c/.h files, no need to
> duplicate it in a text file that will be guaranteed to get out of sync.
>
> > diff --git a/drivers/bus/virtual_bus.c b/drivers/bus/virtual_bus.c new
> > file mode 100644 index 000000000000..af3f6d9b60f4
> > --- /dev/null
> > +++ b/drivers/bus/virtual_bus.c
> > @@ -0,0 +1,339 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * virtual_bus.c - lightweight software based bus for virtual devices
> > + *
> > + * Copyright (c) 2019-20 Intel Corporation
> > + *
> > + * Please see Documentation/driver-api/virtual_bus.rst for
> > + * more information
> > + */
> > +
> > +#include <linux/string.h>
> > +#include <linux/virtual_bus.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/pm_domain.h>
> > +#include <linux/acpi.h>
> > +#include <linux/device.h>
> > +
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_DESCRIPTION("Lightweight Virtual Bus");
> MODULE_AUTHOR("David
> > +Ertman <david.m.ertman@...el.com>"); MODULE_AUTHOR("Kiran Patil
> > +<kiran.patil@...el.com>");
> > +
> > +static DEFINE_IDA(virtbus_dev_id);
> > +
> > +static void virtual_bus_release(struct device *dev) {
> > + pr_info("Removing virtual bus device.\n"); }
>
> This is just one step away from doing horrible things.
>
> A release function should free the memory. Not just print a message :(
>
> Also, this is the driver code, use dev_info() and friends, never use
> pr_*() Same goes for all places in this code.
>
> So this is a debugging line, why?
> How can this be called? You only use it:
>
> > +
> > +struct device virtual_bus = {
> > + .init_name = "virtbus",
> > + .release = virtual_bus_release,
> > +};
> > +EXPORT_SYMBOL_GPL(virtual_bus);
>
> Here.
>
> Ick.
>
> A static struct device? Called 'bus'? That's _REALLY_ confusing. What is this
> for? And why export it? That's guaranteed to cause problems (hint, code
> lifecycle vs. data lifecycles...)
>
> > +/**
> > + * virtbus_add_dev - add a virtual bus device
> > + * @vdev: virtual bus device to add
> > + */
> > +int virtbus_dev_add(struct virtbus_device *vdev) {
> > + int ret;
> > +
> > + if (!vdev)
> > + return -EINVAL;
> > +
> > + device_initialize(&vdev->dev);
> > + if (!vdev->dev.parent)
> > + vdev->dev.parent = &virtual_bus;
>
> So it's a parent? Ok, then why export it?
>
> Again I want to see a user please...
>
> > +
> > + vdev->dev.bus = &virtual_bus_type;
> > + /* All device IDs are automatically allocated */
> > + ret = ida_simple_get(&virtbus_dev_id, 0, 0, GFP_KERNEL);
> > + if (ret < 0)
> > + return ret;
> > +
> > + vdev->id = ret;
> > + dev_set_name(&vdev->dev, "%s.%d", vdev->name, vdev->id);
> > +
> > + pr_debug("Registering VirtBus device '%s'. Parent at %s\n",
> > + dev_name(&vdev->dev), dev_name(vdev->dev.parent));
>
> dev_dbg().
>
> > +
> > + ret = device_add(&vdev->dev);
> > + if (!ret)
> > + return ret;
> > +
> > + /* Error adding virtual device */
> > + ida_simple_remove(&virtbus_dev_id, vdev->id);
> > + vdev->id = VIRTBUS_DEVID_NONE;
>
> That's all you need to clean up? Did you read the device_add()
> documentation? Please do so.
>
> And what's up with this DEVID_NONE stuff?
>
> > +
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(virtbus_dev_add);
> > +
> > +/**
> > + * virtbus_dev_del - remove a virtual bus device
> > + * vdev: virtual bus device we are removing */ void
> > +virtbus_dev_del(struct virtbus_device *vdev) {
> > + if (!IS_ERR_OR_NULL(vdev)) {
> > + device_del(&vdev->dev);
> > +
> > + ida_simple_remove(&virtbus_dev_id, vdev->id);
> > + vdev->id = VIRTBUS_DEVID_NONE;
> > + }
> > +}
> > +EXPORT_SYMBOL_GPL(virtbus_dev_del);
> > +
> > +struct virtbus_object {
> > + struct virtbus_device vdev;
> > + char name[];
> > +};
>
> A device has a name, why have another one?
>
> > +
> > +/**
> > + * virtbus_dev_release - Destroy a virtbus device
> > + * @vdev: virtual device to release
> > + *
> > + * Note that the vdev->data which is separately allocated needs to be
> > + * separately freed on it own.
> > + */
> > +static void virtbus_dev_release(struct device *dev) {
> > + struct virtbus_object *vo = container_of(dev, struct virtbus_object,
> > + vdev.dev);
> > +
> > + kfree(vo);
> > +}
> > +
> > +/**
> > + * virtbus_dev_alloc - allocate a virtbus device
> > + * @name: name to associate with the vdev
> > + * @data: pointer to data to be associated with this device */
> > +struct virtbus_device *virtbus_dev_alloc(const char *name, void
> > +*data) {
> > + struct virtbus_object *vo;
> > +
> > + /* Create a virtbus object to contain the vdev and name. This
> > + * avoids a problem with the const attribute of name in the vdev.
> > + * The virtbus_object will be allocated here and freed in the
> > + * release function.
> > + */
> > + vo = kzalloc(sizeof(*vo) + strlen(name) + 1, GFP_KERNEL);
> > + if (!vo)
> > + return NULL;
>
> What problem are you trying to work around with the name?
>
> > +
> > + strcpy(vo->name, name);
> > + vo->vdev.name = vo->name;
> > + vo->vdev.data = data;
> > + vo->vdev.dev.release = virtbus_dev_release;
> > +
> > + return &vo->vdev;
> > +}
> > +EXPORT_SYMBOL_GPL(virtbus_dev_alloc);
>
> Why have an alloc/add pair of functions? Why not just one?
>
> > +
> > +static int virtbus_drv_probe(struct device *_dev) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(_dev->driver);
> > + struct virtbus_device *vdev = to_virtbus_dev(_dev);
> > + int ret;
> > +
> > + ret = dev_pm_domain_attach(_dev, true);
> > + if (ret) {
> > + dev_warn(_dev, "Failed to attatch to PM Domain : %d\n",
> ret);
> > + return ret;
> > + }
> > +
> > + if (vdrv->probe) {
> > + ret = vdrv->probe(vdev);
> > + if (ret)
> > + dev_pm_domain_detach(_dev, true);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int virtbus_drv_remove(struct device *_dev) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(_dev->driver);
> > + struct virtbus_device *vdev = to_virtbus_dev(_dev);
> > + int ret = 0;
> > +
> > + if (vdrv->remove)
> > + ret = vdrv->remove(vdev);
> > +
> > + dev_pm_domain_detach(_dev, true);
> > +
> > + return ret;
> > +}
> > +
> > +static void virtbus_drv_shutdown(struct device *_dev) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(_dev->driver);
> > + struct virtbus_device *vdev = to_virtbus_dev(_dev);
> > +
> > + if (vdrv->shutdown)
> > + vdrv->shutdown(vdev);
> > +}
> > +
> > +static int virtbus_drv_suspend(struct device *_dev, pm_message_t
> > +state) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(_dev->driver);
> > + struct virtbus_device *vdev = to_virtbus_dev(_dev);
> > +
> > + return vdrv->suspend ? vdrv->suspend(vdev, state) : 0; }
> > +
> > +static int virtbus_drv_resume(struct device *_dev) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(_dev->driver);
> > + struct virtbus_device *vdev = to_virtbus_dev(_dev);
> > +
> > + return vdrv->resume ? vdrv->resume(vdev) : 0; }
> > +
> > +/**
> > + * virtbus_drv_register - register a driver for virtual bus devices
> > + * @vdrv: virtbus_driver structure
> > + * @owner: owning module/driver
> > + */
> > +int virtbus_drv_register(struct virtbus_driver *vdrv, struct module
> > +*owner)
>
> Don't force someone to type THIS_MODULE for this call, use the macro trick
> instead that most subsystems use.
>
> Again, I want to see a user, that will cause lots of these types of things to be
> painfully obvious :)
>
>
> > +{
> > + vdrv->driver.owner = owner;
> > + vdrv->driver.bus = &virtual_bus_type;
> > + vdrv->driver.probe = virtbus_drv_probe;
> > + vdrv->driver.remove = virtbus_drv_remove;
> > + vdrv->driver.shutdown = virtbus_drv_shutdown;
> > + vdrv->driver.suspend = virtbus_drv_suspend;
> > + vdrv->driver.resume = virtbus_drv_resume;
> > +
> > + return driver_register(&vdrv->driver); }
> > +EXPORT_SYMBOL_GPL(virtbus_drv_register);
> > +
> > +/**
> > + * virtbus_drv_unregister - unregister a driver for virtual bus
> > +devices
> > + * @drv: virtbus_driver structure
> > + */
> > +void virtbus_drv_unregister(struct virtbus_driver *vdrv) {
> > + driver_unregister(&vdrv->driver);
> > +}
> > +EXPORT_SYMBOL_GPL(virtbus_drv_unregister);
> > +
> > +static const
> > +struct virtbus_dev_id *virtbus_match_id(const struct virtbus_dev_id *id,
> > + struct virtbus_device *vdev)
> > +{
> > + while (id->name[0]) {
> > + if (strcmp(vdev->name, id->name) == 0) {
> > + vdev->dev_id = id;
> > + return id;
> > + }
> > + id++;
> > + }
> > + return NULL;
> > +}
> > +
> > +/**
> > + * virtbus_match - bind virtbus device to virtbus driver
> > + * @dev: device
> > + * @drv: driver
> > + *
> > + * Virtbus device IDs are always in "<name>.<instance>" format.
> > + * Instances are automatically selected through an ida_simple_get so
> > + * are positive integers. Names are taken from the device name field.
> > + * Driver IDs are simple <name>. Need to extract the name from the
> > + * Virtual Device compare to name of the driver.
> > + */
> > +static int virtbus_match(struct device *dev, struct device_driver
> > +*drv) {
> > + struct virtbus_driver *vdrv = to_virtbus_drv(drv);
> > + struct virtbus_device *vdev = to_virtbus_dev(dev);
> > +
> > + if (vdrv->id_table)
> > + return virtbus_match_id(vdrv->id_table, vdev) != NULL;
> > +
> > + return (strcmp(vdev->name, drv->name) == 0); }
> > +
> > +/**
> > + * virtbus_probe - call probe of the virtbus_drv
> > + * @dev: device struct
> > + */
> > +static int virtbus_probe(struct device *dev) {
> > + return dev->driver->probe ? dev->driver->probe(dev) : 0; }
> > +
> > +static int virtbus_remove(struct device *dev) {
> > + return dev->driver->remove ? dev->driver->remove(dev) : 0; }
> > +
> > +static void virtbus_shutdown(struct device *dev) {
> > + if (dev->driver->shutdown)
> > + dev->driver->shutdown(dev);
> > +}
> > +
> > +static int virtbus_suspend(struct device *dev, pm_message_t state) {
> > + if (dev->driver->suspend)
> > + return dev->driver->suspend(dev, state);
>
> You have two different styles here with these calls, use this one instead of
> the crazy ? : style above in probe/remove please.
>
> > +
> > + return 0;
> > +}
> > +
> > +static int virtbus_resume(struct device *dev) {
> > + if (dev->driver->resume)
> > + return dev->driver->resume(dev);
> > +
> > + return 0;
> > +}
> > +
> > +struct bus_type virtual_bus_type = {
> > + .name = "virtbus",
> > + .match = virtbus_match,
> > + .probe = virtbus_probe,
> > + .remove = virtbus_remove,
> > + .shutdown = virtbus_shutdown,
> > + .suspend = virtbus_suspend,
> > + .resume = virtbus_resume,
> > +};
> > +EXPORT_SYMBOL_GPL(virtual_bus_type);
>
> Why is this exported?
>
> > +
> > +static int __init virtual_bus_init(void) {
> > + int err;
> > +
> > + err = device_register(&virtual_bus);
> > + if (err) {
> > + put_device(&virtual_bus);
> > + return err;
> > + }
> > +
> > + err = bus_register(&virtual_bus_type);
> > + if (err) {
> > + device_unregister(&virtual_bus);
> > + return err;
> > + }
> > +
> > + pr_debug("Virtual Bus (virtbus) registered with kernel\n");
>
> Don't be noisy. And remove your debugging code :)
>
>
> > + return err;
> > +}
> > +
> > +static void __exit virtual_bus_exit(void) {
> > + bus_unregister(&virtual_bus_type);
> > + device_unregister(&virtual_bus);
> > +}
> > +
> > +module_init(virtual_bus_init);
> > +module_exit(virtual_bus_exit);
> > diff --git a/include/linux/virtual_bus.h b/include/linux/virtual_bus.h
> > new file mode 100644 index 000000000000..722f020ac53b
> > --- /dev/null
> > +++ b/include/linux/virtual_bus.h
> > @@ -0,0 +1,64 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * virtual_bus.h - lightweight software bus
> > + *
> > + * Copyright (c) 2019-20 Intel Corporation
> > + *
> > + * Please see Documentation/driver-api/virtual_bus.rst for more
> > +information */
> > +
> > +#ifndef _VIRTUAL_BUS_H_
> > +#define _VIRTUAL_BUS_H_
> > +
> > +#include <linux/device.h>
> > +
> > +#define VIRTBUS_DEVID_NONE (-1)
>
> What is this for?
>
> > +#define VIRTBUS_NAME_SIZE 20
>
> Why? Why is 20 "ok"?
>
> > +
> > +struct virtbus_dev_id {
> > + char name[VIRTBUS_NAME_SIZE];
> > + u64 driver_data;
>
> u64 or a pointer? You use both, pick one please.
>
> > +};
> > +
> > +/* memory allocation for dev_id is expected to be done by the
> > +virtbus_driver
> > + * that will match with the virtbus_device, and the matching process
> > +will
> > + * copy the pointer from the matched element from the driver to the
> device.
>
> What pointer? I don't understand.
>
> > + */
> > +struct virtbus_device {
> > + const char *name;
> > + int id;
> > + const struct virtbus_dev_id *dev_id;
> > + struct device dev;
> > + void *data;
> > +};
> > +
> > +struct virtbus_driver {
> > + int (*probe)(struct virtbus_device *);
> > + int (*remove)(struct virtbus_device *);
> > + void (*shutdown)(struct virtbus_device *);
> > + int (*suspend)(struct virtbus_device *, pm_message_t state);
> > + int (*resume)(struct virtbus_device *);
> > + struct device_driver driver;
> > + const struct virtbus_dev_id *id_table; };
> > +
> > +#define virtbus_get_dev_id(vdev) ((vdev)->id_entry)
> > +#define virtbus_get_devdata(dev) ((dev)->devdata)
>
> What are these for?
>
> > +#define dev_is_virtbus(dev) ((dev)->bus == &virtbus_type)
>
> Who needs this?
>
> > +#define to_virtbus_dev(x) container_of((x), struct virtbus_device, dev)
> > +#define to_virtbus_drv(drv) (container_of((drv), struct
> virtbus_driver, \
> > + driver))
>
> Why are these in a public .h file?
>
> > +
> > +extern struct bus_type virtual_bus_type; extern struct device
> > +virtual_bus;
>
> Again, why exported?
>
> > +
> > +int virtbus_dev_add(struct virtbus_device *vdev); void
> > +virtbus_dev_del(struct virtbus_device *vdev); struct virtbus_device
> > +*virtbus_dev_alloc(const char *name, void *devdata); int
> > +virtbus_drv_register(struct virtbus_driver *vdrv, struct module
> > +*owner); void virtbus_drv_unregister(struct virtbus_driver *vdrv);
> > +
> > +int virtbus_for_each_dev(void *data, int (*fn)(struct device *, void
> > +*)); int virtbus_for_each_drv(void *data, int(*fn)(struct
> > +device_driver *, void *));
>
> pick a coding style and stick with it please...
>
> thanks,
>
> greg k-h
Thanks for the quick feedback!! Working on requests and feedback.
-Dave E
Powered by blists - more mailing lists