[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