On Monday 24 September 2007, Rusty Russell wrote: > This attempts to implement a "virtual I/O" layer which should allow > common drivers to be efficiently used across most virtual I/O > mechanisms. It will no-doubt need further enhancement. Hi Rusty, Thanks for your update, as you can imagine, I'm much happier with this version ;-) > + > +struct virtio_bus { > + struct bus_type bus; > + struct device dev; > +}; > + > +static struct virtio_bus virtio_bus = { > + .bus = { > + .name = "virtio", > + .match = virtio_dev_match, > + .dev_attrs = virtio_dev_attrs, > + }, > + .dev = { > + /* Can override this if you have a real bus behind it. */ > + .parent = NULL, > + .bus_id = "virtio", > + } > +}; This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just static struct bus_type virtio_bus_type; static struct device virtio_root_dev; Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately. > +#ifndef _LINUX_VIRTIO_CONFIG_H > +#define _LINUX_VIRTIO_CONFIG_H > +/* Virtio devices use a standardized configuration space to define their > + * features and pass configuration information, but each implementation can > + * store and access that space differently. */ > +#include <linux/types.h> > + > +/* Status byte for guest to report progress, and synchronize config. */ > +/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ > +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 > +/* We have found a driver for the device. */ > +#define VIRTIO_CONFIG_S_DRIVER 2 > +/* Driver has used its parts of the config, and is happy */ > +#define VIRTIO_CONFIG_S_DRIVER_OK 4 > +/* We've given up on this device. */ > +#define VIRTIO_CONFIG_S_FAILED 0x80 > + > +/* Feature byte (actually 7 bits availabe): */ > +/* Requirements/features of the virtio implementation. */ > +#define VIRTIO_CONFIG_F_VIRTIO 1 > +/* Requirements/features of the virtqueue (may have more than one). */ > +#define VIRTIO_CONFIG_F_VIRTQUEUE 2 > + > +#ifdef __KERNEL__ > +struct virtio_device; > + > +/** > + * virtio_config_ops - operations for configuring a virtio device > + * @find: search for the next configuration field of the given type. > + * vdev: the virtio_device > + * type: the feature type > + * len: the (returned) length of the field if found. > + * Returns a token if found, or NULL. Never returnes the same field twice > + * (ie. it's used up). > + * @get: read the value of a configuration field after find(). > + * vdev: the virtio_device > + * token: the token returned from find(). > + * buf: the buffer to write the field value into. > + * len: the length of the buffer (given by find()). > + * Note that contents are conventionally little-endian. > + * @set: write the value of a configuration field after find(). > + * vdev: the virtio_device > + * token: the token returned from find(). > + * buf: the buffer to read the field value from. > + * len: the length of the buffer (given by find()). > + * Note that contents are conventionally little-endian. > + * @get_status: read the status byte > + * vdev: the virtio_device > + * Returns the status byte > + * @set_status: write the status byte > + * vdev: the virtio_device > + * status: the new status byte > + * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue. > + * vdev: the virtio_device > + * callback: the virqtueue callback > + * Returns the new virtqueue or ERR_PTR(). > + * @del_vq: free a virtqueue found by find_vq(). > + */ > +struct virtio_config_ops > +{ > + void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len); > + void (*get)(struct virtio_device *vdev, void *token, > + void *buf, unsigned len); > + void (*set)(struct virtio_device *vdev, void *token, > + const void *buf, unsigned len); > + u8 (*get_status)(struct virtio_device *vdev); > + void (*set_status)(struct virtio_device *vdev, u8 status); > + struct virtqueue *(*find_vq)(struct virtio_device *vdev, > + bool (*callback)(struct virtqueue *)); > + void (*del_vq)(struct virtqueue *vq); > +}; The configuration logic looks more complicated than it should be. Maybe more of this can be done using data structure definitions instead of dynamic callback. E.g. the virtqueues of a given device can be listed as members of the struct virtio_device. > +/** > + * virtio_config_val - get a single virtio config and mark it used. > + * @config: the virtio config space > + * @type: the type to search for. > + * @val: a pointer to the value to fill in. > + * > + * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't > + * be found again. This version does endian conversion. */ > +#define virtio_config_val(vdev, type, v) ({ \ > + int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \ > + \ > + BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ > + && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ > + if (!_err) { \ > + switch (sizeof(*(v))) { \ > + case 2: le16_to_cpus(v); break; \ > + case 4: le32_to_cpus(v); break; \ > + case 8: le64_to_cpus(v); break; \ > + } \ > + } \ > + _err; \ > +}) Especially the macro looks like something better avoided... Arnd <>< _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization