1a46f8d58SGaetan Rivet /*- 2a46f8d58SGaetan Rivet * BSD LICENSE 3a46f8d58SGaetan Rivet * 4a46f8d58SGaetan Rivet * Copyright 2017 6WIND S.A. 5a46f8d58SGaetan Rivet * Copyright 2017 Mellanox. 6a46f8d58SGaetan Rivet * 7a46f8d58SGaetan Rivet * Redistribution and use in source and binary forms, with or without 8a46f8d58SGaetan Rivet * modification, are permitted provided that the following conditions 9a46f8d58SGaetan Rivet * are met: 10a46f8d58SGaetan Rivet * 11a46f8d58SGaetan Rivet * * Redistributions of source code must retain the above copyright 12a46f8d58SGaetan Rivet * notice, this list of conditions and the following disclaimer. 13a46f8d58SGaetan Rivet * * Redistributions in binary form must reproduce the above copyright 14a46f8d58SGaetan Rivet * notice, this list of conditions and the following disclaimer in 15a46f8d58SGaetan Rivet * the documentation and/or other materials provided with the 16a46f8d58SGaetan Rivet * distribution. 17a46f8d58SGaetan Rivet * * Neither the name of 6WIND S.A. nor the names of its 18a46f8d58SGaetan Rivet * contributors may be used to endorse or promote products derived 19a46f8d58SGaetan Rivet * from this software without specific prior written permission. 20a46f8d58SGaetan Rivet * 21a46f8d58SGaetan Rivet * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22a46f8d58SGaetan Rivet * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23a46f8d58SGaetan Rivet * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24a46f8d58SGaetan Rivet * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25a46f8d58SGaetan Rivet * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26a46f8d58SGaetan Rivet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27a46f8d58SGaetan Rivet * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28a46f8d58SGaetan Rivet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29a46f8d58SGaetan Rivet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30a46f8d58SGaetan Rivet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31a46f8d58SGaetan Rivet * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32a46f8d58SGaetan Rivet */ 33a46f8d58SGaetan Rivet 34a46f8d58SGaetan Rivet #include <rte_alarm.h> 35a46f8d58SGaetan Rivet #include <rte_malloc.h> 36a46f8d58SGaetan Rivet #include <rte_ethdev.h> 37a46f8d58SGaetan Rivet #include <rte_ethdev_vdev.h> 38a46f8d58SGaetan Rivet #include <rte_devargs.h> 39a46f8d58SGaetan Rivet #include <rte_kvargs.h> 40a46f8d58SGaetan Rivet #include <rte_vdev.h> 41a46f8d58SGaetan Rivet 42a46f8d58SGaetan Rivet #include "failsafe_private.h" 43a46f8d58SGaetan Rivet 44a46f8d58SGaetan Rivet const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME; 45a46f8d58SGaetan Rivet static const struct rte_eth_link eth_link = { 46a46f8d58SGaetan Rivet .link_speed = ETH_SPEED_NUM_10G, 47a46f8d58SGaetan Rivet .link_duplex = ETH_LINK_FULL_DUPLEX, 48a46f8d58SGaetan Rivet .link_status = ETH_LINK_UP, 49a46f8d58SGaetan Rivet .link_autoneg = ETH_LINK_SPEED_AUTONEG, 50a46f8d58SGaetan Rivet }; 51a46f8d58SGaetan Rivet 52a46f8d58SGaetan Rivet static int 53a46f8d58SGaetan Rivet fs_sub_device_alloc(struct rte_eth_dev *dev, 54a46f8d58SGaetan Rivet const char *params) 55a46f8d58SGaetan Rivet { 56a46f8d58SGaetan Rivet uint8_t nb_subs; 57a46f8d58SGaetan Rivet int ret; 58a46f8d58SGaetan Rivet 59a46f8d58SGaetan Rivet ret = failsafe_args_count_subdevice(dev, params); 60a46f8d58SGaetan Rivet if (ret) 61a46f8d58SGaetan Rivet return ret; 62a46f8d58SGaetan Rivet if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) { 63a46f8d58SGaetan Rivet ERROR("Cannot allocate more than %d ports", 64a46f8d58SGaetan Rivet FAILSAFE_MAX_ETHPORTS); 65a46f8d58SGaetan Rivet return -ENOSPC; 66a46f8d58SGaetan Rivet } 67a46f8d58SGaetan Rivet nb_subs = PRIV(dev)->subs_tail; 68a46f8d58SGaetan Rivet PRIV(dev)->subs = rte_zmalloc(NULL, 69a46f8d58SGaetan Rivet sizeof(struct sub_device) * nb_subs, 70a46f8d58SGaetan Rivet RTE_CACHE_LINE_SIZE); 71a46f8d58SGaetan Rivet if (PRIV(dev)->subs == NULL) { 72a46f8d58SGaetan Rivet ERROR("Could not allocate sub_devices"); 73a46f8d58SGaetan Rivet return -ENOMEM; 74a46f8d58SGaetan Rivet } 75a46f8d58SGaetan Rivet return 0; 76a46f8d58SGaetan Rivet } 77a46f8d58SGaetan Rivet 78a46f8d58SGaetan Rivet static void 79a46f8d58SGaetan Rivet fs_sub_device_free(struct rte_eth_dev *dev) 80a46f8d58SGaetan Rivet { 81a46f8d58SGaetan Rivet rte_free(PRIV(dev)->subs); 82a46f8d58SGaetan Rivet } 83a46f8d58SGaetan Rivet 84ebea83f8SGaetan Rivet static void fs_hotplug_alarm(void *arg); 85ebea83f8SGaetan Rivet 86ebea83f8SGaetan Rivet int 87ebea83f8SGaetan Rivet failsafe_hotplug_alarm_install(struct rte_eth_dev *dev) 88ebea83f8SGaetan Rivet { 89ebea83f8SGaetan Rivet int ret; 90ebea83f8SGaetan Rivet 91ebea83f8SGaetan Rivet if (dev == NULL) 92ebea83f8SGaetan Rivet return -EINVAL; 93ebea83f8SGaetan Rivet if (PRIV(dev)->pending_alarm) 94ebea83f8SGaetan Rivet return 0; 95ebea83f8SGaetan Rivet ret = rte_eal_alarm_set(hotplug_poll * 1000, 96ebea83f8SGaetan Rivet fs_hotplug_alarm, 97ebea83f8SGaetan Rivet dev); 98ebea83f8SGaetan Rivet if (ret) { 99ebea83f8SGaetan Rivet ERROR("Could not set up plug-in event detection"); 100ebea83f8SGaetan Rivet return ret; 101ebea83f8SGaetan Rivet } 102ebea83f8SGaetan Rivet PRIV(dev)->pending_alarm = 1; 103ebea83f8SGaetan Rivet return 0; 104ebea83f8SGaetan Rivet } 105ebea83f8SGaetan Rivet 106ebea83f8SGaetan Rivet int 107ebea83f8SGaetan Rivet failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev) 108ebea83f8SGaetan Rivet { 109ebea83f8SGaetan Rivet int ret = 0; 110ebea83f8SGaetan Rivet 111ebea83f8SGaetan Rivet if (PRIV(dev)->pending_alarm) { 112ebea83f8SGaetan Rivet rte_errno = 0; 113ebea83f8SGaetan Rivet rte_eal_alarm_cancel(fs_hotplug_alarm, dev); 114ebea83f8SGaetan Rivet if (rte_errno) { 115ebea83f8SGaetan Rivet ERROR("rte_eal_alarm_cancel failed (errno: %s)", 116ebea83f8SGaetan Rivet strerror(rte_errno)); 117ebea83f8SGaetan Rivet ret = -rte_errno; 118ebea83f8SGaetan Rivet } else { 119ebea83f8SGaetan Rivet PRIV(dev)->pending_alarm = 0; 120ebea83f8SGaetan Rivet } 121ebea83f8SGaetan Rivet } 122ebea83f8SGaetan Rivet return ret; 123ebea83f8SGaetan Rivet } 124ebea83f8SGaetan Rivet 125ebea83f8SGaetan Rivet static void 126ebea83f8SGaetan Rivet fs_hotplug_alarm(void *arg) 127ebea83f8SGaetan Rivet { 128ebea83f8SGaetan Rivet struct rte_eth_dev *dev = arg; 129ebea83f8SGaetan Rivet struct sub_device *sdev; 130ebea83f8SGaetan Rivet int ret; 131ebea83f8SGaetan Rivet uint8_t i; 132ebea83f8SGaetan Rivet 133ebea83f8SGaetan Rivet if (!PRIV(dev)->pending_alarm) 134ebea83f8SGaetan Rivet return; 135ebea83f8SGaetan Rivet PRIV(dev)->pending_alarm = 0; 136ebea83f8SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 137ebea83f8SGaetan Rivet if (sdev->state != PRIV(dev)->state) 138ebea83f8SGaetan Rivet break; 139ebea83f8SGaetan Rivet /* if we have non-probed device */ 140ebea83f8SGaetan Rivet if (i != PRIV(dev)->subs_tail) { 141ebea83f8SGaetan Rivet ret = failsafe_eth_dev_state_sync(dev); 142ebea83f8SGaetan Rivet if (ret) 143ebea83f8SGaetan Rivet ERROR("Unable to synchronize sub_device state"); 144ebea83f8SGaetan Rivet } 145598fb8aeSGaetan Rivet failsafe_dev_remove(dev); 146ebea83f8SGaetan Rivet ret = failsafe_hotplug_alarm_install(dev); 147ebea83f8SGaetan Rivet if (ret) 148ebea83f8SGaetan Rivet ERROR("Unable to set up next alarm"); 149ebea83f8SGaetan Rivet } 150ebea83f8SGaetan Rivet 151a46f8d58SGaetan Rivet static int 152a46f8d58SGaetan Rivet fs_eth_dev_create(struct rte_vdev_device *vdev) 153a46f8d58SGaetan Rivet { 154a46f8d58SGaetan Rivet struct rte_eth_dev *dev; 155a46f8d58SGaetan Rivet struct ether_addr *mac; 156a46f8d58SGaetan Rivet struct fs_priv *priv; 157a46f8d58SGaetan Rivet struct sub_device *sdev; 158a46f8d58SGaetan Rivet const char *params; 159a46f8d58SGaetan Rivet unsigned int socket_id; 160a46f8d58SGaetan Rivet uint8_t i; 161a46f8d58SGaetan Rivet int ret; 162a46f8d58SGaetan Rivet 163a46f8d58SGaetan Rivet dev = NULL; 164a46f8d58SGaetan Rivet priv = NULL; 165a46f8d58SGaetan Rivet socket_id = rte_socket_id(); 166a46f8d58SGaetan Rivet INFO("Creating fail-safe device on NUMA socket %u", socket_id); 167a46f8d58SGaetan Rivet params = rte_vdev_device_args(vdev); 168a46f8d58SGaetan Rivet if (params == NULL) { 169a46f8d58SGaetan Rivet ERROR("This PMD requires sub-devices, none provided"); 170a46f8d58SGaetan Rivet return -1; 171a46f8d58SGaetan Rivet } 172a46f8d58SGaetan Rivet dev = rte_eth_vdev_allocate(vdev, sizeof(*priv)); 173a46f8d58SGaetan Rivet if (dev == NULL) { 174a46f8d58SGaetan Rivet ERROR("Unable to allocate rte_eth_dev"); 175a46f8d58SGaetan Rivet return -1; 176a46f8d58SGaetan Rivet } 177a46f8d58SGaetan Rivet priv = PRIV(dev); 178a46f8d58SGaetan Rivet priv->dev = dev; 179a46f8d58SGaetan Rivet dev->dev_ops = &failsafe_ops; 180a46f8d58SGaetan Rivet dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0]; 181a46f8d58SGaetan Rivet dev->data->dev_link = eth_link; 182a46f8d58SGaetan Rivet PRIV(dev)->nb_mac_addr = 1; 183b737a1eeSGaetan Rivet TAILQ_INIT(&PRIV(dev)->flow_list); 184a46f8d58SGaetan Rivet dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst; 185a46f8d58SGaetan Rivet dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst; 186a46f8d58SGaetan Rivet ret = fs_sub_device_alloc(dev, params); 187a46f8d58SGaetan Rivet if (ret) { 188a46f8d58SGaetan Rivet ERROR("Could not allocate sub_devices"); 189a46f8d58SGaetan Rivet goto free_dev; 190a46f8d58SGaetan Rivet } 191a46f8d58SGaetan Rivet ret = failsafe_args_parse(dev, params); 192a46f8d58SGaetan Rivet if (ret) 193a46f8d58SGaetan Rivet goto free_subs; 194a46f8d58SGaetan Rivet ret = failsafe_eal_init(dev); 195a46f8d58SGaetan Rivet if (ret) 196a46f8d58SGaetan Rivet goto free_args; 197ebea83f8SGaetan Rivet ret = failsafe_hotplug_alarm_install(dev); 198ebea83f8SGaetan Rivet if (ret) { 199ebea83f8SGaetan Rivet ERROR("Could not set up plug-in event detection"); 200ebea83f8SGaetan Rivet goto free_args; 201ebea83f8SGaetan Rivet } 202a46f8d58SGaetan Rivet mac = &dev->data->mac_addrs[0]; 203a46f8d58SGaetan Rivet if (mac_from_arg) { 204a46f8d58SGaetan Rivet /* 205a46f8d58SGaetan Rivet * If MAC address was provided as a parameter, 206a46f8d58SGaetan Rivet * apply to all probed slaves. 207a46f8d58SGaetan Rivet */ 208a46f8d58SGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 209a46f8d58SGaetan Rivet ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 210a46f8d58SGaetan Rivet mac); 211a46f8d58SGaetan Rivet if (ret) { 212a46f8d58SGaetan Rivet ERROR("Failed to set default MAC address"); 213a46f8d58SGaetan Rivet goto free_args; 214a46f8d58SGaetan Rivet } 215a46f8d58SGaetan Rivet } 216a46f8d58SGaetan Rivet } else { 217a46f8d58SGaetan Rivet /* 218a46f8d58SGaetan Rivet * Use the ether_addr from first probed 219a46f8d58SGaetan Rivet * device, either preferred or fallback. 220a46f8d58SGaetan Rivet */ 221a46f8d58SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 222a46f8d58SGaetan Rivet if (sdev->state >= DEV_PROBED) { 223a46f8d58SGaetan Rivet ether_addr_copy(Ð(sdev)->data->mac_addrs[0], 224a46f8d58SGaetan Rivet mac); 225a46f8d58SGaetan Rivet break; 226a46f8d58SGaetan Rivet } 227a46f8d58SGaetan Rivet /* 228a46f8d58SGaetan Rivet * If no device has been probed and no ether_addr 229a46f8d58SGaetan Rivet * has been provided on the command line, use a random 230a46f8d58SGaetan Rivet * valid one. 231a46f8d58SGaetan Rivet * It will be applied during future slave state syncs to 232a46f8d58SGaetan Rivet * probed slaves. 233a46f8d58SGaetan Rivet */ 234a46f8d58SGaetan Rivet if (i == priv->subs_tail) 235a46f8d58SGaetan Rivet eth_random_addr(&mac->addr_bytes[0]); 236a46f8d58SGaetan Rivet } 237a46f8d58SGaetan Rivet INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x", 238a46f8d58SGaetan Rivet mac->addr_bytes[0], mac->addr_bytes[1], 239a46f8d58SGaetan Rivet mac->addr_bytes[2], mac->addr_bytes[3], 240a46f8d58SGaetan Rivet mac->addr_bytes[4], mac->addr_bytes[5]); 241*ad7d6a35SGaetan Rivet dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; 242a46f8d58SGaetan Rivet return 0; 243a46f8d58SGaetan Rivet free_args: 244a46f8d58SGaetan Rivet failsafe_args_free(dev); 245a46f8d58SGaetan Rivet free_subs: 246a46f8d58SGaetan Rivet fs_sub_device_free(dev); 247a46f8d58SGaetan Rivet free_dev: 248a46f8d58SGaetan Rivet rte_free(PRIV(dev)); 249a46f8d58SGaetan Rivet rte_eth_dev_release_port(dev); 250a46f8d58SGaetan Rivet return -1; 251a46f8d58SGaetan Rivet } 252a46f8d58SGaetan Rivet 253a46f8d58SGaetan Rivet static int 254a46f8d58SGaetan Rivet fs_rte_eth_free(const char *name) 255a46f8d58SGaetan Rivet { 256a46f8d58SGaetan Rivet struct rte_eth_dev *dev; 257a46f8d58SGaetan Rivet int ret; 258a46f8d58SGaetan Rivet 259a46f8d58SGaetan Rivet dev = rte_eth_dev_allocated(name); 260a46f8d58SGaetan Rivet if (dev == NULL) 261a46f8d58SGaetan Rivet return -ENODEV; 262a46f8d58SGaetan Rivet ret = failsafe_eal_uninit(dev); 263a46f8d58SGaetan Rivet if (ret) 264a46f8d58SGaetan Rivet ERROR("Error while uninitializing sub-EAL"); 265a46f8d58SGaetan Rivet failsafe_args_free(dev); 266a46f8d58SGaetan Rivet fs_sub_device_free(dev); 267a46f8d58SGaetan Rivet rte_free(PRIV(dev)); 268a46f8d58SGaetan Rivet rte_eth_dev_release_port(dev); 269a46f8d58SGaetan Rivet return ret; 270a46f8d58SGaetan Rivet } 271a46f8d58SGaetan Rivet 272a46f8d58SGaetan Rivet static int 273a46f8d58SGaetan Rivet rte_pmd_failsafe_probe(struct rte_vdev_device *vdev) 274a46f8d58SGaetan Rivet { 275a46f8d58SGaetan Rivet const char *name; 276a46f8d58SGaetan Rivet 277a46f8d58SGaetan Rivet name = rte_vdev_device_name(vdev); 278a46f8d58SGaetan Rivet INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s", 279a46f8d58SGaetan Rivet name); 280a46f8d58SGaetan Rivet return fs_eth_dev_create(vdev); 281a46f8d58SGaetan Rivet } 282a46f8d58SGaetan Rivet 283a46f8d58SGaetan Rivet static int 284a46f8d58SGaetan Rivet rte_pmd_failsafe_remove(struct rte_vdev_device *vdev) 285a46f8d58SGaetan Rivet { 286a46f8d58SGaetan Rivet const char *name; 287a46f8d58SGaetan Rivet 288a46f8d58SGaetan Rivet name = rte_vdev_device_name(vdev); 289a46f8d58SGaetan Rivet INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name); 290a46f8d58SGaetan Rivet return fs_rte_eth_free(name); 291a46f8d58SGaetan Rivet } 292a46f8d58SGaetan Rivet 293a46f8d58SGaetan Rivet static struct rte_vdev_driver failsafe_drv = { 294a46f8d58SGaetan Rivet .probe = rte_pmd_failsafe_probe, 295a46f8d58SGaetan Rivet .remove = rte_pmd_failsafe_remove, 296a46f8d58SGaetan Rivet }; 297a46f8d58SGaetan Rivet 298a46f8d58SGaetan Rivet RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv); 299a46f8d58SGaetan Rivet RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING); 300