Name
Overview — eCosPro Support for VirtIO
Description
The eCosPro VirtIO package supports access to VirtIO devices. It provides general management of the device and the buffer queues associated with it. Normally a next-level driver will use the facilities provided by this driver to then implement an eCos compliant driver for a particular class of device.
A VirtIO device is described by a cyg_vio_driver structure. Data transfers are described by a cyg_vio_tfr structure. Operations are handled through an API that is used by the class drivers.
VirtIO Device Structure
A VirtIO device is instantiated by creating one of these structures and populating its fields with suitable values. The following fields need to be set; other fields in the structure will be initialized by the VirtIO driver.
- base
- Base address of the device.
- vector
- Device interrupt vector. Interrupts are not handled by the VirtIO driver, instead they need to be handled by the parent class driver. See the API description for details.
- vector_pri
- Interrupt vector priority.
- priv
- A private pointer for the parent driver. This will usually be a pointer to a data structure that the driver uses to store state for this device.
- legacy
- If set to 1, this indicates that the device is a legacy device. At present only legacy devices are supported.
- pci
- If set to 1 this indicates that this is a PCI device. At present PCI devices are not supported.
- drv_features
- A bit mask corresponding to the driver feature bits defined for this class of driver. This will be set in the DRV_FEATURES field of the device during feature negotiation.
- queue_count
- The number of queues in the queue array.
- queue
-
A pointer to an array of pointers to
cyg_vio_queue
structures. Queues are defined using the
VIO_QUEUE(__name, __size)
macro and then collected together into an array which is pointed to by this field.
The following example shows how a VirtIO console driver would be instantiated:
// Define driver feature set #define VIO_CONSOLE_FEATURES VIRTIO_F_RING_INDIRECT_DESC | \ VIRTIO_F_NOTIFY_ON_EMPTY | \ VIRTIO_F_ANY_LAYOUT | \ VIRTIO_CONSOLE_F_MULTIPORT | \ VIRTIO_CONSOLE_F_EMERG_WRITE // Set queue size #define CONSOLE_QUEUE_SIZE 128 // Define queues. Here we have two console channels and a control channel. VIO_QUEUE( virtual_console_rxq0, CONSOLE_QUEUE_SIZE ); VIO_QUEUE( virtual_console_txq0, CONSOLE_QUEUE_SIZE ); VIO_QUEUE( virtual_control_rxq, CONSOLE_QUEUE_SIZE ); VIO_QUEUE( virtual_control_txq, CONSOLE_QUEUE_SIZE ); VIO_QUEUE( virtual_console_rxq1, CONSOLE_QUEUE_SIZE ); VIO_QUEUE( virtual_console_txq1, CONSOLE_QUEUE_SIZE ); // Collect queues together into an array cyg_vio_queue *virtual_console_queues[] = { &virtual_console_rxq0, &virtual_console_txq0, &virtual_control_rxq, &virtual_control_txq, &virtual_console_rxq1, &virtual_console_txq1 }; // Declare the driver cyg_vio_driver console_vio_driver = { // Hardware parameters .base = CYGHWR_HAL_CONSOLE0_BASE, .vector = CYGNUM_HAL_INTERRUPT_CONSOLE0, .vector_pri = 0xa0, // Console driver private data .priv = &virtual_console, // This is a legacy, non PCI device .legacy = 1, .pci = 0, // Set driver features for use in negotiation .drv_features = VIO_CONSOLE_FEATURES, // Attach queues. .queue_count = 6, .queue = virtual_console_queues, };
VirtIO Transfer Structure
Data transfers are described using a cyg_vio_tfr structure. The parent driver prepares a transfer object, passes it to the VirtIO driver and receives it back via a callback when the transfer is complete.
A transfer object has the following structure:
#define VIO_IOV_MAX 8 struct cyg_vio_tfr { cyg_uint16 queue; // Queue number cyg_uint16 head; // head descriptor index cyg_uint16 iov_len; // IOV entry count cyg_uint32 actual; // Total actual bytes transferred void (*callback)( cyg_vio_tfr *tfr ); void *priv; // Private data pointer struct { void *buffer; cyg_uint32 size; cyg_uint32 flags; } iov[VIO_IOV_MAX]; }; #define VIO_IOV_FLAGS_WRITE CYGHWR_VIRTIO_DESC_FLAGS_WRITE
The fields are as follows:
- queue
- The index in the queue array of the queue to apply the transfer to.
- head
- This is used to store the index of the head buffer descriptor associated with this transfer. It does not need to be set by the client, but may be monitored to detect transfer completion, it will be set to 0xFFFF when the transfer is done.
- iov_len
-
The number of entries in the
iov
field that are in use. - actual
- The actual number of bytes transferred. This is the value of the used queue element length field and therefore depends on the hypervisors device emulation to set it correctly.
- callback
-
A function that is called when the transfer is
completed. The single argument is a pointer to the
completed transfer. This will only be called from
within the
cyg_vio_poll()
. - priv
- A private pointer that can be used by the parent driver to supply context to the callback.
- iov
An array of buffer pointers with their sizes. The
flags
field for each will either be zero, or contain theVIO_IOV_FLAGS_WRITE
flag. If the flag is zero, then this buffer is for transfer from the VM to the hypervisor, and if set, then the buffer is for transfer from the hypervisor to the VM.While the default size of this array is 8, this is not a fixed limit. Larger arrays could be passed by treating a transfer object as an initial substructure of a larger object that contains space for a longer IOV array.
2024-03-18 | eCosPro Non-Commercial Public License |