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 #ifdef __cplusplus 10 extern "C" { 11 #endif 12 13 #include <rte_malloc.h> 14 #include <rte_pci.h> 15 #include <rte_bus_pci.h> 16 #include <rte_config.h> 17 #include <ethdev_driver.h> 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(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 eth_dev->data->dev_private = rte_zmalloc_socket(name, 97 private_data_size, RTE_CACHE_LINE_SIZE, 98 dev->device.numa_node); 99 if (!eth_dev->data->dev_private) { 100 rte_eth_dev_release_port(eth_dev); 101 return NULL; 102 } 103 } 104 } else { 105 eth_dev = rte_eth_dev_attach_secondary(name); 106 if (!eth_dev) 107 return NULL; 108 } 109 110 eth_dev->device = &dev->device; 111 rte_eth_copy_pci_info(eth_dev, dev); 112 return eth_dev; 113 } 114 115 typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev); 116 117 /** 118 * @internal 119 * Wrapper for use by pci drivers in a .probe function to attach to a ethdev 120 * interface. 121 */ 122 static inline int 123 rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev, 124 size_t private_data_size, eth_dev_pci_callback_t dev_init) 125 { 126 struct rte_eth_dev *eth_dev; 127 int ret; 128 129 eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size); 130 if (!eth_dev) 131 return -ENOMEM; 132 133 RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL); 134 ret = dev_init(eth_dev); 135 if (ret) 136 rte_eth_dev_release_port(eth_dev); 137 else 138 rte_eth_dev_probing_finish(eth_dev); 139 140 return ret; 141 } 142 143 /** 144 * @internal 145 * Wrapper for use by pci drivers in a .remove function to detach a ethdev 146 * interface. 147 */ 148 static inline int 149 rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev, 150 eth_dev_pci_callback_t dev_uninit) 151 { 152 struct rte_eth_dev *eth_dev; 153 int ret; 154 155 eth_dev = rte_eth_dev_allocated(pci_dev->device.name); 156 if (!eth_dev) 157 return 0; 158 159 /* 160 * In secondary process, a released eth device can be found by its name 161 * in shared memory. 162 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the 163 * eth device has been released. 164 */ 165 if (rte_eal_process_type() == RTE_PROC_SECONDARY && 166 eth_dev->state == RTE_ETH_DEV_UNUSED) 167 return 0; 168 169 if (dev_uninit) { 170 ret = dev_uninit(eth_dev); 171 if (ret) 172 return ret; 173 } 174 175 rte_eth_dev_release_port(eth_dev); 176 return 0; 177 } 178 179 #ifdef __cplusplus 180 } 181 #endif 182 183 #endif /* _RTE_ETHDEV_PCI_H_ */ 184