Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Updated NE2000 and RTL8139 to conform to interface changes
[palacios.git] / palacios / src / devices / rtl8139.c
index 2867208..0a1a335 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#include <devices/ethernet.h>
 #include <devices/pci.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_types.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_ethernet.h>
+#include <palacios/vmm_sprintf.h>
 
 
-#ifndef CONFIG_DEBUG_RTL8139
+
+#ifndef V3_CONFIG_DEBUG_RTL8139
 #undef PrintDebug
 #define PrintDebug(fmts, args...)
 #endif
 
-
-
-#define NIC_BASE_ADDR  0xc100
-#define NIC_IRQ                11
-
-#define RTL8139_IDR0    (0x00)         /* ID Registers */
-#define RTL8139_IDR1    (0x01)
-#define RTL8139_IDR2    (0x02)
-#define RTL8139_IDR3    (0x03)
-#define RTL8139_IDR4    (0x04)
-#define RTL8139_IDR5    (0x05)
-
-#define RTL8139_MAR0    (0x08) /* Mulicast Registers*/
-#define RTL8139_MAR1    (0x09)
-#define RTL8139_MAR2    (0x0a)
-#define RTL8139_MAR3    (0x0b)
-#define RTL8139_MAR4    (0x0c)
-#define RTL8139_MAR5    (0x0d)
-#define RTL8139_MAR6    (0x0e)
-#define RTL8139_MAR7    (0x0f)
+#define RTL8139_IDR0    (0x00) /* ID Registers start, len 6*1bytes */
+#define RTL8139_MAR0    (0x08) /* Mulicast Registers start, len 8*1bytes */
 
 #define RTL8139_TSD0    (0x10) /* Tx Status of Descriptors */
 #define RTL8139_TSD1    (0x14)
@@ -83,7 +67,7 @@
 #define RTL8139_CONFIG4 (0x5a)
 #define RTL8139_MULINT  (0x5c) /* Multiple Intrpt Select */
 #define RTL8139_RERID   (0x5e) 
-#define RTL8139_TSAD    (0x60) /* Tx Status of All Descriptors */
+#define RTL8139_TXSAD    (0x60)        /* Tx Status of All Descriptors */
 #define RTL8139_BMCR    (0x62) /* Basic Mode Control Register */
 #define RTL8139_BMSR    (0x64) /* Basic Mode Status Register */
 #define RTL8139_ANAR    (0x66) /* Auto-Negotiation Advertisement Register */
 #define RTL8139_TW_PARM (0x7c) /* Twister parameter */
 #define RTL8139_PHY2_PARM   (0x80)
 
-#define RTL8139_CRC0    (0x84) /* Power Management CRC Reg for wakeup frame */
-#define RTL8139_CRC1    (0x85)
-#define RTL8139_CRC2    (0x86)
-#define RTL8139_CRC3    (0x87)
-#define RTL8139_CRC4    (0x88)
-#define RTL8139_CRC5    (0x89)
-#define RTL8139_CRC6    (0x8a)
-#define RTL8139_CRC7    (0x8b)
+#define RTL8139_CRC0    (0x84) /* Power Management CRC Reg for wakeup frame 8*1bytes */
 
 #define RTL8139_Wakeup0        (0x8c)  /* Power Management wakeup frame */
 #define RTL8139_Wakeup1        (0x94)
 
 typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
 
