xref: /dpdk/drivers/common/mlx5/mlx5_common_pci.c (revision 37ca457d3fa69730714761a9dce8c673241d17d6)
18a41f4deSParav Pandit /* SPDX-License-Identifier: BSD-3-Clause
28a41f4deSParav Pandit  * Copyright 2020 Mellanox Technologies Ltd
38a41f4deSParav Pandit  */
48a41f4deSParav Pandit 
58a41f4deSParav Pandit #include <stdlib.h>
6ad435d32SXueming Li 
78a41f4deSParav Pandit #include <rte_malloc.h>
8ad435d32SXueming Li #include <rte_devargs.h>
9ad435d32SXueming Li #include <rte_errno.h>
1025245d5dSShiri Kuzin #include <rte_class.h>
11d3c52126SXueming Li #include <rte_pci.h>
12a04322f6SDavid Marchand #include <bus_driver.h>
131f37cb2bSDavid Marchand #include <bus_pci_driver.h>
1425245d5dSShiri Kuzin 
1525245d5dSShiri Kuzin #include "mlx5_common_log.h"
16ad435d32SXueming Li #include "mlx5_common_private.h"
17ad435d32SXueming Li 
18ad435d32SXueming Li static struct rte_pci_driver mlx5_common_pci_driver;
19ad435d32SXueming Li 
208a41f4deSParav Pandit /* PCI ID table is build dynamically based on registered mlx5 drivers. */
218a41f4deSParav Pandit static struct rte_pci_id *mlx5_pci_id_table;
228a41f4deSParav Pandit 
238a41f4deSParav Pandit static int
pci_id_table_size_get(const struct rte_pci_id * id_table)248a41f4deSParav Pandit pci_id_table_size_get(const struct rte_pci_id *id_table)
258a41f4deSParav Pandit {
268a41f4deSParav Pandit 	int table_size = 0;
278a41f4deSParav Pandit 
288a41f4deSParav Pandit 	for (; id_table->vendor_id != 0; id_table++)
298a41f4deSParav Pandit 		table_size++;
308a41f4deSParav Pandit 	return table_size;
318a41f4deSParav Pandit }
328a41f4deSParav Pandit 
338a41f4deSParav Pandit static bool
pci_id_exists(const struct rte_pci_id * id,const struct rte_pci_id * table,int next_idx)348a41f4deSParav Pandit pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table,
358a41f4deSParav Pandit 	      int next_idx)
368a41f4deSParav Pandit {
378a41f4deSParav Pandit 	int current_size = next_idx - 1;
388a41f4deSParav Pandit 	int i;
398a41f4deSParav Pandit 
408a41f4deSParav Pandit 	for (i = 0; i < current_size; i++) {
418a41f4deSParav Pandit 		if (id->device_id == table[i].device_id &&
428a41f4deSParav Pandit 		    id->vendor_id == table[i].vendor_id &&
438a41f4deSParav Pandit 		    id->subsystem_vendor_id == table[i].subsystem_vendor_id &&
448a41f4deSParav Pandit 		    id->subsystem_device_id == table[i].subsystem_device_id)
458a41f4deSParav Pandit 			return true;
468a41f4deSParav Pandit 	}
478a41f4deSParav Pandit 	return false;
488a41f4deSParav Pandit }
498a41f4deSParav Pandit 
508a41f4deSParav Pandit static void
pci_id_insert(struct rte_pci_id * new_table,int * next_idx,const struct rte_pci_id * id_table)518a41f4deSParav Pandit pci_id_insert(struct rte_pci_id *new_table, int *next_idx,
528a41f4deSParav Pandit 	      const struct rte_pci_id *id_table)
538a41f4deSParav Pandit {
548a41f4deSParav Pandit 	/* Traverse the id_table, check if entry exists in new_table;
558a41f4deSParav Pandit 	 * Add non duplicate entries to new table.
568a41f4deSParav Pandit 	 */
578a41f4deSParav Pandit 	for (; id_table->vendor_id != 0; id_table++) {
588a41f4deSParav Pandit 		if (!pci_id_exists(id_table, new_table, *next_idx)) {
598a41f4deSParav Pandit 			/* New entry; add to the table. */
608a41f4deSParav Pandit 			new_table[*next_idx] = *id_table;
618a41f4deSParav Pandit 			(*next_idx)++;
628a41f4deSParav Pandit 		}
638a41f4deSParav Pandit 	}
648a41f4deSParav Pandit }
658a41f4deSParav Pandit 
668a41f4deSParav Pandit static int
pci_ids_table_update(const struct rte_pci_id * driver_id_table)678a41f4deSParav Pandit pci_ids_table_update(const struct rte_pci_id *driver_id_table)
688a41f4deSParav Pandit {
698a41f4deSParav Pandit 	const struct rte_pci_id *id_iter;
708a41f4deSParav Pandit 	struct rte_pci_id *updated_table;
718a41f4deSParav Pandit 	struct rte_pci_id *old_table;
728a41f4deSParav Pandit 	int num_ids = 0;
738a41f4deSParav Pandit 	int i = 0;
748a41f4deSParav Pandit 
758a41f4deSParav Pandit 	old_table = mlx5_pci_id_table;
768a41f4deSParav Pandit 	if (old_table)
778a41f4deSParav Pandit 		num_ids = pci_id_table_size_get(old_table);
788a41f4deSParav Pandit 	num_ids += pci_id_table_size_get(driver_id_table);
798a41f4deSParav Pandit 	/* Increase size by one for the termination entry of vendor_id = 0. */
808a41f4deSParav Pandit 	num_ids += 1;
818a41f4deSParav Pandit 	updated_table = calloc(num_ids, sizeof(*updated_table));
828a41f4deSParav Pandit 	if (!updated_table)
838a41f4deSParav Pandit 		return -ENOMEM;
84ad435d32SXueming Li 	if (old_table == NULL) {
858a41f4deSParav Pandit 		/* Copy the first driver's ID table. */
868a41f4deSParav Pandit 		for (id_iter = driver_id_table; id_iter->vendor_id != 0;
878a41f4deSParav Pandit 		     id_iter++, i++)
888a41f4deSParav Pandit 			updated_table[i] = *id_iter;
898a41f4deSParav Pandit 	} else {
908a41f4deSParav Pandit 		/* First copy existing table entries. */
918a41f4deSParav Pandit 		for (id_iter = old_table; id_iter->vendor_id != 0;
928a41f4deSParav Pandit 		     id_iter++, i++)
938a41f4deSParav Pandit 			updated_table[i] = *id_iter;
948a41f4deSParav Pandit 		/* New id to be added at the end of current ID table. */
958a41f4deSParav Pandit 		pci_id_insert(updated_table, &i, driver_id_table);
968a41f4deSParav Pandit 	}
978a41f4deSParav Pandit 	/* Terminate table with empty entry. */
988a41f4deSParav Pandit 	updated_table[i].vendor_id = 0;
99ad435d32SXueming Li 	mlx5_common_pci_driver.id_table = updated_table;
1008a41f4deSParav Pandit 	mlx5_pci_id_table = updated_table;
1018a41f4deSParav Pandit 	free(old_table);
1028a41f4deSParav Pandit 	return 0;
1038a41f4deSParav Pandit }
1048a41f4deSParav Pandit 
105ad435d32SXueming Li bool
mlx5_dev_is_pci(const struct rte_device * dev)106ad435d32SXueming Li mlx5_dev_is_pci(const struct rte_device *dev)
107ad435d32SXueming Li {
108ad435d32SXueming Li 	return strcmp(dev->bus->name, "pci") == 0;
109ad435d32SXueming Li }
110ad435d32SXueming Li 
111ad435d32SXueming Li bool
mlx5_dev_is_vf_pci(const struct rte_pci_device * pci_dev)112*37ca457dSBing Zhao mlx5_dev_is_vf_pci(const struct rte_pci_device *pci_dev)
113c4c3e8afSMichael Baum {
114c4c3e8afSMichael Baum 	switch (pci_dev->id.device_id) {
115c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTX4VF:
116c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF:
117c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTX5VF:
118c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF:
1190a9fff95SRaslan Darawsheh 	case PCI_DEVICE_ID_MELLANOX_BLUEFIELDVF:
120c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTX6VF:
121c4c3e8afSMichael Baum 	case PCI_DEVICE_ID_MELLANOX_CONNECTXVF:
122c4c3e8afSMichael Baum 		return true;
123c4c3e8afSMichael Baum 	default:
124c4c3e8afSMichael Baum 		break;
125c4c3e8afSMichael Baum 	}
126c4c3e8afSMichael Baum 	return false;
127c4c3e8afSMichael Baum }
128c4c3e8afSMichael Baum 
129c4c3e8afSMichael Baum bool
mlx5_dev_pci_match(const struct mlx5_class_driver * drv,const struct rte_device * dev)130ad435d32SXueming Li mlx5_dev_pci_match(const struct mlx5_class_driver *drv,
131ad435d32SXueming Li 		   const struct rte_device *dev)
132ad435d32SXueming Li {
133ad435d32SXueming Li 	const struct rte_pci_device *pci_dev;
134ad435d32SXueming Li 	const struct rte_pci_id *id_table;
135ad435d32SXueming Li 
136ad435d32SXueming Li 	if (!mlx5_dev_is_pci(dev))
137ad435d32SXueming Li 		return false;
138ad435d32SXueming Li 	pci_dev = RTE_DEV_TO_PCI_CONST(dev);
139ad435d32SXueming Li 	for (id_table = drv->id_table; id_table->vendor_id != 0;
140ad435d32SXueming Li 	     id_table++) {
141ad435d32SXueming Li 		/* Check if device's ids match the class driver's ids. */
142ad435d32SXueming Li 		if (id_table->vendor_id != pci_dev->id.vendor_id &&
143ad435d32SXueming Li 		    id_table->vendor_id != RTE_PCI_ANY_ID)
144ad435d32SXueming Li 			continue;
145ad435d32SXueming Li 		if (id_table->device_id != pci_dev->id.device_id &&
146ad435d32SXueming Li 		    id_table->device_id != RTE_PCI_ANY_ID)
147ad435d32SXueming Li 			continue;
148ad435d32SXueming Li 		if (id_table->subsystem_vendor_id !=
149ad435d32SXueming Li 		    pci_dev->id.subsystem_vendor_id &&
150ad435d32SXueming Li 		    id_table->subsystem_vendor_id != RTE_PCI_ANY_ID)
151ad435d32SXueming Li 			continue;
152ad435d32SXueming Li 		if (id_table->subsystem_device_id !=
153ad435d32SXueming Li 		    pci_dev->id.subsystem_device_id &&
154ad435d32SXueming Li 		    id_table->subsystem_device_id != RTE_PCI_ANY_ID)
155ad435d32SXueming Li 			continue;
156ad435d32SXueming Li 		if (id_table->class_id != pci_dev->id.class_id &&
157ad435d32SXueming Li 		    id_table->class_id != RTE_CLASS_ANY_ID)
158ad435d32SXueming Li 			continue;
159ad435d32SXueming Li 		return true;
160ad435d32SXueming Li 	}
161ad435d32SXueming Li 	return false;
162ad435d32SXueming Li }
163ad435d32SXueming Li 
164ad435d32SXueming Li static int
mlx5_common_pci_probe(struct rte_pci_driver * pci_drv __rte_unused,struct rte_pci_device * pci_dev)165ad435d32SXueming Li mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
166ad435d32SXueming Li 		      struct rte_pci_device *pci_dev)
167ad435d32SXueming Li {
168ad435d32SXueming Li 	return mlx5_common_dev_probe(&pci_dev->device);
169ad435d32SXueming Li }
170ad435d32SXueming Li 
171ad435d32SXueming Li static int
mlx5_common_pci_remove(struct rte_pci_device * pci_dev)172ad435d32SXueming Li mlx5_common_pci_remove(struct rte_pci_device *pci_dev)
173ad435d32SXueming Li {
174ad435d32SXueming Li 	return mlx5_common_dev_remove(&pci_dev->device);
175ad435d32SXueming Li }
176ad435d32SXueming Li 
177ad435d32SXueming Li static int
mlx5_common_pci_dma_map(struct rte_pci_device * pci_dev,void * addr,uint64_t iova,size_t len)178ad435d32SXueming Li mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
179ad435d32SXueming Li 			uint64_t iova, size_t len)
180ad435d32SXueming Li {
181ad435d32SXueming Li 	return mlx5_common_dev_dma_map(&pci_dev->device, addr, iova, len);
182ad435d32SXueming Li }
183ad435d32SXueming Li 
184ad435d32SXueming Li static int
mlx5_common_pci_dma_unmap(struct rte_pci_device * pci_dev,void * addr,uint64_t iova,size_t len)185ad435d32SXueming Li mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
186ad435d32SXueming Li 			  uint64_t iova, size_t len)
187ad435d32SXueming Li {
188ad435d32SXueming Li 	return mlx5_common_dev_dma_unmap(&pci_dev->device, addr, iova, len);
189ad435d32SXueming Li }
190ad435d32SXueming Li 
191ad435d32SXueming Li void
mlx5_common_driver_on_register_pci(struct mlx5_class_driver * driver)192ad435d32SXueming Li mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver)
193ad435d32SXueming Li {
194ad435d32SXueming Li 	if (driver->id_table != NULL) {
195ad435d32SXueming Li 		if (pci_ids_table_update(driver->id_table) != 0)
196ad435d32SXueming Li 			return;
197ad435d32SXueming Li 	}
198ad435d32SXueming Li 	if (driver->probe_again)
199ad435d32SXueming Li 		mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_PROBE_AGAIN;
200ad435d32SXueming Li 	if (driver->intr_lsc)
201ad435d32SXueming Li 		mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC;
202ad435d32SXueming Li 	if (driver->intr_rmv)
203ad435d32SXueming Li 		mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV;
204ad435d32SXueming Li }
205ad435d32SXueming Li 
206ad435d32SXueming Li static struct rte_pci_driver mlx5_common_pci_driver = {
207ad435d32SXueming Li 	.driver = {
208ad435d32SXueming Li 		   .name = MLX5_PCI_DRIVER_NAME,
209ad435d32SXueming Li 	},
210ad435d32SXueming Li 	.probe = mlx5_common_pci_probe,
211ad435d32SXueming Li 	.remove = mlx5_common_pci_remove,
212ad435d32SXueming Li 	.dma_map = mlx5_common_pci_dma_map,
213ad435d32SXueming Li 	.dma_unmap = mlx5_common_pci_dma_unmap,
214ad435d32SXueming Li };
215ad435d32SXueming Li 
mlx5_common_pci_init(void)2168a41f4deSParav Pandit void mlx5_common_pci_init(void)
2178a41f4deSParav Pandit {
2188a41f4deSParav Pandit 	const struct rte_pci_id empty_table[] = {
2198a41f4deSParav Pandit 		{
2208a41f4deSParav Pandit 			.vendor_id = 0
2218a41f4deSParav Pandit 		},
2228a41f4deSParav Pandit 	};
2238a41f4deSParav Pandit 
2248a41f4deSParav Pandit 	/* All mlx5 PMDs constructor runs at same priority. So any of the PMD
2258a41f4deSParav Pandit 	 * including this one can register the PCI table first. If any other
2268a41f4deSParav Pandit 	 * PMD(s) have registered the PCI ID table, No need to register an empty
2278a41f4deSParav Pandit 	 * default one.
2288a41f4deSParav Pandit 	 */
2298a41f4deSParav Pandit 	if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table))
2308a41f4deSParav Pandit 		return;
231ad435d32SXueming Li 	rte_pci_register(&mlx5_common_pci_driver);
2328a41f4deSParav Pandit }
2338a41f4deSParav Pandit 
RTE_FINI(mlx5_common_pci_finish)2348a41f4deSParav Pandit RTE_FINI(mlx5_common_pci_finish)
2358a41f4deSParav Pandit {
2368a41f4deSParav Pandit 	if (mlx5_pci_id_table != NULL) {
2378a41f4deSParav Pandit 		/* Constructor doesn't register with PCI bus if it failed
2388a41f4deSParav Pandit 		 * to build the table.
2398a41f4deSParav Pandit 		 */
240ad435d32SXueming Li 		rte_pci_unregister(&mlx5_common_pci_driver);
2418a41f4deSParav Pandit 		free(mlx5_pci_id_table);
2428a41f4deSParav Pandit 	}
2438a41f4deSParav Pandit }
244ad435d32SXueming Li 
2458a41f4deSParav Pandit RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__);
246