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 struct rte_pci_device *pci_dev = bus_device; 55 56 if (!pci_dev) 57 return -ENODEV; 58 59 rte_eth_copy_pci_info(eth_dev, pci_dev); 60 61 return 0; 62 } 63 64 /** 65 * @internal 66 * Allocates a new ethdev slot for an Ethernet device and returns the pointer 67 * to that slot for the driver to use. 68 * 69 * @param dev 70 * Pointer to the PCI device 71 * 72 * @param private_data_size 73 * Size of private data structure 74 * 75 * @return 76 * A pointer to a rte_eth_dev or NULL if allocation failed. 77 */ 78 static inline struct rte_eth_dev * 79 rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size) 80 { 81 struct rte_eth_dev *eth_dev; 82 const char *name; 83 84 if (!dev) 85 return NULL; 86 87 name = dev->device.name; 88 89 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 90 eth_dev = rte_eth_dev_allocate(name); 91 if (!eth_dev) 92 return NULL; 93 94 if (private_data_size) { 95 eth_dev->data->dev_private = rte_zmalloc_socket(name, 96 private_data_size, RTE_CACHE_LINE_SIZE, 97 dev->device.numa_node); 98 if (!eth_dev->data->dev_private) { 99 rte_eth_dev_release_port(eth_dev); 100 return NULL; 101 } 102 } 103 } else { 104 eth_dev = rte_eth_dev_attach_secondary(name); 105 if (!eth_dev) 106 return NULL; 107 } 108 109 eth_dev->device = &dev->device; 110 rte_eth_copy_pci_info(eth_dev, dev); 111 return eth_dev; 112 } 113 114 typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev); 115 116 /** 117 * @internal 118 * Wrapper for use by pci drivers in a .probe function to attach to a ethdev 119 * interface. 120 */ 121 static inline int 122 rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev, 123 size_t private_data_size, eth_dev_pci_callback_t dev_init) 124 { 125 struct rte_eth_dev *eth_dev; 126 int ret; 127 128 eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size); 129 if (!eth_dev) 130 return -ENOMEM; 131 132 RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL); 133 ret = dev_init(eth_dev); 134 if (ret) 135 rte_eth_dev_release_port(eth_dev); 136 else 137 rte_eth_dev_probing_finish(eth_dev); 138 139 return ret; 140 } 141 142 /** 143 * @internal 144 * Wrapper for use by pci drivers in a .remove function to detach a ethdev 145 * interface. 146 */ 147 static inline int 148 rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev, 149 eth_dev_pci_callback_t dev_uninit) 150 { 151 struct rte_eth_dev *eth_dev; 152 int ret; 153 154 eth_dev = rte_eth_dev_allocated(pci_dev->device.name); 155 if (!eth_dev) 156 return 0; 157 158 /* 159 * In secondary process, a released eth device can be found by its name 160 * in shared memory. 161 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the 162 * eth device has been released. 163 */ 164 if (rte_eal_process_type() == RTE_PROC_SECONDARY && 165 eth_dev->state == RTE_ETH_DEV_UNUSED) 166 return 0; 167 168 if (dev_uninit) { 169 ret = dev_uninit(eth_dev); 170 if (ret) 171 return ret; 172 } 173 174 rte_eth_dev_release_port(eth_dev); 175 return 0; 176 } 177 178 #ifdef __cplusplus 179 } 180 #endif 181 182 #endif /* _RTE_ETHDEV_PCI_H_ */ 183