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