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