net/virtio-user: fix packed vq option parsing
[dpdk.git] / drivers / net / virtio / virtio_ethdev.c
index 5833dad..446c338 100644 (file)
@@ -141,6 +141,96 @@ static const struct rte_virtio_xstats_name_off rte_virtio_txq_stat_strings[] = {
 
 struct virtio_hw_internal virtio_hw_internal[RTE_MAX_ETHPORTS];
 
+static struct virtio_pmd_ctrl *
+virtio_pq_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
+                      int *dlen, int pkt_num)
+{
+       struct virtqueue *vq = cvq->vq;
+       int head;
+       struct vring_packed_desc *desc = vq->ring_packed.desc_packed;
+       struct virtio_pmd_ctrl *result;
+       int wrap_counter;
+       uint16_t flags;
+       int sum = 0;
+       int k;
+
+       /*
+        * Format is enforced in qemu code:
+        * One TX packet for header;
+        * At least one TX packet per argument;
+        * One RX packet for ACK.
+        */
+       head = vq->vq_avail_idx;
+       wrap_counter = vq->avail_wrap_counter;
+       desc[head].flags = VRING_DESC_F_NEXT;
+       desc[head].addr = cvq->virtio_net_hdr_mem;
+       desc[head].len = sizeof(struct virtio_net_ctrl_hdr);
+       vq->vq_free_cnt--;
+       if (++vq->vq_avail_idx >= vq->vq_nentries) {
+               vq->vq_avail_idx -= vq->vq_nentries;
+               vq->avail_wrap_counter ^= 1;
+       }
+
+       for (k = 0; k < pkt_num; k++) {
+               desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem
+                       + sizeof(struct virtio_net_ctrl_hdr)
+                       + sizeof(ctrl->status) + sizeof(uint8_t) * sum;
+               desc[vq->vq_avail_idx].len = dlen[k];
+               flags = VRING_DESC_F_NEXT;
+               sum += dlen[k];
+               vq->vq_free_cnt--;
+               flags |= VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
+                        VRING_DESC_F_USED(!vq->avail_wrap_counter);
+               desc[vq->vq_avail_idx].flags = flags;
+               rte_smp_wmb();
+               vq->vq_free_cnt--;
+               if (++vq->vq_avail_idx >= vq->vq_nentries) {
+                       vq->vq_avail_idx -= vq->vq_nentries;
+                       vq->avail_wrap_counter ^= 1;
+               }
+       }
+
+
+       desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem
+               + sizeof(struct virtio_net_ctrl_hdr);
+       desc[vq->vq_avail_idx].len = sizeof(ctrl->status);
+       flags = VRING_DESC_F_WRITE;
+       flags |= VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
+                VRING_DESC_F_USED(!vq->avail_wrap_counter);
+       desc[vq->vq_avail_idx].flags = flags;
+       flags = VRING_DESC_F_NEXT;
+       flags |= VRING_DESC_F_AVAIL(wrap_counter) |
+                VRING_DESC_F_USED(!wrap_counter);
+       desc[head].flags = flags;
+       rte_smp_wmb();
+
+       vq->vq_free_cnt--;
+       if (++vq->vq_avail_idx >= vq->vq_nentries) {
+               vq->vq_avail_idx -= vq->vq_nentries;
+               vq->avail_wrap_counter ^= 1;
+       }
+
+       virtqueue_notify(vq);
+
+       /* wait for used descriptors in virtqueue */
+       do {
+               rte_rmb();
+               usleep(100);
+       } while (!desc_is_used(&desc[head], vq));
+
+       /* now get used descriptors */
+       while (desc_is_used(&desc[vq->vq_used_cons_idx], vq)) {
+               vq->vq_free_cnt++;
+               if (++vq->vq_used_cons_idx >= vq->vq_nentries) {
+                       vq->vq_used_cons_idx -= vq->vq_nentries;
+                       vq->used_wrap_counter ^= 1;
+               }
+       }
+
+       result = cvq->virtio_net_hdr_mz->addr;
+       return result;
+}
+
 static int
 virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
                int *dlen, int pkt_num)
@@ -174,6 +264,11 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
        memcpy(cvq->virtio_net_hdr_mz->addr, ctrl,
                sizeof(struct virtio_pmd_ctrl));
 
