xref: /dpdk/lib/ethdev/ethdev_pci.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Brocade Communications Systems, Inc.
3  *   Author: Jan Blunck <jblunck@infradead.org>
4  */
5 
6 #ifndef _RTE_ETHDEV_PCI_H_
7 #define _RTE_ETHDEV_PCI_H_
8 
9 #include <rte_malloc.h>
10 #include <rte_pci.h>
11 #include <bus_pci_driver.h>
12 #include <rte_config.h>
13 #include <ethdev_driver.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /**
20  * Copy pci device info to the Ethernet device data.
21  * Shared memory (eth_dev->data) only updated by primary process, so it is safe
22  * to call this function from both primary and secondary processes.
23  *
24  * @param eth_dev
25  * The *eth_dev* pointer is the address of the *rte_eth_dev* structure.
26  * @param pci_dev
27  * The *pci_dev* pointer is the address of the *rte_pci_device* structure.
28  */
29 static inline void
30 rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
31 	struct rte_pci_device *pci_dev)
32 {
33 	if ((eth_dev == NULL) || (pci_dev == NULL)) {
34 		RTE_ETHDEV_LOG_LINE(ERR, "NULL pointer eth_dev=%p pci_dev=%p",
35 			(void *)eth_dev, (void *)pci_dev);
36 		return;
37 	}
38 
39 	eth_dev->intr_handle = pci_dev->intr_handle;
40 
41 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
42 		eth_dev->data->dev_flags = 0;
43 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
44 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
45 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_RMV)
46 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV;
47 
48 		eth_dev->data->numa_node = pci_dev->device.numa_node;
49 	}
50 }
51 
52 static inline int
53 eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device)
54 {
55 	struct rte_pci_device *pci_dev = (struct rte_pci_device *)bus_device;
56 
57 	if (!pci_dev)
58 		return -ENODEV;
59 
60 	rte_eth_copy_pci_info(eth_dev, pci_dev);
61 
62 	return 0;
63 }
64 
65 /**
66  * @internal
67  * Allocates a new ethdev slot for an Ethernet device and returns the pointer
68  * to that slot for the driver to use.
69  *
70  * @param dev
71  *	Pointer to the PCI device
72  *
73  * @param private_data_size
74  *	Size of private data structure
75  *
76  * @return
77  *	A pointer to a rte_eth_dev or NULL if allocation failed.
78  */
79 static inline struct rte_eth_dev *
80 rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size)
81 {
82 	struct rte_eth_dev *eth_dev;
83 	const char *name;
84 
85 	if (!dev)
86 		return NULL;
87 
88 	name = dev->device.name;
89 
90 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
91 		eth_dev = rte_eth_dev_allocate(name);
92 		if (!eth_dev)
93 			return NULL;
94 
95 		if (private_data_size) {
96 			/* Try and alloc the private-data structure on socket local to the device */
97 			eth_dev->data->dev_private = rte_zmalloc_socket(name,
98 				private_data_size, RTE_CACHE_LINE_SIZE,
99 				dev->device.numa_node);
100 
101 			/* if cannot allocate memory on the socket local to the device
102 			 * use rte_malloc to allocate memory on some other socket, if available.
103 			 */
104 			if (eth_dev->data->dev_private == NULL) {
105 				eth_dev->data->dev_private = rte_zmalloc(name,
106 						private_data_size, RTE_CACHE_LINE_SIZE);
107 
108 				if (eth_dev->data->dev_private == NULL) {
109 					rte_eth_dev_release_port(eth_dev);
110 					return NULL;
111 				}
112 				/* got memory, but not local, so issue warning */
113 				RTE_ETHDEV_LOG_LINE(WARNING,
114 						"Private data for ethdev '%s' not allocated on local NUMA node %d",
115 						dev->device.name, dev->device.numa_node);
116 			}
117 		}
118 	} else {
119 		eth_dev = rte_eth_dev_attach_secondary(name);
120 		if (!eth_dev)
121 			return NULL;
122 	}
123 
124 	eth_dev->device = &dev->device;
125 	rte_eth_copy_pci_info(eth_dev, dev);
126 	return eth_dev;
127 }
128 
129 typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev);
130 
131 /**
132  * @internal
133  * Wrapper for use by pci drivers in a .probe function to attach to a ethdev
134  * interface.
135  */
136 static inline int
137 rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
138 	size_t private_data_size, eth_dev_pci_callback_t dev_init)
139 {
140 	struct rte_eth_dev *eth_dev;
141 	int ret;
142 
143 	if (*dev_init == NULL)
144 		return -EINVAL;
145 
146 	eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size);
147 	if (!eth_dev)
148 		return -ENOMEM;
149 
150 	ret = dev_init(eth_dev);
151 	if (ret)
152 		rte_eth_dev_release_port(eth_dev);
153 	else
154 		rte_eth_dev_probing_finish(eth_dev);
155 
156 	return ret;
157 }
158 
159 /**
160  * @internal
161  * Wrapper for use by pci drivers in a .remove function to detach a ethdev
162  * interface.
163  */
164 static inline int
165 rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev,
166 	eth_dev_pci_callback_t dev_uninit)
167 {
168 	struct rte_eth_dev *eth_dev;
169 	int ret;
170 
171 	eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
172 	if (!eth_dev)
173 		return 0;
174 
175 	/*
176 	 * In secondary process, a released eth device can be found by its name
177 	 * in shared memory.
178 	 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the
179 	 * eth device has been released.
180 	 */
181 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
182 	    eth_dev->state == RTE_ETH_DEV_UNUSED)
183 		return 0;
184 
185 	if (dev_uninit) {
186 		ret = dev_uninit(eth_dev);
187 		if (ret)
188 			return ret;
189 	}
190 
191 	rte_eth_dev_release_port(eth_dev);
192 	return 0;
193 }
194 
195 #ifdef __cplusplus
196 }
197 #endif
198 
199 #endif /* _RTE_ETHDEV_PCI_H_ */
200