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