+       if (vtpci_packed_queue(vq->hw)) {
+               result = virtio_pq_send_command(cvq, ctrl, dlen, pkt_num);
+               goto out_unlock;
+       }
+
        /*
         * Format is enforced in qemu code:
         * One TX packet for header;
@@ -245,6 +340,7 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
 
        result = cvq->virtio_net_hdr_mz->addr;
 
+out_unlock:
        rte_spinlock_unlock(&cvq->lock);
        return result->status;
 }
@@ -299,20 +395,22 @@ virtio_init_vring(struct virtqueue *vq)
 
        PMD_INIT_FUNC_TRACE();
 
-       /*
-        * Reinitialise since virtio port might have been stopped and restarted
-        */
        memset(ring_mem, 0, vq->vq_ring_size);
-       vring_init(vr, size, ring_mem, VIRTIO_PCI_VRING_ALIGN);
+
        vq->vq_used_cons_idx = 0;
        vq->vq_desc_head_idx = 0;
        vq->vq_avail_idx = 0;
        vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
        vq->vq_free_cnt = vq->vq_nentries;
        memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
-
-       vring_desc_init(vr->desc, size);
-
+       if (vtpci_packed_queue(vq->hw)) {
+               vring_init_packed(&vq->ring_packed, ring_mem,
+                                 VIRTIO_PCI_VRING_ALIGN, size);
+               vring_desc_init_packed(vq, size);
+       } else {
+               vring_init_split(vr, ring_mem, VIRTIO_PCI_VRING_ALIGN, size);
+               vring_desc_init_split(vr->desc, size);
+       }
        /*
         * Disable device(host) interrupting guest
         */
@@ -335,8 +433,10 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
        void *sw_ring = NULL;
        int queue_type = virtio_get_queue_type(hw, vtpci_queue_idx);
        int ret;
+       int numa_node = dev->device->numa_node;
 
-       PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
+       PMD_INIT_LOG(INFO, "setting up queue: %u on NUMA node %d",
+                       vtpci_queue_idx, numa_node);
 
        /*
         * Read the virtqueue size from the Queue Size field
@@ -372,7 +472,7 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
        }
 
        vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE,
-                               SOCKET_ID_ANY);
+                               numa_node);
        if (vq == NULL) {
                PMD_INIT_LOG(ERR, "can not allocate vq");
                return -ENOMEM;
@@ -382,17 +482,25 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
        vq->hw = hw;
        vq->vq_queue_index = vtpci_queue_idx;
        vq->vq_nentries = vq_size;
+       vq->event_flags_shadow = 0;
+       if (vtpci_packed_queue(hw)) {
+               vq->avail_wrap_counter = 1;
+               vq->used_wrap_counter = 1;
+               vq->avail_used_flags =
+                       VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
+                       VRING_DESC_F_USED(!vq->avail_wrap_counter);
+       }
 
        /*
         * Reserve a memzone for vring elements
         */
-       size = vring_size(vq_size, VIRTIO_PCI_VRING_ALIGN);
+       size = vring_size(hw, vq_size, VIRTIO_PCI_VRING_ALIGN);
        vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN);
        PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d",
                     size, vq->vq_ring_size);
 
        mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
