15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2010-2016 Intel Corporation 36c3169a3SBruce Richardson */ 46c3169a3SBruce Richardson 56c3169a3SBruce Richardson #include <stdint.h> 66c3169a3SBruce Richardson #include <string.h> 76c3169a3SBruce Richardson #include <stdio.h> 86c3169a3SBruce Richardson #include <errno.h> 96c3169a3SBruce Richardson #include <unistd.h> 106c3169a3SBruce Richardson 11ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h> 12fdf91e0fSJan Blunck #include <rte_ethdev_pci.h> 136c3169a3SBruce Richardson #include <rte_memcpy.h> 146c3169a3SBruce Richardson #include <rte_string_fns.h> 156c3169a3SBruce Richardson #include <rte_memzone.h> 166c3169a3SBruce Richardson #include <rte_malloc.h> 176c3169a3SBruce Richardson #include <rte_branch_prediction.h> 186c3169a3SBruce Richardson #include <rte_pci.h> 19c752998bSGaetan Rivet #include <rte_bus_pci.h> 206c3169a3SBruce Richardson #include <rte_ether.h> 217365504fSXiao Wang #include <rte_ip.h> 227365504fSXiao Wang #include <rte_arp.h> 236c3169a3SBruce Richardson #include <rte_common.h> 24abf4c84bSBernard Iremonger #include <rte_errno.h> 254819eae8SOlivier Matz #include <rte_cpuflags.h> 266c3169a3SBruce Richardson 276c3169a3SBruce Richardson #include <rte_memory.h> 286c3169a3SBruce Richardson #include <rte_eal.h> 296c3169a3SBruce Richardson #include <rte_dev.h> 301978a9dcSXiao Wang #include <rte_cycles.h> 31440f03c2SXiao Wang #include <rte_kvargs.h> 326c3169a3SBruce Richardson 336c3169a3SBruce Richardson #include "virtio_ethdev.h" 346c3169a3SBruce Richardson #include "virtio_pci.h" 356c3169a3SBruce Richardson #include "virtio_logs.h" 366c3169a3SBruce Richardson #include "virtqueue.h" 37cab04612SHuawei Xie #include "virtio_rxtx.h" 387f468b2eSTiwei Bie #include "virtio_user/virtio_user_dev.h" 396c3169a3SBruce Richardson 40abf4c84bSBernard Iremonger static int eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev); 416c3169a3SBruce Richardson static int virtio_dev_configure(struct rte_eth_dev *dev); 426c3169a3SBruce Richardson static int virtio_dev_start(struct rte_eth_dev *dev); 436c3169a3SBruce Richardson static void virtio_dev_stop(struct rte_eth_dev *dev); 446c3169a3SBruce Richardson static void virtio_dev_promiscuous_enable(struct rte_eth_dev *dev); 456c3169a3SBruce Richardson static void virtio_dev_promiscuous_disable(struct rte_eth_dev *dev); 466c3169a3SBruce Richardson static void virtio_dev_allmulticast_enable(struct rte_eth_dev *dev); 476c3169a3SBruce Richardson static void virtio_dev_allmulticast_disable(struct rte_eth_dev *dev); 486c3169a3SBruce Richardson static void virtio_dev_info_get(struct rte_eth_dev *dev, 496c3169a3SBruce Richardson struct rte_eth_dev_info *dev_info); 506c3169a3SBruce Richardson static int virtio_dev_link_update(struct rte_eth_dev *dev, 51dd2c630aSFerruh Yigit int wait_to_complete); 52289ba0c0SDavid Harton static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask); 536c3169a3SBruce Richardson 546c3169a3SBruce Richardson static void virtio_set_hwaddr(struct virtio_hw *hw); 556c3169a3SBruce Richardson static void virtio_get_hwaddr(struct virtio_hw *hw); 566c3169a3SBruce Richardson 57d5b0924bSMatan Azrad static int virtio_dev_stats_get(struct rte_eth_dev *dev, 5876d4c652SHarry van Haaren struct rte_eth_stats *stats); 5976d4c652SHarry van Haaren static int virtio_dev_xstats_get(struct rte_eth_dev *dev, 60e2aae1c1SRemy Horton struct rte_eth_xstat *xstats, unsigned n); 61baf91c39SRemy Horton static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev, 62baf91c39SRemy Horton struct rte_eth_xstat_name *xstats_names, 63baf91c39SRemy Horton unsigned limit); 646c3169a3SBruce Richardson static void virtio_dev_stats_reset(struct rte_eth_dev *dev); 656c3169a3SBruce Richardson static void virtio_dev_free_mbufs(struct rte_eth_dev *dev); 666c3169a3SBruce Richardson static int virtio_vlan_filter_set(struct rte_eth_dev *dev, 676c3169a3SBruce Richardson uint16_t vlan_id, int on); 686d01e580SWei Dai static int virtio_mac_addr_add(struct rte_eth_dev *dev, 696d13ea8eSOlivier Matz struct rte_ether_addr *mac_addr, 70dd2c630aSFerruh Yigit uint32_t index, uint32_t vmdq); 716c3169a3SBruce Richardson static void virtio_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index); 72caccf8b3SOlivier Matz static int virtio_mac_addr_set(struct rte_eth_dev *dev, 736d13ea8eSOlivier Matz struct rte_ether_addr *mac_addr); 746c3169a3SBruce Richardson 75fe19d49cSZhiyong Yang static int virtio_intr_disable(struct rte_eth_dev *dev); 76fe19d49cSZhiyong Yang 776c3169a3SBruce Richardson static int virtio_dev_queue_stats_mapping_set( 78dd2c630aSFerruh Yigit struct rte_eth_dev *eth_dev, 79dd2c630aSFerruh Yigit uint16_t queue_id, 80dd2c630aSFerruh Yigit uint8_t stat_idx, 81dd2c630aSFerruh Yigit uint8_t is_rx); 826c3169a3SBruce Richardson 8300628188SStephen Hemminger int virtio_logtype_init; 8400628188SStephen Hemminger int virtio_logtype_driver; 8500628188SStephen Hemminger 867365504fSXiao Wang static void virtio_notify_peers(struct rte_eth_dev *dev); 877365504fSXiao Wang static void virtio_ack_link_announce(struct rte_eth_dev *dev); 887365504fSXiao Wang 896c3169a3SBruce Richardson /* 906c3169a3SBruce Richardson * The set of PCI devices this driver supports 916c3169a3SBruce Richardson */ 926c3169a3SBruce Richardson static const struct rte_pci_id pci_id_virtio_map[] = { 934c790365SJason Wang { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_LEGACY_DEVICEID_NET) }, 944c790365SJason Wang { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_MODERN_DEVICEID_NET) }, 956c3169a3SBruce Richardson { .vendor_id = 0, /* sentinel */ }, 966c3169a3SBruce Richardson }; 976c3169a3SBruce Richardson 9876d4c652SHarry van Haaren struct rte_virtio_xstats_name_off { 9976d4c652SHarry van Haaren char name[RTE_ETH_XSTATS_NAME_SIZE]; 10076d4c652SHarry van Haaren unsigned offset; 10176d4c652SHarry van Haaren }; 10276d4c652SHarry van Haaren 10376d4c652SHarry van Haaren /* [rt]x_qX_ is prepended to the name string here */ 10401ad44fdSHuawei Xie static const struct rte_virtio_xstats_name_off rte_virtio_rxq_stat_strings[] = { 10501ad44fdSHuawei Xie {"good_packets", offsetof(struct virtnet_rx, stats.packets)}, 10601ad44fdSHuawei Xie {"good_bytes", offsetof(struct virtnet_rx, stats.bytes)}, 10701ad44fdSHuawei Xie {"errors", offsetof(struct virtnet_rx, stats.errors)}, 10801ad44fdSHuawei Xie {"multicast_packets", offsetof(struct virtnet_rx, stats.multicast)}, 10901ad44fdSHuawei Xie {"broadcast_packets", offsetof(struct virtnet_rx, stats.broadcast)}, 11001ad44fdSHuawei Xie {"undersize_packets", offsetof(struct virtnet_rx, stats.size_bins[0])}, 11101ad44fdSHuawei Xie {"size_64_packets", offsetof(struct virtnet_rx, stats.size_bins[1])}, 11201ad44fdSHuawei Xie {"size_65_127_packets", offsetof(struct virtnet_rx, stats.size_bins[2])}, 11301ad44fdSHuawei Xie {"size_128_255_packets", offsetof(struct virtnet_rx, stats.size_bins[3])}, 11401ad44fdSHuawei Xie {"size_256_511_packets", offsetof(struct virtnet_rx, stats.size_bins[4])}, 11501ad44fdSHuawei Xie {"size_512_1023_packets", offsetof(struct virtnet_rx, stats.size_bins[5])}, 11681f7234bSZhiyong Yang {"size_1024_1518_packets", offsetof(struct virtnet_rx, stats.size_bins[6])}, 11781f7234bSZhiyong Yang {"size_1519_max_packets", offsetof(struct virtnet_rx, stats.size_bins[7])}, 11876d4c652SHarry van Haaren }; 11976d4c652SHarry van Haaren 12001ad44fdSHuawei Xie /* [rt]x_qX_ is prepended to the name string here */ 12101ad44fdSHuawei Xie static const struct rte_virtio_xstats_name_off rte_virtio_txq_stat_strings[] = { 12201ad44fdSHuawei Xie {"good_packets", offsetof(struct virtnet_tx, stats.packets)}, 12301ad44fdSHuawei Xie {"good_bytes", offsetof(struct virtnet_tx, stats.bytes)}, 12401ad44fdSHuawei Xie {"errors", offsetof(struct virtnet_tx, stats.errors)}, 12501ad44fdSHuawei Xie {"multicast_packets", offsetof(struct virtnet_tx, stats.multicast)}, 12601ad44fdSHuawei Xie {"broadcast_packets", offsetof(struct virtnet_tx, stats.broadcast)}, 12701ad44fdSHuawei Xie {"undersize_packets", offsetof(struct virtnet_tx, stats.size_bins[0])}, 12801ad44fdSHuawei Xie {"size_64_packets", offsetof(struct virtnet_tx, stats.size_bins[1])}, 12901ad44fdSHuawei Xie {"size_65_127_packets", offsetof(struct virtnet_tx, stats.size_bins[2])}, 13001ad44fdSHuawei Xie {"size_128_255_packets", offsetof(struct virtnet_tx, stats.size_bins[3])}, 13101ad44fdSHuawei Xie {"size_256_511_packets", offsetof(struct virtnet_tx, stats.size_bins[4])}, 13201ad44fdSHuawei Xie {"size_512_1023_packets", offsetof(struct virtnet_tx, stats.size_bins[5])}, 13381f7234bSZhiyong Yang {"size_1024_1518_packets", offsetof(struct virtnet_tx, stats.size_bins[6])}, 13481f7234bSZhiyong Yang {"size_1519_max_packets", offsetof(struct virtnet_tx, stats.size_bins[7])}, 13501ad44fdSHuawei Xie }; 13601ad44fdSHuawei Xie 13701ad44fdSHuawei Xie #define VIRTIO_NB_RXQ_XSTATS (sizeof(rte_virtio_rxq_stat_strings) / \ 13801ad44fdSHuawei Xie sizeof(rte_virtio_rxq_stat_strings[0])) 13901ad44fdSHuawei Xie #define VIRTIO_NB_TXQ_XSTATS (sizeof(rte_virtio_txq_stat_strings) / \ 14001ad44fdSHuawei Xie sizeof(rte_virtio_txq_stat_strings[0])) 14176d4c652SHarry van Haaren 142553f4593SYuanhan Liu struct virtio_hw_internal virtio_hw_internal[RTE_MAX_ETHPORTS]; 143553f4593SYuanhan Liu 144ec194c2fSJens Freimann static struct virtio_pmd_ctrl * 1452923b8f9STiwei Bie virtio_send_command_packed(struct virtnet_ctl *cvq, 1462923b8f9STiwei Bie struct virtio_pmd_ctrl *ctrl, 147ec194c2fSJens Freimann int *dlen, int pkt_num) 148ec194c2fSJens Freimann { 149ec194c2fSJens Freimann struct virtqueue *vq = cvq->vq; 150ec194c2fSJens Freimann int head; 1514cdc4d98STiwei Bie struct vring_packed_desc *desc = vq->vq_packed.ring.desc; 152ec194c2fSJens Freimann struct virtio_pmd_ctrl *result; 1538e148e49STiwei Bie uint16_t flags; 154ec194c2fSJens Freimann int sum = 0; 1552923b8f9STiwei Bie int nb_descs = 0; 156ec194c2fSJens Freimann int k; 157ec194c2fSJens Freimann 158ec194c2fSJens Freimann /* 159ec194c2fSJens Freimann * Format is enforced in qemu code: 160ec194c2fSJens Freimann * One TX packet for header; 161ec194c2fSJens Freimann * At least one TX packet per argument; 162ec194c2fSJens Freimann * One RX packet for ACK. 163ec194c2fSJens Freimann */ 164ec194c2fSJens Freimann head = vq->vq_avail_idx; 165dfd33aa4STiwei Bie flags = vq->vq_packed.cached_flags; 166ec194c2fSJens Freimann desc[head].addr = cvq->virtio_net_hdr_mem; 167ec194c2fSJens Freimann desc[head].len = sizeof(struct virtio_net_ctrl_hdr); 168ec194c2fSJens Freimann vq->vq_free_cnt--; 1692923b8f9STiwei Bie nb_descs++; 170ec194c2fSJens Freimann if (++vq->vq_avail_idx >= vq->vq_nentries) { 171ec194c2fSJens Freimann vq->vq_avail_idx -= vq->vq_nentries; 17212e9e70cSTiwei Bie vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED; 173ec194c2fSJens Freimann } 174ec194c2fSJens Freimann 175ec194c2fSJens Freimann for (k = 0; k < pkt_num; k++) { 176ec194c2fSJens Freimann desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem 177ec194c2fSJens Freimann + sizeof(struct virtio_net_ctrl_hdr) 178ec194c2fSJens Freimann + sizeof(ctrl->status) + sizeof(uint8_t) * sum; 179ec194c2fSJens Freimann desc[vq->vq_avail_idx].len = dlen[k]; 1802923b8f9STiwei Bie desc[vq->vq_avail_idx].flags = VRING_DESC_F_NEXT | 181dfd33aa4STiwei Bie vq->vq_packed.cached_flags; 182ec194c2fSJens Freimann sum += dlen[k]; 183ec194c2fSJens Freimann vq->vq_free_cnt--; 1842923b8f9STiwei Bie nb_descs++; 185ec194c2fSJens Freimann if (++vq->vq_avail_idx >= vq->vq_nentries) { 186ec194c2fSJens Freimann vq->vq_avail_idx -= vq->vq_nentries; 187dfd33aa4STiwei Bie vq->vq_packed.cached_flags ^= 18812e9e70cSTiwei Bie VRING_PACKED_DESC_F_AVAIL_USED; 189ec194c2fSJens Freimann } 190ec194c2fSJens Freimann } 191ec194c2fSJens Freimann 192ec194c2fSJens Freimann desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem 193ec194c2fSJens Freimann + sizeof(struct virtio_net_ctrl_hdr); 194ec194c2fSJens Freimann desc[vq->vq_avail_idx].len = sizeof(ctrl->status); 195dfd33aa4STiwei Bie desc[vq->vq_avail_idx].flags = VRING_DESC_F_WRITE | 196dfd33aa4STiwei Bie vq->vq_packed.cached_flags; 197ec194c2fSJens Freimann vq->vq_free_cnt--; 1982923b8f9STiwei Bie nb_descs++; 199ec194c2fSJens Freimann if (++vq->vq_avail_idx >= vq->vq_nentries) { 200ec194c2fSJens Freimann vq->vq_avail_idx -= vq->vq_nentries; 20112e9e70cSTiwei Bie vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED; 202ec194c2fSJens Freimann } 203ec194c2fSJens Freimann 2042923b8f9STiwei Bie virtio_wmb(vq->hw->weak_barriers); 2058e148e49STiwei Bie desc[head].flags = VRING_DESC_F_NEXT | flags; 2062923b8f9STiwei Bie 2072923b8f9STiwei Bie virtio_wmb(vq->hw->weak_barriers); 208ec194c2fSJens Freimann virtqueue_notify(vq); 209ec194c2fSJens Freimann 210ec194c2fSJens Freimann /* wait for used descriptors in virtqueue */ 2112923b8f9STiwei Bie while (!desc_is_used(&desc[head], vq)) 212ec194c2fSJens Freimann usleep(100); 2132923b8f9STiwei Bie 2142923b8f9STiwei Bie virtio_rmb(vq->hw->weak_barriers); 215ec194c2fSJens Freimann 216ec194c2fSJens Freimann /* now get used descriptors */ 2172923b8f9STiwei Bie vq->vq_free_cnt += nb_descs; 2182923b8f9STiwei Bie vq->vq_used_cons_idx += nb_descs; 2192923b8f9STiwei Bie if (vq->vq_used_cons_idx >= vq->vq_nentries) { 220ec194c2fSJens Freimann vq->vq_used_cons_idx -= vq->vq_nentries; 221dfd33aa4STiwei Bie vq->vq_packed.used_wrap_counter ^= 1; 222ec194c2fSJens Freimann } 223ec194c2fSJens Freimann 22445c224e7STiwei Bie PMD_INIT_LOG(DEBUG, "vq->vq_free_cnt=%d\n" 22545c224e7STiwei Bie "vq->vq_avail_idx=%d\n" 22645c224e7STiwei Bie "vq->vq_used_cons_idx=%d\n" 227dfd33aa4STiwei Bie "vq->vq_packed.cached_flags=0x%x\n" 228dfd33aa4STiwei Bie "vq->vq_packed.used_wrap_counter=%d\n", 22945c224e7STiwei Bie vq->vq_free_cnt, 23045c224e7STiwei Bie vq->vq_avail_idx, 23145c224e7STiwei Bie vq->vq_used_cons_idx, 232dfd33aa4STiwei Bie vq->vq_packed.cached_flags, 233dfd33aa4STiwei Bie vq->vq_packed.used_wrap_counter); 23445c224e7STiwei Bie 235ec194c2fSJens Freimann result = cvq->virtio_net_hdr_mz->addr; 236ec194c2fSJens Freimann return result; 237ec194c2fSJens Freimann } 238ec194c2fSJens Freimann 239d5e1ce79STiwei Bie static struct virtio_pmd_ctrl * 240d5e1ce79STiwei Bie virtio_send_command_split(struct virtnet_ctl *cvq, 241d5e1ce79STiwei Bie struct virtio_pmd_ctrl *ctrl, 2426c3169a3SBruce Richardson int *dlen, int pkt_num) 2436c3169a3SBruce Richardson { 244d5e1ce79STiwei Bie struct virtio_pmd_ctrl *result; 245d5e1ce79STiwei Bie struct virtqueue *vq = cvq->vq; 2469e71668bSDamjan Marion uint32_t head, i; 2476c3169a3SBruce Richardson int k, sum = 0; 2486c3169a3SBruce Richardson 2499e71668bSDamjan Marion head = vq->vq_desc_head_idx; 2506c3169a3SBruce Richardson 2516c3169a3SBruce Richardson /* 2526c3169a3SBruce Richardson * Format is enforced in qemu code: 2536c3169a3SBruce Richardson * One TX packet for header; 2546c3169a3SBruce Richardson * At least one TX packet per argument; 2556c3169a3SBruce Richardson * One RX packet for ACK. 2566c3169a3SBruce Richardson */ 257dfd33aa4STiwei Bie vq->vq_split.ring.desc[head].flags = VRING_DESC_F_NEXT; 258dfd33aa4STiwei Bie vq->vq_split.ring.desc[head].addr = cvq->virtio_net_hdr_mem; 259dfd33aa4STiwei Bie vq->vq_split.ring.desc[head].len = sizeof(struct virtio_net_ctrl_hdr); 2606c3169a3SBruce Richardson vq->vq_free_cnt--; 261dfd33aa4STiwei Bie i = vq->vq_split.ring.desc[head].next; 2626c3169a3SBruce Richardson 2636c3169a3SBruce Richardson for (k = 0; k < pkt_num; k++) { 264dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].flags = VRING_DESC_F_NEXT; 265dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].addr = cvq->virtio_net_hdr_mem 2666c3169a3SBruce Richardson + sizeof(struct virtio_net_ctrl_hdr) 2676c3169a3SBruce Richardson + sizeof(ctrl->status) + sizeof(uint8_t)*sum; 268dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].len = dlen[k]; 2696c3169a3SBruce Richardson sum += dlen[k]; 2706c3169a3SBruce Richardson vq->vq_free_cnt--; 271dfd33aa4STiwei Bie i = vq->vq_split.ring.desc[i].next; 2726c3169a3SBruce Richardson } 2736c3169a3SBruce Richardson 274dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].flags = VRING_DESC_F_WRITE; 275dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].addr = cvq->virtio_net_hdr_mem 2766c3169a3SBruce Richardson + sizeof(struct virtio_net_ctrl_hdr); 277dfd33aa4STiwei Bie vq->vq_split.ring.desc[i].len = sizeof(ctrl->status); 2786c3169a3SBruce Richardson vq->vq_free_cnt--; 2796c3169a3SBruce Richardson 280dfd33aa4STiwei Bie vq->vq_desc_head_idx = vq->vq_split.ring.desc[i].next; 2816c3169a3SBruce Richardson 2826c3169a3SBruce Richardson vq_update_avail_ring(vq, head); 2836c3169a3SBruce Richardson vq_update_avail_idx(vq); 2846c3169a3SBruce Richardson 2856c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "vq->vq_queue_index = %d", vq->vq_queue_index); 2866c3169a3SBruce Richardson 2876c3169a3SBruce Richardson virtqueue_notify(vq); 2886c3169a3SBruce Richardson 2896c3169a3SBruce Richardson rte_rmb(); 290b81026f1SHuawei Xie while (VIRTQUEUE_NUSED(vq) == 0) { 2916c3169a3SBruce Richardson rte_rmb(); 2926c3169a3SBruce Richardson usleep(100); 2936c3169a3SBruce Richardson } 2946c3169a3SBruce Richardson 295b81026f1SHuawei Xie while (VIRTQUEUE_NUSED(vq)) { 2966c3169a3SBruce Richardson uint32_t idx, desc_idx, used_idx; 2976c3169a3SBruce Richardson struct vring_used_elem *uep; 2986c3169a3SBruce Richardson 2996c3169a3SBruce Richardson used_idx = (uint32_t)(vq->vq_used_cons_idx 3006c3169a3SBruce Richardson & (vq->vq_nentries - 1)); 301dfd33aa4STiwei Bie uep = &vq->vq_split.ring.used->ring[used_idx]; 3026c3169a3SBruce Richardson idx = (uint32_t) uep->id; 3036c3169a3SBruce Richardson desc_idx = idx; 3046c3169a3SBruce Richardson 305dfd33aa4STiwei Bie while (vq->vq_split.ring.desc[desc_idx].flags & 306dfd33aa4STiwei Bie VRING_DESC_F_NEXT) { 307dfd33aa4STiwei Bie desc_idx = vq->vq_split.ring.desc[desc_idx].next; 3086c3169a3SBruce Richardson vq->vq_free_cnt++; 3096c3169a3SBruce Richardson } 3106c3169a3SBruce Richardson 311dfd33aa4STiwei Bie vq->vq_split.ring.desc[desc_idx].next = vq->vq_desc_head_idx; 3126c3169a3SBruce Richardson vq->vq_desc_head_idx = idx; 3136c3169a3SBruce Richardson 3146c3169a3SBruce Richardson vq->vq_used_cons_idx++; 3156c3169a3SBruce Richardson vq->vq_free_cnt++; 3166c3169a3SBruce Richardson } 3176c3169a3SBruce Richardson 3186c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "vq->vq_free_cnt=%d\nvq->vq_desc_head_idx=%d", 3196c3169a3SBruce Richardson vq->vq_free_cnt, vq->vq_desc_head_idx); 3206c3169a3SBruce Richardson 321da4f2e4bSZhiyong Yang result = cvq->virtio_net_hdr_mz->addr; 322d5e1ce79STiwei Bie return result; 323d5e1ce79STiwei Bie } 3246c3169a3SBruce Richardson 325d5e1ce79STiwei Bie static int 326d5e1ce79STiwei Bie virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl, 327d5e1ce79STiwei Bie int *dlen, int pkt_num) 328d5e1ce79STiwei Bie { 329d5e1ce79STiwei Bie virtio_net_ctrl_ack status = ~0; 330d5e1ce79STiwei Bie struct virtio_pmd_ctrl *result; 331d5e1ce79STiwei Bie struct virtqueue *vq; 332d5e1ce79STiwei Bie 333d5e1ce79STiwei Bie ctrl->status = status; 334d5e1ce79STiwei Bie 335d5e1ce79STiwei Bie if (!cvq || !cvq->vq) { 336d5e1ce79STiwei Bie PMD_INIT_LOG(ERR, "Control queue is not supported."); 337d5e1ce79STiwei Bie return -1; 338d5e1ce79STiwei Bie } 339d5e1ce79STiwei Bie 340d5e1ce79STiwei Bie rte_spinlock_lock(&cvq->lock); 341d5e1ce79STiwei Bie vq = cvq->vq; 342d5e1ce79STiwei Bie 343d5e1ce79STiwei Bie PMD_INIT_LOG(DEBUG, "vq->vq_desc_head_idx = %d, status = %d, " 344d5e1ce79STiwei Bie "vq->hw->cvq = %p vq = %p", 345d5e1ce79STiwei Bie vq->vq_desc_head_idx, status, vq->hw->cvq, vq); 346d5e1ce79STiwei Bie 347d5e1ce79STiwei Bie if (vq->vq_free_cnt < pkt_num + 2 || pkt_num < 1) { 348d5e1ce79STiwei Bie rte_spinlock_unlock(&cvq->lock); 349d5e1ce79STiwei Bie return -1; 350d5e1ce79STiwei Bie } 351d5e1ce79STiwei Bie 352d5e1ce79STiwei Bie memcpy(cvq->virtio_net_hdr_mz->addr, ctrl, 353d5e1ce79STiwei Bie sizeof(struct virtio_pmd_ctrl)); 354d5e1ce79STiwei Bie 355d5e1ce79STiwei Bie if (vtpci_packed_queue(vq->hw)) 356d5e1ce79STiwei Bie result = virtio_send_command_packed(cvq, ctrl, dlen, pkt_num); 357d5e1ce79STiwei Bie else 358d5e1ce79STiwei Bie result = virtio_send_command_split(cvq, ctrl, dlen, pkt_num); 359d5e1ce79STiwei Bie 360a2ffb87bSXiao Wang rte_spinlock_unlock(&cvq->lock); 361da4f2e4bSZhiyong Yang return result->status; 3626c3169a3SBruce Richardson } 3636c3169a3SBruce Richardson 3646c3169a3SBruce Richardson static int 3656c3169a3SBruce Richardson virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues) 3666c3169a3SBruce Richardson { 3676c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 3686c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 3696c3169a3SBruce Richardson int dlen[1]; 3706c3169a3SBruce Richardson int ret; 3716c3169a3SBruce Richardson 3726c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_MQ; 3736c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET; 3746c3169a3SBruce Richardson memcpy(ctrl.data, &nb_queues, sizeof(uint16_t)); 3756c3169a3SBruce Richardson 3766c3169a3SBruce Richardson dlen[0] = sizeof(uint16_t); 3776c3169a3SBruce Richardson 3786c3169a3SBruce Richardson ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); 3796c3169a3SBruce Richardson if (ret) { 3806c3169a3SBruce Richardson PMD_INIT_LOG(ERR, "Multiqueue configured but send command " 3816c3169a3SBruce Richardson "failed, this is too late now..."); 3826c3169a3SBruce Richardson return -EINVAL; 3836c3169a3SBruce Richardson } 3846c3169a3SBruce Richardson 3856c3169a3SBruce Richardson return 0; 3866c3169a3SBruce Richardson } 3876c3169a3SBruce Richardson 38869c80d4eSYuanhan Liu static void 38969c80d4eSYuanhan Liu virtio_dev_queue_release(void *queue __rte_unused) 3902963d99aSJianfeng Tan { 39169c80d4eSYuanhan Liu /* do nothing */ 3925382b188SBernard Iremonger } 3935382b188SBernard Iremonger 39469c80d4eSYuanhan Liu static uint16_t 39569c80d4eSYuanhan Liu virtio_get_nr_vq(struct virtio_hw *hw) 39669c80d4eSYuanhan Liu { 39769c80d4eSYuanhan Liu uint16_t nr_vq = hw->max_queue_pairs * 2; 39869c80d4eSYuanhan Liu 39969c80d4eSYuanhan Liu if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ)) 40069c80d4eSYuanhan Liu nr_vq += 1; 40169c80d4eSYuanhan Liu 40269c80d4eSYuanhan Liu return nr_vq; 40369c80d4eSYuanhan Liu } 40469c80d4eSYuanhan Liu 405f4d1ad15SYuanhan Liu static void 406f4d1ad15SYuanhan Liu virtio_init_vring(struct virtqueue *vq) 407f4d1ad15SYuanhan Liu { 408f4d1ad15SYuanhan Liu int size = vq->vq_nentries; 409f4d1ad15SYuanhan Liu uint8_t *ring_mem = vq->vq_ring_virt_mem; 410f4d1ad15SYuanhan Liu 411f4d1ad15SYuanhan Liu PMD_INIT_FUNC_TRACE(); 412f4d1ad15SYuanhan Liu 413f4d1ad15SYuanhan Liu memset(ring_mem, 0, vq->vq_ring_size); 414f803734bSJens Freimann 415f4d1ad15SYuanhan Liu vq->vq_used_cons_idx = 0; 416f4d1ad15SYuanhan Liu vq->vq_desc_head_idx = 0; 417f4d1ad15SYuanhan Liu vq->vq_avail_idx = 0; 418f4d1ad15SYuanhan Liu vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1); 419f4d1ad15SYuanhan Liu vq->vq_free_cnt = vq->vq_nentries; 420f4d1ad15SYuanhan Liu memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries); 421f803734bSJens Freimann if (vtpci_packed_queue(vq->hw)) { 422dfd33aa4STiwei Bie vring_init_packed(&vq->vq_packed.ring, ring_mem, 423f803734bSJens Freimann VIRTIO_PCI_VRING_ALIGN, size); 424f803734bSJens Freimann vring_desc_init_packed(vq, size); 425f803734bSJens Freimann } else { 426dfd33aa4STiwei Bie struct vring *vr = &vq->vq_split.ring; 427dfd33aa4STiwei Bie 428f803734bSJens Freimann vring_init_split(vr, ring_mem, VIRTIO_PCI_VRING_ALIGN, size); 429f803734bSJens Freimann vring_desc_init_split(vr->desc, size); 430f803734bSJens Freimann } 431f4d1ad15SYuanhan Liu /* 432f4d1ad15SYuanhan Liu * Disable device(host) interrupting guest 433f4d1ad15SYuanhan Liu */ 434f4d1ad15SYuanhan Liu virtqueue_disable_intr(vq); 435f4d1ad15SYuanhan Liu } 436f4d1ad15SYuanhan Liu 43769c80d4eSYuanhan Liu static int 43869c80d4eSYuanhan Liu virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx) 4396c3169a3SBruce Richardson { 4406c3169a3SBruce Richardson char vq_name[VIRTQUEUE_MAX_NAME_SZ]; 44101ad44fdSHuawei Xie char vq_hdr_name[VIRTQUEUE_MAX_NAME_SZ]; 44201ad44fdSHuawei Xie const struct rte_memzone *mz = NULL, *hdr_mz = NULL; 4431e7bd238SStephen Hemminger unsigned int vq_size, size; 4446c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 445f24f8f9fSJianfeng Tan struct virtnet_rx *rxvq = NULL; 446f24f8f9fSJianfeng Tan struct virtnet_tx *txvq = NULL; 447f24f8f9fSJianfeng Tan struct virtnet_ctl *cvq = NULL; 44801ad44fdSHuawei Xie struct virtqueue *vq; 449905a2469SYuanhan Liu size_t sz_hdr_mz = 0; 45001ad44fdSHuawei Xie void *sw_ring = NULL; 45169c80d4eSYuanhan Liu int queue_type = virtio_get_queue_type(hw, vtpci_queue_idx); 45201ad44fdSHuawei Xie int ret; 4534a5140abSMaxime Coquelin int numa_node = dev->device->numa_node; 4546c3169a3SBruce Richardson 4554a5140abSMaxime Coquelin PMD_INIT_LOG(INFO, "setting up queue: %u on NUMA node %d", 4564a5140abSMaxime Coquelin vtpci_queue_idx, numa_node); 4576c3169a3SBruce Richardson 4586c3169a3SBruce Richardson /* 4596c3169a3SBruce Richardson * Read the virtqueue size from the Queue Size field 4606c3169a3SBruce Richardson * Always power of 2 and if 0 virtqueue does not exist 4616c3169a3SBruce Richardson */ 462553f4593SYuanhan Liu vq_size = VTPCI_OPS(hw)->get_queue_num(hw, vtpci_queue_idx); 46369c80d4eSYuanhan Liu PMD_INIT_LOG(DEBUG, "vq_size: %u", vq_size); 4646c3169a3SBruce Richardson if (vq_size == 0) { 4650bb159adSHuawei Xie PMD_INIT_LOG(ERR, "virtqueue does not exist"); 4666c3169a3SBruce Richardson return -EINVAL; 467d78deadaSStephen Hemminger } 468d78deadaSStephen Hemminger 469d78deadaSStephen Hemminger if (!rte_is_power_of_2(vq_size)) { 4700bb159adSHuawei Xie PMD_INIT_LOG(ERR, "virtqueue size is not powerof 2"); 4716c3169a3SBruce Richardson return -EINVAL; 472d78deadaSStephen Hemminger } 473d78deadaSStephen Hemminger 47473d017ddSYuanhan Liu snprintf(vq_name, sizeof(vq_name), "port%d_vq%d", 47573d017ddSYuanhan Liu dev->data->port_id, vtpci_queue_idx); 47601ad44fdSHuawei Xie 477905a2469SYuanhan Liu size = RTE_ALIGN_CEIL(sizeof(*vq) + 4786c3169a3SBruce Richardson vq_size * sizeof(struct vq_desc_extra), 4796c3169a3SBruce Richardson RTE_CACHE_LINE_SIZE); 480905a2469SYuanhan Liu if (queue_type == VTNET_TQ) { 48101ad44fdSHuawei Xie /* 48201ad44fdSHuawei Xie * For each xmit packet, allocate a virtio_net_hdr 48301ad44fdSHuawei Xie * and indirect ring elements 48401ad44fdSHuawei Xie */ 48501ad44fdSHuawei Xie sz_hdr_mz = vq_size * sizeof(struct virtio_tx_region); 48601ad44fdSHuawei Xie } else if (queue_type == VTNET_CQ) { 48701ad44fdSHuawei Xie /* Allocate a page for control vq command, data and status */ 48801ad44fdSHuawei Xie sz_hdr_mz = PAGE_SIZE; 48901ad44fdSHuawei Xie } 4904166bbf6SJianfeng Tan 49169c80d4eSYuanhan Liu vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE, 4924a5140abSMaxime Coquelin numa_node); 49301ad44fdSHuawei Xie if (vq == NULL) { 49401ad44fdSHuawei Xie PMD_INIT_LOG(ERR, "can not allocate vq"); 495cab04612SHuawei Xie return -ENOMEM; 496cab04612SHuawei Xie } 49769c80d4eSYuanhan Liu hw->vqs[vtpci_queue_idx] = vq; 49869c80d4eSYuanhan Liu 4996c3169a3SBruce Richardson vq->hw = hw; 5006c3169a3SBruce Richardson vq->vq_queue_index = vtpci_queue_idx; 5016c3169a3SBruce Richardson vq->vq_nentries = vq_size; 502f803734bSJens Freimann if (vtpci_packed_queue(hw)) { 503dfd33aa4STiwei Bie vq->vq_packed.used_wrap_counter = 1; 50412e9e70cSTiwei Bie vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL; 505dfd33aa4STiwei Bie vq->vq_packed.event_flags_shadow = 0; 5068e148e49STiwei Bie if (queue_type == VTNET_RQ) 507dfd33aa4STiwei Bie vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE; 508f803734bSJens Freimann } 5096c3169a3SBruce Richardson 5106c3169a3SBruce Richardson /* 5116c3169a3SBruce Richardson * Reserve a memzone for vring elements 5126c3169a3SBruce Richardson */ 513f803734bSJens Freimann size = vring_size(hw, vq_size, VIRTIO_PCI_VRING_ALIGN); 5146c3169a3SBruce Richardson vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN); 51501ad44fdSHuawei Xie PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d", 51601ad44fdSHuawei Xie size, vq->vq_ring_size); 5176c3169a3SBruce Richardson 51869c80d4eSYuanhan Liu mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size, 5194a5140abSMaxime Coquelin numa_node, RTE_MEMZONE_IOVA_CONTIG, 52025553d44SAnatoly Burakov VIRTIO_PCI_VRING_ALIGN); 5216c3169a3SBruce Richardson if (mz == NULL) { 522abf4c84bSBernard Iremonger if (rte_errno == EEXIST) 523abf4c84bSBernard Iremonger mz = rte_memzone_lookup(vq_name); 524abf4c84bSBernard Iremonger if (mz == NULL) { 52501ad44fdSHuawei Xie ret = -ENOMEM; 52601ad44fdSHuawei Xie goto fail_q_alloc; 5276c3169a3SBruce Richardson } 528abf4c84bSBernard Iremonger } 5296c3169a3SBruce Richardson 5305bdd24e4STiwei Bie memset(mz->addr, 0, mz->len); 53101ad44fdSHuawei Xie 532f17ca787SThomas Monjalon vq->vq_ring_mem = mz->iova; 5336c3169a3SBruce Richardson vq->vq_ring_virt_mem = mz->addr; 53401ad44fdSHuawei Xie PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64, 535f17ca787SThomas Monjalon (uint64_t)mz->iova); 53601ad44fdSHuawei Xie PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: 0x%" PRIx64, 53701ad44fdSHuawei Xie (uint64_t)(uintptr_t)mz->addr); 5386c3169a3SBruce Richardson 539f4d1ad15SYuanhan Liu virtio_init_vring(vq); 540f4d1ad15SYuanhan Liu 54101ad44fdSHuawei Xie if (sz_hdr_mz) { 54273d017ddSYuanhan Liu snprintf(vq_hdr_name, sizeof(vq_hdr_name), "port%d_vq%d_hdr", 54373d017ddSYuanhan Liu dev->data->port_id, vtpci_queue_idx); 54401ad44fdSHuawei Xie hdr_mz = rte_memzone_reserve_aligned(vq_hdr_name, sz_hdr_mz, 5454a5140abSMaxime Coquelin numa_node, RTE_MEMZONE_IOVA_CONTIG, 5466dc5de3aSStephen Hemminger RTE_CACHE_LINE_SIZE); 5476dc5de3aSStephen Hemminger if (hdr_mz == NULL) { 548abf4c84bSBernard Iremonger if (rte_errno == EEXIST) 54901ad44fdSHuawei Xie hdr_mz = rte_memzone_lookup(vq_hdr_name); 5506dc5de3aSStephen Hemminger if (hdr_mz == NULL) { 55101ad44fdSHuawei Xie ret = -ENOMEM; 55201ad44fdSHuawei Xie goto fail_q_alloc; 5536c3169a3SBruce Richardson } 554abf4c84bSBernard Iremonger } 55501ad44fdSHuawei Xie } 55601ad44fdSHuawei Xie 55701ad44fdSHuawei Xie if (queue_type == VTNET_RQ) { 55801ad44fdSHuawei Xie size_t sz_sw = (RTE_PMD_VIRTIO_RX_MAX_BURST + vq_size) * 55901ad44fdSHuawei Xie sizeof(vq->sw_ring[0]); 56001ad44fdSHuawei Xie 56101ad44fdSHuawei Xie sw_ring = rte_zmalloc_socket("sw_ring", sz_sw, 5624a5140abSMaxime Coquelin RTE_CACHE_LINE_SIZE, numa_node); 56301ad44fdSHuawei Xie if (!sw_ring) { 56401ad44fdSHuawei Xie PMD_INIT_LOG(ERR, "can not allocate RX soft ring"); 56501ad44fdSHuawei Xie ret = -ENOMEM; 56601ad44fdSHuawei Xie goto fail_q_alloc; 56701ad44fdSHuawei Xie } 56801ad44fdSHuawei Xie 56901ad44fdSHuawei Xie vq->sw_ring = sw_ring; 570905a2469SYuanhan Liu rxvq = &vq->rxq; 57101ad44fdSHuawei Xie rxvq->vq = vq; 57201ad44fdSHuawei Xie rxvq->port_id = dev->data->port_id; 57301ad44fdSHuawei Xie rxvq->mz = mz; 57401ad44fdSHuawei Xie } else if (queue_type == VTNET_TQ) { 575905a2469SYuanhan Liu txvq = &vq->txq; 57601ad44fdSHuawei Xie txvq->vq = vq; 57701ad44fdSHuawei Xie txvq->port_id = dev->data->port_id; 57801ad44fdSHuawei Xie txvq->mz = mz; 57901ad44fdSHuawei Xie txvq->virtio_net_hdr_mz = hdr_mz; 580f17ca787SThomas Monjalon txvq->virtio_net_hdr_mem = hdr_mz->iova; 581f24f8f9fSJianfeng Tan } else if (queue_type == VTNET_CQ) { 582905a2469SYuanhan Liu cvq = &vq->cq; 583f24f8f9fSJianfeng Tan cvq->vq = vq; 584f24f8f9fSJianfeng Tan cvq->mz = mz; 585f24f8f9fSJianfeng Tan cvq->virtio_net_hdr_mz = hdr_mz; 586f17ca787SThomas Monjalon cvq->virtio_net_hdr_mem = hdr_mz->iova; 587f24f8f9fSJianfeng Tan memset(cvq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE); 58869c80d4eSYuanhan Liu 58969c80d4eSYuanhan Liu hw->cvq = cvq; 590f24f8f9fSJianfeng Tan } 591f24f8f9fSJianfeng Tan 5926a7c0dfcSJan Blunck /* For virtio_user case (that is when hw->dev is NULL), we use 593f24f8f9fSJianfeng Tan * virtual address. And we need properly set _offset_, please see 59425f80d10SOlivier Matz * VIRTIO_MBUF_DATA_DMA_ADDR in virtqueue.h for more information. 595f24f8f9fSJianfeng Tan */ 5969470427cSYuanhan Liu if (!hw->virtio_user_dev) 597455da545SSantosh Shukla vq->offset = offsetof(struct rte_mbuf, buf_iova); 598f24f8f9fSJianfeng Tan else { 599f24f8f9fSJianfeng Tan vq->vq_ring_mem = (uintptr_t)mz->addr; 600f24f8f9fSJianfeng Tan vq->offset = offsetof(struct rte_mbuf, buf_addr); 601f24f8f9fSJianfeng Tan if (queue_type == VTNET_TQ) 602f24f8f9fSJianfeng Tan txvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr; 603f24f8f9fSJianfeng Tan else if (queue_type == VTNET_CQ) 604f24f8f9fSJianfeng Tan cvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr; 605f24f8f9fSJianfeng Tan } 606f24f8f9fSJianfeng Tan 607f24f8f9fSJianfeng Tan if (queue_type == VTNET_TQ) { 608f24f8f9fSJianfeng Tan struct virtio_tx_region *txr; 609f24f8f9fSJianfeng Tan unsigned int i; 610f24f8f9fSJianfeng Tan 6116dc5de3aSStephen Hemminger txr = hdr_mz->addr; 6126dc5de3aSStephen Hemminger memset(txr, 0, vq_size * sizeof(*txr)); 6136dc5de3aSStephen Hemminger for (i = 0; i < vq_size; i++) { 6146dc5de3aSStephen Hemminger struct vring_desc *start_dp = txr[i].tx_indir; 6156dc5de3aSStephen Hemminger 6166dc5de3aSStephen Hemminger /* first indirect descriptor is always the tx header */ 617bc80357cSTiwei Bie if (!vtpci_packed_queue(hw)) { 618892dc798SJens Freimann vring_desc_init_split(start_dp, 619892dc798SJens Freimann RTE_DIM(txr[i].tx_indir)); 62001ad44fdSHuawei Xie start_dp->addr = txvq->virtio_net_hdr_mem 6216dc5de3aSStephen Hemminger + i * sizeof(*txr) 622892dc798SJens Freimann + offsetof(struct virtio_tx_region, 623892dc798SJens Freimann tx_hdr); 62401ad44fdSHuawei Xie start_dp->len = hw->vtnet_hdr_size; 6256dc5de3aSStephen Hemminger start_dp->flags = VRING_DESC_F_NEXT; 6266dc5de3aSStephen Hemminger } 6276c3169a3SBruce Richardson } 628892dc798SJens Freimann } 6296c3169a3SBruce Richardson 630553f4593SYuanhan Liu if (VTPCI_OPS(hw)->setup_queue(hw, vq) < 0) { 631595454c5SJianfeng Tan PMD_INIT_LOG(ERR, "setup_queue failed"); 632595454c5SJianfeng Tan return -EINVAL; 633595454c5SJianfeng Tan } 634595454c5SJianfeng Tan 6356c3169a3SBruce Richardson return 0; 63601ad44fdSHuawei Xie 63701ad44fdSHuawei Xie fail_q_alloc: 63801ad44fdSHuawei Xie rte_free(sw_ring); 63901ad44fdSHuawei Xie rte_memzone_free(hdr_mz); 64001ad44fdSHuawei Xie rte_memzone_free(mz); 64101ad44fdSHuawei Xie rte_free(vq); 64201ad44fdSHuawei Xie 64301ad44fdSHuawei Xie return ret; 6446c3169a3SBruce Richardson } 6456c3169a3SBruce Richardson 64669c80d4eSYuanhan Liu static void 64769c80d4eSYuanhan Liu virtio_free_queues(struct virtio_hw *hw) 6486c3169a3SBruce Richardson { 64969c80d4eSYuanhan Liu uint16_t nr_vq = virtio_get_nr_vq(hw); 65069c80d4eSYuanhan Liu struct virtqueue *vq; 65169c80d4eSYuanhan Liu int queue_type; 65269c80d4eSYuanhan Liu uint16_t i; 6536c3169a3SBruce Richardson 6540e78cfddSHuanle Han if (hw->vqs == NULL) 6550e78cfddSHuanle Han return; 6560e78cfddSHuanle Han 65769c80d4eSYuanhan Liu for (i = 0; i < nr_vq; i++) { 65869c80d4eSYuanhan Liu vq = hw->vqs[i]; 65969c80d4eSYuanhan Liu if (!vq) 66069c80d4eSYuanhan Liu continue; 66169c80d4eSYuanhan Liu 66269c80d4eSYuanhan Liu queue_type = virtio_get_queue_type(hw, i); 66369c80d4eSYuanhan Liu if (queue_type == VTNET_RQ) { 66469c80d4eSYuanhan Liu rte_free(vq->sw_ring); 66569c80d4eSYuanhan Liu rte_memzone_free(vq->rxq.mz); 66669c80d4eSYuanhan Liu } else if (queue_type == VTNET_TQ) { 66769c80d4eSYuanhan Liu rte_memzone_free(vq->txq.mz); 66869c80d4eSYuanhan Liu rte_memzone_free(vq->txq.virtio_net_hdr_mz); 66969c80d4eSYuanhan Liu } else { 67069c80d4eSYuanhan Liu rte_memzone_free(vq->cq.mz); 67169c80d4eSYuanhan Liu rte_memzone_free(vq->cq.virtio_net_hdr_mz); 67269c80d4eSYuanhan Liu } 67369c80d4eSYuanhan Liu 67469c80d4eSYuanhan Liu rte_free(vq); 6750e78cfddSHuanle Han hw->vqs[i] = NULL; 67669c80d4eSYuanhan Liu } 67769c80d4eSYuanhan Liu 67869c80d4eSYuanhan Liu rte_free(hw->vqs); 6790e78cfddSHuanle Han hw->vqs = NULL; 68069c80d4eSYuanhan Liu } 68169c80d4eSYuanhan Liu 68269c80d4eSYuanhan Liu static int 68369c80d4eSYuanhan Liu virtio_alloc_queues(struct rte_eth_dev *dev) 68469c80d4eSYuanhan Liu { 68569c80d4eSYuanhan Liu struct virtio_hw *hw = dev->data->dev_private; 68669c80d4eSYuanhan Liu uint16_t nr_vq = virtio_get_nr_vq(hw); 68769c80d4eSYuanhan Liu uint16_t i; 68869c80d4eSYuanhan Liu int ret; 68969c80d4eSYuanhan Liu 69069c80d4eSYuanhan Liu hw->vqs = rte_zmalloc(NULL, sizeof(struct virtqueue *) * nr_vq, 0); 69169c80d4eSYuanhan Liu if (!hw->vqs) { 69269c80d4eSYuanhan Liu PMD_INIT_LOG(ERR, "failed to allocate vqs"); 69369c80d4eSYuanhan Liu return -ENOMEM; 69469c80d4eSYuanhan Liu } 69569c80d4eSYuanhan Liu 69669c80d4eSYuanhan Liu for (i = 0; i < nr_vq; i++) { 69769c80d4eSYuanhan Liu ret = virtio_init_queue(dev, i); 6986c3169a3SBruce Richardson if (ret < 0) { 69969c80d4eSYuanhan Liu virtio_free_queues(hw); 7006c3169a3SBruce Richardson return ret; 7016c3169a3SBruce Richardson } 7026c3169a3SBruce Richardson } 7036c3169a3SBruce Richardson 70469c80d4eSYuanhan Liu return 0; 705941d64b5SBernard Iremonger } 706941d64b5SBernard Iremonger 7079ebdeefeSJianfeng Tan static void virtio_queues_unbind_intr(struct rte_eth_dev *dev); 7089ebdeefeSJianfeng Tan 709941d64b5SBernard Iremonger static void 7106c3169a3SBruce Richardson virtio_dev_close(struct rte_eth_dev *dev) 7116c3169a3SBruce Richardson { 7126c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 7139ebdeefeSJianfeng Tan struct rte_intr_conf *intr_conf = &dev->data->dev_conf.intr_conf; 7146c3169a3SBruce Richardson 7156c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "virtio_dev_close"); 7166c3169a3SBruce Richardson 7172a821d81SChas Williams if (!hw->opened) 7182a821d81SChas Williams return; 7192a821d81SChas Williams hw->opened = false; 7202a821d81SChas Williams 7216c3169a3SBruce Richardson /* reset the NIC */ 72262a785a6SJianfeng Tan if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) 723981e61f5SJianfeng Tan VTPCI_OPS(hw)->set_config_irq(hw, VIRTIO_MSI_NO_VECTOR); 7249ebdeefeSJianfeng Tan if (intr_conf->rxq) 7259ebdeefeSJianfeng Tan virtio_queues_unbind_intr(dev); 7269ebdeefeSJianfeng Tan 7279ebdeefeSJianfeng Tan if (intr_conf->lsc || intr_conf->rxq) { 728fe19d49cSZhiyong Yang virtio_intr_disable(dev); 7299ebdeefeSJianfeng Tan rte_intr_efd_disable(dev->intr_handle); 7309ebdeefeSJianfeng Tan rte_free(dev->intr_handle->intr_vec); 7319ebdeefeSJianfeng Tan dev->intr_handle->intr_vec = NULL; 7329ebdeefeSJianfeng Tan } 7339ebdeefeSJianfeng Tan 7346c3169a3SBruce Richardson vtpci_reset(hw); 7356c3169a3SBruce Richardson virtio_dev_free_mbufs(dev); 73669c80d4eSYuanhan Liu virtio_free_queues(hw); 7377f468b2eSTiwei Bie 7387f468b2eSTiwei Bie #ifdef RTE_VIRTIO_USER 7397f468b2eSTiwei Bie if (hw->virtio_user_dev) 7407f468b2eSTiwei Bie virtio_user_dev_uninit(hw->virtio_user_dev); 7417f468b2eSTiwei Bie else 7427f468b2eSTiwei Bie #endif 7437f468b2eSTiwei Bie if (dev->device) { 7447f468b2eSTiwei Bie rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(dev)); 7457f468b2eSTiwei Bie if (!hw->modern) 7467f468b2eSTiwei Bie rte_pci_ioport_unmap(VTPCI_IO(hw)); 7477f468b2eSTiwei Bie } 7486c3169a3SBruce Richardson } 7496c3169a3SBruce Richardson 7506c3169a3SBruce Richardson static void 7516c3169a3SBruce Richardson virtio_dev_promiscuous_enable(struct rte_eth_dev *dev) 7526c3169a3SBruce Richardson { 7536c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 7546c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 7556c3169a3SBruce Richardson int dlen[1]; 7566c3169a3SBruce Richardson int ret; 7576c3169a3SBruce Richardson 758e9e414a4SStephen Hemminger if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) { 759f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "host does not support rx control"); 760e9e414a4SStephen Hemminger return; 761e9e414a4SStephen Hemminger } 762e9e414a4SStephen Hemminger 7636c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_RX; 7646c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC; 7656c3169a3SBruce Richardson ctrl.data[0] = 1; 7666c3169a3SBruce Richardson dlen[0] = 1; 7676c3169a3SBruce Richardson 7686c3169a3SBruce Richardson ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); 7696c3169a3SBruce Richardson if (ret) 7706c3169a3SBruce Richardson PMD_INIT_LOG(ERR, "Failed to enable promisc"); 7716c3169a3SBruce Richardson } 7726c3169a3SBruce Richardson 7736c3169a3SBruce Richardson static void 7746c3169a3SBruce Richardson virtio_dev_promiscuous_disable(struct rte_eth_dev *dev) 7756c3169a3SBruce Richardson { 7766c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 7776c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 7786c3169a3SBruce Richardson int dlen[1]; 7796c3169a3SBruce Richardson int ret; 7806c3169a3SBruce Richardson 781e9e414a4SStephen Hemminger if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) { 782f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "host does not support rx control"); 783e9e414a4SStephen Hemminger return; 784e9e414a4SStephen Hemminger } 785e9e414a4SStephen Hemminger 7866c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_RX; 7876c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC; 7886c3169a3SBruce Richardson ctrl.data[0] = 0; 7896c3169a3SBruce Richardson dlen[0] = 1; 7906c3169a3SBruce Richardson 7916c3169a3SBruce Richardson ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); 7926c3169a3SBruce Richardson if (ret) 7936c3169a3SBruce Richardson PMD_INIT_LOG(ERR, "Failed to disable promisc"); 7946c3169a3SBruce Richardson } 7956c3169a3SBruce Richardson 7966c3169a3SBruce Richardson static void 7976c3169a3SBruce Richardson virtio_dev_allmulticast_enable(struct rte_eth_dev *dev) 7986c3169a3SBruce Richardson { 7996c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 8006c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 8016c3169a3SBruce Richardson int dlen[1]; 8026c3169a3SBruce Richardson int ret; 8036c3169a3SBruce Richardson 804e9e414a4SStephen Hemminger if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) { 805f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "host does not support rx control"); 806e9e414a4SStephen Hemminger return; 807e9e414a4SStephen Hemminger } 808e9e414a4SStephen Hemminger 8096c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_RX; 8106c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI; 8116c3169a3SBruce Richardson ctrl.data[0] = 1; 8126c3169a3SBruce Richardson dlen[0] = 1; 8136c3169a3SBruce Richardson 8146c3169a3SBruce Richardson ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); 8156c3169a3SBruce Richardson if (ret) 8166c3169a3SBruce Richardson PMD_INIT_LOG(ERR, "Failed to enable allmulticast"); 8176c3169a3SBruce Richardson } 8186c3169a3SBruce Richardson 8196c3169a3SBruce Richardson static void 8206c3169a3SBruce Richardson virtio_dev_allmulticast_disable(struct rte_eth_dev *dev) 8216c3169a3SBruce Richardson { 8226c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 8236c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 8246c3169a3SBruce Richardson int dlen[1]; 8256c3169a3SBruce Richardson int ret; 8266c3169a3SBruce Richardson 827e9e414a4SStephen Hemminger if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) { 828f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "host does not support rx control"); 829e9e414a4SStephen Hemminger return; 830e9e414a4SStephen Hemminger } 831e9e414a4SStephen Hemminger 8326c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_RX; 8336c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI; 8346c3169a3SBruce Richardson ctrl.data[0] = 0; 8356c3169a3SBruce Richardson dlen[0] = 1; 8366c3169a3SBruce Richardson 8376c3169a3SBruce Richardson ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1); 8386c3169a3SBruce Richardson if (ret) 8396c3169a3SBruce Richardson PMD_INIT_LOG(ERR, "Failed to disable allmulticast"); 8406c3169a3SBruce Richardson } 8416c3169a3SBruce Richardson 8424ec2424aSSouvik Dey #define VLAN_TAG_LEN 4 /* 802.3ac tag (not DMA'd) */ 8434ec2424aSSouvik Dey static int 8444ec2424aSSouvik Dey virtio_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) 8454ec2424aSSouvik Dey { 8464ec2424aSSouvik Dey struct virtio_hw *hw = dev->data->dev_private; 84735b2d13fSOlivier Matz uint32_t ether_hdr_len = RTE_ETHER_HDR_LEN + VLAN_TAG_LEN + 8484ec2424aSSouvik Dey hw->vtnet_hdr_size; 8494ec2424aSSouvik Dey uint32_t frame_size = mtu + ether_hdr_len; 85049d26d9eSMaxime Coquelin uint32_t max_frame_size = hw->max_mtu + ether_hdr_len; 8514ec2424aSSouvik Dey 85249d26d9eSMaxime Coquelin max_frame_size = RTE_MIN(max_frame_size, VIRTIO_MAX_RX_PKTLEN); 85349d26d9eSMaxime Coquelin 85435b2d13fSOlivier Matz if (mtu < RTE_ETHER_MIN_MTU || frame_size > max_frame_size) { 855f2462150SFerruh Yigit PMD_INIT_LOG(ERR, "MTU should be between %d and %d", 85635b2d13fSOlivier Matz RTE_ETHER_MIN_MTU, max_frame_size - ether_hdr_len); 8574ec2424aSSouvik Dey return -EINVAL; 8584ec2424aSSouvik Dey } 8594ec2424aSSouvik Dey return 0; 8604ec2424aSSouvik Dey } 8614ec2424aSSouvik Dey 862c056be23SJianfeng Tan static int 863c056be23SJianfeng Tan virtio_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id) 864c056be23SJianfeng Tan { 8658f66bc4aSTiwei Bie struct virtio_hw *hw = dev->data->dev_private; 866c056be23SJianfeng Tan struct virtnet_rx *rxvq = dev->data->rx_queues[queue_id]; 867c056be23SJianfeng Tan struct virtqueue *vq = rxvq->vq; 868c056be23SJianfeng Tan 869c056be23SJianfeng Tan virtqueue_enable_intr(vq); 8708f66bc4aSTiwei Bie virtio_mb(hw->weak_barriers); 871c056be23SJianfeng Tan return 0; 872c056be23SJianfeng Tan } 873c056be23SJianfeng Tan 874c056be23SJianfeng Tan static int 875c056be23SJianfeng Tan virtio_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id) 876c056be23SJianfeng Tan { 877c056be23SJianfeng Tan struct virtnet_rx *rxvq = dev->data->rx_queues[queue_id]; 878c056be23SJianfeng Tan struct virtqueue *vq = rxvq->vq; 879c056be23SJianfeng Tan 880c056be23SJianfeng Tan virtqueue_disable_intr(vq); 881c056be23SJianfeng Tan return 0; 882c056be23SJianfeng Tan } 883c056be23SJianfeng Tan 8846c3169a3SBruce Richardson /* 8856c3169a3SBruce Richardson * dev_ops for virtio, bare necessities for basic operation 8866c3169a3SBruce Richardson */ 8876c3169a3SBruce Richardson static const struct eth_dev_ops virtio_eth_dev_ops = { 8886c3169a3SBruce Richardson .dev_configure = virtio_dev_configure, 8896c3169a3SBruce Richardson .dev_start = virtio_dev_start, 8906c3169a3SBruce Richardson .dev_stop = virtio_dev_stop, 8916c3169a3SBruce Richardson .dev_close = virtio_dev_close, 8926c3169a3SBruce Richardson .promiscuous_enable = virtio_dev_promiscuous_enable, 8936c3169a3SBruce Richardson .promiscuous_disable = virtio_dev_promiscuous_disable, 8946c3169a3SBruce Richardson .allmulticast_enable = virtio_dev_allmulticast_enable, 8956c3169a3SBruce Richardson .allmulticast_disable = virtio_dev_allmulticast_disable, 8964ec2424aSSouvik Dey .mtu_set = virtio_mtu_set, 8976c3169a3SBruce Richardson .dev_infos_get = virtio_dev_info_get, 8986c3169a3SBruce Richardson .stats_get = virtio_dev_stats_get, 89976d4c652SHarry van Haaren .xstats_get = virtio_dev_xstats_get, 900baf91c39SRemy Horton .xstats_get_names = virtio_dev_xstats_get_names, 9016c3169a3SBruce Richardson .stats_reset = virtio_dev_stats_reset, 90276d4c652SHarry van Haaren .xstats_reset = virtio_dev_stats_reset, 9036c3169a3SBruce Richardson .link_update = virtio_dev_link_update, 904289ba0c0SDavid Harton .vlan_offload_set = virtio_dev_vlan_offload_set, 9056c3169a3SBruce Richardson .rx_queue_setup = virtio_dev_rx_queue_setup, 906c056be23SJianfeng Tan .rx_queue_intr_enable = virtio_dev_rx_queue_intr_enable, 907c056be23SJianfeng Tan .rx_queue_intr_disable = virtio_dev_rx_queue_intr_disable, 90869c80d4eSYuanhan Liu .rx_queue_release = virtio_dev_queue_release, 909b0caba1aSJianfeng Tan .rx_descriptor_done = virtio_dev_rx_queue_done, 9106c3169a3SBruce Richardson .tx_queue_setup = virtio_dev_tx_queue_setup, 91169c80d4eSYuanhan Liu .tx_queue_release = virtio_dev_queue_release, 9126c3169a3SBruce Richardson /* collect stats per queue */ 9136c3169a3SBruce Richardson .queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set, 9146c3169a3SBruce Richardson .vlan_filter_set = virtio_vlan_filter_set, 9156c3169a3SBruce Richardson .mac_addr_add = virtio_mac_addr_add, 9166c3169a3SBruce Richardson .mac_addr_remove = virtio_mac_addr_remove, 9176c3169a3SBruce Richardson .mac_addr_set = virtio_mac_addr_set, 9186c3169a3SBruce Richardson }; 9196c3169a3SBruce Richardson 9201c8489daSTiwei Bie /* 9211c8489daSTiwei Bie * dev_ops for virtio-user in secondary processes, as we just have 9221c8489daSTiwei Bie * some limited supports currently. 9231c8489daSTiwei Bie */ 9241c8489daSTiwei Bie const struct eth_dev_ops virtio_user_secondary_eth_dev_ops = { 9251c8489daSTiwei Bie .dev_infos_get = virtio_dev_info_get, 9261c8489daSTiwei Bie .stats_get = virtio_dev_stats_get, 9271c8489daSTiwei Bie .xstats_get = virtio_dev_xstats_get, 9281c8489daSTiwei Bie .xstats_get_names = virtio_dev_xstats_get_names, 9291c8489daSTiwei Bie .stats_reset = virtio_dev_stats_reset, 9301c8489daSTiwei Bie .xstats_reset = virtio_dev_stats_reset, 9311c8489daSTiwei Bie /* collect stats per queue */ 9321c8489daSTiwei Bie .queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set, 9331c8489daSTiwei Bie }; 9341c8489daSTiwei Bie 9356c3169a3SBruce Richardson static void 93676d4c652SHarry van Haaren virtio_update_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats) 9376c3169a3SBruce Richardson { 9386c3169a3SBruce Richardson unsigned i; 9396c3169a3SBruce Richardson 9406c3169a3SBruce Richardson for (i = 0; i < dev->data->nb_tx_queues; i++) { 94101ad44fdSHuawei Xie const struct virtnet_tx *txvq = dev->data->tx_queues[i]; 9426c3169a3SBruce Richardson if (txvq == NULL) 9436c3169a3SBruce Richardson continue; 9446c3169a3SBruce Richardson 94501ad44fdSHuawei Xie stats->opackets += txvq->stats.packets; 94601ad44fdSHuawei Xie stats->obytes += txvq->stats.bytes; 94701ad44fdSHuawei Xie stats->oerrors += txvq->stats.errors; 9486c3169a3SBruce Richardson 9496c3169a3SBruce Richardson if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 95001ad44fdSHuawei Xie stats->q_opackets[i] = txvq->stats.packets; 95101ad44fdSHuawei Xie stats->q_obytes[i] = txvq->stats.bytes; 9526c3169a3SBruce Richardson } 9536c3169a3SBruce Richardson } 9546c3169a3SBruce Richardson 9556c3169a3SBruce Richardson for (i = 0; i < dev->data->nb_rx_queues; i++) { 95601ad44fdSHuawei Xie const struct virtnet_rx *rxvq = dev->data->rx_queues[i]; 9576c3169a3SBruce Richardson if (rxvq == NULL) 9586c3169a3SBruce Richardson continue; 9596c3169a3SBruce Richardson 96001ad44fdSHuawei Xie stats->ipackets += rxvq->stats.packets; 96101ad44fdSHuawei Xie stats->ibytes += rxvq->stats.bytes; 96201ad44fdSHuawei Xie stats->ierrors += rxvq->stats.errors; 9636c3169a3SBruce Richardson 9646c3169a3SBruce Richardson if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 96501ad44fdSHuawei Xie stats->q_ipackets[i] = rxvq->stats.packets; 96601ad44fdSHuawei Xie stats->q_ibytes[i] = rxvq->stats.bytes; 9676c3169a3SBruce Richardson } 9686c3169a3SBruce Richardson } 9696c3169a3SBruce Richardson 9706c3169a3SBruce Richardson stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed; 9716c3169a3SBruce Richardson } 9726c3169a3SBruce Richardson 973baf91c39SRemy Horton static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev, 974baf91c39SRemy Horton struct rte_eth_xstat_name *xstats_names, 975baf91c39SRemy Horton __rte_unused unsigned limit) 976baf91c39SRemy Horton { 977baf91c39SRemy Horton unsigned i; 978baf91c39SRemy Horton unsigned count = 0; 979baf91c39SRemy Horton unsigned t; 980baf91c39SRemy Horton 98101ad44fdSHuawei Xie unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS + 98201ad44fdSHuawei Xie dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS; 983baf91c39SRemy Horton 9847e1eb993SYuanhan Liu if (xstats_names != NULL) { 985baf91c39SRemy Horton /* Note: limit checked in rte_eth_xstats_names() */ 986baf91c39SRemy Horton 987baf91c39SRemy Horton for (i = 0; i < dev->data->nb_rx_queues; i++) { 98843ec842cSDidier Pallard struct virtnet_rx *rxvq = dev->data->rx_queues[i]; 989baf91c39SRemy Horton if (rxvq == NULL) 990baf91c39SRemy Horton continue; 99101ad44fdSHuawei Xie for (t = 0; t < VIRTIO_NB_RXQ_XSTATS; t++) { 992baf91c39SRemy Horton snprintf(xstats_names[count].name, 993baf91c39SRemy Horton sizeof(xstats_names[count].name), 994baf91c39SRemy Horton "rx_q%u_%s", i, 99501ad44fdSHuawei Xie rte_virtio_rxq_stat_strings[t].name); 996baf91c39SRemy Horton count++; 997baf91c39SRemy Horton } 998baf91c39SRemy Horton } 999baf91c39SRemy Horton 1000baf91c39SRemy Horton for (i = 0; i < dev->data->nb_tx_queues; i++) { 100143ec842cSDidier Pallard struct virtnet_tx *txvq = dev->data->tx_queues[i]; 1002baf91c39SRemy Horton if (txvq == NULL) 1003baf91c39SRemy Horton continue; 100401ad44fdSHuawei Xie for (t = 0; t < VIRTIO_NB_TXQ_XSTATS; t++) { 1005baf91c39SRemy Horton snprintf(xstats_names[count].name, 1006baf91c39SRemy Horton sizeof(xstats_names[count].name), 1007baf91c39SRemy Horton "tx_q%u_%s", i, 100801ad44fdSHuawei Xie rte_virtio_txq_stat_strings[t].name); 1009baf91c39SRemy Horton count++; 1010baf91c39SRemy Horton } 1011baf91c39SRemy Horton } 1012baf91c39SRemy Horton return count; 1013baf91c39SRemy Horton } 1014baf91c39SRemy Horton return nstats; 1015baf91c39SRemy Horton } 1016baf91c39SRemy Horton 101776d4c652SHarry van Haaren static int 1018e2aae1c1SRemy Horton virtio_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats, 101976d4c652SHarry van Haaren unsigned n) 102076d4c652SHarry van Haaren { 102176d4c652SHarry van Haaren unsigned i; 102276d4c652SHarry van Haaren unsigned count = 0; 102376d4c652SHarry van Haaren 102401ad44fdSHuawei Xie unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS + 102501ad44fdSHuawei Xie dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS; 102676d4c652SHarry van Haaren 102776d4c652SHarry van Haaren if (n < nstats) 102876d4c652SHarry van Haaren return nstats; 102976d4c652SHarry van Haaren 103076d4c652SHarry van Haaren for (i = 0; i < dev->data->nb_rx_queues; i++) { 103101ad44fdSHuawei Xie struct virtnet_rx *rxvq = dev->data->rx_queues[i]; 103276d4c652SHarry van Haaren 103376d4c652SHarry van Haaren if (rxvq == NULL) 103476d4c652SHarry van Haaren continue; 103576d4c652SHarry van Haaren 103676d4c652SHarry van Haaren unsigned t; 103776d4c652SHarry van Haaren 103801ad44fdSHuawei Xie for (t = 0; t < VIRTIO_NB_RXQ_XSTATS; t++) { 103976d4c652SHarry van Haaren xstats[count].value = *(uint64_t *)(((char *)rxvq) + 104001ad44fdSHuawei Xie rte_virtio_rxq_stat_strings[t].offset); 1041513c78aeSOlivier Matz xstats[count].id = count; 104276d4c652SHarry van Haaren count++; 104376d4c652SHarry van Haaren } 104476d4c652SHarry van Haaren } 104576d4c652SHarry van Haaren 104676d4c652SHarry van Haaren for (i = 0; i < dev->data->nb_tx_queues; i++) { 104701ad44fdSHuawei Xie struct virtnet_tx *txvq = dev->data->tx_queues[i]; 104876d4c652SHarry van Haaren 104976d4c652SHarry van Haaren if (txvq == NULL) 105076d4c652SHarry van Haaren continue; 105176d4c652SHarry van Haaren 105276d4c652SHarry van Haaren unsigned t; 105376d4c652SHarry van Haaren 105401ad44fdSHuawei Xie for (t = 0; t < VIRTIO_NB_TXQ_XSTATS; t++) { 105576d4c652SHarry van Haaren xstats[count].value = *(uint64_t *)(((char *)txvq) + 105601ad44fdSHuawei Xie rte_virtio_txq_stat_strings[t].offset); 1057513c78aeSOlivier Matz xstats[count].id = count; 105876d4c652SHarry van Haaren count++; 105976d4c652SHarry van Haaren } 106076d4c652SHarry van Haaren } 106176d4c652SHarry van Haaren 106276d4c652SHarry van Haaren return count; 106376d4c652SHarry van Haaren } 106476d4c652SHarry van Haaren 1065d5b0924bSMatan Azrad static int 106676d4c652SHarry van Haaren virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) 106776d4c652SHarry van Haaren { 106876d4c652SHarry van Haaren virtio_update_stats(dev, stats); 1069d5b0924bSMatan Azrad 1070d5b0924bSMatan Azrad return 0; 107176d4c652SHarry van Haaren } 107276d4c652SHarry van Haaren 10736c3169a3SBruce Richardson static void 10746c3169a3SBruce Richardson virtio_dev_stats_reset(struct rte_eth_dev *dev) 10756c3169a3SBruce Richardson { 10766c3169a3SBruce Richardson unsigned int i; 10776c3169a3SBruce Richardson 10786c3169a3SBruce Richardson for (i = 0; i < dev->data->nb_tx_queues; i++) { 107901ad44fdSHuawei Xie struct virtnet_tx *txvq = dev->data->tx_queues[i]; 10806c3169a3SBruce Richardson if (txvq == NULL) 10816c3169a3SBruce Richardson continue; 10826c3169a3SBruce Richardson 108301ad44fdSHuawei Xie txvq->stats.packets = 0; 108401ad44fdSHuawei Xie txvq->stats.bytes = 0; 108501ad44fdSHuawei Xie txvq->stats.errors = 0; 108601ad44fdSHuawei Xie txvq->stats.multicast = 0; 108701ad44fdSHuawei Xie txvq->stats.broadcast = 0; 108801ad44fdSHuawei Xie memset(txvq->stats.size_bins, 0, 108901ad44fdSHuawei Xie sizeof(txvq->stats.size_bins[0]) * 8); 10906c3169a3SBruce Richardson } 10916c3169a3SBruce Richardson 10926c3169a3SBruce Richardson for (i = 0; i < dev->data->nb_rx_queues; i++) { 109301ad44fdSHuawei Xie struct virtnet_rx *rxvq = dev->data->rx_queues[i]; 10946c3169a3SBruce Richardson if (rxvq == NULL) 10956c3169a3SBruce Richardson continue; 10966c3169a3SBruce Richardson 109701ad44fdSHuawei Xie rxvq->stats.packets = 0; 109801ad44fdSHuawei Xie rxvq->stats.bytes = 0; 109901ad44fdSHuawei Xie rxvq->stats.errors = 0; 110001ad44fdSHuawei Xie rxvq->stats.multicast = 0; 110101ad44fdSHuawei Xie rxvq->stats.broadcast = 0; 110201ad44fdSHuawei Xie memset(rxvq->stats.size_bins, 0, 110301ad44fdSHuawei Xie sizeof(rxvq->stats.size_bins[0]) * 8); 11046c3169a3SBruce Richardson } 11056c3169a3SBruce Richardson } 11066c3169a3SBruce Richardson 11076c3169a3SBruce Richardson static void 11086c3169a3SBruce Richardson virtio_set_hwaddr(struct virtio_hw *hw) 11096c3169a3SBruce Richardson { 11106c3169a3SBruce Richardson vtpci_write_dev_config(hw, 11116c3169a3SBruce Richardson offsetof(struct virtio_net_config, mac), 111235b2d13fSOlivier Matz &hw->mac_addr, RTE_ETHER_ADDR_LEN); 11136c3169a3SBruce Richardson } 11146c3169a3SBruce Richardson 11156c3169a3SBruce Richardson static void 11166c3169a3SBruce Richardson virtio_get_hwaddr(struct virtio_hw *hw) 11176c3169a3SBruce Richardson { 11186c3169a3SBruce Richardson if (vtpci_with_feature(hw, VIRTIO_NET_F_MAC)) { 11196c3169a3SBruce Richardson vtpci_read_dev_config(hw, 11206c3169a3SBruce Richardson offsetof(struct virtio_net_config, mac), 112135b2d13fSOlivier Matz &hw->mac_addr, RTE_ETHER_ADDR_LEN); 11226c3169a3SBruce Richardson } else { 1123538da7a1SOlivier Matz rte_eth_random_addr(&hw->mac_addr[0]); 11246c3169a3SBruce Richardson virtio_set_hwaddr(hw); 11256c3169a3SBruce Richardson } 11266c3169a3SBruce Richardson } 11276c3169a3SBruce Richardson 11286d01e580SWei Dai static int 11296c3169a3SBruce Richardson virtio_mac_table_set(struct virtio_hw *hw, 11306c3169a3SBruce Richardson const struct virtio_net_ctrl_mac *uc, 11316c3169a3SBruce Richardson const struct virtio_net_ctrl_mac *mc) 11326c3169a3SBruce Richardson { 11336c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 11346c3169a3SBruce Richardson int err, len[2]; 11356c3169a3SBruce Richardson 113627046236SStephen Hemminger if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_MAC_ADDR)) { 1137e9083127SJianfeng Tan PMD_DRV_LOG(INFO, "host does not support mac table"); 11386d01e580SWei Dai return -1; 113927046236SStephen Hemminger } 114027046236SStephen Hemminger 11416c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_MAC; 11426c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_MAC_TABLE_SET; 11436c3169a3SBruce Richardson 114435b2d13fSOlivier Matz len[0] = uc->entries * RTE_ETHER_ADDR_LEN + sizeof(uc->entries); 11456c3169a3SBruce Richardson memcpy(ctrl.data, uc, len[0]); 11466c3169a3SBruce Richardson 114735b2d13fSOlivier Matz len[1] = mc->entries * RTE_ETHER_ADDR_LEN + sizeof(mc->entries); 11486c3169a3SBruce Richardson memcpy(ctrl.data + len[0], mc, len[1]); 11496c3169a3SBruce Richardson 11506c3169a3SBruce Richardson err = virtio_send_command(hw->cvq, &ctrl, len, 2); 11516c3169a3SBruce Richardson if (err != 0) 11526c3169a3SBruce Richardson PMD_DRV_LOG(NOTICE, "mac table set failed: %d", err); 11536d01e580SWei Dai return err; 11546c3169a3SBruce Richardson } 11556c3169a3SBruce Richardson 11566d01e580SWei Dai static int 11576d13ea8eSOlivier Matz virtio_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr, 11586c3169a3SBruce Richardson uint32_t index, uint32_t vmdq __rte_unused) 11596c3169a3SBruce Richardson { 11606c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 11616d13ea8eSOlivier Matz const struct rte_ether_addr *addrs = dev->data->mac_addrs; 11626c3169a3SBruce Richardson unsigned int i; 11636c3169a3SBruce Richardson struct virtio_net_ctrl_mac *uc, *mc; 11646c3169a3SBruce Richardson 11656c3169a3SBruce Richardson if (index >= VIRTIO_MAX_MAC_ADDRS) { 11666c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "mac address index %u out of range", index); 11676d01e580SWei Dai return -EINVAL; 11686c3169a3SBruce Richardson } 11696c3169a3SBruce Richardson 117035b2d13fSOlivier Matz uc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN + 117135b2d13fSOlivier Matz sizeof(uc->entries)); 11726c3169a3SBruce Richardson uc->entries = 0; 117335b2d13fSOlivier Matz mc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN + 117435b2d13fSOlivier Matz sizeof(mc->entries)); 11756c3169a3SBruce Richardson mc->entries = 0; 11766c3169a3SBruce Richardson 11776c3169a3SBruce Richardson for (i = 0; i < VIRTIO_MAX_MAC_ADDRS; i++) { 11786d13ea8eSOlivier Matz const struct rte_ether_addr *addr 11796c3169a3SBruce Richardson = (i == index) ? mac_addr : addrs + i; 11806c3169a3SBruce Richardson struct virtio_net_ctrl_mac *tbl 1181538da7a1SOlivier Matz = rte_is_multicast_ether_addr(addr) ? mc : uc; 11826c3169a3SBruce Richardson 118335b2d13fSOlivier Matz memcpy(&tbl->macs[tbl->entries++], addr, RTE_ETHER_ADDR_LEN); 11846c3169a3SBruce Richardson } 11856c3169a3SBruce Richardson 11866d01e580SWei Dai return virtio_mac_table_set(hw, uc, mc); 11876c3169a3SBruce Richardson } 11886c3169a3SBruce Richardson 11896c3169a3SBruce Richardson static void 11906c3169a3SBruce Richardson virtio_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 11916c3169a3SBruce Richardson { 11926c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 11936d13ea8eSOlivier Matz struct rte_ether_addr *addrs = dev->data->mac_addrs; 11946c3169a3SBruce Richardson struct virtio_net_ctrl_mac *uc, *mc; 11956c3169a3SBruce Richardson unsigned int i; 11966c3169a3SBruce Richardson 11976c3169a3SBruce Richardson if (index >= VIRTIO_MAX_MAC_ADDRS) { 11986c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "mac address index %u out of range", index); 11996c3169a3SBruce Richardson return; 12006c3169a3SBruce Richardson } 12016c3169a3SBruce Richardson 120235b2d13fSOlivier Matz uc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN + 120335b2d13fSOlivier Matz sizeof(uc->entries)); 12046c3169a3SBruce Richardson uc->entries = 0; 120535b2d13fSOlivier Matz mc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN + 120635b2d13fSOlivier Matz sizeof(mc->entries)); 12076c3169a3SBruce Richardson mc->entries = 0; 12086c3169a3SBruce Richardson 12096c3169a3SBruce Richardson for (i = 0; i < VIRTIO_MAX_MAC_ADDRS; i++) { 12106c3169a3SBruce Richardson struct virtio_net_ctrl_mac *tbl; 12116c3169a3SBruce Richardson 1212538da7a1SOlivier Matz if (i == index || rte_is_zero_ether_addr(addrs + i)) 12136c3169a3SBruce Richardson continue; 12146c3169a3SBruce Richardson 1215538da7a1SOlivier Matz tbl = rte_is_multicast_ether_addr(addrs + i) ? mc : uc; 121635b2d13fSOlivier Matz memcpy(&tbl->macs[tbl->entries++], addrs + i, 121735b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 12186c3169a3SBruce Richardson } 12196c3169a3SBruce Richardson 12206c3169a3SBruce Richardson virtio_mac_table_set(hw, uc, mc); 12216c3169a3SBruce Richardson } 12226c3169a3SBruce Richardson 1223caccf8b3SOlivier Matz static int 12246d13ea8eSOlivier Matz virtio_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr) 12256c3169a3SBruce Richardson { 12266c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 12276c3169a3SBruce Richardson 122835b2d13fSOlivier Matz memcpy(hw->mac_addr, mac_addr, RTE_ETHER_ADDR_LEN); 12296c3169a3SBruce Richardson 12306c3169a3SBruce Richardson /* Use atomic update if available */ 12316c3169a3SBruce Richardson if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_MAC_ADDR)) { 12326c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 123335b2d13fSOlivier Matz int len = RTE_ETHER_ADDR_LEN; 12346c3169a3SBruce Richardson 12356c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_MAC; 12366c3169a3SBruce Richardson ctrl.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET; 12376c3169a3SBruce Richardson 123835b2d13fSOlivier Matz memcpy(ctrl.data, mac_addr, RTE_ETHER_ADDR_LEN); 1239caccf8b3SOlivier Matz return virtio_send_command(hw->cvq, &ctrl, &len, 1); 1240caccf8b3SOlivier Matz } 1241caccf8b3SOlivier Matz 1242caccf8b3SOlivier Matz if (!vtpci_with_feature(hw, VIRTIO_NET_F_MAC)) 1243caccf8b3SOlivier Matz return -ENOTSUP; 1244caccf8b3SOlivier Matz 12456c3169a3SBruce Richardson virtio_set_hwaddr(hw); 1246caccf8b3SOlivier Matz return 0; 12476c3169a3SBruce Richardson } 12486c3169a3SBruce Richardson 12496c3169a3SBruce Richardson static int 12506c3169a3SBruce Richardson virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 12516c3169a3SBruce Richardson { 12526c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 12536c3169a3SBruce Richardson struct virtio_pmd_ctrl ctrl; 12546c3169a3SBruce Richardson int len; 12556c3169a3SBruce Richardson 12566c3169a3SBruce Richardson if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) 12576c3169a3SBruce Richardson return -ENOTSUP; 12586c3169a3SBruce Richardson 12596c3169a3SBruce Richardson ctrl.hdr.class = VIRTIO_NET_CTRL_VLAN; 12606c3169a3SBruce Richardson ctrl.hdr.cmd = on ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL; 12616c3169a3SBruce Richardson memcpy(ctrl.data, &vlan_id, sizeof(vlan_id)); 12626c3169a3SBruce Richardson len = sizeof(vlan_id); 12636c3169a3SBruce Richardson 12646c3169a3SBruce Richardson return virtio_send_command(hw->cvq, &ctrl, &len, 1); 12656c3169a3SBruce Richardson } 12666c3169a3SBruce Richardson 12676ba1f63bSYuanhan Liu static int 1268fe19d49cSZhiyong Yang virtio_intr_enable(struct rte_eth_dev *dev) 1269fe19d49cSZhiyong Yang { 1270fe19d49cSZhiyong Yang struct virtio_hw *hw = dev->data->dev_private; 1271fe19d49cSZhiyong Yang 1272fe19d49cSZhiyong Yang if (rte_intr_enable(dev->intr_handle) < 0) 1273fe19d49cSZhiyong Yang return -1; 1274fe19d49cSZhiyong Yang 1275fe19d49cSZhiyong Yang if (!hw->virtio_user_dev) 1276fe19d49cSZhiyong Yang hw->use_msix = vtpci_msix_detect(RTE_ETH_DEV_TO_PCI(dev)); 1277fe19d49cSZhiyong Yang 1278fe19d49cSZhiyong Yang return 0; 1279fe19d49cSZhiyong Yang } 1280fe19d49cSZhiyong Yang 1281fe19d49cSZhiyong Yang static int 1282fe19d49cSZhiyong Yang virtio_intr_disable(struct rte_eth_dev *dev) 1283fe19d49cSZhiyong Yang { 1284fe19d49cSZhiyong Yang struct virtio_hw *hw = dev->data->dev_private; 1285fe19d49cSZhiyong Yang 1286fe19d49cSZhiyong Yang if (rte_intr_disable(dev->intr_handle) < 0) 1287fe19d49cSZhiyong Yang return -1; 1288fe19d49cSZhiyong Yang 1289fe19d49cSZhiyong Yang if (!hw->virtio_user_dev) 1290fe19d49cSZhiyong Yang hw->use_msix = vtpci_msix_detect(RTE_ETH_DEV_TO_PCI(dev)); 1291fe19d49cSZhiyong Yang 1292fe19d49cSZhiyong Yang return 0; 1293fe19d49cSZhiyong Yang } 1294fe19d49cSZhiyong Yang 1295fe19d49cSZhiyong Yang static int 129660e6f470SOlivier Matz virtio_negotiate_features(struct virtio_hw *hw, uint64_t req_features) 12976c3169a3SBruce Richardson { 12983891f233SYuanhan Liu uint64_t host_features; 12996c3169a3SBruce Richardson 13006c3169a3SBruce Richardson /* Prepare guest_features: feature that driver wants to support */ 13013891f233SYuanhan Liu PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %" PRIx64, 130260e6f470SOlivier Matz req_features); 13036c3169a3SBruce Richardson 13046c3169a3SBruce Richardson /* Read device(host) feature bits */ 1305553f4593SYuanhan Liu host_features = VTPCI_OPS(hw)->get_features(hw); 13063891f233SYuanhan Liu PMD_INIT_LOG(DEBUG, "host_features before negotiate = %" PRIx64, 13076c3169a3SBruce Richardson host_features); 13086c3169a3SBruce Richardson 130949d26d9eSMaxime Coquelin /* If supported, ensure MTU value is valid before acknowledging it. */ 131049d26d9eSMaxime Coquelin if (host_features & req_features & (1ULL << VIRTIO_NET_F_MTU)) { 131149d26d9eSMaxime Coquelin struct virtio_net_config config; 131249d26d9eSMaxime Coquelin 131349d26d9eSMaxime Coquelin vtpci_read_dev_config(hw, 131449d26d9eSMaxime Coquelin offsetof(struct virtio_net_config, mtu), 131549d26d9eSMaxime Coquelin &config.mtu, sizeof(config.mtu)); 131649d26d9eSMaxime Coquelin 131735b2d13fSOlivier Matz if (config.mtu < RTE_ETHER_MIN_MTU) 131849d26d9eSMaxime Coquelin req_features &= ~(1ULL << VIRTIO_NET_F_MTU); 131949d26d9eSMaxime Coquelin } 132049d26d9eSMaxime Coquelin 13216c3169a3SBruce Richardson /* 13226c3169a3SBruce Richardson * Negotiate features: Subset of device feature bits are written back 13236c3169a3SBruce Richardson * guest feature bits. 13246c3169a3SBruce Richardson */ 132560e6f470SOlivier Matz hw->guest_features = req_features; 13266c3169a3SBruce Richardson hw->guest_features = vtpci_negotiate_features(hw, host_features); 13273891f233SYuanhan Liu PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64, 13286c3169a3SBruce Richardson hw->guest_features); 13296ba1f63bSYuanhan Liu 13306ba1f63bSYuanhan Liu if (hw->modern) { 13316ba1f63bSYuanhan Liu if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { 13326ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 13336ba1f63bSYuanhan Liu "VIRTIO_F_VERSION_1 features is not enabled."); 13346ba1f63bSYuanhan Liu return -1; 13356ba1f63bSYuanhan Liu } 13366ba1f63bSYuanhan Liu vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); 13376ba1f63bSYuanhan Liu if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { 13386ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 13396ba1f63bSYuanhan Liu "failed to set FEATURES_OK status!"); 13406ba1f63bSYuanhan Liu return -1; 13416ba1f63bSYuanhan Liu } 13426ba1f63bSYuanhan Liu } 13436ba1f63bSYuanhan Liu 134460e6f470SOlivier Matz hw->req_guest_features = req_features; 134560e6f470SOlivier Matz 13466ba1f63bSYuanhan Liu return 0; 13476c3169a3SBruce Richardson } 13486c3169a3SBruce Richardson 13491978a9dcSXiao Wang int 13501978a9dcSXiao Wang virtio_dev_pause(struct rte_eth_dev *dev) 13511978a9dcSXiao Wang { 13521978a9dcSXiao Wang struct virtio_hw *hw = dev->data->dev_private; 13531978a9dcSXiao Wang 13541978a9dcSXiao Wang rte_spinlock_lock(&hw->state_lock); 13551978a9dcSXiao Wang 13561978a9dcSXiao Wang if (hw->started == 0) { 13571978a9dcSXiao Wang /* Device is just stopped. */ 13581978a9dcSXiao Wang rte_spinlock_unlock(&hw->state_lock); 13591978a9dcSXiao Wang return -1; 13601978a9dcSXiao Wang } 13611978a9dcSXiao Wang hw->started = 0; 13621978a9dcSXiao Wang /* 13631978a9dcSXiao Wang * Prevent the worker threads from touching queues to avoid contention, 13641978a9dcSXiao Wang * 1 ms should be enough for the ongoing Tx function to finish. 13651978a9dcSXiao Wang */ 13661978a9dcSXiao Wang rte_delay_ms(1); 13671978a9dcSXiao Wang return 0; 13681978a9dcSXiao Wang } 13691978a9dcSXiao Wang 13701978a9dcSXiao Wang /* 13711978a9dcSXiao Wang * Recover hw state to let the worker threads continue. 13721978a9dcSXiao Wang */ 13731978a9dcSXiao Wang void 13741978a9dcSXiao Wang virtio_dev_resume(struct rte_eth_dev *dev) 13751978a9dcSXiao Wang { 13761978a9dcSXiao Wang struct virtio_hw *hw = dev->data->dev_private; 13771978a9dcSXiao Wang 13781978a9dcSXiao Wang hw->started = 1; 13791978a9dcSXiao Wang rte_spinlock_unlock(&hw->state_lock); 13801978a9dcSXiao Wang } 13811978a9dcSXiao Wang 13821978a9dcSXiao Wang /* 13831978a9dcSXiao Wang * Should be called only after device is paused. 13841978a9dcSXiao Wang */ 13851978a9dcSXiao Wang int 13861978a9dcSXiao Wang virtio_inject_pkts(struct rte_eth_dev *dev, struct rte_mbuf **tx_pkts, 13871978a9dcSXiao Wang int nb_pkts) 13881978a9dcSXiao Wang { 13891978a9dcSXiao Wang struct virtio_hw *hw = dev->data->dev_private; 13901978a9dcSXiao Wang struct virtnet_tx *txvq = dev->data->tx_queues[0]; 13911978a9dcSXiao Wang int ret; 13921978a9dcSXiao Wang 13931978a9dcSXiao Wang hw->inject_pkts = tx_pkts; 13941978a9dcSXiao Wang ret = dev->tx_pkt_burst(txvq, tx_pkts, nb_pkts); 13951978a9dcSXiao Wang hw->inject_pkts = NULL; 13961978a9dcSXiao Wang 13971978a9dcSXiao Wang return ret; 13981978a9dcSXiao Wang } 13991978a9dcSXiao Wang 14007365504fSXiao Wang static void 14017365504fSXiao Wang virtio_notify_peers(struct rte_eth_dev *dev) 14027365504fSXiao Wang { 14037365504fSXiao Wang struct virtio_hw *hw = dev->data->dev_private; 14047c7f2e60SZhiyong Yang struct virtnet_rx *rxvq; 14057365504fSXiao Wang struct rte_mbuf *rarp_mbuf; 14067365504fSXiao Wang 14077c7f2e60SZhiyong Yang if (!dev->data->rx_queues) 14087c7f2e60SZhiyong Yang return; 14097c7f2e60SZhiyong Yang 14107c7f2e60SZhiyong Yang rxvq = dev->data->rx_queues[0]; 1411f42deafaSZhiyong Yang if (!rxvq) 1412f42deafaSZhiyong Yang return; 1413f42deafaSZhiyong Yang 14147365504fSXiao Wang rarp_mbuf = rte_net_make_rarp_packet(rxvq->mpool, 14156d13ea8eSOlivier Matz (struct rte_ether_addr *)hw->mac_addr); 14167365504fSXiao Wang if (rarp_mbuf == NULL) { 14177365504fSXiao Wang PMD_DRV_LOG(ERR, "failed to make RARP packet."); 14187365504fSXiao Wang return; 14197365504fSXiao Wang } 14207365504fSXiao Wang 14217365504fSXiao Wang /* If virtio port just stopped, no need to send RARP */ 14227365504fSXiao Wang if (virtio_dev_pause(dev) < 0) { 14237365504fSXiao Wang rte_pktmbuf_free(rarp_mbuf); 14247365504fSXiao Wang return; 14257365504fSXiao Wang } 14267365504fSXiao Wang 14277365504fSXiao Wang virtio_inject_pkts(dev, &rarp_mbuf, 1); 14287365504fSXiao Wang virtio_dev_resume(dev); 14297365504fSXiao Wang } 14307365504fSXiao Wang 14317365504fSXiao Wang static void 14327365504fSXiao Wang virtio_ack_link_announce(struct rte_eth_dev *dev) 14337365504fSXiao Wang { 14347365504fSXiao Wang struct virtio_hw *hw = dev->data->dev_private; 14357365504fSXiao Wang struct virtio_pmd_ctrl ctrl; 14367365504fSXiao Wang 14377365504fSXiao Wang ctrl.hdr.class = VIRTIO_NET_CTRL_ANNOUNCE; 14387365504fSXiao Wang ctrl.hdr.cmd = VIRTIO_NET_CTRL_ANNOUNCE_ACK; 14397365504fSXiao Wang 14407365504fSXiao Wang virtio_send_command(hw->cvq, &ctrl, NULL, 0); 14417365504fSXiao Wang } 14427365504fSXiao Wang 14436c3169a3SBruce Richardson /* 14447365504fSXiao Wang * Process virtio config changed interrupt. Call the callback 14457365504fSXiao Wang * if link state changed, generate gratuitous RARP packet if 14467365504fSXiao Wang * the status indicates an ANNOUNCE. 14476c3169a3SBruce Richardson */ 1448ef53b603SJianfeng Tan void 1449c23a1a30SQi Zhang virtio_interrupt_handler(void *param) 14506c3169a3SBruce Richardson { 14516c3169a3SBruce Richardson struct rte_eth_dev *dev = param; 14526c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 14536c3169a3SBruce Richardson uint8_t isr; 14545db1684eSTiwei Bie uint16_t status; 14556c3169a3SBruce Richardson 14566c3169a3SBruce Richardson /* Read interrupt status which clears interrupt */ 14576c3169a3SBruce Richardson isr = vtpci_isr(hw); 14586c3169a3SBruce Richardson PMD_DRV_LOG(INFO, "interrupt status = %#x", isr); 14596c3169a3SBruce Richardson 1460fe19d49cSZhiyong Yang if (virtio_intr_enable(dev) < 0) 14616c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "interrupt enable failed"); 14626c3169a3SBruce Richardson 14636c3169a3SBruce Richardson if (isr & VIRTIO_PCI_ISR_CONFIG) { 14646c3169a3SBruce Richardson if (virtio_dev_link_update(dev, 0) == 0) 14656c3169a3SBruce Richardson _rte_eth_dev_callback_process(dev, 1466d6af1a13SBernard Iremonger RTE_ETH_EVENT_INTR_LSC, 1467cebe3d7bSThomas Monjalon NULL); 14686c3169a3SBruce Richardson 14695db1684eSTiwei Bie if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) { 14705db1684eSTiwei Bie vtpci_read_dev_config(hw, 14715db1684eSTiwei Bie offsetof(struct virtio_net_config, status), 14725db1684eSTiwei Bie &status, sizeof(status)); 14735db1684eSTiwei Bie if (status & VIRTIO_NET_S_ANNOUNCE) { 14747365504fSXiao Wang virtio_notify_peers(dev); 1475ac860c86SZhiyong Yang if (hw->cvq) 14767365504fSXiao Wang virtio_ack_link_announce(dev); 14777365504fSXiao Wang } 14786c3169a3SBruce Richardson } 14795db1684eSTiwei Bie } 14805db1684eSTiwei Bie } 14816c3169a3SBruce Richardson 14824819eae8SOlivier Matz /* set rx and tx handlers according to what is supported */ 14836c3169a3SBruce Richardson static void 14844819eae8SOlivier Matz set_rxtx_funcs(struct rte_eth_dev *eth_dev) 14856c3169a3SBruce Richardson { 14866c3169a3SBruce Richardson struct virtio_hw *hw = eth_dev->data->dev_private; 14874819eae8SOlivier Matz 1488*00a5ea02SDilshod Urazov eth_dev->tx_pkt_prepare = virtio_xmit_pkts_prepare; 1489892dc798SJens Freimann if (vtpci_packed_queue(hw)) { 1490892dc798SJens Freimann PMD_INIT_LOG(INFO, 14915c75a8efSTiwei Bie "virtio: using packed ring %s Tx path on port %u", 14925c75a8efSTiwei Bie hw->use_inorder_tx ? "inorder" : "standard", 1493892dc798SJens Freimann eth_dev->data->port_id); 1494892dc798SJens Freimann eth_dev->tx_pkt_burst = virtio_xmit_pkts_packed; 1495892dc798SJens Freimann } else { 1496892dc798SJens Freimann if (hw->use_inorder_tx) { 1497892dc798SJens Freimann PMD_INIT_LOG(INFO, "virtio: using inorder Tx path on port %u", 1498892dc798SJens Freimann eth_dev->data->port_id); 1499892dc798SJens Freimann eth_dev->tx_pkt_burst = virtio_xmit_pkts_inorder; 1500892dc798SJens Freimann } else { 1501892dc798SJens Freimann PMD_INIT_LOG(INFO, "virtio: using standard Tx path on port %u", 1502892dc798SJens Freimann eth_dev->data->port_id); 1503892dc798SJens Freimann eth_dev->tx_pkt_burst = virtio_xmit_pkts; 1504892dc798SJens Freimann } 1505892dc798SJens Freimann } 1506892dc798SJens Freimann 1507a76290c8SJens Freimann if (vtpci_packed_queue(hw)) { 1508a76290c8SJens Freimann if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) { 1509a76290c8SJens Freimann PMD_INIT_LOG(INFO, 1510a76290c8SJens Freimann "virtio: using packed ring mergeable buffer Rx path on port %u", 1511a76290c8SJens Freimann eth_dev->data->port_id); 1512a76290c8SJens Freimann eth_dev->rx_pkt_burst = 1513a76290c8SJens Freimann &virtio_recv_mergeable_pkts_packed; 1514a76290c8SJens Freimann } else { 1515a76290c8SJens Freimann PMD_INIT_LOG(INFO, 1516a76290c8SJens Freimann "virtio: using packed ring standard Rx path on port %u", 1517a76290c8SJens Freimann eth_dev->data->port_id); 1518a76290c8SJens Freimann eth_dev->rx_pkt_burst = &virtio_recv_pkts_packed; 1519a76290c8SJens Freimann } 1520a76290c8SJens Freimann } else { 152109649363SOlivier Matz if (hw->use_simple_rx) { 15224819eae8SOlivier Matz PMD_INIT_LOG(INFO, "virtio: using simple Rx path on port %u", 15234819eae8SOlivier Matz eth_dev->data->port_id); 15244819eae8SOlivier Matz eth_dev->rx_pkt_burst = virtio_recv_pkts_vec; 15258f3bd7e8SMarvin Liu } else if (hw->use_inorder_rx) { 15268f3bd7e8SMarvin Liu PMD_INIT_LOG(INFO, 1527efcda136SMaxime Coquelin "virtio: using inorder Rx path on port %u", 15288f3bd7e8SMarvin Liu eth_dev->data->port_id); 1529efcda136SMaxime Coquelin eth_dev->rx_pkt_burst = &virtio_recv_pkts_inorder; 15304819eae8SOlivier Matz } else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) { 15314819eae8SOlivier Matz PMD_INIT_LOG(INFO, 15324819eae8SOlivier Matz "virtio: using mergeable buffer Rx path on port %u", 15334819eae8SOlivier Matz eth_dev->data->port_id); 15346c3169a3SBruce Richardson eth_dev->rx_pkt_burst = &virtio_recv_mergeable_pkts; 15354819eae8SOlivier Matz } else { 15364819eae8SOlivier Matz PMD_INIT_LOG(INFO, "virtio: using standard Rx path on port %u", 15374819eae8SOlivier Matz eth_dev->data->port_id); 15386c3169a3SBruce Richardson eth_dev->rx_pkt_burst = &virtio_recv_pkts; 15396c3169a3SBruce Richardson } 1540a76290c8SJens Freimann } 15416c3169a3SBruce Richardson 15424819eae8SOlivier Matz } 15434819eae8SOlivier Matz 154426b683b4SJianfeng Tan /* Only support 1:1 queue/interrupt mapping so far. 154526b683b4SJianfeng Tan * TODO: support n:1 queue/interrupt mapping when there are limited number of 154626b683b4SJianfeng Tan * interrupt vectors (<N+1). 154726b683b4SJianfeng Tan */ 154826b683b4SJianfeng Tan static int 154926b683b4SJianfeng Tan virtio_queues_bind_intr(struct rte_eth_dev *dev) 155026b683b4SJianfeng Tan { 155126b683b4SJianfeng Tan uint32_t i; 155226b683b4SJianfeng Tan struct virtio_hw *hw = dev->data->dev_private; 155326b683b4SJianfeng Tan 1554f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "queue/interrupt binding"); 155526b683b4SJianfeng Tan for (i = 0; i < dev->data->nb_rx_queues; ++i) { 155626b683b4SJianfeng Tan dev->intr_handle->intr_vec[i] = i + 1; 155726b683b4SJianfeng Tan if (VTPCI_OPS(hw)->set_queue_irq(hw, hw->vqs[i * 2], i + 1) == 155826b683b4SJianfeng Tan VIRTIO_MSI_NO_VECTOR) { 155926b683b4SJianfeng Tan PMD_DRV_LOG(ERR, "failed to set queue vector"); 156026b683b4SJianfeng Tan return -EBUSY; 156126b683b4SJianfeng Tan } 156226b683b4SJianfeng Tan } 156326b683b4SJianfeng Tan 156426b683b4SJianfeng Tan return 0; 156526b683b4SJianfeng Tan } 156626b683b4SJianfeng Tan 15679ebdeefeSJianfeng Tan static void 15689ebdeefeSJianfeng Tan virtio_queues_unbind_intr(struct rte_eth_dev *dev) 15699ebdeefeSJianfeng Tan { 15709ebdeefeSJianfeng Tan uint32_t i; 15719ebdeefeSJianfeng Tan struct virtio_hw *hw = dev->data->dev_private; 15729ebdeefeSJianfeng Tan 1573f2462150SFerruh Yigit PMD_INIT_LOG(INFO, "queue/interrupt unbinding"); 15749ebdeefeSJianfeng Tan for (i = 0; i < dev->data->nb_rx_queues; ++i) 15759ebdeefeSJianfeng Tan VTPCI_OPS(hw)->set_queue_irq(hw, 15769ebdeefeSJianfeng Tan hw->vqs[i * VTNET_CQ], 15779ebdeefeSJianfeng Tan VIRTIO_MSI_NO_VECTOR); 15789ebdeefeSJianfeng Tan } 15799ebdeefeSJianfeng Tan 158026b683b4SJianfeng Tan static int 158126b683b4SJianfeng Tan virtio_configure_intr(struct rte_eth_dev *dev) 158226b683b4SJianfeng Tan { 158326b683b4SJianfeng Tan struct virtio_hw *hw = dev->data->dev_private; 158426b683b4SJianfeng Tan 158526b683b4SJianfeng Tan if (!rte_intr_cap_multiple(dev->intr_handle)) { 158626b683b4SJianfeng Tan PMD_INIT_LOG(ERR, "Multiple intr vector not supported"); 158726b683b4SJianfeng Tan return -ENOTSUP; 158826b683b4SJianfeng Tan } 158926b683b4SJianfeng Tan 159026b683b4SJianfeng Tan if (rte_intr_efd_enable(dev->intr_handle, dev->data->nb_rx_queues)) { 159126b683b4SJianfeng Tan PMD_INIT_LOG(ERR, "Fail to create eventfd"); 159226b683b4SJianfeng Tan return -1; 159326b683b4SJianfeng Tan } 159426b683b4SJianfeng Tan 159526b683b4SJianfeng Tan if (!dev->intr_handle->intr_vec) { 159626b683b4SJianfeng Tan dev->intr_handle->intr_vec = 159726b683b4SJianfeng Tan rte_zmalloc("intr_vec", 159826b683b4SJianfeng Tan hw->max_queue_pairs * sizeof(int), 0); 159926b683b4SJianfeng Tan if (!dev->intr_handle->intr_vec) { 160026b683b4SJianfeng Tan PMD_INIT_LOG(ERR, "Failed to allocate %u rxq vectors", 160126b683b4SJianfeng Tan hw->max_queue_pairs); 160226b683b4SJianfeng Tan return -ENOMEM; 160326b683b4SJianfeng Tan } 160426b683b4SJianfeng Tan } 160526b683b4SJianfeng Tan 160626b683b4SJianfeng Tan /* Re-register callback to update max_intr */ 160726b683b4SJianfeng Tan rte_intr_callback_unregister(dev->intr_handle, 160826b683b4SJianfeng Tan virtio_interrupt_handler, 160926b683b4SJianfeng Tan dev); 161026b683b4SJianfeng Tan rte_intr_callback_register(dev->intr_handle, 161126b683b4SJianfeng Tan virtio_interrupt_handler, 161226b683b4SJianfeng Tan dev); 161326b683b4SJianfeng Tan 161426b683b4SJianfeng Tan /* DO NOT try to remove this! This function will enable msix, or QEMU 161526b683b4SJianfeng Tan * will encounter SIGSEGV when DRIVER_OK is sent. 161626b683b4SJianfeng Tan * And for legacy devices, this should be done before queue/vec binding 161726b683b4SJianfeng Tan * to change the config size from 20 to 24, or VIRTIO_MSI_QUEUE_VECTOR 161826b683b4SJianfeng Tan * (22) will be ignored. 161926b683b4SJianfeng Tan */ 1620fe19d49cSZhiyong Yang if (virtio_intr_enable(dev) < 0) { 162126b683b4SJianfeng Tan PMD_DRV_LOG(ERR, "interrupt enable failed"); 162226b683b4SJianfeng Tan return -1; 162326b683b4SJianfeng Tan } 162426b683b4SJianfeng Tan 162526b683b4SJianfeng Tan if (virtio_queues_bind_intr(dev) < 0) { 162626b683b4SJianfeng Tan PMD_INIT_LOG(ERR, "Failed to bind queue/interrupt"); 162726b683b4SJianfeng Tan return -1; 162826b683b4SJianfeng Tan } 162926b683b4SJianfeng Tan 163026b683b4SJianfeng Tan return 0; 163126b683b4SJianfeng Tan } 163226b683b4SJianfeng Tan 163360e6f470SOlivier Matz /* reset device and renegotiate features if needed */ 1634198ab336SOlivier Matz static int 163560e6f470SOlivier Matz virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features) 16366c3169a3SBruce Richardson { 16376c3169a3SBruce Richardson struct virtio_hw *hw = eth_dev->data->dev_private; 16386c3169a3SBruce Richardson struct virtio_net_config *config; 16396c3169a3SBruce Richardson struct virtio_net_config local_config; 16409470427cSYuanhan Liu struct rte_pci_device *pci_dev = NULL; 164169c80d4eSYuanhan Liu int ret; 16426c3169a3SBruce Richardson 16436c3169a3SBruce Richardson /* Reset the device although not necessary at startup */ 16446c3169a3SBruce Richardson vtpci_reset(hw); 16456c3169a3SBruce Richardson 16463669a1afSOlivier Matz if (hw->vqs) { 16473669a1afSOlivier Matz virtio_dev_free_mbufs(eth_dev); 16483669a1afSOlivier Matz virtio_free_queues(hw); 16493669a1afSOlivier Matz } 16503669a1afSOlivier Matz 16516c3169a3SBruce Richardson /* Tell the host we've noticed this device. */ 16526c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK); 16536c3169a3SBruce Richardson 16546c3169a3SBruce Richardson /* Tell the host we've known how to drive the device. */ 16556c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); 165660e6f470SOlivier Matz if (virtio_negotiate_features(hw, req_features) < 0) 16576ba1f63bSYuanhan Liu return -1; 16586c3169a3SBruce Richardson 16599230ab8dSIlya Maximets hw->weak_barriers = !vtpci_with_feature(hw, VIRTIO_F_ORDER_PLATFORM); 16609230ab8dSIlya Maximets 16617f468b2eSTiwei Bie if (!hw->virtio_user_dev) 1662c0802544SFerruh Yigit pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); 1663f229eb41SJianfeng Tan 1664a5ed8448SMatt Peters /* If host does not support both status and MSI-X then disable LSC */ 1665fe19d49cSZhiyong Yang if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS) && 1666fe19d49cSZhiyong Yang hw->use_msix != VIRTIO_MSIX_NONE) 1667198ab336SOlivier Matz eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 1668a5ed8448SMatt Peters else 1669a5ed8448SMatt Peters eth_dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC; 1670954ea115SStephen Hemminger 16716c3169a3SBruce Richardson /* Setting up rx_header size for the device */ 16726ba1f63bSYuanhan Liu if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || 1673f803734bSJens Freimann vtpci_with_feature(hw, VIRTIO_F_VERSION_1) || 1674f803734bSJens Freimann vtpci_with_feature(hw, VIRTIO_F_RING_PACKED)) 16756c3169a3SBruce Richardson hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); 16766c3169a3SBruce Richardson else 16776c3169a3SBruce Richardson hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); 16786c3169a3SBruce Richardson 16796c3169a3SBruce Richardson /* Copy the permanent MAC address to: virtio_hw */ 16806c3169a3SBruce Richardson virtio_get_hwaddr(hw); 1681538da7a1SOlivier Matz rte_ether_addr_copy((struct rte_ether_addr *)hw->mac_addr, 16826c3169a3SBruce Richardson ð_dev->data->mac_addrs[0]); 16836c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 16846c3169a3SBruce Richardson "PORT MAC: %02X:%02X:%02X:%02X:%02X:%02X", 16856c3169a3SBruce Richardson hw->mac_addr[0], hw->mac_addr[1], hw->mac_addr[2], 16866c3169a3SBruce Richardson hw->mac_addr[3], hw->mac_addr[4], hw->mac_addr[5]); 16876c3169a3SBruce Richardson 16886c3169a3SBruce Richardson if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ)) { 16896c3169a3SBruce Richardson config = &local_config; 16906c3169a3SBruce Richardson 16916d7740e2SChangchun Ouyang vtpci_read_dev_config(hw, 16926d7740e2SChangchun Ouyang offsetof(struct virtio_net_config, mac), 16936d7740e2SChangchun Ouyang &config->mac, sizeof(config->mac)); 16946d7740e2SChangchun Ouyang 16956c3169a3SBruce Richardson if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) { 16966d7740e2SChangchun Ouyang vtpci_read_dev_config(hw, 16976d7740e2SChangchun Ouyang offsetof(struct virtio_net_config, status), 16986d7740e2SChangchun Ouyang &config->status, sizeof(config->status)); 16996c3169a3SBruce Richardson } else { 17006c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 17016c3169a3SBruce Richardson "VIRTIO_NET_F_STATUS is not supported"); 17026c3169a3SBruce Richardson config->status = 0; 17036c3169a3SBruce Richardson } 17046c3169a3SBruce Richardson 17056c3169a3SBruce Richardson if (vtpci_with_feature(hw, VIRTIO_NET_F_MQ)) { 17066d7740e2SChangchun Ouyang vtpci_read_dev_config(hw, 17076d7740e2SChangchun Ouyang offsetof(struct virtio_net_config, max_virtqueue_pairs), 17086d7740e2SChangchun Ouyang &config->max_virtqueue_pairs, 17096d7740e2SChangchun Ouyang sizeof(config->max_virtqueue_pairs)); 17106c3169a3SBruce Richardson } else { 17116c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 17126c3169a3SBruce Richardson "VIRTIO_NET_F_MQ is not supported"); 17136c3169a3SBruce Richardson config->max_virtqueue_pairs = 1; 17146c3169a3SBruce Richardson } 17156c3169a3SBruce Richardson 171645e4acd4SOlivier Matz hw->max_queue_pairs = config->max_virtqueue_pairs; 17176c3169a3SBruce Richardson 171849d26d9eSMaxime Coquelin if (vtpci_with_feature(hw, VIRTIO_NET_F_MTU)) { 171949d26d9eSMaxime Coquelin vtpci_read_dev_config(hw, 172049d26d9eSMaxime Coquelin offsetof(struct virtio_net_config, mtu), 172149d26d9eSMaxime Coquelin &config->mtu, 172249d26d9eSMaxime Coquelin sizeof(config->mtu)); 172349d26d9eSMaxime Coquelin 172449d26d9eSMaxime Coquelin /* 172549d26d9eSMaxime Coquelin * MTU value has already been checked at negotiation 172649d26d9eSMaxime Coquelin * time, but check again in case it has changed since 172749d26d9eSMaxime Coquelin * then, which should not happen. 172849d26d9eSMaxime Coquelin */ 172935b2d13fSOlivier Matz if (config->mtu < RTE_ETHER_MIN_MTU) { 173049d26d9eSMaxime Coquelin PMD_INIT_LOG(ERR, "invalid max MTU value (%u)", 173149d26d9eSMaxime Coquelin config->mtu); 173249d26d9eSMaxime Coquelin return -1; 173349d26d9eSMaxime Coquelin } 173449d26d9eSMaxime Coquelin 173549d26d9eSMaxime Coquelin hw->max_mtu = config->mtu; 173649d26d9eSMaxime Coquelin /* Set initial MTU to maximum one supported by vhost */ 173749d26d9eSMaxime Coquelin eth_dev->data->mtu = config->mtu; 173849d26d9eSMaxime Coquelin 173949d26d9eSMaxime Coquelin } else { 174035b2d13fSOlivier Matz hw->max_mtu = VIRTIO_MAX_RX_PKTLEN - RTE_ETHER_HDR_LEN - 174149d26d9eSMaxime Coquelin VLAN_TAG_LEN - hw->vtnet_hdr_size; 174249d26d9eSMaxime Coquelin } 174349d26d9eSMaxime Coquelin 17446c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "config->max_virtqueue_pairs=%d", 17456c3169a3SBruce Richardson config->max_virtqueue_pairs); 17466c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "config->status=%d", config->status); 17476c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 17486c3169a3SBruce Richardson "PORT MAC: %02X:%02X:%02X:%02X:%02X:%02X", 17496c3169a3SBruce Richardson config->mac[0], config->mac[1], 17506c3169a3SBruce Richardson config->mac[2], config->mac[3], 17516c3169a3SBruce Richardson config->mac[4], config->mac[5]); 17526c3169a3SBruce Richardson } else { 175345e4acd4SOlivier Matz PMD_INIT_LOG(DEBUG, "config->max_virtqueue_pairs=1"); 175445e4acd4SOlivier Matz hw->max_queue_pairs = 1; 175535b2d13fSOlivier Matz hw->max_mtu = VIRTIO_MAX_RX_PKTLEN - RTE_ETHER_HDR_LEN - 1756240da8b2SZhike Wang VLAN_TAG_LEN - hw->vtnet_hdr_size; 17576c3169a3SBruce Richardson } 17586c3169a3SBruce Richardson 175969c80d4eSYuanhan Liu ret = virtio_alloc_queues(eth_dev); 176069c80d4eSYuanhan Liu if (ret < 0) 176169c80d4eSYuanhan Liu return ret; 176226b683b4SJianfeng Tan 176326b683b4SJianfeng Tan if (eth_dev->data->dev_conf.intr_conf.rxq) { 176426b683b4SJianfeng Tan if (virtio_configure_intr(eth_dev) < 0) { 176526b683b4SJianfeng Tan PMD_INIT_LOG(ERR, "failed to configure interrupt"); 17662b38151fSTiwei Bie virtio_free_queues(hw); 176726b683b4SJianfeng Tan return -1; 176826b683b4SJianfeng Tan } 176926b683b4SJianfeng Tan } 177026b683b4SJianfeng Tan 1771ee85024cSYuanhan Liu vtpci_reinit_complete(hw); 177269c80d4eSYuanhan Liu 1773ce2eabddSJianfeng Tan if (pci_dev) 17746c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x", 17756c3169a3SBruce Richardson eth_dev->data->port_id, pci_dev->id.vendor_id, 17766c3169a3SBruce Richardson pci_dev->id.device_id); 17776c3169a3SBruce Richardson 1778198ab336SOlivier Matz return 0; 1779198ab336SOlivier Matz } 1780198ab336SOlivier Matz 1781198ab336SOlivier Matz /* 17826d890f8aSYuanhan Liu * Remap the PCI device again (IO port map for legacy device and 17836d890f8aSYuanhan Liu * memory map for modern device), so that the secondary process 17846d890f8aSYuanhan Liu * could have the PCI initiated correctly. 17856d890f8aSYuanhan Liu */ 17866d890f8aSYuanhan Liu static int 17876d890f8aSYuanhan Liu virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_hw *hw) 17886d890f8aSYuanhan Liu { 17896d890f8aSYuanhan Liu if (hw->modern) { 17906d890f8aSYuanhan Liu /* 17916d890f8aSYuanhan Liu * We don't have to re-parse the PCI config space, since 17923dcfe039SThomas Monjalon * rte_pci_map_device() makes sure the mapped address 17936d890f8aSYuanhan Liu * in secondary process would equal to the one mapped in 17946d890f8aSYuanhan Liu * the primary process: error will be returned if that 17956d890f8aSYuanhan Liu * requirement is not met. 17966d890f8aSYuanhan Liu * 17976d890f8aSYuanhan Liu * That said, we could simply reuse all cap pointers 17986d890f8aSYuanhan Liu * (such as dev_cfg, common_cfg, etc.) parsed from the 17996d890f8aSYuanhan Liu * primary process, which is stored in shared memory. 18006d890f8aSYuanhan Liu */ 18013dcfe039SThomas Monjalon if (rte_pci_map_device(pci_dev)) { 18026d890f8aSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 18036d890f8aSYuanhan Liu return -1; 18046d890f8aSYuanhan Liu } 18056d890f8aSYuanhan Liu } else { 18063dcfe039SThomas Monjalon if (rte_pci_ioport_map(pci_dev, 0, VTPCI_IO(hw)) < 0) 18076d890f8aSYuanhan Liu return -1; 18086d890f8aSYuanhan Liu } 18096d890f8aSYuanhan Liu 18106d890f8aSYuanhan Liu return 0; 18116d890f8aSYuanhan Liu } 18126d890f8aSYuanhan Liu 18136d890f8aSYuanhan Liu static void 18146d890f8aSYuanhan Liu virtio_set_vtpci_ops(struct virtio_hw *hw) 18156d890f8aSYuanhan Liu { 1816e754c959SThomas Monjalon #ifdef RTE_VIRTIO_USER 18176d890f8aSYuanhan Liu if (hw->virtio_user_dev) 18186d890f8aSYuanhan Liu VTPCI_OPS(hw) = &virtio_user_ops; 1819e754c959SThomas Monjalon else 1820e754c959SThomas Monjalon #endif 1821e754c959SThomas Monjalon if (hw->modern) 18226d890f8aSYuanhan Liu VTPCI_OPS(hw) = &modern_ops; 18236d890f8aSYuanhan Liu else 18246d890f8aSYuanhan Liu VTPCI_OPS(hw) = &legacy_ops; 18256d890f8aSYuanhan Liu } 18266d890f8aSYuanhan Liu 18276d890f8aSYuanhan Liu /* 1828198ab336SOlivier Matz * This function is based on probe() function in virtio_pci.c 1829198ab336SOlivier Matz * It returns 0 on success. 1830198ab336SOlivier Matz */ 1831198ab336SOlivier Matz int 1832198ab336SOlivier Matz eth_virtio_dev_init(struct rte_eth_dev *eth_dev) 1833198ab336SOlivier Matz { 1834198ab336SOlivier Matz struct virtio_hw *hw = eth_dev->data->dev_private; 1835198ab336SOlivier Matz int ret; 1836198ab336SOlivier Matz 1837198ab336SOlivier Matz RTE_BUILD_BUG_ON(RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr_mrg_rxbuf)); 1838198ab336SOlivier Matz 1839198ab336SOlivier Matz eth_dev->dev_ops = &virtio_eth_dev_ops; 1840198ab336SOlivier Matz 1841198ab336SOlivier Matz if (rte_eal_process_type() == RTE_PROC_SECONDARY) { 18426d890f8aSYuanhan Liu if (!hw->virtio_user_dev) { 1843c0802544SFerruh Yigit ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_dev), hw); 18446d890f8aSYuanhan Liu if (ret) 18456d890f8aSYuanhan Liu return ret; 18466d890f8aSYuanhan Liu } 18476d890f8aSYuanhan Liu 18486d890f8aSYuanhan Liu virtio_set_vtpci_ops(hw); 18494819eae8SOlivier Matz set_rxtx_funcs(eth_dev); 18504819eae8SOlivier Matz 1851198ab336SOlivier Matz return 0; 1852198ab336SOlivier Matz } 1853198ab336SOlivier Matz 18547f468b2eSTiwei Bie /* 18557f468b2eSTiwei Bie * Pass the information to the rte_eth_dev_close() that it should also 18567f468b2eSTiwei Bie * release the private port resources. 18577f468b2eSTiwei Bie */ 18587f468b2eSTiwei Bie eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE; 18597f468b2eSTiwei Bie 1860198ab336SOlivier Matz /* Allocate memory for storing MAC addresses */ 186135b2d13fSOlivier Matz eth_dev->data->mac_addrs = rte_zmalloc("virtio", 186235b2d13fSOlivier Matz VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN, 0); 1863198ab336SOlivier Matz if (eth_dev->data->mac_addrs == NULL) { 1864198ab336SOlivier Matz PMD_INIT_LOG(ERR, 1865198ab336SOlivier Matz "Failed to allocate %d bytes needed to store MAC addresses", 186635b2d13fSOlivier Matz VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN); 1867198ab336SOlivier Matz return -ENOMEM; 1868198ab336SOlivier Matz } 1869198ab336SOlivier Matz 187076873125SYuanhan Liu hw->port_id = eth_dev->data->port_id; 18716a7c0dfcSJan Blunck /* For virtio_user case the hw->virtio_user_dev is populated by 18726a7c0dfcSJan Blunck * virtio_user_eth_dev_alloc() before eth_virtio_dev_init() is called. 18736a7c0dfcSJan Blunck */ 18746a7c0dfcSJan Blunck if (!hw->virtio_user_dev) { 1875c0802544SFerruh Yigit ret = vtpci_init(RTE_ETH_DEV_TO_PCI(eth_dev), hw); 1876198ab336SOlivier Matz if (ret) 18773484c8d8STiwei Bie goto err_vtpci_init; 1878198ab336SOlivier Matz } 1879198ab336SOlivier Matz 188060e6f470SOlivier Matz /* reset device and negotiate default features */ 188196cb6711SOlivier Matz ret = virtio_init_device(eth_dev, VIRTIO_PMD_DEFAULT_GUEST_FEATURES); 1882198ab336SOlivier Matz if (ret < 0) 18833484c8d8STiwei Bie goto err_virtio_init; 1884198ab336SOlivier Matz 18857f468b2eSTiwei Bie hw->opened = true; 18867f468b2eSTiwei Bie 18876c3169a3SBruce Richardson return 0; 188843d18765SPengzhen Liu 18893484c8d8STiwei Bie err_virtio_init: 18903484c8d8STiwei Bie if (!hw->virtio_user_dev) { 18913484c8d8STiwei Bie rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev)); 18923484c8d8STiwei Bie if (!hw->modern) 18933484c8d8STiwei Bie rte_pci_ioport_unmap(VTPCI_IO(hw)); 18943484c8d8STiwei Bie } 18953484c8d8STiwei Bie err_vtpci_init: 189643d18765SPengzhen Liu rte_free(eth_dev->data->mac_addrs); 18977dee8c79SAaron Conole eth_dev->data->mac_addrs = NULL; 189843d18765SPengzhen Liu return ret; 18996c3169a3SBruce Richardson } 19006c3169a3SBruce Richardson 1901abf4c84bSBernard Iremonger static int 1902abf4c84bSBernard Iremonger eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) 1903abf4c84bSBernard Iremonger { 1904abf4c84bSBernard Iremonger PMD_INIT_FUNC_TRACE(); 1905abf4c84bSBernard Iremonger 1906abf4c84bSBernard Iremonger if (rte_eal_process_type() == RTE_PROC_SECONDARY) 19078f62ec38SQi Zhang return 0; 1908abf4c84bSBernard Iremonger 19093f3b3d54SYuanhan Liu virtio_dev_stop(eth_dev); 1910abf4c84bSBernard Iremonger virtio_dev_close(eth_dev); 1911abf4c84bSBernard Iremonger 1912abf4c84bSBernard Iremonger eth_dev->dev_ops = NULL; 1913abf4c84bSBernard Iremonger eth_dev->tx_pkt_burst = NULL; 1914abf4c84bSBernard Iremonger eth_dev->rx_pkt_burst = NULL; 1915abf4c84bSBernard Iremonger 1916abf4c84bSBernard Iremonger PMD_INIT_LOG(DEBUG, "dev_uninit completed"); 1917abf4c84bSBernard Iremonger 1918abf4c84bSBernard Iremonger return 0; 1919abf4c84bSBernard Iremonger } 1920abf4c84bSBernard Iremonger 1921440f03c2SXiao Wang static int vdpa_check_handler(__rte_unused const char *key, 1922440f03c2SXiao Wang const char *value, __rte_unused void *opaque) 1923440f03c2SXiao Wang { 1924440f03c2SXiao Wang if (strcmp(value, "1")) 1925440f03c2SXiao Wang return -1; 1926440f03c2SXiao Wang 1927440f03c2SXiao Wang return 0; 1928440f03c2SXiao Wang } 1929440f03c2SXiao Wang 1930440f03c2SXiao Wang static int 1931440f03c2SXiao Wang vdpa_mode_selected(struct rte_devargs *devargs) 1932440f03c2SXiao Wang { 1933440f03c2SXiao Wang struct rte_kvargs *kvlist; 1934440f03c2SXiao Wang const char *key = "vdpa"; 1935440f03c2SXiao Wang int ret = 0; 1936440f03c2SXiao Wang 1937440f03c2SXiao Wang if (devargs == NULL) 1938440f03c2SXiao Wang return 0; 1939440f03c2SXiao Wang 1940440f03c2SXiao Wang kvlist = rte_kvargs_parse(devargs->args, NULL); 1941440f03c2SXiao Wang if (kvlist == NULL) 1942440f03c2SXiao Wang return 0; 1943440f03c2SXiao Wang 1944440f03c2SXiao Wang if (!rte_kvargs_count(kvlist, key)) 1945440f03c2SXiao Wang goto exit; 1946440f03c2SXiao Wang 1947440f03c2SXiao Wang /* vdpa mode selected when there's a key-value pair: vdpa=1 */ 1948440f03c2SXiao Wang if (rte_kvargs_process(kvlist, key, 1949440f03c2SXiao Wang vdpa_check_handler, NULL) < 0) { 1950440f03c2SXiao Wang goto exit; 1951440f03c2SXiao Wang } 1952440f03c2SXiao Wang ret = 1; 1953440f03c2SXiao Wang 1954440f03c2SXiao Wang exit: 1955440f03c2SXiao Wang rte_kvargs_free(kvlist); 1956440f03c2SXiao Wang return ret; 1957440f03c2SXiao Wang } 1958440f03c2SXiao Wang 1959fdf91e0fSJan Blunck static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 1960fdf91e0fSJan Blunck struct rte_pci_device *pci_dev) 1961fdf91e0fSJan Blunck { 1962705dced4SIlya Maximets if (rte_eal_iopl_init() != 0) { 1963705dced4SIlya Maximets PMD_INIT_LOG(ERR, "IOPL call failed - cannot use virtio PMD"); 1964705dced4SIlya Maximets return 1; 1965705dced4SIlya Maximets } 1966705dced4SIlya Maximets 1967440f03c2SXiao Wang /* virtio pmd skips probe if device needs to work in vdpa mode */ 1968440f03c2SXiao Wang if (vdpa_mode_selected(pci_dev->device.devargs)) 1969440f03c2SXiao Wang return 1; 1970440f03c2SXiao Wang 1971fdf91e0fSJan Blunck return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_hw), 1972fdf91e0fSJan Blunck eth_virtio_dev_init); 1973fdf91e0fSJan Blunck } 1974fdf91e0fSJan Blunck 1975fdf91e0fSJan Blunck static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev) 1976fdf91e0fSJan Blunck { 19777f468b2eSTiwei Bie int ret; 19787f468b2eSTiwei Bie 19797f468b2eSTiwei Bie ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_dev_uninit); 19807f468b2eSTiwei Bie /* Port has already been released by close. */ 19817f468b2eSTiwei Bie if (ret == -ENODEV) 19827f468b2eSTiwei Bie ret = 0; 19837f468b2eSTiwei Bie return ret; 1984fdf91e0fSJan Blunck } 1985fdf91e0fSJan Blunck 1986fdf91e0fSJan Blunck static struct rte_pci_driver rte_virtio_pmd = { 1987cd433ce5SDavid Marchand .driver = { 1988cd433ce5SDavid Marchand .name = "net_virtio", 1989cd433ce5SDavid Marchand }, 19906c3169a3SBruce Richardson .id_table = pci_id_virtio_map, 199122dda618SBen Walker .drv_flags = 0, 1992fdf91e0fSJan Blunck .probe = eth_virtio_pci_probe, 1993fdf91e0fSJan Blunck .remove = eth_virtio_pci_remove, 19946c3169a3SBruce Richardson }; 19956c3169a3SBruce Richardson 1996f8e99896SThomas Monjalon RTE_INIT(rte_virtio_pmd_init) 19976c3169a3SBruce Richardson { 1998705dced4SIlya Maximets rte_eal_iopl_init(); 19993dcfe039SThomas Monjalon rte_pci_register(&rte_virtio_pmd); 20006c3169a3SBruce Richardson } 20016c3169a3SBruce Richardson 2002db8d6790SMaxime Coquelin static bool 2003db8d6790SMaxime Coquelin rx_offload_enabled(struct virtio_hw *hw) 2004db8d6790SMaxime Coquelin { 2005db8d6790SMaxime Coquelin return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) || 2006db8d6790SMaxime Coquelin vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) || 2007db8d6790SMaxime Coquelin vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6); 2008db8d6790SMaxime Coquelin } 2009db8d6790SMaxime Coquelin 2010db8d6790SMaxime Coquelin static bool 2011db8d6790SMaxime Coquelin tx_offload_enabled(struct virtio_hw *hw) 2012db8d6790SMaxime Coquelin { 2013db8d6790SMaxime Coquelin return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) || 2014db8d6790SMaxime Coquelin vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) || 2015db8d6790SMaxime Coquelin vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6); 2016db8d6790SMaxime Coquelin } 2017db8d6790SMaxime Coquelin 20186c3169a3SBruce Richardson /* 20196c3169a3SBruce Richardson * Configure virtio device 20206c3169a3SBruce Richardson * It returns 0 on success. 20216c3169a3SBruce Richardson */ 20226c3169a3SBruce Richardson static int 20236c3169a3SBruce Richardson virtio_dev_configure(struct rte_eth_dev *dev) 20246c3169a3SBruce Richardson { 20256c3169a3SBruce Richardson const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode; 20264174a7b5SMaxime Coquelin const struct rte_eth_txmode *txmode = &dev->data->dev_conf.txmode; 20276c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 202835b2d13fSOlivier Matz uint32_t ether_hdr_len = RTE_ETHER_HDR_LEN + VLAN_TAG_LEN + 20298b90e435SJens Freimann hw->vtnet_hdr_size; 20309c7ce8bdSTiwei Bie uint64_t rx_offloads = rxmode->offloads; 20314174a7b5SMaxime Coquelin uint64_t tx_offloads = txmode->offloads; 2032ec9f3d12SOlivier Matz uint64_t req_features; 2033e7b9d1d2SJiayu Hu int ret; 20346c3169a3SBruce Richardson 20356c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "configure"); 2036ec9f3d12SOlivier Matz req_features = VIRTIO_PMD_DEFAULT_GUEST_FEATURES; 20374dab342bSStephen Hemminger 2038e7b9d1d2SJiayu Hu if (dev->data->dev_conf.intr_conf.rxq) { 2039e7b9d1d2SJiayu Hu ret = virtio_init_device(dev, hw->req_guest_features); 2040e7b9d1d2SJiayu Hu if (ret < 0) 2041e7b9d1d2SJiayu Hu return ret; 2042e7b9d1d2SJiayu Hu } 2043e7b9d1d2SJiayu Hu 20448b90e435SJens Freimann if (rxmode->max_rx_pkt_len > hw->max_mtu + ether_hdr_len) 20458b90e435SJens Freimann req_features &= ~(1ULL << VIRTIO_NET_F_MTU); 20468b90e435SJens Freimann 20479c7ce8bdSTiwei Bie if (rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM | 20489c7ce8bdSTiwei Bie DEV_RX_OFFLOAD_TCP_CKSUM)) 2049d67d86ceSOlivier Matz req_features |= (1ULL << VIRTIO_NET_F_GUEST_CSUM); 2050d67d86ceSOlivier Matz 20519c7ce8bdSTiwei Bie if (rx_offloads & DEV_RX_OFFLOAD_TCP_LRO) 2052ec9f3d12SOlivier Matz req_features |= 2053ec9f3d12SOlivier Matz (1ULL << VIRTIO_NET_F_GUEST_TSO4) | 2054ec9f3d12SOlivier Matz (1ULL << VIRTIO_NET_F_GUEST_TSO6); 20556c3169a3SBruce Richardson 20564174a7b5SMaxime Coquelin if (tx_offloads & (DEV_TX_OFFLOAD_UDP_CKSUM | 20574174a7b5SMaxime Coquelin DEV_TX_OFFLOAD_TCP_CKSUM)) 20584174a7b5SMaxime Coquelin req_features |= (1ULL << VIRTIO_NET_F_CSUM); 20594174a7b5SMaxime Coquelin 20604174a7b5SMaxime Coquelin if (tx_offloads & DEV_TX_OFFLOAD_TCP_TSO) 20614174a7b5SMaxime Coquelin req_features |= 20624174a7b5SMaxime Coquelin (1ULL << VIRTIO_NET_F_HOST_TSO4) | 20634174a7b5SMaxime Coquelin (1ULL << VIRTIO_NET_F_HOST_TSO6); 20644174a7b5SMaxime Coquelin 2065ec9f3d12SOlivier Matz /* if request features changed, reinit the device */ 2066ec9f3d12SOlivier Matz if (req_features != hw->req_guest_features) { 2067ec9f3d12SOlivier Matz ret = virtio_init_device(dev, req_features); 2068ec9f3d12SOlivier Matz if (ret < 0) 2069ec9f3d12SOlivier Matz return ret; 2070ec9f3d12SOlivier Matz } 2071ec9f3d12SOlivier Matz 20729c7ce8bdSTiwei Bie if ((rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM | 20739c7ce8bdSTiwei Bie DEV_RX_OFFLOAD_TCP_CKSUM)) && 2074d67d86ceSOlivier Matz !vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM)) { 207578fd97c3SOlivier Matz PMD_DRV_LOG(ERR, 2076d67d86ceSOlivier Matz "rx checksum not available on this host"); 2077d67d86ceSOlivier Matz return -ENOTSUP; 2078d67d86ceSOlivier Matz } 2079d67d86ceSOlivier Matz 20809c7ce8bdSTiwei Bie if ((rx_offloads & DEV_RX_OFFLOAD_TCP_LRO) && 2081ec9f3d12SOlivier Matz (!vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) || 2082b628cb24STiwei Bie !vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6))) { 208378fd97c3SOlivier Matz PMD_DRV_LOG(ERR, 2084ec9f3d12SOlivier Matz "Large Receive Offload not available on this host"); 208586d59b21SOlivier Matz return -ENOTSUP; 208686d59b21SOlivier Matz } 208786d59b21SOlivier Matz 208869c80d4eSYuanhan Liu /* start control queue */ 208969c80d4eSYuanhan Liu if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ)) 209045e4acd4SOlivier Matz virtio_dev_cq_start(dev); 209145e4acd4SOlivier Matz 20929c7ce8bdSTiwei Bie if (rx_offloads & DEV_RX_OFFLOAD_VLAN_STRIP) 20939c7ce8bdSTiwei Bie hw->vlan_strip = 1; 20946c3169a3SBruce Richardson 20959c7ce8bdSTiwei Bie if ((rx_offloads & DEV_RX_OFFLOAD_VLAN_FILTER) 20966c3169a3SBruce Richardson && !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) { 209778fd97c3SOlivier Matz PMD_DRV_LOG(ERR, 20986c3169a3SBruce Richardson "vlan filtering not available on this host"); 20996c3169a3SBruce Richardson return -ENOTSUP; 21006c3169a3SBruce Richardson } 21016c3169a3SBruce Richardson 2102db8d6790SMaxime Coquelin hw->has_tx_offload = tx_offload_enabled(hw); 2103db8d6790SMaxime Coquelin hw->has_rx_offload = rx_offload_enabled(hw); 2104db8d6790SMaxime Coquelin 210562a785a6SJianfeng Tan if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) 2106981e61f5SJianfeng Tan /* Enable vector (0) for Link State Intrerrupt */ 2107981e61f5SJianfeng Tan if (VTPCI_OPS(hw)->set_config_irq(hw, 0) == 2108981e61f5SJianfeng Tan VIRTIO_MSI_NO_VECTOR) { 21096c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "failed to set config vector"); 21106c3169a3SBruce Richardson return -EBUSY; 21116c3169a3SBruce Richardson } 21126c3169a3SBruce Richardson 21131978a9dcSXiao Wang rte_spinlock_init(&hw->state_lock); 21141978a9dcSXiao Wang 211509649363SOlivier Matz hw->use_simple_rx = 1; 21164819eae8SOlivier Matz 21178f3bd7e8SMarvin Liu if (vtpci_with_feature(hw, VIRTIO_F_IN_ORDER)) { 21188f3bd7e8SMarvin Liu hw->use_inorder_tx = 1; 21198f3bd7e8SMarvin Liu hw->use_inorder_rx = 1; 21208f3bd7e8SMarvin Liu hw->use_simple_rx = 0; 21218f3bd7e8SMarvin Liu } 21228f3bd7e8SMarvin Liu 2123a76290c8SJens Freimann if (vtpci_packed_queue(hw)) { 2124a76290c8SJens Freimann hw->use_simple_rx = 0; 2125a76290c8SJens Freimann hw->use_inorder_rx = 0; 2126a76290c8SJens Freimann } 2127a76290c8SJens Freimann 21288f3d451dSSamuel Gauthier #if defined RTE_ARCH_ARM64 || defined RTE_ARCH_ARM 212909649363SOlivier Matz if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON)) { 213009649363SOlivier Matz hw->use_simple_rx = 0; 213109649363SOlivier Matz } 21324819eae8SOlivier Matz #endif 213309649363SOlivier Matz if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) { 213409649363SOlivier Matz hw->use_simple_rx = 0; 213509649363SOlivier Matz } 21364819eae8SOlivier Matz 21379c7ce8bdSTiwei Bie if (rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM | 21382f901132SMaxime Coquelin DEV_RX_OFFLOAD_TCP_CKSUM | 21392f901132SMaxime Coquelin DEV_RX_OFFLOAD_TCP_LRO | 21402f901132SMaxime Coquelin DEV_RX_OFFLOAD_VLAN_STRIP)) 214116e48c9eSOlivier Matz hw->use_simple_rx = 0; 214216e48c9eSOlivier Matz 21436c3169a3SBruce Richardson return 0; 21446c3169a3SBruce Richardson } 21456c3169a3SBruce Richardson 21466c3169a3SBruce Richardson 21476c3169a3SBruce Richardson static int 21486c3169a3SBruce Richardson virtio_dev_start(struct rte_eth_dev *dev) 21496c3169a3SBruce Richardson { 21506c3169a3SBruce Richardson uint16_t nb_queues, i; 215101ad44fdSHuawei Xie struct virtnet_rx *rxvq; 215201ad44fdSHuawei Xie struct virtnet_tx *txvq __rte_unused; 2153663c7679SYuanhan Liu struct virtio_hw *hw = dev->data->dev_private; 2154efc83a1eSOlivier Matz int ret; 2155efc83a1eSOlivier Matz 2156efc83a1eSOlivier Matz /* Finish the initialization of the queues */ 2157efc83a1eSOlivier Matz for (i = 0; i < dev->data->nb_rx_queues; i++) { 2158efc83a1eSOlivier Matz ret = virtio_dev_rx_queue_setup_finish(dev, i); 2159efc83a1eSOlivier Matz if (ret < 0) 2160efc83a1eSOlivier Matz return ret; 2161efc83a1eSOlivier Matz } 2162efc83a1eSOlivier Matz for (i = 0; i < dev->data->nb_tx_queues; i++) { 2163efc83a1eSOlivier Matz ret = virtio_dev_tx_queue_setup_finish(dev, i); 2164efc83a1eSOlivier Matz if (ret < 0) 2165efc83a1eSOlivier Matz return ret; 2166efc83a1eSOlivier Matz } 21676c3169a3SBruce Richardson 21686c3169a3SBruce Richardson /* check if lsc interrupt feature is enabled */ 2169954ea115SStephen Hemminger if (dev->data->dev_conf.intr_conf.lsc) { 217062a785a6SJianfeng Tan if (!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)) { 21716c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "link status not supported by host"); 21726c3169a3SBruce Richardson return -ENOTSUP; 21736c3169a3SBruce Richardson } 2174349a447bSJianfeng Tan } 2175349a447bSJianfeng Tan 2176349a447bSJianfeng Tan /* Enable uio/vfio intr/eventfd mapping: althrough we already did that 2177349a447bSJianfeng Tan * in device configure, but it could be unmapped when device is 2178349a447bSJianfeng Tan * stopped. 2179349a447bSJianfeng Tan */ 2180349a447bSJianfeng Tan if (dev->data->dev_conf.intr_conf.lsc || 2181349a447bSJianfeng Tan dev->data->dev_conf.intr_conf.rxq) { 2182fe19d49cSZhiyong Yang virtio_intr_disable(dev); 21836c3169a3SBruce Richardson 2184f9b0d190SLuca Boccassi /* Setup interrupt callback */ 2185f9b0d190SLuca Boccassi if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) 2186f9b0d190SLuca Boccassi rte_intr_callback_register(dev->intr_handle, 2187f9b0d190SLuca Boccassi virtio_interrupt_handler, 2188f9b0d190SLuca Boccassi dev); 2189f9b0d190SLuca Boccassi 2190fe19d49cSZhiyong Yang if (virtio_intr_enable(dev) < 0) { 21916c3169a3SBruce Richardson PMD_DRV_LOG(ERR, "interrupt enable failed"); 21926c3169a3SBruce Richardson return -EIO; 21936c3169a3SBruce Richardson } 21946c3169a3SBruce Richardson } 21956c3169a3SBruce Richardson 21966c3169a3SBruce Richardson /*Notify the backend 21976c3169a3SBruce Richardson *Otherwise the tap backend might already stop its queue due to fullness. 21986c3169a3SBruce Richardson *vhost backend will have no chance to be waked up 21996c3169a3SBruce Richardson */ 220060d4a353SYuanhan Liu nb_queues = RTE_MAX(dev->data->nb_rx_queues, dev->data->nb_tx_queues); 2201663c7679SYuanhan Liu if (hw->max_queue_pairs > 1) { 22026c3169a3SBruce Richardson if (virtio_set_multiple_queues(dev, nb_queues) != 0) 22036c3169a3SBruce Richardson return -EINVAL; 22046c3169a3SBruce Richardson } 22056c3169a3SBruce Richardson 22066c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "nb_queues=%d", nb_queues); 22076c3169a3SBruce Richardson 220860d4a353SYuanhan Liu for (i = 0; i < dev->data->nb_rx_queues; i++) { 220901ad44fdSHuawei Xie rxvq = dev->data->rx_queues[i]; 2210d8227497STiwei Bie /* Flush the old packets */ 2211bcf55c93STiwei Bie virtqueue_rxvq_flush(rxvq->vq); 221201ad44fdSHuawei Xie virtqueue_notify(rxvq->vq); 221301ad44fdSHuawei Xie } 22146c3169a3SBruce Richardson 2215924da8f1SSteven Luong for (i = 0; i < dev->data->nb_tx_queues; i++) { 2216924da8f1SSteven Luong txvq = dev->data->tx_queues[i]; 2217924da8f1SSteven Luong virtqueue_notify(txvq->vq); 2218924da8f1SSteven Luong } 2219924da8f1SSteven Luong 22206c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "Notified backend at initialization"); 22216c3169a3SBruce Richardson 222201ad44fdSHuawei Xie for (i = 0; i < dev->data->nb_rx_queues; i++) { 222301ad44fdSHuawei Xie rxvq = dev->data->rx_queues[i]; 222401ad44fdSHuawei Xie VIRTQUEUE_DUMP(rxvq->vq); 222501ad44fdSHuawei Xie } 22266c3169a3SBruce Richardson 222701ad44fdSHuawei Xie for (i = 0; i < dev->data->nb_tx_queues; i++) { 222801ad44fdSHuawei Xie txvq = dev->data->tx_queues[i]; 222901ad44fdSHuawei Xie VIRTQUEUE_DUMP(txvq->vq); 223001ad44fdSHuawei Xie } 223158d9fe40SJianfeng Tan 22324819eae8SOlivier Matz set_rxtx_funcs(dev); 22332a821d81SChas Williams hw->started = true; 22346c3169a3SBruce Richardson 223558d9fe40SJianfeng Tan /* Initialize Link state */ 223658d9fe40SJianfeng Tan virtio_dev_link_update(dev, 0); 223758d9fe40SJianfeng Tan 22386c3169a3SBruce Richardson return 0; 22396c3169a3SBruce Richardson } 22406c3169a3SBruce Richardson 22416c3169a3SBruce Richardson static void virtio_dev_free_mbufs(struct rte_eth_dev *dev) 22426c3169a3SBruce Richardson { 2243bdb32afbSOlivier Matz struct virtio_hw *hw = dev->data->dev_private; 2244bdb32afbSOlivier Matz uint16_t nr_vq = virtio_get_nr_vq(hw); 2245bdb32afbSOlivier Matz const char *type __rte_unused; 2246bdb32afbSOlivier Matz unsigned int i, mbuf_num = 0; 2247bdb32afbSOlivier Matz struct virtqueue *vq; 22486c3169a3SBruce Richardson struct rte_mbuf *buf; 2249bdb32afbSOlivier Matz int queue_type; 22506c3169a3SBruce Richardson 2251b87c0648SDavid Harton if (hw->vqs == NULL) 2252b87c0648SDavid Harton return; 2253b87c0648SDavid Harton 2254bdb32afbSOlivier Matz for (i = 0; i < nr_vq; i++) { 2255bdb32afbSOlivier Matz vq = hw->vqs[i]; 2256bdb32afbSOlivier Matz if (!vq) 2257bdb32afbSOlivier Matz continue; 225801ad44fdSHuawei Xie 2259bdb32afbSOlivier Matz queue_type = virtio_get_queue_type(hw, i); 2260bdb32afbSOlivier Matz if (queue_type == VTNET_RQ) 2261bdb32afbSOlivier Matz type = "rxq"; 2262bdb32afbSOlivier Matz else if (queue_type == VTNET_TQ) 2263bdb32afbSOlivier Matz type = "txq"; 2264bdb32afbSOlivier Matz else 22653669a1afSOlivier Matz continue; 22663669a1afSOlivier Matz 22676c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 2268bdb32afbSOlivier Matz "Before freeing %s[%d] used and unused buf", 2269bdb32afbSOlivier Matz type, i); 2270bdb32afbSOlivier Matz VIRTQUEUE_DUMP(vq); 22716c3169a3SBruce Richardson 2272727411f5SOlivier Matz while ((buf = virtqueue_detach_unused(vq)) != NULL) { 22736c3169a3SBruce Richardson rte_pktmbuf_free(buf); 22746c3169a3SBruce Richardson mbuf_num++; 22756c3169a3SBruce Richardson } 22766c3169a3SBruce Richardson 22776c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, 2278bdb32afbSOlivier Matz "After freeing %s[%d] used and unused buf", 2279bdb32afbSOlivier Matz type, i); 2280bdb32afbSOlivier Matz VIRTQUEUE_DUMP(vq); 22816c3169a3SBruce Richardson } 22826c3169a3SBruce Richardson 2283bdb32afbSOlivier Matz PMD_INIT_LOG(DEBUG, "%d mbufs freed", mbuf_num); 22846c3169a3SBruce Richardson } 22856c3169a3SBruce Richardson 22866c3169a3SBruce Richardson /* 22876c3169a3SBruce Richardson * Stop device: disable interrupt and mark link down 22886c3169a3SBruce Richardson */ 22896c3169a3SBruce Richardson static void 22906c3169a3SBruce Richardson virtio_dev_stop(struct rte_eth_dev *dev) 22916c3169a3SBruce Richardson { 2292aa9f0606SYuanhan Liu struct virtio_hw *hw = dev->data->dev_private; 22936c3169a3SBruce Richardson struct rte_eth_link link; 2294349a447bSJianfeng Tan struct rte_intr_conf *intr_conf = &dev->data->dev_conf.intr_conf; 22956c3169a3SBruce Richardson 22966c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "stop"); 22976c3169a3SBruce Richardson 22981978a9dcSXiao Wang rte_spinlock_lock(&hw->state_lock); 22992a821d81SChas Williams if (!hw->started) 23002a821d81SChas Williams goto out_unlock; 23012a821d81SChas Williams hw->started = false; 23022a821d81SChas Williams 2303f9b0d190SLuca Boccassi if (intr_conf->lsc || intr_conf->rxq) { 2304fe19d49cSZhiyong Yang virtio_intr_disable(dev); 23056c3169a3SBruce Richardson 2306f9b0d190SLuca Boccassi /* Reset interrupt callback */ 2307f9b0d190SLuca Boccassi if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) { 2308f9b0d190SLuca Boccassi rte_intr_callback_unregister(dev->intr_handle, 2309f9b0d190SLuca Boccassi virtio_interrupt_handler, 2310f9b0d190SLuca Boccassi dev); 2311f9b0d190SLuca Boccassi } 2312f9b0d190SLuca Boccassi } 2313f9b0d190SLuca Boccassi 23146c3169a3SBruce Richardson memset(&link, 0, sizeof(link)); 2315717b2e8eSStephen Hemminger rte_eth_linkstatus_set(dev, &link); 23162a821d81SChas Williams out_unlock: 23171978a9dcSXiao Wang rte_spinlock_unlock(&hw->state_lock); 23186c3169a3SBruce Richardson } 23196c3169a3SBruce Richardson 23206c3169a3SBruce Richardson static int 23216c3169a3SBruce Richardson virtio_dev_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete) 23226c3169a3SBruce Richardson { 2323717b2e8eSStephen Hemminger struct rte_eth_link link; 23246c3169a3SBruce Richardson uint16_t status; 23256c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 2326717b2e8eSStephen Hemminger 23276c3169a3SBruce Richardson memset(&link, 0, sizeof(link)); 232811319000SMarc Sune link.link_duplex = ETH_LINK_FULL_DUPLEX; 232967090011SZhiyong Yang link.link_speed = ETH_SPEED_NUM_10G; 2330717b2e8eSStephen Hemminger link.link_autoneg = ETH_LINK_FIXED; 23316c3169a3SBruce Richardson 23322a821d81SChas Williams if (!hw->started) { 2333aa9f0606SYuanhan Liu link.link_status = ETH_LINK_DOWN; 2334aa9f0606SYuanhan Liu } else if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) { 23356c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "Get link status from hw"); 23366c3169a3SBruce Richardson vtpci_read_dev_config(hw, 23376c3169a3SBruce Richardson offsetof(struct virtio_net_config, status), 23386c3169a3SBruce Richardson &status, sizeof(status)); 23396c3169a3SBruce Richardson if ((status & VIRTIO_NET_S_LINK_UP) == 0) { 234009419f23SThomas Monjalon link.link_status = ETH_LINK_DOWN; 23416c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "Port %d is down", 23426c3169a3SBruce Richardson dev->data->port_id); 23436c3169a3SBruce Richardson } else { 234409419f23SThomas Monjalon link.link_status = ETH_LINK_UP; 23456c3169a3SBruce Richardson PMD_INIT_LOG(DEBUG, "Port %d is up", 23466c3169a3SBruce Richardson dev->data->port_id); 23476c3169a3SBruce Richardson } 23486c3169a3SBruce Richardson } else { 234909419f23SThomas Monjalon link.link_status = ETH_LINK_UP; 23506c3169a3SBruce Richardson } 23516c3169a3SBruce Richardson 2352717b2e8eSStephen Hemminger return rte_eth_linkstatus_set(dev, &link); 23536c3169a3SBruce Richardson } 23546c3169a3SBruce Richardson 2355289ba0c0SDavid Harton static int 2356289ba0c0SDavid Harton virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask) 2357289ba0c0SDavid Harton { 2358289ba0c0SDavid Harton const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode; 2359289ba0c0SDavid Harton struct virtio_hw *hw = dev->data->dev_private; 23609c7ce8bdSTiwei Bie uint64_t offloads = rxmode->offloads; 2361289ba0c0SDavid Harton 2362289ba0c0SDavid Harton if (mask & ETH_VLAN_FILTER_MASK) { 23639c7ce8bdSTiwei Bie if ((offloads & DEV_RX_OFFLOAD_VLAN_FILTER) && 2364289ba0c0SDavid Harton !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) { 2365289ba0c0SDavid Harton 2366289ba0c0SDavid Harton PMD_DRV_LOG(NOTICE, 2367289ba0c0SDavid Harton "vlan filtering not available on this host"); 2368289ba0c0SDavid Harton 2369289ba0c0SDavid Harton return -ENOTSUP; 2370289ba0c0SDavid Harton } 2371289ba0c0SDavid Harton } 2372289ba0c0SDavid Harton 2373289ba0c0SDavid Harton if (mask & ETH_VLAN_STRIP_MASK) 23749c7ce8bdSTiwei Bie hw->vlan_strip = !!(offloads & DEV_RX_OFFLOAD_VLAN_STRIP); 2375289ba0c0SDavid Harton 2376289ba0c0SDavid Harton return 0; 2377289ba0c0SDavid Harton } 2378289ba0c0SDavid Harton 23796c3169a3SBruce Richardson static void 23806c3169a3SBruce Richardson virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) 23816c3169a3SBruce Richardson { 2382c1e55ed3SOlivier Matz uint64_t tso_mask, host_features; 23836c3169a3SBruce Richardson struct virtio_hw *hw = dev->data->dev_private; 23846c3169a3SBruce Richardson 2385b392e987SIdo Barnea dev_info->speed_capa = ETH_LINK_SPEED_10G; /* fake value */ 2386b392e987SIdo Barnea 238745e4acd4SOlivier Matz dev_info->max_rx_queues = 238845e4acd4SOlivier Matz RTE_MIN(hw->max_queue_pairs, VIRTIO_MAX_RX_QUEUES); 238945e4acd4SOlivier Matz dev_info->max_tx_queues = 239045e4acd4SOlivier Matz RTE_MIN(hw->max_queue_pairs, VIRTIO_MAX_TX_QUEUES); 23916c3169a3SBruce Richardson dev_info->min_rx_bufsize = VIRTIO_MIN_RX_BUFSIZE; 23926c3169a3SBruce Richardson dev_info->max_rx_pktlen = VIRTIO_MAX_RX_PKTLEN; 23936c3169a3SBruce Richardson dev_info->max_mac_addrs = VIRTIO_MAX_MAC_ADDRS; 239458169a9cSOlivier Matz 2395c1e55ed3SOlivier Matz host_features = VTPCI_OPS(hw)->get_features(hw); 2396323e7b66SFerruh Yigit dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP; 23978b90e435SJens Freimann dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_JUMBO_FRAME; 2398c1e55ed3SOlivier Matz if (host_features & (1ULL << VIRTIO_NET_F_GUEST_CSUM)) { 2399c1e55ed3SOlivier Matz dev_info->rx_offload_capa |= 2400c1e55ed3SOlivier Matz DEV_RX_OFFLOAD_TCP_CKSUM | 2401c1e55ed3SOlivier Matz DEV_RX_OFFLOAD_UDP_CKSUM; 2402c1e55ed3SOlivier Matz } 24039c7ce8bdSTiwei Bie if (host_features & (1ULL << VIRTIO_NET_F_CTRL_VLAN)) 24049c7ce8bdSTiwei Bie dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_VLAN_FILTER; 2405c1e55ed3SOlivier Matz tso_mask = (1ULL << VIRTIO_NET_F_GUEST_TSO4) | 2406c1e55ed3SOlivier Matz (1ULL << VIRTIO_NET_F_GUEST_TSO6); 2407ec9f3d12SOlivier Matz if ((host_features & tso_mask) == tso_mask) 2408ec9f3d12SOlivier Matz dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_TCP_LRO; 2409c1e55ed3SOlivier Matz 24109c7ce8bdSTiwei Bie dev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS | 24119c7ce8bdSTiwei Bie DEV_TX_OFFLOAD_VLAN_INSERT; 24124174a7b5SMaxime Coquelin if (host_features & (1ULL << VIRTIO_NET_F_CSUM)) { 241358169a9cSOlivier Matz dev_info->tx_offload_capa |= 241458169a9cSOlivier Matz DEV_TX_OFFLOAD_UDP_CKSUM | 241558169a9cSOlivier Matz DEV_TX_OFFLOAD_TCP_CKSUM; 241658169a9cSOlivier Matz } 241769657304SOlivier Matz tso_mask = (1ULL << VIRTIO_NET_F_HOST_TSO4) | 241869657304SOlivier Matz (1ULL << VIRTIO_NET_F_HOST_TSO6); 24194174a7b5SMaxime Coquelin if ((host_features & tso_mask) == tso_mask) 242069657304SOlivier Matz dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO; 24216c3169a3SBruce Richardson } 24226c3169a3SBruce Richardson 24236c3169a3SBruce Richardson /* 24246c3169a3SBruce Richardson * It enables testpmd to collect per queue stats. 24256c3169a3SBruce Richardson */ 24266c3169a3SBruce Richardson static int 24276c3169a3SBruce Richardson virtio_dev_queue_stats_mapping_set(__rte_unused struct rte_eth_dev *eth_dev, 24286c3169a3SBruce Richardson __rte_unused uint16_t queue_id, __rte_unused uint8_t stat_idx, 24296c3169a3SBruce Richardson __rte_unused uint8_t is_rx) 24306c3169a3SBruce Richardson { 24316c3169a3SBruce Richardson return 0; 24326c3169a3SBruce Richardson } 24336c3169a3SBruce Richardson 243401f19227SShreyansh Jain RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__); 243501f19227SShreyansh Jain RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map); 243606e81dc9SDavid Marchand RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci"); 243700628188SStephen Hemminger 2438f8e99896SThomas Monjalon RTE_INIT(virtio_init_log) 243900628188SStephen Hemminger { 2440bace76f6SHarry van Haaren virtio_logtype_init = rte_log_register("pmd.net.virtio.init"); 244100628188SStephen Hemminger if (virtio_logtype_init >= 0) 244200628188SStephen Hemminger rte_log_set_level(virtio_logtype_init, RTE_LOG_NOTICE); 2443bace76f6SHarry van Haaren virtio_logtype_driver = rte_log_register("pmd.net.virtio.driver"); 244400628188SStephen Hemminger if (virtio_logtype_driver >= 0) 244500628188SStephen Hemminger rte_log_set_level(virtio_logtype_driver, RTE_LOG_NOTICE); 244600628188SStephen Hemminger } 2447