mirror of
https://github.com/OpenAMP/open-amp.git
synced 2025-12-07 04:01:15 +08:00
virtio_mmio: unify device and driver interfaces into a
single header file. Signed-off-by: Felipe Neves <felipe.neves@linaro.org>
This commit is contained in:
committed by
Arnaud Pouliquen
parent
ead7ad8bb0
commit
a76b28b248
@@ -8,6 +8,7 @@
|
||||
#ifndef OPENAMP_VIRTIO_MMIO_H
|
||||
#define OPENAMP_VIRTIO_MMIO_H
|
||||
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/device.h>
|
||||
#include <openamp/virtio.h>
|
||||
#include <openamp/virtqueue.h>
|
||||
@@ -167,6 +168,73 @@ struct virtio_mmio_device {
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is called when the driver side should be notifyed
|
||||
*
|
||||
* @param dev The device that need to notify the other side
|
||||
*/
|
||||
typedef void (*virtio_mmio_notify)(struct virtio_device *dev);
|
||||
|
||||
#ifdef WITH_VIRTIO_MMIO_DEV
|
||||
/**
|
||||
* @brief Define an Empty MMIO register table with only the strict necessary
|
||||
* for a driver to recognise the device
|
||||
*
|
||||
* @note The initial state NOT_READY is the current approach to block the
|
||||
* device side usage from driver until it gets properly configured.
|
||||
*/
|
||||
#define EMPTY_MMIO_TABLE { \
|
||||
.magic = VIRTIO_MMIO_MAGIC_VALUE_STRING, \
|
||||
.version = 2, \
|
||||
.status = VIRTIO_CONFIG_STATUS_NOT_READY, \
|
||||
}
|
||||
|
||||
/** @brief MMIO Device Registers: 256 bytes in practice */
|
||||
struct virtio_mmio_dev_table {
|
||||
|
||||
/* 0x00 R should be 0x74726976 */
|
||||
uint32_t magic;
|
||||
|
||||
/* 0x04 R */
|
||||
uint32_t version;
|
||||
|
||||
/* padding */
|
||||
uint32_t padding[26];
|
||||
|
||||
/* 0x70 RW Writing non-zero values to this register sets the status flags,
|
||||
* indicating the driver progress.
|
||||
* Writing zero (0x0) to this register triggers a device reset.
|
||||
*/
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/** @brief VirtIO mmio dev instance, should be init with mmio_dev_init */
|
||||
struct virtio_mmio_dev {
|
||||
|
||||
/** VirtIO device instance */
|
||||
struct virtio_device vdev;
|
||||
|
||||
/** Number of descriptors per ring */
|
||||
int vring_size;
|
||||
|
||||
/** Array of virtqueues */
|
||||
struct virtqueue *vqs;
|
||||
|
||||
/** Metal IO Region used to access the MMIO registers */
|
||||
struct metal_io_region *io;
|
||||
|
||||
/** Called when an interrupt should be sent to the other side */
|
||||
virtio_mmio_notify notify;
|
||||
|
||||
/** The features supported by this device */
|
||||
uint64_t device_features;
|
||||
|
||||
/** The features supported by the driver from the other side */
|
||||
uint64_t driver_features;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Register a VIRTIO device with the VIRTIO stack.
|
||||
*
|
||||
@@ -214,6 +282,24 @@ int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem
|
||||
*/
|
||||
void virtio_mmio_isr(struct virtio_device *vdev);
|
||||
|
||||
/**
|
||||
* @brief This should be called to initialize a virtio mmio device,
|
||||
* the configure function should be called next by the device driver
|
||||
*
|
||||
* @param dev The device to initialize
|
||||
* @param io The memory region in wich the device should operate
|
||||
* @param callback The callback that will be called when the other side should be notifyed
|
||||
*/
|
||||
void virtio_mmio_dev_init(struct virtio_mmio_dev *dev, struct metal_io_region *io, virtio_mmio_notify callback);
|
||||
|
||||
/**
|
||||
* @brief Should be called by the app when it receive an interrupt for the mmio device
|
||||
*
|
||||
* @param dev The virtio mmio device
|
||||
*/
|
||||
void virtio_mmio_dev_interrupt(struct virtio_mmio_dev *dev);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, STMicroelectronics
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef OPENAMP_VIRTIO_MMIO_DEV_H
|
||||
#define OPENAMP_VIRTIO_MMIO_DEV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/device.h>
|
||||
#include <openamp/virtio_mmio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Define an Empty MMIO register table with only the strict necessary
|
||||
* for a driver to recognise the device
|
||||
*
|
||||
* @note The initial state NOT_READY is the current approach to block the
|
||||
* device side usage from driver until it gets properly configured.
|
||||
*/
|
||||
#define EMPTY_MMIO_TABLE { \
|
||||
.magic = VIRTIO_MMIO_MAGIC_VALUE_STRING, \
|
||||
.version = 2, \
|
||||
.status = VIRTIO_CONFIG_STATUS_NOT_READY, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MMIO Device Registers: 256 bytes in practice, more if the configuration space is used.
|
||||
* This is a trimmed down version with only the essential values needed to be detected correctly.
|
||||
*/
|
||||
struct mmio_table {
|
||||
|
||||
/* 0x00 R should be 0x74726976 */
|
||||
uint32_t magic;
|
||||
|
||||
/* 0x04 R */
|
||||
uint32_t version;
|
||||
|
||||
/* padding */
|
||||
uint32_t padding[26];
|
||||
|
||||
/* 0x70 RW Writing non-zero values to this register sets the status flags,
|
||||
* indicating the driver progress.
|
||||
* Writing zero (0x0) to this register triggers a device reset.
|
||||
*/
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is called when the other side should be notifyed
|
||||
*
|
||||
* @param dev The device that need to notify the other side
|
||||
*/
|
||||
typedef void (*virtio_notify)(struct virtio_device *dev);
|
||||
|
||||
/**
|
||||
* @brief VirtIO mmio dev instance, should be init with mmio_dev_init,
|
||||
* then the VirtIO driver should set it's data using mmio_dev_set_device_data
|
||||
*
|
||||
* @param vdev VirtIO device instance
|
||||
* @param vring_size Number of descriptors per ring
|
||||
* @param vqs Array of virtqueues
|
||||
* @param io Metal IO Region used to access the MMIO registers
|
||||
* @param notify Called when an interrupt should be sent to the other side
|
||||
* @param device_features The features supported by this device
|
||||
* @param driver_features The features supported by the driver from the other side
|
||||
*/
|
||||
struct virtio_mmio_dev {
|
||||
struct virtio_device vdev;
|
||||
int vring_size;
|
||||
struct virtqueue *vqs;
|
||||
struct metal_io_region *io;
|
||||
virtio_notify notify;
|
||||
uint64_t device_features;
|
||||
uint64_t driver_features;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This should be called to initialize a virtio mmio device,
|
||||
* the configure function should be called next by the device driver
|
||||
*
|
||||
* @param dev The device to initialize
|
||||
* @param io The memory region in wich the device should operate
|
||||
* @param callback The callback that will be called when the other side should be notifyed
|
||||
*/
|
||||
void mmio_dev_init(struct virtio_mmio_dev *dev, struct metal_io_region *io, virtio_notify callback);
|
||||
|
||||
/**
|
||||
* @brief Should be called by the app when it receive an interrupt for the mmio device
|
||||
*
|
||||
* @param dev The virtio mmio device
|
||||
*/
|
||||
void mmio_dev_interrupt(struct virtio_mmio_dev *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENAMP_VIRTIO_MMIO_DEV_H */
|
||||
@@ -5,19 +5,19 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <openamp/virtio_mmio_dev.h>
|
||||
#include <openamp/virtio_mmio.h>
|
||||
|
||||
static inline uint32_t read_reg(struct virtio_mmio_dev *dev, uint32_t address)
|
||||
static inline uint32_t virtio_mmio_dev_read_reg(struct virtio_mmio_dev *dev, uint32_t address)
|
||||
{
|
||||
return metal_io_read32(dev->io, address);
|
||||
}
|
||||
|
||||
static inline void write_reg(struct virtio_mmio_dev *dev, uint32_t address, uint32_t value)
|
||||
static inline void virtio_mmio_dev_write_reg(struct virtio_mmio_dev *dev, uint32_t address, uint32_t value)
|
||||
{
|
||||
metal_io_write32(dev->io, address, value);
|
||||
}
|
||||
|
||||
static void mmio_dev_notify_other_side(struct virtqueue *vq)
|
||||
static void virtio_mmio_dev_notify_driver(struct virtqueue *vq)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vq->vq_dev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
@@ -25,12 +25,12 @@ static void mmio_dev_notify_other_side(struct virtqueue *vq)
|
||||
return;
|
||||
|
||||
/* we set the interrupt status to 1 to tell that a buffer was used */
|
||||
write_reg(dev, VIRTIO_MMIO_INTERRUPT_STATUS, 1);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_INTERRUPT_STATUS, 1);
|
||||
|
||||
dev->notify(&dev->vdev);
|
||||
}
|
||||
|
||||
static int mmio_dev_create_virtqueues(struct virtio_device *vdev, unsigned int flags,
|
||||
static int virtio_mmio_dev_create_virtqueues(struct virtio_device *vdev, unsigned int flags,
|
||||
unsigned int nvqs, const char **names, vq_callback *callbacks)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
@@ -50,7 +50,7 @@ static int mmio_dev_create_virtqueues(struct virtio_device *vdev, unsigned int f
|
||||
/* we set all infos needed by the virtqueue */
|
||||
vring_info->vq->callback = callbacks[i];
|
||||
vring_info->vq->vq_name = names[i];
|
||||
vring_info->vq->notify = mmio_dev_notify_other_side;
|
||||
vring_info->vq->notify = virtio_mmio_dev_notify_driver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -59,7 +59,7 @@ static int mmio_dev_create_virtqueues(struct virtio_device *vdev, unsigned int f
|
||||
/* Since the virtqueues are not actually instantiated in the create virtqueues function,
|
||||
* maybe we should free the allocs from configure device ?
|
||||
*/
|
||||
static void mmio_dev_delete_virtqueues(struct virtio_device *vdev)
|
||||
static void virtio_mmio_dev_delete_virtqueues(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
@@ -67,7 +67,7 @@ static void mmio_dev_delete_virtqueues(struct virtio_device *vdev)
|
||||
return;
|
||||
|
||||
/* we are deleting virtqueues so we reset the device at the same time */
|
||||
write_reg(dev, VIRTIO_MMIO_STATUS, VIRTIO_CONFIG_STATUS_NOT_READY);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_STATUS, VIRTIO_CONFIG_STATUS_NOT_READY);
|
||||
|
||||
vdev->vrings_num = 0;
|
||||
dev->vring_size = 0;
|
||||
@@ -75,7 +75,7 @@ static void mmio_dev_delete_virtqueues(struct virtio_device *vdev)
|
||||
metal_free_memory(vdev->vrings_info);
|
||||
}
|
||||
|
||||
static int mmio_dev_configure_device(struct virtio_device *vdev, uint64_t device_features,
|
||||
static int virtio_mmio_dev_configure_device(struct virtio_device *vdev, uint64_t device_features,
|
||||
uint32_t device_type, int nvqs, int vring_size)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
@@ -90,7 +90,8 @@ static int mmio_dev_configure_device(struct virtio_device *vdev, uint64_t device
|
||||
if (!dev->vqs)
|
||||
return ret;
|
||||
|
||||
vdev->vrings_info = metal_allocate_memory(nvqs * sizeof(struct virtio_vring_info));
|
||||
if (!vdev->vrings_info)
|
||||
vdev->vrings_info = metal_allocate_memory(nvqs * sizeof(struct virtio_vring_info));
|
||||
|
||||
if (!vdev->vrings_info)
|
||||
goto free_vqs;
|
||||
@@ -101,15 +102,15 @@ static int mmio_dev_configure_device(struct virtio_device *vdev, uint64_t device
|
||||
vdev->id.device = device_type;
|
||||
|
||||
/* tell the other side the max number of vring allowed */
|
||||
write_reg(dev, VIRTIO_MMIO_QUEUE_NUM_MAX, vring_size);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_QUEUE_NUM_MAX, vring_size);
|
||||
|
||||
/* Set the type of driver needed by the guest */
|
||||
write_reg(dev->io, VIRTIO_MMIO_DEVICE_ID, device_type);
|
||||
virtio_mmio_dev_write_reg(dev->io, VIRTIO_MMIO_DEVICE_ID, device_type);
|
||||
|
||||
/* Allow the other side to init the mmio device */
|
||||
write_reg(dev, VIRTIO_MMIO_DEVICE_ID, device_type);
|
||||
write_reg(dev, VIRTIO_MMIO_STATUS,
|
||||
(uint32_t)read_reg(dev, VIRTIO_MMIO_STATUS) & ~VIRTIO_CONFIG_STATUS_NOT_READY);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_DEVICE_ID, device_type);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_STATUS,
|
||||
(uint32_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_STATUS) & ~VIRTIO_CONFIG_STATUS_NOT_READY);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -118,108 +119,102 @@ free_vqs:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint8_t mmio_dev_get_status(struct virtio_device *vdev)
|
||||
static uint8_t virtio_mmio_dev_get_status(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
return (uint8_t)read_reg(dev, VIRTIO_MMIO_STATUS);
|
||||
return (uint8_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_STATUS);
|
||||
}
|
||||
|
||||
static void mmio_dev_set_status(struct virtio_device *vdev, uint8_t status)
|
||||
static void virtio_mmio_dev_set_status(struct virtio_device *vdev, uint8_t status)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
write_reg(dev, VIRTIO_MMIO_STATUS, status);
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_STATUS, status);
|
||||
}
|
||||
|
||||
static uint64_t mmio_dev_get_features(struct virtio_device *vdev)
|
||||
static uint64_t virtio_mmio_dev_get_features(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
return dev->device_features;
|
||||
}
|
||||
|
||||
static void mmio_dev_set_features(struct virtio_device *vdev, uint32_t feature)
|
||||
static void virtio_mmio_dev_set_features(struct virtio_device *vdev, uint32_t feature)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
dev->device_features = feature;
|
||||
}
|
||||
|
||||
static void mmio_dev_read_config(struct virtio_device *vdev, uint32_t offset, void *dst,
|
||||
static void virtio_mmio_dev_read_config(struct virtio_device *vdev, uint32_t offset, void *dst,
|
||||
int length)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
uint8_t *buf = dst;
|
||||
|
||||
/* TODO: replace to metal_io_block_read, it also need a sanity check regarding
|
||||
* the offset and length of block read
|
||||
*/
|
||||
for (int i = 0; i < length; i++)
|
||||
buf[i] = metal_io_read8(dev->io, VIRTIO_MMIO_CONFIG + i);
|
||||
}
|
||||
|
||||
static void mmio_dev_write_config(struct virtio_device *vdev, uint32_t offset, void *src,
|
||||
static void virtio_mmio_dev_write_config(struct virtio_device *vdev, uint32_t offset, void *src,
|
||||
int length)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
uint8_t *buf = src;
|
||||
|
||||
/* TODO: replace to metal_io_block_write, it also need a sanity check regarding
|
||||
* the offset and length of block being written
|
||||
*/
|
||||
for (int i = 0; i < length; i++)
|
||||
metal_io_write8(dev->io, VIRTIO_MMIO_CONFIG + i, buf[i]);
|
||||
}
|
||||
|
||||
static void mmio_dev_reset_device(struct virtio_device *vdev)
|
||||
static void virtio_mmio_dev_reset_device(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mmio_dev *dev = metal_container_of(vdev, struct virtio_mmio_dev, vdev);
|
||||
|
||||
write_reg(dev, VIRTIO_MMIO_STATUS, read_reg(dev, VIRTIO_MMIO_STATUS) |
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_STATUS, virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_STATUS) |
|
||||
VIRTIO_CONFIG_STATUS_NEEDS_RESET);
|
||||
}
|
||||
|
||||
const static struct virtio_dispatch virtio_ops = {
|
||||
|
||||
.create_virtqueues = mmio_dev_create_virtqueues,
|
||||
.delete_virtqueues = mmio_dev_delete_virtqueues,
|
||||
.create_virtqueues = virtio_mmio_dev_create_virtqueues,
|
||||
.delete_virtqueues = virtio_mmio_dev_delete_virtqueues,
|
||||
|
||||
.configure_device = mmio_dev_configure_device,
|
||||
.configure_device = virtio_mmio_dev_configure_device,
|
||||
|
||||
.get_status = mmio_dev_get_status,
|
||||
.set_status = mmio_dev_set_status,
|
||||
.get_status = virtio_mmio_dev_get_status,
|
||||
.set_status = virtio_mmio_dev_set_status,
|
||||
|
||||
.get_features = mmio_dev_get_features,
|
||||
.set_features = mmio_dev_set_features,
|
||||
.get_features = virtio_mmio_dev_get_features,
|
||||
.set_features = virtio_mmio_dev_set_features,
|
||||
|
||||
.read_config = mmio_dev_read_config,
|
||||
.write_config = mmio_dev_write_config,
|
||||
.read_config = virtio_mmio_dev_read_config,
|
||||
.write_config = virtio_mmio_dev_write_config,
|
||||
|
||||
.reset_device = mmio_dev_reset_device,
|
||||
.reset_device = virtio_mmio_dev_reset_device,
|
||||
};
|
||||
|
||||
void mmio_dev_init(struct virtio_mmio_dev *dev, struct metal_io_region *io, virtio_notify callback)
|
||||
{
|
||||
dev->io = io;
|
||||
dev->notify = callback;
|
||||
dev->vdev.func = &virtio_ops;
|
||||
|
||||
dev->driver_features = 0;
|
||||
|
||||
/* Init vdev struct */
|
||||
dev->vdev.role = VIRTIO_DEV_DEVICE;
|
||||
}
|
||||
|
||||
static void mmio_dev_negotiate_features(struct virtio_mmio_dev *dev)
|
||||
static void virtio_mmio_dev_negotiate_features(struct virtio_mmio_dev *dev)
|
||||
{
|
||||
/* we update the device features each time in case the feature sel changed */
|
||||
write_reg(dev, VIRTIO_MMIO_DEVICE_FEATURES, dev->device_features >>
|
||||
(read_reg(dev, VIRTIO_MMIO_DEVICE_FEATURES_SEL) * 32));
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_DEVICE_FEATURES, dev->device_features >>
|
||||
(virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_DEVICE_FEATURES_SEL) * 32));
|
||||
|
||||
/* we update the driver features each time in case the feature sel changed */
|
||||
dev->driver_features |= ((uint64_t)read_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES) <<
|
||||
(read_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL) * 32));
|
||||
dev->driver_features |= ((uint64_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES) <<
|
||||
(virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL) * 32));
|
||||
}
|
||||
|
||||
static void mmio_dev_receive_queues(struct virtio_mmio_dev *dev, struct virtio_device *vdev)
|
||||
static void virtio_mmio_dev_receive_queues(struct virtio_mmio_dev *dev, struct virtio_device *vdev)
|
||||
{
|
||||
/* Now the driver should send us the virtqueues */
|
||||
uint32_t queuesel = read_reg(dev, VIRTIO_MMIO_QUEUE_SEL);
|
||||
uint32_t queuesel = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_SEL);
|
||||
|
||||
/* Update virtqueue registers according to the queuesel index */
|
||||
if (queuesel >= vdev->vrings_num)
|
||||
@@ -229,18 +224,18 @@ static void mmio_dev_receive_queues(struct virtio_mmio_dev *dev, struct virtio_d
|
||||
struct vring_alloc_info *alloc_info = &vinfo->info;
|
||||
struct virtqueue *vq = &dev->vqs[queuesel];
|
||||
|
||||
/* if this queue allready exist or the driver did not set it up */
|
||||
if (vinfo->vq || !read_reg(dev, VIRTIO_MMIO_QUEUE_READY)) {
|
||||
/* tell the driver if the queue allready exist or not */
|
||||
write_reg(dev, VIRTIO_MMIO_QUEUE_READY, vinfo->vq ? 1 : 0);
|
||||
/* if this queue already exists or the driver did not set it up */
|
||||
if (vinfo->vq || !virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_READY)) {
|
||||
/* tell the driver if the queue already exists or not */
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_QUEUE_READY, vinfo->vq ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the host set Queue Ready then we can read the virtqueue */
|
||||
alloc_info->num_descs = read_reg(dev, VIRTIO_MMIO_QUEUE_NUM);
|
||||
/* If the host sets Queue Ready then we can read the virtqueue */
|
||||
alloc_info->num_descs = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_NUM);
|
||||
|
||||
alloc_info->vaddr = read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_LOW) |
|
||||
((uint64_t)read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_HIGH) << 32);
|
||||
alloc_info->vaddr = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_LOW) |
|
||||
((uint64_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_HIGH) << 32);
|
||||
|
||||
/* TODO: the alignment should be set in a config instead of being hardcoded */
|
||||
alloc_info->align = 4096;
|
||||
@@ -252,21 +247,33 @@ static void mmio_dev_receive_queues(struct virtio_mmio_dev *dev, struct virtio_d
|
||||
vinfo->vq = vq;
|
||||
|
||||
/* Use the vring addresses provided in case they were aligned differently */
|
||||
vq->vq_ring.desc = read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_LOW) |
|
||||
((uint64_t)read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_HIGH) << 32);
|
||||
vq->vq_ring.desc = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_LOW) |
|
||||
((uint64_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_DESC_HIGH) << 32);
|
||||
|
||||
vq->vq_ring.avail = read_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_LOW) |
|
||||
((uint64_t)read_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_HIGH) << 32);
|
||||
vq->vq_ring.avail = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_LOW) |
|
||||
((uint64_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_HIGH) << 32);
|
||||
|
||||
vq->vq_ring.used = read_reg(dev, VIRTIO_MMIO_QUEUE_USED_LOW) |
|
||||
((uint64_t)read_reg(dev, VIRTIO_MMIO_QUEUE_USED_HIGH) << 32);
|
||||
vq->vq_ring.used = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_USED_LOW) |
|
||||
((uint64_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_USED_HIGH) << 32);
|
||||
}
|
||||
|
||||
void mmio_dev_interrupt(struct virtio_mmio_dev *dev)
|
||||
void virtio_mmio_dev_init(struct virtio_mmio_dev *dev, struct metal_io_region *io, virtio_mmio_notify callback)
|
||||
{
|
||||
dev->io = io;
|
||||
dev->notify = callback;
|
||||
dev->vdev.func = &virtio_ops;
|
||||
|
||||
dev->driver_features = 0;
|
||||
|
||||
/* Init vdev struct */
|
||||
dev->vdev.role = VIRTIO_DEV_DEVICE;
|
||||
}
|
||||
|
||||
void virtio_mmio_dev_interrupt(struct virtio_mmio_dev *dev)
|
||||
{
|
||||
struct virtio_device *vdev = &dev->vdev;
|
||||
|
||||
switch (read_reg(dev, VIRTIO_MMIO_STATUS)) {
|
||||
switch (virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_STATUS)) {
|
||||
case VIRTIO_CONFIG_STATUS_RESET:
|
||||
dev->driver_features = 0;
|
||||
break;
|
||||
@@ -275,7 +282,7 @@ void mmio_dev_interrupt(struct virtio_mmio_dev *dev)
|
||||
* the features sel register are used to select the features bits we want to read
|
||||
*/
|
||||
case (VIRTIO_CONFIG_STATUS_ACK | VIRTIO_CONFIG_STATUS_DRIVER):
|
||||
mmio_dev_negotiate_features(dev);
|
||||
virtio_mmio_dev_negotiate_features(dev);
|
||||
break;
|
||||
|
||||
/* Check if the features negotiated are the right ones
|
||||
@@ -285,18 +292,18 @@ void mmio_dev_interrupt(struct virtio_mmio_dev *dev)
|
||||
VIRTIO_CONFIG_STATUS_FEATURES_OK):
|
||||
/* if the features does not match then we should not allow feature ok status */
|
||||
if (dev->driver_features != dev->device_features) {
|
||||
write_reg(dev, VIRTIO_MMIO_STATUS,
|
||||
(uint32_t)read_reg(dev, VIRTIO_MMIO_STATUS) &
|
||||
virtio_mmio_dev_write_reg(dev, VIRTIO_MMIO_STATUS,
|
||||
(uint32_t)virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_STATUS) &
|
||||
~VIRTIO_CONFIG_STATUS_FEATURES_OK);
|
||||
return;
|
||||
}
|
||||
/* The features are fully negotiated ! */
|
||||
vdev->features = dev->driver_features;
|
||||
mmio_dev_receive_queues(dev, vdev);
|
||||
virtio_mmio_dev_receive_queues(dev, vdev);
|
||||
break;
|
||||
|
||||
case VIRTIO_CONFIG_STATUS_READY:
|
||||
uint32_t notify_idx = read_reg(dev, VIRTIO_MMIO_QUEUE_NOTIFY);
|
||||
uint32_t notify_idx = virtio_mmio_dev_read_reg(dev, VIRTIO_MMIO_QUEUE_NOTIFY);
|
||||
/* if the virtqueue does have an available buffer, notify it */
|
||||
if (notify_idx < vdev->vrings_num && vdev->vrings_info[notify_idx].vq &&
|
||||
virtqueue_get_desc_size(&dev->vqs[notify_idx]) > 0)
|
||||
|
||||
Reference in New Issue
Block a user