-                       SOCKET_ID_ANY, RTE_MEMZONE_IOVA_CONTIG,
+                       numa_node, RTE_MEMZONE_IOVA_CONTIG,
                        VIRTIO_PCI_VRING_ALIGN);
        if (mz == NULL) {
                if (rte_errno == EEXIST)
@@ -418,7 +526,7 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
                snprintf(vq_hdr_name, sizeof(vq_hdr_name), "port%d_vq%d_hdr",
                         dev->data->port_id, vtpci_queue_idx);
                hdr_mz = rte_memzone_reserve_aligned(vq_hdr_name, sz_hdr_mz,
-                               SOCKET_ID_ANY, RTE_MEMZONE_IOVA_CONTIG,
+                               numa_node, RTE_MEMZONE_IOVA_CONTIG,
                                RTE_CACHE_LINE_SIZE);
                if (hdr_mz == NULL) {
                        if (rte_errno == EEXIST)
@@ -435,7 +543,7 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
                               sizeof(vq->sw_ring[0]);
 
                sw_ring = rte_zmalloc_socket("sw_ring", sz_sw,
-                               RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+                               RTE_CACHE_LINE_SIZE, numa_node);
                if (!sw_ring) {
                        PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
                        ret = -ENOMEM;
@@ -488,16 +596,26 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
                memset(txr, 0, vq_size * sizeof(*txr));
                for (i = 0; i < vq_size; i++) {
                        struct vring_desc *start_dp = txr[i].tx_indir;
-
-                       vring_desc_init(start_dp, RTE_DIM(txr[i].tx_indir));
+                       struct vring_packed_desc *start_dp_packed =
+                               txr[i].tx_indir_pq;
 
                        /* first indirect descriptor is always the tx header */
-                       start_dp->addr = txvq->virtio_net_hdr_mem
-                               + i * sizeof(*txr)
-                               + offsetof(struct virtio_tx_region, tx_hdr);
-
-                       start_dp->len = hw->vtnet_hdr_size;
-                       start_dp->flags = VRING_DESC_F_NEXT;
+                       if (vtpci_packed_queue(hw)) {
+                               start_dp_packed->addr = txvq->virtio_net_hdr_mem
+                                       + i * sizeof(*txr)
+                                       + offsetof(struct virtio_tx_region,
+                                                  tx_hdr);
+                               start_dp_packed->len = hw->vtnet_hdr_size;
+                       } else {
+                               vring_desc_init_split(start_dp,
+                                                     RTE_DIM(txr[i].tx_indir));
+                               start_dp->addr = txvq->virtio_net_hdr_mem
+                                       + i * sizeof(*txr)
+                                       + offsetof(struct virtio_tx_region,
+                                                  tx_hdr);
+                               start_dp->len = hw->vtnet_hdr_size;
+                               start_dp->flags = VRING_DESC_F_NEXT;
+                       }
                }
        }
 
@@ -588,6 +706,10 @@ virtio_dev_close(struct rte_eth_dev *dev)
 
        PMD_INIT_LOG(DEBUG, "virtio_dev_close");
 
+       if (!hw->opened)
+               return;
+       hw->opened = false;
+
        /* reset the NIC */
        if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
                VTPCI_OPS(hw)->set_config_irq(hw, VIRTIO_MSI_NO_VECTOR);
@@ -1245,6 +1367,9 @@ virtio_notify_peers(struct rte_eth_dev *dev)
                return;
 
        rxvq = dev->data->rx_queues[0];
+       if (!rxvq)
+               return;
+
        rarp_mbuf = rte_net_make_rarp_packet(rxvq->mpool,
                        (struct ether_addr *)hw->mac_addr);
        if (rarp_mbuf == NULL) {
@@ -1285,6 +1410,7 @@ virtio_interrupt_handler(void *param)
        struct rte_eth_dev *dev = param;
        struct virtio_hw *hw = dev->data->dev_private;
        uint8_t isr;
+       uint16_t status;
 
        /* Read interrupt status which clears interrupt */
        isr = vtpci_isr(hw);
@@ -1298,12 +1424,17 @@ virtio_interrupt_handler(void *param)
                        _rte_eth_dev_callback_process(dev,
                                                      RTE_ETH_EVENT_INTR_LSC,
                                                      NULL);
-       }
 
-       if (isr & VIRTIO_NET_S_ANNOUNCE) {
-               virtio_notify_peers(dev);
-               if (hw->cvq)
-                       virtio_ack_link_announce(dev);
+               if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
+                       vtpci_read_dev_config(hw,
+                               offsetof(struct virtio_net_config, status),
+                               &status, sizeof(status));
+                       if (status & VIRTIO_NET_S_ANNOUNCE) {
+                               virtio_notify_peers(dev);
+                               if (hw->cvq)
+                                       virtio_ack_link_announce(dev);
+                       }
+               }
        }
 }
 
