12bfe3f2eSlogwang /*- 22bfe3f2eSlogwang * BSD LICENSE 32bfe3f2eSlogwang * 42bfe3f2eSlogwang * Copyright 2017 6WIND S.A. 52bfe3f2eSlogwang * Copyright 2017 Mellanox. 62bfe3f2eSlogwang * 72bfe3f2eSlogwang * Redistribution and use in source and binary forms, with or without 82bfe3f2eSlogwang * modification, are permitted provided that the following conditions 92bfe3f2eSlogwang * are met: 102bfe3f2eSlogwang * 112bfe3f2eSlogwang * * Redistributions of source code must retain the above copyright 122bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer. 132bfe3f2eSlogwang * * Redistributions in binary form must reproduce the above copyright 142bfe3f2eSlogwang * notice, this list of conditions and the following disclaimer in 152bfe3f2eSlogwang * the documentation and/or other materials provided with the 162bfe3f2eSlogwang * distribution. 172bfe3f2eSlogwang * * Neither the name of 6WIND S.A. nor the names of its 182bfe3f2eSlogwang * contributors may be used to endorse or promote products derived 192bfe3f2eSlogwang * from this software without specific prior written permission. 202bfe3f2eSlogwang * 212bfe3f2eSlogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 222bfe3f2eSlogwang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 232bfe3f2eSlogwang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 242bfe3f2eSlogwang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 252bfe3f2eSlogwang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 262bfe3f2eSlogwang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 272bfe3f2eSlogwang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 282bfe3f2eSlogwang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 292bfe3f2eSlogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 302bfe3f2eSlogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 312bfe3f2eSlogwang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 322bfe3f2eSlogwang */ 332bfe3f2eSlogwang 342bfe3f2eSlogwang #include <rte_alarm.h> 352bfe3f2eSlogwang #include <rte_malloc.h> 362bfe3f2eSlogwang #include <rte_ethdev.h> 372bfe3f2eSlogwang #include <rte_ethdev_vdev.h> 382bfe3f2eSlogwang #include <rte_devargs.h> 392bfe3f2eSlogwang #include <rte_kvargs.h> 402bfe3f2eSlogwang #include <rte_bus_vdev.h> 412bfe3f2eSlogwang 422bfe3f2eSlogwang #include "failsafe_private.h" 432bfe3f2eSlogwang 442bfe3f2eSlogwang const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME; 452bfe3f2eSlogwang static const struct rte_eth_link eth_link = { 462bfe3f2eSlogwang .link_speed = ETH_SPEED_NUM_10G, 472bfe3f2eSlogwang .link_duplex = ETH_LINK_FULL_DUPLEX, 482bfe3f2eSlogwang .link_status = ETH_LINK_UP, 492bfe3f2eSlogwang .link_autoneg = ETH_LINK_AUTONEG, 502bfe3f2eSlogwang }; 512bfe3f2eSlogwang 522bfe3f2eSlogwang static int 532bfe3f2eSlogwang fs_sub_device_alloc(struct rte_eth_dev *dev, 542bfe3f2eSlogwang const char *params) 552bfe3f2eSlogwang { 562bfe3f2eSlogwang uint8_t nb_subs; 572bfe3f2eSlogwang int ret; 582bfe3f2eSlogwang 592bfe3f2eSlogwang ret = failsafe_args_count_subdevice(dev, params); 602bfe3f2eSlogwang if (ret) 612bfe3f2eSlogwang return ret; 622bfe3f2eSlogwang if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) { 632bfe3f2eSlogwang ERROR("Cannot allocate more than %d ports", 642bfe3f2eSlogwang FAILSAFE_MAX_ETHPORTS); 652bfe3f2eSlogwang return -ENOSPC; 662bfe3f2eSlogwang } 672bfe3f2eSlogwang nb_subs = PRIV(dev)->subs_tail; 682bfe3f2eSlogwang PRIV(dev)->subs = rte_zmalloc(NULL, 692bfe3f2eSlogwang sizeof(struct sub_device) * nb_subs, 702bfe3f2eSlogwang RTE_CACHE_LINE_SIZE); 712bfe3f2eSlogwang if (PRIV(dev)->subs == NULL) { 722bfe3f2eSlogwang ERROR("Could not allocate sub_devices"); 732bfe3f2eSlogwang return -ENOMEM; 742bfe3f2eSlogwang } 752bfe3f2eSlogwang return 0; 762bfe3f2eSlogwang } 772bfe3f2eSlogwang 782bfe3f2eSlogwang static void 792bfe3f2eSlogwang fs_sub_device_free(struct rte_eth_dev *dev) 802bfe3f2eSlogwang { 812bfe3f2eSlogwang rte_free(PRIV(dev)->subs); 822bfe3f2eSlogwang } 832bfe3f2eSlogwang 842bfe3f2eSlogwang static void fs_hotplug_alarm(void *arg); 852bfe3f2eSlogwang 862bfe3f2eSlogwang int 872bfe3f2eSlogwang failsafe_hotplug_alarm_install(struct rte_eth_dev *dev) 882bfe3f2eSlogwang { 892bfe3f2eSlogwang int ret; 902bfe3f2eSlogwang 912bfe3f2eSlogwang if (dev == NULL) 922bfe3f2eSlogwang return -EINVAL; 932bfe3f2eSlogwang if (PRIV(dev)->pending_alarm) 942bfe3f2eSlogwang return 0; 952bfe3f2eSlogwang ret = rte_eal_alarm_set(hotplug_poll * 1000, 962bfe3f2eSlogwang fs_hotplug_alarm, 972bfe3f2eSlogwang dev); 982bfe3f2eSlogwang if (ret) { 992bfe3f2eSlogwang ERROR("Could not set up plug-in event detection"); 1002bfe3f2eSlogwang return ret; 1012bfe3f2eSlogwang } 1022bfe3f2eSlogwang PRIV(dev)->pending_alarm = 1; 1032bfe3f2eSlogwang return 0; 1042bfe3f2eSlogwang } 1052bfe3f2eSlogwang 1062bfe3f2eSlogwang int 1072bfe3f2eSlogwang failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev) 1082bfe3f2eSlogwang { 1092bfe3f2eSlogwang int ret = 0; 1102bfe3f2eSlogwang 1112bfe3f2eSlogwang if (PRIV(dev)->pending_alarm) { 1122bfe3f2eSlogwang rte_errno = 0; 1132bfe3f2eSlogwang rte_eal_alarm_cancel(fs_hotplug_alarm, dev); 1142bfe3f2eSlogwang if (rte_errno) { 1152bfe3f2eSlogwang ERROR("rte_eal_alarm_cancel failed (errno: %s)", 1162bfe3f2eSlogwang strerror(rte_errno)); 1172bfe3f2eSlogwang ret = -rte_errno; 1182bfe3f2eSlogwang } else { 1192bfe3f2eSlogwang PRIV(dev)->pending_alarm = 0; 1202bfe3f2eSlogwang } 1212bfe3f2eSlogwang } 1222bfe3f2eSlogwang return ret; 1232bfe3f2eSlogwang } 1242bfe3f2eSlogwang 1252bfe3f2eSlogwang static void 1262bfe3f2eSlogwang fs_hotplug_alarm(void *arg) 1272bfe3f2eSlogwang { 1282bfe3f2eSlogwang struct rte_eth_dev *dev = arg; 1292bfe3f2eSlogwang struct sub_device *sdev; 1302bfe3f2eSlogwang int ret; 1312bfe3f2eSlogwang uint8_t i; 1322bfe3f2eSlogwang 1332bfe3f2eSlogwang if (!PRIV(dev)->pending_alarm) 1342bfe3f2eSlogwang return; 1352bfe3f2eSlogwang PRIV(dev)->pending_alarm = 0; 1362bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) 1372bfe3f2eSlogwang if (sdev->state != PRIV(dev)->state) 1382bfe3f2eSlogwang break; 1392bfe3f2eSlogwang /* if we have non-probed device */ 1402bfe3f2eSlogwang if (i != PRIV(dev)->subs_tail) { 1412bfe3f2eSlogwang ret = failsafe_eth_dev_state_sync(dev); 1422bfe3f2eSlogwang if (ret) 1432bfe3f2eSlogwang ERROR("Unable to synchronize sub_device state"); 1442bfe3f2eSlogwang } 1452bfe3f2eSlogwang failsafe_dev_remove(dev); 1462bfe3f2eSlogwang ret = failsafe_hotplug_alarm_install(dev); 1472bfe3f2eSlogwang if (ret) 1482bfe3f2eSlogwang ERROR("Unable to set up next alarm"); 1492bfe3f2eSlogwang } 1502bfe3f2eSlogwang 1512bfe3f2eSlogwang static int 1522bfe3f2eSlogwang fs_eth_dev_create(struct rte_vdev_device *vdev) 1532bfe3f2eSlogwang { 1542bfe3f2eSlogwang struct rte_eth_dev *dev; 1552bfe3f2eSlogwang struct ether_addr *mac; 1562bfe3f2eSlogwang struct fs_priv *priv; 1572bfe3f2eSlogwang struct sub_device *sdev; 1582bfe3f2eSlogwang const char *params; 1592bfe3f2eSlogwang unsigned int socket_id; 1602bfe3f2eSlogwang uint8_t i; 1612bfe3f2eSlogwang int ret; 1622bfe3f2eSlogwang 1632bfe3f2eSlogwang dev = NULL; 1642bfe3f2eSlogwang priv = NULL; 1652bfe3f2eSlogwang socket_id = rte_socket_id(); 1662bfe3f2eSlogwang INFO("Creating fail-safe device on NUMA socket %u", socket_id); 1672bfe3f2eSlogwang params = rte_vdev_device_args(vdev); 1682bfe3f2eSlogwang if (params == NULL) { 1692bfe3f2eSlogwang ERROR("This PMD requires sub-devices, none provided"); 1702bfe3f2eSlogwang return -1; 1712bfe3f2eSlogwang } 1722bfe3f2eSlogwang dev = rte_eth_vdev_allocate(vdev, sizeof(*priv)); 1732bfe3f2eSlogwang if (dev == NULL) { 1742bfe3f2eSlogwang ERROR("Unable to allocate rte_eth_dev"); 1752bfe3f2eSlogwang return -1; 1762bfe3f2eSlogwang } 1772bfe3f2eSlogwang priv = PRIV(dev); 1782bfe3f2eSlogwang priv->dev = dev; 1792bfe3f2eSlogwang dev->dev_ops = &failsafe_ops; 1802bfe3f2eSlogwang dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0]; 1812bfe3f2eSlogwang dev->data->dev_link = eth_link; 1822bfe3f2eSlogwang PRIV(dev)->nb_mac_addr = 1; 1832bfe3f2eSlogwang TAILQ_INIT(&PRIV(dev)->flow_list); 1842bfe3f2eSlogwang dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst; 1852bfe3f2eSlogwang dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst; 1862bfe3f2eSlogwang ret = fs_sub_device_alloc(dev, params); 1872bfe3f2eSlogwang if (ret) { 1882bfe3f2eSlogwang ERROR("Could not allocate sub_devices"); 1892bfe3f2eSlogwang goto free_dev; 1902bfe3f2eSlogwang } 1912bfe3f2eSlogwang ret = failsafe_args_parse(dev, params); 1922bfe3f2eSlogwang if (ret) 1932bfe3f2eSlogwang goto free_subs; 1942bfe3f2eSlogwang ret = failsafe_eal_init(dev); 1952bfe3f2eSlogwang if (ret) 1962bfe3f2eSlogwang goto free_args; 1972bfe3f2eSlogwang ret = failsafe_hotplug_alarm_install(dev); 1982bfe3f2eSlogwang if (ret) { 1992bfe3f2eSlogwang ERROR("Could not set up plug-in event detection"); 2002bfe3f2eSlogwang goto free_args; 2012bfe3f2eSlogwang } 2022bfe3f2eSlogwang mac = &dev->data->mac_addrs[0]; 2032bfe3f2eSlogwang if (mac_from_arg) { 2042bfe3f2eSlogwang /* 2052bfe3f2eSlogwang * If MAC address was provided as a parameter, 2062bfe3f2eSlogwang * apply to all probed slaves. 2072bfe3f2eSlogwang */ 2082bfe3f2eSlogwang FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 2092bfe3f2eSlogwang ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 2102bfe3f2eSlogwang mac); 2112bfe3f2eSlogwang if (ret) { 2122bfe3f2eSlogwang ERROR("Failed to set default MAC address"); 213*579bf1e2Sjfb8856606 goto cancel_alarm; 2142bfe3f2eSlogwang } 2152bfe3f2eSlogwang } 2162bfe3f2eSlogwang } else { 2172bfe3f2eSlogwang /* 2182bfe3f2eSlogwang * Use the ether_addr from first probed 2192bfe3f2eSlogwang * device, either preferred or fallback. 2202bfe3f2eSlogwang */ 2212bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) 2222bfe3f2eSlogwang if (sdev->state >= DEV_PROBED) { 2232bfe3f2eSlogwang ether_addr_copy(Ð(sdev)->data->mac_addrs[0], 2242bfe3f2eSlogwang mac); 2252bfe3f2eSlogwang break; 2262bfe3f2eSlogwang } 2272bfe3f2eSlogwang /* 2282bfe3f2eSlogwang * If no device has been probed and no ether_addr 2292bfe3f2eSlogwang * has been provided on the command line, use a random 2302bfe3f2eSlogwang * valid one. 2312bfe3f2eSlogwang * It will be applied during future slave state syncs to 2322bfe3f2eSlogwang * probed slaves. 2332bfe3f2eSlogwang */ 2342bfe3f2eSlogwang if (i == priv->subs_tail) 2352bfe3f2eSlogwang eth_random_addr(&mac->addr_bytes[0]); 2362bfe3f2eSlogwang } 2372bfe3f2eSlogwang INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x", 2382bfe3f2eSlogwang mac->addr_bytes[0], mac->addr_bytes[1], 2392bfe3f2eSlogwang mac->addr_bytes[2], mac->addr_bytes[3], 2402bfe3f2eSlogwang mac->addr_bytes[4], mac->addr_bytes[5]); 2412bfe3f2eSlogwang dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 2422bfe3f2eSlogwang return 0; 243*579bf1e2Sjfb8856606 cancel_alarm: 244*579bf1e2Sjfb8856606 failsafe_hotplug_alarm_cancel(dev); 2452bfe3f2eSlogwang free_args: 2462bfe3f2eSlogwang failsafe_args_free(dev); 2472bfe3f2eSlogwang free_subs: 2482bfe3f2eSlogwang fs_sub_device_free(dev); 2492bfe3f2eSlogwang free_dev: 2502bfe3f2eSlogwang rte_free(PRIV(dev)); 2512bfe3f2eSlogwang rte_eth_dev_release_port(dev); 2522bfe3f2eSlogwang return -1; 2532bfe3f2eSlogwang } 2542bfe3f2eSlogwang 2552bfe3f2eSlogwang static int 2562bfe3f2eSlogwang fs_rte_eth_free(const char *name) 2572bfe3f2eSlogwang { 2582bfe3f2eSlogwang struct rte_eth_dev *dev; 2592bfe3f2eSlogwang int ret; 2602bfe3f2eSlogwang 2612bfe3f2eSlogwang dev = rte_eth_dev_allocated(name); 2622bfe3f2eSlogwang if (dev == NULL) 2632bfe3f2eSlogwang return -ENODEV; 2642bfe3f2eSlogwang ret = failsafe_eal_uninit(dev); 2652bfe3f2eSlogwang if (ret) 2662bfe3f2eSlogwang ERROR("Error while uninitializing sub-EAL"); 2672bfe3f2eSlogwang failsafe_args_free(dev); 2682bfe3f2eSlogwang fs_sub_device_free(dev); 2692bfe3f2eSlogwang rte_free(PRIV(dev)); 2702bfe3f2eSlogwang rte_eth_dev_release_port(dev); 2712bfe3f2eSlogwang return ret; 2722bfe3f2eSlogwang } 2732bfe3f2eSlogwang 2742bfe3f2eSlogwang static int 2752bfe3f2eSlogwang rte_pmd_failsafe_probe(struct rte_vdev_device *vdev) 2762bfe3f2eSlogwang { 2772bfe3f2eSlogwang const char *name; 2782bfe3f2eSlogwang 2792bfe3f2eSlogwang name = rte_vdev_device_name(vdev); 2802bfe3f2eSlogwang INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s", 2812bfe3f2eSlogwang name); 2822bfe3f2eSlogwang return fs_eth_dev_create(vdev); 2832bfe3f2eSlogwang } 2842bfe3f2eSlogwang 2852bfe3f2eSlogwang static int 2862bfe3f2eSlogwang rte_pmd_failsafe_remove(struct rte_vdev_device *vdev) 2872bfe3f2eSlogwang { 2882bfe3f2eSlogwang const char *name; 2892bfe3f2eSlogwang 2902bfe3f2eSlogwang name = rte_vdev_device_name(vdev); 2912bfe3f2eSlogwang INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name); 2922bfe3f2eSlogwang return fs_rte_eth_free(name); 2932bfe3f2eSlogwang } 2942bfe3f2eSlogwang 2952bfe3f2eSlogwang static struct rte_vdev_driver failsafe_drv = { 2962bfe3f2eSlogwang .probe = rte_pmd_failsafe_probe, 2972bfe3f2eSlogwang .remove = rte_pmd_failsafe_remove, 2982bfe3f2eSlogwang }; 2992bfe3f2eSlogwang 3002bfe3f2eSlogwang RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv); 3012bfe3f2eSlogwang RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING); 302