-enum TxStatusBits
-{
-    TSD_Own = 0x2000,
-    TSD_Tun = 0x4000,
-    TSD_Tok = 0x8000,
-    TSD_Cdh = 0x10000000,
-    TSD_Owc = 0x20000000,
-    TSD_Tabt = 0x40000000,
-    TSD_Crs = 0x80000000,
+enum TxStatusBits {
+    TSD_Own = 1<<13,
+    TSD_Tun = 1<<14,
+    TSD_Tok = 1<<15,
+    TSD_Cdh = 1<<28,
+    TSD_Owc = 1<<29,
+    TSD_Tabt = 1<<30,
+    TSD_Crs = 1<<31,
 };
 
+/* Transmit Status Register (TSD0-3) Offset: 0x10-0x1F */
+struct tx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t size     : 13;
+           uint8_t own     : 1;
+           uint8_t tun     : 1;
+           uint8_t tok     : 1;        
+           uint8_t er_tx_th   : 6;
+           uint8_t reserved    : 2;
+           uint8_t ncc            : 4;
+           uint8_t cdh : 1;
+           uint8_t owc : 1;
+           uint8_t tabt        : 1;
+           uint8_t crs : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 enum RxStatusBits {
-    Rx_Multicast = 0x8000,
-    Rx_Physical = 0x4000,
-    Rx_Broadcast = 0x2000,
-    Rx_BadSymbol = 0x0020,
-    Rx_Runt = 0x0010,
-    Rx_TooLong = 0x0008,
-    Rx_CRCErr = 0x0004,
-    Rx_BadAlign = 0x0002,
-    Rx_StatusOK = 0x0001,
+    Rx_Multicast = 1<<15,
+    Rx_Physical = 1<<14,
+    Rx_Broadcast = 1<<13,
+    Rx_BadSymbol = 1<<5,
+    Rx_Runt = 1<<4,
+    Rx_TooLong = 1<<3,
+    Rx_CRCErr = 1<<2,
+    Rx_BadAlign = 1<<1,
+    Rx_OK = 1<<0,
 };
 
 
+/* Receive Status Register in RX Packet Header */
+struct rx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t rx_ok     : 1;
+           uint16_t rx_bad_align     : 1;
+           uint16_t rx_crc_err     : 1;
+           uint16_t rx_too_long     : 1;       
+           uint16_t rx_runt    : 1;
+           uint16_t rx_bad_sym : 1;
+           uint16_t reserved   : 7;
+           uint16_t rx_brdcast : 1;
+           uint16_t rx_phys    : 1;
+           uint16_t rx_multi   : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+/* ERSR - Early Rx Status Register Offset: 0x36*/
+struct errx_status_reg{
+    union {
+       uint8_t val;
+       struct {
+           uint8_t er_rx_ok     : 1;
+           uint8_t er_rx_ovw     : 1;
+           uint8_t er_rx_bad_pkt     : 1;
+           uint8_t er_rx_good     : 1; 
+           uint8_t reserved    : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 /* Transmit Status of All Descriptors (TSAD) Register */
 enum TSAD_bits {
- TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
- TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
- TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
- TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
- TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
- TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
- TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
- TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
- TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
- TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
- TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
- TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
- TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
- TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
- TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
- TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
+    TSAD_TOK3 = 1<<15, /* TOK bits of Descriptors*/
+    TSAD_TOK2 = 1<<14, 
+    TSAD_TOK1 = 1<<13, 
+    TSAD_TOK0 = 1<<12, 
+    TSAD_TUN3 = 1<<11, /* TUN bits of Descriptors */
+    TSAD_TUN2 = 1<<10, 
+    TSAD_TUN1 = 1<<9, 
+    TSAD_TUN0 = 1<<8,
+    TSAD_TABT3 = 1<<7, /* TABT bits of Descriptors */
+    TSAD_TABT2 = 1<<6,
+    TSAD_TABT1 = 1<<5,
+    TSAD_TABT0 = 1<<4,
+    TSAD_OWN3 = 1<<3, /* OWN bits of Descriptors */
+    TSAD_OWN2 = 1<<2,
+    TSAD_OWN1 = 1<<1, 
+    TSAD_OWN0 = 1<<0,
 };
 
-enum ISRBits
-{
-    ISR_Rok = 0x1,
-    ISR_Rer = 0x2,
-    ISR_Tok = 0x4,
-    ISR_Ter = 0x8,
-    ISR_Rxovw = 0x10,
-    ISR_Pun = 0x20,
-    ISR_Fovw = 0x40,
-    ISR_Lenchg = 0x2000,
-    ISR_Timeout = 0x4000,
-    ISR_Serr = 0x8000,
+
+/* Transmit Status of All Descriptors (TSAD) Register Offset: 0x60-0x61*/
+struct txsad_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t own0     : 1;
+           uint8_t own1     : 1;
+           uint8_t own2     : 1;
+           uint8_t own3     : 1;       
+           uint8_t tabt0       : 1;
+           uint8_t tabt1       : 1;
+           uint8_t tabt2       : 1;
+           uint8_t tabt3       : 1;
+           uint8_t tun0        : 1;
+           uint8_t tun1        : 1;
+           uint8_t tun2        : 1;
+           uint8_t tun3        : 1;
+           uint8_t tok0        : 1;
+           uint8_t tok1        : 1;
+           uint8_t tok2        : 1;
+           uint8_t tok3        : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+enum ISRBits {
+    ISR_Rok = 1<<0,
+    ISR_Rer = 1<<1,
+    ISR_Tok = 1<<2,
+    ISR_Ter = 1<<3,
+    ISR_Rxovw = 1<<4,
+    ISR_Pun = 1<<5,
+    ISR_Fovw = 1<<6,
+    ISR_Lenchg = 1<<13,
+    ISR_Timeout = 1<<14,
+    ISR_Serr = 1<<15,
 };
 
-enum CMDBits
-{
-    CMD_Bufe = 0x1,
-    CMD_Te = 0x4,
-    CMD_Re = 0x8,
-    CMD_Rst = 0x10,
+/* 
+ * Interrupt Status Register (ISR) Offset: ox3e-0x3f
+ * Interrupt Mask Register (IMR 0x3c-0x3d) shares the same structure
+ */
+struct isr_imr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t rx_ok      :1;
+           uint16_t rx_err     : 1;
+           uint16_t tx_ok        : 1;
+           uint16_t tx_err          : 1;
+           uint16_t rx_ovw          : 1;
+           uint16_t pun_linkchg          : 1;
+           uint16_t rx_fifo_ovw  : 1;
+           uint16_t reservd:     6;
+           uint16_t lenchg  :1;
+           uint16_t timeout   :1;
+           uint16_t syserr  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+enum CMDBits {
+    CMD_Bufe = 1<<0,
+    CMD_Te = 1<<2,
+    CMD_Re = 1<<3,
+    CMD_Rst = 1<<4,
 };
 
+
+/* Commmand Register Offset: 0x37 */
+struct cmd_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t cmd_bufe      : 1;
+           uint8_t reservd_1        : 1;
+           uint8_t cmd_te          : 1;
+           uint8_t cmd_re          : 1;
+           uint8_t cmd_rst          : 1;
+           uint8_t reservd_2  : 3;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 enum CMD9346Bits {
-       CMD9346_Lock = 0x00,
-       CMD9346_Unlock = 0xC0,
+    CMD9346_Lock = 0x00,
+    CMD9346_Unlock = 0xC0,
 };
 
+
+
+/* 93C46 Commmand Register Offset: 0x50 */
+struct cmd9346_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t eedo      : 1;
+           uint8_t eedi        : 1;
+           uint8_t eesk          : 1;
+           uint8_t eecs          : 1;
+           uint8_t reserved    : 2;
+           uint8_t eem  : 2;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
 // Bits in TxConfig.
 enum TXConfig_bits{
 
         /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
-      TxIFGShift = 24,
-      TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
-      TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
-      TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
-      TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
-
-       TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
-       TxCRC = (1 << 16),      /* DISABLE appending CRC to end of Tx packets */
-       TxClearAbt = (1 << 0),  /* Clear abort (WO) */
-       TxDMAShift = 8,         /* DMA burst value (0-7) is shifted this many bits */
-       TxRetryShift = 4,       /* TXRR value (0-15) is shifted this many bits */
-
-       TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+    TxIFGShift = 24,
+    TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+    TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+    TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+    TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
+    TxClearAbt = (1 << 0),     /* Clear abort (WO) */
+    TxDMAShift = 8,            /* DMA burst value (0-7) is shifted this many bits */
+    TxRetryShift = 4,  /* TXRR value (0-15) is shifted this many bits */
+
+    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
 };
 
+
+/* Transmit Configuration Register (TCR) Offset: 0x40-0x43 */
+struct tx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t clr_abort   :1;
+           uint8_t reserved_1     : 3;
+           uint8_t tx_retry_cnt        : 4;
+           uint8_t max_dma          : 3;
+           uint8_t reserved_2          : 5;
+           uint8_t tx_crc          : 1;
+           uint8_t loop_test  : 2;
+           uint8_t reservd_3:     3;
+           uint8_t hw_verid_b  :2;
+           uint8_t ifg   :2;
+           uint8_t hw_verid_a  :5;
+           uint8_t reservd_4  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 enum CSCRBits {
     CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
     CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
@@ -247,16 +391,68 @@ enum CSCRBits {
     CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
 };
 
+
+/* CS Configuration Register (CSCR) Offset: 0x74-0x75 */
+struct cscr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t pass_scr    :1;
+           uint8_t reserved_1     : 1;
+           uint8_t con_status_en        : 1;
+           uint8_t con_status          : 1;
+           uint8_t reserved_2          : 1;
+           uint8_t f_connect          : 1;
+           uint8_t f_link_100  : 1;
+           uint8_t jben:     1;
+           uint8_t heart_beat  :1;
+           uint8_t ld   :1;
+           uint8_t reservd_3  :5;
+           uint8_t test_fun  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 /* Bits in RxConfig. */
 enum rx_mode_bits {
-       AcceptErr = 0x20,
-       AcceptRunt = 0x10,
-       AcceptBroadcast = 0x08,
-       AcceptMulticast = 0x04,
-       AcceptMyPhys = 0x02,
-       AcceptAllPhys = 0x01,
+    AcceptErr = 0x20,
+    AcceptRunt = 0x10,
+    AcceptBroadcast = 0x08,
+    AcceptMulticast = 0x04,
+    AcceptMyPhys = 0x02,
+    AcceptAllPhys = 0x01,
 };
 
+
+/* Receive Configuration Register (RCR) Offset: 0x44-0x47 */
+struct rx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t all_phy   : 1;
+           uint8_t my_phy      : 1;
+           uint8_t all_multi     : 1;
+           uint8_t all_brdcast        : 1;
+           uint8_t acpt_runt          : 1;
+           uint8_t acpt_err          : 1;
+           uint8_t reserved_1          : 1;
+           uint8_t wrap  : 1;
+           uint8_t max_dma:     3;
+           uint8_t rx_buf_len  :2;
+           uint8_t rx_fifo_thresd   :3;
+           uint8_t rer8  :1;
+           uint8_t mul_er_intr  :1;
+           uint8_t reserved_2          : 6;
+           uint8_t eraly_rx_thresd   :4;
+           uint8_t reserved_3          : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 #define RTL8139_PCI_REVID_8139      0x10
 
 #define SET_MASKED(input, mask, curr) \
@@ -283,8 +479,7 @@ enum Chip9346Operation
     Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
 };
 
-enum Chip9346Mode
-{
+enum Chip9346Mode {
     Chip9346_none = 0,
     Chip9346_enter_command_mode,
     Chip9346_read_command,
@@ -293,8 +488,7 @@ enum Chip9346Mode
     Chip9346_data_write_all, /* to input register, then filling contents */
 };
 
-struct EEprom9346
-{
+struct EEprom9346 {
     uint16_t contents[EEPROM_9346_SIZE];
     int      mode;
     uint32_t tick;
@@ -361,8 +555,7 @@ struct rtl8139_regs {
 
 
 
-struct rtl8139_state
-{      
+struct rtl8139_state { 
     nic_state_t dev_state;
 
     struct v3_vm_info * vm;
@@ -385,55 +578,21 @@ struct rtl8139_state
     void * backend_data;
 };
 
-
-static void rtl8139_reset(struct vm_device *dev);
-
-static void dump_state(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    PrintDebug("====RTL8139: Dumping State Begin==========\n");
-    PrintDebug("Registers\n");
-    int i;
-    uchar_t *reg;
-       reg = (uchar_t *)&nic_state->regs;
-
-    for(i = 0; i < sizeof(struct nic_regs); i++)
-    {
-        PrintDebug("Register[%d] = 0x%2x\n", i, (int)reg[i]);
-    }
-
-    PrintDebug("====RTL8139: Dumping State End==========\n");
-}
-
-static void rtl8139_update_irq(struct rtl8139_state *nic_state)
-{
-    struct pci_device *pdev = nic_state->pci_dev;
-    int irq_line;
-
-    irq_line = pdev->configs[PCI_INTERRUPT_LINE];
+static inline void rtl8139_update_irq(struct rtl8139_state * nic_state) {
     int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0xffff);
 
-    if(isr & 0xffff)
-    {
-        if (irq_line != 0){
-               v3_raise_irq(dev->vm, irq_line);
-               PrintDebug("VNIC: RaiseIrq %d: isr: 0x%04x imr : 0x%04x\n", irq_line, nic_state->regs.isr, nic_state->regs.imr);
-        } else {
-             PrintError("RTL8139: IRQ_Line: %d\n", irq_line);
-        }
+    if(isr & 0xffff){
+       v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+       nic_state->statistic.tx_interrupts ++;
     }
 }
 
-#if 1
-
-static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
-{
+static void prom9346_decode_command(struct EEprom9346 * eeprom, uint8_t command) {
     PrintDebug("RTL8139: eeprom command 0x%02x\n", command);
 
-    switch (command & Chip9346_op_mask)
-    {
+    switch (command & Chip9346_op_mask) {
         case Chip9346_op_read:
-        {
+       {
             eeprom->address = command & EEPROM_9346_ADDR_MASK;
             eeprom->output = eeprom->contents[eeprom->address];
             eeprom->eedo = 0;
@@ -456,8 +615,7 @@ static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
         break;
         default:
             eeprom->mode = Chip9346_none;
-            switch (command & Chip9346_op_ext_mask)
-            {
+            switch (command & Chip9346_op_ext_mask) {
                 case Chip9346_op_write_enable:
                     PrintDebug("RTL8139: eeprom write enabled\n");
                     break;
@@ -468,23 +626,20 @@ static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
                     PrintDebug("RTL8139: eeprom write disabled\n");
                     break;
             }
-            break;
+        break;
     }
 }
 
-static void prom9346_shift_clock(struct EEprom9346 *eeprom)
-{
+static void prom9346_shift_clock(struct EEprom9346 * eeprom) {
     int bit = eeprom->eedi?1:0;
 
     ++ eeprom->tick;
 
     PrintDebug("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo);
 
-    switch (eeprom->mode)
-    {
+    switch (eeprom->mode) {
         case Chip9346_enter_command_mode:
-            if (bit)
-            {
+            if (bit) {
                 eeprom->mode = Chip9346_read_command;
                 eeprom->tick = 0;
                 eeprom->input = 0;
@@ -494,8 +649,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_read_command:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 8)
-            {
+            if (eeprom->tick == 8) {
                 prom9346_decode_command(eeprom, eeprom->input & 0xff);
             }
             break;
@@ -503,8 +657,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
         case Chip9346_data_read:
             eeprom->eedo = (eeprom->output & 0x8000)?1:0;
             eeprom->output <<= 1;
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16){
 #if 1
         // the FreeBSD drivers (rl and re) don't explicitly toggle
         // CS between reads (or does setting Cfg9346 to 0 count too?),
@@ -529,8 +682,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_data_write:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16) {
                 PrintDebug("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
                        eeprom->address, eeprom->input);
 
@@ -543,8 +695,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_data_write_all:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16) {
                 int i;
                 for (i = 0; i < EEPROM_9346_SIZE; i++)
                 {
@@ -564,20 +715,19 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
     }
 }
 
-static int prom9346_get_wire(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static int prom9346_get_wire(struct rtl8139_state * nic_state) {
     struct EEprom9346 *eeprom = &(nic_state->eeprom);
 
-    if (!eeprom->eecs)
+    if (eeprom->eecs == 0)
         return 0;
 
     return eeprom->eedo;
 }
 
-static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eedi)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static void prom9346_set_wire(struct rtl8139_state * nic_state, 
+                             int eecs, 
+                             int eesk, 
+                             int eedi) {
     struct EEprom9346 *eeprom = &(nic_state->eeprom);
     uint8_t old_eecs = eeprom->eecs;
     uint8_t old_eesk = eeprom->eesk;
@@ -589,8 +739,7 @@ static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eed
     PrintDebug("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
                  eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo);
 
-    if (!old_eecs && eecs)
-    {
+    if (old_eecs == 0 && eecs) {
         /* Synchronize start */
         eeprom->tick = 0;
         eeprom->input = 0;
@@ -600,23 +749,90 @@ static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eed
         PrintDebug("=== eeprom: begin access, enter command mode\n");
     }
 
-    if (!eecs)
-    {
+    if (eecs == 0) {
         PrintDebug("=== eeprom: end access\n");
         return;
     }
 
-    if (!old_eesk && eesk)
-    {
+    if (!old_eesk && eesk) {
         /* SK front rules */
         prom9346_shift_clock(eeprom);
     }
 }
 
-static void rtl8139_9346cr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
 
+static inline void rtl8139_reset_rxbuf(struct rtl8139_state * nic_state, uint32_t bufsize) {
+    nic_state->rx_bufsize = bufsize;
+    nic_state->regs.capr = 0;
+    nic_state->regs.cbr = 0;
+}
+
+
+static void rtl8139_reset(struct rtl8139_state *nic_state) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int i;
+
+    PrintDebug("Rtl8139: Reset\n");
+
+    /* restore MAC address */
+    memcpy(regs->id, nic_state->mac, ETH_ALEN);
+    memset(regs->mult, 0xff, 8);
+
+    rtl8139_update_irq(nic_state);
+
+    // prepare eeprom
+    nic_state->eeprom.contents[0] = 0x8129;
+       
+    // PCI vendor and device ID
+    nic_state->eeprom.contents[1] = 0x10ec;
+    nic_state->eeprom.contents[2] = 0x8139;
+    //Mac address
+    nic_state->eeprom.contents[7] = nic_state->mac[0] | nic_state->mac[1] << 8;
+    nic_state->eeprom.contents[8] = nic_state->mac[2] | nic_state->mac[3] << 8;
+    nic_state->eeprom.contents[9] = nic_state->mac[4] | nic_state->mac[5] << 8;
+
+    for (i = 0; i < 4; ++i) {
+        regs->tsd[i] = TSD_Own;
+    }
+
+    rtl8139_reset_rxbuf(nic_state, 1024*8);
+
+    /* ACK the reset */
+    regs->tcr = 0;
+
+    regs->tcr |= ((0x1d << 26) | (0x1 << 22)); // RTL-8139D
+    regs->rerid = RTL8139_PCI_REVID_8139;
+
+    regs->cmd = CMD_Rst; //RxBufEmpty bit is calculated on read from ChipCmd 
+
+    regs->config[0] = 0x0 | (1 << 4); // No boot ROM 
+    regs->config[1] = 0xC; //IO mapped and MEM mapped registers available
+    //regs->config[1] = 0x4; //Only IO mapped registers available
+    regs->config3[0] = 0x1; // fast back-to-back compatible
+    regs->config3[1] = 0x0;
+    regs->config5 = 0x0;
+       
+    regs->cscr = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+
+    //0x3100 : 100Mbps, full duplex, autonegotiation.  0x2100 : 100Mbps, full duplex
+    regs->bmcr = 0x1000; // autonegotiation
+
+    regs->bmsr  = 0x7809;
+    regs->bmsr |= 0x0020; // autonegotiation completed
+    regs->bmsr |= 0x0004; // link is up
+
+    regs->anar = 0x05e1;     // all modes, full duplex
+    regs->anlpar = 0x05e1;   // all modes, full duplex
+    regs->aner = 0x0001;     // autonegotiation supported
+
+    // reset timer and disable timer interrupt
+    regs->tctr = 0;
+    regs->timer_int = 0;
+}
+
+
+
+static void rtl8139_9346cr_write(struct rtl8139_state * nic_state, uint32_t val) {
     val &= 0xff;
 
     PrintDebug("RTL8139: 9346CR write val=0x%02x\n", val);
@@ -632,32 +848,26 @@ static void rtl8139_9346cr_write(struct vm_device *dev, uint32_t val)
         int eecs = (eeprom_val & 0x08)?1:0;
         int eesk = (eeprom_val & 0x04)?1:0;
         int eedi = (eeprom_val & 0x02)?1:0;
-        prom9346_set_wire(dev, eecs, eesk, eedi);
+        prom9346_set_wire(nic_state, eecs, eesk, eedi);
     } else if (opmode == 0x40) {
         /* Reset.  */
         val = 0;
-        rtl8139_reset(dev);
+        rtl8139_reset(nic_state);
     }
 
     nic_state->regs.cmd9346 = val;
 }
 
-static uint32_t rtl8139_9346cr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static uint32_t rtl8139_9346cr_read(struct rtl8139_state * nic_state) {
     uint32_t ret = nic_state->regs.cmd9346;
     uint32_t opmode = ret & 0xc0;
 
-    if (opmode == 0x80)
-    {
+    if (opmode == 0x80) {
         /* eeprom access */
-        int eedo = prom9346_get_wire(dev);
-        if (eedo)
-        {
+        int eedo = prom9346_get_wire(nic_state);
+        if (eedo){
             ret |=  0x01;
-        }
-        else
-        {
+        } else {
             ret &= ~0x01;
         }
     }
@@ -667,44 +877,34 @@ static uint32_t rtl8139_9346cr_read(struct vm_device *dev)
     return ret;
 }
 
-#endif
-
-static int rtl8139_receiver_enabled(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
 
+static inline int rtl8139_receiver_enabled(struct rtl8139_state * nic_state) {
     return nic_state->regs.cmd & CMD_Re;
 }
 
-static int rtl8139_rxwrap(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static inline int rtl8139_rxwrap(struct rtl8139_state * nic_state) {
     // wrapping enabled; assume 1.5k more buffer space if size < 64K
     return (nic_state->regs.rcr & (1 << 7));
 }
 
-static void rtl8139_rxbuf_write(struct vm_device *dev, const void *buf, int size)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static void rtl8139_rxbuf_write(struct rtl8139_state * nic_state, 
+                               const void * buf, 
+                               int size) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int wrap;
     addr_t guestpa, host_rxbuf;
 
     guestpa = (addr_t)regs->rbstart;
-    guest_pa_to_host_va(dev->vm, guestpa, &host_rxbuf);   
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), guestpa, &host_rxbuf);   
 
     //wrap to the front of rx buffer
-    if (regs->cbr + size > nic_state->rx_bufsize)
-    {
+    if (regs->cbr + size > nic_state->rx_bufsize){
         wrap = MOD2(regs->cbr + size, nic_state->rx_bufsize);
 
-        if (wrap && !(nic_state->rx_bufsize < 64*1024 && rtl8139_rxwrap(dev)))
-        {
+        if (wrap && !(nic_state->rx_bufsize < 64*1024 && rtl8139_rxwrap(nic_state))){
             PrintDebug("RTL8139: rx packet wrapped in buffer at %d\n", size-wrap);
 
-            if (size > wrap)
-            {
+            if (size > wrap){
                 memcpy((void *)(host_rxbuf + regs->cbr), buf, size-wrap);
             }
 
@@ -727,8 +927,7 @@ static void rtl8139_rxbuf_write(struct vm_device *dev, const void *buf, int size
 #define POLYNOMIAL 0x04c11db6
 
 /* From FreeBSD */
-static int compute_mcast_idx(const uint8_t *ep)
-{
+static inline int compute_mcast_idx(const uint8_t *ep) {
     uint32_t crc;
     int carry, i, j;
     uint8_t b;
@@ -740,94 +939,88 @@ static int compute_mcast_idx(const uint8_t *ep)
             carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
             crc <<= 1;
             b >>= 1;
-            if (carry)
+            if (carry){
                 crc = ((crc ^ POLYNOMIAL) | carry);
+           }
         }
     }
     return (crc >> 26);
 }
-static void vnic_receive(struct vm_device *dev, const uchar_t *pkt, uint_t length)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
+
+
+static int rx_one_pkt(struct rtl8139_state * nic_state, 
+                     uint8_t * pkt, 
+                     uint32_t len){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     uint_t rxbufsize = nic_state->rx_bufsize;
     uint32_t header, val;
     uint8_t bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
     if (regs->rcr & AcceptAllPhys) {
-        PrintDebug("RTL8139: packet received in promiscuous mode\n");
+       PrintDebug("RTL8139: packet received in promiscuous mode\n");
     } else {
-        if (!memcmp(pkt,  bcast_addr, 6)) {
-            if (!(regs->rcr & AcceptBroadcast))
-            {
-                PrintDebug("RTL8139: broadcast packet rejected\n");
-                return;
-            }
-            header |= Rx_Broadcast;
-            PrintDebug("RTL8139: broadcast packet received\n");
-        } else if (pkt[0] & 0x01) {
+       if (!memcmp(pkt,  bcast_addr, 6)) {
+           if (!(regs->rcr & AcceptBroadcast)){
+               PrintDebug("RTL8139: broadcast packet rejected\n");
+               return -1;
+           }
+           header |= Rx_Broadcast;
+           PrintDebug("RTL8139: broadcast packet received\n");
+       } else if (pkt[0] & 0x01) {
             // multicast
-            if (!(regs->rcr & AcceptMulticast))
-            {
+            if (!(regs->rcr & AcceptMulticast)){
                 PrintDebug("RTL8139: multicast packet rejected\n");
-                return;
+                return -1;
             }
 
             int mcast_idx = compute_mcast_idx(pkt);
 
-            if (!(regs->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
-            {
+            if (!(regs->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))){
                 PrintDebug("RTL8139: multicast address mismatch\n");
-                return;
+                return -1;
             }
             header |= Rx_Multicast;
             PrintDebug("RTL8139: multicast packet received\n");
-        } else if (regs->id[0] == pkt[0] &&
-                   regs->id[1] == pkt[1] &&
-                   regs->id[2] == pkt[2] &&
-                   regs->id[3] == pkt[3] &&
-                   regs->id[4] == pkt[4] &&
-                   regs->id[5] == pkt[5]) {
-            if (!(regs->rcr & AcceptMyPhys))
-            {
+        } else if (!compare_ethaddr(regs->id, pkt)){
+            if (!(regs->rcr & AcceptMyPhys)){
                 PrintDebug("RTL8139: rejecting physical address matching packet\n");
-                return;
+                return -1;
             }
 
             header |= Rx_Physical;
             PrintDebug("RTL8139: physical address matching packet received\n");
         } else {
             PrintDebug("RTL8139: unknown packet\n");
-            return;
+            return -1;
         }
     }
 
     if(1){
-        PrintDebug("RTL8139: in ring Rx mode\n");
+       PrintDebug("RTL8139: in ring Rx mode\n");
 
-        int avail = MOD2(rxbufsize + regs->capr - regs->cbr, rxbufsize);
+       int avail = MOD2(rxbufsize + regs->capr - regs->cbr, rxbufsize);
 
-        if (avail != 0 && length + 8 >= avail)
-        {
+        if (avail != 0 && len + 8 >= avail){
             PrintError("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
-                   rxbufsize, regs->cbr, regs->capr, avail, length + 8);
+                   rxbufsize, regs->cbr, regs->capr, avail, len + 8);
 
             regs->isr |= ISR_Rxovw;
             ++ regs->mpc;
-            rtl8139_update_irq(dev);
-            return;
+            rtl8139_update_irq(nic_state);
+            return -1;
         }
 
-        header |= Rx_StatusOK;
-        header |= ((length << 16) & 0xffff0000);
+        header |= Rx_OK;
+        header |= ((len << 16) & 0xffff0000);
 
-        rtl8139_rxbuf_write(dev, (uint8_t *)&header, 4);
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&header, 4);
 
-        rtl8139_rxbuf_write(dev, pkt, length);
+        rtl8139_rxbuf_write(nic_state, pkt, len);
 
-        val = V3_Crc32(0, (char *)pkt, length);
+        /* CRC checksum */
+        val = v3_crc32(0, pkt, len);
 
-        rtl8139_rxbuf_write(dev, (uint8_t *)&val, 4);
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&val, 4);
 
         // correct buffer write pointer 
         regs->cbr = MOD2((regs->cbr + 3) & ~0x3, rxbufsize);
@@ -838,48 +1031,43 @@ static void vnic_receive(struct vm_device *dev, const uchar_t *pkt, uint_t lengt
 
     regs->isr |= ISR_Rok;
 
-    nic_state->pkts_rcvd++;
+    nic_state->statistic.rx_pkts ++;
+    nic_state->statistic.rx_bytes += len;
        
-    rtl8139_update_irq(dev);   
+    rtl8139_update_irq(nic_state);   
+
+    return 0;
 }
 
-static int netif_input(uchar_t *pkt, uint_t size)
-{
-    PrintDebug("RTL8139: packet received!\n");
+static int rtl8139_rx(uint8_t * pkt, uint32_t len, void * private_data) {
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)private_data;
 
-    if (!rtl8139_receiver_enabled(current_vnic)){
-               PrintDebug("RTL8139: receiver disabled\n");
-               return 0;
+    if (!rtl8139_receiver_enabled(nic_state)){
+       PrintDebug("RTL8139: receiver disabled\n");
+       nic_state->statistic.rx_dropped ++;
+               
+       return 0;
+    }
+       
+    if(rx_one_pkt(nic_state, pkt, len) >= 0){
+       nic_state->statistic.rx_pkts ++;
+       nic_state->statistic.rx_bytes += len;
+    }else {
+       nic_state->statistic.rx_dropped ++;
     }
-    vnic_receive(current_vnic, pkt, size);
 
     return 0;
 }
 
-static void rtl8139_reset_rxbuf(struct vm_device *dev, uint32_t bufsize)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
-       
-    nic_state->rx_bufsize = bufsize;
-    regs->capr  = 0;
-    regs->cbr = 0;
-}
-
-static void rtl8139_rcr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static void rtl8139_rcr_write(struct rtl8139_state * nic_state, uint32_t val) {
     PrintDebug("RTL8139: RCR write val=0x%08x\n", val);
 
     val = SET_MASKED(val, 0xf0fc0040, nic_state->regs.rcr);
-
     nic_state->regs.rcr = val;
 
 #if 0
     uchar_t rblen = (regs->rcr >> 11) & 0x3;
-    switch(rblen)
-    {
+    switch(rblen) {
         case 0x0:
             rxbufsize = 1024 * 8 + 16;
             break;
@@ -896,100 +1084,11 @@ static void rtl8139_rcr_write(struct vm_device *dev, uint32_t val)
 #endif
 
     // reset buffer size and read/write pointers
-    rtl8139_reset_rxbuf(dev, 8192 << ((nic_state->regs.rcr >> 11) & 0x3));
+    rtl8139_reset_rxbuf(nic_state, 8192 << ((nic_state->regs.rcr >> 11) & 0x3));
 
     PrintDebug("RTL8139: RCR write reset buffer size to %d\n", nic_state->rx_bufsize);
 }
 
-static void rtl8139_reset(struct rtl8139_state *nic_state)
-{
-    struct rtl8139_regs *regs = &(nic_state->regs);
-    int i;
-
-    PrintDebug("Rtl8139: Reset\n");
-
-    /* restore MAC address */
-    memcpy(regs->id, nic_state->mac, ETH_ALEN);
-    memset(regs->mult, 0xff, 8);
-
-    regs->isr = 0;
-    regs->imr = 0;
-
-    rtl8139_update_irq(nic_state);
-
-    // prepare eeprom
-    nic_state->eeprom.contents[0] = 0x8129;
-       
-    // PCI vendor and device ID
-    nic_state->eeprom.contents[1] = 0x10ec;
-    nic_state->eeprom.contents[2] = 0x8139;
-    //Mac address
-    nic_state->eeprom.contents[7] = nic_state->mac[0] | nic_state->mac[1] << 8;
-    nic_state->eeprom.contents[8] = nic_state->mac[2] | nic_state->mac[3] << 8;
-    nic_state->eeprom.contents[9] = nic_state->mac[4] | nic_state->mac[5] << 8;
-
-    for (i = 0; i < 4; ++i)
-    {
-        regs->tsd[i] = TSD_Own;
-    }
-
-    regs->rbstart = 0;
-
-    rtl8139_reset_rxbuf(nic_state, 1024*8);
-
-    /* ACK the reset */
-    regs->tcr = 0;
-
-    regs->tcr |= ((0x1d << 26) | (0x1 << 22)); // RTL-8139D
-    regs->rerid = RTL8139_PCI_REVID_8139;
-
-    regs->cmd = CMD_Rst; //RxBufEmpty bit is calculated on read from ChipCmd 
-
-    regs->config[0] = 0x0 | (1 << 4); // No boot ROM 
-    regs->config[1] = 0xC; //IO mapped and MEM mapped registers available
-    //regs->config[1] = 0x4; //Only IO mapped registers available
-    regs->config3[0] = 0x1; // fast back-to-back compatible
-    regs->config3[1] = 0x0;
-    regs->config5 = 0x0;
-       
-    regs->cscr = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
-
-    //0x3100 : 100Mbps, full duplex, autonegotiation.  0x2100 : 100Mbps, full duplex
-    regs->bmcr = 0x1000; // autonegotiation
-
-    regs->bmsr  = 0x7809;
-    regs->bmsr |= 0x0020; // autonegotiation completed
-    regs->bmsr |= 0x0004; // link is up
-
-    regs->anar = 0x05e1;     // all modes, full duplex
-    regs->anlpar = 0x05e1;   // all modes, full duplex
-    regs->aner = 0x0001;     // autonegotiation supported
-
-    // reset timer and disable timer interrupt
-    regs->tctr = 0;
-    regs->timer_int = 0;
-
-    nic_state->pkts_rcvd = 0;
-}
-
-static void init_rtl8139_regs(struct rtl8139_state *nic_state)
-{
-    nic_state->regs.imr = 0x00;
-    nic_state->regs.tsd[0] = nic_state->regs.tsd[1] = nic_state->regs.tsd[2] = nic_state->regs.tsd[3] = TSD_Own;
-    nic_state->pkts_rcvd = 0;
-
-    int i;
-    for(i = 0; i < 6; i++)
-        nic_state->regs.id[i] = nic_state->mac_addr[i] = mac[i];
-    for(i = 0; i < 8; i++)
-        nic_state->regs.mult[i] = 0xff;
-
-    nic_state->regs.rerid = RTL8139_PCI_REVID_8139;
-    nic_state->regs.tcr |= ((0x1d << 26) | (0x1 << 22));
-
-    rtl8139_reset(dev);
-}
-
 
 #if 0
 
@@ -1009,69 +1108,40 @@ static int rtl8139_config_writeable(struct vm_device *dev)
 
 #endif
 
-static int rtl8139_transmitter_enabled(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static inline int transmitter_enabled(struct rtl8139_state * nic_state){
     return nic_state->regs.cmd & CMD_Te;
 }
 
-static bool rtl8139_rxbufempty(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static int rxbufempty(struct rtl8139_state * nic_state){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int unread;
 
     unread = MOD2(regs->cbr + nic_state->rx_bufsize - regs->capr, nic_state->rx_bufsize);
    
-    if (unread != 0)
-    {
+    if (unread != 0){
         PrintDebug("RTL8139: receiver buffer data available 0x%04x\n", unread);
-        return false;
+        return 0;
     }
 
     PrintDebug("RTL8139: receiver buffer is empty\n");
 
-    return true;
+    return 1;
 }
 
-static uint32_t rtl8139_cmd_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    uint32_t ret = nic_state->regs.cmd;
-
-    if (rtl8139_rxbufempty(dev))
-        ret |= CMD_Bufe;
-
-    PrintDebug("RTL8139: Cmd read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_cmd_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static void rtl8139_cmd_write(struct rtl8139_state * nic_state, uint32_t val){
     val &= 0xff;
 
     PrintDebug("RTL8139: Cmd write val=0x%08x\n", val);
 
-    if (val & CMD_Rst)
-    {
+    if (val & CMD_Rst){
         PrintDebug("RTL8139: Cmd reset\n");
-        rtl8139_reset(dev);
+        rtl8139_reset(nic_state);
     }
-    if (val & CMD_Re)
-    {
+    if (val & CMD_Re){
         PrintDebug("RTL8139: Cmd enable receiver\n");
-
-        //s->currCPlusRxDesc = 0;
     }
-    if (val & CMD_Te)
-    {
+    if (val & CMD_Te){
         PrintDebug("RTL8139: Cmd enable transmitter\n");
-
-        //s->currCPlusTxDesc = 0;
     }
 
     val = SET_MASKED(val, 0xe3, nic_state->regs.cmd);
@@ -1080,23 +1150,18 @@ static void rtl8139_cmd_write(struct vm_device *dev, uint32_t val)
     nic_state->regs.cmd = val;
 }
 
-static int rtl8139_send_packet(struct vm_device *dev, int descriptor)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static int tx_one_packet(struct rtl8139_state * nic_state, int descriptor){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int txsize;
     uint8_t *pkt;
     addr_t pkt_gpa = 0, hostva = 0;
-    int i;
 
-    if (!rtl8139_transmitter_enabled(dev))
-    {
+    if (!transmitter_enabled(nic_state)){
         PrintError("RTL8139: fail to send from descriptor %d: transmitter disabled\n", descriptor);
         return 0;
     }
 
-    if (regs->tsd[descriptor] & TSD_Own)
-    {
+    if (regs->tsd[descriptor] & TSD_Own){
         PrintError("RTL8139: fail to send from descriptor %d: owned by host\n", descriptor);
         return 0;
     }
@@ -1105,51 +1170,46 @@ static int rtl8139_send_packet(struct vm_device *dev, int descriptor)
     pkt_gpa = (addr_t) regs->tsad[descriptor];
 
     PrintDebug("RTL8139: sending %d bytes from guest memory at 0x%08x\n", txsize, regs->tsad[descriptor]);
-
-    guest_pa_to_host_va(dev->vm, (addr_t)pkt_gpa, &hostva);
+       
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), (addr_t)pkt_gpa, &hostva);
     pkt = (uchar_t *)hostva;
 
-    for(i = 0; i < txsize; i++)
-    {
-        PrintDebug("%x ", pkt[i]);
-    }
-    PrintDebug("\n");
+#ifdef V3_CONFIG_DEBUG_RTL8139
+    v3_hexdump(pkt, txsize, NULL, 0);
+#endif
 
-    if (TxLoopBack == (regs->tcr & TxLoopBack)){ //loopback test
+    if (TxLoopBack == (regs->tcr & TxLoopBack)){ /* loopback test */
         PrintDebug(("RTL8139: transmit loopback mode\n"));
-        vnic_receive(dev, pkt, txsize);
+        rx_one_pkt(nic_state, pkt, txsize);
     } else{       
-           if (V3_SEND_PKT(pkt, txsize) == 0){
-                PrintDebug("RTL8139: Sent %d bytes from descriptor %d\n", txsize, descriptor);
-           } else {
-               PrintError("Rtl8139: Sending packet error: 0x%p\n", pkt);
-           }
+        if (nic_state->net_ops->send(pkt, txsize, nic_state->backend_data) == 0){
+           PrintDebug("RTL8139: Sent %d bytes from descriptor %d\n", txsize, descriptor);
+           nic_state->statistic.tx_pkts ++;
+           nic_state->statistic.tx_bytes += txsize;
+       } else {
+           PrintError("Rtl8139: Sending packet error: 0x%p\n", pkt);
+           nic_state->statistic.tx_dropped ++;
+       }
     }
 
     regs->tsd[descriptor] |= TSD_Tok;
     regs->tsd[descriptor] |= TSD_Own;
 
     nic_state->regs.isr |= ISR_Tok;
-    rtl8139_update_irq(dev);
+    rtl8139_update_irq(nic_state);
 
     return 0;
 }
 
-//write to transmit status registers
-static void rtl8139_tsd_write(struct vm_device *dev, uint8_t descriptor, uint32_t val)
-{ 
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-#if 0
-    if (rtl8139_transmitter_enabled(dev))
-    {
-        PrintDebug("RTL8139: TxStatus write val=0x%08x descriptor=%d\n", val, descriptor);
-
-        nic_state->regs.tsd[descriptor] = val;
-
+/*transmit status registers*/
+static void rtl8139_tsd_write(struct rtl8139_state * nic_state, 
+                             uint8_t descriptor, 
+                             uint32_t val){ 
+    if (!transmitter_enabled(nic_state)){
+        PrintDebug("RTL8139: TxStatus write val=0x%08x descriptor=%d, Transmitter not enabled\n", val, descriptor);
+               
         return;
     }
-#endif
 
     PrintDebug("RTL8139: TSD write val=0x%08x descriptor=%d\n", val, descriptor);
 
@@ -1159,17 +1219,15 @@ static void rtl8139_tsd_write(struct vm_device *dev, uint8_t descriptor, uint32_
 
     nic_state->regs.tsd[descriptor] = val;
 
-    rtl8139_send_packet(dev, descriptor);
+    tx_one_packet(nic_state, descriptor);
 }
 
-//transmit status of all descriptors
-static uint16_t rtl8139_tsad_read(struct vm_device *dev)
-{
+/* transmit status of all descriptors */
+static uint16_t rtl8139_txsad_read(struct rtl8139_state * nic_state){
     uint16_t ret = 0;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+    struct rtl8139_regs *regs = &(nic_state->regs);
 
-    ret = ((regs->tsd[3] & TSD_Tok)?TSD_Tok:0)
+    ret = ((regs->tsd[3] & TSD_Tok)?TSAD_TOK3:0)
          |((regs->tsd[2] & TSD_Tok)?TSAD_TOK2:0)
          |((regs->tsd[1] & TSD_Tok)?TSAD_TOK1:0)
          |((regs->tsd[0] & TSD_Tok)?TSAD_TOK0:0)
@@ -1189,41 +1247,16 @@ static uint16_t rtl8139_tsad_read(struct vm_device *dev)
          |((regs->tsd[1] & TSD_Own)?TSAD_OWN1:0)
          |((regs->tsd[0] & TSD_Own)?TSAD_OWN0:0) ;
 
-
-    PrintDebug("RTL8139: tsad read val=0x%04x\n", (int)ret);
+    PrintDebug("RTL8139: txsad read val=0x%04x\n", (int)ret);
 
     return ret;
 }
 
-//interrupt mask register
-static void rtl8139_imr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-       
-    PrintDebug("RTL8139: IMR write val=0x%04x\n", val);
-
-    /* mask unwriteable bits */
-    val = SET_MASKED(val, 0x1e00, nic_state->regs.imr);
-
-    nic_state->regs.imr = val;
-
-    rtl8139_update_irq(dev);
-}
-
-static void rtl8139_isr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static inline void rtl8139_isr_write(struct rtl8139_state * nic_state, uint32_t val) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
 
     PrintDebug("RTL8139: ISR write val=0x%04x\n", val);
 
-#if 0
-
-    // writing to ISR has no effect
-
-    return;
-
-#else
     uint16_t newisr = regs->isr & ~val;
 
     /* mask unwriteable bits */
@@ -1231,767 +1264,498 @@ static void rtl8139_isr_write(struct vm_device *dev, uint32_t val)
 
     /* writing 1 to interrupt status register bit clears it */
     regs->isr = 0;
-    rtl8139_update_irq(dev);
+    rtl8139_update_irq(nic_state);
 
     regs->isr = newisr;
-    rtl8139_update_irq(dev);
-#endif
-}
-
-static uint32_t rtl8139_isr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    uint32_t ret = (uint32_t)nic_state->regs.isr;
-
-    PrintDebug("RTL8139: ISR read val=0x%04x\n", ret);
-
-#if 0
-    // reading ISR clears all interrupts
-    nic_state->regs.isr = 0;
-
-    rtl8139_update_irq(dev);
-
-#endif
-
-    return ret;
-}
-
-static void rtl8139_capr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    PrintDebug("RTL8139: CAPR write val=0x%04x\n", val);
-
-    // this value is off by 16
-    nic_state->regs.capr = MOD2(val + 0x10, nic_state->rx_bufsize);
-
-    PrintDebug("RTL 8139: CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
-           nic_state->rx_bufsize, nic_state->regs.cbr, nic_state->regs.capr);
-}
-
-static uint32_t rtl8139_capr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    /* this value is off by 16 */
-    uint32_t ret = nic_state->regs.capr - 0x10;
-
-    PrintDebug("RTL8139: CAPR read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-typedef enum {read, write} opr_t; 
-static bool need_hook(int port, opr_t op)
-{
-       if (op == read){ 
-               switch (port) {
-                       case RTL8139_IMR:
-                       case RTL8139_ISR:
-                               return true;
-                       default:
-                               break;
-               }
-       }
-       if (op == write){
-               switch (port) {
-                       case RTL8139_TSD0:
-                       case RTL8139_TSD1:
-                       case RTL8139_TSD2:
-                       case RTL8139_TSD3:
-                       case RTL8139_CR:
-                       case RTL8139_IMR:
-                       case RTL8139_ISR:
-                       case RTL8139_TCR:
-                       case RTL8139_RCR:
-                       case RTL8139_CSCR:
-                       case RTL8139_Config5:
-                               return true;
-                       default:
-                               break;
-               }
-       }
-       
-       return false;
+    rtl8139_update_irq(nic_state);
 }
 
-static int rtl8139_mmio_write(addr_t guest_addr, void * src, uint_t length, void * priv_data)
-{
-    int port;
+static int rtl8139_mmio_write(struct guest_info * core, 
+                             addr_t guest_addr, 
+                             void * src,
+                             uint_t length, 
+                             void * priv_data) {
+    int idx;
     uint32_t val;
-    struct vm_device *dev = (struct vm_device *)priv_data;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)(priv_data);
 
-    port = guest_addr & 0xff;
+    idx = guest_addr & 0xff;
 
     memcpy(&val, src, length);
 
     PrintDebug("rtl8139 mmio write: addr:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
        
-    switch(port) {
-           case RTL8139_IDR0:
-               nic_state->regs.id[0] = val & 0xff;
-               break;
-           case RTL8139_IDR1:
-               nic_state->regs.id[1] = val & 0xff;
-               break;
-           case RTL8139_IDR2:
-               nic_state->regs.id[2] = val & 0xff;
-               break;
-           case RTL8139_IDR3:
-               nic_state->regs.id[3] = val & 0xff;
-               break;
-           case RTL8139_IDR4:
-               nic_state->regs.id[4] = val & 0xff;
-               break;
-           case RTL8139_IDR5:
-               nic_state->regs.id[5] = val & 0xff;
-               break;
-           case RTL8139_MAR0:
-               nic_state->regs.mult[0] = val & 0xff;
-               break;
-           case RTL8139_MAR1:
-               nic_state->regs.mult[1] = val & 0xff;
-               break;
-           case RTL8139_MAR2:
-               nic_state->regs.mult[2] = val & 0xff;
-               break;
-           case RTL8139_MAR3:
-               nic_state->regs.mult[3] = val & 0xff;
-               break;
-           case RTL8139_MAR4:
-               nic_state->regs.mult[4] = val & 0xff;
-               break;
-           case RTL8139_MAR5:
-               nic_state->regs.mult[5] = val & 0xff;
-               break;
-           case RTL8139_MAR6:
-               nic_state->regs.mult[6] = val & 0xff;
-               break;
-           case RTL8139_MAR7:
-               nic_state->regs.mult[7] = val & 0xff;
-               break;
-           case RTL8139_TSD0:
-           case RTL8139_TSD1:
-           case RTL8139_TSD2:
-           case RTL8139_TSD3:
-               rtl8139_tsd_write(dev, (port - RTL8139_TSD0)/4, val);
-               break;
-           case RTL8139_TSAD0:
-           case RTL8139_TSAD1:
-           case RTL8139_TSAD2:
-           case RTL8139_TSAD3:
-               nic_state->regs.tsad[(port - RTL8139_TSAD0)/4] = val;
-               break;
-           case RTL8139_RBSTART:
-               nic_state->regs.rbstart = val;
-               break;
-           case RTL8139_ERBCR:
-               nic_state->regs.erbcr = val & 0xffff;
-               break;
-           case RTL8139_ERSR:
-               //nic_state->regs.ersr = val & 0xff;
-               nic_state->regs.ersr &= (~val) & 0x0c;
-               break;
-           case RTL8139_CR:
-                 rtl8139_cmd_write(dev, val);
-               break;
-           case RTL8139_CAPR:
-               rtl8139_capr_write(dev, val & 0xffff);
-               break;
-           case RTL8139_CBR: //this is read only =====
-               //nic_state->regs.cbr = val & 0xffff;
-               break;
-           case RTL8139_IMR:
-                 rtl8139_imr_write(dev, val);
-               break;
-           case RTL8139_ISR:
-               rtl8139_isr_write(dev, val);
-               break;
-           case RTL8139_TCR:
-               nic_state->regs.tcr = val;
-               break;
-           case RTL8139_RCR:
-               rtl8139_rcr_write(dev, val);
-                break;
-           case RTL8139_TCTR:
-               nic_state->regs.tctr = 0; //write clear current tick
-               break;
-           case RTL8139_MPC:
-               nic_state->regs.mpc = 0; //clear on write
-               break;
-           case RTL8139_9346CR:
-                 rtl8139_9346cr_write(dev, val);
-               break;
-           case RTL8139_CONFIG0:
-               nic_state->regs.config[0] = val & 0xff;
-               break;
-           case RTL8139_CONFIG1:
-               nic_state->regs.config[1] = val & 0xff;
-               break;
-           case RTL8139_TimerInt:
-               nic_state->regs.timer_int = val;
-               break;
-           case RTL8139_MSR:
-               nic_state->regs.msr = val & 0xff;
-               break;
-           case RTL8139_CONFIG3:
-               nic_state->regs.config3[0] = val & 0xff;
-               break;
-           case RTL8139_CONFIG4:
-               nic_state->regs.config3[1] = val & 0xff;
-               break;
-           case RTL8139_MULINT:
-               nic_state->regs.mulint = val & 0xffff;
-               break;
-           case RTL8139_RERID:
-               nic_state->regs.rerid = val & 0xffff;
-               break;
-           case RTL8139_TSAD:
-               nic_state->regs.txsad = val & 0xffff;
-               break;
-           case RTL8139_BMCR:
-               nic_state->regs.bmcr = val & 0xffff;
-               break;
-           case RTL8139_BMSR:
-               nic_state->regs.bmsr = val & 0xffff;
-               break;
-           case RTL8139_ANAR:
-               nic_state->regs.anar = val & 0xffff;
-               break;
-           case RTL8139_ANLPAR:
-               nic_state->regs.anlpar = val & 0xffff;
-               break;
-           case RTL8139_ANER:
-               nic_state->regs.aner = val & 0xffff;
-               break;
-           case RTL8139_DIS:
-               nic_state->regs.dis = val & 0xffff;
-               break;
-           case RTL8139_FCSC:
-               nic_state->regs.fcsc = val & 0xffff;
-               break;
-           case RTL8139_NWAYTR:
-               nic_state->regs.nwaytr = val & 0xffff;
-               break;
-           case RTL8139_REC:
-               nic_state->regs.rec = val & 0xffff;
-               break;
-           case RTL8139_CSCR:
-               nic_state->regs.cscr = val;
-               break;
-           case RTL8139_PHY1_PARM:
-               nic_state->regs.phy1_parm = val;
-               break;
-           case RTL8139_TW_PARM:
-               nic_state->regs.tw_parm = val & 0xffff;
-               break;
-           case RTL8139_PHY2_PARM:
-               nic_state->regs.phy2_parm = val;
-               break;
-           case RTL8139_CRC0:
-               nic_state->regs.crc[0] = val & 0xff;
-               break;
-           case RTL8139_CRC1:
-               nic_state->regs.crc[1] = val & 0xff;
-               break;
-           case RTL8139_CRC2:
-               nic_state->regs.crc[2] = val & 0xff;
-               break;
-           case RTL8139_CRC3:
-               nic_state->regs.crc[3] = val & 0xff;
-               break;
-           case RTL8139_CRC4:
-               nic_state->regs.crc[4] = val & 0xff;
-               break;
-           case RTL8139_CRC5:
-               nic_state->regs.crc[5] = val & 0xff;
-               break;
-           case RTL8139_CRC6:
-               nic_state->regs.crc[6] = val & 0xff;
-               break;
-           case RTL8139_CRC7:
-               nic_state->regs.crc[7] = val & 0xff;
-               break;
-           case RTL8139_Config5:
-               nic_state->regs.config5 = val & 0xff;
-               break;
-           default:
-               PrintDebug("rtl8139 write error: invalid port: 0x%x\n", port);
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           nic_state->regs.id[idx - RTL8139_IDR0] = val & 0xff;
+           break;
+
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           nic_state->regs.mult[idx - RTL8139_MAR0] = val & 0xff;
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           rtl8139_tsd_write(nic_state, (idx - RTL8139_TSD0)/4, val);
+           break;
+               
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4] = val;
+           break;
+               
+       case RTL8139_RBSTART:
+           nic_state->regs.rbstart = val;
+           break;
+       case RTL8139_ERBCR:
+           nic_state->regs.erbcr = val & 0xffff;
+           break;
+       case RTL8139_ERSR:
+           //nic_state->regs.ersr = val & 0xff;
+           nic_state->regs.ersr &= (~val) & 0x0c;
+           break;
+       case RTL8139_CR:
+           rtl8139_cmd_write(nic_state, val);
+           break;
+       case RTL8139_CAPR:
+       {
+           val &= 0xffff;
+           /* this value is off by 16 */
+           nic_state->regs.capr = MOD2(val + 0x10, nic_state->rx_bufsize);
+
+           PrintDebug("RTL 8139: CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+           nic_state->rx_bufsize, nic_state->regs.cbr, nic_state->regs.capr);  
+       }
+           break;
+       case RTL8139_CBR: /* read only */
+           //nic_state->regs.cbr = val & 0xffff;
+           break;
+       case RTL8139_IMR:
+       {
+           PrintDebug("RTL8139: IMR write val=0x%04x\n", val);
+
+           /* mask unwriteable bits */
+           val = SET_MASKED(val, 0x1e00, nic_state->regs.imr);
+           nic_state->regs.imr = val;
+           rtl8139_update_irq(nic_state);
+       }
+           break;
+       case RTL8139_ISR:
+           rtl8139_isr_write(nic_state, val);
+           break;
+       case RTL8139_TCR:
+           nic_state->regs.tcr = val;
+           break;
+       case RTL8139_RCR:
+           rtl8139_rcr_write(nic_state, val);
+           break;
+       case RTL8139_TCTR:
+           nic_state->regs.tctr = 0; /* write clear current tick */
+           break;
+       case RTL8139_MPC:
+           nic_state->regs.mpc = 0; /* clear on write */
+           break;
+       case RTL8139_9346CR:
+           rtl8139_9346cr_write(nic_state, val);
+           break;
+       case RTL8139_CONFIG0:
+           nic_state->regs.config[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG1:
+           nic_state->regs.config[1] = val & 0xff;
+           break;
+       case RTL8139_TimerInt:
+           nic_state->regs.timer_int = val;
+           break;
+       case RTL8139_MSR:
+           nic_state->regs.msr = val & 0xff;
+           break;
+       case RTL8139_CONFIG3:
+           nic_state->regs.config3[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG4:
+           nic_state->regs.config3[1] = val & 0xff;
+           break;
+               
+       case RTL8139_MULINT:
+           nic_state->regs.mulint = val & 0xffff;
+           break;
+       case RTL8139_RERID:
+           nic_state->regs.rerid = val & 0xffff;
+           break;
+       case RTL8139_TXSAD:
+           nic_state->regs.txsad = val & 0xffff;
+           break;
+       case RTL8139_BMCR:
+           nic_state->regs.bmcr = val & 0xffff;
+           break;
+       case RTL8139_BMSR:
+           nic_state->regs.bmsr = val & 0xffff;
+           break;
+       case RTL8139_ANAR:
+           nic_state->regs.anar = val & 0xffff;
+           break;
+       case RTL8139_ANLPAR:
+           nic_state->regs.anlpar = val & 0xffff;
+           break;
+       case RTL8139_ANER:
+           nic_state->regs.aner = val & 0xffff;
+           break;
+       case RTL8139_DIS:
+           nic_state->regs.dis = val & 0xffff;
+           break;
+       case RTL8139_FCSC:
+           nic_state->regs.fcsc = val & 0xffff;
+           break;
+       case RTL8139_NWAYTR:
+           nic_state->regs.nwaytr = val & 0xffff;
+           break;
+       case RTL8139_REC:
+           nic_state->regs.rec = val & 0xffff;
+           break;
+
+       case RTL8139_CSCR:
+           nic_state->regs.cscr = val;
+           break;
+       case RTL8139_PHY1_PARM:
+           nic_state->regs.phy1_parm = val;
+           break;
+       case RTL8139_TW_PARM:
+           nic_state->regs.tw_parm = val & 0xffff;
+           break;
+       case RTL8139_PHY2_PARM:
+           nic_state->regs.phy2_parm = val;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           nic_state->regs.crc[idx - RTL8139_CRC0] = val & 0xff;
+           break;
+
+       case RTL8139_Config5:
+           nic_state->regs.config5 = val & 0xff;
+           break;
+       default:
+           PrintDebug("rtl8139 write error: invalid port: 0x%x\n", idx);
        }
-
-       
-#if TEST_PERFORMANCE
-    if (need_hook(port, read))
-               io_hooked ++;
-    if (( ++io_total) % 50 == 0)
-        PrintError("RTL8139: Total IO: %d, Hooked: %d, INT: %d\n", io_total, io_hooked, int_total);
-#endif
         
     return length;
 }
 
-static int rtl8139_mmio_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data)
-{
-    ulong_t port;
+static int rtl8139_mmio_read(struct guest_info * core, 
+                            addr_t guest_addr, 
+                            void * dst, 
+                            uint_t length, 
+                            void * priv_data) {
+    uint16_t idx;
     uint32_t val;
-    struct vm_device *dev = (struct vm_device *)priv_data;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    port = guest_addr & 0xff;
-
-    switch(port) {
-           case RTL8139_IDR0:
-               val = nic_state->regs.id[0];
-               break;
-           case RTL8139_IDR1:
-               val = nic_state->regs.id[1];
-               break;
-           case RTL8139_IDR2:
-               val = nic_state->regs.id[2];
-               break;
-           case RTL8139_IDR3:
-               val = nic_state->regs.id[3];
-               break;
-           case RTL8139_IDR4:
-               val = nic_state->regs.id[4];
-               break;
-           case RTL8139_IDR5:
-               val = nic_state->regs.id[5];
-               break;
-           case RTL8139_MAR0:
-               val = nic_state->regs.mult[0];
-               break;
-           case RTL8139_MAR1:
-               val = nic_state->regs.mult[1];
-               break;
-           case RTL8139_MAR2:
-               val = nic_state->regs.mult[2];
-               break;
-           case RTL8139_MAR3:
-               val = nic_state->regs.mult[3];
-               break;
-           case RTL8139_MAR4:
-               val = nic_state->regs.mult[4];
-               break;
-           case RTL8139_MAR5:
-               val = nic_state->regs.mult[5];
-               break;
-           case RTL8139_MAR6:
-               val = nic_state->regs.mult[6];
-               break;
-           case RTL8139_MAR7:
-               val = nic_state->regs.mult[7];
-               break;
-           case RTL8139_TSD0:
-               val = nic_state->regs.tsd[0];
-               break;
-           case RTL8139_TSD1:
-               val = nic_state->regs.tsd[1];
-               break;
-           case RTL8139_TSD2:
-               val = nic_state->regs.tsd[2];
-               break;
-           case RTL8139_TSD3:
-               val = nic_state->regs.tsd[3];
-               break;
-           case RTL8139_TSAD0:
-               val = nic_state->regs.tsad[0];
-               break;
-           case RTL8139_TSAD1:
-               val = nic_state->regs.tsad[1];
-               break;
-           case RTL8139_TSAD2:
-               val = nic_state->regs.tsad[2];
-               break;
-           case RTL8139_TSAD3:
-               val = nic_state->regs.tsad[3];
-               break;
-           case RTL8139_RBSTART:
-               val = nic_state->regs.rbstart;
-               break;
-           case RTL8139_ERBCR:
-               val = nic_state->regs.erbcr;
-               break;
-           case RTL8139_ERSR:
-               val = nic_state->regs.ersr;
-               break;
-           case RTL8139_CR:
-               val = rtl8139_cmd_read(dev);
-               break;
-           case RTL8139_CAPR:
-               val = rtl8139_capr_read(dev);
-               break;
-           case RTL8139_CBR:
-               val = nic_state->regs.cbr;
-               break;
-           case RTL8139_IMR:
-               val = nic_state->regs.imr;
-               break;
-           case RTL8139_ISR:
-               val = rtl8139_isr_read(dev);
-               break;
-           case RTL8139_TCR:
-               val = nic_state->regs.tcr;
-               break;
-           case RTL8139_RCR:
-               val = nic_state->regs.rcr;
-               break;
-           case RTL8139_TCTR:
-               val = nic_state->regs.tctr;
-               break;
-           case RTL8139_MPC:
-               val = nic_state->regs.mpc;
-               break;
-           case RTL8139_9346CR:
-               val = rtl8139_9346cr_read(dev);
-               break;
-           case RTL8139_CONFIG0:
-               val = nic_state->regs.config[0];
-               break;
-           case RTL8139_CONFIG1:
-               val = nic_state->regs.config[1];
-               break;
-           case RTL8139_TimerInt:
-               val = nic_state->regs.timer_int;
-               break;
-           case RTL8139_MSR:
-               val = nic_state->regs.msr;
-               break;
-           case RTL8139_CONFIG3:
-               val = nic_state->regs.config3[0];
-               break;
-           case RTL8139_CONFIG4:
-               val = nic_state->regs.config3[1];
-               break;
-           case RTL8139_MULINT:
-               val = nic_state->regs.mulint;
-               break;
-           case RTL8139_RERID:
-               val = nic_state->regs.rerid;
-               break;
-           case RTL8139_TSAD: 
-               val = rtl8139_tsad_read(dev);
-               break;
-           case RTL8139_BMCR:
-               val = nic_state->regs.bmcr;
-               break;
-           case RTL8139_BMSR:
-               val = nic_state->regs.bmsr;
-               break;
-           case RTL8139_ANAR:
-               val = nic_state->regs.anar;
-               break;
-           case RTL8139_ANLPAR:
-               val = nic_state->regs.anlpar;
-               break;
-           case RTL8139_ANER:
-               val = nic_state->regs.aner;
-               break;
-           case RTL8139_DIS:
-               val = nic_state->regs.dis;
-               break;
-           case RTL8139_FCSC:
-               val = nic_state->regs.fcsc;
-               break;
-           case RTL8139_NWAYTR:
-               val = nic_state->regs.nwaytr;
-               break;
-           case RTL8139_REC:
-               val = nic_state->regs.rec;
-               break;
-           case RTL8139_CSCR:
-               val = nic_state->regs.cscr;
-               break;
-           case RTL8139_PHY1_PARM:
-               val = nic_state->regs.phy1_parm;
-               break;
-           case RTL8139_TW_PARM:
-               val = nic_state->regs.tw_parm;
-               break;
-           case RTL8139_PHY2_PARM:
-               val = nic_state->regs.phy2_parm;
-               break;
-           case RTL8139_CRC0:
-               val = nic_state->regs.crc[0];
-               break;
-           case RTL8139_CRC1:
-               val = nic_state->regs.crc[1];
-               break;
-           case RTL8139_CRC2:
-               val = nic_state->regs.crc[2];
-               break;
-           case RTL8139_CRC3:
-               val = nic_state->regs.crc[3];
-               break;
-           case RTL8139_CRC4:
-               val = nic_state->regs.crc[4];
-               break;
-           case RTL8139_CRC5:
-               val = nic_state->regs.crc[5];
-               break;
-           case RTL8139_CRC6:
-               val = nic_state->regs.crc[6];
-               break;
-           case RTL8139_CRC7:
-               val = nic_state->regs.crc[7];
-               break;
-           case RTL8139_Config5:
-               val = nic_state->regs.config5;
-               break;
-           default:
-                val = 0x0;
-                break;
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)priv_data;
+
+    idx = guest_addr & 0xff;
+
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           val = nic_state->regs.id[idx - RTL8139_IDR0];
+           break;
+               
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           val = nic_state->regs.mult[idx - RTL8139_MAR0];
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           val = nic_state->regs.tsd[(idx - RTL8139_TSD0)/4];
+           break;
+
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           val = nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4];
+           break;
+
+       case RTL8139_RBSTART:
+           val = nic_state->regs.rbstart;
+           break;
+       case RTL8139_ERBCR:
+           val = nic_state->regs.erbcr;
+           break;
+       case RTL8139_ERSR:
+           val = nic_state->regs.ersr;
+           break;
+       case RTL8139_CR:
+       {
+           val = nic_state->regs.cmd;
+           if (rxbufempty(nic_state)){
+               val |= CMD_Bufe;
+           }
+       }
+           break;
+       case RTL8139_CAPR:
+           /* this value is off by 16 -- don't know why - Lei*/
+           val = nic_state->regs.capr - 0x10;
+           break;
+       case RTL8139_CBR:
+           val = nic_state->regs.cbr;
+           break;
+       case RTL8139_IMR:
+           val = nic_state->regs.imr;
+           break;
+       case RTL8139_ISR:
+           val = (uint32_t)nic_state->regs.isr;
+           break;
+       case RTL8139_TCR:
+           val = nic_state->regs.tcr;
+           break;
+       case RTL8139_RCR:
+           val = nic_state->regs.rcr;
+           break;
+       case RTL8139_TCTR:
+           val = nic_state->regs.tctr;
+           break;
+       case RTL8139_MPC:
+           val = nic_state->regs.mpc;
+           break;
+       case RTL8139_9346CR:
+           val = rtl8139_9346cr_read(nic_state);
+           break;
+       case RTL8139_CONFIG0:
+           val = nic_state->regs.config[0];
+           break;
+       case RTL8139_CONFIG1:
+           val = nic_state->regs.config[1];
+           break;
+       case RTL8139_TimerInt:
+           val = nic_state->regs.timer_int;
+           break;
+       case RTL8139_MSR:
+           val = nic_state->regs.msr;
+           break;
+       case RTL8139_CONFIG3:
+           val = nic_state->regs.config3[0];
+           break;
+       case RTL8139_CONFIG4:
+           val = nic_state->regs.config3[1];
+           break;
+       case RTL8139_MULINT:
+           val = nic_state->regs.mulint;
+           break;
+       case RTL8139_RERID:
+           val = nic_state->regs.rerid;
+           break;
+       case RTL8139_TXSAD: 
+           val = rtl8139_txsad_read(nic_state);
+           break;
+       case RTL8139_BMCR:
+           val = nic_state->regs.bmcr;
+           break;
+       case RTL8139_BMSR:
+           val = nic_state->regs.bmsr;
+           break;
+       case RTL8139_ANAR:
+           val = nic_state->regs.anar;
+           break;
+       case RTL8139_ANLPAR:
+           val = nic_state->regs.anlpar;
+           break;
+       case RTL8139_ANER:
+           val = nic_state->regs.aner;
+           break;
+       case RTL8139_DIS:
+           val = nic_state->regs.dis;
+           break;
+       case RTL8139_FCSC:
+           val = nic_state->regs.fcsc;
+           break;
+       case RTL8139_NWAYTR:
+           val = nic_state->regs.nwaytr;
+           break;
+       case RTL8139_REC:
+           val = nic_state->regs.rec;
+           break;
+       case RTL8139_CSCR:
+           val = nic_state->regs.cscr;
+           break;
+       case RTL8139_PHY1_PARM:
+           val = nic_state->regs.phy1_parm;
+           break;
+       case RTL8139_TW_PARM:
+           val = nic_state->regs.tw_parm;
+           break;
+       case RTL8139_PHY2_PARM:
+           val = nic_state->regs.phy2_parm;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           val = nic_state->regs.crc[idx - RTL8139_CRC0];
+           break;
+       case RTL8139_Config5:
+           val = nic_state->regs.config5;
+           break;
+       default:
+           val = 0x0;
+           break;
     }
 
     memcpy(dst, &val, length);
        
     PrintDebug("rtl8139 mmio read: port:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
 
-#if TEST_PERFORMANCE
-    if (need_hook(port, read))
-               io_hooked ++;
-    if (( ++io_total) % 50 == 0)
-        PrintError("RTL8139: Total IO: %d, Hooked: %d, INT: %d\n", io_total, io_hooked, int_total);
-#endif
-
     return length;
 }
 
 
-static int rtl8139_ioport_write(struct guest_info * core, uint16_t port, void *src, uint_t length, void * private_data)
-{
-    PrintDebug("rtl8139 pio write: port:0x%x (%u bytes)\n", port, length);
-       
-    rtl8139_mmio_write((addr_t)port, src, length, private_data);
-       
-    return length;
+static int rtl8139_ioport_write(struct guest_info * core,
+                               uint16_t port, 
+                               void *src, 
+                               uint_t length, 
+                               void * private_data) {
+    return rtl8139_mmio_write(core, (addr_t)port, 
+                             src, length, private_data);
 }
 
-static int rtl8139_ioport_read(uint16_t port, void *dst, uint_t length, struct vm_device *dev)
-{
-    PrintDebug("rtl8139 pio read: port:0x%x (%u bytes)\n", port, length);
-
-    rtl8139_mmio_read((addr_t)port, dst, length, (void *)dev);
-    
-    return length;
+static int rtl8139_ioport_read(struct guest_info * core, 
+                              uint16_t port, 
+                              void *dst, 
+                              uint_t length, 
+                              void * private_data) {
+    return rtl8139_mmio_read(core, (addr_t)port, 
+                            dst, length, private_data);
 }
 
-static int rtl8139_reset_device(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd |= CMD_Rst;
-    init_rtl8139(dev);
-    regs->cmd &= ~CMD_Rst;
+
+static int rtl8139_init_state(struct rtl8139_state *nic_state) {
+    PrintDebug("rtl8139: init_state\n");
+       
+    nic_state->regs.tsd[0] = nic_state->regs.tsd[1] = nic_state->regs.tsd[2] = nic_state->regs.tsd[3] = TSD_Own;
+
+    nic_state->regs.rerid = RTL8139_PCI_REVID_8139;
+    nic_state->regs.tcr |= ((0x1d << 26) | (0x1 << 22));
+
+    rtl8139_reset(nic_state);
+
     return 0;
 }
 
-static int rtl8139_start_device(struct vm_device *dev)
-{
-    PrintDebug("rtl8139: start device\n");
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd |= CMD_Re | CMD_Te;
+
+#if 0
+static inline int rtl8139_reset_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Rst;
+    rtl8139_init_state(nic_state);
+    nic_state->regs.cmd &= ~CMD_Rst;
+       
     return 0;
 }
 
-static int rtl8139_stop_device(struct vm_device *dev)
-{
-    PrintDebug("rtl8139: stop device\n");
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd &= ~(CMD_Re | CMD_Te);
+static inline int rtl8139_start_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Re | CMD_Te;
+       
     return 0;
 }
 
-static void init_phy_network()
-{
-    V3_REGISTER_PKT_DELIVERY(&netif_input);
+static int rtl8139_stop_device(struct rtl8139_state * nic_state) {
+    PrintDebug("rtl8139: stop device\n");
+
+    nic_state->regs.cmd &= ~(CMD_Re | CMD_Te);
+       
+    return 0;
 }
 
-static int rtl8139_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data)
-{
+static int rtl8139_hook_iospace(struct rtl8139_state * nic_state, 
+                               addr_t base_addr, 
+                               int size, 
+                               int type, 
+                               void *data) {
     int i;
 
-    if (base_addr <= 0)
-    {
+    if (base_addr <= 0){
        PrintError("In RTL8139: Fail to Hook IO Space, base address 0x%x\n", (int) base_addr);
        return -1;
     }
 
-    if (type == PCI_ADDRESS_SPACE_IO){
+    if (type == PCI_BAR_IO){
        PrintDebug("In RTL8139: Hook IO ports starting from %x, size %d\n", (int) base_addr, size);
 
-       for (i = 0; i < 0xff; i++)
-       {       
-           v3_dev_hook_io(vmdev, base_addr + i, &rtl8139_ioport_read, &rtl8139_ioport_write);
+       for (i = 0; i < 0xff; i++){     
+           v3_dev_hook_io(nic_state->dev, base_addr + i, &rtl8139_ioport_read, &rtl8139_ioport_write);
        }
-    } else if (type == PCI_ADDRESS_SPACE_MEM) {
+    } else if (type == PCI_BAR_MEM32) {
        PrintDebug("In RTL8139: Hook memory space starting from %x, size %d\n", (int) base_addr, size);
        
        //hook memory mapped I/O        
-       v3_hook_full_mem(vmdev->vm, base_addr, base_addr + 0xff,
-                                     &rtl8139_mmio_read, &rtl8139_mmio_write, vmdev);
+       v3_hook_full_mem(nic_state->vm, nic_state->vm->cores[0].cpu_id, base_addr, base_addr + 0xff,
+                                     &rtl8139_mmio_read, &rtl8139_mmio_write, nic_state);
     } else {
        PrintError("In RTL8139: unknown memory type: start %x, size %d\n", (int) base_addr, size);
     }
        
     return 0;
 }
+#endif
 
-static int rtl8139_unhook_iospace()
-{
-
-    return 0;
-}
-
-
-static struct pci_device * rtl8139_pci_init(struct vm_device *vmdev, struct pci_bus *bus, int devfn)
-{
-    uchar_t *pci_conf;
-    struct pci_device *pdev;
+static int register_dev(struct rtl8139_state * nic_state)  {
+    int i;
 
-    pdev = v3_pci_register_device(vmdev, bus, "REALTEK8139", devfn, NULL, NULL);
+    if (nic_state->pci_bus == NULL) {
+       PrintError("RTL8139: Not attached to any PCI bus\n");
 
-    if (pdev == NULL)
-    {
-        PrintError("NIC: Register to PCI bus failed\n");
-        return NULL;
+       return -1;
     }
 
-    pci_conf = pdev->configs;
-       
-    pci_conf[0x00] = 0xec;
-    pci_conf[0x01] = 0x10;
-    pci_conf[0x02] = 0x39;
-    pci_conf[0x03] = 0x81;
-    pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
-    pci_conf[0x08] = RTL8139_PCI_REVID_8139; /* PCI revision ID; >=0x20 is for 8139C+ */
-    pci_conf[0x0a] = 0x00; // ethernet network controller
-    pci_conf[0x0b] = 0x02;
-    pci_conf[0x0e] = 0x00; // header_type
-    pci_conf[0x3d] = 1; // interrupt pin 0
-    pci_conf[0x3c] = 12;
-    pci_conf[0x34] = 0xdc;
-
-    pdev->vmdev = vmdev;
-       
-    v3_pci_register_io_region(pdev, 0, 0x100, PCI_ADDRESS_SPACE_IO, &rtl8139_hook_iospace);
-    v3_pci_register_io_region(pdev, 1, 0x100, PCI_ADDRESS_SPACE_MEM, &rtl8139_hook_iospace);
-    
-    return pdev;
-}
+    struct v3_pci_bar bars[6];
+    struct pci_device * pci_dev = NULL;
 
-static int rtl8139_init_state(struct rtl8139_state *nic_state)
-{
-    PrintDebug("rtl8139: init_state\n");
-       
-    init_phy_network();
-    init_rtl8139(dev);
-    current_vnic = dev;
-    bus = v3_get_pcibus(dev->vm, 0);
-
-    if (bus != NULL) 
-    {
-           PrintDebug("Find PCI bus in guest, attach nic to the bus %p\n", bus);
-           pdev = rtl8139_pci_init(dev, bus, -1);
-           if (pdev == NULL)
-                   PrintError("Failure to attach nic to the bus %p\n", bus);
+    for (i = 0; i < 6; i++) {
+       bars[i].type = PCI_BAR_NONE;
     }
 
-    nic_state->pci_dev = pdev;
-
-    //rtl8139_hook_iospace(dev, 0x2000, 0x100, 1, NULL);
-
-    return 0;
-}
+    bars[0].type = PCI_BAR_IO;
+    bars[0].default_base_port = 0xc100;
+    bars[0].num_ports = 0x100;
 
-static int rtl8139_deinit_device(struct vm_device *dev)
-{
-       
-    rtl8139_unhook_iospace(); 
+    bars[0].io_read = rtl8139_ioport_read;
+    bars[0].io_write = rtl8139_ioport_write;
+    bars[0].private_data = nic_state;
 
-    return 0;
-}
-
-static struct vm_device_ops dev_ops =
-{
-    .init = rtl8139_init_device,
-    .deinit = rtl8139_deinit_device,
-    .reset = rtl8139_reset_device,
-    .start = rtl8139_start_device,
-    .stop = rtl8139_stop_device,
-};
-
-struct vm_device *v3_create_rtl8139()
-{
-    struct nic_context *nic_state = V3_Malloc(sizeof(struct nic_context));
-    PrintDebug("rtl8139 internal at %p\n", (void *)nic_state);
-    struct vm_device *dev = v3_create_device("RTL8139", &dev_ops, nic_state);
-    return dev;
-};
-
-
-
-static int register_dev(struct ne2k_state * nic_state) 
-{
-    int i;
-
-    if (nic_state->pci_bus != NULL) {
-       struct v3_pci_bar bars[6];
-       struct pci_device * pci_dev = NULL;
-
-       PrintDebug("NE2000: PCI Enabled\n");
-
-       for (i = 0; i < 6; i++) {
-           bars[i].type = PCI_BAR_NONE;
-       }
-
-       bars[0].type = PCI_BAR_IO;
-       bars[0].default_base_port = NIC_REG_BASE_PORT;
-       bars[0].num_ports = 256;
+/*
+    bars[1].type = PCI_BAR_MEM32;
+    bars[1].default_base_addr = -1;
+    bars[1].num_pages = 1;
 
-       bars[0].io_read = ne2k_pci_read;
-       bars[0].io_write = ne2k_pci_write;
-       bars[0].private_data = nic_state;
+    bars[1].mem_read = rtl8139_mmio_read;
+    bars[1].mem_write = rtl8139_mmio_write;
+    bars[1].private_data = nic_state;
+*/
 
-       pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
-                                        "NE2000", bars,
-                                        pci_config_update, NULL, NULL, nic_state);
+    pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
+                                        "RTL8139", bars,
+                                        NULL, NULL, NULL, nic_state);
 
 
-       if (pci_dev == NULL) {
-           PrintError("NE2000: Could not register PCI Device\n");
-           return -1;
-       }
+    if (pci_dev == NULL) {
+       PrintError("RTL8139: Could not register PCI Device\n");
+       return -1;
+    }
        
-       pci_dev->config_header.vendor_id = 0x10ec;
-       pci_dev->config_header.device_id = 0x8029;
-       pci_dev->config_header.revision = 0x00;
-
-       pci_dev->config_header.subclass = 0x00;
-       pci_dev->config_header.class = 0x02;
-       pci_dev->config_header.header_type = 0x00;
-
-       pci_dev->config_header.intr_line = 11;
-       pci_dev->config_header.intr_pin = 1;
-
-       nic_state->pci_dev = pci_dev;
-    }else {
-       PrintDebug("NE2000: Not attached to PCI\n");
-
-       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT , &ne2k_cmd_read, &ne2k_cmd_write);
-
-       for (i = 1; i < 16; i++){       
-           v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + i, &ne2k_std_read, &ne2k_std_write);
-       }
+    pci_dev->config_header.vendor_id = 0x10ec;
+    pci_dev->config_header.device_id = 0x8139;
+    pci_dev->config_header.command = 0x05;
+       
+    pci_dev->config_header.revision = RTL8139_PCI_REVID_8139;
 
-       v3_dev_hook_io(nic_state->dev, NIC_DATA_PORT, &ne2k_data_read, &ne2k_data_write);
-       v3_dev_hook_io(nic_state->dev, NIC_RESET_PORT, &ne2k_reset_port_read, &ne2k_reset_port_write);
-    }
+    pci_dev->config_header.subclass = 0x00;
+    pci_dev->config_header.class = 0x02;
+    pci_dev->config_header.header_type = 0x00;
 
+    pci_dev->config_header.intr_line = 12;
+    pci_dev->config_header.intr_pin = 1;
+    pci_dev->config_space[0x34] = 0xdc;
 
+    nic_state->pci_dev = pci_dev;
+       
     return 0;
 }
 
@@ -2000,7 +1764,7 @@ static int connect_fn(struct v3_vm_info * info,
                      struct v3_dev_net_ops * ops, 
                      v3_cfg_tree_t * cfg, 
                      void * private_data) {
-    struct ne2k_state * nic_state = (struct ne2k_state *)frontend_data;
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)frontend_data;
 
     rtl8139_init_state(nic_state);
     register_dev(nic_state);
@@ -2008,34 +1772,20 @@ static int connect_fn(struct v3_vm_info * info,
     nic_state->net_ops = ops;
     nic_state->backend_data = private_data;    
 
-    ops->recv = ne2k_rx;
+    ops->recv = rtl8139_rx;
     ops->poll = NULL;
-    ops->start_tx = NULL;
-    ops->stop_tx = NULL;
-    ops->frontend_data = nic_state;
-    memcpy(ops->fnt_mac, nic_state->mac, ETH_ALEN);
+    memcpy(ops->config.fnt_mac, nic_state->mac, ETH_ALEN);
 
     return 0;
 }
 
 
-static int rtl8139_free(struct ne2k_state * nic_state) {
-    int i;
+static int rtl8139_free(void * private_data) {
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)private_data;
 
     /* dettached from backend */
 
-    if(nic_state->pci_bus == NULL){
-       for (i = 0; i < 16; i++){               
-           v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + i);
-       }
-    
-       v3_dev_unhook_io(nic_state->dev, NIC_DATA_PORT);
-       v3_dev_unhook_io(nic_state->dev, NIC_RESET_PORT);
-    }else {
-       /* unregistered from PCI? */
-    }
-  
-    return 0;
+    /* unregistered from PCI? */
 
     V3_Free(nic_state);
        
@@ -2044,7 +1794,7 @@ static int rtl8139_free(struct ne2k_state * nic_state) {
 
 
 static struct v3_device_ops dev_ops = {
-    .free = (int (*)(void *))rtl8139_free,
+    .free = rtl8139_free,
 };
 
 
@@ -2055,7 +1805,7 @@ static int rtl8139_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     char * macstr = v3_cfg_val(cfg, "mac");
 
     nic_state  = (struct rtl8139_state *)V3_Malloc(sizeof(struct rtl8139_state));
-    memset(nic_state, 0, sizeof(struct ne2k_state));
+    memset(nic_state, 0, sizeof(struct rtl8139_state));
 
     nic_state->pci_bus = pci_bus;
     nic_state->vm = vm;