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_malloc.h> 35 36 #include "failsafe_private.h" 37 38 static int 39 fs_ethdev_portid_get(const char *name, uint16_t *port_id) 40 { 41 uint16_t pid; 42 size_t len; 43 44 if (name == NULL) { 45 DEBUG("Null pointer is specified\n"); 46 return -EINVAL; 47 } 48 len = strlen(name); 49 RTE_ETH_FOREACH_DEV(pid) { 50 if (!strncmp(name, rte_eth_devices[pid].device->name, len)) { 51 *port_id = pid; 52 return 0; 53 } 54 } 55 return -ENODEV; 56 } 57 58 static int 59 fs_bus_init(struct rte_eth_dev *dev) 60 { 61 struct sub_device *sdev; 62 struct rte_devargs *da; 63 uint8_t i; 64 uint16_t pid; 65 int ret; 66 67 FOREACH_SUBDEV(sdev, i, dev) { 68 if (sdev->state != DEV_PARSED) 69 continue; 70 da = &sdev->devargs; 71 if (fs_ethdev_portid_get(da->name, &pid) != 0) { 72 ret = rte_eal_hotplug_add(da->bus->name, 73 da->name, 74 da->args); 75 if (ret) { 76 ERROR("sub_device %d probe failed %s%s%s", i, 77 rte_errno ? "(" : "", 78 rte_errno ? strerror(rte_errno) : "", 79 rte_errno ? ")" : ""); 80 continue; 81 } 82 if (fs_ethdev_portid_get(da->name, &pid) != 0) { 83 ERROR("sub_device %d init went wrong", i); 84 return -ENODEV; 85 } 86 } else { 87 char devstr[DEVARGS_MAXLEN] = ""; 88 struct rte_devargs *probed_da = 89 rte_eth_devices[pid].device->devargs; 90 91 /* Take control of device probed by EAL options. */ 92 free(da->args); 93 memset(da, 0, sizeof(*da)); 94 if (probed_da != NULL) 95 snprintf(devstr, sizeof(devstr), "%s,%s", 96 probed_da->name, probed_da->args); 97 else 98 snprintf(devstr, sizeof(devstr), "%s", 99 rte_eth_devices[pid].device->name); 100 ret = rte_eal_devargs_parse(devstr, da); 101 if (ret) { 102 ERROR("Probed devargs parsing failed with code" 103 " %d", ret); 104 return ret; 105 } 106 INFO("Taking control of a probed sub device" 107 " %d named %s", i, da->name); 108 } 109 ETH(sdev) = &rte_eth_devices[pid]; 110 SUB_ID(sdev) = i; 111 sdev->fs_dev = dev; 112 sdev->dev = ETH(sdev)->device; 113 ETH(sdev)->state = RTE_ETH_DEV_DEFERRED; 114 sdev->state = DEV_PROBED; 115 } 116 return 0; 117 } 118 119 int 120 failsafe_eal_init(struct rte_eth_dev *dev) 121 { 122 int ret; 123 124 ret = fs_bus_init(dev); 125 if (ret) 126 return ret; 127 if (PRIV(dev)->state < DEV_PROBED) 128 PRIV(dev)->state = DEV_PROBED; 129 fs_switch_dev(dev, NULL); 130 return 0; 131 } 132 133 static int 134 fs_bus_uninit(struct rte_eth_dev *dev) 135 { 136 struct sub_device *sdev = NULL; 137 uint8_t i; 138 int sdev_ret; 139 int ret = 0; 140 141 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 142 sdev_ret = rte_eal_hotplug_remove(sdev->bus->name, 143 sdev->dev->name); 144 if (sdev_ret) { 145 ERROR("Failed to remove requested device %s (err: %d)", 146 sdev->dev->name, sdev_ret); 147 continue; 148 } 149 sdev->state = DEV_PROBED - 1; 150 } 151 return ret; 152 } 153 154 int 155 failsafe_eal_uninit(struct rte_eth_dev *dev) 156 { 157 int ret; 158 159 ret = fs_bus_uninit(dev); 160 PRIV(dev)->state = DEV_PROBED - 1; 161 return ret; 162 } 163