1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2017 Brocade Communications Systems, Inc.
5  *   Author: Jan Blunck <[email protected]>
6  */
7 
8 #ifndef _RTE_ETHDEV_PCI_H_
9 #define _RTE_ETHDEV_PCI_H_
10 
11 #include <rte_malloc.h>
12 #include <rte_pci.h>
13 #include <rte_bus_pci.h>
14 #include <rte_config.h>
15 #include <rte_ethdev_driver.h>
16 
17 /**
18  * Copy pci device info to the Ethernet device data.
19  * Shared memory (eth_dev->data) only updated by primary process, so it is safe
20  * to call this function from both primary and secondary processes.
21  *
22  * @param eth_dev
23  * The *eth_dev* pointer is the address of the *rte_eth_dev* structure.
24  * @param pci_dev
25  * The *pci_dev* pointer is the address of the *rte_pci_device* structure.
26  */
27 static inline void
28 rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
29 	struct rte_pci_device *pci_dev)
30 {
31 	if ((eth_dev == NULL) || (pci_dev == NULL)) {
32 		RTE_ETHDEV_LOG(ERR, "NULL pointer eth_dev=%p pci_dev=%p",
33 			(void *)eth_dev, (void *)pci_dev);
34 		return;
35 	}
36 
37 	eth_dev->intr_handle = &pci_dev->intr_handle;
38 
39 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
40 		eth_dev->data->dev_flags = 0;
41 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
42 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
43 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_RMV)
44 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV;
45 
46 		eth_dev->data->kdrv = pci_dev->kdrv;
47 		eth_dev->data->numa_node = pci_dev->device.numa_node;
48 	}
49 }
50 
51 static inline int
52 eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device) {
53 	struct rte_pci_device *pci_dev = bus_device;
54 
55 	if (!pci_dev)
56 		return -ENODEV;
57 
58 	rte_eth_copy_pci_info(eth_dev, pci_dev);
59 
60 	return 0;
61 }
62 
63 /**
64  * @internal
65  * Allocates a new ethdev slot for an ethernet device and returns the pointer
66  * to that slot for the driver to use.
67  *
68  * @param dev
69  *	Pointer to the PCI device
70  *
71  * @param private_data_size
72  *	Size of private data structure
73  *
74  * @return
75  *	A pointer to a rte_eth_dev or NULL if allocation failed.
76  */
77 static inline struct rte_eth_dev *
78 rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size)
79 {
80 	struct rte_eth_dev *eth_dev;
81 	const char *name;
82 
83 	if (!dev)
84 		return NULL;
85 
86 	name = dev->device.name;
87 
88 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
89 		eth_dev = rte_eth_dev_allocate(name);
90 		if (!eth_dev)
91 			return NULL;
92 
93 		if (private_data_size) {
94 			eth_dev->data->dev_private = rte_zmalloc_socket(name,
95 				private_data_size, RTE_CACHE_LINE_SIZE,
96 				dev->device.numa_node);
97 			if (!eth_dev->data->dev_private) {
98 				rte_eth_dev_release_port(eth_dev);
99 				return NULL;
100 			}
101 		}
102 	} else {
103 		eth_dev = rte_eth_dev_attach_secondary(name);
104 		if (!eth_dev)
105 			return NULL;
106 	}
107 
108 	eth_dev->device = &dev->device;
109 	rte_eth_copy_pci_info(eth_dev, dev);
110 	return eth_dev;
111 }
112 
113 static inline void
114 rte_eth_dev_pci_release(struct rte_eth_dev *eth_dev)
115 {
116 	eth_dev->device = NULL;
117 	eth_dev->intr_handle = NULL;
118 
119 	/* free ether device */
120 	rte_eth_dev_release_port(eth_dev);
121 }
122 
123 typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev);
124 
125 /**
126  * @internal
127  * Wrapper for use by pci drivers in a .probe function to attach to a ethdev
128  * interface.
129  */
130 static inline int
131 rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
132 	size_t private_data_size, eth_dev_pci_callback_t dev_init)
133 {
134 	struct rte_eth_dev *eth_dev;
135 	int ret;
136 
137 	eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size);
138 	if (!eth_dev)
139 		return -ENOMEM;
140 
141 	RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL);
142 	ret = dev_init(eth_dev);
143 	if (ret)
144 		rte_eth_dev_pci_release(eth_dev);
145 	else
146 		rte_eth_dev_probing_finish(eth_dev);
147 
148 	return ret;
149 }
150 
151 /**
152  * @internal
153  * Wrapper for use by pci drivers in a .remove function to detach a ethdev
154  * interface.
155  */
156 static inline int
157 rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev,
158 	eth_dev_pci_callback_t dev_uninit)
159 {
160 	struct rte_eth_dev *eth_dev;
161 	int ret;
162 
163 	eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
164 	if (!eth_dev)
165 		return 0;
166 
167 	if (dev_uninit) {
168 		ret = dev_uninit(eth_dev);
169 		if (ret)
170 			return ret;
171 	}
172 
173 	rte_eth_dev_pci_release(eth_dev);
174 	return 0;
175 }
176 
177 #endif /* _RTE_ETHDEV_PCI_H_ */
178