@@ -1313,30 +1444,58 @@ set_rxtx_funcs(struct rte_eth_dev *eth_dev)
 {
        struct virtio_hw *hw = eth_dev->data->dev_private;
 
-       if (hw->use_simple_rx) {
-               PMD_INIT_LOG(INFO, "virtio: using simple Rx path on port %u",
-                       eth_dev->data->port_id);
-               eth_dev->rx_pkt_burst = virtio_recv_pkts_vec;
-       } else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
+       if (vtpci_packed_queue(hw)) {
                PMD_INIT_LOG(INFO,
-                       "virtio: using mergeable buffer Rx path on port %u",
+                       "virtio: using packed ring standard Tx path on port %u",
                        eth_dev->data->port_id);
-               eth_dev->rx_pkt_burst = &virtio_recv_mergeable_pkts;
+               eth_dev->tx_pkt_burst = virtio_xmit_pkts_packed;
        } else {
-               PMD_INIT_LOG(INFO, "virtio: using standard Rx path on port %u",
-                       eth_dev->data->port_id);
-               eth_dev->rx_pkt_burst = &virtio_recv_pkts;
+               if (hw->use_inorder_tx) {
+                       PMD_INIT_LOG(INFO, "virtio: using inorder Tx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->tx_pkt_burst = virtio_xmit_pkts_inorder;
+               } else {
+                       PMD_INIT_LOG(INFO, "virtio: using standard Tx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->tx_pkt_burst = virtio_xmit_pkts;
+               }
        }
 
-       if (hw->use_simple_tx) {
-               PMD_INIT_LOG(INFO, "virtio: using simple Tx path on port %u",
-                       eth_dev->data->port_id);
-               eth_dev->tx_pkt_burst = virtio_xmit_pkts_simple;
+       if (vtpci_packed_queue(hw)) {
+               if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
+                       PMD_INIT_LOG(INFO,
+                               "virtio: using packed ring mergeable buffer Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst =
+                               &virtio_recv_mergeable_pkts_packed;
+               } else {
+                       PMD_INIT_LOG(INFO,
+                               "virtio: using packed ring standard Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst = &virtio_recv_pkts_packed;
+               }
        } else {
-               PMD_INIT_LOG(INFO, "virtio: using standard Tx path on port %u",
-                       eth_dev->data->port_id);
-               eth_dev->tx_pkt_burst = virtio_xmit_pkts;
+               if (hw->use_simple_rx) {
+                       PMD_INIT_LOG(INFO, "virtio: using simple Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst = virtio_recv_pkts_vec;
+               } else if (hw->use_inorder_rx) {
+                       PMD_INIT_LOG(INFO,
+                               "virtio: using inorder Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst = &virtio_recv_pkts_inorder;
+               } else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
+                       PMD_INIT_LOG(INFO,
+                               "virtio: using mergeable buffer Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst = &virtio_recv_mergeable_pkts;
+               } else {
+                       PMD_INIT_LOG(INFO, "virtio: using standard Rx path on port %u",
+                               eth_dev->data->port_id);
+                       eth_dev->rx_pkt_burst = &virtio_recv_pkts;
+               }
        }
+
 }
 
 /* Only support 1:1 queue/interrupt mapping so far.
@@ -1468,7 +1627,8 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
 
        /* Setting up rx_header size for the device */
        if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
-           vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
+           vtpci_with_feature(hw, VIRTIO_F_VERSION_1) ||
+           vtpci_with_feature(hw, VIRTIO_F_RING_PACKED))
                hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
        else
                hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1671,11 +1831,6 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
        if (ret < 0)
                goto out;
 
-       /* Setup interrupt callback  */
-       if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
-               rte_intr_callback_register(eth_dev->intr_handle,
-                       virtio_interrupt_handler, eth_dev);
-
        return 0;
 
 out:
@@ -1689,7 +1844,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
        PMD_INIT_FUNC_TRACE();
 
        if (rte_eal_process_type() == RTE_PROC_SECONDARY)
-               return -EPERM;
+               return 0;
 
        virtio_dev_stop(eth_dev);
        virtio_dev_close(eth_dev);
@@ -1698,14 +1853,6 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
        eth_dev->tx_pkt_burst = NULL;
        eth_dev->rx_pkt_burst = NULL;
 
-       rte_free(eth_dev->data->mac_addrs);
-       eth_dev->data->mac_addrs = NULL;
-
-       /* reset interrupt callback  */
-       if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
-               rte_intr_callback_unregister(eth_dev->intr_handle,
-                                               virtio_interrupt_handler,
-                                               eth_dev);
        if (eth_dev->device)
                rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev));
 
@@ -1755,6 +1902,11 @@ exit:
 static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
        struct rte_pci_device *pci_dev)
 {
+       if (rte_eal_iopl_init() != 0) {
+               PMD_INIT_LOG(ERR, "IOPL call failed - cannot use virtio PMD");
+               return 1;
+       }
+
        /* virtio pmd skips probe if device needs to work in vdpa mode */
        if (vdpa_mode_selected(pci_dev->device.devargs))
                return 1;
@@ -1778,18 +1930,28 @@ static struct rte_pci_driver rte_virtio_pmd = {
        .remove = eth_virtio_pci_remove,
 };
 
-RTE_INIT(rte_virtio_pmd_init);
-static void
-rte_virtio_pmd_init(void)
+RTE_INIT(rte_virtio_pmd_init)
 {
-       if (rte_eal_iopl_init() != 0) {
-               PMD_INIT_LOG(ERR, "IOPL call failed - cannot use virtio PMD");
-               return;
-       }
-
+       rte_eal_iopl_init();
        rte_pci_register(&rte_virtio_pmd);
 }
 
+static bool
+rx_offload_enabled(struct virtio_hw *hw)
+{
+       return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
+               vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
+               vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
+}
+
+static bool
+tx_offload_enabled(struct virtio_hw *hw)
+{
+       return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
+               vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
+               vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
+}
+
 /*
  * Configure virtio device
  * It returns 0 on success.
@@ -1798,8 +1960,10 @@ static int
 virtio_dev_configure(struct rte_eth_dev *dev)
 {
        const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+       const struct rte_eth_txmode *txmode = &dev->data->dev_conf.txmode;
        struct virtio_hw *hw = dev->data->dev_private;
        uint64_t rx_offloads = rxmode->offloads;
+       uint64_t tx_offloads = txmode->offloads;
        uint64_t req_features;
        int ret;
 
@@ -1821,6 +1985,15 @@ virtio_dev_configure(struct rte_eth_dev *dev)
                        (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
                        (1ULL << VIRTIO_NET_F_GUEST_TSO6);
 
+       if (tx_offloads & (DEV_TX_OFFLOAD_UDP_CKSUM |
+                          DEV_TX_OFFLOAD_TCP_CKSUM))
+               req_features |= (1ULL << VIRTIO_NET_F_CSUM);
+
+       if (tx_offloads & DEV_TX_OFFLOAD_TCP_TSO)
+               req_features |=
+                       (1ULL << VIRTIO_NET_F_HOST_TSO4) |
+                       (1ULL << VIRTIO_NET_F_HOST_TSO6);
+
        /* if request features changed, reinit the device */
        if (req_features != hw->req_guest_features) {
                ret = virtio_init_device(dev, req_features);
@@ -1858,6 +2031,9 @@ virtio_dev_configure(struct rte_eth_dev *dev)
                return -ENOTSUP;
        }
 
+       hw->has_tx_offload = tx_offload_enabled(hw);
+       hw->has_rx_offload = rx_offload_enabled(hw);
+
        if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
                /* Enable vector (0) for Link State Intrerrupt */
                if (VTPCI_OPS(hw)->set_config_irq(hw, 0) ==
@@ -1869,23 +2045,36 @@ virtio_dev_configure(struct rte_eth_dev *dev)
        rte_spinlock_init(&hw->state_lock);
 
        hw->use_simple_rx = 1;
-       hw->use_simple_tx = 1;
+
+       if (vtpci_with_feature(hw, VIRTIO_F_IN_ORDER)) {
+               hw->use_inorder_tx = 1;
+               hw->use_inorder_rx = 1;
+               hw->use_simple_rx = 0;
+       }
+
+       if (vtpci_packed_queue(hw)) {
+               hw->use_simple_rx = 0;
+               hw->use_inorder_rx = 0;
+               hw->use_inorder_tx = 0;
+       }
 
 #if defined RTE_ARCH_ARM64 || defined RTE_ARCH_ARM
        if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON)) {
                hw->use_simple_rx = 0;
-               hw->use_simple_tx = 0;
        }
 #endif
        if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
-               hw->use_simple_rx = 0;
-               hw->use_simple_tx = 0;
+                hw->use_simple_rx = 0;
        }
 
        if (rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM |
-                          DEV_RX_OFFLOAD_TCP_CKSUM))
+                          DEV_RX_OFFLOAD_TCP_CKSUM |
+                          DEV_RX_OFFLOAD_TCP_LRO |
+                          DEV_RX_OFFLOAD_VLAN_STRIP))
                hw->use_simple_rx = 0;
 
