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