virtio: Add virtio drivers

Summary:
- This commit adds virtio-mmio and virtio-net drivers

Impact:
- None (new drivers)

Testing:
- Tested with rv-virt (will be updated later) with QEMU-7.1

Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
This commit is contained in:
Masayuki Ishikawa 2022-11-23 20:45:05 +09:00 committed by Xiang Xiao
parent cdaa2ba8d4
commit 8b4ffb8d3e
10 changed files with 1941 additions and 0 deletions

33
Kconfig
View File

@ -1873,6 +1873,39 @@ config DEBUG_VIDEO_INFO
Enable video informational output to SYSLOG.
endif # DEBUG_VIDEO
config DEBUG_VIRTIO
bool "Virtio Debug Features"
default n
depends on DRIVERS_VIRTIO
---help---
Enable virtio debug features.
if DEBUG_VIRTIO
config DEBUG_VIRTIO_ERROR
bool "Virtio Error Output"
default n
depends on DEBUG_ERROR
---help---
Enable virtio error output to SYSLOG.
config DEBUG_VIRTIO_WARN
bool "Virtio Warnings Output"
default n
depends on DEBUG_WARN
---help---
Enable virtio warning output to SYSLOG.
config DEBUG_VIRTIO_INFO
bool "Virtio Informational Output"
default n
depends on DEBUG_INFO
---help---
Enable virtio informational output to SYSLOG.
endif # DEBUG_VIDEO
endif # DEBUG_FEATURES
config DEBUG_TCBINFO

View File

@ -19,6 +19,7 @@ source "drivers/timers/Kconfig"
source "drivers/analog/Kconfig"
source "drivers/audio/Kconfig"
source "drivers/video/Kconfig"
source "drivers/virtio/Kconfig"
source "drivers/bch/Kconfig"
source "drivers/input/Kconfig"
source "drivers/ioexpander/Kconfig"

View File

@ -63,6 +63,7 @@ include usbhost/Make.defs
include usbmisc/Make.defs
include usbmonitor/Make.defs
include video/Make.defs
include virtio/Make.defs
include wireless/Make.defs
include contactless/Make.defs
include 1wire/Make.defs

49
drivers/virtio/Kconfig Normal file
View File

@ -0,0 +1,49 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig DRIVERS_VIRTIO
bool "Virtio Device Support"
depends on !OPENAMP
default n
---help---
if DRIVERS_VIRTIO
menuconfig DRIVERS_VIRTIO_MMIO_NUM
int "The number of virtio mmio devices"
default 1
---help---
if DRIVERS_VIRTIO_MMIO_NUM != 0
menuconfig DRIVERS_VIRTIO_MMIO_BASE
hex "Virtio-mmio base address"
---help---
menuconfig DRIVERS_VIRTIO_MMIO_REGSIZE
hex "Virtio-mmio register size"
default 0
---help---
menuconfig DRIVERS_VIRTIO_MMIO_IRQ
int "Virtio-mmio irq number"
---help---
endif
menuconfig DRIVERS_VIRTIO_NET
bool "Virtio network support"
default n
depends on DRIVERS_VIRTIO_MMIO_NUM > 0
select ARCH_HAVE_NETDEV_STATISTICS
---help---
if DRIVERS_VIRTIO_NET
config DRIVERS_VIRTIO_NET_QUEUE_LEN
int "Queue length"
default 16
---help---
endif
endif

34
drivers/virtio/Make.defs Normal file
View File

@ -0,0 +1,34 @@
############################################################################
# drivers/virtio/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
# Include virtio support
ifeq ($(CONFIG_DRIVERS_VIRTIO),y)
CSRCS += virtio-mmio.c
endif
ifeq ($(CONFIG_DRIVERS_VIRTIO_NET),y)
CSRCS += virtio-mmio-net.c
endif
# Include build support
DEPPATH += --dep-path virtio
VPATH += :virtio

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/****************************************************************************
* drivers/virtio/virtio-mmio-net.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __DRIVERS_VIRTIO_VIRTIO_MMIO_NET_H
#define __DRIVERS_VIRTIO_VIRTIO_MMIO_NET_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_DRIVERS_VIRTIO_NET
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: virtio_mmio_net_init
*
* Description:
* Called from virtio-mmio.c to initialize virtnet
*
****************************************************************************/
int virtio_mmio_net_init(FAR struct virtio_mmio_regs *regs, uint32_t intid);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_DRIVERS_VIRTIO_NET */
#endif /* __DRIVERS_VIRTIO_VIRTIO_MMIO_NET_H */

View File