+       hw->opened = true;
+
        return 0;
 }
 
@@ -1927,6 +2116,12 @@ virtio_dev_start(struct rte_eth_dev *dev)
            dev->data->dev_conf.intr_conf.rxq) {
                virtio_intr_disable(dev);
 
+               /* Setup interrupt callback  */
+               if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
+                       rte_intr_callback_register(dev->intr_handle,
+                                                  virtio_interrupt_handler,
+                                                  dev);
+
                if (virtio_intr_enable(dev) < 0) {
                        PMD_DRV_LOG(ERR, "interrupt enable failed");
                        return -EIO;
@@ -1970,7 +2165,7 @@ virtio_dev_start(struct rte_eth_dev *dev)
        }
 
        set_rxtx_funcs(dev);
-       hw->started = 1;
+       hw->started = true;
 
        /* Initialize Link state */
        virtio_dev_link_update(dev, 0);
@@ -2036,12 +2231,24 @@ virtio_dev_stop(struct rte_eth_dev *dev)
        PMD_INIT_LOG(DEBUG, "stop");
 
        rte_spinlock_lock(&hw->state_lock);
-       if (intr_conf->lsc || intr_conf->rxq)
+       if (!hw->started)
+               goto out_unlock;
+       hw->started = false;
+
+       if (intr_conf->lsc || intr_conf->rxq) {
                virtio_intr_disable(dev);
 
-       hw->started = 0;
+               /* Reset interrupt callback  */
+               if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
+                       rte_intr_callback_unregister(dev->intr_handle,
+                                                    virtio_interrupt_handler,
+                                                    dev);
+               }
+       }
+
        memset(&link, 0, sizeof(link));
        rte_eth_linkstatus_set(dev, &link);
