xref: /dpdk/drivers/common/mlx5/mlx5_common_pci.c (revision 8a41f4deccc39d3a86c3c91667bee993bfd3e39c)
1*8a41f4deSParav Pandit /* SPDX-License-Identifier: BSD-3-Clause
2*8a41f4deSParav Pandit  * Copyright 2020 Mellanox Technologies Ltd
3*8a41f4deSParav Pandit  */
4*8a41f4deSParav Pandit 
5*8a41f4deSParav Pandit #include <stdlib.h>
6*8a41f4deSParav Pandit #include <rte_malloc.h>
7*8a41f4deSParav Pandit #include "mlx5_common_utils.h"
8*8a41f4deSParav Pandit #include "mlx5_common_pci.h"
9*8a41f4deSParav Pandit 
10*8a41f4deSParav Pandit struct mlx5_pci_device {
11*8a41f4deSParav Pandit 	struct rte_pci_device *pci_dev;
12*8a41f4deSParav Pandit 	TAILQ_ENTRY(mlx5_pci_device) next;
13*8a41f4deSParav Pandit 	uint32_t classes_loaded;
14*8a41f4deSParav Pandit };
15*8a41f4deSParav Pandit 
16*8a41f4deSParav Pandit /* Head of list of drivers. */
17*8a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_bus_drv_head, mlx5_pci_driver) drv_list =
18*8a41f4deSParav Pandit 				TAILQ_HEAD_INITIALIZER(drv_list);
19*8a41f4deSParav Pandit 
20*8a41f4deSParav Pandit /* Head of mlx5 pci devices. */
21*8a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_devices_head, mlx5_pci_device) devices_list =
22*8a41f4deSParav Pandit 				TAILQ_HEAD_INITIALIZER(devices_list);
23*8a41f4deSParav Pandit 
24*8a41f4deSParav Pandit static const struct {
25*8a41f4deSParav Pandit 	const char *name;
26*8a41f4deSParav Pandit 	unsigned int driver_class;
27*8a41f4deSParav Pandit } mlx5_classes[] = {
28*8a41f4deSParav Pandit 	{ .name = "vdpa", .driver_class = MLX5_CLASS_VDPA },
29*8a41f4deSParav Pandit 	{ .name = "net", .driver_class = MLX5_CLASS_NET },
30*8a41f4deSParav Pandit 	{ .name = "regex", .driver_class = MLX5_CLASS_REGEX },
31*8a41f4deSParav Pandit };
32*8a41f4deSParav Pandit 
33*8a41f4deSParav Pandit static const unsigned int mlx5_class_combinations[] = {
34*8a41f4deSParav Pandit 	MLX5_CLASS_NET,
35*8a41f4deSParav Pandit 	MLX5_CLASS_VDPA,
36*8a41f4deSParav Pandit 	MLX5_CLASS_REGEX,
37*8a41f4deSParav Pandit 	MLX5_CLASS_NET | MLX5_CLASS_REGEX,
38*8a41f4deSParav Pandit 	MLX5_CLASS_VDPA | MLX5_CLASS_REGEX,
39*8a41f4deSParav Pandit 	/* New class combination should be added here. */
40*8a41f4deSParav Pandit };
41*8a41f4deSParav Pandit 
42*8a41f4deSParav Pandit static int
43*8a41f4deSParav Pandit class_name_to_value(const char *class_name)
44*8a41f4deSParav Pandit {
45*8a41f4deSParav Pandit 	unsigned int i;
46*8a41f4deSParav Pandit 
47*8a41f4deSParav Pandit 	for (i = 0; i < RTE_DIM(mlx5_classes); i++) {
48*8a41f4deSParav Pandit 		if (strcmp(class_name, mlx5_classes[i].name) == 0)
49*8a41f4deSParav Pandit 			return mlx5_classes[i].driver_class;
50*8a41f4deSParav Pandit 	}
51*8a41f4deSParav Pandit 	return -EINVAL;
52*8a41f4deSParav Pandit }
53*8a41f4deSParav Pandit 
54*8a41f4deSParav Pandit static struct mlx5_pci_driver *
55*8a41f4deSParav Pandit driver_get(uint32_t class)
56*8a41f4deSParav Pandit {
57*8a41f4deSParav Pandit 	struct mlx5_pci_driver *driver;
58*8a41f4deSParav Pandit 
59*8a41f4deSParav Pandit 	TAILQ_FOREACH(driver, &drv_list, next) {
60*8a41f4deSParav Pandit 		if (driver->driver_class == class)
61*8a41f4deSParav Pandit 			return driver;
62*8a41f4deSParav Pandit 	}
63*8a41f4deSParav Pandit 	return NULL;
64*8a41f4deSParav Pandit }
65*8a41f4deSParav Pandit 
66*8a41f4deSParav Pandit static int
67*8a41f4deSParav Pandit bus_cmdline_options_handler(__rte_unused const char *key,
68*8a41f4deSParav Pandit 			    const char *class_names, void *opaque)
69*8a41f4deSParav Pandit {
70*8a41f4deSParav Pandit 	int *ret = opaque;
71*8a41f4deSParav Pandit 	char *nstr_org;
72*8a41f4deSParav Pandit 	int class_val;
73*8a41f4deSParav Pandit 	char *found;
74*8a41f4deSParav Pandit 	char *nstr;
75*8a41f4deSParav Pandit 
76*8a41f4deSParav Pandit 	*ret = 0;
77*8a41f4deSParav Pandit 	nstr = strdup(class_names);
78*8a41f4deSParav Pandit 	if (!nstr) {
79*8a41f4deSParav Pandit 		*ret = -ENOMEM;
80*8a41f4deSParav Pandit 		return *ret;
81*8a41f4deSParav Pandit 	}
82*8a41f4deSParav Pandit 	nstr_org = nstr;
83*8a41f4deSParav Pandit 	while (nstr) {
84*8a41f4deSParav Pandit 		/* Extract each individual class name. Multiple
85*8a41f4deSParav Pandit 		 * class key,value is supplied as class=net:vdpa:foo:bar.
86*8a41f4deSParav Pandit 		 */
87*8a41f4deSParav Pandit 		found = strsep(&nstr, ":");
88*8a41f4deSParav Pandit 		if (!found)
89*8a41f4deSParav Pandit 			continue;
90*8a41f4deSParav Pandit 		/* Check if its a valid class. */
91*8a41f4deSParav Pandit 		class_val = class_name_to_value(found);
92*8a41f4deSParav Pandit 		if (class_val < 0) {
93*8a41f4deSParav Pandit 			*ret = -EINVAL;
94*8a41f4deSParav Pandit 			goto err;
95*8a41f4deSParav Pandit 		}
96*8a41f4deSParav Pandit 		*ret |= class_val;
97*8a41f4deSParav Pandit 	}
98*8a41f4deSParav Pandit err:
99*8a41f4deSParav Pandit 	free(nstr_org);
100*8a41f4deSParav Pandit 	if (*ret < 0)
101*8a41f4deSParav Pandit 		DRV_LOG(ERR, "Invalid mlx5 class options %s."
102*8a41f4deSParav Pandit 			" Maybe typo in device class argument setting?",
103*8a41f4deSParav Pandit 			class_names);
104*8a41f4deSParav Pandit 	return *ret;
105*8a41f4deSParav Pandit }
106*8a41f4deSParav Pandit 
107*8a41f4deSParav Pandit static int
108*8a41f4deSParav Pandit parse_class_options(const struct rte_devargs *devargs)
109*8a41f4deSParav Pandit {
110*8a41f4deSParav Pandit 	const char *key = MLX5_CLASS_ARG_NAME;
111*8a41f4deSParav Pandit 	struct rte_kvargs *kvlist;
112*8a41f4deSParav Pandit 	int ret = 0;
113*8a41f4deSParav Pandit 
114*8a41f4deSParav Pandit 	if (devargs == NULL)
115*8a41f4deSParav Pandit 		return 0;
116*8a41f4deSParav Pandit 	kvlist = rte_kvargs_parse(devargs->args, NULL);
117*8a41f4deSParav Pandit 	if (kvlist == NULL)
118*8a41f4deSParav Pandit 		return 0;
119*8a41f4deSParav Pandit 	if (rte_kvargs_count(kvlist, key))
120*8a41f4deSParav Pandit 		rte_kvargs_process(kvlist, key, bus_cmdline_options_handler,
121*8a41f4deSParav Pandit 				   &ret);
122*8a41f4deSParav Pandit 	rte_kvargs_free(kvlist);
123*8a41f4deSParav Pandit 	return ret;
124*8a41f4deSParav Pandit }
125*8a41f4deSParav Pandit 
126*8a41f4deSParav Pandit static bool
127*8a41f4deSParav Pandit mlx5_bus_match(const struct mlx5_pci_driver *drv,
128*8a41f4deSParav Pandit 	       const struct rte_pci_device *pci_dev)
129*8a41f4deSParav Pandit {
130*8a41f4deSParav Pandit 	const struct rte_pci_id *id_table;
131*8a41f4deSParav Pandit 
132*8a41f4deSParav Pandit 	for (id_table = drv->pci_driver.id_table; id_table->vendor_id != 0;
133*8a41f4deSParav Pandit 	     id_table++) {
134*8a41f4deSParav Pandit 		/* Check if device's ids match the class driver's ids. */
135*8a41f4deSParav Pandit 		if (id_table->vendor_id != pci_dev->id.vendor_id &&
136*8a41f4deSParav Pandit 		    id_table->vendor_id != PCI_ANY_ID)
137*8a41f4deSParav Pandit 			continue;
138*8a41f4deSParav Pandit 		if (id_table->device_id != pci_dev->id.device_id &&
139*8a41f4deSParav Pandit 		    id_table->device_id != PCI_ANY_ID)
140*8a41f4deSParav Pandit 			continue;
141*8a41f4deSParav Pandit 		if (id_table->subsystem_vendor_id !=
142*8a41f4deSParav Pandit 		    pci_dev->id.subsystem_vendor_id &&
143*8a41f4deSParav Pandit 		    id_table->subsystem_vendor_id != PCI_ANY_ID)
144*8a41f4deSParav Pandit 			continue;
145*8a41f4deSParav Pandit 		if (id_table->subsystem_device_id !=
146*8a41f4deSParav Pandit 		    pci_dev->id.subsystem_device_id &&
147*8a41f4deSParav Pandit 		    id_table->subsystem_device_id != PCI_ANY_ID)
148*8a41f4deSParav Pandit 			continue;
149*8a41f4deSParav Pandit 		if (id_table->class_id != pci_dev->id.class_id &&
150*8a41f4deSParav Pandit 		    id_table->class_id != RTE_CLASS_ANY_ID)
151*8a41f4deSParav Pandit 			continue;
152*8a41f4deSParav Pandit 		return true;
153*8a41f4deSParav Pandit 	}
154*8a41f4deSParav Pandit 	return false;
155*8a41f4deSParav Pandit }
156*8a41f4deSParav Pandit 
157*8a41f4deSParav Pandit static int
158*8a41f4deSParav Pandit is_valid_class_combination(uint32_t user_classes)
159*8a41f4deSParav Pandit {
160*8a41f4deSParav Pandit 	unsigned int i;
161*8a41f4deSParav Pandit 
162*8a41f4deSParav Pandit 	/* Verify if user specified valid supported combination. */
163*8a41f4deSParav Pandit 	for (i = 0; i < RTE_DIM(mlx5_class_combinations); i++) {
164*8a41f4deSParav Pandit 		if (mlx5_class_combinations[i] == user_classes)
165*8a41f4deSParav Pandit 			return 0;
166*8a41f4deSParav Pandit 	}
167*8a41f4deSParav Pandit 	/* Not found any valid class combination. */
168*8a41f4deSParav Pandit 	return -EINVAL;
169*8a41f4deSParav Pandit }
170*8a41f4deSParav Pandit 
171*8a41f4deSParav Pandit static struct mlx5_pci_device *
172*8a41f4deSParav Pandit pci_to_mlx5_device(const struct rte_pci_device *pci_dev)
173*8a41f4deSParav Pandit {
174*8a41f4deSParav Pandit 	struct mlx5_pci_device *dev;
175*8a41f4deSParav Pandit 
176*8a41f4deSParav Pandit 	TAILQ_FOREACH(dev, &devices_list, next) {
177*8a41f4deSParav Pandit 		if (dev->pci_dev == pci_dev)
178*8a41f4deSParav Pandit 			return dev;
179*8a41f4deSParav Pandit 	}
180*8a41f4deSParav Pandit 	return NULL;
181*8a41f4deSParav Pandit }
182*8a41f4deSParav Pandit 
183*8a41f4deSParav Pandit static bool
184*8a41f4deSParav Pandit device_class_enabled(const struct mlx5_pci_device *device, uint32_t class)
185*8a41f4deSParav Pandit {
186*8a41f4deSParav Pandit 	return (device->classes_loaded & class) ? true : false;
187*8a41f4deSParav Pandit }
188*8a41f4deSParav Pandit 
189*8a41f4deSParav Pandit static void
190*8a41f4deSParav Pandit dev_release(struct mlx5_pci_device *dev)
191*8a41f4deSParav Pandit {
192*8a41f4deSParav Pandit 	TAILQ_REMOVE(&devices_list, dev, next);
193*8a41f4deSParav Pandit 	rte_free(dev);
194*8a41f4deSParav Pandit }
195*8a41f4deSParav Pandit 
196*8a41f4deSParav Pandit static int
197*8a41f4deSParav Pandit drivers_remove(struct mlx5_pci_device *dev, uint32_t enabled_classes)
198*8a41f4deSParav Pandit {
199*8a41f4deSParav Pandit 	struct mlx5_pci_driver *driver;
200*8a41f4deSParav Pandit 	int local_ret = -ENODEV;
201*8a41f4deSParav Pandit 	unsigned int i = 0;
202*8a41f4deSParav Pandit 	int ret = 0;
203*8a41f4deSParav Pandit 
204*8a41f4deSParav Pandit 	enabled_classes &= dev->classes_loaded;
205*8a41f4deSParav Pandit 	while (enabled_classes) {
206*8a41f4deSParav Pandit 		driver = driver_get(RTE_BIT64(i));
207*8a41f4deSParav Pandit 		if (driver) {
208*8a41f4deSParav Pandit 			local_ret = driver->pci_driver.remove(dev->pci_dev);
209*8a41f4deSParav Pandit 			if (!local_ret)
210*8a41f4deSParav Pandit 				dev->classes_loaded &= ~RTE_BIT64(i);
211*8a41f4deSParav Pandit 			else if (ret == 0)
212*8a41f4deSParav Pandit 				ret = local_ret;
213*8a41f4deSParav Pandit 		}
214*8a41f4deSParav Pandit 		enabled_classes &= ~RTE_BIT64(i);
215*8a41f4deSParav Pandit 		i++;
216*8a41f4deSParav Pandit 	}
217*8a41f4deSParav Pandit 	if (local_ret)
218*8a41f4deSParav Pandit 		ret = local_ret;
219*8a41f4deSParav Pandit 	return ret;
220*8a41f4deSParav Pandit }
221*8a41f4deSParav Pandit 
222*8a41f4deSParav Pandit static int
223*8a41f4deSParav Pandit drivers_probe(struct mlx5_pci_device *dev, struct rte_pci_driver *pci_drv,
224*8a41f4deSParav Pandit 	      struct rte_pci_device *pci_dev, uint32_t user_classes)
225*8a41f4deSParav Pandit {
226*8a41f4deSParav Pandit 	struct mlx5_pci_driver *driver;
227*8a41f4deSParav Pandit 	uint32_t enabled_classes = 0;
228*8a41f4deSParav Pandit 	bool already_loaded;
229*8a41f4deSParav Pandit 	int ret;
230*8a41f4deSParav Pandit 
231*8a41f4deSParav Pandit 	TAILQ_FOREACH(driver, &drv_list, next) {
232*8a41f4deSParav Pandit 		if ((driver->driver_class & user_classes) == 0)
233*8a41f4deSParav Pandit 			continue;
234*8a41f4deSParav Pandit 		if (!mlx5_bus_match(driver, pci_dev))
235*8a41f4deSParav Pandit 			continue;
236*8a41f4deSParav Pandit 		already_loaded = dev->classes_loaded & driver->driver_class;
237*8a41f4deSParav Pandit 		if (already_loaded &&
238*8a41f4deSParav Pandit 		    !(driver->pci_driver.drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) {
239*8a41f4deSParav Pandit 			DRV_LOG(ERR, "Device %s is already probed\n",
240*8a41f4deSParav Pandit 				pci_dev->device.name);
241*8a41f4deSParav Pandit 			ret = -EEXIST;
242*8a41f4deSParav Pandit 			goto probe_err;
243*8a41f4deSParav Pandit 		}
244*8a41f4deSParav Pandit 		ret = driver->pci_driver.probe(pci_drv, pci_dev);
245*8a41f4deSParav Pandit 		if (ret < 0) {
246*8a41f4deSParav Pandit 			DRV_LOG(ERR, "Failed to load driver = %s.\n",
247*8a41f4deSParav Pandit 				driver->pci_driver.driver.name);
248*8a41f4deSParav Pandit 			goto probe_err;
249*8a41f4deSParav Pandit 		}
250*8a41f4deSParav Pandit 		enabled_classes |= driver->driver_class;
251*8a41f4deSParav Pandit 	}
252*8a41f4deSParav Pandit 	dev->classes_loaded |= enabled_classes;
253*8a41f4deSParav Pandit 	return 0;
254*8a41f4deSParav Pandit probe_err:
255*8a41f4deSParav Pandit 	/* Only unload drivers which are enabled which were enabled
256*8a41f4deSParav Pandit 	 * in this probe instance.
257*8a41f4deSParav Pandit 	 */
258*8a41f4deSParav Pandit 	drivers_remove(dev, enabled_classes);
259*8a41f4deSParav Pandit 	return ret;
260*8a41f4deSParav Pandit }
261*8a41f4deSParav Pandit 
262*8a41f4deSParav Pandit /**
263*8a41f4deSParav Pandit  * DPDK callback to register to probe multiple drivers for a PCI device.
264*8a41f4deSParav Pandit  *
265*8a41f4deSParav Pandit  * @param[in] pci_drv
266*8a41f4deSParav Pandit  *   PCI driver structure.
267*8a41f4deSParav Pandit  * @param[in] dev
268*8a41f4deSParav Pandit  *   PCI device information.
269*8a41f4deSParav Pandit  *
270*8a41f4deSParav Pandit  * @return
271*8a41f4deSParav Pandit  *   0 on success, a negative errno value otherwise and rte_errno is set.
272*8a41f4deSParav Pandit  */
273*8a41f4deSParav Pandit static int
274*8a41f4deSParav Pandit mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
275*8a41f4deSParav Pandit 		      struct rte_pci_device *pci_dev)
276*8a41f4deSParav Pandit {
277*8a41f4deSParav Pandit 	struct mlx5_pci_device *dev;
278*8a41f4deSParav Pandit 	uint32_t user_classes = 0;
279*8a41f4deSParav Pandit 	bool new_device = false;
280*8a41f4deSParav Pandit 	int ret;
281*8a41f4deSParav Pandit 
282*8a41f4deSParav Pandit 	ret = parse_class_options(pci_dev->device.devargs);
283*8a41f4deSParav Pandit 	if (ret < 0)
284*8a41f4deSParav Pandit 		return ret;
285*8a41f4deSParav Pandit 	user_classes = ret;
286*8a41f4deSParav Pandit 	if (user_classes) {
287*8a41f4deSParav Pandit 		/* Validate combination here. */
288*8a41f4deSParav Pandit 		ret = is_valid_class_combination(user_classes);
289*8a41f4deSParav Pandit 		if (ret) {
290*8a41f4deSParav Pandit 			DRV_LOG(ERR, "Unsupported mlx5 classes supplied.");
291*8a41f4deSParav Pandit 			return ret;
292*8a41f4deSParav Pandit 		}
293*8a41f4deSParav Pandit 	} else {
294*8a41f4deSParav Pandit 		/* Default to net class. */
295*8a41f4deSParav Pandit 		user_classes = MLX5_CLASS_NET;
296*8a41f4deSParav Pandit 	}
297*8a41f4deSParav Pandit 	dev = pci_to_mlx5_device(pci_dev);
298*8a41f4deSParav Pandit 	if (!dev) {
299*8a41f4deSParav Pandit 		dev = rte_zmalloc("mlx5_pci_device", sizeof(*dev), 0);
300*8a41f4deSParav Pandit 		if (!dev)
301*8a41f4deSParav Pandit 			return -ENOMEM;
302*8a41f4deSParav Pandit 		dev->pci_dev = pci_dev;
303*8a41f4deSParav Pandit 		TAILQ_INSERT_HEAD(&devices_list, dev, next);
304*8a41f4deSParav Pandit 		new_device = true;
305*8a41f4deSParav Pandit 	}
306*8a41f4deSParav Pandit 	ret = drivers_probe(dev, pci_drv, pci_dev, user_classes);
307*8a41f4deSParav Pandit 	if (ret)
308*8a41f4deSParav Pandit 		goto class_err;
309*8a41f4deSParav Pandit 	return 0;
310*8a41f4deSParav Pandit class_err:
311*8a41f4deSParav Pandit 	if (new_device)
312*8a41f4deSParav Pandit 		dev_release(dev);
313*8a41f4deSParav Pandit 	return ret;
314*8a41f4deSParav Pandit }
315*8a41f4deSParav Pandit 
316*8a41f4deSParav Pandit /**
317*8a41f4deSParav Pandit  * DPDK callback to remove one or more drivers for a PCI device.
318*8a41f4deSParav Pandit  *
319*8a41f4deSParav Pandit  * This function removes all drivers probed for a given PCI device.
320*8a41f4deSParav Pandit  *
321*8a41f4deSParav Pandit  * @param[in] pci_dev
322*8a41f4deSParav Pandit  *   Pointer to the PCI device.
323*8a41f4deSParav Pandit  *
324*8a41f4deSParav Pandit  * @return
325*8a41f4deSParav Pandit  *   0 on success, the function cannot fail.
326*8a41f4deSParav Pandit  */
327*8a41f4deSParav Pandit static int
328*8a41f4deSParav Pandit mlx5_common_pci_remove(struct rte_pci_device *pci_dev)
329*8a41f4deSParav Pandit {
330*8a41f4deSParav Pandit 	struct mlx5_pci_device *dev;
331*8a41f4deSParav Pandit 	int ret;
332*8a41f4deSParav Pandit 
333*8a41f4deSParav Pandit 	dev = pci_to_mlx5_device(pci_dev);
334*8a41f4deSParav Pandit 	if (!dev)
335*8a41f4deSParav Pandit 		return -ENODEV;
336*8a41f4deSParav Pandit 	/* Matching device found, cleanup and unload drivers. */
337*8a41f4deSParav Pandit 	ret = drivers_remove(dev, dev->classes_loaded);
338*8a41f4deSParav Pandit 	if (!ret)
339*8a41f4deSParav Pandit 		dev_release(dev);
340*8a41f4deSParav Pandit 	return ret;
341*8a41f4deSParav Pandit }
342*8a41f4deSParav Pandit 
343*8a41f4deSParav Pandit static int
344*8a41f4deSParav Pandit mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
345*8a41f4deSParav Pandit 			uint64_t iova, size_t len)
346*8a41f4deSParav Pandit {
347*8a41f4deSParav Pandit 	struct mlx5_pci_driver *driver = NULL;
348*8a41f4deSParav Pandit 	struct mlx5_pci_driver *temp;
349*8a41f4deSParav Pandit 	struct mlx5_pci_device *dev;
350*8a41f4deSParav Pandit 	int ret = -EINVAL;
351*8a41f4deSParav Pandit 
352*8a41f4deSParav Pandit 	dev = pci_to_mlx5_device(pci_dev);
353*8a41f4deSParav Pandit 	if (!dev)
354*8a41f4deSParav Pandit 		return -ENODEV;
355*8a41f4deSParav Pandit 	TAILQ_FOREACH(driver, &drv_list, next) {
356*8a41f4deSParav Pandit 		if (device_class_enabled(dev, driver->driver_class) &&
357*8a41f4deSParav Pandit 		    driver->pci_driver.dma_map) {
358*8a41f4deSParav Pandit 			ret = driver->pci_driver.dma_map(pci_dev, addr,
359*8a41f4deSParav Pandit 							 iova, len);
360*8a41f4deSParav Pandit 			if (ret)
361*8a41f4deSParav Pandit 				goto map_err;
362*8a41f4deSParav Pandit 		}
363*8a41f4deSParav Pandit 	}
364*8a41f4deSParav Pandit 	return ret;
365*8a41f4deSParav Pandit map_err:
366*8a41f4deSParav Pandit 	TAILQ_FOREACH(temp, &drv_list, next) {
367*8a41f4deSParav Pandit 		if (temp == driver)
368*8a41f4deSParav Pandit 			break;
369*8a41f4deSParav Pandit 		if (device_class_enabled(dev, temp->driver_class) &&
370*8a41f4deSParav Pandit 		    temp->pci_driver.dma_map && temp->pci_driver.dma_unmap)
371*8a41f4deSParav Pandit 			temp->pci_driver.dma_unmap(pci_dev, addr, iova, len);
372*8a41f4deSParav Pandit 	}
373*8a41f4deSParav Pandit 	return ret;
374*8a41f4deSParav Pandit }
375*8a41f4deSParav Pandit 
376*8a41f4deSParav Pandit static int
377*8a41f4deSParav Pandit mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
378*8a41f4deSParav Pandit 			  uint64_t iova, size_t len)
379*8a41f4deSParav Pandit {
380*8a41f4deSParav Pandit 	struct mlx5_pci_driver *driver;
381*8a41f4deSParav Pandit 	struct mlx5_pci_device *dev;
382*8a41f4deSParav Pandit 	int local_ret = -EINVAL;
383*8a41f4deSParav Pandit 	int ret;
384*8a41f4deSParav Pandit 
385*8a41f4deSParav Pandit 	dev = pci_to_mlx5_device(pci_dev);
386*8a41f4deSParav Pandit 	if (!dev)
387*8a41f4deSParav Pandit 		return -ENODEV;
388*8a41f4deSParav Pandit 	ret = 0;
389*8a41f4deSParav Pandit 	/* There is no unmap error recovery in current implementation. */
390*8a41f4deSParav Pandit 	TAILQ_FOREACH_REVERSE(driver, &drv_list, mlx5_pci_bus_drv_head, next) {
391*8a41f4deSParav Pandit 		if (device_class_enabled(dev, driver->driver_class) &&
392*8a41f4deSParav Pandit 		    driver->pci_driver.dma_unmap) {
393*8a41f4deSParav Pandit 			local_ret = driver->pci_driver.dma_unmap(pci_dev, addr,
394*8a41f4deSParav Pandit 								 iova, len);
395*8a41f4deSParav Pandit 			if (local_ret && (ret == 0))
396*8a41f4deSParav Pandit 				ret = local_ret;
397*8a41f4deSParav Pandit 		}
398*8a41f4deSParav Pandit 	}
399*8a41f4deSParav Pandit 	if (local_ret)
400*8a41f4deSParav Pandit 		ret = local_ret;
401*8a41f4deSParav Pandit 	return ret;
402*8a41f4deSParav Pandit }
403*8a41f4deSParav Pandit 
404*8a41f4deSParav Pandit /* PCI ID table is build dynamically based on registered mlx5 drivers. */
405*8a41f4deSParav Pandit static struct rte_pci_id *mlx5_pci_id_table;
406*8a41f4deSParav Pandit 
407*8a41f4deSParav Pandit static struct rte_pci_driver mlx5_pci_driver = {
408*8a41f4deSParav Pandit 	.driver = {
409*8a41f4deSParav Pandit 		.name = "mlx5_pci",
410*8a41f4deSParav Pandit 	},
411*8a41f4deSParav Pandit 	.probe = mlx5_common_pci_probe,
412*8a41f4deSParav Pandit 	.remove = mlx5_common_pci_remove,
413*8a41f4deSParav Pandit 	.dma_map = mlx5_common_pci_dma_map,
414*8a41f4deSParav Pandit 	.dma_unmap = mlx5_common_pci_dma_unmap,
415*8a41f4deSParav Pandit };
416*8a41f4deSParav Pandit 
417*8a41f4deSParav Pandit static int
418*8a41f4deSParav Pandit pci_id_table_size_get(const struct rte_pci_id *id_table)
419*8a41f4deSParav Pandit {
420*8a41f4deSParav Pandit 	int table_size = 0;
421*8a41f4deSParav Pandit 
422*8a41f4deSParav Pandit 	for (; id_table->vendor_id != 0; id_table++)
423*8a41f4deSParav Pandit 		table_size++;
424*8a41f4deSParav Pandit 	return table_size;
425*8a41f4deSParav Pandit }
426*8a41f4deSParav Pandit 
427*8a41f4deSParav Pandit static bool
428*8a41f4deSParav Pandit pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table,
429*8a41f4deSParav Pandit 	      int next_idx)
430*8a41f4deSParav Pandit {
431*8a41f4deSParav Pandit 	int current_size = next_idx - 1;
432*8a41f4deSParav Pandit 	int i;
433*8a41f4deSParav Pandit 
434*8a41f4deSParav Pandit 	for (i = 0; i < current_size; i++) {
435*8a41f4deSParav Pandit 		if (id->device_id == table[i].device_id &&
436*8a41f4deSParav Pandit 		    id->vendor_id == table[i].vendor_id &&
437*8a41f4deSParav Pandit 		    id->subsystem_vendor_id == table[i].subsystem_vendor_id &&
438*8a41f4deSParav Pandit 		    id->subsystem_device_id == table[i].subsystem_device_id)
439*8a41f4deSParav Pandit 			return true;
440*8a41f4deSParav Pandit 	}
441*8a41f4deSParav Pandit 	return false;
442*8a41f4deSParav Pandit }
443*8a41f4deSParav Pandit 
444*8a41f4deSParav Pandit static void
445*8a41f4deSParav Pandit pci_id_insert(struct rte_pci_id *new_table, int *next_idx,
446*8a41f4deSParav Pandit 	      const struct rte_pci_id *id_table)
447*8a41f4deSParav Pandit {
448*8a41f4deSParav Pandit 	/* Traverse the id_table, check if entry exists in new_table;
449*8a41f4deSParav Pandit 	 * Add non duplicate entries to new table.
450*8a41f4deSParav Pandit 	 */
451*8a41f4deSParav Pandit 	for (; id_table->vendor_id != 0; id_table++) {
452*8a41f4deSParav Pandit 		if (!pci_id_exists(id_table, new_table, *next_idx)) {
453*8a41f4deSParav Pandit 			/* New entry; add to the table. */
454*8a41f4deSParav Pandit 			new_table[*next_idx] = *id_table;
455*8a41f4deSParav Pandit 			(*next_idx)++;
456*8a41f4deSParav Pandit 		}
457*8a41f4deSParav Pandit 	}
458*8a41f4deSParav Pandit }
459*8a41f4deSParav Pandit 
460*8a41f4deSParav Pandit static int
461*8a41f4deSParav Pandit pci_ids_table_update(const struct rte_pci_id *driver_id_table)
462*8a41f4deSParav Pandit {
463*8a41f4deSParav Pandit 	const struct rte_pci_id *id_iter;
464*8a41f4deSParav Pandit 	struct rte_pci_id *updated_table;
465*8a41f4deSParav Pandit 	struct rte_pci_id *old_table;
466*8a41f4deSParav Pandit 	int num_ids = 0;
467*8a41f4deSParav Pandit 	int i = 0;
468*8a41f4deSParav Pandit 
469*8a41f4deSParav Pandit 	old_table = mlx5_pci_id_table;
470*8a41f4deSParav Pandit 	if (old_table)
471*8a41f4deSParav Pandit 		num_ids = pci_id_table_size_get(old_table);
472*8a41f4deSParav Pandit 	num_ids += pci_id_table_size_get(driver_id_table);
473*8a41f4deSParav Pandit 	/* Increase size by one for the termination entry of vendor_id = 0. */
474*8a41f4deSParav Pandit 	num_ids += 1;
475*8a41f4deSParav Pandit 	updated_table = calloc(num_ids, sizeof(*updated_table));
476*8a41f4deSParav Pandit 	if (!updated_table)
477*8a41f4deSParav Pandit 		return -ENOMEM;
478*8a41f4deSParav Pandit 	if (TAILQ_EMPTY(&drv_list)) {
479*8a41f4deSParav Pandit 		/* Copy the first driver's ID table. */
480*8a41f4deSParav Pandit 		for (id_iter = driver_id_table; id_iter->vendor_id != 0;
481*8a41f4deSParav Pandit 		     id_iter++, i++)
482*8a41f4deSParav Pandit 			updated_table[i] = *id_iter;
483*8a41f4deSParav Pandit 	} else {
484*8a41f4deSParav Pandit 		/* First copy existing table entries. */
485*8a41f4deSParav Pandit 		for (id_iter = old_table; id_iter->vendor_id != 0;
486*8a41f4deSParav Pandit 		     id_iter++, i++)
487*8a41f4deSParav Pandit 			updated_table[i] = *id_iter;
488*8a41f4deSParav Pandit 		/* New id to be added at the end of current ID table. */
489*8a41f4deSParav Pandit 		pci_id_insert(updated_table, &i, driver_id_table);
490*8a41f4deSParav Pandit 	}
491*8a41f4deSParav Pandit 	/* Terminate table with empty entry. */
492*8a41f4deSParav Pandit 	updated_table[i].vendor_id = 0;
493*8a41f4deSParav Pandit 	mlx5_pci_driver.id_table = updated_table;
494*8a41f4deSParav Pandit 	mlx5_pci_id_table = updated_table;
495*8a41f4deSParav Pandit 	if (old_table)
496*8a41f4deSParav Pandit 		free(old_table);
497*8a41f4deSParav Pandit 	return 0;
498*8a41f4deSParav Pandit }
499*8a41f4deSParav Pandit 
500*8a41f4deSParav Pandit void
501*8a41f4deSParav Pandit mlx5_pci_driver_register(struct mlx5_pci_driver *driver)
502*8a41f4deSParav Pandit {
503*8a41f4deSParav Pandit 	int ret;
504*8a41f4deSParav Pandit 
505*8a41f4deSParav Pandit 	ret = pci_ids_table_update(driver->pci_driver.id_table);
506*8a41f4deSParav Pandit 	if (ret)
507*8a41f4deSParav Pandit 		return;
508*8a41f4deSParav Pandit 	mlx5_pci_driver.drv_flags |= driver->pci_driver.drv_flags;
509*8a41f4deSParav Pandit 	TAILQ_INSERT_TAIL(&drv_list, driver, next);
510*8a41f4deSParav Pandit }
511*8a41f4deSParav Pandit 
512*8a41f4deSParav Pandit void mlx5_common_pci_init(void)
513*8a41f4deSParav Pandit {
514*8a41f4deSParav Pandit 	const struct rte_pci_id empty_table[] = {
515*8a41f4deSParav Pandit 		{
516*8a41f4deSParav Pandit 			.vendor_id = 0
517*8a41f4deSParav Pandit 		},
518*8a41f4deSParav Pandit 	};
519*8a41f4deSParav Pandit 
520*8a41f4deSParav Pandit 	/* All mlx5 PMDs constructor runs at same priority. So any of the PMD
521*8a41f4deSParav Pandit 	 * including this one can register the PCI table first. If any other
522*8a41f4deSParav Pandit 	 * PMD(s) have registered the PCI ID table, No need to register an empty
523*8a41f4deSParav Pandit 	 * default one.
524*8a41f4deSParav Pandit 	 */
525*8a41f4deSParav Pandit 	if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table))
526*8a41f4deSParav Pandit 		return;
527*8a41f4deSParav Pandit 	rte_pci_register(&mlx5_pci_driver);
528*8a41f4deSParav Pandit }
529*8a41f4deSParav Pandit 
530*8a41f4deSParav Pandit RTE_FINI(mlx5_common_pci_finish)
531*8a41f4deSParav Pandit {
532*8a41f4deSParav Pandit 	if (mlx5_pci_id_table != NULL) {
533*8a41f4deSParav Pandit 		/* Constructor doesn't register with PCI bus if it failed
534*8a41f4deSParav Pandit 		 * to build the table.
535*8a41f4deSParav Pandit 		 */
536*8a41f4deSParav Pandit 		rte_pci_unregister(&mlx5_pci_driver);
537*8a41f4deSParav Pandit 		free(mlx5_pci_id_table);
538*8a41f4deSParav Pandit 	}
539*8a41f4deSParav Pandit }
540*8a41f4deSParav Pandit RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__);
541