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_ETH_DEV_TO_PCI(eth_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(RTE_ETH_DEV_TO_PCI(eth_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) = &modern_ops;
91 : : else
92 : 0 : VIRTIO_OPS(hw) = &legacy_ops;
93 : :
94 : 0 : ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_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(RTE_ETH_DEV_TO_PCI(eth_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 : dev = eth_dev->data->dev_private;
131 : 0 : hw = &dev->hw;
132 : :
133 [ # # ]: 0 : if (dev->modern)
134 : 0 : rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev));
135 : : else
136 : 0 : vtpci_legacy_ioport_unmap(hw);
137 : 0 : return 0;
138 : : }
139 : :
140 : 0 : ret = virtio_dev_stop(eth_dev);
141 : 0 : virtio_dev_close(eth_dev);
142 : :
143 : 0 : PMD_INIT_LOG(DEBUG, "dev_uninit completed");
144 : :
145 : 0 : return ret;
146 : : }
147 : :
148 : 0 : static int vdpa_check_handler(__rte_unused const char *key,
149 : : const char *value, void *ret_val)
150 : : {
151 [ # # ]: 0 : if (value == NULL || ret_val == NULL)
152 : : return -EINVAL;
153 : :
154 [ # # ]: 0 : if (strcmp(value, "1") == 0)
155 : 0 : *(int *)ret_val = 1;
156 : : else
157 : 0 : *(int *)ret_val = 0;
158 : :
159 : : return 0;
160 : : }
161 : :
162 : : #define VIRTIO_ARG_VDPA "vdpa"
163 : :
164 : : static int
165 : 0 : virtio_pci_devargs_parse(struct rte_devargs *devargs, int *vdpa)
166 : : {
167 : : struct rte_kvargs *kvlist;
168 : : int ret = 0;
169 : :
170 [ # # ]: 0 : if (devargs == NULL)
171 : : return 0;
172 : :
173 : 0 : kvlist = rte_kvargs_parse(devargs->args, NULL);
174 [ # # ]: 0 : if (kvlist == NULL) {
175 : 0 : PMD_INIT_LOG(ERR, "error when parsing param");
176 : 0 : return 0;
177 : : }
178 : :
179 [ # # ]: 0 : if (rte_kvargs_count(kvlist, VIRTIO_ARG_VDPA) == 1) {
180 : : /* vdpa mode selected when there's a key-value pair:
181 : : * vdpa=1
182 : : */
183 : 0 : ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA,
184 : : vdpa_check_handler, vdpa);
185 [ # # ]: 0 : if (ret < 0)
186 : 0 : PMD_INIT_LOG(ERR, "Failed to parse %s", VIRTIO_ARG_VDPA);
187 : : }
188 : :
189 : 0 : rte_kvargs_free(kvlist);
190 : :
191 : 0 : return ret;
192 : : }
193 : :
194 : 0 : static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
195 : : struct rte_pci_device *pci_dev)
196 : : {
197 : 0 : int vdpa = 0;
198 : : int ret = 0;
199 : :
200 : 0 : ret = virtio_pci_devargs_parse(pci_dev->device.devargs, &vdpa);
201 [ # # ]: 0 : if (ret < 0) {
202 : 0 : PMD_INIT_LOG(ERR, "devargs parsing is failed");
203 : 0 : return ret;
204 : : }
205 : : /* virtio pmd skips probe if device needs to work in vdpa mode */
206 [ # # ]: 0 : if (vdpa == 1)
207 : : return 1;
208 : :
209 : 0 : return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_pci_dev),
210 : : eth_virtio_pci_init);
211 : : }
212 : :
213 : 0 : static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev)
214 : : {
215 : : int ret;
216 : :
217 : 0 : ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_pci_uninit);
218 : : /* Port has already been released by close. */
219 [ # # ]: 0 : if (ret == -ENODEV)
220 : : ret = 0;
221 : 0 : return ret;
222 : : }
223 : :
224 : : static struct rte_pci_driver rte_virtio_net_pci_pmd = {
225 : : .driver = {
226 : : .name = "net_virtio",
227 : : },
228 : : .id_table = pci_id_virtio_map,
229 : : .drv_flags = 0,
230 : : .probe = eth_virtio_pci_probe,
231 : : .remove = eth_virtio_pci_remove,
232 : : };
233 : :
234 : 251 : RTE_INIT(rte_virtio_net_pci_pmd_init)
235 : : {
236 : 251 : rte_eal_iopl_init();
237 : 251 : rte_pci_register(&rte_virtio_net_pci_pmd);
238 : 251 : }
239 : :
240 : : RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map);
241 : : RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio-pci");
242 : : RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__);
|