1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2010-2016 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang #include <stdint.h>
6a9643ea8Slogwang #include <string.h>
7a9643ea8Slogwang #include <stdio.h>
8a9643ea8Slogwang #include <errno.h>
9a9643ea8Slogwang #include <unistd.h>
10a9643ea8Slogwang
11d30ea906Sjfb8856606 #include <rte_ethdev_driver.h>
122bfe3f2eSlogwang #include <rte_ethdev_pci.h>
13a9643ea8Slogwang #include <rte_memcpy.h>
14a9643ea8Slogwang #include <rte_string_fns.h>
15a9643ea8Slogwang #include <rte_memzone.h>
16a9643ea8Slogwang #include <rte_malloc.h>
17a9643ea8Slogwang #include <rte_branch_prediction.h>
18a9643ea8Slogwang #include <rte_pci.h>
192bfe3f2eSlogwang #include <rte_bus_pci.h>
20a9643ea8Slogwang #include <rte_ether.h>
21d30ea906Sjfb8856606 #include <rte_ip.h>
22d30ea906Sjfb8856606 #include <rte_arp.h>
23a9643ea8Slogwang #include <rte_common.h>
24a9643ea8Slogwang #include <rte_errno.h>
252bfe3f2eSlogwang #include <rte_cpuflags.h>
26*2d9fd380Sjfb8856606 #include <rte_vect.h>
27a9643ea8Slogwang
28a9643ea8Slogwang #include <rte_memory.h>
29a9643ea8Slogwang #include <rte_eal.h>
30a9643ea8Slogwang #include <rte_dev.h>
31d30ea906Sjfb8856606 #include <rte_cycles.h>
32d30ea906Sjfb8856606 #include <rte_kvargs.h>
33a9643ea8Slogwang
34a9643ea8Slogwang #include "virtio_ethdev.h"
35a9643ea8Slogwang #include "virtio_pci.h"
36a9643ea8Slogwang #include "virtio_logs.h"
37a9643ea8Slogwang #include "virtqueue.h"
38a9643ea8Slogwang #include "virtio_rxtx.h"
394418919fSjohnjiang #include "virtio_user/virtio_user_dev.h"
40a9643ea8Slogwang
41a9643ea8Slogwang static int eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev);
42a9643ea8Slogwang static int virtio_dev_configure(struct rte_eth_dev *dev);
43a9643ea8Slogwang static int virtio_dev_start(struct rte_eth_dev *dev);
44*2d9fd380Sjfb8856606 static int virtio_dev_stop(struct rte_eth_dev *dev);
454418919fSjohnjiang static int virtio_dev_promiscuous_enable(struct rte_eth_dev *dev);
464418919fSjohnjiang static int virtio_dev_promiscuous_disable(struct rte_eth_dev *dev);
474418919fSjohnjiang static int virtio_dev_allmulticast_enable(struct rte_eth_dev *dev);
484418919fSjohnjiang static int virtio_dev_allmulticast_disable(struct rte_eth_dev *dev);
49*2d9fd380Sjfb8856606 static uint32_t virtio_dev_speed_capa_get(uint32_t speed);
50*2d9fd380Sjfb8856606 static int virtio_dev_devargs_parse(struct rte_devargs *devargs,
51*2d9fd380Sjfb8856606 int *vdpa,
52*2d9fd380Sjfb8856606 uint32_t *speed,
53*2d9fd380Sjfb8856606 int *vectorized);
544418919fSjohnjiang static int virtio_dev_info_get(struct rte_eth_dev *dev,
55a9643ea8Slogwang struct rte_eth_dev_info *dev_info);
56a9643ea8Slogwang static int virtio_dev_link_update(struct rte_eth_dev *dev,
572bfe3f2eSlogwang int wait_to_complete);
582bfe3f2eSlogwang static int virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
59a9643ea8Slogwang
60a9643ea8Slogwang static void virtio_set_hwaddr(struct virtio_hw *hw);
61a9643ea8Slogwang static void virtio_get_hwaddr(struct virtio_hw *hw);
62a9643ea8Slogwang
632bfe3f2eSlogwang static int virtio_dev_stats_get(struct rte_eth_dev *dev,
64a9643ea8Slogwang struct rte_eth_stats *stats);
65a9643ea8Slogwang static int virtio_dev_xstats_get(struct rte_eth_dev *dev,
66a9643ea8Slogwang struct rte_eth_xstat *xstats, unsigned n);
67a9643ea8Slogwang static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
68a9643ea8Slogwang struct rte_eth_xstat_name *xstats_names,
69a9643ea8Slogwang unsigned limit);
704418919fSjohnjiang static int virtio_dev_stats_reset(struct rte_eth_dev *dev);
71a9643ea8Slogwang static void virtio_dev_free_mbufs(struct rte_eth_dev *dev);
72a9643ea8Slogwang static int virtio_vlan_filter_set(struct rte_eth_dev *dev,
73a9643ea8Slogwang uint16_t vlan_id, int on);
742bfe3f2eSlogwang static int virtio_mac_addr_add(struct rte_eth_dev *dev,
754418919fSjohnjiang struct rte_ether_addr *mac_addr,
762bfe3f2eSlogwang uint32_t index, uint32_t vmdq);
77a9643ea8Slogwang static void virtio_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index);
78d30ea906Sjfb8856606 static int virtio_mac_addr_set(struct rte_eth_dev *dev,
794418919fSjohnjiang struct rte_ether_addr *mac_addr);
80a9643ea8Slogwang
812bfe3f2eSlogwang static int virtio_intr_disable(struct rte_eth_dev *dev);
822bfe3f2eSlogwang
83a9643ea8Slogwang static int virtio_dev_queue_stats_mapping_set(
842bfe3f2eSlogwang struct rte_eth_dev *eth_dev,
852bfe3f2eSlogwang uint16_t queue_id,
862bfe3f2eSlogwang uint8_t stat_idx,
872bfe3f2eSlogwang uint8_t is_rx);
88a9643ea8Slogwang
89d30ea906Sjfb8856606 static void virtio_notify_peers(struct rte_eth_dev *dev);
90d30ea906Sjfb8856606 static void virtio_ack_link_announce(struct rte_eth_dev *dev);
91d30ea906Sjfb8856606
92a9643ea8Slogwang /*
93a9643ea8Slogwang * The set of PCI devices this driver supports
94a9643ea8Slogwang */
95a9643ea8Slogwang static const struct rte_pci_id pci_id_virtio_map[] = {
962bfe3f2eSlogwang { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_LEGACY_DEVICEID_NET) },
972bfe3f2eSlogwang { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_MODERN_DEVICEID_NET) },
98a9643ea8Slogwang { .vendor_id = 0, /* sentinel */ },
99a9643ea8Slogwang };
100a9643ea8Slogwang
101a9643ea8Slogwang struct rte_virtio_xstats_name_off {
102a9643ea8Slogwang char name[RTE_ETH_XSTATS_NAME_SIZE];
103a9643ea8Slogwang unsigned offset;
104a9643ea8Slogwang };
105a9643ea8Slogwang
106a9643ea8Slogwang /* [rt]x_qX_ is prepended to the name string here */
107a9643ea8Slogwang static const struct rte_virtio_xstats_name_off rte_virtio_rxq_stat_strings[] = {
108a9643ea8Slogwang {"good_packets", offsetof(struct virtnet_rx, stats.packets)},
109a9643ea8Slogwang {"good_bytes", offsetof(struct virtnet_rx, stats.bytes)},
110a9643ea8Slogwang {"errors", offsetof(struct virtnet_rx, stats.errors)},
111a9643ea8Slogwang {"multicast_packets", offsetof(struct virtnet_rx, stats.multicast)},
112a9643ea8Slogwang {"broadcast_packets", offsetof(struct virtnet_rx, stats.broadcast)},
113a9643ea8Slogwang {"undersize_packets", offsetof(struct virtnet_rx, stats.size_bins[0])},
114a9643ea8Slogwang {"size_64_packets", offsetof(struct virtnet_rx, stats.size_bins[1])},
115a9643ea8Slogwang {"size_65_127_packets", offsetof(struct virtnet_rx, stats.size_bins[2])},
116a9643ea8Slogwang {"size_128_255_packets", offsetof(struct virtnet_rx, stats.size_bins[3])},
117a9643ea8Slogwang {"size_256_511_packets", offsetof(struct virtnet_rx, stats.size_bins[4])},
118a9643ea8Slogwang {"size_512_1023_packets", offsetof(struct virtnet_rx, stats.size_bins[5])},
119a9643ea8Slogwang {"size_1024_1518_packets", offsetof(struct virtnet_rx, stats.size_bins[6])},
120a9643ea8Slogwang {"size_1519_max_packets", offsetof(struct virtnet_rx, stats.size_bins[7])},
121a9643ea8Slogwang };
122a9643ea8Slogwang
123a9643ea8Slogwang /* [rt]x_qX_ is prepended to the name string here */
124a9643ea8Slogwang static const struct rte_virtio_xstats_name_off rte_virtio_txq_stat_strings[] = {
125a9643ea8Slogwang {"good_packets", offsetof(struct virtnet_tx, stats.packets)},
126a9643ea8Slogwang {"good_bytes", offsetof(struct virtnet_tx, stats.bytes)},
127a9643ea8Slogwang {"multicast_packets", offsetof(struct virtnet_tx, stats.multicast)},
128a9643ea8Slogwang {"broadcast_packets", offsetof(struct virtnet_tx, stats.broadcast)},
129a9643ea8Slogwang {"undersize_packets", offsetof(struct virtnet_tx, stats.size_bins[0])},
130a9643ea8Slogwang {"size_64_packets", offsetof(struct virtnet_tx, stats.size_bins[1])},
131a9643ea8Slogwang {"size_65_127_packets", offsetof(struct virtnet_tx, stats.size_bins[2])},
132a9643ea8Slogwang {"size_128_255_packets", offsetof(struct virtnet_tx, stats.size_bins[3])},
133a9643ea8Slogwang {"size_256_511_packets", offsetof(struct virtnet_tx, stats.size_bins[4])},
134a9643ea8Slogwang {"size_512_1023_packets", offsetof(struct virtnet_tx, stats.size_bins[5])},
135a9643ea8Slogwang {"size_1024_1518_packets", offsetof(struct virtnet_tx, stats.size_bins[6])},
136a9643ea8Slogwang {"size_1519_max_packets", offsetof(struct virtnet_tx, stats.size_bins[7])},
137a9643ea8Slogwang };
138a9643ea8Slogwang
139a9643ea8Slogwang #define VIRTIO_NB_RXQ_XSTATS (sizeof(rte_virtio_rxq_stat_strings) / \
140a9643ea8Slogwang sizeof(rte_virtio_rxq_stat_strings[0]))
141a9643ea8Slogwang #define VIRTIO_NB_TXQ_XSTATS (sizeof(rte_virtio_txq_stat_strings) / \
142a9643ea8Slogwang sizeof(rte_virtio_txq_stat_strings[0]))
143a9643ea8Slogwang
1442bfe3f2eSlogwang struct virtio_hw_internal virtio_hw_internal[RTE_MAX_ETHPORTS];
1452bfe3f2eSlogwang
1464418919fSjohnjiang static struct virtio_pmd_ctrl *
virtio_send_command_packed(struct virtnet_ctl * cvq,struct virtio_pmd_ctrl * ctrl,int * dlen,int pkt_num)1474418919fSjohnjiang virtio_send_command_packed(struct virtnet_ctl *cvq,
1484418919fSjohnjiang struct virtio_pmd_ctrl *ctrl,
149a9643ea8Slogwang int *dlen, int pkt_num)
150a9643ea8Slogwang {
1514418919fSjohnjiang struct virtqueue *vq = cvq->vq;
1524418919fSjohnjiang int head;
1534418919fSjohnjiang struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
1542bfe3f2eSlogwang struct virtio_pmd_ctrl *result;
1554418919fSjohnjiang uint16_t flags;
1564418919fSjohnjiang int sum = 0;
1574418919fSjohnjiang int nb_descs = 0;
1584418919fSjohnjiang int k;
159a9643ea8Slogwang
160a9643ea8Slogwang /*
161a9643ea8Slogwang * Format is enforced in qemu code:
162a9643ea8Slogwang * One TX packet for header;
163a9643ea8Slogwang * At least one TX packet per argument;
164a9643ea8Slogwang * One RX packet for ACK.
165a9643ea8Slogwang */
1664418919fSjohnjiang head = vq->vq_avail_idx;
1674418919fSjohnjiang flags = vq->vq_packed.cached_flags;
1684418919fSjohnjiang desc[head].addr = cvq->virtio_net_hdr_mem;
1694418919fSjohnjiang desc[head].len = sizeof(struct virtio_net_ctrl_hdr);
170a9643ea8Slogwang vq->vq_free_cnt--;
1714418919fSjohnjiang nb_descs++;
1724418919fSjohnjiang if (++vq->vq_avail_idx >= vq->vq_nentries) {
1734418919fSjohnjiang vq->vq_avail_idx -= vq->vq_nentries;
1744418919fSjohnjiang vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED;
175a9643ea8Slogwang }
176a9643ea8Slogwang
1774418919fSjohnjiang for (k = 0; k < pkt_num; k++) {
1784418919fSjohnjiang desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem
1794418919fSjohnjiang + sizeof(struct virtio_net_ctrl_hdr)
1804418919fSjohnjiang + sizeof(ctrl->status) + sizeof(uint8_t) * sum;
1814418919fSjohnjiang desc[vq->vq_avail_idx].len = dlen[k];
1824418919fSjohnjiang desc[vq->vq_avail_idx].flags = VRING_DESC_F_NEXT |
1834418919fSjohnjiang vq->vq_packed.cached_flags;
1844418919fSjohnjiang sum += dlen[k];
1854418919fSjohnjiang vq->vq_free_cnt--;
1864418919fSjohnjiang nb_descs++;
1874418919fSjohnjiang if (++vq->vq_avail_idx >= vq->vq_nentries) {
1884418919fSjohnjiang vq->vq_avail_idx -= vq->vq_nentries;
1894418919fSjohnjiang vq->vq_packed.cached_flags ^=
1904418919fSjohnjiang VRING_PACKED_DESC_F_AVAIL_USED;
1914418919fSjohnjiang }
1924418919fSjohnjiang }
1934418919fSjohnjiang
1944418919fSjohnjiang desc[vq->vq_avail_idx].addr = cvq->virtio_net_hdr_mem
195a9643ea8Slogwang + sizeof(struct virtio_net_ctrl_hdr);
1964418919fSjohnjiang desc[vq->vq_avail_idx].len = sizeof(ctrl->status);
1974418919fSjohnjiang desc[vq->vq_avail_idx].flags = VRING_DESC_F_WRITE |
1984418919fSjohnjiang vq->vq_packed.cached_flags;
1994418919fSjohnjiang vq->vq_free_cnt--;
2004418919fSjohnjiang nb_descs++;
2014418919fSjohnjiang if (++vq->vq_avail_idx >= vq->vq_nentries) {
2024418919fSjohnjiang vq->vq_avail_idx -= vq->vq_nentries;
2034418919fSjohnjiang vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED;
2044418919fSjohnjiang }
2054418919fSjohnjiang
2064418919fSjohnjiang virtio_wmb(vq->hw->weak_barriers);
2074418919fSjohnjiang desc[head].flags = VRING_DESC_F_NEXT | flags;
2084418919fSjohnjiang
2094418919fSjohnjiang virtio_wmb(vq->hw->weak_barriers);
2104418919fSjohnjiang virtqueue_notify(vq);
2114418919fSjohnjiang
2124418919fSjohnjiang /* wait for used descriptors in virtqueue */
2134418919fSjohnjiang while (!desc_is_used(&desc[head], vq))
2144418919fSjohnjiang usleep(100);
2154418919fSjohnjiang
2164418919fSjohnjiang virtio_rmb(vq->hw->weak_barriers);
2174418919fSjohnjiang
2184418919fSjohnjiang /* now get used descriptors */
2194418919fSjohnjiang vq->vq_free_cnt += nb_descs;
2204418919fSjohnjiang vq->vq_used_cons_idx += nb_descs;
2214418919fSjohnjiang if (vq->vq_used_cons_idx >= vq->vq_nentries) {
2224418919fSjohnjiang vq->vq_used_cons_idx -= vq->vq_nentries;
2234418919fSjohnjiang vq->vq_packed.used_wrap_counter ^= 1;
2244418919fSjohnjiang }
2254418919fSjohnjiang
2264418919fSjohnjiang PMD_INIT_LOG(DEBUG, "vq->vq_free_cnt=%d\n"
2274418919fSjohnjiang "vq->vq_avail_idx=%d\n"
2284418919fSjohnjiang "vq->vq_used_cons_idx=%d\n"
2294418919fSjohnjiang "vq->vq_packed.cached_flags=0x%x\n"
2304418919fSjohnjiang "vq->vq_packed.used_wrap_counter=%d\n",
2314418919fSjohnjiang vq->vq_free_cnt,
2324418919fSjohnjiang vq->vq_avail_idx,
2334418919fSjohnjiang vq->vq_used_cons_idx,
2344418919fSjohnjiang vq->vq_packed.cached_flags,
2354418919fSjohnjiang vq->vq_packed.used_wrap_counter);
2364418919fSjohnjiang
2374418919fSjohnjiang result = cvq->virtio_net_hdr_mz->addr;
2384418919fSjohnjiang return result;
2394418919fSjohnjiang }
2404418919fSjohnjiang
2414418919fSjohnjiang static struct virtio_pmd_ctrl *
virtio_send_command_split(struct virtnet_ctl * cvq,struct virtio_pmd_ctrl * ctrl,int * dlen,int pkt_num)2424418919fSjohnjiang virtio_send_command_split(struct virtnet_ctl *cvq,
2434418919fSjohnjiang struct virtio_pmd_ctrl *ctrl,
2444418919fSjohnjiang int *dlen, int pkt_num)
2454418919fSjohnjiang {
2464418919fSjohnjiang struct virtio_pmd_ctrl *result;
2474418919fSjohnjiang struct virtqueue *vq = cvq->vq;
2484418919fSjohnjiang uint32_t head, i;
2494418919fSjohnjiang int k, sum = 0;
2504418919fSjohnjiang
2514418919fSjohnjiang head = vq->vq_desc_head_idx;
2524418919fSjohnjiang
2534418919fSjohnjiang /*
2544418919fSjohnjiang * Format is enforced in qemu code:
2554418919fSjohnjiang * One TX packet for header;
2564418919fSjohnjiang * At least one TX packet per argument;
2574418919fSjohnjiang * One RX packet for ACK.
2584418919fSjohnjiang */
2594418919fSjohnjiang vq->vq_split.ring.desc[head].flags = VRING_DESC_F_NEXT;
2604418919fSjohnjiang vq->vq_split.ring.desc[head].addr = cvq->virtio_net_hdr_mem;
2614418919fSjohnjiang vq->vq_split.ring.desc[head].len = sizeof(struct virtio_net_ctrl_hdr);
2624418919fSjohnjiang vq->vq_free_cnt--;
2634418919fSjohnjiang i = vq->vq_split.ring.desc[head].next;
2644418919fSjohnjiang
2654418919fSjohnjiang for (k = 0; k < pkt_num; k++) {
2664418919fSjohnjiang vq->vq_split.ring.desc[i].flags = VRING_DESC_F_NEXT;
2674418919fSjohnjiang vq->vq_split.ring.desc[i].addr = cvq->virtio_net_hdr_mem
2684418919fSjohnjiang + sizeof(struct virtio_net_ctrl_hdr)
2694418919fSjohnjiang + sizeof(ctrl->status) + sizeof(uint8_t)*sum;
2704418919fSjohnjiang vq->vq_split.ring.desc[i].len = dlen[k];
2714418919fSjohnjiang sum += dlen[k];
2724418919fSjohnjiang vq->vq_free_cnt--;
2734418919fSjohnjiang i = vq->vq_split.ring.desc[i].next;
2744418919fSjohnjiang }
2754418919fSjohnjiang
2764418919fSjohnjiang vq->vq_split.ring.desc[i].flags = VRING_DESC_F_WRITE;
2774418919fSjohnjiang vq->vq_split.ring.desc[i].addr = cvq->virtio_net_hdr_mem
2784418919fSjohnjiang + sizeof(struct virtio_net_ctrl_hdr);
2794418919fSjohnjiang vq->vq_split.ring.desc[i].len = sizeof(ctrl->status);
280a9643ea8Slogwang vq->vq_free_cnt--;
281a9643ea8Slogwang
2824418919fSjohnjiang vq->vq_desc_head_idx = vq->vq_split.ring.desc[i].next;
283a9643ea8Slogwang
284a9643ea8Slogwang vq_update_avail_ring(vq, head);
285a9643ea8Slogwang vq_update_avail_idx(vq);
286a9643ea8Slogwang
287a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "vq->vq_queue_index = %d", vq->vq_queue_index);
288a9643ea8Slogwang
289a9643ea8Slogwang virtqueue_notify(vq);
290a9643ea8Slogwang
291*2d9fd380Sjfb8856606 while (virtqueue_nused(vq) == 0)
292a9643ea8Slogwang usleep(100);
293a9643ea8Slogwang
294*2d9fd380Sjfb8856606 while (virtqueue_nused(vq)) {
295a9643ea8Slogwang uint32_t idx, desc_idx, used_idx;
296a9643ea8Slogwang struct vring_used_elem *uep;
297a9643ea8Slogwang
298a9643ea8Slogwang used_idx = (uint32_t)(vq->vq_used_cons_idx
299a9643ea8Slogwang & (vq->vq_nentries - 1));
3004418919fSjohnjiang uep = &vq->vq_split.ring.used->ring[used_idx];
301a9643ea8Slogwang idx = (uint32_t) uep->id;
302a9643ea8Slogwang desc_idx = idx;
303a9643ea8Slogwang
3044418919fSjohnjiang while (vq->vq_split.ring.desc[desc_idx].flags &
3054418919fSjohnjiang VRING_DESC_F_NEXT) {
3064418919fSjohnjiang desc_idx = vq->vq_split.ring.desc[desc_idx].next;
307a9643ea8Slogwang vq->vq_free_cnt++;
308a9643ea8Slogwang }
309a9643ea8Slogwang
3104418919fSjohnjiang vq->vq_split.ring.desc[desc_idx].next = vq->vq_desc_head_idx;
311a9643ea8Slogwang vq->vq_desc_head_idx = idx;
312a9643ea8Slogwang
313a9643ea8Slogwang vq->vq_used_cons_idx++;
314a9643ea8Slogwang vq->vq_free_cnt++;
315a9643ea8Slogwang }
316a9643ea8Slogwang
317a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "vq->vq_free_cnt=%d\nvq->vq_desc_head_idx=%d",
318a9643ea8Slogwang vq->vq_free_cnt, vq->vq_desc_head_idx);
319a9643ea8Slogwang
3202bfe3f2eSlogwang result = cvq->virtio_net_hdr_mz->addr;
3214418919fSjohnjiang return result;
3224418919fSjohnjiang }
3234418919fSjohnjiang
3244418919fSjohnjiang static int
virtio_send_command(struct virtnet_ctl * cvq,struct virtio_pmd_ctrl * ctrl,int * dlen,int pkt_num)3254418919fSjohnjiang virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
3264418919fSjohnjiang int *dlen, int pkt_num)
3274418919fSjohnjiang {
3284418919fSjohnjiang virtio_net_ctrl_ack status = ~0;
3294418919fSjohnjiang struct virtio_pmd_ctrl *result;
3304418919fSjohnjiang struct virtqueue *vq;
3314418919fSjohnjiang
3324418919fSjohnjiang ctrl->status = status;
3334418919fSjohnjiang
3344418919fSjohnjiang if (!cvq || !cvq->vq) {
3354418919fSjohnjiang PMD_INIT_LOG(ERR, "Control queue is not supported.");
3364418919fSjohnjiang return -1;
3374418919fSjohnjiang }
3384418919fSjohnjiang
3394418919fSjohnjiang rte_spinlock_lock(&cvq->lock);
3404418919fSjohnjiang vq = cvq->vq;
3414418919fSjohnjiang
3424418919fSjohnjiang PMD_INIT_LOG(DEBUG, "vq->vq_desc_head_idx = %d, status = %d, "
3434418919fSjohnjiang "vq->hw->cvq = %p vq = %p",
3444418919fSjohnjiang vq->vq_desc_head_idx, status, vq->hw->cvq, vq);
3454418919fSjohnjiang
3464418919fSjohnjiang if (vq->vq_free_cnt < pkt_num + 2 || pkt_num < 1) {
3474418919fSjohnjiang rte_spinlock_unlock(&cvq->lock);
3484418919fSjohnjiang return -1;
3494418919fSjohnjiang }
3504418919fSjohnjiang
3514418919fSjohnjiang memcpy(cvq->virtio_net_hdr_mz->addr, ctrl,
3524418919fSjohnjiang sizeof(struct virtio_pmd_ctrl));
3534418919fSjohnjiang
3544418919fSjohnjiang if (vtpci_packed_queue(vq->hw))
3554418919fSjohnjiang result = virtio_send_command_packed(cvq, ctrl, dlen, pkt_num);
3564418919fSjohnjiang else
3574418919fSjohnjiang result = virtio_send_command_split(cvq, ctrl, dlen, pkt_num);
358a9643ea8Slogwang
359d30ea906Sjfb8856606 rte_spinlock_unlock(&cvq->lock);
3602bfe3f2eSlogwang return result->status;
361a9643ea8Slogwang }
362a9643ea8Slogwang
363a9643ea8Slogwang static int
virtio_set_multiple_queues(struct rte_eth_dev * dev,uint16_t nb_queues)364a9643ea8Slogwang virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)
365a9643ea8Slogwang {
366a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
367a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
368a9643ea8Slogwang int dlen[1];
369a9643ea8Slogwang int ret;
370a9643ea8Slogwang
371a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_MQ;
372a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
373a9643ea8Slogwang memcpy(ctrl.data, &nb_queues, sizeof(uint16_t));
374a9643ea8Slogwang
375a9643ea8Slogwang dlen[0] = sizeof(uint16_t);
376a9643ea8Slogwang
377a9643ea8Slogwang ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);
378a9643ea8Slogwang if (ret) {
379a9643ea8Slogwang PMD_INIT_LOG(ERR, "Multiqueue configured but send command "
380a9643ea8Slogwang "failed, this is too late now...");
381a9643ea8Slogwang return -EINVAL;
382a9643ea8Slogwang }
383a9643ea8Slogwang
384a9643ea8Slogwang return 0;
385a9643ea8Slogwang }
386a9643ea8Slogwang
3872bfe3f2eSlogwang static void
virtio_dev_queue_release(void * queue __rte_unused)3882bfe3f2eSlogwang virtio_dev_queue_release(void *queue __rte_unused)
389a9643ea8Slogwang {
3902bfe3f2eSlogwang /* do nothing */
391a9643ea8Slogwang }
392a9643ea8Slogwang
3932bfe3f2eSlogwang static uint16_t
virtio_get_nr_vq(struct virtio_hw * hw)3942bfe3f2eSlogwang virtio_get_nr_vq(struct virtio_hw *hw)
3952bfe3f2eSlogwang {
3962bfe3f2eSlogwang uint16_t nr_vq = hw->max_queue_pairs * 2;
3972bfe3f2eSlogwang
3982bfe3f2eSlogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ))
3992bfe3f2eSlogwang nr_vq += 1;
4002bfe3f2eSlogwang
4012bfe3f2eSlogwang return nr_vq;
4022bfe3f2eSlogwang }
4032bfe3f2eSlogwang
4042bfe3f2eSlogwang static void
virtio_init_vring(struct virtqueue * vq)4052bfe3f2eSlogwang virtio_init_vring(struct virtqueue *vq)
4062bfe3f2eSlogwang {
4072bfe3f2eSlogwang int size = vq->vq_nentries;
4082bfe3f2eSlogwang uint8_t *ring_mem = vq->vq_ring_virt_mem;
4092bfe3f2eSlogwang
4102bfe3f2eSlogwang PMD_INIT_FUNC_TRACE();
4112bfe3f2eSlogwang
4122bfe3f2eSlogwang memset(ring_mem, 0, vq->vq_ring_size);
4134418919fSjohnjiang
4142bfe3f2eSlogwang vq->vq_used_cons_idx = 0;
4152bfe3f2eSlogwang vq->vq_desc_head_idx = 0;
4162bfe3f2eSlogwang vq->vq_avail_idx = 0;
4172bfe3f2eSlogwang vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
4182bfe3f2eSlogwang vq->vq_free_cnt = vq->vq_nentries;
4192bfe3f2eSlogwang memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
4204418919fSjohnjiang if (vtpci_packed_queue(vq->hw)) {
4214418919fSjohnjiang vring_init_packed(&vq->vq_packed.ring, ring_mem,
4224418919fSjohnjiang VIRTIO_PCI_VRING_ALIGN, size);
4234418919fSjohnjiang vring_desc_init_packed(vq, size);
4244418919fSjohnjiang } else {
4254418919fSjohnjiang struct vring *vr = &vq->vq_split.ring;
4262bfe3f2eSlogwang
4274418919fSjohnjiang vring_init_split(vr, ring_mem, VIRTIO_PCI_VRING_ALIGN, size);
4284418919fSjohnjiang vring_desc_init_split(vr->desc, size);
4294418919fSjohnjiang }
4302bfe3f2eSlogwang /*
4312bfe3f2eSlogwang * Disable device(host) interrupting guest
4322bfe3f2eSlogwang */
4332bfe3f2eSlogwang virtqueue_disable_intr(vq);
4342bfe3f2eSlogwang }
4352bfe3f2eSlogwang
4362bfe3f2eSlogwang static int
virtio_init_queue(struct rte_eth_dev * dev,uint16_t vtpci_queue_idx)4372bfe3f2eSlogwang virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
438a9643ea8Slogwang {
439a9643ea8Slogwang char vq_name[VIRTQUEUE_MAX_NAME_SZ];
440a9643ea8Slogwang char vq_hdr_name[VIRTQUEUE_MAX_NAME_SZ];
441a9643ea8Slogwang const struct rte_memzone *mz = NULL, *hdr_mz = NULL;
442a9643ea8Slogwang unsigned int vq_size, size;
443a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
444a9643ea8Slogwang struct virtnet_rx *rxvq = NULL;
445a9643ea8Slogwang struct virtnet_tx *txvq = NULL;
446a9643ea8Slogwang struct virtnet_ctl *cvq = NULL;
447a9643ea8Slogwang struct virtqueue *vq;
4482bfe3f2eSlogwang size_t sz_hdr_mz = 0;
449a9643ea8Slogwang void *sw_ring = NULL;
4502bfe3f2eSlogwang int queue_type = virtio_get_queue_type(hw, vtpci_queue_idx);
451a9643ea8Slogwang int ret;
4524418919fSjohnjiang int numa_node = dev->device->numa_node;
453a9643ea8Slogwang
4544418919fSjohnjiang PMD_INIT_LOG(INFO, "setting up queue: %u on NUMA node %d",
4554418919fSjohnjiang vtpci_queue_idx, numa_node);
456a9643ea8Slogwang
457a9643ea8Slogwang /*
458a9643ea8Slogwang * Read the virtqueue size from the Queue Size field
459a9643ea8Slogwang * Always power of 2 and if 0 virtqueue does not exist
460a9643ea8Slogwang */
4612bfe3f2eSlogwang vq_size = VTPCI_OPS(hw)->get_queue_num(hw, vtpci_queue_idx);
4622bfe3f2eSlogwang PMD_INIT_LOG(DEBUG, "vq_size: %u", vq_size);
463a9643ea8Slogwang if (vq_size == 0) {
464a9643ea8Slogwang PMD_INIT_LOG(ERR, "virtqueue does not exist");
465a9643ea8Slogwang return -EINVAL;
466a9643ea8Slogwang }
467a9643ea8Slogwang
4684418919fSjohnjiang if (!vtpci_packed_queue(hw) && !rte_is_power_of_2(vq_size)) {
4694418919fSjohnjiang PMD_INIT_LOG(ERR, "split virtqueue size is not power of 2");
470a9643ea8Slogwang return -EINVAL;
471a9643ea8Slogwang }
472a9643ea8Slogwang
4732bfe3f2eSlogwang snprintf(vq_name, sizeof(vq_name), "port%d_vq%d",
4742bfe3f2eSlogwang dev->data->port_id, vtpci_queue_idx);
475a9643ea8Slogwang
4762bfe3f2eSlogwang size = RTE_ALIGN_CEIL(sizeof(*vq) +
477a9643ea8Slogwang vq_size * sizeof(struct vq_desc_extra),
478a9643ea8Slogwang RTE_CACHE_LINE_SIZE);
4792bfe3f2eSlogwang if (queue_type == VTNET_TQ) {
480a9643ea8Slogwang /*
481a9643ea8Slogwang * For each xmit packet, allocate a virtio_net_hdr
482a9643ea8Slogwang * and indirect ring elements
483a9643ea8Slogwang */
484a9643ea8Slogwang sz_hdr_mz = vq_size * sizeof(struct virtio_tx_region);
485a9643ea8Slogwang } else if (queue_type == VTNET_CQ) {
486a9643ea8Slogwang /* Allocate a page for control vq command, data and status */
487a9643ea8Slogwang sz_hdr_mz = PAGE_SIZE;
488a9643ea8Slogwang }
489a9643ea8Slogwang
4902bfe3f2eSlogwang vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE,
4914418919fSjohnjiang numa_node);
492a9643ea8Slogwang if (vq == NULL) {
493a9643ea8Slogwang PMD_INIT_LOG(ERR, "can not allocate vq");
494a9643ea8Slogwang return -ENOMEM;
495a9643ea8Slogwang }
4962bfe3f2eSlogwang hw->vqs[vtpci_queue_idx] = vq;
4972bfe3f2eSlogwang
498a9643ea8Slogwang vq->hw = hw;
499a9643ea8Slogwang vq->vq_queue_index = vtpci_queue_idx;
500a9643ea8Slogwang vq->vq_nentries = vq_size;
5014418919fSjohnjiang if (vtpci_packed_queue(hw)) {
5024418919fSjohnjiang vq->vq_packed.used_wrap_counter = 1;
5034418919fSjohnjiang vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
5044418919fSjohnjiang vq->vq_packed.event_flags_shadow = 0;
5054418919fSjohnjiang if (queue_type == VTNET_RQ)
5064418919fSjohnjiang vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
5074418919fSjohnjiang }
508a9643ea8Slogwang
509a9643ea8Slogwang /*
510a9643ea8Slogwang * Reserve a memzone for vring elements
511a9643ea8Slogwang */
5124418919fSjohnjiang size = vring_size(hw, vq_size, VIRTIO_PCI_VRING_ALIGN);
513a9643ea8Slogwang vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN);
514a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d",
515a9643ea8Slogwang size, vq->vq_ring_size);
516a9643ea8Slogwang
5172bfe3f2eSlogwang mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
5184418919fSjohnjiang numa_node, RTE_MEMZONE_IOVA_CONTIG,
519d30ea906Sjfb8856606 VIRTIO_PCI_VRING_ALIGN);
520a9643ea8Slogwang if (mz == NULL) {
521a9643ea8Slogwang if (rte_errno == EEXIST)
522a9643ea8Slogwang mz = rte_memzone_lookup(vq_name);
523a9643ea8Slogwang if (mz == NULL) {
524a9643ea8Slogwang ret = -ENOMEM;
525a9643ea8Slogwang goto fail_q_alloc;
526a9643ea8Slogwang }
527a9643ea8Slogwang }
528a9643ea8Slogwang
5292bfe3f2eSlogwang memset(mz->addr, 0, mz->len);
530a9643ea8Slogwang
5312bfe3f2eSlogwang vq->vq_ring_mem = mz->iova;
532a9643ea8Slogwang vq->vq_ring_virt_mem = mz->addr;
533a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64,
5342bfe3f2eSlogwang (uint64_t)mz->iova);
535a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: 0x%" PRIx64,
536a9643ea8Slogwang (uint64_t)(uintptr_t)mz->addr);
537a9643ea8Slogwang
5382bfe3f2eSlogwang virtio_init_vring(vq);
5392bfe3f2eSlogwang
540a9643ea8Slogwang if (sz_hdr_mz) {
5412bfe3f2eSlogwang snprintf(vq_hdr_name, sizeof(vq_hdr_name), "port%d_vq%d_hdr",
5422bfe3f2eSlogwang dev->data->port_id, vtpci_queue_idx);
543a9643ea8Slogwang hdr_mz = rte_memzone_reserve_aligned(vq_hdr_name, sz_hdr_mz,
5444418919fSjohnjiang numa_node, RTE_MEMZONE_IOVA_CONTIG,
545a9643ea8Slogwang RTE_CACHE_LINE_SIZE);
546a9643ea8Slogwang if (hdr_mz == NULL) {
547a9643ea8Slogwang if (rte_errno == EEXIST)
548a9643ea8Slogwang hdr_mz = rte_memzone_lookup(vq_hdr_name);
549a9643ea8Slogwang if (hdr_mz == NULL) {
550a9643ea8Slogwang ret = -ENOMEM;
551a9643ea8Slogwang goto fail_q_alloc;
552a9643ea8Slogwang }
553a9643ea8Slogwang }
554a9643ea8Slogwang }
555a9643ea8Slogwang
556a9643ea8Slogwang if (queue_type == VTNET_RQ) {
557a9643ea8Slogwang size_t sz_sw = (RTE_PMD_VIRTIO_RX_MAX_BURST + vq_size) *
558a9643ea8Slogwang sizeof(vq->sw_ring[0]);
559a9643ea8Slogwang
560a9643ea8Slogwang sw_ring = rte_zmalloc_socket("sw_ring", sz_sw,
5614418919fSjohnjiang RTE_CACHE_LINE_SIZE, numa_node);
562a9643ea8Slogwang if (!sw_ring) {
563a9643ea8Slogwang PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
564a9643ea8Slogwang ret = -ENOMEM;
565a9643ea8Slogwang goto fail_q_alloc;
566a9643ea8Slogwang }
567a9643ea8Slogwang
568a9643ea8Slogwang vq->sw_ring = sw_ring;
5692bfe3f2eSlogwang rxvq = &vq->rxq;
570a9643ea8Slogwang rxvq->vq = vq;
571a9643ea8Slogwang rxvq->port_id = dev->data->port_id;
572a9643ea8Slogwang rxvq->mz = mz;
573a9643ea8Slogwang } else if (queue_type == VTNET_TQ) {
5742bfe3f2eSlogwang txvq = &vq->txq;
575a9643ea8Slogwang txvq->vq = vq;
576a9643ea8Slogwang txvq->port_id = dev->data->port_id;
577a9643ea8Slogwang txvq->mz = mz;
578a9643ea8Slogwang txvq->virtio_net_hdr_mz = hdr_mz;
5792bfe3f2eSlogwang txvq->virtio_net_hdr_mem = hdr_mz->iova;
580a9643ea8Slogwang } else if (queue_type == VTNET_CQ) {
5812bfe3f2eSlogwang cvq = &vq->cq;
582a9643ea8Slogwang cvq->vq = vq;
583a9643ea8Slogwang cvq->mz = mz;
584a9643ea8Slogwang cvq->virtio_net_hdr_mz = hdr_mz;
5852bfe3f2eSlogwang cvq->virtio_net_hdr_mem = hdr_mz->iova;
586a9643ea8Slogwang memset(cvq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
5872bfe3f2eSlogwang
5882bfe3f2eSlogwang hw->cvq = cvq;
589a9643ea8Slogwang }
590a9643ea8Slogwang
5910c6bd470Sfengbojiang /* For virtio_user case (that is when hw->virtio_user_dev is not NULL),
5920c6bd470Sfengbojiang * we use virtual address. And we need properly set _offset_, please see
593a9643ea8Slogwang * VIRTIO_MBUF_DATA_DMA_ADDR in virtqueue.h for more information.
594a9643ea8Slogwang */
5952bfe3f2eSlogwang if (!hw->virtio_user_dev)
5962bfe3f2eSlogwang vq->offset = offsetof(struct rte_mbuf, buf_iova);
597a9643ea8Slogwang else {
598a9643ea8Slogwang vq->vq_ring_mem = (uintptr_t)mz->addr;
599a9643ea8Slogwang vq->offset = offsetof(struct rte_mbuf, buf_addr);
600a9643ea8Slogwang if (queue_type == VTNET_TQ)
601a9643ea8Slogwang txvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr;
602a9643ea8Slogwang else if (queue_type == VTNET_CQ)
603a9643ea8Slogwang cvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr;
604a9643ea8Slogwang }
605a9643ea8Slogwang
606a9643ea8Slogwang if (queue_type == VTNET_TQ) {
607a9643ea8Slogwang struct virtio_tx_region *txr;
608a9643ea8Slogwang unsigned int i;
609a9643ea8Slogwang
610a9643ea8Slogwang txr = hdr_mz->addr;
611a9643ea8Slogwang memset(txr, 0, vq_size * sizeof(*txr));
612a9643ea8Slogwang for (i = 0; i < vq_size; i++) {
613a9643ea8Slogwang /* first indirect descriptor is always the tx header */
6144418919fSjohnjiang if (!vtpci_packed_queue(hw)) {
6150c6bd470Sfengbojiang struct vring_desc *start_dp = txr[i].tx_indir;
6164418919fSjohnjiang vring_desc_init_split(start_dp,
6174418919fSjohnjiang RTE_DIM(txr[i].tx_indir));
618a9643ea8Slogwang start_dp->addr = txvq->virtio_net_hdr_mem
619a9643ea8Slogwang + i * sizeof(*txr)
6204418919fSjohnjiang + offsetof(struct virtio_tx_region,
6214418919fSjohnjiang tx_hdr);
622a9643ea8Slogwang start_dp->len = hw->vtnet_hdr_size;
623a9643ea8Slogwang start_dp->flags = VRING_DESC_F_NEXT;
6240c6bd470Sfengbojiang } else {
6250c6bd470Sfengbojiang struct vring_packed_desc *start_dp =
6260c6bd470Sfengbojiang txr[i].tx_packed_indir;
6270c6bd470Sfengbojiang vring_desc_init_indirect_packed(start_dp,
6280c6bd470Sfengbojiang RTE_DIM(txr[i].tx_packed_indir));
6290c6bd470Sfengbojiang start_dp->addr = txvq->virtio_net_hdr_mem
6300c6bd470Sfengbojiang + i * sizeof(*txr)
6310c6bd470Sfengbojiang + offsetof(struct virtio_tx_region,
6320c6bd470Sfengbojiang tx_hdr);
6330c6bd470Sfengbojiang start_dp->len = hw->vtnet_hdr_size;
634a9643ea8Slogwang }
635a9643ea8Slogwang }
6364418919fSjohnjiang }
637a9643ea8Slogwang
6382bfe3f2eSlogwang if (VTPCI_OPS(hw)->setup_queue(hw, vq) < 0) {
639a9643ea8Slogwang PMD_INIT_LOG(ERR, "setup_queue failed");
640a9643ea8Slogwang return -EINVAL;
641a9643ea8Slogwang }
642a9643ea8Slogwang
643a9643ea8Slogwang return 0;
644a9643ea8Slogwang
645a9643ea8Slogwang fail_q_alloc:
646a9643ea8Slogwang rte_free(sw_ring);
647a9643ea8Slogwang rte_memzone_free(hdr_mz);
648a9643ea8Slogwang rte_memzone_free(mz);
649a9643ea8Slogwang rte_free(vq);
650a9643ea8Slogwang
651a9643ea8Slogwang return ret;
652a9643ea8Slogwang }
653a9643ea8Slogwang
6542bfe3f2eSlogwang static void
virtio_free_queues(struct virtio_hw * hw)6552bfe3f2eSlogwang virtio_free_queues(struct virtio_hw *hw)
656a9643ea8Slogwang {
6572bfe3f2eSlogwang uint16_t nr_vq = virtio_get_nr_vq(hw);
6582bfe3f2eSlogwang struct virtqueue *vq;
6592bfe3f2eSlogwang int queue_type;
6602bfe3f2eSlogwang uint16_t i;
661a9643ea8Slogwang
6622bfe3f2eSlogwang if (hw->vqs == NULL)
6632bfe3f2eSlogwang return;
6642bfe3f2eSlogwang
6652bfe3f2eSlogwang for (i = 0; i < nr_vq; i++) {
6662bfe3f2eSlogwang vq = hw->vqs[i];
6672bfe3f2eSlogwang if (!vq)
6682bfe3f2eSlogwang continue;
6692bfe3f2eSlogwang
6702bfe3f2eSlogwang queue_type = virtio_get_queue_type(hw, i);
6712bfe3f2eSlogwang if (queue_type == VTNET_RQ) {
6722bfe3f2eSlogwang rte_free(vq->sw_ring);
6732bfe3f2eSlogwang rte_memzone_free(vq->rxq.mz);
6742bfe3f2eSlogwang } else if (queue_type == VTNET_TQ) {
6752bfe3f2eSlogwang rte_memzone_free(vq->txq.mz);
6762bfe3f2eSlogwang rte_memzone_free(vq->txq.virtio_net_hdr_mz);
6772bfe3f2eSlogwang } else {
6782bfe3f2eSlogwang rte_memzone_free(vq->cq.mz);
6792bfe3f2eSlogwang rte_memzone_free(vq->cq.virtio_net_hdr_mz);
680a9643ea8Slogwang }
681a9643ea8Slogwang
6822bfe3f2eSlogwang rte_free(vq);
6832bfe3f2eSlogwang hw->vqs[i] = NULL;
6842bfe3f2eSlogwang }
6852bfe3f2eSlogwang
6862bfe3f2eSlogwang rte_free(hw->vqs);
6872bfe3f2eSlogwang hw->vqs = NULL;
6882bfe3f2eSlogwang }
6892bfe3f2eSlogwang
6902bfe3f2eSlogwang static int
virtio_alloc_queues(struct rte_eth_dev * dev)6912bfe3f2eSlogwang virtio_alloc_queues(struct rte_eth_dev *dev)
6922bfe3f2eSlogwang {
6932bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
6942bfe3f2eSlogwang uint16_t nr_vq = virtio_get_nr_vq(hw);
6952bfe3f2eSlogwang uint16_t i;
6962bfe3f2eSlogwang int ret;
6972bfe3f2eSlogwang
6982bfe3f2eSlogwang hw->vqs = rte_zmalloc(NULL, sizeof(struct virtqueue *) * nr_vq, 0);
6992bfe3f2eSlogwang if (!hw->vqs) {
7002bfe3f2eSlogwang PMD_INIT_LOG(ERR, "failed to allocate vqs");
7012bfe3f2eSlogwang return -ENOMEM;
7022bfe3f2eSlogwang }
7032bfe3f2eSlogwang
7042bfe3f2eSlogwang for (i = 0; i < nr_vq; i++) {
7052bfe3f2eSlogwang ret = virtio_init_queue(dev, i);
7062bfe3f2eSlogwang if (ret < 0) {
7072bfe3f2eSlogwang virtio_free_queues(hw);
7082bfe3f2eSlogwang return ret;
7092bfe3f2eSlogwang }
7102bfe3f2eSlogwang }
7112bfe3f2eSlogwang
712a9643ea8Slogwang return 0;
713a9643ea8Slogwang }
714a9643ea8Slogwang
7152bfe3f2eSlogwang static void virtio_queues_unbind_intr(struct rte_eth_dev *dev);
716a9643ea8Slogwang
717*2d9fd380Sjfb8856606 static int
virtio_dev_close(struct rte_eth_dev * dev)718a9643ea8Slogwang virtio_dev_close(struct rte_eth_dev *dev)
719a9643ea8Slogwang {
720a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
7212bfe3f2eSlogwang struct rte_intr_conf *intr_conf = &dev->data->dev_conf.intr_conf;
722a9643ea8Slogwang
723a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "virtio_dev_close");
724*2d9fd380Sjfb8856606 if (rte_eal_process_type() != RTE_PROC_PRIMARY)
725*2d9fd380Sjfb8856606 return 0;
726a9643ea8Slogwang
727d30ea906Sjfb8856606 if (!hw->opened)
728*2d9fd380Sjfb8856606 return 0;
729d30ea906Sjfb8856606 hw->opened = false;
730d30ea906Sjfb8856606
731a9643ea8Slogwang /* reset the NIC */
732a9643ea8Slogwang if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
7332bfe3f2eSlogwang VTPCI_OPS(hw)->set_config_irq(hw, VIRTIO_MSI_NO_VECTOR);
7342bfe3f2eSlogwang if (intr_conf->rxq)
7352bfe3f2eSlogwang virtio_queues_unbind_intr(dev);
7362bfe3f2eSlogwang
7372bfe3f2eSlogwang if (intr_conf->lsc || intr_conf->rxq) {
7382bfe3f2eSlogwang virtio_intr_disable(dev);
7392bfe3f2eSlogwang rte_intr_efd_disable(dev->intr_handle);
7402bfe3f2eSlogwang rte_free(dev->intr_handle->intr_vec);
7412bfe3f2eSlogwang dev->intr_handle->intr_vec = NULL;
7422bfe3f2eSlogwang }
7432bfe3f2eSlogwang
744a9643ea8Slogwang vtpci_reset(hw);
745a9643ea8Slogwang virtio_dev_free_mbufs(dev);
7462bfe3f2eSlogwang virtio_free_queues(hw);
7474418919fSjohnjiang
7484418919fSjohnjiang #ifdef RTE_VIRTIO_USER
7494418919fSjohnjiang if (hw->virtio_user_dev)
7504418919fSjohnjiang virtio_user_dev_uninit(hw->virtio_user_dev);
7514418919fSjohnjiang else
7524418919fSjohnjiang #endif
7534418919fSjohnjiang if (dev->device) {
7544418919fSjohnjiang rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(dev));
7554418919fSjohnjiang if (!hw->modern)
7564418919fSjohnjiang rte_pci_ioport_unmap(VTPCI_IO(hw));
7574418919fSjohnjiang }
758*2d9fd380Sjfb8856606
759*2d9fd380Sjfb8856606 return 0;
760a9643ea8Slogwang }
761a9643ea8Slogwang
7624418919fSjohnjiang static int
virtio_dev_promiscuous_enable(struct rte_eth_dev * dev)763a9643ea8Slogwang virtio_dev_promiscuous_enable(struct rte_eth_dev *dev)
764a9643ea8Slogwang {
765a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
766a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
767a9643ea8Slogwang int dlen[1];
768a9643ea8Slogwang int ret;
769a9643ea8Slogwang
770a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) {
7712bfe3f2eSlogwang PMD_INIT_LOG(INFO, "host does not support rx control");
7724418919fSjohnjiang return -ENOTSUP;
773a9643ea8Slogwang }
774a9643ea8Slogwang
775a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_RX;
776a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC;
777a9643ea8Slogwang ctrl.data[0] = 1;
778a9643ea8Slogwang dlen[0] = 1;
779a9643ea8Slogwang
780a9643ea8Slogwang ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);
7814418919fSjohnjiang if (ret) {
782a9643ea8Slogwang PMD_INIT_LOG(ERR, "Failed to enable promisc");
7834418919fSjohnjiang return -EAGAIN;
784a9643ea8Slogwang }
785a9643ea8Slogwang
7864418919fSjohnjiang return 0;
7874418919fSjohnjiang }
7884418919fSjohnjiang
7894418919fSjohnjiang static int
virtio_dev_promiscuous_disable(struct rte_eth_dev * dev)790a9643ea8Slogwang virtio_dev_promiscuous_disable(struct rte_eth_dev *dev)
791a9643ea8Slogwang {
792a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
793a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
794a9643ea8Slogwang int dlen[1];
795a9643ea8Slogwang int ret;
796a9643ea8Slogwang
797a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) {
7982bfe3f2eSlogwang PMD_INIT_LOG(INFO, "host does not support rx control");
7994418919fSjohnjiang return -ENOTSUP;
800a9643ea8Slogwang }
801a9643ea8Slogwang
802a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_RX;
803a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_PROMISC;
804a9643ea8Slogwang ctrl.data[0] = 0;
805a9643ea8Slogwang dlen[0] = 1;
806a9643ea8Slogwang
807a9643ea8Slogwang ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);
8084418919fSjohnjiang if (ret) {
809a9643ea8Slogwang PMD_INIT_LOG(ERR, "Failed to disable promisc");
8104418919fSjohnjiang return -EAGAIN;
811a9643ea8Slogwang }
812a9643ea8Slogwang
8134418919fSjohnjiang return 0;
8144418919fSjohnjiang }
8154418919fSjohnjiang
8164418919fSjohnjiang static int
virtio_dev_allmulticast_enable(struct rte_eth_dev * dev)817a9643ea8Slogwang virtio_dev_allmulticast_enable(struct rte_eth_dev *dev)
818a9643ea8Slogwang {
819a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
820a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
821a9643ea8Slogwang int dlen[1];
822a9643ea8Slogwang int ret;
823a9643ea8Slogwang
824a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) {
8252bfe3f2eSlogwang PMD_INIT_LOG(INFO, "host does not support rx control");
8264418919fSjohnjiang return -ENOTSUP;
827a9643ea8Slogwang }
828a9643ea8Slogwang
829a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_RX;
830a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI;
831a9643ea8Slogwang ctrl.data[0] = 1;
832a9643ea8Slogwang dlen[0] = 1;
833a9643ea8Slogwang
834a9643ea8Slogwang ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);
8354418919fSjohnjiang if (ret) {
836a9643ea8Slogwang PMD_INIT_LOG(ERR, "Failed to enable allmulticast");
8374418919fSjohnjiang return -EAGAIN;
838a9643ea8Slogwang }
839a9643ea8Slogwang
8404418919fSjohnjiang return 0;
8414418919fSjohnjiang }
8424418919fSjohnjiang
8434418919fSjohnjiang static int
virtio_dev_allmulticast_disable(struct rte_eth_dev * dev)844a9643ea8Slogwang virtio_dev_allmulticast_disable(struct rte_eth_dev *dev)
845a9643ea8Slogwang {
846a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
847a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
848a9643ea8Slogwang int dlen[1];
849a9643ea8Slogwang int ret;
850a9643ea8Slogwang
851a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX)) {
8522bfe3f2eSlogwang PMD_INIT_LOG(INFO, "host does not support rx control");
8534418919fSjohnjiang return -ENOTSUP;
854a9643ea8Slogwang }
855a9643ea8Slogwang
856a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_RX;
857a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_RX_ALLMULTI;
858a9643ea8Slogwang ctrl.data[0] = 0;
859a9643ea8Slogwang dlen[0] = 1;
860a9643ea8Slogwang
861a9643ea8Slogwang ret = virtio_send_command(hw->cvq, &ctrl, dlen, 1);
8624418919fSjohnjiang if (ret) {
863a9643ea8Slogwang PMD_INIT_LOG(ERR, "Failed to disable allmulticast");
8644418919fSjohnjiang return -EAGAIN;
8654418919fSjohnjiang }
8664418919fSjohnjiang
8674418919fSjohnjiang return 0;
868a9643ea8Slogwang }
869a9643ea8Slogwang
8702bfe3f2eSlogwang #define VLAN_TAG_LEN 4 /* 802.3ac tag (not DMA'd) */
8712bfe3f2eSlogwang static int
virtio_mtu_set(struct rte_eth_dev * dev,uint16_t mtu)8722bfe3f2eSlogwang virtio_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
8732bfe3f2eSlogwang {
8742bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
8754418919fSjohnjiang uint32_t ether_hdr_len = RTE_ETHER_HDR_LEN + VLAN_TAG_LEN +
8762bfe3f2eSlogwang hw->vtnet_hdr_size;
8772bfe3f2eSlogwang uint32_t frame_size = mtu + ether_hdr_len;
8782bfe3f2eSlogwang uint32_t max_frame_size = hw->max_mtu + ether_hdr_len;
8792bfe3f2eSlogwang
8802bfe3f2eSlogwang max_frame_size = RTE_MIN(max_frame_size, VIRTIO_MAX_RX_PKTLEN);
8812bfe3f2eSlogwang
8824418919fSjohnjiang if (mtu < RTE_ETHER_MIN_MTU || frame_size > max_frame_size) {
8832bfe3f2eSlogwang PMD_INIT_LOG(ERR, "MTU should be between %d and %d",
8844418919fSjohnjiang RTE_ETHER_MIN_MTU, max_frame_size - ether_hdr_len);
8852bfe3f2eSlogwang return -EINVAL;
8862bfe3f2eSlogwang }
8872bfe3f2eSlogwang return 0;
8882bfe3f2eSlogwang }
8892bfe3f2eSlogwang
8902bfe3f2eSlogwang static int
virtio_dev_rx_queue_intr_enable(struct rte_eth_dev * dev,uint16_t queue_id)8912bfe3f2eSlogwang virtio_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
8922bfe3f2eSlogwang {
8934418919fSjohnjiang struct virtio_hw *hw = dev->data->dev_private;
8942bfe3f2eSlogwang struct virtnet_rx *rxvq = dev->data->rx_queues[queue_id];
8952bfe3f2eSlogwang struct virtqueue *vq = rxvq->vq;
8962bfe3f2eSlogwang
8972bfe3f2eSlogwang virtqueue_enable_intr(vq);
8984418919fSjohnjiang virtio_mb(hw->weak_barriers);
8992bfe3f2eSlogwang return 0;
9002bfe3f2eSlogwang }
9012bfe3f2eSlogwang
9022bfe3f2eSlogwang static int
virtio_dev_rx_queue_intr_disable(struct rte_eth_dev * dev,uint16_t queue_id)9032bfe3f2eSlogwang virtio_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
9042bfe3f2eSlogwang {
9052bfe3f2eSlogwang struct virtnet_rx *rxvq = dev->data->rx_queues[queue_id];
9062bfe3f2eSlogwang struct virtqueue *vq = rxvq->vq;
9072bfe3f2eSlogwang
9082bfe3f2eSlogwang virtqueue_disable_intr(vq);
9092bfe3f2eSlogwang return 0;
9102bfe3f2eSlogwang }
9112bfe3f2eSlogwang
912a9643ea8Slogwang /*
913a9643ea8Slogwang * dev_ops for virtio, bare necessities for basic operation
914a9643ea8Slogwang */
915a9643ea8Slogwang static const struct eth_dev_ops virtio_eth_dev_ops = {
916a9643ea8Slogwang .dev_configure = virtio_dev_configure,
917a9643ea8Slogwang .dev_start = virtio_dev_start,
918a9643ea8Slogwang .dev_stop = virtio_dev_stop,
919a9643ea8Slogwang .dev_close = virtio_dev_close,
920a9643ea8Slogwang .promiscuous_enable = virtio_dev_promiscuous_enable,
921a9643ea8Slogwang .promiscuous_disable = virtio_dev_promiscuous_disable,
922a9643ea8Slogwang .allmulticast_enable = virtio_dev_allmulticast_enable,
923a9643ea8Slogwang .allmulticast_disable = virtio_dev_allmulticast_disable,
9242bfe3f2eSlogwang .mtu_set = virtio_mtu_set,
925a9643ea8Slogwang .dev_infos_get = virtio_dev_info_get,
926a9643ea8Slogwang .stats_get = virtio_dev_stats_get,
927a9643ea8Slogwang .xstats_get = virtio_dev_xstats_get,
928a9643ea8Slogwang .xstats_get_names = virtio_dev_xstats_get_names,
929a9643ea8Slogwang .stats_reset = virtio_dev_stats_reset,
930a9643ea8Slogwang .xstats_reset = virtio_dev_stats_reset,
931a9643ea8Slogwang .link_update = virtio_dev_link_update,
9322bfe3f2eSlogwang .vlan_offload_set = virtio_dev_vlan_offload_set,
933a9643ea8Slogwang .rx_queue_setup = virtio_dev_rx_queue_setup,
9342bfe3f2eSlogwang .rx_queue_intr_enable = virtio_dev_rx_queue_intr_enable,
9352bfe3f2eSlogwang .rx_queue_intr_disable = virtio_dev_rx_queue_intr_disable,
9362bfe3f2eSlogwang .rx_queue_release = virtio_dev_queue_release,
937a9643ea8Slogwang .tx_queue_setup = virtio_dev_tx_queue_setup,
9382bfe3f2eSlogwang .tx_queue_release = virtio_dev_queue_release,
939a9643ea8Slogwang /* collect stats per queue */
940a9643ea8Slogwang .queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set,
941a9643ea8Slogwang .vlan_filter_set = virtio_vlan_filter_set,
942a9643ea8Slogwang .mac_addr_add = virtio_mac_addr_add,
943a9643ea8Slogwang .mac_addr_remove = virtio_mac_addr_remove,
944a9643ea8Slogwang .mac_addr_set = virtio_mac_addr_set,
945a9643ea8Slogwang };
946a9643ea8Slogwang
9471646932aSjfb8856606 /*
9481646932aSjfb8856606 * dev_ops for virtio-user in secondary processes, as we just have
9491646932aSjfb8856606 * some limited supports currently.
9501646932aSjfb8856606 */
9511646932aSjfb8856606 const struct eth_dev_ops virtio_user_secondary_eth_dev_ops = {
9521646932aSjfb8856606 .dev_infos_get = virtio_dev_info_get,
9531646932aSjfb8856606 .stats_get = virtio_dev_stats_get,
9541646932aSjfb8856606 .xstats_get = virtio_dev_xstats_get,
9551646932aSjfb8856606 .xstats_get_names = virtio_dev_xstats_get_names,
9561646932aSjfb8856606 .stats_reset = virtio_dev_stats_reset,
9571646932aSjfb8856606 .xstats_reset = virtio_dev_stats_reset,
9581646932aSjfb8856606 /* collect stats per queue */
9591646932aSjfb8856606 .queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set,
9601646932aSjfb8856606 };
9611646932aSjfb8856606
962a9643ea8Slogwang static void
virtio_update_stats(struct rte_eth_dev * dev,struct rte_eth_stats * stats)963a9643ea8Slogwang virtio_update_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
964a9643ea8Slogwang {
965a9643ea8Slogwang unsigned i;
966a9643ea8Slogwang
967a9643ea8Slogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
968a9643ea8Slogwang const struct virtnet_tx *txvq = dev->data->tx_queues[i];
969a9643ea8Slogwang if (txvq == NULL)
970a9643ea8Slogwang continue;
971a9643ea8Slogwang
972a9643ea8Slogwang stats->opackets += txvq->stats.packets;
973a9643ea8Slogwang stats->obytes += txvq->stats.bytes;
974a9643ea8Slogwang
975a9643ea8Slogwang if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
976a9643ea8Slogwang stats->q_opackets[i] = txvq->stats.packets;
977a9643ea8Slogwang stats->q_obytes[i] = txvq->stats.bytes;
978a9643ea8Slogwang }
979a9643ea8Slogwang }
980a9643ea8Slogwang
981a9643ea8Slogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
982a9643ea8Slogwang const struct virtnet_rx *rxvq = dev->data->rx_queues[i];
983a9643ea8Slogwang if (rxvq == NULL)
984a9643ea8Slogwang continue;
985a9643ea8Slogwang
986a9643ea8Slogwang stats->ipackets += rxvq->stats.packets;
987a9643ea8Slogwang stats->ibytes += rxvq->stats.bytes;
988a9643ea8Slogwang stats->ierrors += rxvq->stats.errors;
989a9643ea8Slogwang
990a9643ea8Slogwang if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
991a9643ea8Slogwang stats->q_ipackets[i] = rxvq->stats.packets;
992a9643ea8Slogwang stats->q_ibytes[i] = rxvq->stats.bytes;
993a9643ea8Slogwang }
994a9643ea8Slogwang }
995a9643ea8Slogwang
996a9643ea8Slogwang stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
997a9643ea8Slogwang }
998a9643ea8Slogwang
virtio_dev_xstats_get_names(struct rte_eth_dev * dev,struct rte_eth_xstat_name * xstats_names,__rte_unused unsigned limit)999a9643ea8Slogwang static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
1000a9643ea8Slogwang struct rte_eth_xstat_name *xstats_names,
1001a9643ea8Slogwang __rte_unused unsigned limit)
1002a9643ea8Slogwang {
1003a9643ea8Slogwang unsigned i;
1004a9643ea8Slogwang unsigned count = 0;
1005a9643ea8Slogwang unsigned t;
1006a9643ea8Slogwang
1007a9643ea8Slogwang unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS +
1008a9643ea8Slogwang dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS;
1009a9643ea8Slogwang
1010a9643ea8Slogwang if (xstats_names != NULL) {
1011a9643ea8Slogwang /* Note: limit checked in rte_eth_xstats_names() */
1012a9643ea8Slogwang
1013a9643ea8Slogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
10142bfe3f2eSlogwang struct virtnet_rx *rxvq = dev->data->rx_queues[i];
1015a9643ea8Slogwang if (rxvq == NULL)
1016a9643ea8Slogwang continue;
1017a9643ea8Slogwang for (t = 0; t < VIRTIO_NB_RXQ_XSTATS; t++) {
1018a9643ea8Slogwang snprintf(xstats_names[count].name,
1019a9643ea8Slogwang sizeof(xstats_names[count].name),
1020a9643ea8Slogwang "rx_q%u_%s", i,
1021a9643ea8Slogwang rte_virtio_rxq_stat_strings[t].name);
1022a9643ea8Slogwang count++;
1023a9643ea8Slogwang }
1024a9643ea8Slogwang }
1025a9643ea8Slogwang
1026a9643ea8Slogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
10272bfe3f2eSlogwang struct virtnet_tx *txvq = dev->data->tx_queues[i];
1028a9643ea8Slogwang if (txvq == NULL)
1029a9643ea8Slogwang continue;
1030a9643ea8Slogwang for (t = 0; t < VIRTIO_NB_TXQ_XSTATS; t++) {
1031a9643ea8Slogwang snprintf(xstats_names[count].name,
1032a9643ea8Slogwang sizeof(xstats_names[count].name),
1033a9643ea8Slogwang "tx_q%u_%s", i,
1034a9643ea8Slogwang rte_virtio_txq_stat_strings[t].name);
1035a9643ea8Slogwang count++;
1036a9643ea8Slogwang }
1037a9643ea8Slogwang }
1038a9643ea8Slogwang return count;
1039a9643ea8Slogwang }
1040a9643ea8Slogwang return nstats;
1041a9643ea8Slogwang }
1042a9643ea8Slogwang
1043a9643ea8Slogwang static int
virtio_dev_xstats_get(struct rte_eth_dev * dev,struct rte_eth_xstat * xstats,unsigned n)1044a9643ea8Slogwang virtio_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
1045a9643ea8Slogwang unsigned n)
1046a9643ea8Slogwang {
1047a9643ea8Slogwang unsigned i;
1048a9643ea8Slogwang unsigned count = 0;
1049a9643ea8Slogwang
1050a9643ea8Slogwang unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS +
1051a9643ea8Slogwang dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS;
1052a9643ea8Slogwang
1053a9643ea8Slogwang if (n < nstats)
1054a9643ea8Slogwang return nstats;
1055a9643ea8Slogwang
1056a9643ea8Slogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
1057a9643ea8Slogwang struct virtnet_rx *rxvq = dev->data->rx_queues[i];
1058a9643ea8Slogwang
1059a9643ea8Slogwang if (rxvq == NULL)
1060a9643ea8Slogwang continue;
1061a9643ea8Slogwang
1062a9643ea8Slogwang unsigned t;
1063a9643ea8Slogwang
1064a9643ea8Slogwang for (t = 0; t < VIRTIO_NB_RXQ_XSTATS; t++) {
1065a9643ea8Slogwang xstats[count].value = *(uint64_t *)(((char *)rxvq) +
1066a9643ea8Slogwang rte_virtio_rxq_stat_strings[t].offset);
10672bfe3f2eSlogwang xstats[count].id = count;
1068a9643ea8Slogwang count++;
1069a9643ea8Slogwang }
1070a9643ea8Slogwang }
1071a9643ea8Slogwang
1072a9643ea8Slogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
1073a9643ea8Slogwang struct virtnet_tx *txvq = dev->data->tx_queues[i];
1074a9643ea8Slogwang
1075a9643ea8Slogwang if (txvq == NULL)
1076a9643ea8Slogwang continue;
1077a9643ea8Slogwang
1078a9643ea8Slogwang unsigned t;
1079a9643ea8Slogwang
1080a9643ea8Slogwang for (t = 0; t < VIRTIO_NB_TXQ_XSTATS; t++) {
1081a9643ea8Slogwang xstats[count].value = *(uint64_t *)(((char *)txvq) +
1082a9643ea8Slogwang rte_virtio_txq_stat_strings[t].offset);
10832bfe3f2eSlogwang xstats[count].id = count;
1084a9643ea8Slogwang count++;
1085a9643ea8Slogwang }
1086a9643ea8Slogwang }
1087a9643ea8Slogwang
1088a9643ea8Slogwang return count;
1089a9643ea8Slogwang }
1090a9643ea8Slogwang
10912bfe3f2eSlogwang static int
virtio_dev_stats_get(struct rte_eth_dev * dev,struct rte_eth_stats * stats)1092a9643ea8Slogwang virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
1093a9643ea8Slogwang {
1094a9643ea8Slogwang virtio_update_stats(dev, stats);
10952bfe3f2eSlogwang
10962bfe3f2eSlogwang return 0;
1097a9643ea8Slogwang }
1098a9643ea8Slogwang
10994418919fSjohnjiang static int
virtio_dev_stats_reset(struct rte_eth_dev * dev)1100a9643ea8Slogwang virtio_dev_stats_reset(struct rte_eth_dev *dev)
1101a9643ea8Slogwang {
1102a9643ea8Slogwang unsigned int i;
1103a9643ea8Slogwang
1104a9643ea8Slogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
1105a9643ea8Slogwang struct virtnet_tx *txvq = dev->data->tx_queues[i];
1106a9643ea8Slogwang if (txvq == NULL)
1107a9643ea8Slogwang continue;
1108a9643ea8Slogwang
1109a9643ea8Slogwang txvq->stats.packets = 0;
1110a9643ea8Slogwang txvq->stats.bytes = 0;
1111a9643ea8Slogwang txvq->stats.multicast = 0;
1112a9643ea8Slogwang txvq->stats.broadcast = 0;
1113a9643ea8Slogwang memset(txvq->stats.size_bins, 0,
1114a9643ea8Slogwang sizeof(txvq->stats.size_bins[0]) * 8);
1115a9643ea8Slogwang }
1116a9643ea8Slogwang
1117a9643ea8Slogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
1118a9643ea8Slogwang struct virtnet_rx *rxvq = dev->data->rx_queues[i];
1119a9643ea8Slogwang if (rxvq == NULL)
1120a9643ea8Slogwang continue;
1121a9643ea8Slogwang
1122a9643ea8Slogwang rxvq->stats.packets = 0;
1123a9643ea8Slogwang rxvq->stats.bytes = 0;
1124a9643ea8Slogwang rxvq->stats.errors = 0;
1125a9643ea8Slogwang rxvq->stats.multicast = 0;
1126a9643ea8Slogwang rxvq->stats.broadcast = 0;
1127a9643ea8Slogwang memset(rxvq->stats.size_bins, 0,
1128a9643ea8Slogwang sizeof(rxvq->stats.size_bins[0]) * 8);
1129a9643ea8Slogwang }
11304418919fSjohnjiang
11314418919fSjohnjiang return 0;
1132a9643ea8Slogwang }
1133a9643ea8Slogwang
1134a9643ea8Slogwang static void
virtio_set_hwaddr(struct virtio_hw * hw)1135a9643ea8Slogwang virtio_set_hwaddr(struct virtio_hw *hw)
1136a9643ea8Slogwang {
1137a9643ea8Slogwang vtpci_write_dev_config(hw,
1138a9643ea8Slogwang offsetof(struct virtio_net_config, mac),
11394418919fSjohnjiang &hw->mac_addr, RTE_ETHER_ADDR_LEN);
1140a9643ea8Slogwang }
1141a9643ea8Slogwang
1142a9643ea8Slogwang static void
virtio_get_hwaddr(struct virtio_hw * hw)1143a9643ea8Slogwang virtio_get_hwaddr(struct virtio_hw *hw)
1144a9643ea8Slogwang {
1145a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_MAC)) {
1146a9643ea8Slogwang vtpci_read_dev_config(hw,
1147a9643ea8Slogwang offsetof(struct virtio_net_config, mac),
11484418919fSjohnjiang &hw->mac_addr, RTE_ETHER_ADDR_LEN);
1149a9643ea8Slogwang } else {
11504418919fSjohnjiang rte_eth_random_addr(&hw->mac_addr[0]);
1151a9643ea8Slogwang virtio_set_hwaddr(hw);
1152a9643ea8Slogwang }
1153a9643ea8Slogwang }
1154a9643ea8Slogwang
11552bfe3f2eSlogwang static int
virtio_mac_table_set(struct virtio_hw * hw,const struct virtio_net_ctrl_mac * uc,const struct virtio_net_ctrl_mac * mc)1156a9643ea8Slogwang virtio_mac_table_set(struct virtio_hw *hw,
1157a9643ea8Slogwang const struct virtio_net_ctrl_mac *uc,
1158a9643ea8Slogwang const struct virtio_net_ctrl_mac *mc)
1159a9643ea8Slogwang {
1160a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
1161a9643ea8Slogwang int err, len[2];
1162a9643ea8Slogwang
1163a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
1164a9643ea8Slogwang PMD_DRV_LOG(INFO, "host does not support mac table");
11652bfe3f2eSlogwang return -1;
1166a9643ea8Slogwang }
1167a9643ea8Slogwang
1168a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_MAC;
1169a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_MAC_TABLE_SET;
1170a9643ea8Slogwang
11714418919fSjohnjiang len[0] = uc->entries * RTE_ETHER_ADDR_LEN + sizeof(uc->entries);
1172a9643ea8Slogwang memcpy(ctrl.data, uc, len[0]);
1173a9643ea8Slogwang
11744418919fSjohnjiang len[1] = mc->entries * RTE_ETHER_ADDR_LEN + sizeof(mc->entries);
1175a9643ea8Slogwang memcpy(ctrl.data + len[0], mc, len[1]);
1176a9643ea8Slogwang
1177a9643ea8Slogwang err = virtio_send_command(hw->cvq, &ctrl, len, 2);
1178a9643ea8Slogwang if (err != 0)
1179a9643ea8Slogwang PMD_DRV_LOG(NOTICE, "mac table set failed: %d", err);
11802bfe3f2eSlogwang return err;
1181a9643ea8Slogwang }
1182a9643ea8Slogwang
11832bfe3f2eSlogwang static int
virtio_mac_addr_add(struct rte_eth_dev * dev,struct rte_ether_addr * mac_addr,uint32_t index,uint32_t vmdq __rte_unused)11844418919fSjohnjiang virtio_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
1185a9643ea8Slogwang uint32_t index, uint32_t vmdq __rte_unused)
1186a9643ea8Slogwang {
1187a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
11884418919fSjohnjiang const struct rte_ether_addr *addrs = dev->data->mac_addrs;
1189a9643ea8Slogwang unsigned int i;
1190a9643ea8Slogwang struct virtio_net_ctrl_mac *uc, *mc;
1191a9643ea8Slogwang
1192a9643ea8Slogwang if (index >= VIRTIO_MAX_MAC_ADDRS) {
1193a9643ea8Slogwang PMD_DRV_LOG(ERR, "mac address index %u out of range", index);
11942bfe3f2eSlogwang return -EINVAL;
1195a9643ea8Slogwang }
1196a9643ea8Slogwang
11974418919fSjohnjiang uc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN +
11984418919fSjohnjiang sizeof(uc->entries));
1199a9643ea8Slogwang uc->entries = 0;
12004418919fSjohnjiang mc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN +
12014418919fSjohnjiang sizeof(mc->entries));
1202a9643ea8Slogwang mc->entries = 0;
1203a9643ea8Slogwang
1204a9643ea8Slogwang for (i = 0; i < VIRTIO_MAX_MAC_ADDRS; i++) {
12054418919fSjohnjiang const struct rte_ether_addr *addr
1206a9643ea8Slogwang = (i == index) ? mac_addr : addrs + i;
1207a9643ea8Slogwang struct virtio_net_ctrl_mac *tbl
12084418919fSjohnjiang = rte_is_multicast_ether_addr(addr) ? mc : uc;
1209a9643ea8Slogwang
12104418919fSjohnjiang memcpy(&tbl->macs[tbl->entries++], addr, RTE_ETHER_ADDR_LEN);
1211a9643ea8Slogwang }
1212a9643ea8Slogwang
12132bfe3f2eSlogwang return virtio_mac_table_set(hw, uc, mc);
1214a9643ea8Slogwang }
1215a9643ea8Slogwang
1216a9643ea8Slogwang static void
virtio_mac_addr_remove(struct rte_eth_dev * dev,uint32_t index)1217a9643ea8Slogwang virtio_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
1218a9643ea8Slogwang {
1219a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
12204418919fSjohnjiang struct rte_ether_addr *addrs = dev->data->mac_addrs;
1221a9643ea8Slogwang struct virtio_net_ctrl_mac *uc, *mc;
1222a9643ea8Slogwang unsigned int i;
1223a9643ea8Slogwang
1224a9643ea8Slogwang if (index >= VIRTIO_MAX_MAC_ADDRS) {
1225a9643ea8Slogwang PMD_DRV_LOG(ERR, "mac address index %u out of range", index);
1226a9643ea8Slogwang return;
1227a9643ea8Slogwang }
1228a9643ea8Slogwang
12294418919fSjohnjiang uc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN +
12304418919fSjohnjiang sizeof(uc->entries));
1231a9643ea8Slogwang uc->entries = 0;
12324418919fSjohnjiang mc = alloca(VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN +
12334418919fSjohnjiang sizeof(mc->entries));
1234a9643ea8Slogwang mc->entries = 0;
1235a9643ea8Slogwang
1236a9643ea8Slogwang for (i = 0; i < VIRTIO_MAX_MAC_ADDRS; i++) {
1237a9643ea8Slogwang struct virtio_net_ctrl_mac *tbl;
1238a9643ea8Slogwang
12394418919fSjohnjiang if (i == index || rte_is_zero_ether_addr(addrs + i))
1240a9643ea8Slogwang continue;
1241a9643ea8Slogwang
12424418919fSjohnjiang tbl = rte_is_multicast_ether_addr(addrs + i) ? mc : uc;
12434418919fSjohnjiang memcpy(&tbl->macs[tbl->entries++], addrs + i,
12444418919fSjohnjiang RTE_ETHER_ADDR_LEN);
1245a9643ea8Slogwang }
1246a9643ea8Slogwang
1247a9643ea8Slogwang virtio_mac_table_set(hw, uc, mc);
1248a9643ea8Slogwang }
1249a9643ea8Slogwang
1250d30ea906Sjfb8856606 static int
virtio_mac_addr_set(struct rte_eth_dev * dev,struct rte_ether_addr * mac_addr)12514418919fSjohnjiang virtio_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
1252a9643ea8Slogwang {
1253a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
1254a9643ea8Slogwang
12554418919fSjohnjiang memcpy(hw->mac_addr, mac_addr, RTE_ETHER_ADDR_LEN);
1256a9643ea8Slogwang
1257a9643ea8Slogwang /* Use atomic update if available */
1258a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
1259a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
12604418919fSjohnjiang int len = RTE_ETHER_ADDR_LEN;
1261a9643ea8Slogwang
1262a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_MAC;
1263a9643ea8Slogwang ctrl.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET;
1264a9643ea8Slogwang
12654418919fSjohnjiang memcpy(ctrl.data, mac_addr, RTE_ETHER_ADDR_LEN);
1266d30ea906Sjfb8856606 return virtio_send_command(hw->cvq, &ctrl, &len, 1);
1267d30ea906Sjfb8856606 }
1268d30ea906Sjfb8856606
1269d30ea906Sjfb8856606 if (!vtpci_with_feature(hw, VIRTIO_NET_F_MAC))
1270d30ea906Sjfb8856606 return -ENOTSUP;
1271d30ea906Sjfb8856606
1272a9643ea8Slogwang virtio_set_hwaddr(hw);
1273d30ea906Sjfb8856606 return 0;
1274a9643ea8Slogwang }
1275a9643ea8Slogwang
1276a9643ea8Slogwang static int
virtio_vlan_filter_set(struct rte_eth_dev * dev,uint16_t vlan_id,int on)1277a9643ea8Slogwang virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
1278a9643ea8Slogwang {
1279a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
1280a9643ea8Slogwang struct virtio_pmd_ctrl ctrl;
1281a9643ea8Slogwang int len;
1282a9643ea8Slogwang
1283a9643ea8Slogwang if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN))
1284a9643ea8Slogwang return -ENOTSUP;
1285a9643ea8Slogwang
1286a9643ea8Slogwang ctrl.hdr.class = VIRTIO_NET_CTRL_VLAN;
1287a9643ea8Slogwang ctrl.hdr.cmd = on ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL;
1288a9643ea8Slogwang memcpy(ctrl.data, &vlan_id, sizeof(vlan_id));
1289a9643ea8Slogwang len = sizeof(vlan_id);
1290a9643ea8Slogwang
1291a9643ea8Slogwang return virtio_send_command(hw->cvq, &ctrl, &len, 1);
1292a9643ea8Slogwang }
1293a9643ea8Slogwang
1294a9643ea8Slogwang static int
virtio_intr_unmask(struct rte_eth_dev * dev)12954418919fSjohnjiang virtio_intr_unmask(struct rte_eth_dev *dev)
12964418919fSjohnjiang {
12974418919fSjohnjiang struct virtio_hw *hw = dev->data->dev_private;
12984418919fSjohnjiang
12994418919fSjohnjiang if (rte_intr_ack(dev->intr_handle) < 0)
13004418919fSjohnjiang return -1;
13014418919fSjohnjiang
13024418919fSjohnjiang if (!hw->virtio_user_dev)
13034418919fSjohnjiang hw->use_msix = vtpci_msix_detect(RTE_ETH_DEV_TO_PCI(dev));
13044418919fSjohnjiang
13054418919fSjohnjiang return 0;
13064418919fSjohnjiang }
13074418919fSjohnjiang
13084418919fSjohnjiang static int
virtio_intr_enable(struct rte_eth_dev * dev)13092bfe3f2eSlogwang virtio_intr_enable(struct rte_eth_dev *dev)
13102bfe3f2eSlogwang {
13112bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
13122bfe3f2eSlogwang
13132bfe3f2eSlogwang if (rte_intr_enable(dev->intr_handle) < 0)
13142bfe3f2eSlogwang return -1;
13152bfe3f2eSlogwang
13162bfe3f2eSlogwang if (!hw->virtio_user_dev)
13172bfe3f2eSlogwang hw->use_msix = vtpci_msix_detect(RTE_ETH_DEV_TO_PCI(dev));
13182bfe3f2eSlogwang
13192bfe3f2eSlogwang return 0;
13202bfe3f2eSlogwang }
13212bfe3f2eSlogwang
13222bfe3f2eSlogwang static int
virtio_intr_disable(struct rte_eth_dev * dev)13232bfe3f2eSlogwang virtio_intr_disable(struct rte_eth_dev *dev)
13242bfe3f2eSlogwang {
13252bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
13262bfe3f2eSlogwang
13272bfe3f2eSlogwang if (rte_intr_disable(dev->intr_handle) < 0)
13282bfe3f2eSlogwang return -1;
13292bfe3f2eSlogwang
13302bfe3f2eSlogwang if (!hw->virtio_user_dev)
13312bfe3f2eSlogwang hw->use_msix = vtpci_msix_detect(RTE_ETH_DEV_TO_PCI(dev));
13322bfe3f2eSlogwang
13332bfe3f2eSlogwang return 0;
13342bfe3f2eSlogwang }
13352bfe3f2eSlogwang
13362bfe3f2eSlogwang static int
virtio_negotiate_features(struct virtio_hw * hw,uint64_t req_features)13372bfe3f2eSlogwang virtio_negotiate_features(struct virtio_hw *hw, uint64_t req_features)
1338a9643ea8Slogwang {
1339a9643ea8Slogwang uint64_t host_features;
1340a9643ea8Slogwang
1341a9643ea8Slogwang /* Prepare guest_features: feature that driver wants to support */
1342a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %" PRIx64,
13432bfe3f2eSlogwang req_features);
1344a9643ea8Slogwang
1345a9643ea8Slogwang /* Read device(host) feature bits */
13462bfe3f2eSlogwang host_features = VTPCI_OPS(hw)->get_features(hw);
1347a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "host_features before negotiate = %" PRIx64,
1348a9643ea8Slogwang host_features);
1349a9643ea8Slogwang
13502bfe3f2eSlogwang /* If supported, ensure MTU value is valid before acknowledging it. */
13512bfe3f2eSlogwang if (host_features & req_features & (1ULL << VIRTIO_NET_F_MTU)) {
13522bfe3f2eSlogwang struct virtio_net_config config;
13532bfe3f2eSlogwang
13542bfe3f2eSlogwang vtpci_read_dev_config(hw,
13552bfe3f2eSlogwang offsetof(struct virtio_net_config, mtu),
13562bfe3f2eSlogwang &config.mtu, sizeof(config.mtu));
13572bfe3f2eSlogwang
13584418919fSjohnjiang if (config.mtu < RTE_ETHER_MIN_MTU)
13592bfe3f2eSlogwang req_features &= ~(1ULL << VIRTIO_NET_F_MTU);
13602bfe3f2eSlogwang }
13612bfe3f2eSlogwang
1362a9643ea8Slogwang /*
1363a9643ea8Slogwang * Negotiate features: Subset of device feature bits are written back
1364a9643ea8Slogwang * guest feature bits.
1365a9643ea8Slogwang */
13662bfe3f2eSlogwang hw->guest_features = req_features;
1367a9643ea8Slogwang hw->guest_features = vtpci_negotiate_features(hw, host_features);
1368a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64,
1369a9643ea8Slogwang hw->guest_features);
1370a9643ea8Slogwang
1371*2d9fd380Sjfb8856606 if (hw->modern && !vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
1372a9643ea8Slogwang PMD_INIT_LOG(ERR,
1373a9643ea8Slogwang "VIRTIO_F_VERSION_1 features is not enabled.");
1374a9643ea8Slogwang return -1;
1375a9643ea8Slogwang }
1376*2d9fd380Sjfb8856606
1377*2d9fd380Sjfb8856606 if (hw->modern || hw->virtio_user_dev) {
1378a9643ea8Slogwang vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
1379a9643ea8Slogwang if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
1380a9643ea8Slogwang PMD_INIT_LOG(ERR,
1381a9643ea8Slogwang "failed to set FEATURES_OK status!");
1382a9643ea8Slogwang return -1;
1383a9643ea8Slogwang }
1384a9643ea8Slogwang }
1385a9643ea8Slogwang
13862bfe3f2eSlogwang hw->req_guest_features = req_features;
13872bfe3f2eSlogwang
1388a9643ea8Slogwang return 0;
1389a9643ea8Slogwang }
1390a9643ea8Slogwang
1391d30ea906Sjfb8856606 int
virtio_dev_pause(struct rte_eth_dev * dev)1392d30ea906Sjfb8856606 virtio_dev_pause(struct rte_eth_dev *dev)
1393d30ea906Sjfb8856606 {
1394d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
1395d30ea906Sjfb8856606
1396d30ea906Sjfb8856606 rte_spinlock_lock(&hw->state_lock);
1397d30ea906Sjfb8856606
1398d30ea906Sjfb8856606 if (hw->started == 0) {
1399d30ea906Sjfb8856606 /* Device is just stopped. */
1400d30ea906Sjfb8856606 rte_spinlock_unlock(&hw->state_lock);
1401d30ea906Sjfb8856606 return -1;
1402d30ea906Sjfb8856606 }
1403d30ea906Sjfb8856606 hw->started = 0;
1404a9643ea8Slogwang /*
1405d30ea906Sjfb8856606 * Prevent the worker threads from touching queues to avoid contention,
1406d30ea906Sjfb8856606 * 1 ms should be enough for the ongoing Tx function to finish.
1407d30ea906Sjfb8856606 */
1408d30ea906Sjfb8856606 rte_delay_ms(1);
1409d30ea906Sjfb8856606 return 0;
1410d30ea906Sjfb8856606 }
1411d30ea906Sjfb8856606
1412d30ea906Sjfb8856606 /*
1413d30ea906Sjfb8856606 * Recover hw state to let the worker threads continue.
1414d30ea906Sjfb8856606 */
1415d30ea906Sjfb8856606 void
virtio_dev_resume(struct rte_eth_dev * dev)1416d30ea906Sjfb8856606 virtio_dev_resume(struct rte_eth_dev *dev)
1417d30ea906Sjfb8856606 {
1418d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
1419d30ea906Sjfb8856606
1420d30ea906Sjfb8856606 hw->started = 1;
1421d30ea906Sjfb8856606 rte_spinlock_unlock(&hw->state_lock);
1422d30ea906Sjfb8856606 }
1423d30ea906Sjfb8856606
1424d30ea906Sjfb8856606 /*
1425d30ea906Sjfb8856606 * Should be called only after device is paused.
1426d30ea906Sjfb8856606 */
1427d30ea906Sjfb8856606 int
virtio_inject_pkts(struct rte_eth_dev * dev,struct rte_mbuf ** tx_pkts,int nb_pkts)1428d30ea906Sjfb8856606 virtio_inject_pkts(struct rte_eth_dev *dev, struct rte_mbuf **tx_pkts,
1429d30ea906Sjfb8856606 int nb_pkts)
1430d30ea906Sjfb8856606 {
1431d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
1432d30ea906Sjfb8856606 struct virtnet_tx *txvq = dev->data->tx_queues[0];
1433d30ea906Sjfb8856606 int ret;
1434d30ea906Sjfb8856606
1435d30ea906Sjfb8856606 hw->inject_pkts = tx_pkts;
1436d30ea906Sjfb8856606 ret = dev->tx_pkt_burst(txvq, tx_pkts, nb_pkts);
1437d30ea906Sjfb8856606 hw->inject_pkts = NULL;
1438d30ea906Sjfb8856606
1439d30ea906Sjfb8856606 return ret;
1440d30ea906Sjfb8856606 }
1441d30ea906Sjfb8856606
1442d30ea906Sjfb8856606 static void
virtio_notify_peers(struct rte_eth_dev * dev)1443d30ea906Sjfb8856606 virtio_notify_peers(struct rte_eth_dev *dev)
1444d30ea906Sjfb8856606 {
1445d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
1446d30ea906Sjfb8856606 struct virtnet_rx *rxvq;
1447d30ea906Sjfb8856606 struct rte_mbuf *rarp_mbuf;
1448d30ea906Sjfb8856606
1449d30ea906Sjfb8856606 if (!dev->data->rx_queues)
1450d30ea906Sjfb8856606 return;
1451d30ea906Sjfb8856606
1452d30ea906Sjfb8856606 rxvq = dev->data->rx_queues[0];
1453d30ea906Sjfb8856606 if (!rxvq)
1454d30ea906Sjfb8856606 return;
1455d30ea906Sjfb8856606
1456d30ea906Sjfb8856606 rarp_mbuf = rte_net_make_rarp_packet(rxvq->mpool,
14574418919fSjohnjiang (struct rte_ether_addr *)hw->mac_addr);
1458d30ea906Sjfb8856606 if (rarp_mbuf == NULL) {
1459d30ea906Sjfb8856606 PMD_DRV_LOG(ERR, "failed to make RARP packet.");
1460d30ea906Sjfb8856606 return;
1461d30ea906Sjfb8856606 }
1462d30ea906Sjfb8856606
1463d30ea906Sjfb8856606 /* If virtio port just stopped, no need to send RARP */
1464d30ea906Sjfb8856606 if (virtio_dev_pause(dev) < 0) {
1465d30ea906Sjfb8856606 rte_pktmbuf_free(rarp_mbuf);
1466d30ea906Sjfb8856606 return;
1467d30ea906Sjfb8856606 }
1468d30ea906Sjfb8856606
1469d30ea906Sjfb8856606 virtio_inject_pkts(dev, &rarp_mbuf, 1);
1470d30ea906Sjfb8856606 virtio_dev_resume(dev);
1471d30ea906Sjfb8856606 }
1472d30ea906Sjfb8856606
1473d30ea906Sjfb8856606 static void
virtio_ack_link_announce(struct rte_eth_dev * dev)1474d30ea906Sjfb8856606 virtio_ack_link_announce(struct rte_eth_dev *dev)
1475d30ea906Sjfb8856606 {
1476d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
1477d30ea906Sjfb8856606 struct virtio_pmd_ctrl ctrl;
1478d30ea906Sjfb8856606
1479d30ea906Sjfb8856606 ctrl.hdr.class = VIRTIO_NET_CTRL_ANNOUNCE;
1480d30ea906Sjfb8856606 ctrl.hdr.cmd = VIRTIO_NET_CTRL_ANNOUNCE_ACK;
1481d30ea906Sjfb8856606
1482d30ea906Sjfb8856606 virtio_send_command(hw->cvq, &ctrl, NULL, 0);
1483d30ea906Sjfb8856606 }
1484d30ea906Sjfb8856606
1485d30ea906Sjfb8856606 /*
1486d30ea906Sjfb8856606 * Process virtio config changed interrupt. Call the callback
1487d30ea906Sjfb8856606 * if link state changed, generate gratuitous RARP packet if
1488d30ea906Sjfb8856606 * the status indicates an ANNOUNCE.
1489a9643ea8Slogwang */
14902bfe3f2eSlogwang void
virtio_interrupt_handler(void * param)14912bfe3f2eSlogwang virtio_interrupt_handler(void *param)
1492a9643ea8Slogwang {
1493a9643ea8Slogwang struct rte_eth_dev *dev = param;
1494a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
1495a9643ea8Slogwang uint8_t isr;
1496d30ea906Sjfb8856606 uint16_t status;
1497a9643ea8Slogwang
1498a9643ea8Slogwang /* Read interrupt status which clears interrupt */
1499a9643ea8Slogwang isr = vtpci_isr(hw);
1500a9643ea8Slogwang PMD_DRV_LOG(INFO, "interrupt status = %#x", isr);
1501a9643ea8Slogwang
15024418919fSjohnjiang if (virtio_intr_unmask(dev) < 0)
1503a9643ea8Slogwang PMD_DRV_LOG(ERR, "interrupt enable failed");
1504a9643ea8Slogwang
1505a9643ea8Slogwang if (isr & VIRTIO_PCI_ISR_CONFIG) {
1506a9643ea8Slogwang if (virtio_dev_link_update(dev, 0) == 0)
1507*2d9fd380Sjfb8856606 rte_eth_dev_callback_process(dev,
15082bfe3f2eSlogwang RTE_ETH_EVENT_INTR_LSC,
1509d30ea906Sjfb8856606 NULL);
1510a9643ea8Slogwang
1511d30ea906Sjfb8856606 if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
1512d30ea906Sjfb8856606 vtpci_read_dev_config(hw,
1513d30ea906Sjfb8856606 offsetof(struct virtio_net_config, status),
1514d30ea906Sjfb8856606 &status, sizeof(status));
1515d30ea906Sjfb8856606 if (status & VIRTIO_NET_S_ANNOUNCE) {
1516d30ea906Sjfb8856606 virtio_notify_peers(dev);
1517d30ea906Sjfb8856606 if (hw->cvq)
1518d30ea906Sjfb8856606 virtio_ack_link_announce(dev);
1519d30ea906Sjfb8856606 }
1520d30ea906Sjfb8856606 }
1521d30ea906Sjfb8856606 }
1522a9643ea8Slogwang }
1523a9643ea8Slogwang
15242bfe3f2eSlogwang /* set rx and tx handlers according to what is supported */
1525a9643ea8Slogwang static void
set_rxtx_funcs(struct rte_eth_dev * eth_dev)15262bfe3f2eSlogwang set_rxtx_funcs(struct rte_eth_dev *eth_dev)
1527a9643ea8Slogwang {
1528a9643ea8Slogwang struct virtio_hw *hw = eth_dev->data->dev_private;
15292bfe3f2eSlogwang
15304b05018fSfengbojiang eth_dev->tx_pkt_prepare = virtio_xmit_pkts_prepare;
15314418919fSjohnjiang if (vtpci_packed_queue(hw)) {
15324418919fSjohnjiang PMD_INIT_LOG(INFO,
15334418919fSjohnjiang "virtio: using packed ring %s Tx path on port %u",
1534*2d9fd380Sjfb8856606 hw->use_vec_tx ? "vectorized" : "standard",
15354418919fSjohnjiang eth_dev->data->port_id);
1536*2d9fd380Sjfb8856606 if (hw->use_vec_tx)
1537*2d9fd380Sjfb8856606 eth_dev->tx_pkt_burst = virtio_xmit_pkts_packed_vec;
1538*2d9fd380Sjfb8856606 else
15394418919fSjohnjiang eth_dev->tx_pkt_burst = virtio_xmit_pkts_packed;
15404418919fSjohnjiang } else {
15414418919fSjohnjiang if (hw->use_inorder_tx) {
15424418919fSjohnjiang PMD_INIT_LOG(INFO, "virtio: using inorder Tx path on port %u",
15434418919fSjohnjiang eth_dev->data->port_id);
15444418919fSjohnjiang eth_dev->tx_pkt_burst = virtio_xmit_pkts_inorder;
15454418919fSjohnjiang } else {
15464418919fSjohnjiang PMD_INIT_LOG(INFO, "virtio: using standard Tx path on port %u",
15474418919fSjohnjiang eth_dev->data->port_id);
15484418919fSjohnjiang eth_dev->tx_pkt_burst = virtio_xmit_pkts;
15494418919fSjohnjiang }
15504418919fSjohnjiang }
15514418919fSjohnjiang
15524418919fSjohnjiang if (vtpci_packed_queue(hw)) {
1553*2d9fd380Sjfb8856606 if (hw->use_vec_rx) {
1554*2d9fd380Sjfb8856606 PMD_INIT_LOG(INFO,
1555*2d9fd380Sjfb8856606 "virtio: using packed ring vectorized Rx path on port %u",
1556*2d9fd380Sjfb8856606 eth_dev->data->port_id);
1557*2d9fd380Sjfb8856606 eth_dev->rx_pkt_burst =
1558*2d9fd380Sjfb8856606 &virtio_recv_pkts_packed_vec;
1559*2d9fd380Sjfb8856606 } else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
15604418919fSjohnjiang PMD_INIT_LOG(INFO,
15614418919fSjohnjiang "virtio: using packed ring mergeable buffer Rx path on port %u",
15624418919fSjohnjiang eth_dev->data->port_id);
15634418919fSjohnjiang eth_dev->rx_pkt_burst =
15644418919fSjohnjiang &virtio_recv_mergeable_pkts_packed;
15654418919fSjohnjiang } else {
15664418919fSjohnjiang PMD_INIT_LOG(INFO,
15674418919fSjohnjiang "virtio: using packed ring standard Rx path on port %u",
15684418919fSjohnjiang eth_dev->data->port_id);
15694418919fSjohnjiang eth_dev->rx_pkt_burst = &virtio_recv_pkts_packed;
15704418919fSjohnjiang }
15714418919fSjohnjiang } else {
1572*2d9fd380Sjfb8856606 if (hw->use_vec_rx) {
1573*2d9fd380Sjfb8856606 PMD_INIT_LOG(INFO, "virtio: using vectorized Rx path on port %u",
15742bfe3f2eSlogwang eth_dev->data->port_id);
15752bfe3f2eSlogwang eth_dev->rx_pkt_burst = virtio_recv_pkts_vec;
1576d30ea906Sjfb8856606 } else if (hw->use_inorder_rx) {
1577d30ea906Sjfb8856606 PMD_INIT_LOG(INFO,
15784418919fSjohnjiang "virtio: using inorder Rx path on port %u",
1579d30ea906Sjfb8856606 eth_dev->data->port_id);
15804418919fSjohnjiang eth_dev->rx_pkt_burst = &virtio_recv_pkts_inorder;
15812bfe3f2eSlogwang } else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
15822bfe3f2eSlogwang PMD_INIT_LOG(INFO,
15832bfe3f2eSlogwang "virtio: using mergeable buffer Rx path on port %u",
15842bfe3f2eSlogwang eth_dev->data->port_id);
1585a9643ea8Slogwang eth_dev->rx_pkt_burst = &virtio_recv_mergeable_pkts;
15862bfe3f2eSlogwang } else {
15872bfe3f2eSlogwang PMD_INIT_LOG(INFO, "virtio: using standard Rx path on port %u",
15882bfe3f2eSlogwang eth_dev->data->port_id);
1589a9643ea8Slogwang eth_dev->rx_pkt_burst = &virtio_recv_pkts;
1590a9643ea8Slogwang }
15912bfe3f2eSlogwang }
15924418919fSjohnjiang
15932bfe3f2eSlogwang }
15942bfe3f2eSlogwang
15952bfe3f2eSlogwang /* Only support 1:1 queue/interrupt mapping so far.
15962bfe3f2eSlogwang * TODO: support n:1 queue/interrupt mapping when there are limited number of
15972bfe3f2eSlogwang * interrupt vectors (<N+1).
1598a9643ea8Slogwang */
15992bfe3f2eSlogwang static int
virtio_queues_bind_intr(struct rte_eth_dev * dev)16002bfe3f2eSlogwang virtio_queues_bind_intr(struct rte_eth_dev *dev)
16012bfe3f2eSlogwang {
16022bfe3f2eSlogwang uint32_t i;
16032bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
16042bfe3f2eSlogwang
16052bfe3f2eSlogwang PMD_INIT_LOG(INFO, "queue/interrupt binding");
16062bfe3f2eSlogwang for (i = 0; i < dev->data->nb_rx_queues; ++i) {
16072bfe3f2eSlogwang dev->intr_handle->intr_vec[i] = i + 1;
16082bfe3f2eSlogwang if (VTPCI_OPS(hw)->set_queue_irq(hw, hw->vqs[i * 2], i + 1) ==
16092bfe3f2eSlogwang VIRTIO_MSI_NO_VECTOR) {
16102bfe3f2eSlogwang PMD_DRV_LOG(ERR, "failed to set queue vector");
16112bfe3f2eSlogwang return -EBUSY;
16122bfe3f2eSlogwang }
16132bfe3f2eSlogwang }
16142bfe3f2eSlogwang
16152bfe3f2eSlogwang return 0;
16162bfe3f2eSlogwang }
16172bfe3f2eSlogwang
16182bfe3f2eSlogwang static void
virtio_queues_unbind_intr(struct rte_eth_dev * dev)16192bfe3f2eSlogwang virtio_queues_unbind_intr(struct rte_eth_dev *dev)
16202bfe3f2eSlogwang {
16212bfe3f2eSlogwang uint32_t i;
16222bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
16232bfe3f2eSlogwang
16242bfe3f2eSlogwang PMD_INIT_LOG(INFO, "queue/interrupt unbinding");
16252bfe3f2eSlogwang for (i = 0; i < dev->data->nb_rx_queues; ++i)
16262bfe3f2eSlogwang VTPCI_OPS(hw)->set_queue_irq(hw,
16272bfe3f2eSlogwang hw->vqs[i * VTNET_CQ],
16282bfe3f2eSlogwang VIRTIO_MSI_NO_VECTOR);
16292bfe3f2eSlogwang }
16302bfe3f2eSlogwang
16312bfe3f2eSlogwang static int
virtio_configure_intr(struct rte_eth_dev * dev)16322bfe3f2eSlogwang virtio_configure_intr(struct rte_eth_dev *dev)
16332bfe3f2eSlogwang {
16342bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
16352bfe3f2eSlogwang
16362bfe3f2eSlogwang if (!rte_intr_cap_multiple(dev->intr_handle)) {
16372bfe3f2eSlogwang PMD_INIT_LOG(ERR, "Multiple intr vector not supported");
16382bfe3f2eSlogwang return -ENOTSUP;
16392bfe3f2eSlogwang }
16402bfe3f2eSlogwang
16412bfe3f2eSlogwang if (rte_intr_efd_enable(dev->intr_handle, dev->data->nb_rx_queues)) {
16422bfe3f2eSlogwang PMD_INIT_LOG(ERR, "Fail to create eventfd");
16432bfe3f2eSlogwang return -1;
16442bfe3f2eSlogwang }
16452bfe3f2eSlogwang
16462bfe3f2eSlogwang if (!dev->intr_handle->intr_vec) {
16472bfe3f2eSlogwang dev->intr_handle->intr_vec =
16482bfe3f2eSlogwang rte_zmalloc("intr_vec",
16492bfe3f2eSlogwang hw->max_queue_pairs * sizeof(int), 0);
16502bfe3f2eSlogwang if (!dev->intr_handle->intr_vec) {
16512bfe3f2eSlogwang PMD_INIT_LOG(ERR, "Failed to allocate %u rxq vectors",
16522bfe3f2eSlogwang hw->max_queue_pairs);
16532bfe3f2eSlogwang return -ENOMEM;
16542bfe3f2eSlogwang }
16552bfe3f2eSlogwang }
16562bfe3f2eSlogwang
16572bfe3f2eSlogwang /* Re-register callback to update max_intr */
16582bfe3f2eSlogwang rte_intr_callback_unregister(dev->intr_handle,
16592bfe3f2eSlogwang virtio_interrupt_handler,
16602bfe3f2eSlogwang dev);
16612bfe3f2eSlogwang rte_intr_callback_register(dev->intr_handle,
16622bfe3f2eSlogwang virtio_interrupt_handler,
16632bfe3f2eSlogwang dev);
16642bfe3f2eSlogwang
16652bfe3f2eSlogwang /* DO NOT try to remove this! This function will enable msix, or QEMU
16662bfe3f2eSlogwang * will encounter SIGSEGV when DRIVER_OK is sent.
16672bfe3f2eSlogwang * And for legacy devices, this should be done before queue/vec binding
16682bfe3f2eSlogwang * to change the config size from 20 to 24, or VIRTIO_MSI_QUEUE_VECTOR
16692bfe3f2eSlogwang * (22) will be ignored.
16702bfe3f2eSlogwang */
16712bfe3f2eSlogwang if (virtio_intr_enable(dev) < 0) {
16722bfe3f2eSlogwang PMD_DRV_LOG(ERR, "interrupt enable failed");
16732bfe3f2eSlogwang return -1;
16742bfe3f2eSlogwang }
16752bfe3f2eSlogwang
16762bfe3f2eSlogwang if (virtio_queues_bind_intr(dev) < 0) {
16772bfe3f2eSlogwang PMD_INIT_LOG(ERR, "Failed to bind queue/interrupt");
16782bfe3f2eSlogwang return -1;
16792bfe3f2eSlogwang }
16802bfe3f2eSlogwang
16812bfe3f2eSlogwang return 0;
16822bfe3f2eSlogwang }
1683*2d9fd380Sjfb8856606 #define DUPLEX_UNKNOWN 0xff
16842bfe3f2eSlogwang /* reset device and renegotiate features if needed */
16852bfe3f2eSlogwang static int
virtio_init_device(struct rte_eth_dev * eth_dev,uint64_t req_features)16862bfe3f2eSlogwang virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
1687a9643ea8Slogwang {
1688a9643ea8Slogwang struct virtio_hw *hw = eth_dev->data->dev_private;
1689a9643ea8Slogwang struct virtio_net_config *config;
1690a9643ea8Slogwang struct virtio_net_config local_config;
16912bfe3f2eSlogwang struct rte_pci_device *pci_dev = NULL;
1692a9643ea8Slogwang int ret;
1693a9643ea8Slogwang
1694a9643ea8Slogwang /* Reset the device although not necessary at startup */
1695a9643ea8Slogwang vtpci_reset(hw);
1696a9643ea8Slogwang
16972bfe3f2eSlogwang if (hw->vqs) {
16982bfe3f2eSlogwang virtio_dev_free_mbufs(eth_dev);
16992bfe3f2eSlogwang virtio_free_queues(hw);
17002bfe3f2eSlogwang }
17012bfe3f2eSlogwang
1702a9643ea8Slogwang /* Tell the host we've noticed this device. */
1703a9643ea8Slogwang vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
1704a9643ea8Slogwang
1705a9643ea8Slogwang /* Tell the host we've known how to drive the device. */
1706a9643ea8Slogwang vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
17072bfe3f2eSlogwang if (virtio_negotiate_features(hw, req_features) < 0)
1708a9643ea8Slogwang return -1;
1709a9643ea8Slogwang
17104418919fSjohnjiang hw->weak_barriers = !vtpci_with_feature(hw, VIRTIO_F_ORDER_PLATFORM);
17114418919fSjohnjiang
17124418919fSjohnjiang if (!hw->virtio_user_dev)
17132bfe3f2eSlogwang pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
1714a9643ea8Slogwang
17152bfe3f2eSlogwang /* If host does not support both status and MSI-X then disable LSC */
17162bfe3f2eSlogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS) &&
17172bfe3f2eSlogwang hw->use_msix != VIRTIO_MSIX_NONE)
17182bfe3f2eSlogwang eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
17192bfe3f2eSlogwang else
17202bfe3f2eSlogwang eth_dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC;
1721a9643ea8Slogwang
1722*2d9fd380Sjfb8856606 eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1723*2d9fd380Sjfb8856606
1724a9643ea8Slogwang /* Setting up rx_header size for the device */
1725a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
17264418919fSjohnjiang vtpci_with_feature(hw, VIRTIO_F_VERSION_1) ||
17274418919fSjohnjiang vtpci_with_feature(hw, VIRTIO_F_RING_PACKED))
1728a9643ea8Slogwang hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
1729a9643ea8Slogwang else
1730a9643ea8Slogwang hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
1731a9643ea8Slogwang
1732a9643ea8Slogwang /* Copy the permanent MAC address to: virtio_hw */
1733a9643ea8Slogwang virtio_get_hwaddr(hw);
17344418919fSjohnjiang rte_ether_addr_copy((struct rte_ether_addr *)hw->mac_addr,
1735a9643ea8Slogwang ð_dev->data->mac_addrs[0]);
1736a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
1737a9643ea8Slogwang "PORT MAC: %02X:%02X:%02X:%02X:%02X:%02X",
1738a9643ea8Slogwang hw->mac_addr[0], hw->mac_addr[1], hw->mac_addr[2],
1739a9643ea8Slogwang hw->mac_addr[3], hw->mac_addr[4], hw->mac_addr[5]);
1740a9643ea8Slogwang
1741*2d9fd380Sjfb8856606 if (hw->speed == ETH_SPEED_NUM_UNKNOWN) {
1742*2d9fd380Sjfb8856606 if (vtpci_with_feature(hw, VIRTIO_NET_F_SPEED_DUPLEX)) {
1743*2d9fd380Sjfb8856606 config = &local_config;
1744*2d9fd380Sjfb8856606 vtpci_read_dev_config(hw,
1745*2d9fd380Sjfb8856606 offsetof(struct virtio_net_config, speed),
1746*2d9fd380Sjfb8856606 &config->speed, sizeof(config->speed));
1747*2d9fd380Sjfb8856606 vtpci_read_dev_config(hw,
1748*2d9fd380Sjfb8856606 offsetof(struct virtio_net_config, duplex),
1749*2d9fd380Sjfb8856606 &config->duplex, sizeof(config->duplex));
1750*2d9fd380Sjfb8856606 hw->speed = config->speed;
1751*2d9fd380Sjfb8856606 hw->duplex = config->duplex;
1752*2d9fd380Sjfb8856606 }
1753*2d9fd380Sjfb8856606 }
1754*2d9fd380Sjfb8856606 if (hw->duplex == DUPLEX_UNKNOWN)
1755*2d9fd380Sjfb8856606 hw->duplex = ETH_LINK_FULL_DUPLEX;
1756*2d9fd380Sjfb8856606 PMD_INIT_LOG(DEBUG, "link speed = %d, duplex = %d",
1757*2d9fd380Sjfb8856606 hw->speed, hw->duplex);
1758a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ)) {
1759a9643ea8Slogwang config = &local_config;
1760a9643ea8Slogwang
1761a9643ea8Slogwang vtpci_read_dev_config(hw,
1762a9643ea8Slogwang offsetof(struct virtio_net_config, mac),
1763a9643ea8Slogwang &config->mac, sizeof(config->mac));
1764a9643ea8Slogwang
1765a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
1766a9643ea8Slogwang vtpci_read_dev_config(hw,
1767a9643ea8Slogwang offsetof(struct virtio_net_config, status),
1768a9643ea8Slogwang &config->status, sizeof(config->status));
1769a9643ea8Slogwang } else {
1770a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
1771a9643ea8Slogwang "VIRTIO_NET_F_STATUS is not supported");
1772a9643ea8Slogwang config->status = 0;
1773a9643ea8Slogwang }
1774a9643ea8Slogwang
1775a9643ea8Slogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_MQ)) {
1776a9643ea8Slogwang vtpci_read_dev_config(hw,
1777a9643ea8Slogwang offsetof(struct virtio_net_config, max_virtqueue_pairs),
1778a9643ea8Slogwang &config->max_virtqueue_pairs,
1779a9643ea8Slogwang sizeof(config->max_virtqueue_pairs));
1780a9643ea8Slogwang } else {
1781a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
1782a9643ea8Slogwang "VIRTIO_NET_F_MQ is not supported");
1783a9643ea8Slogwang config->max_virtqueue_pairs = 1;
1784a9643ea8Slogwang }
1785a9643ea8Slogwang
17862bfe3f2eSlogwang hw->max_queue_pairs = config->max_virtqueue_pairs;
1787a9643ea8Slogwang
17882bfe3f2eSlogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_MTU)) {
17892bfe3f2eSlogwang vtpci_read_dev_config(hw,
17902bfe3f2eSlogwang offsetof(struct virtio_net_config, mtu),
17912bfe3f2eSlogwang &config->mtu,
17922bfe3f2eSlogwang sizeof(config->mtu));
17932bfe3f2eSlogwang
17942bfe3f2eSlogwang /*
17952bfe3f2eSlogwang * MTU value has already been checked at negotiation
17962bfe3f2eSlogwang * time, but check again in case it has changed since
17972bfe3f2eSlogwang * then, which should not happen.
17982bfe3f2eSlogwang */
17994418919fSjohnjiang if (config->mtu < RTE_ETHER_MIN_MTU) {
18002bfe3f2eSlogwang PMD_INIT_LOG(ERR, "invalid max MTU value (%u)",
18012bfe3f2eSlogwang config->mtu);
18022bfe3f2eSlogwang return -1;
18032bfe3f2eSlogwang }
18042bfe3f2eSlogwang
18052bfe3f2eSlogwang hw->max_mtu = config->mtu;
18062bfe3f2eSlogwang /* Set initial MTU to maximum one supported by vhost */
18072bfe3f2eSlogwang eth_dev->data->mtu = config->mtu;
18082bfe3f2eSlogwang
18092bfe3f2eSlogwang } else {
18104418919fSjohnjiang hw->max_mtu = VIRTIO_MAX_RX_PKTLEN - RTE_ETHER_HDR_LEN -
18112bfe3f2eSlogwang VLAN_TAG_LEN - hw->vtnet_hdr_size;
18122bfe3f2eSlogwang }
1813a9643ea8Slogwang
1814a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "config->max_virtqueue_pairs=%d",
1815a9643ea8Slogwang config->max_virtqueue_pairs);
1816a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "config->status=%d", config->status);
1817a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
1818a9643ea8Slogwang "PORT MAC: %02X:%02X:%02X:%02X:%02X:%02X",
1819a9643ea8Slogwang config->mac[0], config->mac[1],
1820a9643ea8Slogwang config->mac[2], config->mac[3],
1821a9643ea8Slogwang config->mac[4], config->mac[5]);
1822a9643ea8Slogwang } else {
18232bfe3f2eSlogwang PMD_INIT_LOG(DEBUG, "config->max_virtqueue_pairs=1");
18242bfe3f2eSlogwang hw->max_queue_pairs = 1;
18254418919fSjohnjiang hw->max_mtu = VIRTIO_MAX_RX_PKTLEN - RTE_ETHER_HDR_LEN -
1826d30ea906Sjfb8856606 VLAN_TAG_LEN - hw->vtnet_hdr_size;
1827a9643ea8Slogwang }
1828a9643ea8Slogwang
18292bfe3f2eSlogwang ret = virtio_alloc_queues(eth_dev);
18302bfe3f2eSlogwang if (ret < 0)
18312bfe3f2eSlogwang return ret;
18322bfe3f2eSlogwang
18332bfe3f2eSlogwang if (eth_dev->data->dev_conf.intr_conf.rxq) {
18342bfe3f2eSlogwang if (virtio_configure_intr(eth_dev) < 0) {
18352bfe3f2eSlogwang PMD_INIT_LOG(ERR, "failed to configure interrupt");
18364b05018fSfengbojiang virtio_free_queues(hw);
18372bfe3f2eSlogwang return -1;
18382bfe3f2eSlogwang }
18392bfe3f2eSlogwang }
18402bfe3f2eSlogwang
18412bfe3f2eSlogwang vtpci_reinit_complete(hw);
18422bfe3f2eSlogwang
1843a9643ea8Slogwang if (pci_dev)
1844a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
1845a9643ea8Slogwang eth_dev->data->port_id, pci_dev->id.vendor_id,
1846a9643ea8Slogwang pci_dev->id.device_id);
1847a9643ea8Slogwang
18482bfe3f2eSlogwang return 0;
18492bfe3f2eSlogwang }
1850a9643ea8Slogwang
18512bfe3f2eSlogwang /*
18522bfe3f2eSlogwang * Remap the PCI device again (IO port map for legacy device and
18532bfe3f2eSlogwang * memory map for modern device), so that the secondary process
18542bfe3f2eSlogwang * could have the PCI initiated correctly.
18552bfe3f2eSlogwang */
18562bfe3f2eSlogwang static int
virtio_remap_pci(struct rte_pci_device * pci_dev,struct virtio_hw * hw)18572bfe3f2eSlogwang virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_hw *hw)
18582bfe3f2eSlogwang {
18592bfe3f2eSlogwang if (hw->modern) {
18602bfe3f2eSlogwang /*
18612bfe3f2eSlogwang * We don't have to re-parse the PCI config space, since
18622bfe3f2eSlogwang * rte_pci_map_device() makes sure the mapped address
18632bfe3f2eSlogwang * in secondary process would equal to the one mapped in
18642bfe3f2eSlogwang * the primary process: error will be returned if that
18652bfe3f2eSlogwang * requirement is not met.
18662bfe3f2eSlogwang *
18672bfe3f2eSlogwang * That said, we could simply reuse all cap pointers
18682bfe3f2eSlogwang * (such as dev_cfg, common_cfg, etc.) parsed from the
18692bfe3f2eSlogwang * primary process, which is stored in shared memory.
18702bfe3f2eSlogwang */
18712bfe3f2eSlogwang if (rte_pci_map_device(pci_dev)) {
18722bfe3f2eSlogwang PMD_INIT_LOG(DEBUG, "failed to map pci device!");
18732bfe3f2eSlogwang return -1;
18742bfe3f2eSlogwang }
18752bfe3f2eSlogwang } else {
18762bfe3f2eSlogwang if (rte_pci_ioport_map(pci_dev, 0, VTPCI_IO(hw)) < 0)
18772bfe3f2eSlogwang return -1;
18782bfe3f2eSlogwang }
1879a9643ea8Slogwang
1880a9643ea8Slogwang return 0;
1881a9643ea8Slogwang }
1882a9643ea8Slogwang
18832bfe3f2eSlogwang static void
virtio_set_vtpci_ops(struct virtio_hw * hw)18842bfe3f2eSlogwang virtio_set_vtpci_ops(struct virtio_hw *hw)
18852bfe3f2eSlogwang {
18862bfe3f2eSlogwang #ifdef RTE_VIRTIO_USER
18872bfe3f2eSlogwang if (hw->virtio_user_dev)
18882bfe3f2eSlogwang VTPCI_OPS(hw) = &virtio_user_ops;
18892bfe3f2eSlogwang else
18902bfe3f2eSlogwang #endif
18912bfe3f2eSlogwang if (hw->modern)
18922bfe3f2eSlogwang VTPCI_OPS(hw) = &modern_ops;
18932bfe3f2eSlogwang else
18942bfe3f2eSlogwang VTPCI_OPS(hw) = &legacy_ops;
18952bfe3f2eSlogwang }
18962bfe3f2eSlogwang
18972bfe3f2eSlogwang /*
18982bfe3f2eSlogwang * This function is based on probe() function in virtio_pci.c
18992bfe3f2eSlogwang * It returns 0 on success.
19002bfe3f2eSlogwang */
19012bfe3f2eSlogwang int
eth_virtio_dev_init(struct rte_eth_dev * eth_dev)19022bfe3f2eSlogwang eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
19032bfe3f2eSlogwang {
19042bfe3f2eSlogwang struct virtio_hw *hw = eth_dev->data->dev_private;
1905*2d9fd380Sjfb8856606 uint32_t speed = ETH_SPEED_NUM_UNKNOWN;
1906*2d9fd380Sjfb8856606 int vectorized = 0;
19072bfe3f2eSlogwang int ret;
19082bfe3f2eSlogwang
19094b05018fSfengbojiang if (sizeof(struct virtio_net_hdr_mrg_rxbuf) > RTE_PKTMBUF_HEADROOM) {
19104b05018fSfengbojiang PMD_INIT_LOG(ERR,
19114b05018fSfengbojiang "Not sufficient headroom required = %d, avail = %d",
19124b05018fSfengbojiang (int)sizeof(struct virtio_net_hdr_mrg_rxbuf),
19134b05018fSfengbojiang RTE_PKTMBUF_HEADROOM);
19144b05018fSfengbojiang
19154b05018fSfengbojiang return -1;
19164b05018fSfengbojiang }
19172bfe3f2eSlogwang
19182bfe3f2eSlogwang eth_dev->dev_ops = &virtio_eth_dev_ops;
1919*2d9fd380Sjfb8856606 eth_dev->rx_descriptor_done = virtio_dev_rx_queue_done;
19202bfe3f2eSlogwang
19212bfe3f2eSlogwang if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
19222bfe3f2eSlogwang if (!hw->virtio_user_dev) {
19232bfe3f2eSlogwang ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_dev), hw);
19242bfe3f2eSlogwang if (ret)
19252bfe3f2eSlogwang return ret;
19262bfe3f2eSlogwang }
19272bfe3f2eSlogwang
19282bfe3f2eSlogwang virtio_set_vtpci_ops(hw);
19292bfe3f2eSlogwang set_rxtx_funcs(eth_dev);
19302bfe3f2eSlogwang
19312bfe3f2eSlogwang return 0;
19322bfe3f2eSlogwang }
1933*2d9fd380Sjfb8856606 ret = virtio_dev_devargs_parse(eth_dev->device->devargs,
1934*2d9fd380Sjfb8856606 NULL, &speed, &vectorized);
1935*2d9fd380Sjfb8856606 if (ret < 0)
1936*2d9fd380Sjfb8856606 return ret;
1937*2d9fd380Sjfb8856606 hw->speed = speed;
19384418919fSjohnjiang
19392bfe3f2eSlogwang /* Allocate memory for storing MAC addresses */
19404418919fSjohnjiang eth_dev->data->mac_addrs = rte_zmalloc("virtio",
19414418919fSjohnjiang VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN, 0);
19422bfe3f2eSlogwang if (eth_dev->data->mac_addrs == NULL) {
19432bfe3f2eSlogwang PMD_INIT_LOG(ERR,
19442bfe3f2eSlogwang "Failed to allocate %d bytes needed to store MAC addresses",
19454418919fSjohnjiang VIRTIO_MAX_MAC_ADDRS * RTE_ETHER_ADDR_LEN);
19462bfe3f2eSlogwang return -ENOMEM;
19472bfe3f2eSlogwang }
19482bfe3f2eSlogwang
19492bfe3f2eSlogwang hw->port_id = eth_dev->data->port_id;
19502bfe3f2eSlogwang /* For virtio_user case the hw->virtio_user_dev is populated by
19512bfe3f2eSlogwang * virtio_user_eth_dev_alloc() before eth_virtio_dev_init() is called.
19522bfe3f2eSlogwang */
19532bfe3f2eSlogwang if (!hw->virtio_user_dev) {
19542bfe3f2eSlogwang ret = vtpci_init(RTE_ETH_DEV_TO_PCI(eth_dev), hw);
19552bfe3f2eSlogwang if (ret)
19564b05018fSfengbojiang goto err_vtpci_init;
19572bfe3f2eSlogwang }
19582bfe3f2eSlogwang
19594418919fSjohnjiang rte_spinlock_init(&hw->state_lock);
19604418919fSjohnjiang
19612bfe3f2eSlogwang /* reset device and negotiate default features */
19622bfe3f2eSlogwang ret = virtio_init_device(eth_dev, VIRTIO_PMD_DEFAULT_GUEST_FEATURES);
19632bfe3f2eSlogwang if (ret < 0)
19644b05018fSfengbojiang goto err_virtio_init;
19652bfe3f2eSlogwang
1966*2d9fd380Sjfb8856606 if (vectorized) {
1967*2d9fd380Sjfb8856606 if (!vtpci_packed_queue(hw)) {
1968*2d9fd380Sjfb8856606 hw->use_vec_rx = 1;
1969*2d9fd380Sjfb8856606 } else {
1970*2d9fd380Sjfb8856606 #if !defined(CC_AVX512_SUPPORT)
1971*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
1972*2d9fd380Sjfb8856606 "building environment do not support packed ring vectorized");
1973*2d9fd380Sjfb8856606 #else
1974*2d9fd380Sjfb8856606 hw->use_vec_rx = 1;
1975*2d9fd380Sjfb8856606 hw->use_vec_tx = 1;
1976*2d9fd380Sjfb8856606 #endif
1977*2d9fd380Sjfb8856606 }
1978*2d9fd380Sjfb8856606 }
1979*2d9fd380Sjfb8856606
19804418919fSjohnjiang hw->opened = true;
19814418919fSjohnjiang
19822bfe3f2eSlogwang return 0;
19832bfe3f2eSlogwang
19844b05018fSfengbojiang err_virtio_init:
19854b05018fSfengbojiang if (!hw->virtio_user_dev) {
19864b05018fSfengbojiang rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev));
19874b05018fSfengbojiang if (!hw->modern)
19884b05018fSfengbojiang rte_pci_ioport_unmap(VTPCI_IO(hw));
19894b05018fSfengbojiang }
19904b05018fSfengbojiang err_vtpci_init:
19912bfe3f2eSlogwang rte_free(eth_dev->data->mac_addrs);
19921646932aSjfb8856606 eth_dev->data->mac_addrs = NULL;
19932bfe3f2eSlogwang return ret;
19942bfe3f2eSlogwang }
19952bfe3f2eSlogwang
1996a9643ea8Slogwang static int
eth_virtio_dev_uninit(struct rte_eth_dev * eth_dev)1997a9643ea8Slogwang eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
1998a9643ea8Slogwang {
1999*2d9fd380Sjfb8856606 int ret;
2000a9643ea8Slogwang PMD_INIT_FUNC_TRACE();
2001a9643ea8Slogwang
2002a9643ea8Slogwang if (rte_eal_process_type() == RTE_PROC_SECONDARY)
2003d30ea906Sjfb8856606 return 0;
2004a9643ea8Slogwang
2005*2d9fd380Sjfb8856606 ret = virtio_dev_stop(eth_dev);
2006a9643ea8Slogwang virtio_dev_close(eth_dev);
2007a9643ea8Slogwang
2008a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "dev_uninit completed");
2009a9643ea8Slogwang
2010*2d9fd380Sjfb8856606 return ret;
2011a9643ea8Slogwang }
2012a9643ea8Slogwang
2013*2d9fd380Sjfb8856606
vdpa_check_handler(__rte_unused const char * key,const char * value,void * ret_val)2014d30ea906Sjfb8856606 static int vdpa_check_handler(__rte_unused const char *key,
2015*2d9fd380Sjfb8856606 const char *value, void *ret_val)
2016d30ea906Sjfb8856606 {
2017*2d9fd380Sjfb8856606 if (strcmp(value, "1") == 0)
2018*2d9fd380Sjfb8856606 *(int *)ret_val = 1;
2019*2d9fd380Sjfb8856606 else
2020*2d9fd380Sjfb8856606 *(int *)ret_val = 0;
2021d30ea906Sjfb8856606
2022d30ea906Sjfb8856606 return 0;
2023d30ea906Sjfb8856606 }
2024d30ea906Sjfb8856606
2025*2d9fd380Sjfb8856606
2026*2d9fd380Sjfb8856606 static uint32_t
virtio_dev_speed_capa_get(uint32_t speed)2027*2d9fd380Sjfb8856606 virtio_dev_speed_capa_get(uint32_t speed)
2028*2d9fd380Sjfb8856606 {
2029*2d9fd380Sjfb8856606 switch (speed) {
2030*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_10G:
2031*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_10G;
2032*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_20G:
2033*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_20G;
2034*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_25G:
2035*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_25G;
2036*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_40G:
2037*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_40G;
2038*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_50G:
2039*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_50G;
2040*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_56G:
2041*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_56G;
2042*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_100G:
2043*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_100G;
2044*2d9fd380Sjfb8856606 case ETH_SPEED_NUM_200G:
2045*2d9fd380Sjfb8856606 return ETH_LINK_SPEED_200G;
2046*2d9fd380Sjfb8856606 default:
2047*2d9fd380Sjfb8856606 return 0;
2048*2d9fd380Sjfb8856606 }
2049*2d9fd380Sjfb8856606 }
2050*2d9fd380Sjfb8856606
vectorized_check_handler(__rte_unused const char * key,const char * value,void * ret_val)2051*2d9fd380Sjfb8856606 static int vectorized_check_handler(__rte_unused const char *key,
2052*2d9fd380Sjfb8856606 const char *value, void *ret_val)
2053*2d9fd380Sjfb8856606 {
2054*2d9fd380Sjfb8856606 if (strcmp(value, "1") == 0)
2055*2d9fd380Sjfb8856606 *(int *)ret_val = 1;
2056*2d9fd380Sjfb8856606 else
2057*2d9fd380Sjfb8856606 *(int *)ret_val = 0;
2058*2d9fd380Sjfb8856606
2059*2d9fd380Sjfb8856606 return 0;
2060*2d9fd380Sjfb8856606 }
2061*2d9fd380Sjfb8856606
2062*2d9fd380Sjfb8856606 #define VIRTIO_ARG_SPEED "speed"
2063*2d9fd380Sjfb8856606 #define VIRTIO_ARG_VDPA "vdpa"
2064*2d9fd380Sjfb8856606 #define VIRTIO_ARG_VECTORIZED "vectorized"
2065*2d9fd380Sjfb8856606
2066*2d9fd380Sjfb8856606
2067d30ea906Sjfb8856606 static int
link_speed_handler(const char * key __rte_unused,const char * value,void * ret_val)2068*2d9fd380Sjfb8856606 link_speed_handler(const char *key __rte_unused,
2069*2d9fd380Sjfb8856606 const char *value, void *ret_val)
2070*2d9fd380Sjfb8856606 {
2071*2d9fd380Sjfb8856606 uint32_t val;
2072*2d9fd380Sjfb8856606 if (!value || !ret_val)
2073*2d9fd380Sjfb8856606 return -EINVAL;
2074*2d9fd380Sjfb8856606 val = strtoul(value, NULL, 0);
2075*2d9fd380Sjfb8856606 /* validate input */
2076*2d9fd380Sjfb8856606 if (virtio_dev_speed_capa_get(val) == 0)
2077*2d9fd380Sjfb8856606 return -EINVAL;
2078*2d9fd380Sjfb8856606 *(uint32_t *)ret_val = val;
2079*2d9fd380Sjfb8856606
2080*2d9fd380Sjfb8856606 return 0;
2081*2d9fd380Sjfb8856606 }
2082*2d9fd380Sjfb8856606
2083*2d9fd380Sjfb8856606
2084*2d9fd380Sjfb8856606 static int
virtio_dev_devargs_parse(struct rte_devargs * devargs,int * vdpa,uint32_t * speed,int * vectorized)2085*2d9fd380Sjfb8856606 virtio_dev_devargs_parse(struct rte_devargs *devargs, int *vdpa,
2086*2d9fd380Sjfb8856606 uint32_t *speed, int *vectorized)
2087d30ea906Sjfb8856606 {
2088d30ea906Sjfb8856606 struct rte_kvargs *kvlist;
2089d30ea906Sjfb8856606 int ret = 0;
2090d30ea906Sjfb8856606
2091d30ea906Sjfb8856606 if (devargs == NULL)
2092d30ea906Sjfb8856606 return 0;
2093d30ea906Sjfb8856606
2094d30ea906Sjfb8856606 kvlist = rte_kvargs_parse(devargs->args, NULL);
2095*2d9fd380Sjfb8856606 if (kvlist == NULL) {
2096*2d9fd380Sjfb8856606 PMD_INIT_LOG(ERR, "error when parsing param");
2097d30ea906Sjfb8856606 return 0;
2098*2d9fd380Sjfb8856606 }
2099*2d9fd380Sjfb8856606 if (vdpa && rte_kvargs_count(kvlist, VIRTIO_ARG_VDPA) == 1) {
2100*2d9fd380Sjfb8856606 /* vdpa mode selected when there's a key-value pair:
2101*2d9fd380Sjfb8856606 * vdpa=1
2102*2d9fd380Sjfb8856606 */
2103*2d9fd380Sjfb8856606 ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA,
2104*2d9fd380Sjfb8856606 vdpa_check_handler, vdpa);
2105*2d9fd380Sjfb8856606 if (ret < 0) {
2106*2d9fd380Sjfb8856606 PMD_INIT_LOG(ERR, "Failed to parse %s",
2107*2d9fd380Sjfb8856606 VIRTIO_ARG_VDPA);
2108d30ea906Sjfb8856606 goto exit;
2109d30ea906Sjfb8856606 }
2110*2d9fd380Sjfb8856606 }
2111*2d9fd380Sjfb8856606 if (speed && rte_kvargs_count(kvlist, VIRTIO_ARG_SPEED) == 1) {
2112*2d9fd380Sjfb8856606 ret = rte_kvargs_process(kvlist,
2113*2d9fd380Sjfb8856606 VIRTIO_ARG_SPEED,
2114*2d9fd380Sjfb8856606 link_speed_handler, speed);
2115*2d9fd380Sjfb8856606 if (ret < 0) {
2116*2d9fd380Sjfb8856606 PMD_INIT_LOG(ERR, "Failed to parse %s",
2117*2d9fd380Sjfb8856606 VIRTIO_ARG_SPEED);
2118*2d9fd380Sjfb8856606 goto exit;
2119*2d9fd380Sjfb8856606 }
2120*2d9fd380Sjfb8856606 }
2121*2d9fd380Sjfb8856606
2122*2d9fd380Sjfb8856606 if (vectorized &&
2123*2d9fd380Sjfb8856606 rte_kvargs_count(kvlist, VIRTIO_ARG_VECTORIZED) == 1) {
2124*2d9fd380Sjfb8856606 ret = rte_kvargs_process(kvlist,
2125*2d9fd380Sjfb8856606 VIRTIO_ARG_VECTORIZED,
2126*2d9fd380Sjfb8856606 vectorized_check_handler, vectorized);
2127*2d9fd380Sjfb8856606 if (ret < 0) {
2128*2d9fd380Sjfb8856606 PMD_INIT_LOG(ERR, "Failed to parse %s",
2129*2d9fd380Sjfb8856606 VIRTIO_ARG_VECTORIZED);
2130*2d9fd380Sjfb8856606 goto exit;
2131*2d9fd380Sjfb8856606 }
2132*2d9fd380Sjfb8856606 }
2133d30ea906Sjfb8856606
2134d30ea906Sjfb8856606 exit:
2135d30ea906Sjfb8856606 rte_kvargs_free(kvlist);
2136d30ea906Sjfb8856606 return ret;
2137d30ea906Sjfb8856606 }
2138d30ea906Sjfb8856606
eth_virtio_pci_probe(struct rte_pci_driver * pci_drv __rte_unused,struct rte_pci_device * pci_dev)21392bfe3f2eSlogwang static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
21402bfe3f2eSlogwang struct rte_pci_device *pci_dev)
21412bfe3f2eSlogwang {
2142*2d9fd380Sjfb8856606 int vdpa = 0;
2143*2d9fd380Sjfb8856606 int ret = 0;
2144*2d9fd380Sjfb8856606
2145*2d9fd380Sjfb8856606 ret = virtio_dev_devargs_parse(pci_dev->device.devargs, &vdpa, NULL,
2146*2d9fd380Sjfb8856606 NULL);
2147*2d9fd380Sjfb8856606 if (ret < 0) {
2148*2d9fd380Sjfb8856606 PMD_INIT_LOG(ERR, "devargs parsing is failed");
2149*2d9fd380Sjfb8856606 return ret;
2150*2d9fd380Sjfb8856606 }
2151d30ea906Sjfb8856606 /* virtio pmd skips probe if device needs to work in vdpa mode */
2152*2d9fd380Sjfb8856606 if (vdpa == 1)
2153d30ea906Sjfb8856606 return 1;
2154d30ea906Sjfb8856606
21552bfe3f2eSlogwang return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_hw),
21562bfe3f2eSlogwang eth_virtio_dev_init);
21572bfe3f2eSlogwang }
21582bfe3f2eSlogwang
eth_virtio_pci_remove(struct rte_pci_device * pci_dev)21592bfe3f2eSlogwang static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev)
21602bfe3f2eSlogwang {
21614418919fSjohnjiang int ret;
21624418919fSjohnjiang
21634418919fSjohnjiang ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_dev_uninit);
21644418919fSjohnjiang /* Port has already been released by close. */
21654418919fSjohnjiang if (ret == -ENODEV)
21664418919fSjohnjiang ret = 0;
21674418919fSjohnjiang return ret;
21682bfe3f2eSlogwang }
21692bfe3f2eSlogwang
21702bfe3f2eSlogwang static struct rte_pci_driver rte_virtio_pmd = {
21712bfe3f2eSlogwang .driver = {
21722bfe3f2eSlogwang .name = "net_virtio",
2173a9643ea8Slogwang },
21742bfe3f2eSlogwang .id_table = pci_id_virtio_map,
21752bfe3f2eSlogwang .drv_flags = 0,
21762bfe3f2eSlogwang .probe = eth_virtio_pci_probe,
21772bfe3f2eSlogwang .remove = eth_virtio_pci_remove,
2178a9643ea8Slogwang };
2179a9643ea8Slogwang
RTE_INIT(rte_virtio_pmd_init)2180d30ea906Sjfb8856606 RTE_INIT(rte_virtio_pmd_init)
2181a9643ea8Slogwang {
2182d30ea906Sjfb8856606 rte_eal_iopl_init();
2183d30ea906Sjfb8856606 rte_pci_register(&rte_virtio_pmd);
21845af785ecSfengbojiang(姜凤波) }
21855af785ecSfengbojiang(姜凤波)
2186d30ea906Sjfb8856606 static bool
rx_offload_enabled(struct virtio_hw * hw)2187d30ea906Sjfb8856606 rx_offload_enabled(struct virtio_hw *hw)
2188d30ea906Sjfb8856606 {
2189d30ea906Sjfb8856606 return vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM) ||
2190d30ea906Sjfb8856606 vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
2191d30ea906Sjfb8856606 vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6);
2192d30ea906Sjfb8856606 }
2193d30ea906Sjfb8856606
2194d30ea906Sjfb8856606 static bool
tx_offload_enabled(struct virtio_hw * hw)2195d30ea906Sjfb8856606 tx_offload_enabled(struct virtio_hw *hw)
2196d30ea906Sjfb8856606 {
2197d30ea906Sjfb8856606 return vtpci_with_feature(hw, VIRTIO_NET_F_CSUM) ||
2198d30ea906Sjfb8856606 vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO4) ||
2199d30ea906Sjfb8856606 vtpci_with_feature(hw, VIRTIO_NET_F_HOST_TSO6);
2200a9643ea8Slogwang }
2201a9643ea8Slogwang
2202a9643ea8Slogwang /*
2203a9643ea8Slogwang * Configure virtio device
2204a9643ea8Slogwang * It returns 0 on success.
2205a9643ea8Slogwang */
2206a9643ea8Slogwang static int
virtio_dev_configure(struct rte_eth_dev * dev)2207a9643ea8Slogwang virtio_dev_configure(struct rte_eth_dev *dev)
2208a9643ea8Slogwang {
2209a9643ea8Slogwang const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
2210d30ea906Sjfb8856606 const struct rte_eth_txmode *txmode = &dev->data->dev_conf.txmode;
2211a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
22124418919fSjohnjiang uint32_t ether_hdr_len = RTE_ETHER_HDR_LEN + VLAN_TAG_LEN +
22131646932aSjfb8856606 hw->vtnet_hdr_size;
2214d30ea906Sjfb8856606 uint64_t rx_offloads = rxmode->offloads;
2215d30ea906Sjfb8856606 uint64_t tx_offloads = txmode->offloads;
22162bfe3f2eSlogwang uint64_t req_features;
22172bfe3f2eSlogwang int ret;
2218a9643ea8Slogwang
2219a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "configure");
22202bfe3f2eSlogwang req_features = VIRTIO_PMD_DEFAULT_GUEST_FEATURES;
2221a9643ea8Slogwang
22224418919fSjohnjiang if (rxmode->mq_mode != ETH_MQ_RX_NONE) {
22234418919fSjohnjiang PMD_DRV_LOG(ERR,
22244418919fSjohnjiang "Unsupported Rx multi queue mode %d",
22254418919fSjohnjiang rxmode->mq_mode);
22264418919fSjohnjiang return -EINVAL;
22274418919fSjohnjiang }
22284418919fSjohnjiang
22294418919fSjohnjiang if (txmode->mq_mode != ETH_MQ_TX_NONE) {
22304418919fSjohnjiang PMD_DRV_LOG(ERR,
22314418919fSjohnjiang "Unsupported Tx multi queue mode %d",
22324418919fSjohnjiang txmode->mq_mode);
22334418919fSjohnjiang return -EINVAL;
22344418919fSjohnjiang }
22354418919fSjohnjiang
22362bfe3f2eSlogwang if (dev->data->dev_conf.intr_conf.rxq) {
22372bfe3f2eSlogwang ret = virtio_init_device(dev, hw->req_guest_features);
22382bfe3f2eSlogwang if (ret < 0)
22392bfe3f2eSlogwang return ret;
2240a9643ea8Slogwang }
2241a9643ea8Slogwang
22421646932aSjfb8856606 if (rxmode->max_rx_pkt_len > hw->max_mtu + ether_hdr_len)
22431646932aSjfb8856606 req_features &= ~(1ULL << VIRTIO_NET_F_MTU);
22441646932aSjfb8856606
2245d30ea906Sjfb8856606 if (rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM |
2246d30ea906Sjfb8856606 DEV_RX_OFFLOAD_TCP_CKSUM))
22472bfe3f2eSlogwang req_features |= (1ULL << VIRTIO_NET_F_GUEST_CSUM);
22482bfe3f2eSlogwang
2249d30ea906Sjfb8856606 if (rx_offloads & DEV_RX_OFFLOAD_TCP_LRO)
22502bfe3f2eSlogwang req_features |=
22512bfe3f2eSlogwang (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
22522bfe3f2eSlogwang (1ULL << VIRTIO_NET_F_GUEST_TSO6);
22532bfe3f2eSlogwang
2254d30ea906Sjfb8856606 if (tx_offloads & (DEV_TX_OFFLOAD_UDP_CKSUM |
2255d30ea906Sjfb8856606 DEV_TX_OFFLOAD_TCP_CKSUM))
2256d30ea906Sjfb8856606 req_features |= (1ULL << VIRTIO_NET_F_CSUM);
2257d30ea906Sjfb8856606
2258d30ea906Sjfb8856606 if (tx_offloads & DEV_TX_OFFLOAD_TCP_TSO)
2259d30ea906Sjfb8856606 req_features |=
2260d30ea906Sjfb8856606 (1ULL << VIRTIO_NET_F_HOST_TSO4) |
2261d30ea906Sjfb8856606 (1ULL << VIRTIO_NET_F_HOST_TSO6);
2262d30ea906Sjfb8856606
22632bfe3f2eSlogwang /* if request features changed, reinit the device */
22642bfe3f2eSlogwang if (req_features != hw->req_guest_features) {
22652bfe3f2eSlogwang ret = virtio_init_device(dev, req_features);
22662bfe3f2eSlogwang if (ret < 0)
22672bfe3f2eSlogwang return ret;
22682bfe3f2eSlogwang }
22692bfe3f2eSlogwang
2270d30ea906Sjfb8856606 if ((rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM |
2271d30ea906Sjfb8856606 DEV_RX_OFFLOAD_TCP_CKSUM)) &&
22722bfe3f2eSlogwang !vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_CSUM)) {
22732bfe3f2eSlogwang PMD_DRV_LOG(ERR,
22742bfe3f2eSlogwang "rx checksum not available on this host");
22752bfe3f2eSlogwang return -ENOTSUP;
22762bfe3f2eSlogwang }
22772bfe3f2eSlogwang
2278d30ea906Sjfb8856606 if ((rx_offloads & DEV_RX_OFFLOAD_TCP_LRO) &&
22792bfe3f2eSlogwang (!vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO4) ||
22802bfe3f2eSlogwang !vtpci_with_feature(hw, VIRTIO_NET_F_GUEST_TSO6))) {
22812bfe3f2eSlogwang PMD_DRV_LOG(ERR,
22822bfe3f2eSlogwang "Large Receive Offload not available on this host");
22832bfe3f2eSlogwang return -ENOTSUP;
22842bfe3f2eSlogwang }
22852bfe3f2eSlogwang
22862bfe3f2eSlogwang /* start control queue */
22872bfe3f2eSlogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ))
22882bfe3f2eSlogwang virtio_dev_cq_start(dev);
22892bfe3f2eSlogwang
2290d30ea906Sjfb8856606 if (rx_offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
2291d30ea906Sjfb8856606 hw->vlan_strip = 1;
2292a9643ea8Slogwang
2293d30ea906Sjfb8856606 if ((rx_offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
2294a9643ea8Slogwang && !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) {
22952bfe3f2eSlogwang PMD_DRV_LOG(ERR,
2296a9643ea8Slogwang "vlan filtering not available on this host");
2297a9643ea8Slogwang return -ENOTSUP;
2298a9643ea8Slogwang }
2299a9643ea8Slogwang
2300d30ea906Sjfb8856606 hw->has_tx_offload = tx_offload_enabled(hw);
2301d30ea906Sjfb8856606 hw->has_rx_offload = rx_offload_enabled(hw);
2302d30ea906Sjfb8856606
2303a9643ea8Slogwang if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
23042bfe3f2eSlogwang /* Enable vector (0) for Link State Intrerrupt */
23052bfe3f2eSlogwang if (VTPCI_OPS(hw)->set_config_irq(hw, 0) ==
23062bfe3f2eSlogwang VIRTIO_MSI_NO_VECTOR) {
2307a9643ea8Slogwang PMD_DRV_LOG(ERR, "failed to set config vector");
2308a9643ea8Slogwang return -EBUSY;
2309a9643ea8Slogwang }
2310a9643ea8Slogwang
2311*2d9fd380Sjfb8856606 if (vtpci_packed_queue(hw)) {
2312*2d9fd380Sjfb8856606 #if defined(RTE_ARCH_X86_64) && defined(CC_AVX512_SUPPORT)
2313*2d9fd380Sjfb8856606 if ((hw->use_vec_rx || hw->use_vec_tx) &&
2314*2d9fd380Sjfb8856606 (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) ||
2315*2d9fd380Sjfb8856606 !vtpci_with_feature(hw, VIRTIO_F_IN_ORDER) ||
2316*2d9fd380Sjfb8856606 !vtpci_with_feature(hw, VIRTIO_F_VERSION_1) ||
2317*2d9fd380Sjfb8856606 rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_512)) {
2318*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2319*2d9fd380Sjfb8856606 "disabled packed ring vectorized path for requirements not met");
2320*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2321*2d9fd380Sjfb8856606 hw->use_vec_tx = 0;
2322*2d9fd380Sjfb8856606 }
2323*2d9fd380Sjfb8856606 #else
2324*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2325*2d9fd380Sjfb8856606 hw->use_vec_tx = 0;
2326*2d9fd380Sjfb8856606 #endif
2327d30ea906Sjfb8856606
2328*2d9fd380Sjfb8856606 if (hw->use_vec_rx) {
2329*2d9fd380Sjfb8856606 if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
2330*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2331*2d9fd380Sjfb8856606 "disabled packed ring vectorized rx for mrg_rxbuf enabled");
2332*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2333*2d9fd380Sjfb8856606 }
2334*2d9fd380Sjfb8856606
2335*2d9fd380Sjfb8856606 if (rx_offloads & DEV_RX_OFFLOAD_TCP_LRO) {
2336*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2337*2d9fd380Sjfb8856606 "disabled packed ring vectorized rx for TCP_LRO enabled");
2338*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2339*2d9fd380Sjfb8856606 }
2340*2d9fd380Sjfb8856606 }
2341*2d9fd380Sjfb8856606 } else {
2342d30ea906Sjfb8856606 if (vtpci_with_feature(hw, VIRTIO_F_IN_ORDER)) {
2343d30ea906Sjfb8856606 hw->use_inorder_tx = 1;
2344d30ea906Sjfb8856606 hw->use_inorder_rx = 1;
2345*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2346d30ea906Sjfb8856606 }
23474418919fSjohnjiang
2348*2d9fd380Sjfb8856606 if (hw->use_vec_rx) {
2349*2d9fd380Sjfb8856606 #if defined RTE_ARCH_ARM
23502bfe3f2eSlogwang if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON)) {
2351*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2352*2d9fd380Sjfb8856606 "disabled split ring vectorized path for requirement not met");
2353*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
23542bfe3f2eSlogwang }
23552bfe3f2eSlogwang #endif
23562bfe3f2eSlogwang if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
2357*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2358*2d9fd380Sjfb8856606 "disabled split ring vectorized rx for mrg_rxbuf enabled");
2359*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
23602bfe3f2eSlogwang }
23612bfe3f2eSlogwang
2362d30ea906Sjfb8856606 if (rx_offloads & (DEV_RX_OFFLOAD_UDP_CKSUM |
2363d30ea906Sjfb8856606 DEV_RX_OFFLOAD_TCP_CKSUM |
2364d30ea906Sjfb8856606 DEV_RX_OFFLOAD_TCP_LRO |
2365*2d9fd380Sjfb8856606 DEV_RX_OFFLOAD_VLAN_STRIP)) {
2366*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2367*2d9fd380Sjfb8856606 "disabled split ring vectorized rx for offloading enabled");
2368*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2369*2d9fd380Sjfb8856606 }
2370*2d9fd380Sjfb8856606
2371*2d9fd380Sjfb8856606 if (rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_128) {
2372*2d9fd380Sjfb8856606 PMD_DRV_LOG(INFO,
2373*2d9fd380Sjfb8856606 "disabled split ring vectorized rx, max SIMD bitwidth too low");
2374*2d9fd380Sjfb8856606 hw->use_vec_rx = 0;
2375*2d9fd380Sjfb8856606 }
2376*2d9fd380Sjfb8856606 }
2377*2d9fd380Sjfb8856606 }
23782bfe3f2eSlogwang
2379a9643ea8Slogwang return 0;
2380a9643ea8Slogwang }
2381a9643ea8Slogwang
2382a9643ea8Slogwang
2383a9643ea8Slogwang static int
virtio_dev_start(struct rte_eth_dev * dev)2384a9643ea8Slogwang virtio_dev_start(struct rte_eth_dev *dev)
2385a9643ea8Slogwang {
2386a9643ea8Slogwang uint16_t nb_queues, i;
2387a9643ea8Slogwang struct virtnet_rx *rxvq;
2388a9643ea8Slogwang struct virtnet_tx *txvq __rte_unused;
23892bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
23902bfe3f2eSlogwang int ret;
23912bfe3f2eSlogwang
23922bfe3f2eSlogwang /* Finish the initialization of the queues */
23932bfe3f2eSlogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
23942bfe3f2eSlogwang ret = virtio_dev_rx_queue_setup_finish(dev, i);
23952bfe3f2eSlogwang if (ret < 0)
23962bfe3f2eSlogwang return ret;
23972bfe3f2eSlogwang }
23982bfe3f2eSlogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
23992bfe3f2eSlogwang ret = virtio_dev_tx_queue_setup_finish(dev, i);
24002bfe3f2eSlogwang if (ret < 0)
24012bfe3f2eSlogwang return ret;
24022bfe3f2eSlogwang }
2403a9643ea8Slogwang
2404a9643ea8Slogwang /* check if lsc interrupt feature is enabled */
2405a9643ea8Slogwang if (dev->data->dev_conf.intr_conf.lsc) {
2406a9643ea8Slogwang if (!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)) {
2407a9643ea8Slogwang PMD_DRV_LOG(ERR, "link status not supported by host");
2408a9643ea8Slogwang return -ENOTSUP;
2409a9643ea8Slogwang }
24102bfe3f2eSlogwang }
2411a9643ea8Slogwang
24122bfe3f2eSlogwang /* Enable uio/vfio intr/eventfd mapping: althrough we already did that
24132bfe3f2eSlogwang * in device configure, but it could be unmapped when device is
24142bfe3f2eSlogwang * stopped.
24152bfe3f2eSlogwang */
24162bfe3f2eSlogwang if (dev->data->dev_conf.intr_conf.lsc ||
24172bfe3f2eSlogwang dev->data->dev_conf.intr_conf.rxq) {
24182bfe3f2eSlogwang virtio_intr_disable(dev);
24192bfe3f2eSlogwang
2420d30ea906Sjfb8856606 /* Setup interrupt callback */
2421d30ea906Sjfb8856606 if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
2422d30ea906Sjfb8856606 rte_intr_callback_register(dev->intr_handle,
2423d30ea906Sjfb8856606 virtio_interrupt_handler,
2424d30ea906Sjfb8856606 dev);
2425d30ea906Sjfb8856606
24262bfe3f2eSlogwang if (virtio_intr_enable(dev) < 0) {
2427a9643ea8Slogwang PMD_DRV_LOG(ERR, "interrupt enable failed");
2428a9643ea8Slogwang return -EIO;
2429a9643ea8Slogwang }
2430a9643ea8Slogwang }
2431a9643ea8Slogwang
2432a9643ea8Slogwang /*Notify the backend
2433a9643ea8Slogwang *Otherwise the tap backend might already stop its queue due to fullness.
2434a9643ea8Slogwang *vhost backend will have no chance to be waked up
2435a9643ea8Slogwang */
24362bfe3f2eSlogwang nb_queues = RTE_MAX(dev->data->nb_rx_queues, dev->data->nb_tx_queues);
24372bfe3f2eSlogwang if (hw->max_queue_pairs > 1) {
2438a9643ea8Slogwang if (virtio_set_multiple_queues(dev, nb_queues) != 0)
2439a9643ea8Slogwang return -EINVAL;
2440a9643ea8Slogwang }
2441a9643ea8Slogwang
2442a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "nb_queues=%d", nb_queues);
2443a9643ea8Slogwang
24442bfe3f2eSlogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
2445a9643ea8Slogwang rxvq = dev->data->rx_queues[i];
24462bfe3f2eSlogwang /* Flush the old packets */
24472bfe3f2eSlogwang virtqueue_rxvq_flush(rxvq->vq);
2448a9643ea8Slogwang virtqueue_notify(rxvq->vq);
2449a9643ea8Slogwang }
2450a9643ea8Slogwang
24512bfe3f2eSlogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
24522bfe3f2eSlogwang txvq = dev->data->tx_queues[i];
24532bfe3f2eSlogwang virtqueue_notify(txvq->vq);
24542bfe3f2eSlogwang }
24552bfe3f2eSlogwang
2456a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "Notified backend at initialization");
2457a9643ea8Slogwang
2458a9643ea8Slogwang for (i = 0; i < dev->data->nb_rx_queues; i++) {
2459a9643ea8Slogwang rxvq = dev->data->rx_queues[i];
2460a9643ea8Slogwang VIRTQUEUE_DUMP(rxvq->vq);
2461a9643ea8Slogwang }
2462a9643ea8Slogwang
2463a9643ea8Slogwang for (i = 0; i < dev->data->nb_tx_queues; i++) {
2464a9643ea8Slogwang txvq = dev->data->tx_queues[i];
2465a9643ea8Slogwang VIRTQUEUE_DUMP(txvq->vq);
2466a9643ea8Slogwang }
2467a9643ea8Slogwang
24682bfe3f2eSlogwang set_rxtx_funcs(dev);
2469d30ea906Sjfb8856606 hw->started = true;
24702bfe3f2eSlogwang
24712bfe3f2eSlogwang /* Initialize Link state */
24722bfe3f2eSlogwang virtio_dev_link_update(dev, 0);
24732bfe3f2eSlogwang
2474a9643ea8Slogwang return 0;
2475a9643ea8Slogwang }
2476a9643ea8Slogwang
virtio_dev_free_mbufs(struct rte_eth_dev * dev)2477a9643ea8Slogwang static void virtio_dev_free_mbufs(struct rte_eth_dev *dev)
2478a9643ea8Slogwang {
2479d30ea906Sjfb8856606 struct virtio_hw *hw = dev->data->dev_private;
2480d30ea906Sjfb8856606 uint16_t nr_vq = virtio_get_nr_vq(hw);
2481d30ea906Sjfb8856606 const char *type __rte_unused;
2482d30ea906Sjfb8856606 unsigned int i, mbuf_num = 0;
2483d30ea906Sjfb8856606 struct virtqueue *vq;
2484a9643ea8Slogwang struct rte_mbuf *buf;
2485d30ea906Sjfb8856606 int queue_type;
2486a9643ea8Slogwang
2487d30ea906Sjfb8856606 if (hw->vqs == NULL)
2488d30ea906Sjfb8856606 return;
2489a9643ea8Slogwang
2490d30ea906Sjfb8856606 for (i = 0; i < nr_vq; i++) {
2491d30ea906Sjfb8856606 vq = hw->vqs[i];
2492d30ea906Sjfb8856606 if (!vq)
2493d30ea906Sjfb8856606 continue;
2494d30ea906Sjfb8856606
2495d30ea906Sjfb8856606 queue_type = virtio_get_queue_type(hw, i);
2496d30ea906Sjfb8856606 if (queue_type == VTNET_RQ)
2497d30ea906Sjfb8856606 type = "rxq";
2498d30ea906Sjfb8856606 else if (queue_type == VTNET_TQ)
2499d30ea906Sjfb8856606 type = "txq";
2500d30ea906Sjfb8856606 else
25012bfe3f2eSlogwang continue;
25022bfe3f2eSlogwang
2503a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
2504d30ea906Sjfb8856606 "Before freeing %s[%d] used and unused buf",
2505d30ea906Sjfb8856606 type, i);
2506d30ea906Sjfb8856606 VIRTQUEUE_DUMP(vq);
2507a9643ea8Slogwang
2508d30ea906Sjfb8856606 while ((buf = virtqueue_detach_unused(vq)) != NULL) {
2509a9643ea8Slogwang rte_pktmbuf_free(buf);
2510a9643ea8Slogwang mbuf_num++;
2511a9643ea8Slogwang }
2512a9643ea8Slogwang
2513a9643ea8Slogwang PMD_INIT_LOG(DEBUG,
2514d30ea906Sjfb8856606 "After freeing %s[%d] used and unused buf",
2515d30ea906Sjfb8856606 type, i);
2516d30ea906Sjfb8856606 VIRTQUEUE_DUMP(vq);
2517a9643ea8Slogwang }
2518a9643ea8Slogwang
2519d30ea906Sjfb8856606 PMD_INIT_LOG(DEBUG, "%d mbufs freed", mbuf_num);
2520a9643ea8Slogwang }
2521a9643ea8Slogwang
2522a9643ea8Slogwang /*
2523a9643ea8Slogwang * Stop device: disable interrupt and mark link down
2524a9643ea8Slogwang */
2525*2d9fd380Sjfb8856606 static int
virtio_dev_stop(struct rte_eth_dev * dev)2526a9643ea8Slogwang virtio_dev_stop(struct rte_eth_dev *dev)
2527a9643ea8Slogwang {
25282bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
2529a9643ea8Slogwang struct rte_eth_link link;
25302bfe3f2eSlogwang struct rte_intr_conf *intr_conf = &dev->data->dev_conf.intr_conf;
2531a9643ea8Slogwang
2532a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "stop");
2533*2d9fd380Sjfb8856606 dev->data->dev_started = 0;
2534a9643ea8Slogwang
2535d30ea906Sjfb8856606 rte_spinlock_lock(&hw->state_lock);
2536d30ea906Sjfb8856606 if (!hw->started)
2537d30ea906Sjfb8856606 goto out_unlock;
2538d30ea906Sjfb8856606 hw->started = false;
2539d30ea906Sjfb8856606
2540d30ea906Sjfb8856606 if (intr_conf->lsc || intr_conf->rxq) {
25412bfe3f2eSlogwang virtio_intr_disable(dev);
2542a9643ea8Slogwang
2543d30ea906Sjfb8856606 /* Reset interrupt callback */
2544d30ea906Sjfb8856606 if (dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
2545d30ea906Sjfb8856606 rte_intr_callback_unregister(dev->intr_handle,
2546d30ea906Sjfb8856606 virtio_interrupt_handler,
2547d30ea906Sjfb8856606 dev);
2548d30ea906Sjfb8856606 }
2549d30ea906Sjfb8856606 }
2550d30ea906Sjfb8856606
2551a9643ea8Slogwang memset(&link, 0, sizeof(link));
2552d30ea906Sjfb8856606 rte_eth_linkstatus_set(dev, &link);
2553d30ea906Sjfb8856606 out_unlock:
2554d30ea906Sjfb8856606 rte_spinlock_unlock(&hw->state_lock);
2555*2d9fd380Sjfb8856606
2556*2d9fd380Sjfb8856606 return 0;
2557a9643ea8Slogwang }
2558a9643ea8Slogwang
2559a9643ea8Slogwang static int
virtio_dev_link_update(struct rte_eth_dev * dev,__rte_unused int wait_to_complete)2560a9643ea8Slogwang virtio_dev_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
2561a9643ea8Slogwang {
2562d30ea906Sjfb8856606 struct rte_eth_link link;
2563a9643ea8Slogwang uint16_t status;
2564a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
256528440c50Sjfb8856606
2566d30ea906Sjfb8856606 memset(&link, 0, sizeof(link));
2567*2d9fd380Sjfb8856606 link.link_duplex = hw->duplex;
2568*2d9fd380Sjfb8856606 link.link_speed = hw->speed;
2569*2d9fd380Sjfb8856606 link.link_autoneg = ETH_LINK_AUTONEG;
2570d30ea906Sjfb8856606
2571d30ea906Sjfb8856606 if (!hw->started) {
25722bfe3f2eSlogwang link.link_status = ETH_LINK_DOWN;
2573*2d9fd380Sjfb8856606 link.link_speed = ETH_SPEED_NUM_NONE;
25742bfe3f2eSlogwang } else if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
2575a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "Get link status from hw");
2576a9643ea8Slogwang vtpci_read_dev_config(hw,
2577a9643ea8Slogwang offsetof(struct virtio_net_config, status),
2578a9643ea8Slogwang &status, sizeof(status));
2579a9643ea8Slogwang if ((status & VIRTIO_NET_S_LINK_UP) == 0) {
2580a9643ea8Slogwang link.link_status = ETH_LINK_DOWN;
2581*2d9fd380Sjfb8856606 link.link_speed = ETH_SPEED_NUM_NONE;
2582a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "Port %d is down",
2583a9643ea8Slogwang dev->data->port_id);
2584a9643ea8Slogwang } else {
2585a9643ea8Slogwang link.link_status = ETH_LINK_UP;
2586a9643ea8Slogwang PMD_INIT_LOG(DEBUG, "Port %d is up",
2587a9643ea8Slogwang dev->data->port_id);
2588a9643ea8Slogwang }
2589a9643ea8Slogwang } else {
2590a9643ea8Slogwang link.link_status = ETH_LINK_UP;
2591a9643ea8Slogwang }
2592a9643ea8Slogwang
2593d30ea906Sjfb8856606 return rte_eth_linkstatus_set(dev, &link);
2594a9643ea8Slogwang }
2595a9643ea8Slogwang
25962bfe3f2eSlogwang static int
virtio_dev_vlan_offload_set(struct rte_eth_dev * dev,int mask)25972bfe3f2eSlogwang virtio_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
25982bfe3f2eSlogwang {
25992bfe3f2eSlogwang const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
26002bfe3f2eSlogwang struct virtio_hw *hw = dev->data->dev_private;
2601d30ea906Sjfb8856606 uint64_t offloads = rxmode->offloads;
26022bfe3f2eSlogwang
26032bfe3f2eSlogwang if (mask & ETH_VLAN_FILTER_MASK) {
2604d30ea906Sjfb8856606 if ((offloads & DEV_RX_OFFLOAD_VLAN_FILTER) &&
26052bfe3f2eSlogwang !vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VLAN)) {
26062bfe3f2eSlogwang
26072bfe3f2eSlogwang PMD_DRV_LOG(NOTICE,
26082bfe3f2eSlogwang "vlan filtering not available on this host");
26092bfe3f2eSlogwang
26102bfe3f2eSlogwang return -ENOTSUP;
26112bfe3f2eSlogwang }
26122bfe3f2eSlogwang }
26132bfe3f2eSlogwang
26142bfe3f2eSlogwang if (mask & ETH_VLAN_STRIP_MASK)
2615d30ea906Sjfb8856606 hw->vlan_strip = !!(offloads & DEV_RX_OFFLOAD_VLAN_STRIP);
26162bfe3f2eSlogwang
26172bfe3f2eSlogwang return 0;
26182bfe3f2eSlogwang }
26192bfe3f2eSlogwang
26204418919fSjohnjiang static int
virtio_dev_info_get(struct rte_eth_dev * dev,struct rte_eth_dev_info * dev_info)2621a9643ea8Slogwang virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
2622a9643ea8Slogwang {
26232bfe3f2eSlogwang uint64_t tso_mask, host_features;
2624a9643ea8Slogwang struct virtio_hw *hw = dev->data->dev_private;
2625*2d9fd380Sjfb8856606 dev_info->speed_capa = virtio_dev_speed_capa_get(hw->speed);
26262bfe3f2eSlogwang
26272bfe3f2eSlogwang dev_info->max_rx_queues =
26282bfe3f2eSlogwang RTE_MIN(hw->max_queue_pairs, VIRTIO_MAX_RX_QUEUES);
26292bfe3f2eSlogwang dev_info->max_tx_queues =
26302bfe3f2eSlogwang RTE_MIN(hw->max_queue_pairs, VIRTIO_MAX_TX_QUEUES);
2631a9643ea8Slogwang dev_info->min_rx_bufsize = VIRTIO_MIN_RX_BUFSIZE;
2632a9643ea8Slogwang dev_info->max_rx_pktlen = VIRTIO_MAX_RX_PKTLEN;
2633a9643ea8Slogwang dev_info->max_mac_addrs = VIRTIO_MAX_MAC_ADDRS;
26342bfe3f2eSlogwang
26352bfe3f2eSlogwang host_features = VTPCI_OPS(hw)->get_features(hw);
2636d30ea906Sjfb8856606 dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP;
26371646932aSjfb8856606 dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_JUMBO_FRAME;
26382bfe3f2eSlogwang if (host_features & (1ULL << VIRTIO_NET_F_GUEST_CSUM)) {
26392bfe3f2eSlogwang dev_info->rx_offload_capa |=
26402bfe3f2eSlogwang DEV_RX_OFFLOAD_TCP_CKSUM |
26412bfe3f2eSlogwang DEV_RX_OFFLOAD_UDP_CKSUM;
26422bfe3f2eSlogwang }
2643d30ea906Sjfb8856606 if (host_features & (1ULL << VIRTIO_NET_F_CTRL_VLAN))
2644d30ea906Sjfb8856606 dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_VLAN_FILTER;
26452bfe3f2eSlogwang tso_mask = (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
26462bfe3f2eSlogwang (1ULL << VIRTIO_NET_F_GUEST_TSO6);
26472bfe3f2eSlogwang if ((host_features & tso_mask) == tso_mask)
26482bfe3f2eSlogwang dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_TCP_LRO;
26492bfe3f2eSlogwang
2650d30ea906Sjfb8856606 dev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS |
2651d30ea906Sjfb8856606 DEV_TX_OFFLOAD_VLAN_INSERT;
2652d30ea906Sjfb8856606 if (host_features & (1ULL << VIRTIO_NET_F_CSUM)) {
26532bfe3f2eSlogwang dev_info->tx_offload_capa |=
26542bfe3f2eSlogwang DEV_TX_OFFLOAD_UDP_CKSUM |
26552bfe3f2eSlogwang DEV_TX_OFFLOAD_TCP_CKSUM;
26562bfe3f2eSlogwang }
26572bfe3f2eSlogwang tso_mask = (1ULL << VIRTIO_NET_F_HOST_TSO4) |
26582bfe3f2eSlogwang (1ULL << VIRTIO_NET_F_HOST_TSO6);
2659d30ea906Sjfb8856606 if ((host_features & tso_mask) == tso_mask)
26602bfe3f2eSlogwang dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
26614418919fSjohnjiang
26624418919fSjohnjiang return 0;
2663a9643ea8Slogwang }
2664a9643ea8Slogwang
2665a9643ea8Slogwang /*
2666a9643ea8Slogwang * It enables testpmd to collect per queue stats.
2667a9643ea8Slogwang */
2668a9643ea8Slogwang static int
virtio_dev_queue_stats_mapping_set(__rte_unused struct rte_eth_dev * eth_dev,__rte_unused uint16_t queue_id,__rte_unused uint8_t stat_idx,__rte_unused uint8_t is_rx)2669a9643ea8Slogwang virtio_dev_queue_stats_mapping_set(__rte_unused struct rte_eth_dev *eth_dev,
2670a9643ea8Slogwang __rte_unused uint16_t queue_id, __rte_unused uint8_t stat_idx,
2671a9643ea8Slogwang __rte_unused uint8_t is_rx)
2672a9643ea8Slogwang {
2673a9643ea8Slogwang return 0;
2674a9643ea8Slogwang }
2675a9643ea8Slogwang
26762bfe3f2eSlogwang RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__);
26772bfe3f2eSlogwang RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map);
26782bfe3f2eSlogwang RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci");
2679*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(virtio_logtype_init, pmd.net.virtio.init, NOTICE);
2680*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(virtio_logtype_driver, pmd.net.virtio.driver, NOTICE);
2681