xref: /dpdk/drivers/net/virtio/virtio_pci_ethdev.c (revision 1c1b35b59b4cee8836f34498b7c55b49de39d7b3)
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
virtio_remap_pci(struct rte_pci_device * pci_dev,struct virtio_pci_dev * dev)43 virtio_remap_pci(struct rte_pci_device *pci_dev, struct virtio_pci_dev *dev)
44 {
45 	struct virtio_hw *hw = &dev->hw;
46 
47 	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 		if (rte_pci_map_device(pci_dev)) {
60 			PMD_INIT_LOG(DEBUG, "failed to map pci device!");
61 			return -1;
62 		}
63 	} else {
64 		if (vtpci_legacy_ioport_map(hw) < 0)
65 			return -1;
66 	}
67 
68 	return 0;
69 }
70 
71 static int
eth_virtio_pci_init(struct rte_eth_dev * eth_dev)72 eth_virtio_pci_init(struct rte_eth_dev *eth_dev)
73 {
74 	struct virtio_pci_dev *dev = eth_dev->data->dev_private;
75 	struct virtio_hw *hw = &dev->hw;
76 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
77 	int ret;
78 
79 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
80 		hw->port_id = eth_dev->data->port_id;
81 		VTPCI_DEV(hw) = pci_dev;
82 		ret = vtpci_init(RTE_ETH_DEV_TO_PCI(eth_dev), dev);
83 		if (ret) {
84 			PMD_INIT_LOG(ERR, "Failed to init PCI device");
85 			return -1;
86 		}
87 	} else {
88 		VTPCI_DEV(hw) = pci_dev;
89 		if (dev->modern)
90 			VIRTIO_OPS(hw) = &modern_ops;
91 		else
92 			VIRTIO_OPS(hw) = &legacy_ops;
93 
94 		ret = virtio_remap_pci(RTE_ETH_DEV_TO_PCI(eth_dev), dev);
95 		if (ret < 0) {
96 			PMD_INIT_LOG(ERR, "Failed to remap PCI device");
97 			return -1;
98 		}
99 	}
100 
101 	ret = eth_virtio_dev_init(eth_dev);
102 	if (ret < 0) {
103 		PMD_INIT_LOG(ERR, "Failed to init virtio device");
104 		goto err_unmap;
105 	}
106 
107 	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 	return 0;
112 
113 err_unmap:
114 	rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev));
115 	if (!dev->modern)
116 		vtpci_legacy_ioport_unmap(hw);
117 
118 	return ret;
119 }
120 
121 static int
eth_virtio_pci_uninit(struct rte_eth_dev * eth_dev)122 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 	PMD_INIT_FUNC_TRACE();
128 
129 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
130 		dev = eth_dev->data->dev_private;
131 		hw = &dev->hw;
132 
133 		if (dev->modern)
134 			rte_pci_unmap_device(RTE_ETH_DEV_TO_PCI(eth_dev));
135 		else
136 			vtpci_legacy_ioport_unmap(hw);
137 		return 0;
138 	}
139 
140 	ret = virtio_dev_stop(eth_dev);
141 	virtio_dev_close(eth_dev);
142 
143 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
144 
145 	return ret;
146 }
147 
vdpa_check_handler(__rte_unused const char * key,const char * value,void * ret_val)148 static int vdpa_check_handler(__rte_unused const char *key,
149 		const char *value, void *ret_val)
150 {
151 	if (value == NULL || ret_val == NULL)
152 		return -EINVAL;
153 
154 	if (strcmp(value, "1") == 0)
155 		*(int *)ret_val = 1;
156 	else
157 		*(int *)ret_val = 0;
158 
159 	return 0;
160 }
161 
162 #define VIRTIO_ARG_VDPA       "vdpa"
163 
164 static int
virtio_pci_devargs_parse(struct rte_devargs * devargs,int * vdpa)165 virtio_pci_devargs_parse(struct rte_devargs *devargs, int *vdpa)
166 {
167 	struct rte_kvargs *kvlist;
168 	int ret = 0;
169 
170 	if (devargs == NULL)
171 		return 0;
172 
173 	kvlist = rte_kvargs_parse(devargs->args, NULL);
174 	if (kvlist == NULL) {
175 		PMD_INIT_LOG(ERR, "error when parsing param");
176 		return 0;
177 	}
178 
179 	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 		ret = rte_kvargs_process(kvlist, VIRTIO_ARG_VDPA,
184 				vdpa_check_handler, vdpa);
185 		if (ret < 0)
186 			PMD_INIT_LOG(ERR, "Failed to parse %s", VIRTIO_ARG_VDPA);
187 	}
188 
189 	rte_kvargs_free(kvlist);
190 
191 	return ret;
192 }
193 
eth_virtio_pci_probe(struct rte_pci_driver * pci_drv __rte_unused,struct rte_pci_device * pci_dev)194 static int eth_virtio_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
195 	struct rte_pci_device *pci_dev)
196 {
197 	int vdpa = 0;
198 	int ret = 0;
199 
200 	ret = virtio_pci_devargs_parse(pci_dev->device.devargs, &vdpa);
201 	if (ret < 0) {
202 		PMD_INIT_LOG(ERR, "devargs parsing is failed");
203 		return ret;
204 	}
205 	/* virtio pmd skips probe if device needs to work in vdpa mode */
206 	if (vdpa == 1)
207 		return 1;
208 
209 	return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct virtio_pci_dev),
210 		eth_virtio_pci_init);
211 }
212 
eth_virtio_pci_remove(struct rte_pci_device * pci_dev)213 static int eth_virtio_pci_remove(struct rte_pci_device *pci_dev)
214 {
215 	int ret;
216 
217 	ret = rte_eth_dev_pci_generic_remove(pci_dev, eth_virtio_pci_uninit);
218 	/* Port has already been released by close. */
219 	if (ret == -ENODEV)
220 		ret = 0;
221 	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 
RTE_INIT(rte_virtio_net_pci_pmd_init)234 RTE_INIT(rte_virtio_net_pci_pmd_init)
235 {
236 	rte_eal_iopl_init();
237 	rte_pci_register(&rte_virtio_net_pci_pmd);
238 }
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__);
243