[PATCH] pc386: Add virtio network driver
Joel Sherrill
joel at rtems.org
Tue Mar 29 14:40:33 UTC 2016
Hi
Thanks for the submission. My comments are going to be very general.
+ Can you document which version of the FreeBSD source files this is based
up? Perhaps an svn revision/branch and a list of the exact files in their
source
tree? This has been a historical problem when trying to track future
changes.
+ What were the nature of the rtems specific changes? Are they cleanly
ifdef'ed so a diff against the original FreeBSD source shows ifdef additions
and blocks of RTEMS specific code added?
+ I didn't see any instructions on how to use this. What type of setup is
needed?
I am pretty sure I actually reviewed a conference paper on this work and
am excited to see it submitted. Let's just make it top notch on usability
and maintainability.
--joel
On Tue, Mar 29, 2016 at 8:47 AM, Jinhyun <jinhyun at konkuk.ac.kr> wrote:
> diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.am
> b/c/src/lib/libbsp/i386/pc386/Makefile.am
> index d9af7dd..da50c67 100644
> --- a/c/src/lib/libbsp/i386/pc386/Makefile.am
> +++ b/c/src/lib/libbsp/i386/pc386/Makefile.am
> @@ -232,6 +232,19 @@ noinst_PROGRAMS += 3c509.rel
> 3c509_rel_LDFLAGS += -Wl,--undefined=ep_board
> endif
>
> +if HAS_NETWORKING
> +vtnet_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
> +noinst_PROGRAMS += vtnet.rel
> +vtnet_rel_SOURCES = virtio/if_vtnet.c
> +vtnet_rel_SOURCES += virtio/if_vtnet.h
> +vtnet_rel_SOURCES += virtio/virtio_pci.c
> +vtnet_rel_SOURCES += virtio/virtio_pci.h
> +vtnet_rel_SOURCES += virtio/virtio.c
> +vtnet_rel_SOURCES += virtio/virtio.h
> +vtnet_rel_CPPFLAGS = $(AM_CPPFLAGS) $(vtnet_CPPFLAGS)
> +vtnet_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
> +endif
> +
> libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel
> libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/page.rel
> libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/score.rel
> @@ -246,6 +259,7 @@ if HAS_NETWORKING
> libbsp_a_LIBADD += ne2000.rel
> libbsp_a_LIBADD += wd8003.rel
> libbsp_a_LIBADD += 3c509.rel
> +libbsp_a_LIBADD += vtnet.rel
> endif
>
> EXTRA_DIST += HOWTO
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c
> b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c
> new file mode 100644
> index 0000000..4fcd92c
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c
> @@ -0,0 +1,1032 @@
> +/**
> + * @file if_vtnet.c
> + * @brief Driver for virtio network devices
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice unmodified, this list of conditions, and the following
> + * disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +#include <rtems.h>
> +#include <rtems/rtems_bsdnet.h>
> +
> +#include <bsp.h>
> +#include <bsp/irq.h>
> +
> +#include <sys/mbuf.h>
> +#include <sys/param.h>
> +#include <sys/socket.h>
> +#include <sys/sockio.h>
> +#include <sys/systm.h>
> +
> +#include <net/if.h>
> +
> +#include <netinet/in.h>
> +#include <netinet/if_ether.h>
> +
> +#include <pcibios.h>
> +
> +#include "virtio.h"
> +#include "virtio_pci.h"
> +#include "if_vtnet.h"
> +
> +static struct vtnet_softc vtnet_softc;
> +static rtems_interval vtnet_ticksPerSecond;
> +
> +int rtems_vtnet_driver_attach(
> + struct rtems_bsdnet_ifconfig *config,
> + int attaching
> +)
> +{
> + struct vtnet_softc *sc;
> + int ret;
> +
> + printk( "rtems_vtnet_driver_attach start\n" );
> +
> + sc = &vtnet_softc;
> + memset( sc, 0, sizeof( struct vtnet_softc ) );
> +
> + /* Set up timing values */
> + vtnet_ticksPerSecond = rtems_clock_get_ticks_per_second();
> +
> + printk( "\tAttaching virtio pci...\n" );
> + ret = vtpci_attach( config, &sc->vtpci_softc );
> +
> + if ( ret ) {
> + printk( "vtpci_attach fail...\n" );
> + }
> +
> + /* Alloc virtqueues */
> + printk( "\tAllocating virtqueues...\n" );
> + ret = vtnet_alloc_virtqueues( sc );
> +
> + if ( ret ) {
> + printk( "vtnet_alloc_virtqueues fail...\n" );
> + }
> +
> + /* Setup interrupt */
> + printk( "\tSetup interrupt...\n" );
> + ret = vtnet_setup_intr( &sc->vtpci_softc );
> +
> + if ( ret ) {
> + printk( "vtpci_setup_intr fail...\n" );
> + }
> +
> + /* Setup interface */
> + printk( "\tSetup interface...\n" );
> + ret = vtnet_setup_interface( sc, config );
> +
> + if ( ret ) {
> + printk( "vtnet_setup_interface fail...\n" );
> + }
> +
> + printk( "rtems_vtnet_driver_attach end\n" );
> +
> + return 0;
> +}
> +
> +static int vtnet_alloc_virtqueues( struct vtnet_softc *sc )
> +{
> + uint16_t val16;
> + int size, error;
> +
> + /* Init virtio_net_hdr */
> + memset( &sc->vtnet_net_hdr, 0, sizeof( struct virtio_net_hdr ) );
> +
> + /* Select virtqueue 0 */
> + vtpci_io_write_2( &sc->vtpci_softc,
> + VIRTIO_PCI_QUEUE_SEL,
> + VIRTIO_PCI_QUEUE_SEL_RX );
> + val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );
> +
> + /* Alloc memory & continuous memory for vring */
> + sc->vtnet_rxvq_size = val16;
> + size = sizeof( struct virtqueue ) + val16 * sizeof( struct vq_desc_extra
> );
> + sc->vtnet_rxvq = malloc( size, M_DEVBUF, M_NOWAIT );
> + memset( sc->vtnet_rxvq, 0, size );
> +
> + error =
> + vtnet_alloc_virtqueue( sc->vtnet_rxvq, VIRTIO_PCI_QUEUE_SEL_RX, val16
> );
> +
> + if ( error ) {
> + return error;
> + }
> +
> + /* Select virtqueue 1 */
> + vtpci_io_write_2( &sc->vtpci_softc,
> + VIRTIO_PCI_QUEUE_SEL,
> + VIRTIO_PCI_QUEUE_SEL_TX );
> + val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );
> +
> + /* Alloc memory & continuous memory for vring */
> + sc->vtnet_txvq_size = val16;
> + size = sizeof( struct virtqueue ) + val16 * sizeof( struct vq_desc_extra
> );
> + sc->vtnet_txvq = malloc( size, M_DEVBUF, M_NOWAIT );
> + memset( sc->vtnet_txvq, 0, size );
> +
> + error =
> + vtnet_alloc_virtqueue( sc->vtnet_txvq, VIRTIO_PCI_QUEUE_SEL_TX, val16
> );
> +
> + if ( error ) {
> + return error;
> + }
> +
> + return 0;
> +}
> +
> +static int vtnet_alloc_virtqueue(
> + struct virtqueue *vq,
> + uint16_t queue_num,
> + uint16_t queue_size
> +)
> +{
> + unsigned long align;
> + void *mem;
> + int size;
> +
> + vq->vq_queue_index = queue_num;
> + vq->vq_alignment = VIRTIO_PCI_VRING_ALIGN;
> + vq->vq_nentries = queue_size;
> + vq->vq_free_cnt = queue_size;
> + vq->vq_max_indirect_size = VTNET_RX_MIN_SEGS;
> +
> + align = vq->vq_alignment;
> + size = queue_size * sizeof( struct vring_desc );
> + size += sizeof( struct vring_avail ) + ( queue_size * sizeof( uint16_t )
> ) +
> + sizeof( uint16_t );
> +
> + size = ( size + align - 1 ) & ~( vq->vq_alignment - 1 );
> + size += sizeof( struct vring_used ) +
> + ( queue_size * sizeof( struct vring_used_elem ) ) +
> + sizeof( uint16_t );
> +
> + mem = (void *) malloc( size + align, M_DEVBUF, M_NOWAIT );
> +
> + if ( ( (unsigned long) mem % align ) > 0 ) {
> + mem =
> + (void *) ( (unsigned long) mem +
> + ( align - ( (unsigned long) mem % align ) ) );
> + }
> +
> + vq->vq_ring_size = size;
> + vq->vq_ring_mem = mem;
> + memset( vq->vq_ring_mem, 0, size );
> +
> + virtqueue_disable_intr( vq );
> +
> + return 0;
> +}
> +
> +int vtnet_setup_intr( struct vtpci_softc *sc )
> +{
> + uint8_t val8;
> + int ret;
> +
> + /* Get intrrupt level */
> + pcib_conf_read8( sc->pci_signature, PCI_INTERRUPT_LINE, &val8 );
> + ret = rtems_interrupt_handler_install(
> + val8,
> + NULL,
> + RTEMS_INTERRUPT_SHARED,
> + (rtems_interrupt_handler) vtnet_intr,
> + NULL );
> +
> + return ret;
> +}
> +
> +static int vtnet_setup_interface(
> + struct vtnet_softc *sc,
> + struct rtems_bsdnet_ifconfig *config
> +)
> +{
> + struct ifnet *ifp;
> + int mtu;
> +
> + ifp = &sc->arpcom.ac_if;
> + ifp->if_softc = (void *) &vtnet_softc;
> +
> + if ( config->mtu ) {
> + mtu = config->mtu;
> + } else {
> + mtu = ETHERMTU;
> + }
> +
> + sc->arpcom.ac_enaddr[ 0 ] = 0x08;
> + sc->arpcom.ac_enaddr[ 1 ] = 0x00;
> + sc->arpcom.ac_enaddr[ 2 ] = 0x27;
> + sc->arpcom.ac_enaddr[ 3 ] = 0x98;
> + sc->arpcom.ac_enaddr[ 4 ] = 0xe7;
> + sc->arpcom.ac_enaddr[ 5 ] = 0x0f;
> +
> + ifp->if_softc = sc;
> + ifp->if_unit = sc->vtpci_softc.unit_number;
> + ifp->if_name = sc->vtpci_softc.unit_name;
> + ifp->if_mtu = mtu;
> + ifp->if_init = vtnet_init;
> + ifp->if_ioctl = vtnet_ioctl;
> + ifp->if_start = vtnet_start;
> + ifp->if_output = ether_output;
> + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
> + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
> +
> + if_attach( ifp );
> + ether_ifattach( ifp );
> +
> + return 0;
> +}
> +
> +static void vtnet_init( void *xsc )
> +{
> + rtems_interrupt_level level;
> + struct vtnet_softc *sc;
> + struct ifnet *ifp;
> + struct mbuf *m;
> + uint32_t val32;
> + uint16_t val16;
> + uint8_t val8;
> + int last;
> +
> + sc = xsc;
> + ifp = &sc->arpcom.ac_if;
> +
> + rtems_interrupt_disable( level );
> +
> + if ( ifp->if_flags & IFF_RUNNING ) {
> + return;
> + }
> +
> + printk( "vtnet_init start\n" );
> +
> + /* vtnet_stop */
> + ifp->if_flags &= ~IFF_RUNNING;
> + sc->vtnet_link_active = 0;
> + vtnet_callout_stop( sc );
> +
> + /* vtnet_disable_interrupts */
> + virtqueue_disable_intr( sc->vtnet_rxvq );
> + virtqueue_disable_intr( sc->vtnet_txvq );
> +
> + /* vtpci_stop */
> + vtpci_io_write_1( &sc->vtpci_softc,
> + VIRTIO_PCI_STATUS,
> + VIRTIO_CONFIG_STATUS_RESET );
> +
> + /* vtnet_drain_rxtx_queues */
> + last = 0;
> +
> + while ( ( m = virtqueue_drain( sc->vtnet_rxvq, &last ) ) != NULL ) {
> + m_freem( m );
> + }
> +
> + last = 0;
> +
> + while ( ( m = virtqueue_drain( sc->vtnet_txvq, &last ) ) != NULL ) {
> + m_freem( m );
> + }
> +
> + /* vtpci_reinit */
> + val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );
> +
> + if ( val8 != VIRTIO_CONFIG_STATUS_RESET ) {
> + /* vtpci_stop */
> + vtpci_io_write_1( &sc->vtpci_softc,
> + VIRTIO_PCI_STATUS,
> + VIRTIO_CONFIG_STATUS_RESET );
> + }
> +
> + /* Set status bit as acknowlege & driver */
> + val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );
> + val8 |= VIRTIO_CONFIG_STATUS_ACK;
> + vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );
> + val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );
> + val8 |= VIRTIO_CONFIG_STATUS_DRIVER;
> + vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );
> +
> + vtnet_negotiate_features( sc );
> +
> + /* vtpci_init_virtqueue */
> + vtnet_init_virtqueue( sc, sc->vtnet_rxvq );
> + vtnet_init_virtqueue( sc, sc->vtnet_txvq );
> +
> + vtpci_io_write_2( &sc->vtpci_softc,
> + VIRTIO_PCI_QUEUE_SEL,
> + VIRTIO_PCI_QUEUE_SEL_RX );
> + val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );
> +
> + if ( !val16 || vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN )
> ) {
> + printk( "\tRXQ already exists!\n" );
> + }
> +
> + vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN,
> + ( (uint32_t) sc->vtnet_rxvq->vq_ring_mem >>
> + VIRTIO_PCI_QUEUE_ADDR_SHIFT ) );
> +
> + vtpci_io_write_2( &sc->vtpci_softc,
> + VIRTIO_PCI_QUEUE_SEL,
> + VIRTIO_PCI_QUEUE_SEL_TX );
> + val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );
> +
> + if ( !val16 || vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN )
> ) {
> + printk( "\tTXQ already exists!\n" );
> + }
> +
> + vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN,
> + ( (uint32_t) sc->vtnet_txvq->vq_ring_mem >>
> + VIRTIO_PCI_QUEUE_ADDR_SHIFT ) );
> +
> + /* vtnet_init_rx_queues */
> + sc->vtnet_rx_clsize = MCLBYTES;
> + vtnet_rxq_populate( sc );
> +
> + /* vtnet_init_tx_queues */
> + sc->vtnet_tx_watchdog = 0;
> +
> + vq_ring_enable_interrupt( sc->vtnet_rxvq, 0 );
> + vq_ring_enable_interrupt( sc->vtnet_txvq, 0 );
> + ifp->if_flags |= IFF_RUNNING;
> +
> + /* virtio_reinit_complete */
> + val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );
> + val8 |= VIRTIO_CONFIG_STATUS_DRIVER_OK;
> + vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );
> +
> + /* vtnet_update_link_status; */
> + sc->vtnet_link_active = 1;
> +
> + /* start vtnet_daemon */
> + if ( sc->daemonTid == 0 ) {
> + sc->daemonTid = rtems_bsdnet_newproc( "VTNd",
> + VTNET_DAEMON_STKSIZE,
> + vtnet_daemon,
> + sc );
> + }
> +
> + /* start vtnet_tick */
> + sc->stat_ch = vtnet_timeout_running;
> + /* TODO: timeout routine is not working */
> + /* timeout(vtnet_tick, sc, hz); */
> +
> + printk( "vtnet_init end\n" );
> +
> + rtems_interrupt_enable( level );
> +}
> +
> +static int vtnet_rxq_eof( struct vtnet_softc *sc )
> +{
> + struct virtqueue *vq;
> + struct ifnet *ifp;
> + struct mbuf *m;
> + struct ether_header *eh;
> + uint32_t len;
> + int deq, count;
> +
> + vq = sc->vtnet_rxvq;
> + ifp = &sc->arpcom.ac_if;
> + len = 0;
> + deq = 0;
> + count = VTNET_RX_PROCESS_LIMIT;
> +
> + while ( count-- > 0 ) {
> + m = virtqueue_dequeue( vq, &len );
> +
> + if ( m == NULL ) {
> + break;
> + }
> +
> + deq++;
> +
> + if ( len < sc->vtnet_hdr_size ) {
> + vtnet_rxq_enqueue( sc, m );
> + continue;
> + }
> +
> + if ( vtnet_rxq_replace( sc, m, len ) != 0 ) {
> + vtnet_rxq_enqueue( sc, m );
> + continue;
> + }
> +
> + m->m_pkthdr.len = len;
> + m->m_pkthdr.rcvif = ifp;
> + m_adj( m, sizeof( struct virtio_net_hdr ) );
> +
> + /* vtnet_rxq_input */
> + eh = mtod( m, struct ether_header * );
> + m_adj( m, sizeof( struct ether_header ) );
> + m->m_pkthdr.len = m->m_len;
> +
> + ether_input( ifp, eh, m );
> +
> + if ( ( ifp->if_flags & IFF_RUNNING ) == 0 ) {
> + break;
> + }
> + }
> +
> + if ( deq > 0 ) {
> + vtpci_notify( &sc->vtpci_softc, vq );
> + }
> +
> + return ( count > 0 ? 0 : EAGAIN );
> +}
> +
> +static int vtnet_rxq_enqueue(
> + struct vtnet_softc *sc,
> + struct mbuf *m_head
> +)
> +{
> + struct virtqueue *vq;
> + struct vring_desc *desc, *dp;
> + struct vq_desc_extra *dxp;
> + struct mbuf *m;
> + uint16_t head_idx, idx;
> + uint8_t segs;
> +
> + vq = sc->vtnet_rxvq;
> + desc = vq->vq_ring.desc;
> +
> + if ( vq->vq_free_cnt == 0 ) {
> + return ENOSPC;
> + }
> +
> + segs = 0;
> +
> + for ( m = m_head; m != NULL; m = m->m_next ) {
> + segs++;
> + }
> +
> + if ( segs == 0 ) {
> + return EINVAL;
> + }
> +
> + if ( vq->vq_free_cnt < segs ) {
> + return EMSGSIZE;
> + }
> +
> + head_idx = vq->vq_desc_head_idx;
> + dxp = &vq->vq_descx[ head_idx ];
> + dxp->cookie = m_head;
> + dxp->ndescs = segs;
> +
> + for ( m = m_head, idx = head_idx; m != NULL;
> + m = m->m_next, idx = dp->next ) {
> + dp = &desc[ idx ];
> + dp->addr = (uint32_t) m->m_data;
> + dp->len = m->m_len;
> + dp->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
> + }
> +
> + dp->flags &= ~( VRING_DESC_F_NEXT );
> +
> + vq->vq_desc_head_idx = idx;
> + vq->vq_free_cnt -= segs;
> +
> + vq_ring_update_avail( vq, head_idx );
> +
> + return 0;
> +}
> +
> +static int vtnet_rxq_replace(
> + struct vtnet_softc *sc,
> + struct mbuf *m,
> + int len
> +)
> +{
> + struct mbuf *m_new;
> + int error;
> +
> + if ( m->m_next == NULL ) {
> + if ( m->m_len < len ) {
> + return EINVAL;
> + }
> +
> + m_new = vtnet_rxq_alloc_mbuf( sc, 1, NULL );
> +
> + if ( m_new == NULL ) {
> + return ENOBUFS;
> + }
> +
> + error = vtnet_rxq_enqueue( sc, m_new );
> +
> + if ( error ) {
> + m_freem( m_new );
> + } else {
> + m->m_len = len;
> + }
> + } else {
> + error = vtnet_rxq_replace_nomgr( sc, m, len );
> + }
> +
> + return error;
> +}
> +
> +static struct mbuf *vtnet_rxq_alloc_mbuf(
> + struct vtnet_softc *sc,
> + int nbufs,
> + struct mbuf **m_tailp
> +)
> +{
> + struct mbuf *m_head, *m_tail, *m;
> + int i;
> +
> + MGETHDR( m_head, M_DONTWAIT, MT_DATA );
> +
> + if ( m_head == NULL ) {
> + m_freem( m_head );
> +
> + return NULL;
> + }
> +
> + MCLGET( m_head, M_DONTWAIT );
> +
> + if ( ( m_head->m_flags & M_EXT ) == 0 ) {
> + m_freem( m_head );
> +
> + return NULL;
> + }
> +
> + m_head->m_len = sc->vtnet_rx_clsize;
> + m_tail = m_head;
> +
> + for ( i = 1; i < nbufs; i++ ) {
> + MGETHDR( m, M_DONTWAIT, MT_DATA );
> +
> + if ( m == NULL ) {
> + m_freem( m_head );
> +
> + return NULL;
> + }
> +
> + MCLGET( m, M_DONTWAIT );
> +
> + if ( ( m->m_flags & M_EXT ) == 0 ) {
> + m_freem( m_head );
> + m_freem( m );
> +
> + return NULL;
> + }
> +
> + m->m_len = sc->vtnet_rx_clsize;
> + m_tail->m_next = m;
> + m_tail = m;
> + }
> +
> + if ( m_tailp != NULL ) {
> + *m_tailp = m_tail;
> + }
> +
> + return m_head;
> +}
> +
> +static int vtnet_rxq_replace_nomgr(
> + struct vtnet_softc *sc,
> + struct mbuf *m0,
> + int len0
> +)
> +{
> + struct mbuf *m, *m_prev, *m_new, *m_tail;
> + int len, clsize, nreplace, error;
> +
> + clsize = sc->vtnet_rx_clsize;
> + m_prev = NULL;
> + m_tail = NULL;
> + nreplace = 0;
> + m = m0;
> + len = len0;
> +
> + while ( len > 0 ) {
> + if ( m == NULL ) {
> + return EMSGSIZE;
> + }
> +
> + m->m_len = ( m->m_len > len ) ? len : m->m_len;
> + len -= m->m_len;
> +
> + m_prev = m;
> + m = m->m_next;
> + nreplace++;
> + }
> +
> + m_new = vtnet_rxq_alloc_mbuf( sc, nreplace, &m_tail );
> +
> + if ( m_new == NULL ) {
> + m_prev->m_len = clsize;
> +
> + return ENOBUFS;
> + }
> +
> + if ( m_prev->m_next != NULL ) {
> + m_tail->m_next = m_prev->m_next;
> + m_prev->m_next = NULL;
> + }
> +
> + error = vtnet_rxq_enqueue( sc, m_new );
> +
> + if ( error ) {
> + if ( m_tail->m_next != NULL ) {
> + m_prev->m_next = m_tail->m_next;
> + m_tail->m_next = NULL;
> + }
> +
> + m_prev->m_len = clsize;
> + m_freem( m_new );
> + }
> +
> + return error;
> +}
> +
> +static void vtnet_start( struct ifnet *ifp )
> +{
> + rtems_interrupt_level level;
> + struct vtnet_softc *sc;
> + struct virtqueue *vq;
> + struct mbuf *m;
> + int enq, error;
> +
> + sc = &vtnet_softc;
> + vq = sc->vtnet_txvq;
> + enq = 0;
> +
> + rtems_interrupt_disable( level );
> +
> + if ( ( ifp->if_flags & IFF_RUNNING ) == 0 || sc->vtnet_link_active == 0
> )
> {
> + rtems_interrupt_enable( level );
> +
> + return;
> + }
> +
> + vtnet_txq_eof( sc );
> +
> + while ( ifp->if_snd.ifq_head != NULL ) {
> + IF_DEQUEUE( &ifp->if_snd, m );
> +
> + if ( m == NULL ) {
> + break;
> + }
> +
> + if ( ( error = vtnet_txq_enqueue( sc, m ) ) != 0 ) {
> + if ( m != NULL ) {
> + IF_PREPEND( &ifp->if_snd, m );
> + }
> +
> + break;
> + }
> +
> + enq++;
> + }
> +
> + if ( enq > 0 ) {
> + vtpci_notify( &sc->vtpci_softc, vq );
> + sc->vtnet_tx_watchdog = VTNET_TX_TIMEOUT;
> + }
> +
> + rtems_interrupt_enable( level );
> +}
> +
> +static void vtnet_txq_eof( struct vtnet_softc *sc )
> +{
> + struct virtqueue *vq;
> + struct mbuf *m;
> +
> + vq = sc->vtnet_txvq;
> +
> + while ( ( m = virtqueue_dequeue( vq, NULL ) ) != NULL ) {
> + m_freem( m );
> + }
> +
> + if ( vq->vq_nentries == vq->vq_free_cnt ) {
> + sc->vtnet_tx_watchdog = 0;
> + }
> +}
> +
> +static int vtnet_txq_enqueue(
> + struct vtnet_softc *sc,
> + struct mbuf *m_head
> +)
> +{
> + struct virtqueue *vq;
> + struct vring_desc *desc, *dp;
> + struct vq_desc_extra *dxp;
> + struct mbuf *m;
> + uint16_t head_idx;
> + uint8_t segs;
> +
> + vq = sc->vtnet_txvq;
> + desc = vq->vq_ring.desc;
> +
> + if ( vq->vq_free_cnt == 0 ) {
> + return ENOSPC;
> + }
> +
> + segs = 1;
> +
> + for ( m = m_head; m != NULL; m = m->m_next ) {
> + segs++;
> + }
> +
> + if ( segs == 1 ) {
> + return EINVAL;
> + }
> +
> + if ( vq->vq_free_cnt < segs ) {
> + return EMSGSIZE;
> + }
> +
> + head_idx = vq->vq_desc_head_idx;
> + dxp = &vq->vq_descx[ head_idx ];
> + dxp->cookie = m_head;
> + dxp->ndescs = segs;
> +
> + /* First desc of chain must be vtnet tx hdr */
> + dp = &desc[ head_idx ];
> + dp->addr = (uint32_t) &sc->vtnet_net_hdr;
> + dp->len = sizeof( struct virtio_net_hdr );
> + dp->flags |= VRING_DESC_F_NEXT;
> +
> + /* Link rest mbuf to chain */
> + for ( m = m_head; m != NULL; m = m->m_next ) {
> + dp = &desc[ dp->next ];
> + dp->addr = mtod( m, uint32_t );
> + dp->len = m->m_len;
> + dp->flags |= VRING_DESC_F_NEXT;
> + }
> +
> + dp->flags &= ~( VRING_DESC_F_NEXT );
> +
> + vq->vq_desc_head_idx = dp->next;
> + vq->vq_free_cnt -= segs;
> +
> + vq_ring_update_avail( vq, head_idx );
> +
> + return 0;
> +}
> +
> +static void vtnet_negotiate_features( struct vtnet_softc *sc )
> +{
> + uint32_t host_features;
> + uint32_t guest_features;
> +
> + host_features =
> + vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_HOST_FEATURES );
> + guest_features = host_features & 0xfffff;
> + guest_features &= VTNET_FEATURES;
> +
> + vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_GUEST_FEATURES,
> + guest_features );
> + guest_features =
> + vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_GUEST_FEATURES );
> +
> + printk( "\tHost_features:\t0x%08x\n", host_features );
> + printk( "\tGuest_features:\t0x%08x\n", guest_features );
> +
> + sc->vtnet_hdr_size = sizeof( struct virtio_net_hdr ) + ETHER_HDR_LEN;
> +}
> +
> +static void vtnet_callout_stop( struct vtnet_softc *sc )
> +{
> + if ( sc->stat_ch == vtnet_timeout_running ) {
> + sc->stat_ch = vtnet_timeout_stop_rq;
> +
> + while ( sc->stat_ch != vtnet_timeout_stopped ) {
> + rtems_bsdnet_semaphore_release();
> + rtems_task_wake_after( vtnet_ticksPerSecond );
> + rtems_bsdnet_semaphore_obtain();
> + }
> + }
> +}
> +
> +static void vtnet_callout_reset( struct vtnet_softc *sc )
> +{
> + if ( sc->stat_ch == vtnet_timeout_running ) {
> + timeout( vtnet_tick, sc, hz );
> + } else if ( sc->stat_ch == vtnet_timeout_stop_rq ) {
> + sc->stat_ch = vtnet_timeout_stopped;
> + }
> +}
> +
> +static int vtnet_init_virtqueue(
> + struct vtnet_softc *sc,
> + struct virtqueue *vq
> +)
> +{
> + struct vq_desc_extra *dxp;
> + int i;
> +
> + vq->vq_desc_head_idx = 0;
> + vq->vq_used_cons_idx = 0;
> + vq->vq_queued_cnt = 0;
> + vq->vq_free_cnt = vq->vq_nentries;
> +
> + memset( vq->vq_ring_mem, 0, vq->vq_ring_size );
> +
> + for ( i = 0; i < vq->vq_nentries; i++ ) {
> + dxp = &vq->vq_descx[ i ];
> + dxp->cookie = NULL;
> + dxp->ndescs = 0;
> + dxp->indirect = NULL;
> + }
> +
> + vq_ring_init( vq );
> + virtqueue_disable_intr( vq );
> +
> + return 0;
> +}
> +
> +static int vtnet_rxq_populate( struct vtnet_softc *sc )
> +{
> + struct virtqueue *rxvq;
> + struct mbuf *m;
> + int nbufs, error;
> +
> + rxvq = sc->vtnet_rxvq;
> +
> + for ( nbufs = 0; rxvq->vq_free_cnt; nbufs++ ) {
> + m = vtnet_rxq_alloc_mbuf( sc, 1, NULL );
> +
> + if ( m == NULL ) {
> + return ENOBUFS;
> + }
> +
> + error = vtnet_rxq_enqueue( sc, m );
> +
> + if ( error ) {
> + m_freem( m );
> + }
> + }
> +
> + if ( nbufs > 0 ) {
> + vtpci_notify( &sc->vtpci_softc, rxvq );
> +
> + if ( error == EMSGSIZE ) {
> + error = 0;
> + }
> + }
> +
> + return error;
> +}
> +
> +static int vtnet_ioctl(
> + struct ifnet *ifp,
> + ioctl_command_t cmd,
> + caddr_t data
> +)
> +{
> + int error;
> +
> + error = 0;
> +
> + switch ( cmd ) {
> + case SIOCSIFMTU:
> + /* TODO: vtnet_change_mtu */
> + break;
> + case SIOCSIFFLAGS:
> + vtnet_init( ifp->if_softc );
> + break;
> + case SIOCADDMULTI:
> + case SIOCDELMULTI:
> + /* TODO: vtnet_rx_filter_mac */
> + break;
> + default:
> + error = ether_ioctl( ifp, cmd, data );
> + break;
> + }
> +
> + return error;
> +}
> +
> +static void vtnet_tick( void *xsc )
> +{
> + struct vtnet_softc *sc;
> + struct ifnet *ifp;
> + int timedout;
> +
> + sc = &vtnet_softc;
> + ifp = &sc->arpcom.ac_if;
> +
> + timedout = vtnet_watchdog( sc );
> +
> + if ( timedout != 0 ) {
> + ifp->if_flags &= ~IFF_RUNNING;
> + vtnet_init( sc );
> + } else {
> + vtnet_callout_reset( sc );
> + }
> +}
> +
> +static int vtnet_watchdog( struct vtnet_softc *sc )
> +{
> + if ( sc->vtnet_tx_watchdog == 0 || --sc->vtnet_tx_watchdog ) {
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static rtems_isr vtnet_intr( rtems_vector_number v )
> +{
> + struct vtnet_softc *sc;
> + struct ifnet *ifp;
> + uint8_t isr;
> +
> + sc = &vtnet_softc;
> + ifp = &sc->arpcom.ac_if;
> +
> + isr = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_ISR );
> +
> + if ( isr & VIRTIO_PCI_ISR_INTR ) {
> + if ( ( ifp->if_flags & IFF_RUNNING ) == 0 ) {
> + return;
> + }
> +
> + rtems_bsdnet_event_send( sc->daemonTid, RTEMS_EVENT_1 );
> + } else if ( isr & VIRTIO_PCI_ISR_CONFIG ) {
> + /*
> + * TODO: Handling of config interrupt
> + */
> + }
> +}
> +
> +static void vtnet_daemon( void *xsc )
> +{
> + struct vtnet_softc *sc;
> + struct ifnet *ifp;
> + struct virtqueue *rxvq;
> + struct virtqueue *txvq;
> + int more, tries;
> + rtems_event_set events;
> +
> + sc = &vtnet_softc;
> + ifp = &sc->arpcom.ac_if;
> + rxvq = sc->vtnet_rxvq;
> + txvq = sc->vtnet_txvq;
> +
> + while ( 1 ) {
> + rtems_bsdnet_event_receive( RTEMS_EVENT_1,
> + RTEMS_WAIT | RTEMS_EVENT_ANY,
> + RTEMS_NO_TIMEOUT,
> + &events );
> +
> + /* tx intr */
> + tries = 0;
> +againtx:
> + vtnet_txq_eof( sc );
> +
> + if ( ifp->if_snd.ifq_head != NULL ) {
> + vtnet_start( ifp );
> + }
> +
> + if ( virtqueue_postpone_intr( txvq, VQ_POSTPONE_LONG ) != 0 ) {
> + virtqueue_disable_intr( txvq );
> +
> + if ( tries++ < VTNET_INTR_DISABLE_RETRIES ) {
> + goto againtx;
> + }
> + }
> +
> + /* rx intr */
> + tries = 0;
> +againrx:
> + more = vtnet_rxq_eof( sc );
> +
> + if ( more || vq_ring_enable_interrupt( rxvq, 0 ) != 0 ) {
> + if ( !more ) {
> + virtqueue_disable_intr( rxvq );
> + }
> +
> + if ( tries++ < VTNET_INTR_DISABLE_RETRIES ) {
> + goto againrx;
> + }
> + }
> + }
> +}
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h
> b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h
> new file mode 100644
> index 0000000..7f81bad
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h
> @@ -0,0 +1,181 @@
> +/**
> + * @file if_vtnet.h
> + * @brief Header for if_vtnet.c
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * This header is BSD licensed so anyone can use the definitions to
> implement
> + * compatible drivers/servers.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of IBM nor the names of its contributors
> + * may be used to endorse or promote products derived from this
> software
> + * without specific prior written permission.
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED
> + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR
> + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE
> LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD: release/10.0.0/sys/dev/virtio/network/virtio_net.h 255111
> 2013-09-01 04:23:54Z bryanv $
> + */
> +
> +#ifndef _IF_VTNET_H_
> +#define _IF_VTNET_H_
> +
> +/* The feature bitmap for virtio net */
> +#define VIRTIO_NET_F_CSUM 0x00001 /* Host handles pkts w/ partial
> csum */
> +#define VIRTIO_NET_F_GUEST_CSUM 0x00002 /* Guest handles pkts w/ partial
> csum*/
> +#define VIRTIO_NET_F_MAC 0x00020 /* Host has given MAC address. */
> +#define VIRTIO_NET_F_GSO 0x00040 /* Host handles pkts w/ any GSO
> type */
> +#define VIRTIO_NET_F_GUEST_TSO4 0x00080 /* Guest can handle TSOv4 in. */
> +#define VIRTIO_NET_F_GUEST_TSO6 0x00100 /* Guest can handle TSOv6 in. */
> +#define VIRTIO_NET_F_GUEST_ECN 0x00200 /* Guest can handle TSO[6] w/ ECN
> in.*/
> +#define VIRTIO_NET_F_GUEST_UFO 0x00400 /* Guest can handle UFO in. */
> +#define VIRTIO_NET_F_HOST_TSO4 0x00800 /* Host can handle TSOv4 in. */
> +#define VIRTIO_NET_F_HOST_TSO6 0x01000 /* Host can handle TSOv6 in. */
> +#define VIRTIO_NET_F_HOST_ECN 0x02000 /* Host can handle TSO[6] w/ ECN
> in. */
> +#define VIRTIO_NET_F_HOST_UFO 0x04000 /* Host can handle UFO in. */
> +#define VIRTIO_NET_F_MRG_RXBUF 0x08000 /* Host can merge receive buffers.
> */
> +#define VIRTIO_NET_F_STATUS 0x10000 /* virtio_net_config.status
> available*/
> +#define VIRTIO_NET_F_CTRL_VQ 0x20000 /* Control channel available */
> +#define VIRTIO_NET_F_CTRL_RX 0x40000 /* Control channel RX mode support
> */
> +#define VIRTIO_NET_F_CTRL_VLAN 0x80000 /* Control channel VLAN filtering
> */
> +
> +#define VTNET_FEATURES \
> + ( VIRTIO_NET_F_CSUM | \
> + VIRTIO_NET_F_MAC | \
> + VIRTIO_NET_F_GSO | \
> + VIRTIO_NET_F_HOST_TSO4 | \
> + VIRTIO_NET_F_HOST_TSO6 | \
> + VIRTIO_NET_F_HOST_ECN | \
> + VIRTIO_NET_F_HOST_UFO )
> +
> +#define VTNET_RX_MIN_SEGS 2
> +#define VTNET_RX_PROCESS_LIMIT 512
> +#define VTNET_TX_TIMEOUT 5
> +#define VTNET_INTR_DISABLE_RETRIES 4
> +
> +#define VTNET_DAEMON_STKSIZE 4096
> +
> +struct virtio_net_hdr {
> + uint8_t flags;
> + uint8_t gso_type;
> + uint16_t hdr_len;
> + uint16_t gso_size;
> + uint16_t csum_start;
> + uint16_t csum_offset;
> +};
> +
> +struct vtnet_tx_header {
> + struct virtio_net_hdr hdr;
> + struct mbuf *vth_mbuf;
> +};
> +
> +struct vtnet_softc {
> + struct arpcom arpcom;
> +
> + struct vtpci_softc vtpci_softc;
> + struct virtqueue *vtnet_rxvq;
> + struct virtqueue *vtnet_txvq;
> +
> + rtems_id daemonTid;
> +
> + struct virtio_net_hdr vtnet_net_hdr;
> + int vtnet_rxvq_size;
> + int vtnet_txvq_size;
> +
> + int vtnet_link_active;
> + int vtnet_hdr_size;
> + int vtnet_rx_clsize;
> + int vtnet_tx_watchdog;
> +
> + enum { vtnet_timeout_stopped, vtnet_timeout_running,
> vtnet_timeout_stop_rq }
> + stat_ch;
> +};
> +
> +static int vtnet_alloc_virtqueues( struct vtnet_softc *sc );
> +static int vtnet_alloc_virtqueue(
> + struct virtqueue *vq,
> + uint16_t num,
> + uint16_t queue_size
> +);
> +
> +static int vtnet_setup_interface(
> + struct vtnet_softc *sc,
> + struct rtems_bsdnet_ifconfig *config
> +);
> +static void vtnet_init( void *xsc );
> +static void vtnet_negotiate_features( struct vtnet_softc *sc );
> +static int vtnet_init_virtqueue(
> + struct vtnet_softc *sc,
> + struct virtqueue *vq
> +);
> +static void vtnet_start( struct ifnet *ifp );
> +static int vtnet_ioctl(
> + struct ifnet *ifp,
> + ioctl_command_t cmd,
> + caddr_t data
> +);
> +
> +static int vtnet_setup_intr( struct vtpci_softc *sc );
> +static rtems_isr vtnet_intr( rtems_vector_number v );
> +static void vtnet_daemon( void *xsc );
> +
> +static void vtnet_tick( void *xsc );
> +static int vtnet_watchdog( struct vtnet_softc *sc );
> +static void vtnet_callout_stop( struct vtnet_softc *sc );
> +static void vtnet_callout_reset( struct vtnet_softc *sc );
> +
> +static int vtnet_rxq_populate( struct vtnet_softc *sc );
> +static int vtnet_rxq_eof( struct vtnet_softc *sc );
> +static int vtnet_rxq_enqueue(
> + struct vtnet_softc *sc,
> + struct mbuf *m_head
> +);
> +static int vtnet_rxq_replace(
> + struct vtnet_softc *sc,
> + struct mbuf *m,
> + int len
> +);
> +static struct mbuf *vtnet_rxq_alloc_mbuf(
> + struct vtnet_softc *sc,
> + int nbufs,
> + struct mbuf **m_tailp
> +);
> +static int vtnet_rxq_replace_nomgr(
> + struct vtnet_softc *sc,
> + struct mbuf *m0,
> + int len0
> +);
> +
> +static void vtnet_txq_eof( struct vtnet_softc *sc );
> +static int vtnet_txq_enqueue(
> + struct vtnet_softc *sc,
> + struct mbuf *m_head
> +);
> +
> +#endif /* _IF_VTNET_H_ */
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio.c
> b/c/src/lib/libbsp/i386/pc386/virtio/virtio.c
> new file mode 100644
> index 0000000..85251fa
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio.c
> @@ -0,0 +1,220 @@
> +/**
> + * @file virtio.c
> + * @brief Functions for virtqueue, vring
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice unmodified, this list of conditions, and the following
> + * disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <rtems.h>
> +
> +#include "virtio.h"
> +
> +void *virtqueue_dequeue(
> + struct virtqueue *vq,
> + uint32_t *len
> +)
> +{
> + struct vring_used_elem *uep;
> + void *cookie;
> + uint16_t used_idx, desc_idx;
> +
> + if ( vq->vq_used_cons_idx == vq->vq_ring.used->idx ) {
> + return NULL;
> + }
> +
> + used_idx = vq->vq_used_cons_idx++ & ( vq->vq_nentries - 1 );
> + uep = &vq->vq_ring.used->ring[ used_idx ];
> +
> + rmb();
> +
> + desc_idx = (uint16_t) uep->id;
> +
> + if ( len != NULL ) {
> + *len = uep->len;
> + }
> +
> + vq_ring_free_chain( vq, desc_idx );
> +
> + cookie = vq->vq_descx[ desc_idx ].cookie;
> + vq->vq_descx[ desc_idx ].cookie = NULL;
> +
> + return cookie;
> +}
> +
> +void *virtqueue_drain(
> + struct virtqueue *vq,
> + int *last
> +)
> +{
> + void *cookie;
> + int idx;
> +
> + cookie = NULL;
> + idx = *last;
> +
> + while ( idx < vq->vq_nentries && cookie == NULL ) {
> + if ( ( cookie = vq->vq_descx[ idx ].cookie ) != NULL ) {
> + vq->vq_descx[ idx ].cookie = NULL;
> + vq_ring_free_chain( vq, idx );
> + }
> +
> + idx++;
> + }
> +
> + *last = idx;
> +
> + return cookie;
> +}
> +
> +void virtqueue_disable_intr( struct virtqueue *vq )
> +{
> + vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
> +}
> +
> +int virtqueue_postpone_intr(
> + struct virtqueue *vq,
> + vq_postpone_t hint
> +)
> +{
> + uint16_t ndesc, avail_idx;
> +
> + avail_idx = vq->vq_ring.avail->idx;
> + ndesc = (uint16_t) ( avail_idx - vq->vq_used_cons_idx );
> +
> + switch ( hint ) {
> + case VQ_POSTPONE_SHORT:
> + ndesc = ndesc / 4;
> + break;
> + case VQ_POSTPONE_LONG:
> + ndesc = ( ndesc * 3 ) / 4;
> + break;
> + case VQ_POSTPONE_EMPTIED:
> + break;
> + }
> +
> + return vq_ring_enable_interrupt( vq, ndesc );
> +}
> +
> +void vq_ring_init( struct virtqueue *vq )
> +{
> + struct vring *vr;
> + uint8_t *ring_mem;
> + int i, size;
> +
> + ring_mem = vq->vq_ring_mem;
> + size = vq->vq_nentries;
> + vr = &vq->vq_ring;
> +
> + vr->num = size;
> + vr->desc = (struct vring_desc *) ring_mem;
> + vr->avail =
> + (struct vring_avail *) ( ring_mem + size * sizeof( struct vring_desc )
> );
> + vr->used = (void *)
> + ( ( (unsigned long) &vr->avail->ring[ size ] +
> vq->vq_alignment -
> + 1 ) & ~( vq->vq_alignment - 1 ) );
> +
> + for ( i = 0; i < size - 1; i++ ) {
> + vr->desc[ i ].next = i + 1;
> + }
> +
> + vr->desc[ i ].next = VQ_RING_DESC_CHAIN_END;
> +}
> +
> +void vq_ring_free_chain(
> + struct virtqueue *vq,
> + uint16_t desc_idx
> +)
> +{
> + struct vring_desc *dp;
> + struct vq_desc_extra *dxp;
> +
> + dp = &vq->vq_ring.desc[ desc_idx ];
> + dxp = &vq->vq_descx[ desc_idx ];
> +
> + vq->vq_free_cnt += dxp->ndescs;
> + dxp->ndescs--;
> +
> + while ( dp->flags & VRING_DESC_F_NEXT ) {
> + dp = &vq->vq_ring.desc[ dp->next ];
> + dxp->ndescs--;
> + }
> +
> + dp->next = vq->vq_desc_head_idx;
> + vq->vq_desc_head_idx = desc_idx;
> +}
> +
> +void vq_ring_update_avail(
> + struct virtqueue *vq,
> + uint16_t desc_idx
> +)
> +{
> + uint16_t avail_idx;
> +
> + avail_idx = vq->vq_ring.avail->idx & ( vq->vq_nentries - 1 );
> + vq->vq_ring.avail->ring[ avail_idx ] = desc_idx;
> +
> + wmb();
> +
> + vq->vq_ring.avail->idx++;
> + vq->vq_queued_cnt++;
> +}
> +
> +int vq_ring_must_notify_host( struct virtqueue *vq )
> +{
> + return ( ( vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY ) == 0 );
> +}
> +
> +int vq_ring_enable_interrupt(
> + struct virtqueue *vq,
> + uint16_t ndesc
> +)
> +{
> + uint16_t used_idx, nused;
> +
> + vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
> +
> + mb();
> +
> + used_idx = vq->vq_ring.used->idx;
> + nused = (uint16_t) ( used_idx - vq->vq_used_cons_idx );
> +
> + if ( nused > ndesc ) {
> + return 1;
> + }
> +
> + return 0;
> +}
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio.h
> b/c/src/lib/libbsp/i386/pc386/virtio/virtio.h
> new file mode 100644
> index 0000000..47a61e8
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio.h
> @@ -0,0 +1,167 @@
> +/**
> + * @file virtio.h
> + * @brief Header for virtio.c
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * This header is BSD licensed so anyone can use the definitions to
> implement
> + * compatible drivers/servers.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of IBM nor the names of its contributors
> + * may be used to endorse or promote products derived from this
> software
> + * without specific prior written permission.
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED
> + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR
> + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE
> LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD: release/10.0.0/sys/dev/virtio/virtio.h 252708 2013-07-04
> 17:59:09Z bryanv $
> + */
> +
> +#ifndef _VIRTIO_H_
> +#define _VIRTIO_H_
> +
> +#define mb() asm volatile ( "lock; addl $0,0(%%esp) " ::: "memory" );
> +#define rmb() mb()
> +#define wmb() asm volatile ( "lock; addl $0, (%%esp)" ::: "memory", "cc" )
> +
> +#define vring_used_event( vr ) ( ( vr )->avail->ring[ ( vr )->num ] )
> +#define vring_avail_event( vr ) ( *(uint16_t *) &( vr )->used->ring[ ( vr
> )-> \
> + num ]
> )
> +#define vring_need_event( event_idx, new_idx, old ) \
> + ( (uint16_t) ( new_idx - event_idx - 1 ) < (uint16_t) ( new_idx - old )
> )
> +
> +/* VirtIO PCI vendor/device ID. */
> +#define VIRTIO_VENDOR_ID 0x1AF4
> +#define VIRTIO_DEVICE_ID_MIN 0x1000
> +#define VIRTIO_DEVICE_ID_MAX 0x1040
> +
> +#define VRING_DESC_F_NEXT 1
> +#define VRING_DESC_F_WRITE 2
> +#define VRING_DESC_F_INDIRECT 4
> +#define VRING_USED_F_NO_NOTIFY 1
> +#define VRING_AVAIL_F_NO_INTERRUPT 1
> +
> +#define VQ_RING_DESC_CHAIN_END 32768
> +
> +typedef enum {
> + VQ_POSTPONE_SHORT,
> + VQ_POSTPONE_LONG,
> + VQ_POSTPONE_EMPTIED
> +} vq_postpone_t;
> +
> +struct vring_desc {
> + uint64_t addr;
> + uint32_t len;
> + uint16_t flags;
> + uint16_t next;
> +};
> +
> +struct vring_avail {
> + uint16_t flags;
> + uint16_t idx;
> + uint16_t ring[];
> +};
> +
> +struct vring_used_elem {
> + uint32_t id;
> + uint32_t len;
> +};
> +
> +struct vring_used {
> + uint16_t flags;
> + uint16_t idx;
> + struct vring_used_elem ring[];
> +};
> +
> +struct vring {
> + unsigned int num;
> + struct vring_desc *desc;
> + struct vring_avail *avail;
> + struct vring_used *used;
> +};
> +
> +struct vq_desc_extra {
> + void *cookie;
> + struct vring_desc *indirect;
> + uint32_t indirect_paddr;
> + uint16_t ndescs;
> +};
> +
> +struct virtqueue {
> + uint16_t vq_queue_index;
> + uint16_t vq_nentries;
> + uint32_t vq_flags;
> +
> + uint16_t vq_free_cnt;
> + uint16_t vq_queued_cnt;
> +
> + int vq_alignment;
> + int vq_ring_size;
> +
> + struct vring vq_ring;
> + void *vq_ring_mem;
> + int vq_max_indirect_size;
> + int vq_indirect_mem_size;
> +
> + uint16_t vq_desc_head_idx;
> + uint16_t vq_used_cons_idx;
> +
> + struct vq_desc_extra vq_descx[ 0 ];
> +};
> +
> +void *virtqueue_dequeue(
> + struct virtqueue *vq,
> + uint32_t *len
> +);
> +void *virtqueue_drain(
> + struct virtqueue *vq,
> + int *last
> +);
> +void virtqueue_disable_intr( struct virtqueue *vq );
> +int virtqueue_postpone_intr(
> + struct virtqueue *vq,
> + vq_postpone_t hint
> +);
> +
> +void vq_ring_init( struct virtqueue *vq );
> +void vq_ring_free_chain(
> + struct virtqueue *vq,
> + uint16_t desc_idx
> +);
> +void vq_ring_update_avail(
> + struct virtqueue *vq,
> + uint16_t desc_idx
> +);
> +int vq_ring_must_notify_host( struct virtqueue *vq );
> +int vq_ring_enable_interrupt(
> + struct virtqueue *vq,
> + uint16_t ndesc
> +);
> +
> +#endif /* _VIRTIO_H_ */
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c
> b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c
> new file mode 100644
> index 0000000..8ba9365
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c
> @@ -0,0 +1,176 @@
> +/**
> + * @file virtio_pci.c
> + * @brief Driver for the virtio PCI interface
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice unmodified, this list of conditions, and the following
> + * disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +/* Driver for the VirtIO PCI interface. */
> +
> +#ifdef __i386__
> +
> +#include <rtems.h>
> +#include <rtems/rtems_bsdnet.h>
> +#include <bsp.h>
> +
> +#include <pcibios.h>
> +
> +#include "virtio.h"
> +#include "virtio_pci.h"
> +
> +__inline uint8_t vtpci_io_read_1(
> + struct vtpci_softc *sc,
> + int reg
> +)
> +{
> + uint8_t val;
> +
> + inport_byte( sc->pci_io_base + reg, val );
> +
> + return val;
> +}
> +__inline uint16_t vtpci_io_read_2(
> + struct vtpci_softc *sc,
> + int reg
> +)
> +{
> + uint16_t val;
> +
> + inport_word( sc->pci_io_base + reg, val );
> +
> + return val;
> +}
> +__inline uint32_t vtpci_io_read_4(
> + struct vtpci_softc *sc,
> + int reg
> +)
> +{
> + uint32_t val;
> +
> + inport_long( sc->pci_io_base + reg, val );
> +
> + return val;
> +}
> +__inline void vtpci_io_write_1(
> + struct vtpci_softc *sc,
> + int reg,
> + uint8_t val
> +)
> +{
> + outport_byte( sc->pci_io_base + reg, val );
> +}
> +__inline void vtpci_io_write_2(
> + struct vtpci_softc *sc,
> + int reg,
> + uint16_t val
> +)
> +{
> + outport_word( sc->pci_io_base + reg, val );
> +}
> +__inline void vtpci_io_write_4(
> + struct vtpci_softc *sc,
> + int reg,
> + uint32_t val
> +)
> +{
> + outport_long( sc->pci_io_base + reg, val );
> +}
> +
> +int vtpci_attach(
> + struct rtems_bsdnet_ifconfig *config,
> + struct vtpci_softc *sc
> +)
> +{
> + int i, ret;
> + uint8_t val8;
> + uint16_t val16;
> + uint32_t val32;
> +
> + /* Parse NIC_NAME & Init structures */
> + if ( ( sc->unit_number =
> + rtems_bsdnet_parse_driver_name( config, &sc->unit_name ) ) < 0
> )
> {
> + return 0;
> + }
> +
> + /* Find device on pci bus */
> + {
> + int pbus, pdev, pfun;
> +
> + for ( i = VIRTIO_DEVICE_ID_MIN; i < VIRTIO_DEVICE_ID_MAX; i++ ) {
> + ret = pci_find_device( VIRTIO_VENDOR_ID, i, sc->unit_number,
> + &pbus, &pdev, &pfun );
> +
> + if ( ret == PCIB_ERR_SUCCESS ) {
> + sc->pci_signature = PCIB_DEVSIG_MAKE( pbus, pdev, pfun );
> + break;
> + }
> + }
> + }
> +
> + /* Enable bus matering */
> + pcib_conf_read16( sc->pci_signature, PCI_COMMAND, &val16 );
> + val16 |= PCI_COMMAND_MASTER;
> + pcib_conf_write16( sc->pci_signature, PCI_COMMAND, val16 );
> +
> + /* Set latency timer */
> + pcib_conf_read8( sc->pci_signature, PCI_LATENCY_TIMER, &val8 );
> + val8 |= 0x00;
> + pcib_conf_write8( sc->pci_signature, PCI_LATENCY_TIMER, val8 );
> +
> + /* Get IO Address */
> + pcib_conf_read32( sc->pci_signature, PCI_BASE_ADDRESS_0, &val32 );
> + val32 &= PCI_BASE_ADDRESS_IO_MASK;
> + sc->pci_io_base = val32;
> +
> + return 0;
> +}
> +
> +void vtpci_notify(
> + struct vtpci_softc *sc,
> + struct virtqueue *vq
> +)
> +{
> + mb();
> +
> + if ( vq_ring_must_notify_host( vq ) ) {
> + vtpci_io_write_2( sc, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index );
> + }
> +
> + vq->vq_queued_cnt = 0;
> +}
> +
> +#endif /* __i386__ */
> diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h
> b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h
> new file mode 100644
> index 0000000..7d0db9e
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h
> @@ -0,0 +1,131 @@
> +/**
> + * @file virtio_pci.h
> + * @brief Header for virtio_pci.c
> + */
> +
> +/*
> + * Copyright (c) 2016 Jin-Hyun Kim <jinhyun at konkuk.ac.kr>
> + * and Hyun-Wook Jin <jinh at konkuk.ac.kr>
> + * Ported from FreeBSD to RTEMS March 16, http://sslab.konkuk.ac.kr
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +/*-
> + * Copyright IBM Corp. 2007
> + *
> + * Authors:
> + * Anthony Liguori <aliguori at us.ibm.com>
> + *
> + * This header is BSD licensed so anyone can use the definitions to
> implement
> + * compatible drivers/servers.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of IBM nor the names of its contributors
> + * may be used to endorse or promote products derived from this
> software
> + * without specific prior written permission.
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED
> + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR
> + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE
> LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY `
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD: release/10.0.0/sys/dev/virtio/pci/virtio_pci.h 238360
> 2012-07-11 02:57:19Z grehan $
> + */
> +
> +#ifndef _VIRTIO_PCI_H_
> +#define _VIRTIO_PCI_H_
> +
> +/* VirtIO Header, located in BAR 0. */
> +#define VIRTIO_PCI_HOST_FEATURES 0 /* host's supported features (32bit,
> RO)*/
> +#define VIRTIO_PCI_GUEST_FEATURES 4 /* guest's supported features (32,
> RW)
> */
> +#define VIRTIO_PCI_QUEUE_PFN 8 /* physical address of VQ (32, RW) */
> +#define VIRTIO_PCI_QUEUE_NUM 12 /* number of ring entries (16, RO) */
> +#define VIRTIO_PCI_QUEUE_SEL 14 /* current VQ selection (16, RW) */
> +#define VIRTIO_PCI_QUEUE_NOTIFY 16 /* notify host regarding VQ (16, RW)
> */
> +#define VIRTIO_PCI_STATUS 18 /* device status register (8, RW) */
> +#define VIRTIO_PCI_ISR 19 /* interrupt status register, reading
> */
> +#define VIRTIO_MSI_CONFIG_VECTOR 20
> +#define VIRTIO_MSI_QUEUE_VECTOR 22
> +
> +#define VIRTIO_PCI_QUEUE_SEL_RX 0
> +#define VIRTIO_PCI_QUEUE_SEL_TX 1
> +
> +#define VIRTIO_PCI_ISR_INTR 0x1
> +#define VIRTIO_PCI_ISR_CONFIG 0x2
> +
> +#define VIRTIO_MSI_NO_VECTOR 0xFFFF
> +
> +/* How many bits to shift physical queue address written to QUEUE_PFN */
> +#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
> +
> +/* The alignment to use between consumer and producer parts of vring */
> +#define VIRTIO_PCI_VRING_ALIGN 4096
> +
> +/* Status byte for guest to report progress. */
> +#define VIRTIO_CONFIG_STATUS_RESET 0x00
> +#define VIRTIO_CONFIG_STATUS_ACK 0x01
> +#define VIRTIO_CONFIG_STATUS_DRIVER 0x02
> +#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
> +#define VIRTIO_CONFIG_STATUS_FAILED 0x80
> +
> +struct vtpci_softc {
> + int unit_number;
> + char *unit_name;
> +
> + int pci_signature;
> + uint32_t pci_io_base;
> +};
> +
> +__inline uint8_t vtpci_io_read_1(
> + struct vtpci_softc *sc,
> + int reg
> +);
> +__inline uint16_t vtpci_io_read_2(
> + struct vtpci_softc *sc,
> + int reg
> +);
> +__inline uint32_t vtpci_io_read_4(
> + struct vtpci_softc *sc,
> + int reg
> +);
> +__inline void vtpci_io_write_1(
> + struct vtpci_softc *sc,
> + int reg,
> + uint8_t val
> +);
> +__inline void vtpci_io_write_2(
> + struct vtpci_softc *sc,
> + int reg,
> + uint16_t val
> +);
> +__inline void vtpci_io_write_4(
> + struct vtpci_softc *sc,
> + int reg,
> + uint32_t val
> +);
> +int vtpci_attach(
> + struct rtems_bsdnet_ifconfig *config,
> + struct vtpci_softc *sc
> +);
> +void vtpci_notify(
> + struct vtpci_softc *sc,
> + struct virtqueue *vq
> +);
> +
> +#endif /* _VIRTIO_PCI_H_ */
>
>
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20160329/de950465/attachment-0002.html>
More information about the devel
mailing list