@ -0,0 +1,226 @@
/****************************************************************************
* drivers/virtio/virtio-mmio.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/virtio/virtio-mmio.h>
#ifdef CONFIG_DRIVERS_VIRTIO_NET
# include "virtio-mmio-net.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ptr_to_uint64(x) ((uint64_t)(uintptr_t)(x))
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: virtq_create
****************************************************************************/
FAR struct virtqueue *virtq_create(uint32_t len)
{
FAR struct virtqueue *virtq = (FAR struct virtqueue *)
kmm_zalloc(sizeof(struct virtqueue));
ASSERT(virtq);
virtq->len = len;
/* See: 2.6 Split Virtqueues */
virtq->desc = (FAR struct virtqueue_desc *)
kmm_memalign(16, 16 * len);
ASSERT(virtq->desc);
virtq->avail = (FAR struct virtqueue_avail *)
kmm_memalign(2, 6 + 2 * len);
ASSERT(virtq->avail);
virtq->used = (FAR struct virtqueue_used *)
kmm_memalign(4, 6 + 8 * len);
ASSERT(virtq->used);
virtq->desc_virt = (FAR void **)
kmm_memalign(16, sizeof(FAR void *) * len);
ASSERT(virtq->desc_virt);
vrtinfo("virtq=%p (len=%" PRId32 ")\n", virtq, len);
vrtinfo("virtq->desc=%p \n", virtq->desc);
vrtinfo("virtq->avail=%p \n", virtq->avail);
vrtinfo("virtq->used=%p \n", virtq->used);
virtq->avail->idx = 0;
virtq->used->idx = 0;
virtq->last_used_idx = 0;
return virtq;
}
/****************************************************************************
* Name: virtq_dev_init
****************************************************************************/
static int virtio_dev_init(uintptr_t virt, uint32_t irq)
{
FAR struct virtio_mmio_regs *regs = (FAR struct virtio_mmio_regs *)virt;
int ret = -ENODEV;
uint32_t val;
vrtinfo("examine virtio at 0x%" PRIxPTR "\n", virt);
val = virtio_getreg32(&regs->magic_value);
if (VIRTIO_MAGIC != val)
{
vrterr("error: virtio at 0x%" PRIxPTR
" had wrong magic value 0x%" PRIx32 "\n", virt, val);
return ret;
}
val = virtio_getreg32(&regs->version);
if (VIRTIO_VERSION != val)
{
vrterr("error: virtio at 0x%" PRIxPTR
" had wrong version 0x%" PRIx32 "\n", virt, val);
return ret;
}
/* Reset */
virtio_putreg32(0, &regs->status);
virtio_mb();
/* Set ack */
val = virtio_getreg32(&regs->status) | VIRTIO_STATUS_ACKNOWLEDGE;
virtio_putreg32(val, &regs->status);
virtio_mb();
/* Set driver */
val = virtio_getreg32(&regs->status) | VIRTIO_STATUS_DRIVER;
virtio_putreg32(val, &regs->status);
virtio_mb();
/* Check the device_id */
val = virtio_getreg32(&regs->device_id);
switch (val)
{
#ifdef CONFIG_DRIVERS_VIRTIO_NET
case VIRTIO_DEV_NET:
ret = virtio_mmio_net_init(regs, irq);
break;
#endif
default:
vrtwarn("unsupported device_id 0x%" PRIx32 "\n", val);
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: virtq_alloc_desc
****************************************************************************/
uint32_t virtq_alloc_desc(FAR struct virtqueue *virtq,
uint32_t idx, FAR void *addr)
{
uint32_t id = idx % virtq->len;
vrtinfo("virtq=%p, idx=%" PRId32 "\n", virtq, idx);
virtq->desc[id].addr = (uintptr_t)addr;
virtq->desc_virt[id] = addr;
return id;
}
/****************************************************************************
* Name: virtq_add_to_mmio_device
****************************************************************************/
void virtq_add_to_mmio_device(FAR struct virtio_mmio_regs *regs,
FAR struct virtqueue *virtq,
uint32_t queue_sel)
{
vrtinfo("==== queue_sel=%" PRId32 ", virtq->len=%" PRId32 "\n",
queue_sel, virtq->len);
virtio_putreg32(queue_sel, &regs->queue_sel);
virtio_mb();
virtio_putreg32(virtq->len, &regs->queue_num);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->desc)),
&regs->queue_desc_low);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->desc) >> 32),
&regs->queue_desc_high);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->avail)),
&regs->queue_avail_low);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->avail) >> 32),
&regs->queue_avail_high);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->used)),
&regs->queue_used_low);
virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->used) >> 32),
&regs->queue_used_high);
virtio_mb();
virtio_putreg32(1, &regs->queue_ready);
}
/****************************************************************************
* Name: virtio_mmio_init
****************************************************************************/
void virtio_mmio_init(void)
{
uintptr_t virtio = (uintptr_t)CONFIG_DRIVERS_VIRTIO_MMIO_BASE;
uint32_t irq = CONFIG_DRIVERS_VIRTIO_MMIO_IRQ;
uint32_t size = CONFIG_DRIVERS_VIRTIO_MMIO_REGSIZE;
uint32_t i;
for (i = 0; i < CONFIG_DRIVERS_VIRTIO_MMIO_NUM; i++)
{
virtio_dev_init(virtio + size * i, irq + i);
}
}

