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