1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause 22bfe3f2eSlogwang * Copyright 2017 6WIND S.A. 3*d30ea906Sjfb8856606 * Copyright 2017 Mellanox Technologies, Ltd 42bfe3f2eSlogwang */ 52bfe3f2eSlogwang 62bfe3f2eSlogwang #include <rte_alarm.h> 72bfe3f2eSlogwang #include <rte_malloc.h> 8*d30ea906Sjfb8856606 #include <rte_ethdev_driver.h> 92bfe3f2eSlogwang #include <rte_ethdev_vdev.h> 102bfe3f2eSlogwang #include <rte_devargs.h> 112bfe3f2eSlogwang #include <rte_kvargs.h> 122bfe3f2eSlogwang #include <rte_bus_vdev.h> 132bfe3f2eSlogwang 142bfe3f2eSlogwang #include "failsafe_private.h" 152bfe3f2eSlogwang 16*d30ea906Sjfb8856606 int failsafe_logtype; 17*d30ea906Sjfb8856606 182bfe3f2eSlogwang const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME; 192bfe3f2eSlogwang static const struct rte_eth_link eth_link = { 202bfe3f2eSlogwang .link_speed = ETH_SPEED_NUM_10G, 212bfe3f2eSlogwang .link_duplex = ETH_LINK_FULL_DUPLEX, 222bfe3f2eSlogwang .link_status = ETH_LINK_UP, 232bfe3f2eSlogwang .link_autoneg = ETH_LINK_AUTONEG, 242bfe3f2eSlogwang }; 252bfe3f2eSlogwang 262bfe3f2eSlogwang static int 272bfe3f2eSlogwang fs_sub_device_alloc(struct rte_eth_dev *dev, 282bfe3f2eSlogwang const char *params) 292bfe3f2eSlogwang { 302bfe3f2eSlogwang uint8_t nb_subs; 312bfe3f2eSlogwang int ret; 32*d30ea906Sjfb8856606 int i; 332bfe3f2eSlogwang 342bfe3f2eSlogwang ret = failsafe_args_count_subdevice(dev, params); 352bfe3f2eSlogwang if (ret) 362bfe3f2eSlogwang return ret; 372bfe3f2eSlogwang if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) { 382bfe3f2eSlogwang ERROR("Cannot allocate more than %d ports", 392bfe3f2eSlogwang FAILSAFE_MAX_ETHPORTS); 402bfe3f2eSlogwang return -ENOSPC; 412bfe3f2eSlogwang } 422bfe3f2eSlogwang nb_subs = PRIV(dev)->subs_tail; 432bfe3f2eSlogwang PRIV(dev)->subs = rte_zmalloc(NULL, 442bfe3f2eSlogwang sizeof(struct sub_device) * nb_subs, 452bfe3f2eSlogwang RTE_CACHE_LINE_SIZE); 462bfe3f2eSlogwang if (PRIV(dev)->subs == NULL) { 472bfe3f2eSlogwang ERROR("Could not allocate sub_devices"); 482bfe3f2eSlogwang return -ENOMEM; 492bfe3f2eSlogwang } 50*d30ea906Sjfb8856606 /* Initiate static sub devices linked list. */ 51*d30ea906Sjfb8856606 for (i = 1; i < nb_subs; i++) 52*d30ea906Sjfb8856606 PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i; 53*d30ea906Sjfb8856606 PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs; 542bfe3f2eSlogwang return 0; 552bfe3f2eSlogwang } 562bfe3f2eSlogwang 572bfe3f2eSlogwang static void 582bfe3f2eSlogwang fs_sub_device_free(struct rte_eth_dev *dev) 592bfe3f2eSlogwang { 602bfe3f2eSlogwang rte_free(PRIV(dev)->subs); 612bfe3f2eSlogwang } 622bfe3f2eSlogwang 632bfe3f2eSlogwang static void fs_hotplug_alarm(void *arg); 642bfe3f2eSlogwang 652bfe3f2eSlogwang int 662bfe3f2eSlogwang failsafe_hotplug_alarm_install(struct rte_eth_dev *dev) 672bfe3f2eSlogwang { 682bfe3f2eSlogwang int ret; 692bfe3f2eSlogwang 702bfe3f2eSlogwang if (dev == NULL) 712bfe3f2eSlogwang return -EINVAL; 722bfe3f2eSlogwang if (PRIV(dev)->pending_alarm) 732bfe3f2eSlogwang return 0; 74*d30ea906Sjfb8856606 ret = rte_eal_alarm_set(failsafe_hotplug_poll * 1000, 752bfe3f2eSlogwang fs_hotplug_alarm, 762bfe3f2eSlogwang dev); 772bfe3f2eSlogwang if (ret) { 782bfe3f2eSlogwang ERROR("Could not set up plug-in event detection"); 792bfe3f2eSlogwang return ret; 802bfe3f2eSlogwang } 812bfe3f2eSlogwang PRIV(dev)->pending_alarm = 1; 822bfe3f2eSlogwang return 0; 832bfe3f2eSlogwang } 842bfe3f2eSlogwang 852bfe3f2eSlogwang int 862bfe3f2eSlogwang failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev) 872bfe3f2eSlogwang { 882bfe3f2eSlogwang int ret = 0; 892bfe3f2eSlogwang 902bfe3f2eSlogwang rte_errno = 0; 912bfe3f2eSlogwang rte_eal_alarm_cancel(fs_hotplug_alarm, dev); 922bfe3f2eSlogwang if (rte_errno) { 932bfe3f2eSlogwang ERROR("rte_eal_alarm_cancel failed (errno: %s)", 942bfe3f2eSlogwang strerror(rte_errno)); 952bfe3f2eSlogwang ret = -rte_errno; 962bfe3f2eSlogwang } else { 972bfe3f2eSlogwang PRIV(dev)->pending_alarm = 0; 982bfe3f2eSlogwang } 992bfe3f2eSlogwang return ret; 1002bfe3f2eSlogwang } 1012bfe3f2eSlogwang 1022bfe3f2eSlogwang static void 1032bfe3f2eSlogwang fs_hotplug_alarm(void *arg) 1042bfe3f2eSlogwang { 1052bfe3f2eSlogwang struct rte_eth_dev *dev = arg; 1062bfe3f2eSlogwang struct sub_device *sdev; 1072bfe3f2eSlogwang int ret; 1082bfe3f2eSlogwang uint8_t i; 1092bfe3f2eSlogwang 1102bfe3f2eSlogwang if (!PRIV(dev)->pending_alarm) 1112bfe3f2eSlogwang return; 1122bfe3f2eSlogwang PRIV(dev)->pending_alarm = 0; 1132bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) 1142bfe3f2eSlogwang if (sdev->state != PRIV(dev)->state) 1152bfe3f2eSlogwang break; 1162bfe3f2eSlogwang /* if we have non-probed device */ 1172bfe3f2eSlogwang if (i != PRIV(dev)->subs_tail) { 118*d30ea906Sjfb8856606 if (fs_lock(dev, 1) != 0) 119*d30ea906Sjfb8856606 goto reinstall; 1202bfe3f2eSlogwang ret = failsafe_eth_dev_state_sync(dev); 121*d30ea906Sjfb8856606 fs_unlock(dev, 1); 1222bfe3f2eSlogwang if (ret) 1232bfe3f2eSlogwang ERROR("Unable to synchronize sub_device state"); 1242bfe3f2eSlogwang } 1252bfe3f2eSlogwang failsafe_dev_remove(dev); 126*d30ea906Sjfb8856606 reinstall: 1272bfe3f2eSlogwang ret = failsafe_hotplug_alarm_install(dev); 1282bfe3f2eSlogwang if (ret) 1292bfe3f2eSlogwang ERROR("Unable to set up next alarm"); 1302bfe3f2eSlogwang } 1312bfe3f2eSlogwang 1322bfe3f2eSlogwang static int 133*d30ea906Sjfb8856606 fs_mutex_init(struct fs_priv *priv) 134*d30ea906Sjfb8856606 { 135*d30ea906Sjfb8856606 int ret; 136*d30ea906Sjfb8856606 pthread_mutexattr_t attr; 137*d30ea906Sjfb8856606 138*d30ea906Sjfb8856606 ret = pthread_mutexattr_init(&attr); 139*d30ea906Sjfb8856606 if (ret) { 140*d30ea906Sjfb8856606 ERROR("Cannot initiate mutex attributes - %s", strerror(ret)); 141*d30ea906Sjfb8856606 return ret; 142*d30ea906Sjfb8856606 } 143*d30ea906Sjfb8856606 /* Allow mutex relocks for the thread holding the mutex. */ 144*d30ea906Sjfb8856606 ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 145*d30ea906Sjfb8856606 if (ret) { 146*d30ea906Sjfb8856606 ERROR("Cannot set mutex type - %s", strerror(ret)); 147*d30ea906Sjfb8856606 return ret; 148*d30ea906Sjfb8856606 } 149*d30ea906Sjfb8856606 ret = pthread_mutex_init(&priv->hotplug_mutex, &attr); 150*d30ea906Sjfb8856606 if (ret) { 151*d30ea906Sjfb8856606 ERROR("Cannot initiate mutex - %s", strerror(ret)); 152*d30ea906Sjfb8856606 return ret; 153*d30ea906Sjfb8856606 } 154*d30ea906Sjfb8856606 return 0; 155*d30ea906Sjfb8856606 } 156*d30ea906Sjfb8856606 157*d30ea906Sjfb8856606 static int 1582bfe3f2eSlogwang fs_eth_dev_create(struct rte_vdev_device *vdev) 1592bfe3f2eSlogwang { 1602bfe3f2eSlogwang struct rte_eth_dev *dev; 1612bfe3f2eSlogwang struct ether_addr *mac; 1622bfe3f2eSlogwang struct fs_priv *priv; 1632bfe3f2eSlogwang struct sub_device *sdev; 1642bfe3f2eSlogwang const char *params; 1652bfe3f2eSlogwang unsigned int socket_id; 1662bfe3f2eSlogwang uint8_t i; 1672bfe3f2eSlogwang int ret; 1682bfe3f2eSlogwang 1692bfe3f2eSlogwang dev = NULL; 1702bfe3f2eSlogwang priv = NULL; 1712bfe3f2eSlogwang socket_id = rte_socket_id(); 1722bfe3f2eSlogwang INFO("Creating fail-safe device on NUMA socket %u", socket_id); 1732bfe3f2eSlogwang params = rte_vdev_device_args(vdev); 1742bfe3f2eSlogwang if (params == NULL) { 1752bfe3f2eSlogwang ERROR("This PMD requires sub-devices, none provided"); 1762bfe3f2eSlogwang return -1; 1772bfe3f2eSlogwang } 1782bfe3f2eSlogwang dev = rte_eth_vdev_allocate(vdev, sizeof(*priv)); 1792bfe3f2eSlogwang if (dev == NULL) { 1802bfe3f2eSlogwang ERROR("Unable to allocate rte_eth_dev"); 1812bfe3f2eSlogwang return -1; 1822bfe3f2eSlogwang } 1832bfe3f2eSlogwang priv = PRIV(dev); 1842bfe3f2eSlogwang priv->dev = dev; 1852bfe3f2eSlogwang dev->dev_ops = &failsafe_ops; 1862bfe3f2eSlogwang dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0]; 1872bfe3f2eSlogwang dev->data->dev_link = eth_link; 1882bfe3f2eSlogwang PRIV(dev)->nb_mac_addr = 1; 1892bfe3f2eSlogwang TAILQ_INIT(&PRIV(dev)->flow_list); 1902bfe3f2eSlogwang dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst; 1912bfe3f2eSlogwang dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst; 1922bfe3f2eSlogwang ret = fs_sub_device_alloc(dev, params); 1932bfe3f2eSlogwang if (ret) { 1942bfe3f2eSlogwang ERROR("Could not allocate sub_devices"); 1952bfe3f2eSlogwang goto free_dev; 1962bfe3f2eSlogwang } 1972bfe3f2eSlogwang ret = failsafe_args_parse(dev, params); 1982bfe3f2eSlogwang if (ret) 1992bfe3f2eSlogwang goto free_subs; 200*d30ea906Sjfb8856606 ret = rte_eth_dev_owner_new(&priv->my_owner.id); 201*d30ea906Sjfb8856606 if (ret) { 202*d30ea906Sjfb8856606 ERROR("Failed to get unique owner identifier"); 203*d30ea906Sjfb8856606 goto free_args; 204*d30ea906Sjfb8856606 } 205*d30ea906Sjfb8856606 snprintf(priv->my_owner.name, sizeof(priv->my_owner.name), 206*d30ea906Sjfb8856606 FAILSAFE_OWNER_NAME); 207*d30ea906Sjfb8856606 DEBUG("Failsafe port %u owner info: %s_%016"PRIX64, dev->data->port_id, 208*d30ea906Sjfb8856606 priv->my_owner.name, priv->my_owner.id); 209*d30ea906Sjfb8856606 ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_NEW, 210*d30ea906Sjfb8856606 failsafe_eth_new_event_callback, 211*d30ea906Sjfb8856606 dev); 212*d30ea906Sjfb8856606 if (ret) { 213*d30ea906Sjfb8856606 ERROR("Failed to register NEW callback"); 214*d30ea906Sjfb8856606 goto free_args; 215*d30ea906Sjfb8856606 } 2162bfe3f2eSlogwang ret = failsafe_eal_init(dev); 2172bfe3f2eSlogwang if (ret) 218*d30ea906Sjfb8856606 goto unregister_new_callback; 219*d30ea906Sjfb8856606 ret = fs_mutex_init(priv); 220*d30ea906Sjfb8856606 if (ret) 221*d30ea906Sjfb8856606 goto unregister_new_callback; 2222bfe3f2eSlogwang ret = failsafe_hotplug_alarm_install(dev); 2232bfe3f2eSlogwang if (ret) { 2242bfe3f2eSlogwang ERROR("Could not set up plug-in event detection"); 225*d30ea906Sjfb8856606 goto unregister_new_callback; 2262bfe3f2eSlogwang } 2272bfe3f2eSlogwang mac = &dev->data->mac_addrs[0]; 228*d30ea906Sjfb8856606 if (failsafe_mac_from_arg) { 2292bfe3f2eSlogwang /* 2302bfe3f2eSlogwang * If MAC address was provided as a parameter, 2312bfe3f2eSlogwang * apply to all probed slaves. 2322bfe3f2eSlogwang */ 2332bfe3f2eSlogwang FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 2342bfe3f2eSlogwang ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 2352bfe3f2eSlogwang mac); 2362bfe3f2eSlogwang if (ret) { 2372bfe3f2eSlogwang ERROR("Failed to set default MAC address"); 238579bf1e2Sjfb8856606 goto cancel_alarm; 2392bfe3f2eSlogwang } 2402bfe3f2eSlogwang } 2412bfe3f2eSlogwang } else { 2422bfe3f2eSlogwang /* 2432bfe3f2eSlogwang * Use the ether_addr from first probed 2442bfe3f2eSlogwang * device, either preferred or fallback. 2452bfe3f2eSlogwang */ 2462bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) 2472bfe3f2eSlogwang if (sdev->state >= DEV_PROBED) { 2482bfe3f2eSlogwang ether_addr_copy(Ð(sdev)->data->mac_addrs[0], 2492bfe3f2eSlogwang mac); 2502bfe3f2eSlogwang break; 2512bfe3f2eSlogwang } 2522bfe3f2eSlogwang /* 2532bfe3f2eSlogwang * If no device has been probed and no ether_addr 2542bfe3f2eSlogwang * has been provided on the command line, use a random 2552bfe3f2eSlogwang * valid one. 2562bfe3f2eSlogwang * It will be applied during future slave state syncs to 2572bfe3f2eSlogwang * probed slaves. 2582bfe3f2eSlogwang */ 2592bfe3f2eSlogwang if (i == priv->subs_tail) 2602bfe3f2eSlogwang eth_random_addr(&mac->addr_bytes[0]); 2612bfe3f2eSlogwang } 2622bfe3f2eSlogwang INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x", 2632bfe3f2eSlogwang mac->addr_bytes[0], mac->addr_bytes[1], 2642bfe3f2eSlogwang mac->addr_bytes[2], mac->addr_bytes[3], 2652bfe3f2eSlogwang mac->addr_bytes[4], mac->addr_bytes[5]); 2662bfe3f2eSlogwang dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 267*d30ea906Sjfb8856606 PRIV(dev)->intr_handle = (struct rte_intr_handle){ 268*d30ea906Sjfb8856606 .fd = -1, 269*d30ea906Sjfb8856606 .type = RTE_INTR_HANDLE_EXT, 270*d30ea906Sjfb8856606 }; 271*d30ea906Sjfb8856606 rte_eth_dev_probing_finish(dev); 2722bfe3f2eSlogwang return 0; 273579bf1e2Sjfb8856606 cancel_alarm: 274579bf1e2Sjfb8856606 failsafe_hotplug_alarm_cancel(dev); 275*d30ea906Sjfb8856606 unregister_new_callback: 276*d30ea906Sjfb8856606 rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW, 277*d30ea906Sjfb8856606 failsafe_eth_new_event_callback, dev); 2782bfe3f2eSlogwang free_args: 2792bfe3f2eSlogwang failsafe_args_free(dev); 2802bfe3f2eSlogwang free_subs: 2812bfe3f2eSlogwang fs_sub_device_free(dev); 2822bfe3f2eSlogwang free_dev: 283*d30ea906Sjfb8856606 /* mac_addrs must not be freed alone because part of dev_private */ 284*d30ea906Sjfb8856606 dev->data->mac_addrs = NULL; 2852bfe3f2eSlogwang rte_eth_dev_release_port(dev); 2862bfe3f2eSlogwang return -1; 2872bfe3f2eSlogwang } 2882bfe3f2eSlogwang 2892bfe3f2eSlogwang static int 2902bfe3f2eSlogwang fs_rte_eth_free(const char *name) 2912bfe3f2eSlogwang { 2922bfe3f2eSlogwang struct rte_eth_dev *dev; 2932bfe3f2eSlogwang int ret; 2942bfe3f2eSlogwang 2952bfe3f2eSlogwang dev = rte_eth_dev_allocated(name); 2962bfe3f2eSlogwang if (dev == NULL) 2972bfe3f2eSlogwang return -ENODEV; 298*d30ea906Sjfb8856606 rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW, 299*d30ea906Sjfb8856606 failsafe_eth_new_event_callback, dev); 3002bfe3f2eSlogwang ret = failsafe_eal_uninit(dev); 3012bfe3f2eSlogwang if (ret) 3022bfe3f2eSlogwang ERROR("Error while uninitializing sub-EAL"); 3032bfe3f2eSlogwang failsafe_args_free(dev); 3042bfe3f2eSlogwang fs_sub_device_free(dev); 305*d30ea906Sjfb8856606 ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex); 306*d30ea906Sjfb8856606 if (ret) 307*d30ea906Sjfb8856606 ERROR("Error while destroying hotplug mutex"); 308*d30ea906Sjfb8856606 rte_free(PRIV(dev)->mcast_addrs); 309*d30ea906Sjfb8856606 /* mac_addrs must not be freed alone because part of dev_private */ 310*d30ea906Sjfb8856606 dev->data->mac_addrs = NULL; 3112bfe3f2eSlogwang rte_eth_dev_release_port(dev); 3122bfe3f2eSlogwang return ret; 3132bfe3f2eSlogwang } 3142bfe3f2eSlogwang 3152bfe3f2eSlogwang static int 3162bfe3f2eSlogwang rte_pmd_failsafe_probe(struct rte_vdev_device *vdev) 3172bfe3f2eSlogwang { 3182bfe3f2eSlogwang const char *name; 319*d30ea906Sjfb8856606 struct rte_eth_dev *eth_dev; 3202bfe3f2eSlogwang 3212bfe3f2eSlogwang name = rte_vdev_device_name(vdev); 3222bfe3f2eSlogwang INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s", 3232bfe3f2eSlogwang name); 324*d30ea906Sjfb8856606 325*d30ea906Sjfb8856606 if (rte_eal_process_type() == RTE_PROC_SECONDARY && 326*d30ea906Sjfb8856606 strlen(rte_vdev_device_args(vdev)) == 0) { 327*d30ea906Sjfb8856606 eth_dev = rte_eth_dev_attach_secondary(name); 328*d30ea906Sjfb8856606 if (!eth_dev) { 329*d30ea906Sjfb8856606 ERROR("Failed to probe %s", name); 330*d30ea906Sjfb8856606 return -1; 331*d30ea906Sjfb8856606 } 332*d30ea906Sjfb8856606 /* TODO: request info from primary to set up Rx and Tx */ 333*d30ea906Sjfb8856606 eth_dev->dev_ops = &failsafe_ops; 334*d30ea906Sjfb8856606 eth_dev->device = &vdev->device; 335*d30ea906Sjfb8856606 rte_eth_dev_probing_finish(eth_dev); 336*d30ea906Sjfb8856606 return 0; 337*d30ea906Sjfb8856606 } 338*d30ea906Sjfb8856606 3392bfe3f2eSlogwang return fs_eth_dev_create(vdev); 3402bfe3f2eSlogwang } 3412bfe3f2eSlogwang 3422bfe3f2eSlogwang static int 3432bfe3f2eSlogwang rte_pmd_failsafe_remove(struct rte_vdev_device *vdev) 3442bfe3f2eSlogwang { 3452bfe3f2eSlogwang const char *name; 3462bfe3f2eSlogwang 3472bfe3f2eSlogwang name = rte_vdev_device_name(vdev); 3482bfe3f2eSlogwang INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name); 3492bfe3f2eSlogwang return fs_rte_eth_free(name); 3502bfe3f2eSlogwang } 3512bfe3f2eSlogwang 3522bfe3f2eSlogwang static struct rte_vdev_driver failsafe_drv = { 3532bfe3f2eSlogwang .probe = rte_pmd_failsafe_probe, 3542bfe3f2eSlogwang .remove = rte_pmd_failsafe_remove, 3552bfe3f2eSlogwang }; 3562bfe3f2eSlogwang 3572bfe3f2eSlogwang RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv); 3582bfe3f2eSlogwang RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING); 359*d30ea906Sjfb8856606 360*d30ea906Sjfb8856606 RTE_INIT(failsafe_init_log) 361*d30ea906Sjfb8856606 { 362*d30ea906Sjfb8856606 failsafe_logtype = rte_log_register("pmd.net.failsafe"); 363*d30ea906Sjfb8856606 if (failsafe_logtype >= 0) 364*d30ea906Sjfb8856606 rte_log_set_level(failsafe_logtype, RTE_LOG_NOTICE); 365*d30ea906Sjfb8856606 } 366