View File

@ -790,6 +790,24 @@
# define vinfo _none
#endif
#ifdef CONFIG_DEBUG_VIRTIO_ERROR
# define vrterr _err
#else
# define vrterr _none
#endif
#ifdef CONFIG_DEBUG_VIRTIO_WARN
# define vrtwarn _warn
#else
# define vrtwarn _none
#endif
#ifdef CONFIG_DEBUG_VIRTIO_INFO
# define vrtinfo _info
#else
# define vrtinfo _none
#endif
/* Buffer dumping macros do not depend on varargs */
#ifdef CONFIG_DEBUG_ERROR

View File

@ -0,0 +1,169 @@
/****************************************************************************
* include/nuttx/virtio/virtio-mmio.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_VIRTIO_VIRTIO_MMIO_H
#define __INCLUDE_NUTTX_VIRTIO_VIRTIO_MMIO_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <arch/spinlock.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* See virtio-v1.1-csprd01.pdf */
#define VIRTIO_MAGIC 0x74726976
#define VIRTIO_VERSION 0x2 /* NOTE: Legacy devices used 0x1 */
#define VIRTIO_DEV_NET 0x1
#define VIRTIO_STATUS_ACKNOWLEDGE (1)
#define VIRTIO_STATUS_DRIVER (2)
#define VIRTIO_STATUS_DRIVER_OK (4)
#define VIRTIO_STATUS_FEATURES_OK (8)
#define VIRTQ_DESC_F_NEXT 1 /* marks a buffer as continuing */
#define VIRTQ_DESC_F_WRITE 2 /* marks a buffer as device write-only */
#define virtio_mb() SP_DMB()
#define virtio_getreg32(a) (FAR *(volatile FAR uint32_t *)(a))
#define virtio_putreg32(v,a) (FAR *(volatile FAR uint32_t *)(a) = (v))
/****************************************************************************
* Public Types
****************************************************************************/
/* Table 4.1 MMIO Device Register Layout */
struct virtio_mmio_regs
{
uint32_t magic_value; /* offset:0x000 */
uint32_t version; /* offset:0x004 */
uint32_t device_id; /* offset:0x008 */
uint32_t vendor_id; /* offset:0x00c */
uint32_t device_features; /* offset:0x010 */
uint32_t device_features_sel; /* offset:0x014 */
uint32_t _reserved0[2];
uint32_t driver_features; /* offset:0x020 */
uint32_t driver_features_sel; /* offset:0x024 */
uint32_t _reserved1[2];
uint32_t queue_sel; /* offset:0x030 */
uint32_t queue_num_max; /* offset:0x034 */
uint32_t queue_num; /* offset:0x038 */
uint32_t _reserved2[2];
uint32_t queue_ready; /* offset:0x044 */
uint32_t _reserved3[2];
uint32_t queue_notify; /* offset:0x050 */
uint32_t _reserved4[3];
uint32_t interrupt_status; /* offset:0x060 */
uint32_t interrupt_ack; /* offset:0x064 */
uint32_t _reserved5[2];
uint32_t status; /* offset:0x070 */
uint32_t _reserved6[3];
uint32_t queue_desc_low; /* offset:0x080 */
uint32_t queue_desc_high; /* offset:0x084 */
uint32_t _reserved7[2];
uint32_t queue_avail_low; /* offset:0x090 */
uint32_t queue_avail_high; /* offset:0x094 */
uint32_t _reserved8[2];
uint32_t queue_used_low; /* offset:0x0a0 */
uint32_t queue_used_high; /* offset:0x0a4 */
uint32_t _reserved9[21];
uint32_t config_generation; /* offset:0x0fc */
uint32_t config[0];
};
struct virtqueue_desc
{
uint64_t addr;
uint32_t len;
uint16_t flags;
uint16_t next;
};
struct virtqueue_avail
{
uint16_t flags;
uint16_t idx;
uint16_t ring[0];
};
struct virtqueue_used_elem
{
uint32_t id;
uint32_t len;
};
struct virtqueue_used
{
uint16_t flags;
uint16_t idx;
struct virtqueue_used_elem ring[0];
};
struct virtqueue
{
uint32_t len;
uint16_t last_used_idx;
FAR struct virtqueue_desc *desc;
FAR struct virtqueue_avail *avail;
FAR struct virtqueue_used *used;
FAR uint16_t *avail_event;
FAR void **desc_virt;
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
FAR struct virtqueue *virtq_create(uint32_t len);
uint32_t virtq_alloc_desc(FAR struct virtqueue *virtq,
uint32_t id,
FAR void *addr);
void virtq_add_to_mmio_device(FAR struct virtio_mmio_regs *regs,
FAR struct virtqueue *virtq,
uint32_t queue_sel);
void virtio_mmio_init(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_NUTTX_VIRTIO_VIRTIO_MMIO_H */