1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 6WIND S.A. 3 * Copyright 2017 Mellanox Technologies, Ltd 4 */ 5 6 #include <bus_driver.h> 7 #include <rte_string_fns.h> 8 #include <rte_malloc.h> 9 10 #include "failsafe_private.h" 11 12 static int 13 fs_ethdev_portid_get(const char *name, uint16_t *port_id) 14 { 15 uint16_t pid; 16 size_t len; 17 18 if (name == NULL) { 19 DEBUG("Null pointer is specified"); 20 return -EINVAL; 21 } 22 len = strlen(name); 23 for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) { 24 if (rte_eth_dev_is_valid_port(pid) && 25 !strncmp(name, rte_eth_devices[pid].device->name, len)) { 26 *port_id = pid; 27 return 0; 28 } 29 } 30 return -ENODEV; 31 } 32 33 static int 34 fs_bus_init(struct rte_eth_dev *dev) 35 { 36 struct sub_device *sdev; 37 struct rte_devargs *da; 38 uint8_t i; 39 uint16_t pid; 40 int ret; 41 42 FOREACH_SUBDEV(sdev, i, dev) { 43 if (sdev->state != DEV_PARSED) 44 continue; 45 da = &sdev->devargs; 46 if (fs_ethdev_portid_get(da->name, &pid) != 0) { 47 struct rte_eth_dev_owner pid_owner; 48 49 ret = rte_eal_hotplug_add(da->bus->name, 50 da->name, 51 da->args); 52 if (ret < 0) { 53 ERROR("sub_device %d probe failed %s%s%s", i, 54 rte_errno ? "(" : "", 55 rte_errno ? strerror(rte_errno) : "", 56 rte_errno ? ")" : ""); 57 continue; 58 } 59 if (fs_ethdev_portid_get(da->name, &pid) != 0) { 60 ERROR("sub_device %d init went wrong", i); 61 return -ENODEV; 62 } 63 /* 64 * The NEW callback tried to take ownership, check 65 * whether it succeed or didn't. 66 */ 67 rte_eth_dev_owner_get(pid, &pid_owner); 68 if (pid_owner.id != PRIV(dev)->my_owner.id) { 69 INFO("sub_device %d owner(%s_%016"PRIX64") is not my," 70 " owner(%s_%016"PRIX64"), will try again later", 71 i, pid_owner.name, pid_owner.id, 72 PRIV(dev)->my_owner.name, 73 PRIV(dev)->my_owner.id); 74 continue; 75 } 76 } else { 77 /* The sub-device port was found. */ 78 char devstr[DEVARGS_MAXLEN] = ""; 79 struct rte_devargs *probed_da = 80 rte_eth_devices[pid].device->devargs; 81 82 /* Take control of probed device. */ 83 rte_devargs_reset(da); 84 memset(da, 0, sizeof(*da)); 85 if (probed_da != NULL) 86 snprintf(devstr, sizeof(devstr), "%s,%s", 87 probed_da->name, probed_da->args); 88 else 89 strlcpy(devstr, 90 rte_eth_devices[pid].device->name, 91 sizeof(devstr)); 92 ret = rte_devargs_parse(da, devstr); 93 if (ret) { 94 ERROR("Probed devargs parsing failed with code" 95 " %d", ret); 96 return ret; 97 } 98 INFO("Taking control of a probed sub device" 99 " %d named %s", i, da->name); 100 ret = rte_eth_dev_owner_set(pid, &PRIV(dev)->my_owner); 101 if (ret < 0) { 102 INFO("sub_device %d owner set failed (%s), " 103 "will try again later", i, strerror(-ret)); 104 continue; 105 } else if (strncmp(rte_eth_devices[pid].device->name, 106 da->name, strlen(da->name)) != 0) { 107 /* 108 * The device probably was removed and its port 109 * id was reallocated before ownership set. 110 */ 111 rte_eth_dev_owner_unset(pid, 112 PRIV(dev)->my_owner.id); 113 INFO("sub_device %d was removed before taking" 114 " ownership, will try again later", i); 115 continue; 116 } 117 } 118 sdev->sdev_port_id = pid; 119 SUB_ID(sdev) = i; 120 sdev->fs_port_id = dev->data->port_id; 121 sdev->dev = ETH(sdev)->device; 122 sdev->state = DEV_PROBED; 123 } 124 return 0; 125 } 126 127 int 128 failsafe_eal_init(struct rte_eth_dev *dev) 129 { 130 int ret; 131 132 ret = fs_bus_init(dev); 133 if (ret) 134 return ret; 135 if (PRIV(dev)->state < DEV_PROBED) 136 PRIV(dev)->state = DEV_PROBED; 137 fs_switch_dev(dev, NULL); 138 return 0; 139 } 140 141 static int 142 fs_bus_uninit(struct rte_eth_dev *dev) 143 { 144 struct sub_device *sdev = NULL; 145 uint8_t i; 146 int sdev_ret; 147 int ret = 0; 148 149 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 150 sdev_ret = rte_dev_remove(sdev->dev); 151 if (sdev_ret < 0) { 152 ERROR("Failed to remove requested device %s (err: %d)", 153 sdev->dev->name, sdev_ret); 154 continue; 155 } 156 sdev->state = DEV_PROBED - 1; 157 } 158 return ret; 159 } 160 161 int 162 failsafe_eal_uninit(struct rte_eth_dev *dev) 163 { 164 int ret; 165 166 ret = fs_bus_uninit(dev); 167 PRIV(dev)->state = DEV_PROBED - 1; 168 return ret; 169 } 170