Branch data Line data Source code
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 : 0 : rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev, 31 : : struct rte_pci_device *pci_dev) 32 : : { 33 [ # # ]: 0 : if ((eth_dev == NULL) || (pci_dev == NULL)) { 34 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "NULL pointer eth_dev=%p pci_dev=%p", 35 : : (void *)eth_dev, (void *)pci_dev); 36 : 0 : return; 37 : : } 38 : : 39 : 0 : eth_dev->intr_handle = pci_dev->intr_handle; 40 : : 41 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 42 : 0 : const struct rte_pci_driver *pci_drv; 43 : : 44 : 0 : pci_drv = RTE_BUS_DRIVER(pci_dev->device.driver, *pci_drv); 45 : 0 : eth_dev->data->dev_flags = 0; 46 [ # # ]: 0 : if (pci_drv->drv_flags & RTE_PCI_DRV_INTR_LSC) 47 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 48 [ # # ]: 0 : if (pci_drv->drv_flags & RTE_PCI_DRV_INTR_RMV) 49 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV; 50 : : 51 : 0 : eth_dev->data->numa_node = pci_dev->device.numa_node; 52 : : } 53 : : } 54 : : 55 : : static inline int 56 : 0 : eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device) 57 : : { 58 : : struct rte_pci_device *pci_dev = (struct rte_pci_device *)bus_device; 59 : : 60 [ # # ]: 0 : if (!pci_dev) 61 : : return -ENODEV; 62 : : 63 : 0 : rte_eth_copy_pci_info(eth_dev, pci_dev); 64 : : 65 : 0 : return 0; 66 : : } 67 : : 68 : : /** 69 : : * @internal 70 : : * Allocates a new ethdev slot for an Ethernet device and returns the pointer 71 : : * to that slot for the driver to use. 72 : : * 73 : : * @param dev 74 : : * Pointer to the PCI device 75 : : * 76 : : * @param private_data_size 77 : : * Size of private data structure 78 : : * 79 : : * @return 80 : : * A pointer to a rte_eth_dev or NULL if allocation failed. 81 : : */ 82 : : static inline struct rte_eth_dev * 83 : 0 : rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size) 84 : : { 85 : 0 : struct rte_eth_dev *eth_dev; 86 : 0 : const char *name; 87 : : 88 [ # # ]: 0 : if (!dev) 89 : : return NULL; 90 : : 91 : 0 : name = dev->device.name; 92 : : 93 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 94 : 0 : eth_dev = rte_eth_dev_allocate(name); 95 [ # # ]: 0 : if (!eth_dev) 96 : : return NULL; 97 : : 98 [ # # ]: 0 : if (private_data_size) { 99 : : /* Try and alloc the private-data structure on socket local to the device */ 100 : 0 : eth_dev->data->dev_private = rte_zmalloc_socket(name, 101 : : private_data_size, RTE_CACHE_LINE_SIZE, 102 : : dev->device.numa_node); 103 : : 104 : : /* if cannot allocate memory on the socket local to the device 105 : : * use rte_malloc to allocate memory on some other socket, if available. 106 : : */ 107 [ # # ]: 0 : if (eth_dev->data->dev_private == NULL) { 108 : 0 : eth_dev->data->dev_private = rte_zmalloc(name, 109 : : private_data_size, RTE_CACHE_LINE_SIZE); 110 : : 111 [ # # ]: 0 : if (eth_dev->data->dev_private == NULL) { 112 : 0 : rte_eth_dev_release_port(eth_dev); 113 : 0 : return NULL; 114 : : } 115 : : /* got memory, but not local, so issue warning */ 116 : 0 : RTE_ETHDEV_LOG_LINE(WARNING, 117 : : "Private data for ethdev '%s' not allocated on local NUMA node %d", 118 : : dev->device.name, dev->device.numa_node); 119 : : } 120 : : } 121 : : } else { 122 : 0 : eth_dev = rte_eth_dev_attach_secondary(name); 123 [ # # ]: 0 : if (!eth_dev) 124 : : return NULL; 125 : : } 126 : : 127 : 0 : eth_dev->device = &dev->device; 128 : 0 : rte_eth_copy_pci_info(eth_dev, dev); 129 : 0 : return eth_dev; 130 : : } 131 : : 132 : : typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev); 133 : : 134 : : /** 135 : : * @internal 136 : : * Wrapper for use by pci drivers in a .probe function to attach to a ethdev 137 : : * interface. 138 : : */ 139 : : static inline int 140 : 0 : rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev, 141 : : size_t private_data_size, eth_dev_pci_callback_t dev_init) 142 : : { 143 : : struct rte_eth_dev *eth_dev; 144 : : int ret; 145 : : 146 [ # # ]: 0 : if (*dev_init == NULL) 147 : : return -EINVAL; 148 : : 149 : 0 : eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size); 150 [ # # ]: 0 : if (!eth_dev) 151 : : return -ENOMEM; 152 : : 153 : 0 : ret = dev_init(eth_dev); 154 [ # # ]: 0 : if (ret) 155 : 0 : rte_eth_dev_release_port(eth_dev); 156 : : else 157 : 0 : rte_eth_dev_probing_finish(eth_dev); 158 : : 159 : : return ret; 160 : : } 161 : : 162 : : /** 163 : : * @internal 164 : : * Wrapper for use by pci drivers in a .remove function to detach a ethdev 165 : : * interface. 166 : : */ 167 : : static inline int 168 : 0 : rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev, 169 : : eth_dev_pci_callback_t dev_uninit) 170 : : { 171 : : struct rte_eth_dev *eth_dev; 172 : : int ret; 173 : : 174 : 0 : eth_dev = rte_eth_dev_allocated(pci_dev->device.name); 175 [ # # ]: 0 : if (!eth_dev) 176 : : return 0; 177 : : 178 : : /* 179 : : * In secondary process, a released eth device can be found by its name 180 : : * in shared memory. 181 : : * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the 182 : : * eth device has been released. 183 : : */ 184 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY && 185 [ # # ]: 0 : eth_dev->state == RTE_ETH_DEV_UNUSED) 186 : : return 0; 187 : : 188 [ # # ]: 0 : if (dev_uninit) { 189 : 0 : ret = dev_uninit(eth_dev); 190 [ # # ]: 0 : if (ret) 191 : : return ret; 192 : : } 193 : : 194 : 0 : rte_eth_dev_release_port(eth_dev); 195 : 0 : return 0; 196 : : } 197 : : 198 : : #ifdef __cplusplus 199 : : } 200 : : #endif 201 : : 202 : : #endif /* _RTE_ETHDEV_PCI_H_ */