1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 6WIND S.A. 3 * Copyright 2017 Mellanox. 4 */ 5 6 #include <rte_alarm.h> 7 #include <rte_malloc.h> 8 #include <rte_ethdev_driver.h> 9 #include <rte_ethdev_vdev.h> 10 #include <rte_devargs.h> 11 #include <rte_kvargs.h> 12 #include <rte_bus_vdev.h> 13 14 #include "failsafe_private.h" 15 16 const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME; 17 static const struct rte_eth_link eth_link = { 18 .link_speed = ETH_SPEED_NUM_10G, 19 .link_duplex = ETH_LINK_FULL_DUPLEX, 20 .link_status = ETH_LINK_UP, 21 .link_autoneg = ETH_LINK_AUTONEG, 22 }; 23 24 static int 25 fs_sub_device_alloc(struct rte_eth_dev *dev, 26 const char *params) 27 { 28 uint8_t nb_subs; 29 int ret; 30 int i; 31 32 ret = failsafe_args_count_subdevice(dev, params); 33 if (ret) 34 return ret; 35 if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) { 36 ERROR("Cannot allocate more than %d ports", 37 FAILSAFE_MAX_ETHPORTS); 38 return -ENOSPC; 39 } 40 nb_subs = PRIV(dev)->subs_tail; 41 PRIV(dev)->subs = rte_zmalloc(NULL, 42 sizeof(struct sub_device) * nb_subs, 43 RTE_CACHE_LINE_SIZE); 44 if (PRIV(dev)->subs == NULL) { 45 ERROR("Could not allocate sub_devices"); 46 return -ENOMEM; 47 } 48 /* Initiate static sub devices linked list. */ 49 for (i = 1; i < nb_subs; i++) 50 PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i; 51 PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs; 52 return 0; 53 } 54 55 static void 56 fs_sub_device_free(struct rte_eth_dev *dev) 57 { 58 rte_free(PRIV(dev)->subs); 59 } 60 61 static void fs_hotplug_alarm(void *arg); 62 63 int 64 failsafe_hotplug_alarm_install(struct rte_eth_dev *dev) 65 { 66 int ret; 67 68 if (dev == NULL) 69 return -EINVAL; 70 if (PRIV(dev)->pending_alarm) 71 return 0; 72 ret = rte_eal_alarm_set(hotplug_poll * 1000, 73 fs_hotplug_alarm, 74 dev); 75 if (ret) { 76 ERROR("Could not set up plug-in event detection"); 77 return ret; 78 } 79 PRIV(dev)->pending_alarm = 1; 80 return 0; 81 } 82 83 int 84 failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev) 85 { 86 int ret = 0; 87 88 rte_errno = 0; 89 rte_eal_alarm_cancel(fs_hotplug_alarm, dev); 90 if (rte_errno) { 91 ERROR("rte_eal_alarm_cancel failed (errno: %s)", 92 strerror(rte_errno)); 93 ret = -rte_errno; 94 } else { 95 PRIV(dev)->pending_alarm = 0; 96 } 97 return ret; 98 } 99 100 static void 101 fs_hotplug_alarm(void *arg) 102 { 103 struct rte_eth_dev *dev = arg; 104 struct sub_device *sdev; 105 int ret; 106 uint8_t i; 107 108 if (!PRIV(dev)->pending_alarm) 109 return; 110 PRIV(dev)->pending_alarm = 0; 111 FOREACH_SUBDEV(sdev, i, dev) 112 if (sdev->state != PRIV(dev)->state) 113 break; 114 /* if we have non-probed device */ 115 if (i != PRIV(dev)->subs_tail) { 116 if (fs_lock(dev, 1) != 0) 117 goto reinstall; 118 ret = failsafe_eth_dev_state_sync(dev); 119 fs_unlock(dev, 1); 120 if (ret) 121 ERROR("Unable to synchronize sub_device state"); 122 } 123 failsafe_dev_remove(dev); 124 reinstall: 125 ret = failsafe_hotplug_alarm_install(dev); 126 if (ret) 127 ERROR("Unable to set up next alarm"); 128 } 129 130 static int 131 fs_mutex_init(struct fs_priv *priv) 132 { 133 int ret; 134 pthread_mutexattr_t attr; 135 136 ret = pthread_mutexattr_init(&attr); 137 if (ret) { 138 ERROR("Cannot initiate mutex attributes - %s", strerror(ret)); 139 return ret; 140 } 141 /* Allow mutex relocks for the thread holding the mutex. */ 142 ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 143 if (ret) { 144 ERROR("Cannot set mutex type - %s", strerror(ret)); 145 return ret; 146 } 147 ret = pthread_mutex_init(&priv->hotplug_mutex, &attr); 148 if (ret) { 149 ERROR("Cannot initiate mutex - %s", strerror(ret)); 150 return ret; 151 } 152 return 0; 153 } 154 155 static int 156 fs_eth_dev_create(struct rte_vdev_device *vdev) 157 { 158 struct rte_eth_dev *dev; 159 struct ether_addr *mac; 160 struct fs_priv *priv; 161 struct sub_device *sdev; 162 const char *params; 163 unsigned int socket_id; 164 uint8_t i; 165 int ret; 166 167 dev = NULL; 168 priv = NULL; 169 socket_id = rte_socket_id(); 170 INFO("Creating fail-safe device on NUMA socket %u", socket_id); 171 params = rte_vdev_device_args(vdev); 172 if (params == NULL) { 173 ERROR("This PMD requires sub-devices, none provided"); 174 return -1; 175 } 176 dev = rte_eth_vdev_allocate(vdev, sizeof(*priv)); 177 if (dev == NULL) { 178 ERROR("Unable to allocate rte_eth_dev"); 179 return -1; 180 } 181 priv = PRIV(dev); 182 priv->dev = dev; 183 dev->dev_ops = &failsafe_ops; 184 dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0]; 185 dev->data->dev_link = eth_link; 186 PRIV(dev)->nb_mac_addr = 1; 187 TAILQ_INIT(&PRIV(dev)->flow_list); 188 dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst; 189 dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst; 190 ret = fs_sub_device_alloc(dev, params); 191 if (ret) { 192 ERROR("Could not allocate sub_devices"); 193 goto free_dev; 194 } 195 ret = failsafe_args_parse(dev, params); 196 if (ret) 197 goto free_subs; 198 ret = rte_eth_dev_owner_new(&priv->my_owner.id); 199 if (ret) { 200 ERROR("Failed to get unique owner identifier"); 201 goto free_args; 202 } 203 snprintf(priv->my_owner.name, sizeof(priv->my_owner.name), 204 FAILSAFE_OWNER_NAME); 205 ret = failsafe_eal_init(dev); 206 if (ret) 207 goto free_args; 208 ret = fs_mutex_init(priv); 209 if (ret) 210 goto free_args; 211 ret = failsafe_hotplug_alarm_install(dev); 212 if (ret) { 213 ERROR("Could not set up plug-in event detection"); 214 goto free_args; 215 } 216 mac = &dev->data->mac_addrs[0]; 217 if (mac_from_arg) { 218 /* 219 * If MAC address was provided as a parameter, 220 * apply to all probed slaves. 221 */ 222 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 223 ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 224 mac); 225 if (ret) { 226 ERROR("Failed to set default MAC address"); 227 goto free_args; 228 } 229 } 230 } else { 231 /* 232 * Use the ether_addr from first probed 233 * device, either preferred or fallback. 234 */ 235 FOREACH_SUBDEV(sdev, i, dev) 236 if (sdev->state >= DEV_PROBED) { 237 ether_addr_copy(Ð(sdev)->data->mac_addrs[0], 238 mac); 239 break; 240 } 241 /* 242 * If no device has been probed and no ether_addr 243 * has been provided on the command line, use a random 244 * valid one. 245 * It will be applied during future slave state syncs to 246 * probed slaves. 247 */ 248 if (i == priv->subs_tail) 249 eth_random_addr(&mac->addr_bytes[0]); 250 } 251 INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x", 252 mac->addr_bytes[0], mac->addr_bytes[1], 253 mac->addr_bytes[2], mac->addr_bytes[3], 254 mac->addr_bytes[4], mac->addr_bytes[5]); 255 dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 256 PRIV(dev)->intr_handle = (struct rte_intr_handle){ 257 .fd = -1, 258 .type = RTE_INTR_HANDLE_EXT, 259 }; 260 return 0; 261 free_args: 262 failsafe_args_free(dev); 263 free_subs: 264 fs_sub_device_free(dev); 265 free_dev: 266 rte_free(PRIV(dev)); 267 rte_eth_dev_release_port(dev); 268 return -1; 269 } 270 271 static int 272 fs_rte_eth_free(const char *name) 273 { 274 struct rte_eth_dev *dev; 275 int ret; 276 277 dev = rte_eth_dev_allocated(name); 278 if (dev == NULL) 279 return -ENODEV; 280 ret = failsafe_eal_uninit(dev); 281 if (ret) 282 ERROR("Error while uninitializing sub-EAL"); 283 failsafe_args_free(dev); 284 fs_sub_device_free(dev); 285 ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex); 286 if (ret) 287 ERROR("Error while destroying hotplug mutex"); 288 rte_free(PRIV(dev)); 289 rte_eth_dev_release_port(dev); 290 return ret; 291 } 292 293 static int 294 rte_pmd_failsafe_probe(struct rte_vdev_device *vdev) 295 { 296 const char *name; 297 298 name = rte_vdev_device_name(vdev); 299 INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s", 300 name); 301 return fs_eth_dev_create(vdev); 302 } 303 304 static int 305 rte_pmd_failsafe_remove(struct rte_vdev_device *vdev) 306 { 307 const char *name; 308 309 name = rte_vdev_device_name(vdev); 310 INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name); 311 return fs_rte_eth_free(name); 312 } 313 314 static struct rte_vdev_driver failsafe_drv = { 315 .probe = rte_pmd_failsafe_probe, 316 .remove = rte_pmd_failsafe_remove, 317 }; 318 319 RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv); 320 RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING); 321