+out_unlock:
        rte_spinlock_unlock(&hw->state_lock);
 }
 
@@ -2057,7 +2264,7 @@ virtio_dev_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complet
        link.link_speed  = ETH_SPEED_NUM_10G;
        link.link_autoneg = ETH_LINK_FIXED;
 
-       if (hw->started == 0) {
+       if (!hw->started) {
                link.link_status = ETH_LINK_DOWN;
        } else if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
                PMD_INIT_LOG(DEBUG, "Get link status from hw");
@@ -2119,9 +2326,6 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->min_rx_bufsize = VIRTIO_MIN_RX_BUFSIZE;
        dev_info->max_rx_pktlen = VIRTIO_MAX_RX_PKTLEN;
        dev_info->max_mac_addrs = VIRTIO_MAX_MAC_ADDRS;
-       dev_info->default_txconf = (struct rte_eth_txconf) {
-               .txq_flags = ETH_TXQ_FLAGS_NOOFFLOADS
-       };
 
        host_features = VTPCI_OPS(hw)->get_features(hw);
        dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP;
@@ -2139,14 +2343,14 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 
        dev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS |
                                    DEV_TX_OFFLOAD_VLAN_INSERT;
-       if (hw->guest_features & (1ULL << VIRTIO_NET_F_CSUM)) {
+       if (host_features & (1ULL << VIRTIO_NET_F_CSUM)) {
                dev_info->tx_offload_capa |=
                        DEV_TX_OFFLOAD_UDP_CKSUM |
                        DEV_TX_OFFLOAD_TCP_CKSUM;
        }
        tso_mask = (1ULL << VIRTIO_NET_F_HOST_TSO4) |
                (1ULL << VIRTIO_NET_F_HOST_TSO6);
-       if ((hw->guest_features & tso_mask) == tso_mask)
+       if ((host_features & tso_mask) == tso_mask)
                dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
 }
 
@@ -2165,9 +2369,7 @@ RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__);
 RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci");
 
-RTE_INIT(virtio_init_log);
-static void
-virtio_init_log(void)
+RTE_INIT(virtio_init_log)
 {
        virtio_logtype_init = rte_log_register("pmd.net.virtio.init");
        if (virtio_logtype_init >= 0)