Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2016 Intel Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <string.h>
7 : : #include <stdio.h>
8 : : #include <errno.h>
9 : : #include <unistd.h>
10 : :
11 : : #include <ethdev_driver.h>
12 : : #include <ethdev_pci.h>
13 : : #include <rte_pci.h>
14 : : #include <bus_pci_driver.h>
15 : : #include <rte_errno.h>
16 : :
17 : : #include <rte_memory.h>
18 : : #include <rte_eal.h>
19 : : #include <dev_driver.h>
20 : : #include <rte_kvargs.h>
21 : :
22 : : #include "virtio.h"
23 : : #include "virtio_ethdev.h"
24 : : #include "virtio_pci.h"
25 : : #include "virtio_logs.h"
26 : :
27 : : /*
28 : : * The set of PCI devices this driver supports
29 : : */
30 : : static const struct rte_pci_id pci_id_virtio_map[] = {
31 : : { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_LEGACY_DEVICEID_NET) },
32 : : { RTE_PCI_DEVICE(VIRTIO_PCI_VENDORID, VIRTIO_PCI_MODERN_DEVICEID_NET) },
33 : : { .vendor_id = 0, /* sentinel */ },
34 : : };
35 : :
36 : :
37 : : /*
38 : : * Remap the PCI device again (IO port map for legacy device and
39 : : * memory map for modern device), so that the secondary process
40 : : * could have the PCI initiated correctly.
41 : : */
42 : : static int
43 : 0 : virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_pci_dev *dev)
44 : : {
45 : 0 : struct virtio_hw *hw = &dev->hw;
46 : :
47 [ # # ]: 0 : if (dev->modern) {
48 : : /*
49 : : * We don't have to re-parse the PCI config space, since
50 : : * rte_pci_map_device() makes sure the mapped address
51 : : * in secondary process would equal to the one mapped in
52 : : * the primary process: error will be returned if that
53 : : * requirement is not met.
54 : : *
55 : : * That said, we could simply reuse all cap pointers
56 : : * (such as dev_cfg, common_cfg, etc.) parsed from the
57 : : * primary process, which is stored in shared memory.
58 : : */
59 [ # # ]: 0 : if (rte_pci_map_device(pci_dev)) {
60 : 0 : PMD_INIT_LOG(DEBUG, "failed to map pci device!");
61 : 0 : return -1;
62 : : }
63 : : } else {
64 [ # # ]: 0 : if (vtpci_legacy_ioport_map(hw) < 0)
65 : 0 : return -1;
66 : : }
67 : :
68 : : return 0;
69 : : }
70 : :
71 : : static int
72 : 0 : eth_virtio_pci_init(struct rte_eth_dev *eth_dev)
73 : : {
74 : 0 : struct virtio_pci_dev *dev = eth_dev->data->dev_private;
75 : 0 : struct virtio_hw *hw = &dev->hw;
76 : 0 : struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
77 : : int ret;
78 : :
79 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
80 : 0 : hw->port_id = eth_dev->data->port_id;
81 : 0 : VTPCI_DEV(hw) = pci_dev;
82 : 0 : ret = vtpci_init(pci_dev, dev);
83 [ # # ]: 0 : if (ret) {
84 : 0 : PMD_INIT_LOG(ERR, "Failed to init PCI device");
85 : 0 : return -1;
86 : : }
87 : : } else {
88 : 0 : VTPCI_DEV(hw) = pci_dev;
89 [ # # ]: 0 : if (dev->modern)
90 : 0 : VIRTIO_OPS(hw) = &virtio_modern_ops;
91 : : else
92 : 0 : VIRTIO_OPS(hw) = &virtio_legacy_ops;
93 : :
94 : 0 : ret = virtio_remap_pci(pci_dev, dev);
95 [ # # ]: 0 : if (ret < 0) {
96 : 0 : PMD_INIT_LOG(ERR, "Failed to remap PCI device");
97 : 0 : return -1;
98 : : }
99 : : }
100 : :
101 : 0 : ret = eth_virtio_dev_init(eth_dev);
102 [ # # ]: 0 : if (ret < 0) {
103 : 0 : PMD_INIT_LOG(ERR, "Failed to init virtio device");
104 : 0 : goto err_unmap;
105 : : }
106 : :
107 : 0 : PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
108 : : eth_dev->data->port_id, pci_dev->id.vendor_id,
109 : : pci_dev->id.device_id);
110 : :
111 : 0 : return 0;
112 : :
113 : : err_unmap:
114 : 0 : rte_pci_unmap_device(pci_dev);
115 [ # # ]: 0 : if (!dev->modern)
116 : 0 : vtpci_legacy_ioport_unmap(hw);
117 : :
118 : : return ret;
119 : : }
120 : :
121 : : static int
122 : 0 : eth_virtio_pci_uninit(struct rte_eth_dev *eth_dev)
123 : : {
124 : : int ret;
125 : : struct virtio_pci_dev *dev;
126 : : struct virtio_hw *hw;
127 : 0 : PMD_INIT_FUNC_TRACE();
128 : :
129 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
130 : 0 : struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
131 : 0 : dev = eth_dev->data->dev_private;
132 : 0 : hw = &dev->hw;
133 : :
134 [ # # ]: 0 : if (dev->modern)
135 : 0 : rte_pci_unmap_device(pci_dev);
136 : : else
137 : 0 : vtpci_legacy_ioport_unmap(hw);
138 : 0 : return 0;
139 : : }
140 : :
141 : 0 : ret = virtio_dev_stop(eth_dev);
142 : 0 : virtio_dev_close(eth_dev);
143 : :
144 : 0 : PMD_INIT_LOG(DEBUG, "dev_uninit completed");
145 : :
146 : 0 : return ret;
147 : : }
148 : :
149 : 0 : static int vdpa_check_handler(__rte_unused const char *key,
150 : : const char *value, void *ret_val)
151 : : {
152 [ # # ]: 0 : if (value == NULL || ret_val == NULL)
153 : : return -EINVAL;
154 : :
155 [ # # ]: 0 : if (strcmp(value, "1") == 0)
156 : 0 : *(int *)ret_val = 1;
157 : : else
158 : 0 : *(int *)ret_val = 0;
159 : :
160 : : return 0;
161 : : }
162 : :
163 : : #define VIRTIO_ARG_VDPA "vdpa"
164 : :
165 : : static int
166 : 0 : virtio_pci_devargs_parse(struct rte_devargs *devargs, int *vdpa)
167 : : {
168 : : struct rte_kvargs *kvlist;
169 : : int ret = 0;
170 : :
171 [ # # ]: 0 : if (devargs == NULL)
172 : : return 0;
173 : :
174 : 0 : kvlist = rte_kvargs_parse(devargs->args, NULL);
175 [ # # ]: 0 : if (kvlist == NULL) {
176 : 0 : PMD_INIT_LOG(ERR, "error when parsing param");
177 : 0 : return 0;
178 : : }
179 : :
180 [ # # ]: 0 : if (rte_kvargs_count(kvlist, VIRTIO_ARG_VDPA) == 1) {
181 : : /* vdpa mode selected when there's a key-value pair:
182 : : * vdpa=1
183 : : */
184 : 0 : ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA,
185 : : vdpa_check_handler, vdpa);
186 [ # # ]: 0 : if (ret < 0)
187 : 0 : PMD_INIT_LOG(ERR, "Failed to parse %s", VIRTIO_ARG_VDPA);
188 : : }
189 : :
190 : 0 : rte_kvargs_free(kvlist);
191 : :
192 : 0 : return ret;
193 : : }
194 : :
195 : 0 : static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
196 : : struct rte_pci_device *pci_dev)
197 : : {
198 : 0 : int vdpa = 0;
199 : : int ret = 0;
200 : :
201 : 0 : ret = virtio_pci_devargs_parse(pci_dev->device.devargs, &vdpa);
202 [ # # ]: 0 : if (ret < 0) {
203 : 0 : PMD_INIT_LOG(ERR, "devargs parsing is failed");
204 : 0 : return ret;
205 : : }
206 : : /* virtio pmd skips probe if device needs to work in vdpa mode */
207 [ # # ]: 0 : if (vdpa == 1)
208 : : return 1;
209 : :
210 : 0 : return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_pci_dev),
211 : : eth_virtio_pci_init);
212 : : }
213 : :
214 : 0 : static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev)
215 : : {
216 : : int ret;
217 : :
218 : 0 : ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_pci_uninit);
219 : : /* Port has already been released by close. */
220 [ # # ]: 0 : if (ret == -ENODEV)
221 : : ret = 0;
222 : 0 : return ret;
223 : : }
224 : :
225 : : static struct rte_pci_driver rte_virtio_net_pci_pmd = {
226 : : .driver = {
227 : : .name = "net_virtio",
228 : : },
229 : : .id_table = pci_id_virtio_map,
230 : : .drv_flags = 0,
231 : : .probe = eth_virtio_pci_probe,
232 : : .remove = eth_virtio_pci_remove,
233 : : };
234 : :
235 : 301 : RTE_INIT(rte_virtio_net_pci_pmd_init)
236 : : {
237 : 301 : rte_eal_iopl_init();
238 : 301 : rte_pci_register(&rte_virtio_net_pci_pmd);
239 : 301 : }
240 : :
241 : : RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map);
242 : : RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci");
243 : : RTE_PMD_EXPORT_NAME(net_virtio);
|